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 BTextView::FreeRunArray(runArray); 417 } else { 418 // run array seems to be garbled; the text alone must be enough 419 intoView->Insert(intoView->TextLength(), text, 420 textHeader.header.data_size); 421 } 422 } else { 423 intoView->Insert(intoView->TextLength(), text, 424 textHeader.header.data_size); 425 } 426 427 return B_OK; 428 } 429 430 431 /*! 432 This function takes styled text data from fromView and writes it to 433 intoStream. The plain text data and styled text data are combined 434 when they are written to intoStream. This is different than how 435 a save operation in StyledEdit works. With StyledEdit, it writes 436 plain text data to the file, but puts the styled text data in 437 the "styles" attribute. In other words, this function writes 438 styled text data to files in a manner that isn't human readable. 439 440 So, if you want to write styled text 441 data to a file, and you want it to behave the way StyledEdit does, 442 you want to use the BTranslationUtils::WriteStyledEditFile() function. 443 444 \param fromView, the view with the styled text in it 445 \param intoStream, the stream where the styled text is put 446 roster, not used 447 448 \return B_BAD_VALUE, if fromView or intoStream is NULL 449 \return B_ERROR, if anything else went wrong 450 \return B_NO_ERROR, if successful 451 */ 452 status_t 453 BTranslationUtils::PutStyledText(BTextView *fromView, BPositionIO *intoStream, 454 BTranslatorRoster *roster) 455 { 456 if (fromView == NULL || intoStream == NULL) 457 return B_BAD_VALUE; 458 459 int32 textLength = fromView->TextLength(); 460 if (textLength < 0) 461 return B_ERROR; 462 463 const char *pTextData = fromView->Text(); 464 // its OK if the result of fromView->Text() is NULL 465 466 int32 runArrayLength = 0; 467 text_run_array *runArray = fromView->RunArray(0, textLength, 468 &runArrayLength); 469 if (runArray == NULL) 470 return B_ERROR; 471 472 int32 flatRunArrayLength = 0; 473 void *pflatRunArray = 474 BTextView::FlattenRunArray(runArray, &flatRunArrayLength); 475 if (pflatRunArray == NULL) { 476 BTextView::FreeRunArray(runArray); 477 return B_ERROR; 478 } 479 480 // Rather than use a goto, I put a whole bunch of code that 481 // could error out inside of a loop, and break out of the loop 482 // if there is an error. 483 484 // This block of code is where I do all of the writing of the 485 // data to the stream. I've gathered all of the data that I 486 // need at this point. 487 bool ok = false; 488 while (ok) { 489 const size_t kStreamHeaderSize = 490 sizeof(TranslatorStyledTextStreamHeader); 491 TranslatorStyledTextStreamHeader stm_header; 492 stm_header.header.magic = 'STXT'; 493 stm_header.header.header_size = kStreamHeaderSize; 494 stm_header.header.data_size = 0; 495 stm_header.version = 100; 496 497 // convert the stm_header.header struct to the host format 498 const size_t kRecordHeaderSize = 499 sizeof(TranslatorStyledTextRecordHeader); 500 if (swap_data(B_UINT32_TYPE, &stm_header.header, kRecordHeaderSize, 501 B_SWAP_HOST_TO_BENDIAN) != B_OK) 502 break; 503 if (swap_data(B_INT32_TYPE, &stm_header.version, sizeof(int32), 504 B_SWAP_HOST_TO_BENDIAN) != B_OK) 505 break; 506 507 const size_t kTextHeaderSize = sizeof(TranslatorStyledTextTextHeader); 508 TranslatorStyledTextTextHeader txt_header; 509 txt_header.header.magic = 'TEXT'; 510 txt_header.header.header_size = kTextHeaderSize; 511 txt_header.header.data_size = textLength; 512 txt_header.charset = B_UNICODE_UTF8; 513 514 // convert the stm_header.header struct to the host format 515 if (swap_data(B_UINT32_TYPE, &txt_header.header, kRecordHeaderSize, 516 B_SWAP_HOST_TO_BENDIAN) != B_OK) 517 break; 518 if (swap_data(B_INT32_TYPE, &txt_header.charset, sizeof(int32), 519 B_SWAP_HOST_TO_BENDIAN) != B_OK) 520 break; 521 522 const size_t kStyleHeaderSize = 523 sizeof(TranslatorStyledTextStyleHeader); 524 TranslatorStyledTextStyleHeader stl_header; 525 stl_header.header.magic = 'STYL'; 526 stl_header.header.header_size = kStyleHeaderSize; 527 stl_header.header.data_size = flatRunArrayLength; 528 stl_header.apply_offset = 0; 529 stl_header.apply_length = textLength; 530 531 // convert the stl_header.header struct to the host format 532 if (swap_data(B_UINT32_TYPE, &stl_header.header, kRecordHeaderSize, 533 B_SWAP_HOST_TO_BENDIAN) != B_OK) 534 break; 535 if (swap_data(B_UINT32_TYPE, &stl_header.apply_offset, sizeof(uint32), 536 B_SWAP_HOST_TO_BENDIAN) != B_OK) 537 break; 538 if (swap_data(B_UINT32_TYPE, &stl_header.apply_length, sizeof(uint32), 539 B_SWAP_HOST_TO_BENDIAN) != B_OK) 540 break; 541 542 // Here, you can see the structure of the styled text data by 543 // observing the order that the various structs and data are 544 // written to the stream 545 ssize_t amountWritten = 0; 546 amountWritten = intoStream->Write(&stm_header, kStreamHeaderSize); 547 if ((size_t) amountWritten != kStreamHeaderSize) 548 break; 549 amountWritten = intoStream->Write(&txt_header, kTextHeaderSize); 550 if ((size_t) amountWritten != kTextHeaderSize) 551 break; 552 amountWritten = intoStream->Write(pTextData, textLength); 553 if (amountWritten != textLength) 554 break; 555 amountWritten = intoStream->Write(&stl_header, kStyleHeaderSize); 556 if ((size_t) amountWritten != kStyleHeaderSize) 557 break; 558 amountWritten = intoStream->Write(pflatRunArray, flatRunArrayLength); 559 if (amountWritten != flatRunArrayLength) 560 break; 561 562 ok = true; 563 // gracefully break out of the loop 564 } 565 566 free(pflatRunArray); 567 BTextView::FreeRunArray(runArray); 568 569 return ok ? B_OK : B_ERROR; 570 } 571 572 573 /*! 574 \brief Writes the styled text data from \a view to the specified \a file. 575 576 This function is similar to PutStyledText() except that it 577 only writes styled text data to files and it puts the 578 plain text data in the file and stores the styled data as 579 the attribute "styles". 580 581 You can use PutStyledText() to write styled text data 582 to files, but it writes the data in a format that isn't 583 human readable. 584 585 \param view the view with the styled text 586 \param file the file where the styled text is written to 587 588 \return B_BAD_VALUE, if either parameter is NULL 589 B_OK, if successful, and any possible file error 590 if writing failed. 591 */ 592 status_t 593 BTranslationUtils::WriteStyledEditFile(BTextView* view, BFile* file) 594 { 595 if (view == NULL || file == NULL) 596 return B_BAD_VALUE; 597 598 int32 textLength = view->TextLength(); 599 if (textLength < 0) 600 return B_ERROR; 601 602 const char *text = view->Text(); 603 if (text == NULL && textLength != 0) 604 return B_ERROR; 605 606 // move to the start of the file if not already there 607 status_t result = file->Seek(0, SEEK_SET); 608 if (result != B_OK) 609 return result; 610 611 // Write plain text data to file 612 ssize_t bytesWritten = file->Write(text, textLength); 613 if (bytesWritten != textLength) 614 return B_ERROR; 615 616 // truncate any extra text 617 result = file->SetSize(textLength); 618 if (result != B_OK) 619 return result; 620 621 // Write attributes. We don't report an error anymore after this point, 622 // as attributes aren't that crucial - not all volumes support attributes. 623 // However, if writing one attribute fails, no further attributes are 624 // tried to be written. 625 626 BNodeInfo info(file); 627 char type[B_MIME_TYPE_LENGTH]; 628 if (info.GetType(type) != B_OK) { 629 // This file doesn't have a file type yet, so let's set it 630 result = info.SetType("text/plain"); 631 if (result < B_OK) 632 return B_OK; 633 } 634 635 // word wrap setting, turned on by default 636 int32 wordWrap = view->DoesWordWrap() ? 1 : 0; 637 bytesWritten = file->WriteAttr("wrap", B_INT32_TYPE, 0, 638 &wordWrap, sizeof(int32)); 639 if (bytesWritten != sizeof(int32)) 640 return B_OK; 641 642 // alignment, default is B_ALIGN_LEFT 643 int32 alignment = view->Alignment(); 644 bytesWritten = file->WriteAttr("alignment", B_INT32_TYPE, 0, 645 &alignment, sizeof(int32)); 646 if (bytesWritten != sizeof(int32)) 647 return B_OK; 648 649 // be:encoding, defaults to UTF-8 (65535) 650 // Note that the B_UNICODE_UTF8 constant is 0 and for some reason 651 // not appropriate for use here. 652 int32 encoding = 65535; 653 bytesWritten = file->WriteAttr("be:encoding", B_INT32_TYPE, 0, 654 &encoding, sizeof(int32)); 655 if (bytesWritten != sizeof(int32)) 656 return B_OK; 657 658 // Write text_run_array, ie. the styles of the text 659 660 text_run_array *runArray = view->RunArray(0, view->TextLength()); 661 if (runArray != NULL) { 662 int32 runArraySize = 0; 663 void *flattenedRunArray = BTextView::FlattenRunArray(runArray, &runArraySize); 664 if (flattenedRunArray != NULL) { 665 file->WriteAttr("styles", B_RAW_TYPE, 0, flattenedRunArray, 666 runArraySize); 667 } 668 669 free(flattenedRunArray); 670 BTextView::FreeRunArray(runArray); 671 } 672 673 return B_OK; 674 } 675 676 677 /*! 678 Each translator can have default settings, set by the 679 "translations" control panel. You can read these settings to 680 pass on to a translator using one of these functions. 681 682 \param forTranslator, the translator the settings are for 683 roster, the roster used to get the settings 684 685 \return BMessage of configuration data for forTranslator - you own 686 this message and have to free it when you're done with it. 687 \return NULL, if anything went wrong 688 */ 689 BMessage * 690 BTranslationUtils::GetDefaultSettings(translator_id forTranslator, 691 BTranslatorRoster *roster) 692 { 693 // Use default Translator if none is specified 694 if (roster == NULL) { 695 roster = BTranslatorRoster::Default(); 696 if (roster == NULL) 697 return NULL; 698 } 699 700 BMessage *message = new BMessage(); 701 if (message == NULL) 702 return NULL; 703 704 status_t result = roster->GetConfigurationMessage(forTranslator, message); 705 if (result != B_OK && result != B_NO_TRANSLATOR) { 706 // Be's version seems to just pass an empty BMessage 707 // in case of B_NO_TRANSLATOR, well, in some cases anyway 708 delete message; 709 return NULL; 710 } 711 712 return message; 713 } 714 715 716 // --------------------------------------------------------------- 717 // GetDefaultSettings 718 // 719 // Attempts to find the translator settings for 720 // the translator named kTranslatorName with a version of 721 // translatorVersion. 722 // 723 // Preconditions: 724 // 725 // Parameters: kTranslatorName, the name of the translator 726 // the settings are for 727 // translatorVersion, the version of the translator 728 // to retrieve 729 // 730 // Postconditions: 731 // 732 // Returns: NULL, if anything went wrong 733 // BMessage * of configuration data for kTranslatorName 734 // --------------------------------------------------------------- 735 BMessage * 736 BTranslationUtils::GetDefaultSettings(const char *kTranslatorName, 737 int32 translatorVersion) 738 { 739 BTranslatorRoster *roster = BTranslatorRoster::Default(); 740 translator_id *translators = NULL; 741 int32 numTranslators = 0; 742 if (roster == NULL 743 || roster->GetAllTranslators(&translators, &numTranslators) != B_OK) 744 return NULL; 745 746 // Cycle through all of the default translators 747 // looking for a translator that matches the name and version 748 // that I was given 749 BMessage *pMessage = NULL; 750 const char *currentTranName = NULL, *currentTranInfo = NULL; 751 int32 currentTranVersion = 0; 752 for (int i = 0; i < numTranslators; i++) { 753 754 if (roster->GetTranslatorInfo(translators[i], ¤tTranName, 755 ¤tTranInfo, ¤tTranVersion) == B_OK) { 756 757 if (currentTranVersion == translatorVersion 758 && strcmp(currentTranName, kTranslatorName) == 0) { 759 pMessage = GetDefaultSettings(translators[i], roster); 760 break; 761 } 762 } 763 } 764 765 delete[] translators; 766 return pMessage; 767 } 768 769 // --------------------------------------------------------------- 770 // AddTranslationItems 771 // 772 // Envious of that "Save As" menu in ShowImage? Well, you can have your own! 773 // AddTranslationItems will add menu items for all translations from the 774 // basic format you specify (B_TRANSLATOR_BITMAP, B_TRANSLATOR_TEXT etc). 775 // The translator ID and format constant chosen will be added to the message 776 // that is sent to you when the menu item is selected. 777 // 778 // The following code is a modified version of code 779 // written by Jon Watte from 780 // http://www.b500.com/bepage/TranslationKit2.html 781 // 782 // Preconditions: 783 // 784 // Parameters: intoMenu, the menu where the entries are created 785 // fromType, the type of translators to put on 786 // intoMenu 787 // kModel, the BMessage model for creating the menu 788 // if NULL, B_TRANSLATION_MENU is used 789 // kTranslationIdName, the name used for 790 // translator_id in the menuitem, 791 // if NULL, be:translator is used 792 // kTranslatorTypeName, the name used for 793 // output format id in the menuitem 794 // roster, BTranslatorRoster used to find translators 795 // if NULL, the default translators are used 796 // 797 // 798 // Postconditions: 799 // 800 // Returns: B_BAD_VALUE, if intoMenu is NULL 801 // B_OK, if successful 802 // error value if not successful 803 // --------------------------------------------------------------- 804 status_t 805 BTranslationUtils::AddTranslationItems(BMenu *intoMenu, uint32 fromType, 806 const BMessage *kModel, const char *kTranslatorIdName, 807 const char *kTranslatorTypeName, BTranslatorRoster *roster) 808 { 809 if (!intoMenu) 810 return B_BAD_VALUE; 811 812 if (!roster) 813 roster = BTranslatorRoster::Default(); 814 815 if (!kTranslatorIdName) 816 kTranslatorIdName = "be:translator"; 817 818 if (!kTranslatorTypeName) 819 kTranslatorTypeName = "be:type"; 820 821 translator_id * ids = NULL; 822 int32 count = 0; 823 status_t err = roster->GetAllTranslators(&ids, &count); 824 if (err < B_OK) 825 return err; 826 827 for (int tix = 0; tix < count; tix++) { 828 const translation_format *formats = NULL; 829 int32 numFormats = 0; 830 bool ok = false; 831 err = roster->GetInputFormats(ids[tix], &formats, &numFormats); 832 if (err == B_OK) { 833 for (int iix = 0; iix < numFormats; iix++) { 834 if (formats[iix].type == fromType) { 835 ok = true; 836 break; 837 } 838 } 839 } 840 if (!ok) 841 continue; 842 843 err = roster->GetOutputFormats(ids[tix], &formats, &numFormats); 844 if (err == B_OK) { 845 for (int oix = 0; oix < numFormats; oix++) { 846 if (formats[oix].type != fromType) { 847 BMessage *itemmsg; 848 if (kModel) 849 itemmsg = new BMessage(*kModel); 850 else 851 itemmsg = new BMessage(B_TRANSLATION_MENU); 852 itemmsg->AddInt32(kTranslatorIdName, ids[tix]); 853 itemmsg->AddInt32(kTranslatorTypeName, formats[oix].type); 854 intoMenu->AddItem( 855 new BMenuItem(formats[oix].name, itemmsg)); 856 } 857 } 858 } 859 } 860 861 delete[] ids; 862 return B_OK; 863 } 864