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