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