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