1 /* 2 * Copyright 2002-2006, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Wilber 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 /*! Utility functions for the Translation Kit */ 11 12 13 #include <Application.h> 14 #include <Bitmap.h> 15 #include <BitmapStream.h> 16 #include <Entry.h> 17 #include <File.h> 18 #include <MenuItem.h> 19 #include <NodeInfo.h> 20 #include <Path.h> 21 #include <Resources.h> 22 #include <Roster.h> 23 #include <TextView.h> 24 #include <TranslationUtils.h> 25 #include <TranslatorFormats.h> 26 #include <TranslatorRoster.h> 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 33 BTranslationUtils::BTranslationUtils() 34 { 35 } 36 37 38 BTranslationUtils::~BTranslationUtils() 39 { 40 } 41 42 43 BTranslationUtils::BTranslationUtils(const BTranslationUtils &kUtils) 44 { 45 } 46 47 48 BTranslationUtils & 49 BTranslationUtils::operator=(const BTranslationUtils &kUtils) 50 { 51 return *this; 52 } 53 54 // --------------------------------------------------------------- 55 // GetBitmap 56 // 57 // Returns a BBitmap object for the bitmap file or resource 58 // kName. The user has to delete this object. It first tries 59 // to open kName as a file, then as a resource. 60 // 61 // Preconditions: 62 // 63 // Parameters: kName, the name of the bitmap file or resource to 64 // be returned 65 // roster, BTranslatorRoster used to do the translation 66 // 67 // Postconditions: 68 // 69 // Returns: NULL, if the file could not be opened and the 70 // resource couldn't be found or couldn't be 71 // translated to a BBitmap 72 // BBitmap * to the bitmap reference by kName 73 // --------------------------------------------------------------- 74 BBitmap * 75 BTranslationUtils::GetBitmap(const char *kName, BTranslatorRoster *roster) 76 { 77 BBitmap *pBitmap = GetBitmapFile(kName, roster); 78 // Try loading a bitmap from the file named name 79 80 // Try loading the bitmap as an application resource 81 if (pBitmap == NULL) 82 pBitmap = GetBitmap(B_TRANSLATOR_BITMAP, kName, roster); 83 84 return pBitmap; 85 } 86 87 // --------------------------------------------------------------- 88 // GetBitmap 89 // 90 // Returns a BBitmap object for the bitmap resource identified by 91 // the type type with the resource id, id. 92 // The user has to delete this object. 93 // 94 // Preconditions: 95 // 96 // Parameters: type, the type of resource to be loaded 97 // id, the id for the resource to be loaded 98 // roster, BTranslatorRoster used to do the translation 99 // 100 // Postconditions: 101 // 102 // Returns: NULL, if the resource couldn't be loaded or couldn't 103 // be translated to a BBitmap 104 // BBitmap * to the bitmap identified by type and id 105 // --------------------------------------------------------------- 106 BBitmap * 107 BTranslationUtils::GetBitmap(uint32 type, int32 id, BTranslatorRoster *roster) 108 { 109 BResources *pResources = BApplication::AppResources(); 110 // Remember: pResources must not be freed because 111 // it belongs to the application 112 if (pResources == NULL || pResources->HasResource(type, id) == false) 113 return NULL; 114 115 // Load the bitmap resource from the application file 116 // pRawData should be NULL if the resource is an 117 // unknown type or not available 118 size_t bitmapSize = 0; 119 const void *kpRawData = pResources->LoadResource(type, id, &bitmapSize); 120 if (kpRawData == NULL || bitmapSize == 0) 121 return NULL; 122 123 BMemoryIO memio(kpRawData, bitmapSize); 124 // Put the pointer to the raw image data into a BMemoryIO object 125 // so that it can be used with BTranslatorRoster->Translate() in 126 // the GetBitmap(BPositionIO *, BTranslatorRoster *) function 127 128 return GetBitmap(&memio, roster); 129 // Translate the data in memio using the BTranslatorRoster roster 130 } 131 132 // --------------------------------------------------------------- 133 // GetBitmap 134 // 135 // Returns a BBitmap object for the bitmap resource identified by 136 // the type type with the resource name, kName. 137 // The user has to delete this object. Note that a resource type 138 // and name does not uniquely identify a resource in a file. 139 // 140 // Preconditions: 141 // 142 // Parameters: type, the type of resource to be loaded 143 // kName, the name of the resource to be loaded 144 // roster, BTranslatorRoster used to do the translation 145 // 146 // Postconditions: 147 // 148 // Returns: NULL, if the resource couldn't be loaded or couldn't 149 // be translated to a BBitmap 150 // BBitmap * to the bitmap identified by type and kName 151 // --------------------------------------------------------------- 152 BBitmap * 153 BTranslationUtils::GetBitmap(uint32 type, const char *kName, 154 BTranslatorRoster *roster) 155 { 156 BResources *pResources = BApplication::AppResources(); 157 // Remember: pResources must not be freed because 158 // it belongs to the application 159 if (pResources == NULL || pResources->HasResource(type, kName) == false) 160 return NULL; 161 162 // Load the bitmap resource from the application file 163 size_t bitmapSize = 0; 164 const void *kpRawData = pResources->LoadResource(type, kName, &bitmapSize); 165 if (kpRawData == NULL || bitmapSize == 0) 166 return NULL; 167 168 BMemoryIO memio(kpRawData, bitmapSize); 169 // Put the pointer to the raw image data into a BMemoryIO object so 170 // that it can be used with BTranslatorRoster->Translate() 171 172 return GetBitmap(&memio, roster); 173 // Translate the data in memio using the BTranslatorRoster roster 174 } 175 176 // --------------------------------------------------------------- 177 // GetBitmapFile 178 // 179 // Returns a BBitmap object for the bitmap file named kName. 180 // The user has to delete this object. 181 // 182 // Preconditions: 183 // 184 // Parameters: kName, the name of the bitmap file 185 // roster, BTranslatorRoster used to do the translation 186 // 187 // Postconditions: 188 // 189 // Returns: NULL, if the file couldn't be opened or couldn't 190 // be translated to a BBitmap 191 // BBitmap * to the bitmap file named kName 192 // --------------------------------------------------------------- 193 BBitmap * 194 BTranslationUtils::GetBitmapFile(const char *kName, BTranslatorRoster *roster) 195 { 196 if (!be_app || !kName || kName[0] == '\0') 197 return NULL; 198 199 BPath path; 200 if (kName[0] != '/') { 201 // If kName is a relative path, use the path of the application's 202 // executable as the base for the relative path 203 app_info info; 204 if (be_app->GetAppInfo(&info) != B_OK) 205 return NULL; 206 BEntry appRef(&info.ref); 207 if (path.SetTo(&appRef) != B_OK) 208 return NULL; 209 if (path.GetParent(&path) != B_OK) 210 return NULL; 211 if (path.Append(kName) != B_OK) 212 return NULL; 213 214 } else if (path.SetTo(kName) != B_OK) 215 return NULL; 216 217 BFile bitmapFile(path.Path(), B_READ_ONLY); 218 if (bitmapFile.InitCheck() != B_OK) 219 return NULL; 220 221 return GetBitmap(&bitmapFile, roster); 222 // Translate the data in memio using the BTranslatorRoster roster 223 } 224 225 // --------------------------------------------------------------- 226 // GetBitmap 227 // 228 // Returns a BBitmap object for the bitmap file with the entry_ref 229 // kRef. The user has to delete this object. 230 // 231 // Preconditions: 232 // 233 // Parameters: kRef, the entry_ref for the bitmap file 234 // roster, BTranslatorRoster used to do the translation 235 // 236 // Postconditions: 237 // 238 // Returns: NULL, if the file couldn't be opened or couldn't 239 // be translated to a BBitmap 240 // BBitmap * to the bitmap file referenced by kRef 241 // --------------------------------------------------------------- 242 BBitmap * 243 BTranslationUtils::GetBitmap(const entry_ref *kRef, BTranslatorRoster *roster) 244 { 245 BFile bitmapFile(kRef, B_READ_ONLY); 246 if (bitmapFile.InitCheck() != B_OK) 247 return NULL; 248 249 return GetBitmap(&bitmapFile, roster); 250 // Translate the data in bitmapFile using the BTranslatorRoster roster 251 } 252 253 // --------------------------------------------------------------- 254 // GetBitmap 255 // 256 // Returns a BBitmap object from the BPositionIO *stream. The 257 // user must delete the returned object. This GetBitmap function 258 // is used by the other GetBitmap functions to do all of the 259 // "real" work. 260 // 261 // Preconditions: 262 // 263 // Parameters: stream, the stream with bitmap data in it 264 // roster, BTranslatorRoster used to do the translation 265 // 266 // Postconditions: 267 // 268 // Returns: NULL, if the stream couldn't be translated to a BBitmap 269 // BBitmap * for the bitmap data from pio if successful 270 // --------------------------------------------------------------- 271 BBitmap * 272 BTranslationUtils::GetBitmap(BPositionIO *stream, BTranslatorRoster *roster) 273 { 274 if (stream == NULL) 275 return NULL; 276 277 // Use default Translator if none is specified 278 if (roster == NULL) { 279 roster = BTranslatorRoster::Default(); 280 if (roster == NULL) 281 return NULL; 282 } 283 284 // Translate the file from whatever format it is in the file 285 // to the type format so that it can be stored in a BBitmap 286 BBitmapStream bitmapStream; 287 if (roster->Translate(stream, NULL, NULL, &bitmapStream, 288 B_TRANSLATOR_BITMAP) < B_OK) 289 return NULL; 290 291 // Detach the BBitmap from the BBitmapStream so the user 292 // of this function can do what they please with it. 293 BBitmap *pBitmap = NULL; 294 if (bitmapStream.DetachBitmap(&pBitmap) == B_NO_ERROR) 295 return pBitmap; 296 else 297 return NULL; 298 } 299 300 301 /*! 302 This function translates the styled text in fromStream and 303 inserts it at the end of the text in intoView, using the 304 BTranslatorRoster *roster to do the translation. The structs 305 that make it possible to work with the translated data are 306 defined in 307 /boot/develop/headers/be/translation/TranslatorFormats.h 308 309 \param fromStream the stream with the styled text 310 \param intoView the view where the test will be inserted 311 roster, BTranslatorRoster used to do the translation 312 313 \return B_BAD_VALUE, if fromStream or intoView is NULL 314 \return B_ERROR, if any other error occurred 315 \return B_OK, if successful 316 */ 317 status_t 318 BTranslationUtils::GetStyledText(BPositionIO *fromStream, BTextView *intoView, 319 BTranslatorRoster *roster) 320 { 321 if (fromStream == NULL || intoView == NULL) 322 return B_BAD_VALUE; 323 324 // Use default Translator if none is specified 325 if (roster == NULL) { 326 roster = BTranslatorRoster::Default(); 327 if (roster == NULL) 328 return B_ERROR; 329 } 330 331 // Translate the file from whatever format it is to B_STYLED_TEXT_FORMAT 332 // we understand 333 BMallocIO mallocIO; 334 if (roster->Translate(fromStream, NULL, NULL, &mallocIO, 335 B_STYLED_TEXT_FORMAT) < B_OK) 336 return B_BAD_TYPE; 337 338 const uint8* buffer = (const uint8*)mallocIO.Buffer(); 339 340 // make sure there is enough data to fill the stream header 341 const size_t kStreamHeaderSize = sizeof(TranslatorStyledTextStreamHeader); 342 if (mallocIO.BufferLength() < kStreamHeaderSize) 343 return B_ERROR; 344 345 // copy the stream header from the mallio buffer 346 TranslatorStyledTextStreamHeader stm_header = 347 *(reinterpret_cast<const TranslatorStyledTextStreamHeader *>(buffer)); 348 349 // convert the stm_header.header struct to the host format 350 const size_t kRecordHeaderSize = sizeof(TranslatorStyledTextRecordHeader); 351 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, 352 B_SWAP_BENDIAN_TO_HOST) != B_OK 353 || swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), 354 B_SWAP_BENDIAN_TO_HOST) != B_OK 355 || stm_header.header.magic != 'STXT') 356 return B_ERROR; 357 358 // copy the text header from the mallocIO buffer 359 360 uint32 offset = stm_header.header.header_size + 361 stm_header.header.data_size; 362 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); 363 if (mallocIO.BufferLength() < offset + kTextHeaderSize) 364 return B_ERROR; 365 366 TranslatorStyledTextTextHeader textHeader = 367 *(const TranslatorStyledTextTextHeader *)(buffer + offset); 368 369 // convert the stm_header.header struct to the host format 370 if (swap_data(B_UINT32_TYPE, &textHeader.header, kRecordHeaderSize, 371 B_SWAP_BENDIAN_TO_HOST) != B_OK 372 || swap_data(B_INT32_TYPE, &textHeader.charset, sizeof(int32), 373 B_SWAP_BENDIAN_TO_HOST) != B_OK 374 || textHeader.header.magic != 'TEXT' 375 || textHeader.charset != B_UNICODE_UTF8) 376 return B_ERROR; 377 378 offset += textHeader.header.header_size; 379 if (mallocIO.BufferLength() < offset + textHeader.header.data_size) 380 return B_ERROR; 381 382 const char* text = (const char*)buffer + offset; 383 // point text pointer at the actual character data 384 385 if (mallocIO.BufferLength() > offset + textHeader.header.data_size) { 386 // If the stream contains information beyond the text data 387 // (which means that this data is probably styled text data) 388 389 offset += textHeader.header.data_size; 390 const size_t kStyleHeaderSize = 391 sizeof(TranslatorStyledTextStyleHeader); 392 if (mallocIO.BufferLength() < offset + kStyleHeaderSize) 393 return B_ERROR; 394 395 TranslatorStyledTextStyleHeader styleHeader = 396 *(reinterpret_cast<const TranslatorStyledTextStyleHeader *>(buffer + offset)); 397 if (swap_data(B_UINT32_TYPE, &styleHeader.header, kRecordHeaderSize, 398 B_SWAP_BENDIAN_TO_HOST) != B_OK 399 || swap_data(B_UINT32_TYPE, &styleHeader.apply_offset, sizeof(uint32), 400 B_SWAP_BENDIAN_TO_HOST) != B_OK 401 || swap_data(B_UINT32_TYPE, &styleHeader.apply_length, sizeof(uint32), 402 B_SWAP_BENDIAN_TO_HOST) != B_OK 403 || styleHeader.header.magic != 'STYL') 404 return B_ERROR; 405 406 offset += styleHeader.header.header_size; 407 if (mallocIO.BufferLength() < offset + styleHeader.header.data_size) 408 return B_ERROR; 409 410 // get the text run array 411 412 text_run_array *runArray = BTextView::UnflattenRunArray(buffer + offset); 413 if (runArray) { 414 intoView->Insert(intoView->TextLength(), text, 415 textHeader.header.data_size, runArray); 416 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 417 BTextView::FreeRunArray(runArray); 418 #else 419 free(runArray); 420 #endif 421 } else { 422 // run array seems to be garbled; the text alone must be enough 423 intoView->Insert(intoView->TextLength(), text, 424 textHeader.header.data_size); 425 } 426 } else { 427 intoView->Insert(intoView->TextLength(), text, 428 textHeader.header.data_size); 429 } 430 431 return B_OK; 432 } 433 434 435 /*! 436 This function takes styled text data from fromView and writes it to 437 intoStream. The plain text data and styled text data are combined 438 when they are written to intoStream. This is different than how 439 a save operation in StyledEdit works. With StyledEdit, it writes 440 plain text data to the file, but puts the styled text data in 441 the "styles" attribute. In other words, this function writes 442 styled text data to files in a manner that isn't human readable. 443 444 So, if you want to write styled text 445 data to a file, and you want it to behave the way StyledEdit does, 446 you want to use the BTranslationUtils::WriteStyledEditFile() function. 447 448 \param fromView, the view with the styled text in it 449 \param intoStream, the stream where the styled text is put 450 roster, not used 451 452 \return B_BAD_VALUE, if fromView or intoStream is NULL 453 \return B_ERROR, if anything else went wrong 454 \return B_NO_ERROR, if successful 455 */ 456 status_t 457 BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream, 458 BTranslatorRoster *roster) 459 { 460 if (fromView == NULL || intoStream == NULL) 461 return B_BAD_VALUE; 462 463 int32 textLength = fromView->TextLength(); 464 if (textLength < 0) 465 return B_ERROR; 466 467 const char *pTextData = fromView->Text(); 468 // its OK if the result of fromView->Text() is NULL 469 470 int32 runArrayLength = 0; 471 text_run_array *runArray = fromView->RunArray(0, textLength, 472 &runArrayLength); 473 if (runArray == NULL) 474 return B_ERROR; 475 476 int32 flatRunArrayLength = 0; 477 void *pflatRunArray = 478 BTextView::FlattenRunArray(runArray, &flatRunArrayLength); 479 if (pflatRunArray == NULL) { 480 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 481 BTextView::FreeRunArray(runArray); 482 #else 483 free(runArray); 484 #endif 485 return B_ERROR; 486 } 487 488 // Rather than use a goto, I put a whole bunch of code that 489 // could error out inside of a loop, and break out of the loop 490 // if there is an error. 491 492 // This block of code is where I do all of the writing of the 493 // data to the stream. I've gathered all of the data that I 494 // need at this point. 495 bool ok = false; 496 while (ok) { 497 const size_t kStreamHeaderSize = 498 sizeof(TranslatorStyledTextStreamHeader); 499 TranslatorStyledTextStreamHeader stm_header; 500 stm_header.header.magic = 'STXT'; 501 stm_header.header.header_size = kStreamHeaderSize; 502 stm_header.header.data_size = 0; 503 stm_header.version = 100; 504 505 // convert the stm_header.header struct to the host format 506 const size_t kRecordHeaderSize = 507 sizeof(TranslatorStyledTextRecordHeader); 508 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, 509 B_SWAP_HOST_TO_BENDIAN) != B_OK) 510 break; 511 if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), 512 B_SWAP_HOST_TO_BENDIAN) != B_OK) 513 break; 514 515 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); 516 TranslatorStyledTextTextHeader txt_header; 517 txt_header.header.magic = 'TEXT'; 518 txt_header.header.header_size = kTextHeaderSize; 519 txt_header.header.data_size = textLength; 520 txt_header.charset = B_UNICODE_UTF8; 521 522 // convert the stm_header.header struct to the host format 523 if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, 524 B_SWAP_HOST_TO_BENDIAN) != B_OK) 525 break; 526 if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), 527 B_SWAP_HOST_TO_BENDIAN) != B_OK) 528 break; 529 530 const size_t kStyleHeaderSize = 531 sizeof(TranslatorStyledTextStyleHeader); 532 TranslatorStyledTextStyleHeader stl_header; 533 stl_header.header.magic = 'STYL'; 534 stl_header.header.header_size = kStyleHeaderSize; 535 stl_header.header.data_size = flatRunArrayLength; 536 stl_header.apply_offset = 0; 537 stl_header.apply_length = textLength; 538 539 // convert the stl_header.header struct to the host format 540 if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, 541 B_SWAP_HOST_TO_BENDIAN) != B_OK) 542 break; 543 if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), 544 B_SWAP_HOST_TO_BENDIAN) != B_OK) 545 break; 546 if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), 547 B_SWAP_HOST_TO_BENDIAN) != B_OK) 548 break; 549 550 // Here, you can see the structure of the styled text data by 551 // observing the order that the various structs and data are 552 // written to the stream 553 ssize_t amountWritten = 0; 554 amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize); 555 if ((size_t) amountWritten != kStreamHeaderSize) 556 break; 557 amountWritten = intoStream->Write(&txt_header, kTextHeaderSize); 558 if ((size_t) amountWritten != kTextHeaderSize) 559 break; 560 amountWritten = intoStream->Write(pTextData, textLength); 561 if (amountWritten != textLength) 562 break; 563 amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize); 564 if ((size_t) amountWritten != kStyleHeaderSize) 565 break; 566 amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength); 567 if (amountWritten != flatRunArrayLength) 568 break; 569 570 ok = true; 571 // gracefully break out of the loop 572 } 573 574 free(pflatRunArray); 575 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 576 BTextView::FreeRunArray(runArray); 577 #else 578 free(runArray); 579 #endif 580 581 return ok ? B_OK : B_ERROR; 582 } 583 584 585 /*! 586 \brief Writes the styled text data from \a view to the specified \a file. 587 588 This function is similar to PutStyledText() except that it 589 only writes styled text data to files and it puts the 590 plain text data in the file and stores the styled data as 591 the attribute "styles". 592 593 You can use PutStyledText() to write styled text data 594 to files, but it writes the data in a format that isn't 595 human readable. 596 597 \param view the view with the styled text 598 \param file the file where the styled text is written to 599 600 \return B_BAD_VALUE, if either parameter is NULL 601 B_OK, if successful, and any possible file error 602 if writing failed. 603 */ 604 status_t 605 BTranslationUtils::WriteStyledEditFile(BTextView* view, BFile* file) 606 { 607 if (view == NULL || file == NULL) 608 return B_BAD_VALUE; 609 610 int32 textLength = view->TextLength(); 611 if (textLength < 0) 612 return B_ERROR; 613 614 const char *text = view->Text(); 615 if (text == NULL && textLength != 0) 616 return B_ERROR; 617 618 // move to the start of the file if not already there 619 status_t result = file->Seek(0, SEEK_SET); 620 if (result != B_OK) 621 return result; 622 623 // Write plain text data to file 624 ssize_t bytesWritten = file->Write(text, textLength); 625 if (bytesWritten != textLength) 626 return B_ERROR; 627 628 // truncate any extra text 629 result = file->SetSize(textLength); 630 if (result != B_OK) 631 return result; 632 633 // Write attributes. We don't report an error anymore after this point, 634 // as attributes aren't that crucial - not all volumes support attributes. 635 // However, if writing one attribute fails, no further attributes are 636 // tried to be written. 637 638 BNodeInfo info(file); 639 char type[B_MIME_TYPE_LENGTH]; 640 if (info.GetType(type) != B_OK) { 641 // This file doesn't have a file type yet, so let's set it 642 result = info.SetType("text/plain"); 643 if (result < B_OK) 644 return B_OK; 645 } 646 647 // word wrap setting, turned on by default 648 int32 wordWrap = view->DoesWordWrap() ? 1 : 0; 649 bytesWritten = file->WriteAttr("wrap", B_INT32_TYPE, 0, 650 &wordWrap, sizeof(int32)); 651 if (bytesWritten != sizeof(int32)) 652 return B_OK; 653 654 // alignment, default is B_ALIGN_LEFT 655 int32 alignment = view->Alignment(); 656 bytesWritten = file->WriteAttr("alignment", B_INT32_TYPE, 0, 657 &alignment, sizeof(int32)); 658 if (bytesWritten != sizeof(int32)) 659 return B_OK; 660 661 // be:encoding, defaults to UTF-8 (65535) 662 // Note that the B_UNICODE_UTF8 constant is 0 and for some reason 663 // not appropriate for use here. 664 int32 encoding = 65535; 665 bytesWritten = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, 666 &encoding, sizeof(int32)); 667 if (bytesWritten != sizeof(int32)) 668 return B_OK; 669 670 // Write text_run_array, ie. the styles of the text 671 672 text_run_array *runArray = view->RunArray(0, view->TextLength()); 673 if (runArray != NULL) { 674 int32 runArraySize = 0; 675 void *flattenedRunArray = BTextView::FlattenRunArray(runArray, &runArraySize); 676 if (flattenedRunArray != NULL) { 677 file->WriteAttr("styles", B_RAW_TYPE, 0, flattenedRunArray, 678 runArraySize); 679 } 680 681 free(flattenedRunArray); 682 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 683 BTextView::FreeRunArray(runArray); 684 #else 685 free(runArray); 686 #endif 687 } 688 689 return B_OK; 690 } 691 692 693 /*! 694 Each translator can have default settings, set by the 695 "translations" control panel. You can read these settings to 696 pass on to a translator using one of these functions. 697 698 \param forTranslator, the translator the settings are for 699 roster, the roster used to get the settings 700 701 \return BMessage of configuration data for forTranslator - you own 702 this message and have to free it when you're done with it. 703 \return NULL, if anything went wrong 704 */ 705 BMessage * 706 BTranslationUtils::GetDefaultSettings(translator_id forTranslator, 707 BTranslatorRoster *roster) 708 { 709 // Use default Translator if none is specified 710 if (roster == NULL) { 711 roster = BTranslatorRoster::Default(); 712 if (roster == NULL) 713 return NULL; 714 } 715 716 BMessage *message = new BMessage(); 717 if (message == NULL) 718 return NULL; 719 720 status_t result = roster->GetConfigurationMessage(forTranslator, message); 721 if (result != B_OK && result != B_NO_TRANSLATOR) { 722 // Be's version seems to just pass an empty BMessage 723 // in case of B_NO_TRANSLATOR, well, in some cases anyway 724 delete message; 725 return NULL; 726 } 727 728 return message; 729 } 730 731 732 // --------------------------------------------------------------- 733 // GetDefaultSettings 734 // 735 // Attempts to find the translator settings for 736 // the translator named kTranslatorName with a version of 737 // translatorVersion. 738 // 739 // Preconditions: 740 // 741 // Parameters: kTranslatorName, the name of the translator 742 // the settings are for 743 // translatorVersion, the version of the translator 744 // to retrieve 745 // 746 // Postconditions: 747 // 748 // Returns: NULL, if anything went wrong 749 // BMessage * of configuration data for kTranslatorName 750 // --------------------------------------------------------------- 751 BMessage * 752 BTranslationUtils::GetDefaultSettings(const char *kTranslatorName, 753 int32 translatorVersion) 754 { 755 BTranslatorRoster *roster = BTranslatorRoster::Default(); 756 translator_id *translators = NULL; 757 int32 numTranslators = 0; 758 if (roster == NULL 759 || roster->GetAllTranslators(&translators, &numTranslators) != B_OK) 760 return NULL; 761 762 // Cycle through all of the default translators 763 // looking for a translator that matches the name and version 764 // that I was given 765 BMessage *pMessage = NULL; 766 const char *currentTranName = NULL, *currentTranInfo = NULL; 767 int32 currentTranVersion = 0; 768 for (int i = 0; i < numTranslators; i++) { 769 770 if (roster->GetTranslatorInfo(translators[i], ¤tTranName, 771 ¤tTranInfo, ¤tTranVersion) == B_OK) { 772 773 if (currentTranVersion == translatorVersion 774 && strcmp(currentTranName, kTranslatorName) == 0) { 775 pMessage = GetDefaultSettings(translators[i], roster); 776 break; 777 } 778 } 779 } 780 781 delete[] translators; 782 return pMessage; 783 } 784 785 // --------------------------------------------------------------- 786 // AddTranslationItems 787 // 788 // Envious of that "Save As" menu in ShowImage? Well, you can have your own! 789 // AddTranslationItems will add menu items for all translations from the 790 // basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc). 791 // The translator ID and format constant chosen will be added to the message 792 // that is sent to you when the menu item is selected. 793 // 794 // The following code is a modified version of code 795 // written by Jon Watte from 796 // http://www.b500.com/bepage/TranslationKit2.html 797 // 798 // Preconditions: 799 // 800 // Parameters: intoMenu, the menu where the entries are created 801 // fromType, the type of translators to put on 802 // intoMenu 803 // kModel, the BMessage model for creating the menu 804 // if NULL, B_TRANSLATION_MENU is used 805 // kTranslationIdName, the name used for 806 // translator_id in the menuitem, 807 // if NULL, be:translator is used 808 // kTranslatorTypeName, the name used for 809 // output format id in the menuitem 810 // roster, BTranslatorRoster used to find translators 811 // if NULL, the default translators are used 812 // 813 // 814 // Postconditions: 815 // 816 // Returns: B_BAD_VALUE, if intoMenu is NULL 817 // B_OK, if successful 818 // error value if not successful 819 // --------------------------------------------------------------- 820 status_t 821 BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType, 822 const BMessage *kModel, const char *kTranslatorIdName, 823 const char *kTranslatorTypeName, BTranslatorRoster *roster) 824 { 825 if (!intoMenu) 826 return B_BAD_VALUE; 827 828 if (!roster) 829 roster = BTranslatorRoster::Default(); 830 831 if (!kTranslatorIdName) 832 kTranslatorIdName = "be:translator"; 833 834 if (!kTranslatorTypeName) 835 kTranslatorTypeName = "be:type"; 836 837 translator_id * ids = NULL; 838 int32 count = 0; 839 status_t err = roster->GetAllTranslators(&ids, &count); 840 if (err < B_OK) 841 return err; 842 843 for (int tix = 0; tix < count; tix++) { 844 const translation_format *formats = NULL; 845 int32 numFormats = 0; 846 bool ok = false; 847 err = roster->GetInputFormats(ids[tix], &formats, &numFormats); 848 if (err == B_OK) { 849 for (int iix = 0; iix < numFormats; iix++) { 850 if (formats[iix].type == fromType) { 851 ok = true; 852 break; 853 } 854 } 855 } 856 if (!ok) 857 continue; 858 859 err = roster->GetOutputFormats(ids[tix], &formats, &numFormats); 860 if (err == B_OK) { 861 for (int oix = 0; oix < numFormats; oix++) { 862 if (formats[oix].type != fromType) { 863 BMessage *itemmsg; 864 if (kModel) 865 itemmsg = new BMessage(*kModel); 866 else 867 itemmsg = new BMessage(B_TRANSLATION_MENU); 868 itemmsg->AddInt32(kTranslatorIdName, ids[tix]); 869 itemmsg->AddInt32(kTranslatorTypeName, formats[oix].type); 870 intoMenu->AddItem( 871 new BMenuItem(formats[oix].name, itemmsg)); 872 } 873 } 874 } 875 } 876 877 delete[] ids; 878 return B_OK; 879 } 880