1 /* 2 * Copyright 2006-2011, Stephan Aßmus <superstippi@gmx.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 #include "MainWindow.h" 7 8 #include <new> 9 #include <stdio.h> 10 11 #include <Alert.h> 12 #include <Catalog.h> 13 #include <Clipboard.h> 14 #include <GridLayout.h> 15 #include <GroupLayout.h> 16 #include <GroupView.h> 17 #include <Directory.h> 18 #include <Entry.h> 19 #include <File.h> 20 #include <fs_attr.h> 21 #include <Locale.h> 22 #include <Menu.h> 23 #include <MenuBar.h> 24 #include <MenuItem.h> 25 #include <Message.h> 26 #include <Screen.h> 27 #include <ScrollView.h> 28 29 #include "support_ui.h" 30 31 #include "AddPathsCommand.h" 32 #include "AddShapesCommand.h" 33 #include "AddStylesCommand.h" 34 #include "AttributeSaver.h" 35 #include "BitmapExporter.h" 36 #include "BitmapSetSaver.h" 37 #include "CanvasView.h" 38 #include "CommandStack.h" 39 #include "CompoundCommand.h" 40 #include "CurrentColor.h" 41 #include "Document.h" 42 #include "FlatIconExporter.h" 43 #include "FlatIconFormat.h" 44 #include "FlatIconImporter.h" 45 #include "IconObjectListView.h" 46 #include "IconEditorApp.h" 47 #include "IconView.h" 48 #include "MessageExporter.h" 49 #include "MessageImporter.h" 50 #include "MessengerSaver.h" 51 #include "NativeSaver.h" 52 #include "PathListView.h" 53 #include "RDefExporter.h" 54 #include "ScrollView.h" 55 #include "SimpleFileSaver.h" 56 #include "ShapeListView.h" 57 #include "SourceExporter.h" 58 #include "StyleListView.h" 59 #include "StyleView.h" 60 #include "SVGExporter.h" 61 #include "SVGImporter.h" 62 #include "SwatchGroup.h" 63 #include "TransformerListView.h" 64 #include "TransformGradientBox.h" 65 #include "TransformShapesBox.h" 66 #include "Util.h" 67 68 // TODO: just for testing 69 #include "AffineTransformer.h" 70 #include "GradientTransformable.h" 71 #include "Icon.h" 72 #include "MultipleManipulatorState.h" 73 #include "PathManipulator.h" 74 #include "Shape.h" 75 #include "ShapeContainer.h" 76 #include "ShapeListView.h" 77 #include "StrokeTransformer.h" 78 #include "Style.h" 79 #include "StyleContainer.h" 80 #include "VectorPath.h" 81 82 #include "StyledTextImporter.h" 83 84 85 #undef B_TRANSLATE_CONTEXT 86 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Main" 87 88 89 using std::nothrow; 90 91 enum { 92 MSG_UNDO = 'undo', 93 MSG_REDO = 'redo', 94 MSG_UNDO_STACK_CHANGED = 'usch', 95 96 MSG_PATH_SELECTED = 'vpsl', 97 MSG_STYLE_SELECTED = 'stsl', 98 MSG_SHAPE_SELECTED = 'spsl', 99 100 MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh', 101 MSG_STYLE_RESET_TRANSFORMATION = 'rtst', 102 103 MSG_MOUSE_FILTER_MODE = 'mfmd', 104 105 MSG_RENAME_OBJECT = 'rnam', 106 }; 107 108 109 MainWindow::MainWindow(BRect frame, IconEditorApp* app, 110 const BMessage* settings) 111 : 112 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Icon-O-Matic"), 113 B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 114 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), 115 fApp(app), 116 fDocument(new Document(B_TRANSLATE("Untitled"))), 117 fCurrentColor(new CurrentColor()), 118 fIcon(NULL), 119 fMessageAfterSave(NULL) 120 { 121 _Init(); 122 123 RestoreSettings(settings); 124 } 125 126 127 MainWindow::~MainWindow() 128 { 129 delete fState; 130 131 SetIcon(NULL); 132 133 // Make sure there are no listeners attached to the document anymore. 134 while (BView* child = ChildAt(0L)) { 135 child->RemoveSelf(); 136 delete child; 137 } 138 139 fDocument->CommandStack()->RemoveObserver(this); 140 141 // NOTE: it is important that the GUI has been deleted 142 // at this point, so that all the listener/observer 143 // stuff is properly detached 144 delete fDocument; 145 146 delete fMessageAfterSave; 147 } 148 149 150 // #pragma mark - 151 152 153 void 154 MainWindow::MessageReceived(BMessage* message) 155 { 156 bool discard = false; 157 158 // Figure out if we need the write lock on the Document. For most 159 // messages we do, but exporting takes place in another thread and 160 // locking is taken care of there. 161 bool requiresWriteLock = true; 162 switch (message->what) { 163 case MSG_SAVE: 164 case MSG_EXPORT: 165 case MSG_SAVE_AS: 166 case MSG_EXPORT_AS: 167 requiresWriteLock = false; 168 break; 169 default: 170 break; 171 } 172 if (requiresWriteLock && !fDocument->WriteLock()) { 173 BWindow::MessageReceived(message); 174 return; 175 } 176 177 if (message->WasDropped()) { 178 const rgb_color* color; 179 int32 length; 180 // create styles from dropped colors 181 for (int32 i = 0; message->FindData("RGBColor", B_RGB_COLOR_TYPE, i, 182 (const void**)&color, &length) == B_OK; i++) { 183 if (length != sizeof(rgb_color)) 184 continue; 185 char name[30]; 186 sprintf(name, 187 B_TRANSLATE_WITH_CONTEXT("Color (#%02x%02x%02x)", 188 "Style name after dropping a color"), 189 color->red, color->green, color->blue); 190 Style* style = new (nothrow) Style(*color); 191 style->SetName(name); 192 Style* styles[1] = { style }; 193 AddStylesCommand* styleCommand = new (nothrow) AddStylesCommand( 194 fDocument->Icon()->Styles(), styles, 1, 195 fDocument->Icon()->Styles()->CountStyles()); 196 fDocument->CommandStack()->Perform(styleCommand); 197 // don't handle anything else, 198 // or we might paste the clipboard on B_PASTE 199 discard = true; 200 } 201 } 202 203 switch (message->what) { 204 205 case B_REFS_RECEIVED: 206 case B_SIMPLE_DATA: 207 message->what = B_REFS_RECEIVED; 208 if (modifiers() & B_SHIFT_KEY) { 209 message->AddBool("append", true); 210 message->AddPointer("window", this); 211 } 212 be_app->PostMessage(message); 213 break; 214 215 case B_PASTE: 216 case B_MIME_DATA: 217 { 218 BMessage* clip = message; 219 status_t err; 220 221 if (discard) 222 break; 223 224 if (message->what == B_PASTE) { 225 if (!be_clipboard->Lock()) 226 break; 227 clip = be_clipboard->Data(); 228 } 229 230 if (!clip || !clip->HasData("text/plain", B_MIME_TYPE)) { 231 if (message->what == B_PASTE) 232 be_clipboard->Unlock(); 233 break; 234 } 235 236 Icon* icon = new (std::nothrow) Icon(*fDocument->Icon()); 237 if (icon != NULL) { 238 StyledTextImporter importer; 239 err = importer.Import(icon, clip); 240 if (err >= B_OK) { 241 AutoWriteLocker locker(fDocument); 242 243 SetIcon(NULL); 244 245 // incorporate the loaded icon into the document 246 // (either replace it or append to it) 247 fDocument->MakeEmpty(false); 248 // if append, the document savers are preserved 249 fDocument->SetIcon(icon); 250 SetIcon(icon); 251 } 252 } 253 254 if (message->what == B_PASTE) 255 be_clipboard->Unlock(); 256 break; 257 } 258 259 case MSG_SAVE: 260 case MSG_EXPORT: 261 { 262 DocumentSaver* saver; 263 if (message->what == MSG_SAVE) 264 saver = fDocument->NativeSaver(); 265 else 266 saver = fDocument->ExportSaver(); 267 if (saver != NULL) { 268 saver->Save(fDocument); 269 _PickUpActionBeforeSave(); 270 break; 271 } // else fall through 272 } 273 case MSG_SAVE_AS: 274 case MSG_EXPORT_AS: 275 { 276 int32 exportMode; 277 if (message->FindInt32("export mode", &exportMode) < B_OK) 278 exportMode = EXPORT_MODE_MESSAGE; 279 entry_ref ref; 280 const char* name; 281 if (message->FindRef("directory", &ref) == B_OK 282 && message->FindString("name", &name) == B_OK) { 283 // this message comes from the file panel 284 BDirectory dir(&ref); 285 BEntry entry; 286 if (dir.InitCheck() >= B_OK 287 && entry.SetTo(&dir, name, true) >= B_OK 288 && entry.GetRef(&ref) >= B_OK) { 289 290 // create the document saver and remember it for later 291 DocumentSaver* saver = _CreateSaver(ref, exportMode); 292 if (saver != NULL) { 293 if (fDocument->WriteLock()) { 294 if (exportMode == EXPORT_MODE_MESSAGE) 295 fDocument->SetNativeSaver(saver); 296 else 297 fDocument->SetExportSaver(saver); 298 _UpdateWindowTitle(); 299 fDocument->WriteUnlock(); 300 } 301 saver->Save(fDocument); 302 _PickUpActionBeforeSave(); 303 } 304 } 305 // TODO: ... 306 // _SyncPanels(fSavePanel, fOpenPanel); 307 } else { 308 // configure the file panel 309 uint32 requestRefWhat = MSG_SAVE_AS; 310 bool isExportMode = message->what == MSG_EXPORT_AS 311 || message->what == MSG_EXPORT; 312 if (isExportMode) 313 requestRefWhat = MSG_EXPORT_AS; 314 const char* saveText = _FileName(isExportMode); 315 316 BMessage requestRef(requestRefWhat); 317 if (saveText != NULL) 318 requestRef.AddString("save text", saveText); 319 requestRef.AddMessenger("target", BMessenger(this, this)); 320 be_app->PostMessage(&requestRef); 321 } 322 break; 323 } 324 325 case MSG_UNDO: 326 fDocument->CommandStack()->Undo(); 327 break; 328 case MSG_REDO: 329 fDocument->CommandStack()->Redo(); 330 break; 331 case MSG_UNDO_STACK_CHANGED: 332 { 333 // relable Undo item and update enabled status 334 BString label(B_TRANSLATE("Undo")); 335 fUndoMI->SetEnabled(fDocument->CommandStack()->GetUndoName(label)); 336 if (fUndoMI->IsEnabled()) 337 fUndoMI->SetLabel(label.String()); 338 else { 339 fUndoMI->SetLabel(B_TRANSLATE_WITH_CONTEXT("<nothing to undo>", 340 "Icon-O-Matic-Menu-Edit")); 341 } 342 343 // relable Redo item and update enabled status 344 label.SetTo(B_TRANSLATE("Redo")); 345 fRedoMI->SetEnabled(fDocument->CommandStack()->GetRedoName(label)); 346 if (fRedoMI->IsEnabled()) 347 fRedoMI->SetLabel(label.String()); 348 else { 349 fRedoMI->SetLabel(B_TRANSLATE_WITH_CONTEXT("<nothing to redo>", 350 "Icon-O-Matic-Menu-Edit")); 351 } 352 break; 353 } 354 355 case MSG_MOUSE_FILTER_MODE: 356 { 357 uint32 mode; 358 if (message->FindInt32("mode", (int32*)&mode) == B_OK) 359 fCanvasView->SetMouseFilterMode(mode); 360 break; 361 } 362 363 case MSG_ADD_SHAPE: { 364 AddStylesCommand* styleCommand = NULL; 365 Style* style = NULL; 366 if (message->HasBool("style")) { 367 new_style(fCurrentColor->Color(), 368 fDocument->Icon()->Styles(), &style, &styleCommand); 369 } 370 371 AddPathsCommand* pathCommand = NULL; 372 VectorPath* path = NULL; 373 if (message->HasBool("path")) { 374 new_path(fDocument->Icon()->Paths(), &path, &pathCommand); 375 } 376 377 if (!style) { 378 // use current or first style 379 int32 currentStyle = fStyleListView->CurrentSelection(0); 380 style = fDocument->Icon()->Styles()->StyleAt(currentStyle); 381 if (!style) 382 style = fDocument->Icon()->Styles()->StyleAt(0); 383 } 384 385 Shape* shape = new (nothrow) Shape(style); 386 Shape* shapes[1]; 387 shapes[0] = shape; 388 AddShapesCommand* shapeCommand = new (nothrow) AddShapesCommand( 389 fDocument->Icon()->Shapes(), shapes, 1, 390 fDocument->Icon()->Shapes()->CountShapes(), 391 fDocument->Selection()); 392 393 if (path && shape) 394 shape->Paths()->AddPath(path); 395 396 ::Command* command = NULL; 397 if (styleCommand || pathCommand) { 398 if (styleCommand && pathCommand) { 399 Command** commands = new Command*[3]; 400 commands[0] = styleCommand; 401 commands[1] = pathCommand; 402 commands[2] = shapeCommand; 403 command = new CompoundCommand(commands, 3, 404 B_TRANSLATE_WITH_CONTEXT("Add shape with path & style", 405 "Icon-O-Matic-Menu-Shape"), 406 0); 407 } else if (styleCommand) { 408 Command** commands = new Command*[2]; 409 commands[0] = styleCommand; 410 commands[1] = shapeCommand; 411 command = new CompoundCommand(commands, 2, 412 B_TRANSLATE_WITH_CONTEXT("Add shape with style", 413 "Icon-O-Matic-Menu-Shape"), 414 0); 415 } else { 416 Command** commands = new Command*[2]; 417 commands[0] = pathCommand; 418 commands[1] = shapeCommand; 419 command = new CompoundCommand(commands, 2, 420 B_TRANSLATE_WITH_CONTEXT("Add shape with path", 421 "Icon-O-Matic-Menu-Shape"), 422 0); 423 } 424 } else { 425 command = shapeCommand; 426 } 427 fDocument->CommandStack()->Perform(command); 428 break; 429 } 430 431 // TODO: listen to selection in CanvasView to add a manipulator 432 case MSG_PATH_SELECTED: { 433 VectorPath* path; 434 if (message->FindPointer("path", (void**)&path) < B_OK) 435 path = NULL; 436 437 fPathListView->SetCurrentShape(NULL); 438 fStyleListView->SetCurrentShape(NULL); 439 fTransformerListView->SetShape(NULL); 440 441 fState->DeleteManipulators(); 442 if (fDocument->Icon()->Paths()->HasPath(path)) { 443 PathManipulator* pathManipulator = new (nothrow) PathManipulator(path); 444 fState->AddManipulator(pathManipulator); 445 } 446 break; 447 } 448 case MSG_STYLE_SELECTED: 449 case MSG_STYLE_TYPE_CHANGED: { 450 Style* style; 451 if (message->FindPointer("style", (void**)&style) < B_OK) 452 style = NULL; 453 if (!fDocument->Icon()->Styles()->HasStyle(style)) 454 style = NULL; 455 456 fStyleView->SetStyle(style); 457 fPathListView->SetCurrentShape(NULL); 458 fStyleListView->SetCurrentShape(NULL); 459 fTransformerListView->SetShape(NULL); 460 461 fState->DeleteManipulators(); 462 Gradient* gradient = style ? style->Gradient() : NULL; 463 if (gradient != NULL) { 464 TransformGradientBox* transformBox 465 = new (nothrow) TransformGradientBox(fCanvasView, gradient, NULL); 466 fState->AddManipulator(transformBox); 467 } 468 break; 469 } 470 case MSG_SHAPE_SELECTED: { 471 Shape* shape; 472 if (message->FindPointer("shape", (void**)&shape) < B_OK) 473 shape = NULL; 474 if (!fIcon || !fIcon->Shapes()->HasShape(shape)) 475 shape = NULL; 476 477 fPathListView->SetCurrentShape(shape); 478 fStyleListView->SetCurrentShape(shape); 479 fTransformerListView->SetShape(shape); 480 481 BList selectedShapes; 482 ShapeContainer* shapes = fDocument->Icon()->Shapes(); 483 int32 count = shapes->CountShapes(); 484 for (int32 i = 0; i < count; i++) { 485 shape = shapes->ShapeAtFast(i); 486 if (shape->IsSelected()) { 487 selectedShapes.AddItem((void*)shape); 488 } 489 } 490 491 fState->DeleteManipulators(); 492 if (selectedShapes.CountItems() > 0) { 493 TransformShapesBox* transformBox = new (nothrow) TransformShapesBox( 494 fCanvasView, 495 (const Shape**)selectedShapes.Items(), 496 selectedShapes.CountItems()); 497 fState->AddManipulator(transformBox); 498 } 499 break; 500 } 501 case MSG_RENAME_OBJECT: 502 fPropertyListView->FocusNameProperty(); 503 break; 504 505 default: 506 BWindow::MessageReceived(message); 507 } 508 509 if (requiresWriteLock) 510 fDocument->WriteUnlock(); 511 } 512 513 514 bool 515 MainWindow::QuitRequested() 516 { 517 if (!_CheckSaveIcon(CurrentMessage())) 518 return false; 519 520 BMessage message(MSG_WINDOW_CLOSED); 521 522 BMessage settings; 523 StoreSettings(&settings); 524 message.AddMessage("settings", &settings); 525 message.AddRect("window frame", Frame()); 526 527 be_app->PostMessage(&message); 528 529 return true; 530 } 531 532 533 void 534 MainWindow::WorkspaceActivated(int32 workspace, bool active) 535 { 536 BWindow::WorkspaceActivated(workspace, active); 537 538 // NOTE: hack to workaround buggy BScreen::DesktopColor() on R5 539 540 uint32 workspaces = Workspaces(); 541 if (!active || ((1 << workspace) & workspaces) == 0) 542 return; 543 544 WorkspacesChanged(workspaces, workspaces); 545 } 546 547 548 void 549 MainWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) 550 { 551 if (oldWorkspaces != newWorkspaces) 552 BWindow::WorkspacesChanged(oldWorkspaces, newWorkspaces); 553 554 BScreen screen(this); 555 556 // Unfortunately, this is buggy on R5: screen.DesktopColor() 557 // as well as ui_color(B_DESKTOP_COLOR) return the color 558 // of the *active* screen, not the one on which this window 559 // is. So this trick only works when you drag this window 560 // from another workspace onto the current workspace, not 561 // when you drag the window from the current workspace onto 562 // another workspace and then switch to the other workspace. 563 564 fIconPreview32Desktop->SetIconBGColor(screen.DesktopColor()); 565 fIconPreview64->SetIconBGColor(screen.DesktopColor()); 566 } 567 568 569 // #pragma mark - 570 571 572 void 573 MainWindow::ObjectChanged(const Observable* object) 574 { 575 if (!fDocument || !fDocument->ReadLock()) 576 return; 577 578 if (object == fDocument->CommandStack()) 579 PostMessage(MSG_UNDO_STACK_CHANGED); 580 581 fDocument->ReadUnlock(); 582 } 583 584 585 // #pragma mark - 586 587 588 void 589 MainWindow::MakeEmpty() 590 { 591 fPathListView->SetCurrentShape(NULL); 592 fStyleListView->SetCurrentShape(NULL); 593 fStyleView->SetStyle(NULL); 594 595 fTransformerListView->SetShape(NULL); 596 597 fState->DeleteManipulators(); 598 } 599 600 601 void 602 MainWindow::Open(const entry_ref& ref, bool append) 603 { 604 BFile file(&ref, B_READ_ONLY); 605 if (file.InitCheck() < B_OK) 606 return; 607 608 Icon* icon; 609 if (append) 610 icon = new (nothrow) Icon(*fDocument->Icon()); 611 else 612 icon = new (nothrow) Icon(); 613 614 if (icon == NULL) { 615 // TODO: Report error to user. 616 return; 617 } 618 619 enum { 620 REF_NONE = 0, 621 REF_MESSAGE, 622 REF_FLAT, 623 REF_FLAT_ATTR, 624 REF_SVG 625 }; 626 uint32 refMode = REF_NONE; 627 628 // try different file types 629 FlatIconImporter flatImporter; 630 status_t ret = flatImporter.Import(icon, &file); 631 if (ret >= B_OK) { 632 refMode = REF_FLAT; 633 } else { 634 file.Seek(0, SEEK_SET); 635 MessageImporter msgImporter; 636 ret = msgImporter.Import(icon, &file); 637 if (ret >= B_OK) { 638 refMode = REF_MESSAGE; 639 } else { 640 file.Seek(0, SEEK_SET); 641 SVGImporter svgImporter; 642 ret = svgImporter.Import(icon, &ref); 643 if (ret >= B_OK) { 644 refMode = REF_SVG; 645 } else { 646 // fall back to flat icon format but use the icon attribute 647 ret = B_OK; 648 attr_info attrInfo; 649 if (file.GetAttrInfo(kVectorAttrNodeName, &attrInfo) == B_OK) { 650 if (attrInfo.type != B_VECTOR_ICON_TYPE) 651 ret = B_ERROR; 652 // If the attribute is there, we must succeed in reading 653 // an icon! Otherwise we may overwrite an existing icon 654 // when the user saves. 655 uint8* buffer = NULL; 656 if (ret == B_OK) { 657 buffer = new(nothrow) uint8[attrInfo.size]; 658 if (buffer == NULL) 659 ret = B_NO_MEMORY; 660 } 661 if (ret == B_OK) { 662 ssize_t bytesRead = file.ReadAttr(kVectorAttrNodeName, 663 B_VECTOR_ICON_TYPE, 0, buffer, attrInfo.size); 664 if (bytesRead != (ssize_t)attrInfo.size) { 665 ret = bytesRead < 0 ? (status_t)bytesRead 666 : B_IO_ERROR; 667 } 668 } 669 if (ret == B_OK) { 670 ret = flatImporter.Import(icon, buffer, attrInfo.size); 671 if (ret == B_OK) 672 refMode = REF_FLAT_ATTR; 673 } 674 675 delete[] buffer; 676 } else { 677 // If there is no icon attribute, simply fall back 678 // to creating an icon for this file. TODO: We may or may 679 // not want to display an alert asking the user if that is 680 // what he wants to do. 681 refMode = REF_FLAT_ATTR; 682 } 683 } 684 } 685 } 686 687 if (ret < B_OK) { 688 // inform user of failure at this point 689 BString helper(B_TRANSLATE("Opening the document failed!")); 690 helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); 691 BAlert* alert = new BAlert( 692 B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), 693 helper.String(), 694 B_TRANSLATE_WITH_CONTEXT("Bummer", 695 "Cancel button - error alert"), 696 NULL, NULL); 697 // launch alert asynchronously 698 alert->Go(NULL); 699 700 delete icon; 701 return; 702 } 703 704 AutoWriteLocker locker(fDocument); 705 706 // incorporate the loaded icon into the document 707 // (either replace it or append to it) 708 fDocument->MakeEmpty(!append); 709 // if append, the document savers are preserved 710 fDocument->SetIcon(icon); 711 if (!append) { 712 // document got replaced, but we have at 713 // least one ref already 714 switch (refMode) { 715 case REF_MESSAGE: 716 fDocument->SetNativeSaver(new NativeSaver(ref)); 717 break; 718 case REF_FLAT: 719 fDocument->SetExportSaver( 720 new SimpleFileSaver(new FlatIconExporter(), ref)); 721 break; 722 case REF_FLAT_ATTR: 723 fDocument->SetNativeSaver( 724 new AttributeSaver(ref, kVectorAttrNodeName)); 725 break; 726 case REF_SVG: 727 fDocument->SetExportSaver( 728 new SimpleFileSaver(new SVGExporter(), ref)); 729 break; 730 } 731 } 732 733 locker.Unlock(); 734 735 SetIcon(icon); 736 737 _UpdateWindowTitle(); 738 } 739 740 741 void 742 MainWindow::Open(const BMessenger& externalObserver, const uint8* data, 743 size_t size) 744 { 745 if (!_CheckSaveIcon(CurrentMessage())) 746 return; 747 748 if (!externalObserver.IsValid()) 749 return; 750 751 Icon* icon = new (nothrow) Icon(); 752 if (!icon) 753 return; 754 755 if (data && size > 0) { 756 // try to open the icon from the provided data 757 FlatIconImporter flatImporter; 758 status_t ret = flatImporter.Import(icon, const_cast<uint8*>(data), 759 size); 760 // NOTE: the const_cast is a bit ugly, but no harm is done 761 // the reason is that the LittleEndianBuffer knows read and write 762 // mode, in this case it is used read-only, and it does not assume 763 // ownership of the buffer 764 765 if (ret < B_OK) { 766 // inform user of failure at this point 767 BString helper(B_TRANSLATE("Opening the icon failed!")); 768 helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); 769 BAlert* alert = new BAlert( 770 B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), 771 helper.String(), 772 B_TRANSLATE_WITH_CONTEXT("Bummer", 773 "Cancel button - error alert"), 774 NULL, NULL); 775 // launch alert asynchronously 776 alert->Go(NULL); 777 778 delete icon; 779 return; 780 } 781 } 782 783 AutoWriteLocker locker(fDocument); 784 785 SetIcon(NULL); 786 787 // incorporate the loaded icon into the document 788 // (either replace it or append to it) 789 fDocument->MakeEmpty(); 790 fDocument->SetIcon(icon); 791 792 fDocument->SetNativeSaver(new MessengerSaver(externalObserver)); 793 794 locker.Unlock(); 795 796 SetIcon(icon); 797 } 798 799 800 void 801 MainWindow::SetIcon(Icon* icon) 802 { 803 if (fIcon == icon) 804 return; 805 806 Icon* oldIcon = fIcon; 807 808 fIcon = icon; 809 810 if (fIcon != NULL) 811 fIcon->Acquire(); 812 else 813 MakeEmpty(); 814 815 fCanvasView->SetIcon(fIcon); 816 817 fPathListView->SetPathContainer(fIcon != NULL ? fIcon->Paths() : NULL); 818 fPathListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); 819 820 fStyleListView->SetStyleContainer(fIcon != NULL ? fIcon->Styles() : NULL); 821 fStyleListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); 822 823 fShapeListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); 824 825 // icon previews 826 fIconPreview16Folder->SetIcon(fIcon); 827 fIconPreview16Menu->SetIcon(fIcon); 828 fIconPreview32Folder->SetIcon(fIcon); 829 fIconPreview32Desktop->SetIcon(fIcon); 830 // fIconPreview48->SetIcon(fIcon); 831 fIconPreview64->SetIcon(fIcon); 832 833 // keep this last 834 if (oldIcon != NULL) 835 oldIcon->Release(); 836 } 837 838 839 // #pragma mark - 840 841 842 void 843 MainWindow::StoreSettings(BMessage* archive) 844 { 845 if (archive->ReplaceUInt32("mouse filter mode", 846 fCanvasView->MouseFilterMode()) != B_OK) { 847 archive->AddUInt32("mouse filter mode", 848 fCanvasView->MouseFilterMode()); 849 } 850 } 851 852 853 void 854 MainWindow::RestoreSettings(const BMessage* archive) 855 { 856 uint32 mouseFilterMode; 857 if (archive->FindUInt32("mouse filter mode", &mouseFilterMode) == B_OK) { 858 fCanvasView->SetMouseFilterMode(mouseFilterMode); 859 fMouseFilterOffMI->SetMarked(mouseFilterMode == SNAPPING_OFF); 860 fMouseFilter64MI->SetMarked(mouseFilterMode == SNAPPING_64); 861 fMouseFilter32MI->SetMarked(mouseFilterMode == SNAPPING_32); 862 fMouseFilter16MI->SetMarked(mouseFilterMode == SNAPPING_16); 863 } 864 } 865 866 867 // #pragma mark - 868 869 870 void 871 MainWindow::_Init() 872 { 873 // create the GUI 874 _CreateGUI(); 875 876 // fix up scrollbar layout in listviews 877 _ImproveScrollBarLayout(fPathListView); 878 _ImproveScrollBarLayout(fStyleListView); 879 _ImproveScrollBarLayout(fShapeListView); 880 _ImproveScrollBarLayout(fTransformerListView); 881 882 // TODO: move this to CanvasView? 883 fState = new MultipleManipulatorState(fCanvasView); 884 fCanvasView->SetState(fState); 885 886 fCanvasView->SetCatchAllEvents(true); 887 fCanvasView->SetCommandStack(fDocument->CommandStack()); 888 fCanvasView->SetMouseFilterMode(SNAPPING_64); 889 fMouseFilter64MI->SetMarked(true); 890 // fCanvasView->SetSelection(fDocument->Selection()); 891 892 fPathListView->SetMenu(fPathMenu); 893 fPathListView->SetCommandStack(fDocument->CommandStack()); 894 fPathListView->SetSelection(fDocument->Selection()); 895 896 fStyleListView->SetMenu(fStyleMenu); 897 fStyleListView->SetCommandStack(fDocument->CommandStack()); 898 fStyleListView->SetSelection(fDocument->Selection()); 899 fStyleListView->SetCurrentColor(fCurrentColor); 900 901 fStyleView->SetCommandStack(fDocument->CommandStack()); 902 fStyleView->SetCurrentColor(fCurrentColor); 903 904 fShapeListView->SetMenu(fShapeMenu); 905 fShapeListView->SetCommandStack(fDocument->CommandStack()); 906 fShapeListView->SetSelection(fDocument->Selection()); 907 908 fTransformerListView->SetMenu(fTransformerMenu); 909 fTransformerListView->SetCommandStack(fDocument->CommandStack()); 910 fTransformerListView->SetSelection(fDocument->Selection()); 911 912 fPropertyListView->SetCommandStack(fDocument->CommandStack()); 913 fPropertyListView->SetSelection(fDocument->Selection()); 914 fPropertyListView->SetMenu(fPropertyMenu); 915 916 fDocument->CommandStack()->AddObserver(this); 917 918 fSwatchGroup->SetCurrentColor(fCurrentColor); 919 920 SetIcon(fDocument->Icon()); 921 922 AddShortcut('Y', 0, new BMessage(MSG_UNDO)); 923 AddShortcut('Y', B_SHIFT_KEY, new BMessage(MSG_REDO)); 924 AddShortcut('E', 0, new BMessage(MSG_RENAME_OBJECT)); 925 } 926 927 928 void 929 MainWindow::_CreateGUI() 930 { 931 SetLayout(new BGroupLayout(B_HORIZONTAL)); 932 933 BGridLayout* layout = new BGridLayout(); 934 layout->SetSpacing(0, 0); 935 BView* rootView = new BView("root view", 0, layout); 936 AddChild(rootView); 937 rootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 938 939 BGroupView* leftTopView = new BGroupView(B_VERTICAL, 0); 940 layout->AddView(leftTopView, 0, 0); 941 942 // views along the left side 943 leftTopView->AddChild(_CreateMenuBar()); 944 945 float splitWidth = 13 * be_plain_font->Size(); 946 BSize minSize = leftTopView->MinSize(); 947 splitWidth = std::max(splitWidth, minSize.width); 948 leftTopView->SetExplicitMaxSize(BSize(splitWidth, B_SIZE_UNSET)); 949 leftTopView->SetExplicitMinSize(BSize(splitWidth, B_SIZE_UNSET)); 950 951 BGroupView* iconPreviews = new BGroupView(B_HORIZONTAL); 952 iconPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 953 iconPreviews->GroupLayout()->SetSpacing(5); 954 955 // icon previews 956 fIconPreview16Folder = new IconView(BRect(0, 0, 15, 15), 957 "icon preview 16 folder"); 958 fIconPreview16Menu = new IconView(BRect(0, 0, 15, 15), 959 "icon preview 16 menu"); 960 fIconPreview16Menu->SetLowColor(ui_color(B_MENU_BACKGROUND_COLOR)); 961 962 fIconPreview32Folder = new IconView(BRect(0, 0, 31, 31), 963 "icon preview 32 folder"); 964 fIconPreview32Desktop = new IconView(BRect(0, 0, 31, 31), 965 "icon preview 32 desktop"); 966 fIconPreview32Desktop->SetLowColor(ui_color(B_DESKTOP_COLOR)); 967 968 fIconPreview64 = new IconView(BRect(0, 0, 63, 63), "icon preview 64"); 969 fIconPreview64->SetLowColor(ui_color(B_DESKTOP_COLOR)); 970 971 972 BGroupView* smallPreviews = new BGroupView(B_VERTICAL); 973 smallPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 974 smallPreviews->GroupLayout()->SetSpacing(5); 975 976 smallPreviews->AddChild(fIconPreview16Folder); 977 smallPreviews->AddChild(fIconPreview16Menu); 978 979 BGroupView* mediumPreviews = new BGroupView(B_VERTICAL); 980 mediumPreviews->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 981 mediumPreviews->GroupLayout()->SetSpacing(5); 982 983 mediumPreviews->AddChild(fIconPreview32Folder); 984 mediumPreviews->AddChild(fIconPreview32Desktop); 985 986 // iconPreviews->AddChild(fIconPreview48); 987 988 iconPreviews->AddChild(smallPreviews); 989 iconPreviews->AddChild(mediumPreviews); 990 iconPreviews->AddChild(fIconPreview64); 991 iconPreviews->SetExplicitMaxSize(BSize(B_SIZE_UNSET, B_SIZE_UNLIMITED)); 992 993 leftTopView->AddChild(iconPreviews); 994 995 996 BGroupView* leftSideView = new BGroupView(B_VERTICAL, 0); 997 layout->AddView(leftSideView, 0, 1); 998 leftSideView->SetExplicitMaxSize(BSize(splitWidth, B_SIZE_UNSET)); 999 1000 // path menu and list view 1001 BMenuBar* menuBar = new BMenuBar("path menu bar"); 1002 menuBar->AddItem(fPathMenu); 1003 leftSideView->AddChild(menuBar); 1004 1005 fPathListView = new PathListView(BRect(0, 0, splitWidth, 100), 1006 "path list view", new BMessage(MSG_PATH_SELECTED), this); 1007 1008 BView* scrollView = new BScrollView("path list scroll view", 1009 fPathListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER); 1010 leftSideView->AddChild(scrollView); 1011 1012 // shape list view 1013 menuBar = new BMenuBar("shape menu bar"); 1014 menuBar->AddItem(fShapeMenu); 1015 leftSideView->AddChild(menuBar); 1016 1017 fShapeListView = new ShapeListView(BRect(0, 0, splitWidth, 100), 1018 "shape list view", new BMessage(MSG_SHAPE_SELECTED), this); 1019 scrollView = new BScrollView("shape list scroll view", 1020 fShapeListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER); 1021 leftSideView->AddChild(scrollView); 1022 1023 // transformer list view 1024 menuBar = new BMenuBar("transformer menu bar"); 1025 menuBar->AddItem(fTransformerMenu); 1026 leftSideView->AddChild(menuBar); 1027 1028 fTransformerListView = new TransformerListView(BRect(0, 0, splitWidth, 100), 1029 "transformer list view"); 1030 scrollView = new BScrollView("transformer list scroll view", 1031 fTransformerListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER); 1032 leftSideView->AddChild(scrollView); 1033 1034 // property list view 1035 menuBar = new BMenuBar("property menu bar"); 1036 menuBar->AddItem(fPropertyMenu); 1037 leftSideView->AddChild(menuBar); 1038 1039 fPropertyListView = new IconObjectListView(); 1040 1041 // scroll view around property list view 1042 ScrollView* propScrollView = new ScrollView(fPropertyListView, 1043 SCROLL_VERTICAL, BRect(0, 0, splitWidth, 100), "property scroll view", 1044 B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER, 1045 BORDER_RIGHT); 1046 leftSideView->AddChild(propScrollView); 1047 1048 BGroupLayout* topSide = new BGroupLayout(B_HORIZONTAL); 1049 topSide->SetSpacing(0); 1050 BView* topSideView = new BView("top side view", 0, topSide); 1051 layout->AddView(topSideView, 1, 0); 1052 1053 // canvas view 1054 BRect canvasBounds = BRect(0, 0, 200, 200); 1055 fCanvasView = new CanvasView(canvasBounds); 1056 1057 // scroll view around canvas view 1058 canvasBounds.bottom += B_H_SCROLL_BAR_HEIGHT; 1059 canvasBounds.right += B_V_SCROLL_BAR_WIDTH; 1060 ScrollView* canvasScrollView = new ScrollView(fCanvasView, SCROLL_VERTICAL 1061 | SCROLL_HORIZONTAL | SCROLL_VISIBLE_RECT_IS_CHILD_BOUNDS, 1062 canvasBounds, "canvas scroll view", B_FOLLOW_NONE, 1063 B_WILL_DRAW | B_FRAME_EVENTS, B_NO_BORDER); 1064 layout->AddView(canvasScrollView, 1, 1); 1065 1066 // views along the top 1067 1068 BGroupLayout* styleGroup = new BGroupLayout(B_VERTICAL, 0); 1069 BView* styleGroupView = new BView("style group", 0, styleGroup); 1070 topSide->AddView(styleGroupView); 1071 1072 // style list view 1073 menuBar = new BMenuBar("style menu bar"); 1074 menuBar->AddItem(fStyleMenu); 1075 styleGroup->AddView(menuBar); 1076 1077 fStyleListView = new StyleListView(BRect(0, 0, splitWidth, 100), 1078 "style list view", new BMessage(MSG_STYLE_SELECTED), this); 1079 scrollView = new BScrollView("style list scroll view", fStyleListView, 1080 B_FOLLOW_NONE, 0, false, true, B_NO_BORDER); 1081 scrollView->SetExplicitMaxSize(BSize(splitWidth, B_SIZE_UNLIMITED)); 1082 styleGroup->AddView(scrollView); 1083 1084 // style view 1085 fStyleView = new StyleView(BRect(0, 0, 200, 100)); 1086 topSide->AddView(fStyleView); 1087 1088 // swatch group 1089 BGroupLayout* swatchGroup = new BGroupLayout(B_VERTICAL); 1090 swatchGroup->SetSpacing(0); 1091 BView* swatchGroupView = new BView("swatch group", 0, swatchGroup); 1092 topSide->AddView(swatchGroupView); 1093 1094 menuBar = new BMenuBar("swatches menu bar"); 1095 menuBar->AddItem(fSwatchMenu); 1096 swatchGroup->AddView(menuBar); 1097 1098 fSwatchGroup = new SwatchGroup(BRect(0, 0, 100, 100)); 1099 swatchGroup->AddView(fSwatchGroup); 1100 1101 swatchGroupView->SetExplicitMaxSize(swatchGroupView->MinSize()); 1102 1103 // make sure the top side has fixed height 1104 topSideView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1105 swatchGroupView->MinSize().height)); 1106 } 1107 1108 BMenuBar* 1109 MainWindow::_CreateMenuBar() 1110 { 1111 BMenuBar* menuBar = new BMenuBar("main menu"); 1112 1113 1114 #undef B_TRANSLATE_CONTEXT 1115 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Menus" 1116 1117 1118 BMenu* fileMenu = new BMenu(B_TRANSLATE("File")); 1119 BMenu* editMenu = new BMenu(B_TRANSLATE("Edit")); 1120 BMenu* settingsMenu = new BMenu(B_TRANSLATE("Options")); 1121 fPathMenu = new BMenu(B_TRANSLATE("Path")); 1122 fStyleMenu = new BMenu(B_TRANSLATE("Style")); 1123 fShapeMenu = new BMenu(B_TRANSLATE("Shape")); 1124 fTransformerMenu = new BMenu(B_TRANSLATE("Transformer")); 1125 fPropertyMenu = new BMenu(B_TRANSLATE("Properties")); 1126 fSwatchMenu = new BMenu(B_TRANSLATE("Swatches")); 1127 1128 menuBar->AddItem(fileMenu); 1129 menuBar->AddItem(editMenu); 1130 menuBar->AddItem(settingsMenu); 1131 1132 1133 // File 1134 #undef B_TRANSLATE_CONTEXT 1135 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Menu-File" 1136 1137 1138 BMenuItem* item = new BMenuItem(B_TRANSLATE("New"), 1139 new BMessage(MSG_NEW), 'N'); 1140 fileMenu->AddItem(item); 1141 item->SetTarget(be_app); 1142 item = new BMenuItem(B_TRANSLATE("Open"B_UTF8_ELLIPSIS), 1143 new BMessage(MSG_OPEN), 'O'); 1144 fileMenu->AddItem(item); 1145 item->SetTarget(be_app); 1146 BMessage* appendMessage = new BMessage(MSG_APPEND); 1147 appendMessage->AddPointer("window", this); 1148 item = new BMenuItem(B_TRANSLATE("Append"B_UTF8_ELLIPSIS), 1149 appendMessage, 'O', B_SHIFT_KEY); 1150 fileMenu->AddItem(item); 1151 item->SetTarget(be_app); 1152 fileMenu->AddSeparatorItem(); 1153 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Save"), 1154 new BMessage(MSG_SAVE), 'S')); 1155 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Save as"B_UTF8_ELLIPSIS), 1156 new BMessage(MSG_SAVE_AS), 'S', B_SHIFT_KEY)); 1157 fileMenu->AddSeparatorItem(); 1158 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Export"), 1159 new BMessage(MSG_EXPORT), 'P')); 1160 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Export as"B_UTF8_ELLIPSIS), 1161 new BMessage(MSG_EXPORT_AS), 'P', B_SHIFT_KEY)); 1162 fileMenu->AddSeparatorItem(); 1163 fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Close"), 1164 new BMessage(B_QUIT_REQUESTED), 'W')); 1165 item = new BMenuItem(B_TRANSLATE("Quit"), 1166 new BMessage(B_QUIT_REQUESTED), 'Q'); 1167 fileMenu->AddItem(item); 1168 item->SetTarget(be_app); 1169 1170 // Edit 1171 #undef B_TRANSLATE_CONTEXT 1172 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Menu-Edit" 1173 1174 1175 fUndoMI = new BMenuItem(B_TRANSLATE("<nothing to undo>"), 1176 new BMessage(MSG_UNDO), 'Z'); 1177 fRedoMI = new BMenuItem(B_TRANSLATE("<nothing to redo>"), 1178 new BMessage(MSG_REDO), 'Z', B_SHIFT_KEY); 1179 1180 fUndoMI->SetEnabled(false); 1181 fRedoMI->SetEnabled(false); 1182 1183 editMenu->AddItem(fUndoMI); 1184 editMenu->AddItem(fRedoMI); 1185 1186 1187 // Settings 1188 #undef B_TRANSLATE_CONTEXT 1189 #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Menu-Settings" 1190 1191 1192 BMenu* filterModeMenu = new BMenu(B_TRANSLATE("Snap to grid")); 1193 BMessage* message = new BMessage(MSG_MOUSE_FILTER_MODE); 1194 message->AddInt32("mode", SNAPPING_OFF); 1195 fMouseFilterOffMI = new BMenuItem(B_TRANSLATE("Off"), message, '4'); 1196 filterModeMenu->AddItem(fMouseFilterOffMI); 1197 1198 message = new BMessage(MSG_MOUSE_FILTER_MODE); 1199 message->AddInt32("mode", SNAPPING_64); 1200 fMouseFilter64MI = new BMenuItem("64 x 64", message, '3'); 1201 filterModeMenu->AddItem(fMouseFilter64MI); 1202 1203 message = new BMessage(MSG_MOUSE_FILTER_MODE); 1204 message->AddInt32("mode", SNAPPING_32); 1205 fMouseFilter32MI = new BMenuItem("32 x 32", message, '2'); 1206 filterModeMenu->AddItem(fMouseFilter32MI); 1207 1208 message = new BMessage(MSG_MOUSE_FILTER_MODE); 1209 message->AddInt32("mode", SNAPPING_16); 1210 fMouseFilter16MI = new BMenuItem("16 x 16", message, '1'); 1211 filterModeMenu->AddItem(fMouseFilter16MI); 1212 1213 filterModeMenu->SetRadioMode(true); 1214 1215 settingsMenu->AddItem(filterModeMenu); 1216 1217 return menuBar; 1218 } 1219 1220 1221 void 1222 MainWindow::_ImproveScrollBarLayout(BView* target) 1223 { 1224 // NOTE: The BListViews for which this function is used 1225 // are directly below a BMenuBar. If the BScrollBar and 1226 // the BMenuBar share bottom/top border respectively, the 1227 // GUI looks a little more polished. This trick can be 1228 // removed if/when the BScrollViews are embedded in a 1229 // surounding border like in WonderBrush. 1230 1231 if (BScrollBar* scrollBar = target->ScrollBar(B_VERTICAL)) { 1232 scrollBar->MoveBy(0, -1); 1233 scrollBar->ResizeBy(0, 1); 1234 } 1235 } 1236 1237 1238 // #pragma mark - 1239 1240 1241 bool 1242 MainWindow::_CheckSaveIcon(const BMessage* currentMessage) 1243 { 1244 if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved()) 1245 return true; 1246 1247 // Make sure the user sees us. 1248 Activate(); 1249 1250 BAlert* alert = new BAlert("save", 1251 B_TRANSLATE("Save changes to current icon?"), B_TRANSLATE("Discard"), 1252 B_TRANSLATE("Cancel"), B_TRANSLATE("Save")); 1253 int32 choice = alert->Go(); 1254 switch (choice) { 1255 case 0: 1256 // discard 1257 return true; 1258 case 1: 1259 // cancel 1260 return false; 1261 case 2: 1262 default: 1263 // cancel (save first) but pick up what we were doing before 1264 PostMessage(MSG_SAVE); 1265 if (currentMessage != NULL) { 1266 delete fMessageAfterSave; 1267 fMessageAfterSave = new BMessage(*currentMessage); 1268 } 1269 return false; 1270 } 1271 } 1272 1273 1274 void 1275 MainWindow::_PickUpActionBeforeSave() 1276 { 1277 if (fDocument->WriteLock()) { 1278 fDocument->CommandStack()->Save(); 1279 fDocument->WriteUnlock(); 1280 } 1281 1282 if (fMessageAfterSave == NULL) 1283 return; 1284 1285 PostMessage(fMessageAfterSave); 1286 delete fMessageAfterSave; 1287 fMessageAfterSave = NULL; 1288 } 1289 1290 1291 // #pragma mark - 1292 1293 1294 void 1295 MainWindow::_MakeIconEmpty() 1296 { 1297 if (!_CheckSaveIcon(CurrentMessage())) 1298 return; 1299 1300 AutoWriteLocker locker(fDocument); 1301 1302 MakeEmpty(); 1303 fDocument->MakeEmpty(); 1304 1305 locker.Unlock(); 1306 } 1307 1308 1309 DocumentSaver* 1310 MainWindow::_CreateSaver(const entry_ref& ref, uint32 exportMode) 1311 { 1312 DocumentSaver* saver; 1313 1314 switch (exportMode) { 1315 case EXPORT_MODE_FLAT_ICON: 1316 saver = new SimpleFileSaver(new FlatIconExporter(), ref); 1317 break; 1318 1319 case EXPORT_MODE_ICON_ATTR: 1320 case EXPORT_MODE_ICON_MIME_ATTR: { 1321 const char* attrName 1322 = exportMode == EXPORT_MODE_ICON_ATTR ? 1323 kVectorAttrNodeName : kVectorAttrMimeName; 1324 saver = new AttributeSaver(ref, attrName); 1325 break; 1326 } 1327 1328 case EXPORT_MODE_ICON_RDEF: 1329 saver = new SimpleFileSaver(new RDefExporter(), ref); 1330 break; 1331 case EXPORT_MODE_ICON_SOURCE: 1332 saver = new SimpleFileSaver(new SourceExporter(), ref); 1333 break; 1334 1335 case EXPORT_MODE_BITMAP_16: 1336 saver = new SimpleFileSaver(new BitmapExporter(16), ref); 1337 break; 1338 case EXPORT_MODE_BITMAP_32: 1339 saver = new SimpleFileSaver(new BitmapExporter(32), ref); 1340 break; 1341 case EXPORT_MODE_BITMAP_64: 1342 saver = new SimpleFileSaver(new BitmapExporter(64), ref); 1343 break; 1344 1345 case EXPORT_MODE_BITMAP_SET: 1346 saver = new BitmapSetSaver(ref); 1347 break; 1348 1349 case EXPORT_MODE_SVG: 1350 saver = new SimpleFileSaver(new SVGExporter(), ref); 1351 break; 1352 1353 case EXPORT_MODE_MESSAGE: 1354 default: 1355 saver = new NativeSaver(ref); 1356 break; 1357 } 1358 1359 return saver; 1360 } 1361 1362 1363 const char* 1364 MainWindow::_FileName(bool preferExporter) const 1365 { 1366 FileSaver* saver1; 1367 FileSaver* saver2; 1368 if (preferExporter) { 1369 saver1 = dynamic_cast<FileSaver*>(fDocument->ExportSaver()); 1370 saver2 = dynamic_cast<FileSaver*>(fDocument->NativeSaver()); 1371 } else { 1372 saver1 = dynamic_cast<FileSaver*>(fDocument->NativeSaver()); 1373 saver2 = dynamic_cast<FileSaver*>(fDocument->ExportSaver()); 1374 } 1375 const char* fileName = NULL; 1376 if (saver1 != NULL) 1377 fileName = saver1->Ref()->name; 1378 if ((fileName == NULL || fileName[0] == '\0') && saver2 != NULL) 1379 fileName = saver2->Ref()->name; 1380 return fileName; 1381 } 1382 1383 1384 void 1385 MainWindow::_UpdateWindowTitle() 1386 { 1387 const char* fileName = _FileName(false); 1388 if (fileName != NULL) 1389 SetTitle(fileName); 1390 else 1391 SetTitle(B_TRANSLATE_SYSTEM_NAME("Icon-O-Matic")); 1392 } 1393 1394