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