vfs: check userland buffers before reading them.
[haiku.git] / src / apps / icon-o-matic / MainWindow.cpp
blob1146a1920445f855cc57de4b098144f1b8fde039
1 /*
2 * Copyright 2006-2011, Stephan Aßmus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include "MainWindow.h"
8 #include <new>
9 #include <stdio.h>
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>
29 #include "support_ui.h"
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"
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"
82 #include "StyledTextImporter.h"
85 #undef B_TRANSLATION_CONTEXT
86 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Main"
89 using std::nothrow;
91 enum {
92 MSG_UNDO = 'undo',
93 MSG_REDO = 'redo',
94 MSG_UNDO_STACK_CHANGED = 'usch',
96 MSG_PATH_SELECTED = 'vpsl',
97 MSG_STYLE_SELECTED = 'stsl',
98 MSG_SHAPE_SELECTED = 'spsl',
100 MSG_SHAPE_RESET_TRANSFORMATION = 'rtsh',
101 MSG_STYLE_RESET_TRANSFORMATION = 'rtst',
103 MSG_MOUSE_FILTER_MODE = 'mfmd',
105 MSG_RENAME_OBJECT = 'rnam',
109 MainWindow::MainWindow(BRect frame, IconEditorApp* app,
110 const BMessage* settings)
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)
121 _Init();
123 RestoreSettings(settings);
127 MainWindow::~MainWindow()
129 SetIcon(NULL);
131 delete fState;
133 // Make sure there are no listeners attached to the document anymore.
134 while (BView* child = ChildAt(0L)) {
135 child->RemoveSelf();
136 delete child;
139 fDocument->CommandStack()->RemoveObserver(this);
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;
146 delete fMessageAfterSave;
150 // #pragma mark -
153 void
154 MainWindow::MessageReceived(BMessage* message)
156 bool discard = false;
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;
172 if (requiresWriteLock && !fDocument->WriteLock()) {
173 BWindow::MessageReceived(message);
174 return;
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;
203 switch (message->what) {
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;
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);
224 be_app->PostMessage(message);
225 break;
227 case B_PASTE:
228 case B_MIME_DATA:
230 BMessage* clip = message;
231 status_t err;
233 if (discard)
234 break;
236 if (message->what == B_PASTE) {
237 if (!be_clipboard->Lock())
238 break;
239 clip = be_clipboard->Data();
242 if (!clip || !clip->HasData("text/plain", B_MIME_TYPE)) {
243 if (message->what == B_PASTE)
244 be_clipboard->Unlock();
245 break;
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);
255 SetIcon(NULL);
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);
266 if (message->what == B_PASTE)
267 be_clipboard->Unlock();
268 break;
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);
279 be_app->PostMessage(message);
280 break;
282 case MSG_SAVE:
283 case MSG_EXPORT:
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
296 case MSG_SAVE_AS:
297 case MSG_EXPORT_AS:
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) {
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();
324 saver->Save(fDocument);
325 _PickUpActionBeforeSave();
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);
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);
345 break;
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;
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:
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"));
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"));
381 break;
384 case MSG_MOUSE_FILTER_MODE:
386 uint32 mode;
387 if (message->FindInt32("mode", (int32*)&mode) == B_OK)
388 fCanvasView->SetMouseFilterMode(mode);
389 break;
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);
400 AddPathsCommand* pathCommand = NULL;
401 VectorPath* path = NULL;
402 if (message->HasBool("path")) {
403 new_path(fDocument->Icon()->Paths(), &path, &pathCommand);
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);
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());
422 if (path && shape)
423 shape->Paths()->AddPath(path);
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"),
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"),
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"),
453 } else {
454 command = shapeCommand;
456 fDocument->CommandStack()->Perform(command);
457 break;
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;
466 fPathListView->SetCurrentShape(NULL);
467 fStyleListView->SetCurrentShape(NULL);
468 fTransformerListView->SetShape(NULL);
470 fState->DeleteManipulators();
471 if (fDocument->Icon()->Paths()->HasPath(path)) {
472 PathManipulator* pathManipulator = new (nothrow) PathManipulator(path);
473 fState->AddManipulator(pathManipulator);
475 break;
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;
485 fStyleView->SetStyle(style);
486 fPathListView->SetCurrentShape(NULL);
487 fStyleListView->SetCurrentShape(NULL);
488 fTransformerListView->SetShape(NULL);
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);
497 break;
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;
506 fPathListView->SetCurrentShape(shape);
507 fStyleListView->SetCurrentShape(shape);
508 fTransformerListView->SetShape(shape);
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);
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);
528 break;
530 case MSG_RENAME_OBJECT:
531 fPropertyListView->FocusNameProperty();
532 break;
534 default:
535 BWindow::MessageReceived(message);
538 if (requiresWriteLock)
539 fDocument->WriteUnlock();
543 bool
544 MainWindow::QuitRequested()
546 if (!_CheckSaveIcon(CurrentMessage()))
547 return false;
549 BMessage message(MSG_WINDOW_CLOSED);
551 BMessage settings;
552 StoreSettings(&settings);
553 message.AddMessage("settings", &settings);
554 message.AddRect("window frame", Frame());
556 be_app->PostMessage(&message);
558 return true;
562 void
563 MainWindow::WorkspaceActivated(int32 workspace, bool active)
565 BWindow::WorkspaceActivated(workspace, active);
567 // NOTE: hack to workaround buggy BScreen::DesktopColor() on R5
569 uint32 workspaces = Workspaces();
570 if (!active || ((1 << workspace) & workspaces) == 0)
571 return;
573 WorkspacesChanged(workspaces, workspaces);
577 void
578 MainWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
580 if (oldWorkspaces != newWorkspaces)
581 BWindow::WorkspacesChanged(oldWorkspaces, newWorkspaces);
583 BScreen screen(this);
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.
593 fIconPreview32Desktop->SetIconBGColor(screen.DesktopColor());
594 fIconPreview64->SetIconBGColor(screen.DesktopColor());
598 // #pragma mark -
601 void
602 MainWindow::ObjectChanged(const Observable* object)
604 if (!fDocument || !fDocument->ReadLock())
605 return;
607 if (object == fDocument->CommandStack())
608 PostMessage(MSG_UNDO_STACK_CHANGED);
610 fDocument->ReadUnlock();
614 // #pragma mark -
617 void
618 MainWindow::MakeEmpty()
620 fPathListView->SetCurrentShape(NULL);
621 fStyleListView->SetCurrentShape(NULL);
622 fStyleView->SetStyle(NULL);
624 fTransformerListView->SetShape(NULL);
626 fState->DeleteManipulators();
630 void
631 MainWindow::Open(const entry_ref& ref, bool append)
633 BFile file(&ref, B_READ_ONLY);
634 if (file.InitCheck() < B_OK)
635 return;
637 Icon* icon;
638 if (append)
639 icon = new (nothrow) Icon(*fDocument->Icon());
640 else
641 icon = new (nothrow) Icon();
643 if (icon == NULL) {
644 // TODO: Report error to user.
645 return;
648 enum {
649 REF_NONE = 0,
650 REF_MESSAGE,
651 REF_FLAT,
652 REF_FLAT_ATTR,
653 REF_SVG
655 uint32 refMode = REF_NONE;
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;
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;
698 if (ret == B_OK) {
699 ret = flatImporter.Import(icon, buffer, attrInfo.size);
700 if (ret == B_OK)
701 refMode = REF_FLAT_ATTR;
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;
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);
730 delete icon;
731 return;
734 AutoWriteLocker locker(fDocument);
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;
763 locker.Unlock();
765 SetIcon(icon);
767 _UpdateWindowTitle();
771 void
772 MainWindow::Open(const BMessenger& externalObserver, const uint8* data,
773 size_t size)
775 if (!_CheckSaveIcon(CurrentMessage()))
776 return;
778 if (!externalObserver.IsValid())
779 return;
781 Icon* icon = new (nothrow) Icon();
782 if (!icon)
783 return;
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
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);
809 delete icon;
810 return;
814 AutoWriteLocker locker(fDocument);
816 SetIcon(NULL);
818 // incorporate the loaded icon into the document
819 // (either replace it or append to it)
820 fDocument->MakeEmpty();
821 fDocument->SetIcon(icon);
823 fDocument->SetNativeSaver(new MessengerSaver(externalObserver));
825 locker.Unlock();
827 SetIcon(icon);
831 void
832 MainWindow::SetIcon(Icon* icon)
834 if (fIcon == icon)
835 return;
837 Icon* oldIcon = fIcon;
839 fIcon = icon;
841 if (fIcon != NULL)
842 fIcon->AcquireReference();
843 else
844 MakeEmpty();
846 fCanvasView->SetIcon(fIcon);
848 fPathListView->SetPathContainer(fIcon != NULL ? fIcon->Paths() : NULL);
849 fPathListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL);
851 fStyleListView->SetStyleContainer(fIcon != NULL ? fIcon->Styles() : NULL);
852 fStyleListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL);
854 fShapeListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL);
855 fShapeListView->SetStyleContainer(fIcon != NULL ? fIcon->Styles() : NULL);
856 fShapeListView->SetPathContainer(fIcon != NULL ? fIcon->Paths() : NULL);
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);
866 // keep this last
867 if (oldIcon != NULL)
868 oldIcon->ReleaseReference();
872 // #pragma mark -
875 void
876 MainWindow::StoreSettings(BMessage* archive)
878 if (archive->ReplaceUInt32("mouse filter mode",
879 fCanvasView->MouseFilterMode()) != B_OK) {
880 archive->AddUInt32("mouse filter mode",
881 fCanvasView->MouseFilterMode());
886 void
887 MainWindow::RestoreSettings(const BMessage* archive)
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);
900 // #pragma mark -
903 void
904 MainWindow::_Init()
906 // create the GUI
907 _CreateGUI();
909 // fix up scrollbar layout in listviews
910 _ImproveScrollBarLayout(fPathListView);
911 _ImproveScrollBarLayout(fStyleListView);
912 _ImproveScrollBarLayout(fShapeListView);
913 _ImproveScrollBarLayout(fTransformerListView);
915 // TODO: move this to CanvasView?
916 fState = new MultipleManipulatorState(fCanvasView);
917 fCanvasView->SetState(fState);
919 fCanvasView->SetCatchAllEvents(true);
920 fCanvasView->SetCommandStack(fDocument->CommandStack());
921 fCanvasView->SetMouseFilterMode(SNAPPING_64);
922 fMouseFilter64MI->SetMarked(true);
923 // fCanvasView->SetSelection(fDocument->Selection());
925 fPathListView->SetMenu(fPathMenu);
926 fPathListView->SetCommandStack(fDocument->CommandStack());
927 fPathListView->SetSelection(fDocument->Selection());
929 fStyleListView->SetMenu(fStyleMenu);
930 fStyleListView->SetCommandStack(fDocument->CommandStack());
931 fStyleListView->SetSelection(fDocument->Selection());
932 fStyleListView->SetCurrentColor(fCurrentColor);
934 fStyleView->SetCommandStack(fDocument->CommandStack());
935 fStyleView->SetCurrentColor(fCurrentColor);
937 fShapeListView->SetMenu(fShapeMenu);
938 fShapeListView->SetCommandStack(fDocument->CommandStack());
939 fShapeListView->SetSelection(fDocument->Selection());
941 fTransformerListView->SetMenu(fTransformerMenu);
942 fTransformerListView->SetCommandStack(fDocument->CommandStack());
943 fTransformerListView->SetSelection(fDocument->Selection());
945 fPropertyListView->SetCommandStack(fDocument->CommandStack());
946 fPropertyListView->SetSelection(fDocument->Selection());
947 fPropertyListView->SetMenu(fPropertyMenu);
949 fDocument->CommandStack()->AddObserver(this);
951 fSwatchGroup->SetCurrentColor(fCurrentColor);
953 SetIcon(fDocument->Icon());
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));
961 void
962 MainWindow::_CreateGUI()
964 SetLayout(new BGroupLayout(B_HORIZONTAL));
966 BGridLayout* layout = new BGridLayout();
967 layout->SetSpacing(0, 0);
968 BView* rootView = new BView("root view", 0, layout);
969 AddChild(rootView);
970 rootView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
972 BGroupView* leftTopView = new BGroupView(B_VERTICAL, 0);
973 layout->AddView(leftTopView, 0, 0);
975 // views along the left side
976 leftTopView->AddChild(_CreateMenuBar());
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));
984 BGroupView* iconPreviews = new BGroupView(B_HORIZONTAL);
985 iconPreviews->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
986 iconPreviews->GroupLayout()->SetSpacing(5);
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));
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));
1001 fIconPreview64 = new IconView(BRect(0, 0, 63, 63), "icon preview 64");
1002 fIconPreview64->SetLowColor(ui_color(B_DESKTOP_COLOR));
1005 BGroupView* smallPreviews = new BGroupView(B_VERTICAL);
1006 smallPreviews->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1007 smallPreviews->GroupLayout()->SetSpacing(5);
1009 smallPreviews->AddChild(fIconPreview16Folder);
1010 smallPreviews->AddChild(fIconPreview16Menu);
1012 BGroupView* mediumPreviews = new BGroupView(B_VERTICAL);
1013 mediumPreviews->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1014 mediumPreviews->GroupLayout()->SetSpacing(5);
1016 mediumPreviews->AddChild(fIconPreview32Folder);
1017 mediumPreviews->AddChild(fIconPreview32Desktop);
1019 // iconPreviews->AddChild(fIconPreview48);
1021 iconPreviews->AddChild(smallPreviews);
1022 iconPreviews->AddChild(mediumPreviews);
1023 iconPreviews->AddChild(fIconPreview64);
1024 iconPreviews->SetExplicitMaxSize(BSize(B_SIZE_UNSET, B_SIZE_UNLIMITED));
1026 leftTopView->AddChild(iconPreviews);
1029 BGroupView* leftSideView = new BGroupView(B_VERTICAL, 0);
1030 layout->AddView(leftSideView, 0, 1);
1031 leftSideView->SetExplicitMaxSize(BSize(splitWidth, B_SIZE_UNSET));
1033 // path menu and list view
1034 BMenuBar* menuBar = new BMenuBar("path menu bar");
1035 menuBar->AddItem(fPathMenu);
1036 leftSideView->AddChild(menuBar);
1038 fPathListView = new PathListView(BRect(0, 0, splitWidth, 100),
1039 "path list view", new BMessage(MSG_PATH_SELECTED), this);
1041 BView* scrollView = new BScrollView("path list scroll view",
1042 fPathListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER);
1043 leftSideView->AddChild(scrollView);
1045 // shape list view
1046 menuBar = new BMenuBar("shape menu bar");
1047 menuBar->AddItem(fShapeMenu);
1048 leftSideView->AddChild(menuBar);
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);
1056 // transformer list view
1057 menuBar = new BMenuBar("transformer menu bar");
1058 menuBar->AddItem(fTransformerMenu);
1059 leftSideView->AddChild(menuBar);
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);
1067 // property list view
1068 menuBar = new BMenuBar("property menu bar");
1069 menuBar->AddItem(fPropertyMenu);
1070 leftSideView->AddChild(menuBar);
1072 fPropertyListView = new IconObjectListView();
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);
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);
1086 // canvas view
1087 BRect canvasBounds = BRect(0, 0, 200, 200);
1088 fCanvasView = new CanvasView(canvasBounds);
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);
1099 // views along the top
1101 BGroupLayout* styleGroup = new BGroupLayout(B_VERTICAL, 0);
1102 BView* styleGroupView = new BView("style group", 0, styleGroup);
1103 topSide->AddView(styleGroupView);
1105 // style list view
1106 menuBar = new BMenuBar("style menu bar");
1107 menuBar->AddItem(fStyleMenu);
1108 styleGroup->AddView(menuBar);
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);
1117 // style view
1118 fStyleView = new StyleView(BRect(0, 0, 200, 100));
1119 topSide->AddView(fStyleView);
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);
1127 menuBar = new BMenuBar("swatches menu bar");
1128 menuBar->AddItem(fSwatchMenu);
1129 swatchGroup->AddView(menuBar);
1131 fSwatchGroup = new SwatchGroup(BRect(0, 0, 100, 100));
1132 swatchGroup->AddView(fSwatchGroup);
1134 swatchGroupView->SetExplicitMaxSize(swatchGroupView->MinSize());
1136 // make sure the top side has fixed height
1137 topSideView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED,
1138 swatchGroupView->MinSize().height));
1141 BMenuBar*
1142 MainWindow::_CreateMenuBar()
1144 BMenuBar* menuBar = new BMenuBar("main menu");
1147 #undef B_TRANSLATION_CONTEXT
1148 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Menus"
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"));
1161 menuBar->AddItem(fileMenu);
1162 menuBar->AddItem(editMenu);
1163 menuBar->AddItem(settingsMenu);
1166 // File
1167 #undef B_TRANSLATION_CONTEXT
1168 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Menu-File"
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);
1202 // Edit
1203 #undef B_TRANSLATION_CONTEXT
1204 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Menu-Edit"
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);
1212 fUndoMI->SetEnabled(false);
1213 fRedoMI->SetEnabled(false);
1215 editMenu->AddItem(fUndoMI);
1216 editMenu->AddItem(fRedoMI);
1219 // Settings
1220 #undef B_TRANSLATION_CONTEXT
1221 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Menu-Settings"
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);
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);
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);
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);
1245 filterModeMenu->SetRadioMode(true);
1247 settingsMenu->AddItem(filterModeMenu);
1249 return menuBar;
1253 void
1254 MainWindow::_ImproveScrollBarLayout(BView* target)
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.
1263 if (BScrollBar* scrollBar = target->ScrollBar(B_VERTICAL)) {
1264 scrollBar->MoveBy(0, -1);
1265 scrollBar->ResizeBy(0, 1);
1270 // #pragma mark -
1273 bool
1274 MainWindow::_CheckSaveIcon(const BMessage* currentMessage)
1276 if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved())
1277 return true;
1279 // Make sure the user sees us.
1280 Activate();
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);
1306 return false;
1311 void
1312 MainWindow::_PickUpActionBeforeSave()
1314 if (fDocument->WriteLock()) {
1315 fDocument->CommandStack()->Save();
1316 fDocument->WriteUnlock();
1319 if (fMessageAfterSave == NULL)
1320 return;
1322 PostMessage(fMessageAfterSave);
1323 delete fMessageAfterSave;
1324 fMessageAfterSave = NULL;
1328 // #pragma mark -
1331 void
1332 MainWindow::_MakeIconEmpty()
1334 if (!_CheckSaveIcon(CurrentMessage()))
1335 return;
1337 AutoWriteLocker locker(fDocument);
1339 MakeEmpty();
1340 fDocument->MakeEmpty();
1342 locker.Unlock();
1346 DocumentSaver*
1347 MainWindow::_CreateSaver(const entry_ref& ref, uint32 exportMode)
1349 DocumentSaver* saver;
1351 switch (exportMode) {
1352 case EXPORT_MODE_FLAT_ICON:
1353 saver = new SimpleFileSaver(new FlatIconExporter(), ref);
1354 break;
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;
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;
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;
1382 case EXPORT_MODE_BITMAP_SET:
1383 saver = new BitmapSetSaver(ref);
1384 break;
1386 case EXPORT_MODE_SVG:
1387 saver = new SimpleFileSaver(new SVGExporter(), ref);
1388 break;
1390 case EXPORT_MODE_MESSAGE:
1391 default:
1392 saver = new NativeSaver(ref);
1393 break;
1396 return saver;
1400 const char*
1401 MainWindow::_FileName(bool preferExporter) const
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());
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;
1421 void
1422 MainWindow::_UpdateWindowTitle()
1424 const char* fileName = _FileName(false);
1425 if (fileName != NULL)
1426 SetTitle(fileName);
1427 else
1428 SetTitle(B_TRANSLATE_SYSTEM_NAME("Icon-O-Matic"));