1/*
2 * Copyright 2003-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Fernando Francisco de Oliveira
7 *		Michael Wilber
8 *		Michael Pfeiffer
9 *		Ryan Leavengood
10 */
11
12
13#include "ShowImageApp.h"
14
15#include <stdio.h>
16
17#include <Catalog.h>
18#include <Clipboard.h>
19#include <FilePanel.h>
20#include <Locale.h>
21#include <Path.h>
22#include <Screen.h>
23#include <String.h>
24
25#include "ShowImageConstants.h"
26#include "ShowImageWindow.h"
27#include "ToolBarIcons.h"
28
29
30const char* kApplicationSignature = "application/x-vnd.Haiku-ShowImage";
31const int32 kWindowsToIgnore = 1;
32	// ignore the always open file panel
33
34
35ShowImageApp::ShowImageApp()
36	:
37	BApplication(kApplicationSignature),
38	fOpenPanel(new BFilePanel(B_OPEN_PANEL)),
39	fPulseStarted(false),
40	fLastWindowFrame(BRect(30, 30, 430, 330))
41{
42	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("ShowImage");
43	_UpdateLastWindowFrame();
44	// BBitmap can be created after there is a BApplication instance.
45	init_tool_bar_icons();
46}
47
48
49ShowImageApp::~ShowImageApp()
50{
51	// BBitmap must be deleted while there is still a BApplication instance.
52	uninit_tool_bar_icons();
53}
54
55
56void
57ShowImageApp::ArgvReceived(int32 argc, char **argv)
58{
59	BMessage message;
60	bool hasRefs = false;
61
62	// get current working directory
63	const char* cwd;
64	if (CurrentMessage() == NULL
65		|| CurrentMessage()->FindString("cwd", &cwd) != B_OK)
66		cwd = "";
67
68	for (int32 i = 1; i < argc; i++) {
69		BPath path;
70		if (argv[i][0] == '/') {
71			// absolute path
72			path.SetTo(argv[i]);
73		} else {
74			// relative path
75			path.SetTo(cwd);
76			path.Append(argv[i]);
77		}
78
79		entry_ref ref;
80		status_t err = get_ref_for_path(path.Path(), &ref);
81		if (err == B_OK) {
82			message.AddRef("refs", &ref);
83			hasRefs = true;
84		}
85	}
86
87	if (hasRefs)
88		RefsReceived(&message);
89}
90
91
92void
93ShowImageApp::ReadyToRun()
94{
95	if (CountWindows() == kWindowsToIgnore)
96		fOpenPanel->Show();
97	else {
98		// If image windows are already open
99		// (paths supplied on the command line)
100		// start checking the number of open windows
101		_StartPulse();
102	}
103
104	be_clipboard->StartWatching(be_app_messenger);
105		// tell the clipboard to notify this app when its contents change
106}
107
108
109void
110ShowImageApp::MessageReceived(BMessage* message)
111{
112	switch (message->what) {
113		case MSG_FILE_OPEN:
114			fOpenPanel->Show();
115			break;
116
117		case B_CANCEL:
118			// File open panel was closed,
119			// start checking count of open windows
120			_StartPulse();
121			break;
122
123		case B_CLIPBOARD_CHANGED:
124			_CheckClipboard();
125			break;
126
127		case MSG_WINDOW_HAS_QUIT:
128			// Make sure that new windows open with the location/size of the
129			// last closed window.
130			_UpdateLastWindowFrame();
131			break;
132
133		default:
134			BApplication::MessageReceived(message);
135			break;
136	}
137}
138
139
140void
141ShowImageApp::Pulse()
142{
143	// Bug: The BFilePanel is automatically closed if the volume that
144	// is displayed is unmounted.
145	if (!IsLaunching() && CountWindows() <= kWindowsToIgnore) {
146		// If the application is not launching and
147		// all windows are closed except for the file open panel,
148		// quit the application
149		PostMessage(B_QUIT_REQUESTED);
150	}
151}
152
153
154void
155ShowImageApp::RefsReceived(BMessage* message)
156{
157	// If a tracker window opened me, get a messenger from it.
158	BMessenger trackerMessenger;
159	if (message->HasMessenger("TrackerViewToken"))
160		message->FindMessenger("TrackerViewToken", &trackerMessenger);
161
162	entry_ref ref;
163	for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++)
164		_Open(ref, trackerMessenger);
165}
166
167
168bool
169ShowImageApp::QuitRequested()
170{
171	// Give the windows a chance to prompt the user if there are changes
172	bool result = BApplication::QuitRequested();
173	if (result) {
174		be_clipboard->StopWatching(be_app_messenger);
175			// tell clipboard we don't want anymore notification
176	}
177	DefaultCache().Stop();
178
179	return result;
180}
181
182
183void
184ShowImageApp::_StartPulse()
185{
186	if (!fPulseStarted) {
187		// Tell the app to begin checking
188		// for the number of open windows
189		fPulseStarted = true;
190		SetPulseRate(250000);
191			// Set pulse to every 1/4 second
192	}
193}
194
195
196void
197ShowImageApp::_Open(const entry_ref& ref, const BMessenger& trackerMessenger)
198{
199	fLastWindowFrame.OffsetBy(20, 20);
200	if (!BScreen(B_MAIN_SCREEN_ID).Frame().Contains(fLastWindowFrame))
201		fLastWindowFrame.OffsetTo(50, 50);
202
203	new ShowImageWindow(fLastWindowFrame, ref, trackerMessenger);
204}
205
206
207void
208ShowImageApp::_BroadcastToWindows(BMessage* message)
209{
210	const int32 count = CountWindows();
211	for (int32 i = 0; i < count; i++) {
212		// BMessenger checks for us if BWindow is still a valid object
213		BMessenger messenger(WindowAt(i));
214		messenger.SendMessage(message);
215	}
216}
217
218
219void
220ShowImageApp::_CheckClipboard()
221{
222	// Determines if the contents of the clipboard contain
223	// data that is useful to this application.
224	// After checking the clipboard, a message is sent to
225	// all windows indicating that the clipboard has changed
226	// and whether or not the clipboard contains useful data.
227	bool dataAvailable = false;
228
229	if (be_clipboard->Lock()) {
230		BMessage* clip = be_clipboard->Data();
231		if (clip != NULL) {
232			dataAvailable = clip->HasMessage("image/bitmap")
233				|| clip->HasMessage("image/x-be-bitmap");
234		}
235
236		be_clipboard->Unlock();
237	}
238
239	BMessage msg(B_CLIPBOARD_CHANGED);
240	msg.AddBool("data_available", dataAvailable);
241	_BroadcastToWindows(&msg);
242}
243
244
245void
246ShowImageApp::_UpdateLastWindowFrame()
247{
248	fLastWindowFrame = fSettings.GetRect("WindowFrame", fLastWindowFrame);
249	// Compensate the offset which we always add to new windows.
250	fLastWindowFrame.OffsetBy(-20, -20);
251}
252
253
254//	#pragma mark -
255
256
257int
258main(int, char**)
259{
260	ShowImageApp app;
261	app.Run();
262	return 0;
263}
264
265