xref: /haiku/src/apps/icon-o-matic/IconEditorApp.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "IconEditorApp.h"
10 
11 #include <new>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <Alert.h>
16 #include <Directory.h>
17 #include <Entry.h>
18 #include <File.h>
19 #include <FilePanel.h>
20 #include <fs_attr.h>
21 #include <IconEditorProtocol.h>
22 #include <Message.h>
23 #include <Mime.h>
24 
25 #include "support_settings.h"
26 
27 #include "AttributeSaver.h"
28 #include "AutoLocker.h"
29 #include "BitmapExporter.h"
30 #include "BitmapSetSaver.h"
31 #include "CommandStack.h"
32 #include "Defines.h"
33 #include "Document.h"
34 #include "FlatIconExporter.h"
35 #include "FlatIconFormat.h"
36 #include "FlatIconImporter.h"
37 #include "Icon.h"
38 #include "MainWindow.h"
39 #include "MessageExporter.h"
40 #include "MessageImporter.h"
41 #include "MessengerSaver.h"
42 #include "NativeSaver.h"
43 #include "PathContainer.h"
44 #include "RDefExporter.h"
45 #include "SavePanel.h"
46 #include "ShapeContainer.h"
47 #include "SimpleFileSaver.h"
48 #include "SourceExporter.h"
49 #include "SVGExporter.h"
50 #include "SVGImporter.h"
51 
52 using std::nothrow;
53 
54 static const char* kAppSig = "application/x-vnd.haiku-icon_o_matic";
55 
56 // constructor
57 IconEditorApp::IconEditorApp()
58 	: BApplication(kAppSig),
59 	  fMainWindow(NULL),
60 	  fDocument(new Document("test")),
61 
62 	  fOpenPanel(NULL),
63 	  fSavePanel(NULL),
64 
65 	  fLastOpenPath(""),
66 	  fLastSavePath(""),
67 	  fLastExportPath(""),
68 
69 	  fMessageAfterSave(NULL)
70 {
71 }
72 
73 // destructor
74 IconEditorApp::~IconEditorApp()
75 {
76 	// NOTE: it is important that the GUI has been deleted
77 	// at this point, so that all the listener/observer
78 	// stuff is properly detached
79 	delete fDocument;
80 
81 	delete fOpenPanel;
82 	delete fSavePanel;
83 
84 	delete fMessageAfterSave;
85 }
86 
87 // #pragma mark -
88 
89 // QuitRequested
90 bool
91 IconEditorApp::QuitRequested()
92 {
93 	if (!_CheckSaveIcon(CurrentMessage()))
94 		return false;
95 
96 	_StoreSettings();
97 
98 	fMainWindow->Lock();
99 	fMainWindow->Quit();
100 	fMainWindow = NULL;
101 
102 	return true;
103 }
104 
105 // MessageReceived
106 void
107 IconEditorApp::MessageReceived(BMessage* message)
108 {
109 	switch (message->what) {
110 		case MSG_NEW:
111 			_MakeIconEmpty();
112 			break;
113 		case MSG_OPEN: {
114 			BMessage openMessage(B_REFS_RECEIVED);
115 			fOpenPanel->SetMessage(&openMessage);
116 			fOpenPanel->Show();
117 			break;
118 		}
119 		case MSG_APPEND: {
120 			BMessage openMessage(B_REFS_RECEIVED);
121 			openMessage.AddBool("append", true);
122 			fOpenPanel->SetMessage(&openMessage);
123 			fOpenPanel->Show();
124 			break;
125 		}
126 		case MSG_SAVE:
127 		case MSG_EXPORT: {
128 			DocumentSaver* saver;
129 			if (message->what == MSG_SAVE)
130 				saver = fDocument->NativeSaver();
131 			else
132 				saver = fDocument->ExportSaver();
133 			if (saver) {
134 				saver->Save(fDocument);
135 				_PickUpActionBeforeSave();
136 				break;
137 			} // else fall through
138 		}
139 		case MSG_SAVE_AS:
140 		case MSG_EXPORT_AS: {
141 			int32 exportMode;
142 			if (message->FindInt32("export mode", &exportMode) < B_OK)
143 				exportMode = EXPORT_MODE_MESSAGE;
144 			entry_ref ref;
145 			const char* name;
146 			if (message->FindRef("directory", &ref) == B_OK
147 				&& message->FindString("name", &name) == B_OK) {
148 				// this message comes from the file panel
149 				BDirectory dir(&ref);
150 				BEntry entry;
151 				if (dir.InitCheck() >= B_OK
152 					&& entry.SetTo(&dir, name, true) >= B_OK
153 					&& entry.GetRef(&ref) >= B_OK) {
154 
155 					// create the document saver and remember it for later
156 					DocumentSaver* saver = _CreateSaver(ref, exportMode);
157 					if (saver) {
158 						if (exportMode == EXPORT_MODE_MESSAGE)
159 							fDocument->SetNativeSaver(saver);
160 						else
161 							fDocument->SetExportSaver(saver);
162 						saver->Save(fDocument);
163 						_PickUpActionBeforeSave();
164 					}
165 				}
166 				_SyncPanels(fSavePanel, fOpenPanel);
167 			} else {
168 				// configure the file panel
169 				const char* saveText = NULL;
170 				FileSaver* saver = dynamic_cast<FileSaver*>(
171 					fDocument->NativeSaver());
172 
173 				bool exportMode = message->what == MSG_EXPORT_AS
174 									|| message->what == MSG_EXPORT;
175 				if (exportMode) {
176 					saver = dynamic_cast<FileSaver*>(
177 						fDocument->ExportSaver());
178 				}
179 
180 				if (saver)
181 					saveText = saver->Ref()->name;
182 
183 				fSavePanel->SetExportMode(exportMode);
184 //				fSavePanel->Refresh();
185 				if (saveText)
186 					fSavePanel->SetSaveText(saveText);
187 				fSavePanel->Show();
188 			}
189 			break;
190 		}
191 		case B_EDIT_ICON_DATA: {
192 			BMessenger messenger;
193 			if (message->FindMessenger("reply to", &messenger) < B_OK) {
194 				// required
195 				break;
196 			}
197 			const uint8* data;
198 			ssize_t size;
199 			if (message->FindData("icon data", B_VECTOR_ICON_TYPE,
200 				(const void**)&data, &size) < B_OK) {
201 				// optional (new icon will be created)
202 				data = NULL;
203 				size = 0;
204 			}
205 			_Open(messenger, data, size);
206 			break;
207 		}
208 
209 		default:
210 			BApplication::MessageReceived(message);
211 			break;
212 	}
213 }
214 
215 // ReadyToRun
216 void
217 IconEditorApp::ReadyToRun()
218 {
219 	// create file panels
220 	BMessenger messenger(this, this);
221 	BMessage message(B_REFS_RECEIVED);
222 	fOpenPanel = new BFilePanel(B_OPEN_PANEL,
223 								&messenger,
224 								NULL,
225 								B_FILE_NODE,
226 								true,
227 								&message);
228 
229 	message.what = MSG_SAVE_AS;
230 	fSavePanel = new SavePanel("save panel",
231 							   &messenger,
232 								NULL,
233 								B_FILE_NODE
234 									| B_DIRECTORY_NODE
235 									| B_SYMLINK_NODE,
236 								false,
237 								&message);
238 
239 	// create main window
240 	BMessage settings('stns');
241 	_RestoreSettings(settings);
242 
243 	fMainWindow = new MainWindow(this, fDocument, &settings);
244 	fMainWindow->Show();
245 
246 	_InstallDocumentMimeType();
247 }
248 
249 // RefsReceived
250 void
251 IconEditorApp::RefsReceived(BMessage* message)
252 {
253 	// TODO: multiple documents (iterate over refs)
254 	bool append;
255 	if (message->FindBool("append", &append) < B_OK)
256 		append = false;
257 	entry_ref ref;
258 	if (message->FindRef("refs", &ref) == B_OK)
259 		_Open(ref, append);
260 
261 	if (fOpenPanel && fSavePanel)
262 		_SyncPanels(fOpenPanel, fSavePanel);
263 }
264 
265 // ArgvReceived
266 void
267 IconEditorApp::ArgvReceived(int32 argc, char** argv)
268 {
269 	if (argc < 2)
270 		return;
271 
272 	// TODO: multiple documents (iterate over argv)
273 	entry_ref ref;
274 	if (get_ref_for_path(argv[1], &ref) == B_OK)
275 		_Open(ref);
276 }
277 
278 // #pragma mark -
279 
280 // _CheckSaveIcon
281 bool
282 IconEditorApp::_CheckSaveIcon(const BMessage* currentMessage)
283 {
284 	if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved())
285 		return true;
286 
287 	BAlert* alert = new BAlert("save", "Save changes to current icon?",
288 		"Discard", "Cancel", "Save");
289 	int32 choice = alert->Go();
290 	switch (choice) {
291 		case 0:
292 			// discard
293 			return true;
294 		case 1:
295 			// cancel
296 			return false;
297 		case 2:
298 		default:
299 			// cancel (save first) but pick what we were doing before
300 			PostMessage(MSG_SAVE);
301 			if (currentMessage) {
302 				delete fMessageAfterSave;
303 				fMessageAfterSave = new BMessage(*currentMessage);
304 			}
305 			return false;
306 	}
307 }
308 
309 // _PickUpActionBeforeSave
310 void
311 IconEditorApp::_PickUpActionBeforeSave()
312 {
313 	if (fDocument->WriteLock()) {
314 		fDocument->CommandStack()->Save();
315 		fDocument->WriteUnlock();
316 	}
317 
318 	if (!fMessageAfterSave)
319 		return;
320 
321 	PostMessage(fMessageAfterSave);
322 	delete fMessageAfterSave;
323 	fMessageAfterSave = NULL;
324 }
325 
326 // #pragma mark -
327 
328 // _MakeIconEmpty
329 void
330 IconEditorApp::_MakeIconEmpty()
331 {
332 	if (!_CheckSaveIcon(CurrentMessage()))
333 		return;
334 
335 	bool mainWindowLocked = fMainWindow && fMainWindow->Lock();
336 
337 	AutoWriteLocker locker(fDocument);
338 
339 	if (fMainWindow)
340 		fMainWindow->MakeEmpty();
341 
342 	fDocument->MakeEmpty();
343 
344 	locker.Unlock();
345 
346 	if (mainWindowLocked)
347 		fMainWindow->Unlock();
348 }
349 
350 // _Open
351 void
352 IconEditorApp::_Open(const entry_ref& ref, bool append)
353 {
354 	if (!_CheckSaveIcon(CurrentMessage()))
355 		return;
356 
357 	BFile file(&ref, B_READ_ONLY);
358 	if (file.InitCheck() < B_OK)
359 		return;
360 
361 	Icon* icon;
362 	if (append)
363 		icon = new (nothrow) Icon(*fDocument->Icon());
364 	else
365 		icon = new (nothrow) Icon();
366 
367 	if (!icon)
368 		return;
369 
370 	enum {
371 		REF_NONE = 0,
372 		REF_MESSAGE,
373 		REF_FLAT,
374 		REF_FLAT_ATTR,
375 		REF_SVG
376 	};
377 	uint32 refMode = REF_NONE;
378 
379 	// try different file types
380 	FlatIconImporter flatImporter;
381 	status_t ret = flatImporter.Import(icon, &file);
382 	if (ret >= B_OK) {
383 		refMode = REF_FLAT;
384 	} else {
385 		file.Seek(0, SEEK_SET);
386 		MessageImporter msgImporter;
387 		ret = msgImporter.Import(icon, &file);
388 		if (ret >= B_OK) {
389 			refMode = REF_MESSAGE;
390 		} else {
391 			file.Seek(0, SEEK_SET);
392 			SVGImporter svgImporter;
393 			ret = svgImporter.Import(icon, &ref);
394 			if (ret >= B_OK) {
395 				refMode = REF_SVG;
396 			} else {
397 				// fall back to flat icon format but use the icon attribute
398 				ret = B_OK;
399 				attr_info attrInfo;
400 				if (file.GetAttrInfo(kVectorAttrNodeName, &attrInfo) == B_OK) {
401 					if (attrInfo.type != B_VECTOR_ICON_TYPE)
402 						ret = B_ERROR;
403 					// If the attribute is there, we must succeed in reading
404 					// an icon! Otherwise we may overwrite an existing icon
405 					// when the user saves.
406 					uint8* buffer = NULL;
407 					if (ret == B_OK) {
408 						buffer = new(nothrow) uint8[attrInfo.size];
409 						if (buffer == NULL)
410 							ret = B_NO_MEMORY;
411 					}
412 					if (ret == B_OK) {
413 						ssize_t bytesRead = file.ReadAttr(kVectorAttrNodeName,
414 							B_VECTOR_ICON_TYPE, 0, buffer, attrInfo.size);
415 						if (bytesRead != (ssize_t)attrInfo.size) {
416 							ret = bytesRead < 0 ? (status_t)bytesRead
417 								: B_IO_ERROR;
418 						}
419 					}
420 					if (ret == B_OK) {
421 						ret = flatImporter.Import(icon, buffer, attrInfo.size);
422 						if (ret == B_OK)
423 							refMode = REF_FLAT_ATTR;
424 					}
425 
426 					delete[] buffer;
427 				} else {
428 					// If there is no icon attribute, simply fall back
429 					// to creating an icon for this file. TODO: We may or may
430 					// not want to display an alert asking the user if that is
431 					// what he wants to do.
432 					refMode = REF_FLAT_ATTR;
433 				}
434 			}
435 		}
436 	}
437 
438 	if (ret < B_OK) {
439 		// inform user of failure at this point
440 		BString helper("Opening the document failed!");
441 		helper << "\n\n" << "Error: " << strerror(ret);
442 		BAlert* alert = new BAlert("bad news", helper.String(),
443 								   "Bummer", NULL, NULL);
444 		// launch alert asynchronously
445 		alert->Go(NULL);
446 
447 		delete icon;
448 		return;
449 	}
450 
451 	// keep the mainwindow locked while switching icons
452 	bool mainWindowLocked = fMainWindow && fMainWindow->Lock();
453 
454 	AutoWriteLocker locker(fDocument);
455 
456 	if (mainWindowLocked)
457 		fMainWindow->SetIcon(NULL);
458 
459 	// incorporate the loaded icon into the document
460 	// (either replace it or append to it)
461 	fDocument->MakeEmpty(!append);
462 		// if append, the document savers are preserved
463 	fDocument->SetIcon(icon);
464 	if (!append) {
465 		// document got replaced, but we have at
466 		// least one ref already
467 		switch (refMode) {
468 			case REF_MESSAGE:
469 				fDocument->SetNativeSaver(
470 					new NativeSaver(ref));
471 				break;
472 			case REF_FLAT:
473 				fDocument->SetExportSaver(
474 					new SimpleFileSaver(new FlatIconExporter(), ref));
475 				break;
476 			case REF_FLAT_ATTR:
477 				fDocument->SetNativeSaver(
478 					new AttributeSaver(ref, kVectorAttrNodeName));
479 				break;
480 			case REF_SVG:
481 				fDocument->SetExportSaver(
482 					new SimpleFileSaver(new SVGExporter(), ref));
483 				break;
484 		}
485 	}
486 
487 	locker.Unlock();
488 
489 	if (mainWindowLocked) {
490 		fMainWindow->Unlock();
491 		// cause the mainwindow to adopt icon in
492 		// it's own thread
493 		fMainWindow->PostMessage(MSG_SET_ICON);
494 	}
495 }
496 
497 // _Open
498 void
499 IconEditorApp::_Open(const BMessenger& externalObserver, const uint8* data,
500 	size_t size)
501 {
502 	if (!_CheckSaveIcon(CurrentMessage()))
503 		return;
504 
505 	if (!externalObserver.IsValid())
506 		return;
507 
508 	Icon* icon = new (nothrow) Icon();
509 	if (!icon)
510 		return;
511 
512 	if (data && size > 0) {
513 		// try to open the icon from the provided data
514 		FlatIconImporter flatImporter;
515 		status_t ret = flatImporter.Import(icon, const_cast<uint8*>(data), size);
516 			// NOTE: the const_cast is a bit ugly, but no harm is done
517 			// the reason is that the LittleEndianBuffer knows read and write
518 			// mode, in this case it is used read-only, and it does not assume
519 			// ownership of the buffer
520 
521 		if (ret < B_OK) {
522 			// inform user of failure at this point
523 			BString helper("Opening the icon failed!");
524 			helper << "\n\n" << "Error: " << strerror(ret);
525 			BAlert* alert = new BAlert("bad news", helper.String(),
526 									   "Bummer", NULL, NULL);
527 			// launch alert asynchronously
528 			alert->Go(NULL);
529 
530 			delete icon;
531 			return;
532 		}
533 	}
534 
535 	// keep the mainwindow locked while switching icons
536 	bool mainWindowLocked = fMainWindow && fMainWindow->Lock();
537 
538 	AutoWriteLocker locker(fDocument);
539 
540 	if (mainWindowLocked)
541 		fMainWindow->SetIcon(NULL);
542 
543 	// incorporate the loaded icon into the document
544 	// (either replace it or append to it)
545 	fDocument->MakeEmpty();
546 	fDocument->SetIcon(icon);
547 
548 	fDocument->SetNativeSaver(new MessengerSaver(externalObserver));
549 
550 	locker.Unlock();
551 
552 	if (mainWindowLocked) {
553 		fMainWindow->Unlock();
554 		// cause the mainwindow to adopt icon in
555 		// it's own thread
556 		fMainWindow->PostMessage(MSG_SET_ICON);
557 	}
558 }
559 
560 // _CreateSaver
561 DocumentSaver*
562 IconEditorApp::_CreateSaver(const entry_ref& ref, uint32 exportMode)
563 {
564 	DocumentSaver* saver;
565 
566 	switch (exportMode) {
567 		case EXPORT_MODE_FLAT_ICON:
568 			saver = new SimpleFileSaver(new FlatIconExporter(), ref);
569 			break;
570 
571 		case EXPORT_MODE_ICON_ATTR:
572 		case EXPORT_MODE_ICON_MIME_ATTR: {
573 			const char* attrName
574 				= exportMode == EXPORT_MODE_ICON_ATTR ?
575 					kVectorAttrNodeName : kVectorAttrMimeName;
576 			saver = new AttributeSaver(ref, attrName);
577 			break;
578 		}
579 
580 		case EXPORT_MODE_ICON_RDEF:
581 			saver = new SimpleFileSaver(new RDefExporter(), ref);
582 			break;
583 		case EXPORT_MODE_ICON_SOURCE:
584 			saver = new SimpleFileSaver(new SourceExporter(), ref);
585 			break;
586 
587 		case EXPORT_MODE_BITMAP:
588 			saver = new SimpleFileSaver(new BitmapExporter(64), ref);
589 			break;
590 
591 		case EXPORT_MODE_BITMAP_SET:
592 			saver = new BitmapSetSaver(ref);
593 			break;
594 
595 		case EXPORT_MODE_SVG:
596 			saver = new SimpleFileSaver(new SVGExporter(), ref);
597 			break;
598 
599 		case EXPORT_MODE_MESSAGE:
600 		default:
601 			saver = new NativeSaver(ref);
602 			break;
603 	}
604 
605 	return saver;
606 }
607 
608 // _SyncPanels
609 void
610 IconEditorApp::_SyncPanels(BFilePanel* from, BFilePanel* to)
611 {
612 	if (from->Window()->Lock()) {
613 		// location
614 		if (to->Window()->Lock()) {
615 			BRect frame = from->Window()->Frame();
616 			to->Window()->MoveTo(frame.left, frame.top);
617 			to->Window()->ResizeTo(frame.Width(), frame.Height());
618 			to->Window()->Unlock();
619 		}
620 		// current folder
621 		entry_ref panelDir;
622 		from->GetPanelDirectory(&panelDir);
623 		to->SetPanelDirectory(&panelDir);
624 		from->Window()->Unlock();
625 	}
626 }
627 
628 // _LastFilePath
629 const char*
630 IconEditorApp::_LastFilePath(path_kind which)
631 {
632 	const char* path = NULL;
633 
634 	switch (which) {
635 		case LAST_PATH_OPEN:
636 			if (fLastOpenPath.Length() > 0)
637 				path = fLastOpenPath.String();
638 			else if (fLastSavePath.Length() > 0)
639 				path = fLastSavePath.String();
640 			else if (fLastExportPath.Length() > 0)
641 				path = fLastExportPath.String();
642 			break;
643 		case LAST_PATH_SAVE:
644 			if (fLastSavePath.Length() > 0)
645 				path = fLastSavePath.String();
646 			else if (fLastExportPath.Length() > 0)
647 				path = fLastExportPath.String();
648 			else if (fLastOpenPath.Length() > 0)
649 				path = fLastOpenPath.String();
650 			break;
651 		case LAST_PATH_EXPORT:
652 			if (fLastExportPath.Length() > 0)
653 				path = fLastExportPath.String();
654 			else if (fLastSavePath.Length() > 0)
655 				path = fLastSavePath.String();
656 			else if (fLastOpenPath.Length() > 0)
657 				path = fLastOpenPath.String();
658 			break;
659 	}
660 	if (!path)
661 		path = "/boot/home";
662 
663 	return path;
664 }
665 
666 // #pragma mark -
667 
668 // _StoreSettings
669 void
670 IconEditorApp::_StoreSettings()
671 {
672 	BMessage settings('stns');
673 
674 	fMainWindow->StoreSettings(&settings);
675 
676 	if (settings.ReplaceInt32("export mode", fSavePanel->ExportMode()) < B_OK)
677 		settings.AddInt32("export mode", fSavePanel->ExportMode());
678 
679 	save_settings(&settings, "Icon-O-Matic");
680 }
681 
682 // _RestoreSettings
683 void
684 IconEditorApp::_RestoreSettings(BMessage& settings)
685 {
686 	load_settings(&settings, "Icon-O-Matic");
687 
688 	int32 mode;
689 	if (settings.FindInt32("export mode", &mode) >= B_OK)
690 		fSavePanel->SetExportMode(mode);
691 }
692 
693 // _InstallDocumentMimeType
694 void
695 IconEditorApp::_InstallDocumentMimeType()
696 {
697 	// install mime type of documents
698 	BMimeType mime(kNativeIconMimeType);
699 	status_t ret = mime.InitCheck();
700 	if (ret < B_OK) {
701 		fprintf(stderr, "Could not init native document mime type (%s): %s.\n",
702 			kNativeIconMimeType, strerror(ret));
703 		return;
704 	}
705 
706 	if (mime.IsInstalled() && !(modifiers() & B_SHIFT_KEY)) {
707 		// mime is already installed, and the user is not
708 		// pressing the shift key to force a re-install
709 		return;
710 	}
711 
712 	ret = mime.Install();
713 	if (ret < B_OK) {
714 		fprintf(stderr, "Could not install native document mime type (%s): %s.\n",
715 			kNativeIconMimeType, strerror(ret));
716 		return;
717 	}
718 	// set preferred app
719 	ret = mime.SetPreferredApp(kAppSig);
720 	if (ret < B_OK)
721 		fprintf(stderr, "Could not set native document preferred app: %s\n",
722 			strerror(ret));
723 
724 	// set descriptions
725 	ret = mime.SetShortDescription("Haiku Icon");
726 	if (ret < B_OK)
727 		fprintf(stderr, "Could not set short description of mime type: %s\n",
728 			strerror(ret));
729 	ret = mime.SetLongDescription("Native Haiku vector icon");
730 	if (ret < B_OK)
731 		fprintf(stderr, "Could not set long description of mime type: %s\n",
732 			strerror(ret));
733 
734 	// set extensions
735 	BMessage message('extn');
736 	message.AddString("extensions", "icon");
737 	ret = mime.SetFileExtensions(&message);
738 	if (ret < B_OK)
739 		fprintf(stderr, "Could not set extensions of mime type: %s\n",
740 			strerror(ret));
741 
742 	// set sniffer rule
743 	const char* snifferRule = "0.9 ('IMSG')";
744 	ret = mime.SetSnifferRule(snifferRule);
745 	if (ret < B_OK) {
746 		BString parseError;
747 		BMimeType::CheckSnifferRule(snifferRule, &parseError);
748 		fprintf(stderr, "Could not set sniffer rule of mime type: %s\n",
749 			parseError.String());
750 	}
751 
752 // NOTE: Icon-O-Matic writes the icon being saved as icon of the file anyways
753 // therefor, the following code is not needed, it is also not tested and I am
754 // spotting an error with SetIcon()
755 //	// set document icon
756 //	BResources* resources = AppResources();
757 //		// does not need to be freed (belongs to BApplication base)
758 //	if (resources) {
759 //		size_t size;
760 //		const void* iconData = resources->LoadResource('VICN', "IOM:DOC_ICON", &size);
761 //		if (iconData && size > 0) {
762 //			memcpy(largeIcon.Bits(), iconData, size);
763 //			if (mime.SetIcon(&largeIcon, B_LARGE_ICON) < B_OK)
764 //				fprintf(stderr, "Could not set large icon of mime type.\n");
765 //		} else
766 //			fprintf(stderr, "Could not find icon in app resources (data: %p, size: %ld).\n", iconData, size);
767 //	} else
768 //		fprintf(stderr, "Could not find app resources.\n");
769 }
770