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
178	return result;
179}
180
181
182void
183ShowImageApp::_StartPulse()
184{
185	if (!fPulseStarted) {
186		// Tell the app to begin checking
187		// for the number of open windows
188		fPulseStarted = true;
189		SetPulseRate(250000);
190			// Set pulse to every 1/4 second
191	}
192}
193
194
195void
196ShowImageApp::_Open(const entry_ref& ref, const BMessenger& trackerMessenger)
197{
198	fLastWindowFrame.OffsetBy(20, 20);
199	if (!BScreen(B_MAIN_SCREEN_ID).Frame().Contains(fLastWindowFrame))
200		fLastWindowFrame.OffsetTo(50, 50);
201
202	new ShowImageWindow(fLastWindowFrame, ref, trackerMessenger);
203}
204
205
206void
207ShowImageApp::_BroadcastToWindows(BMessage* message)
208{
209	const int32 count = CountWindows();
210	for (int32 i = 0; i < count; i++) {
211		// BMessenger checks for us if BWindow is still a valid object
212		BMessenger messenger(WindowAt(i));
213		messenger.SendMessage(message);
214	}
215}
216
217
218void
219ShowImageApp::_CheckClipboard()
220{
221	// Determines if the contents of the clipboard contain
222	// data that is useful to this application.
223	// After checking the clipboard, a message is sent to
224	// all windows indicating that the clipboard has changed
225	// and whether or not the clipboard contains useful data.
226	bool dataAvailable = false;
227
228	if (be_clipboard->Lock()) {
229		BMessage* clip = be_clipboard->Data();
230		if (clip != NULL) {
231			dataAvailable = clip->HasMessage("image/bitmap")
232				|| clip->HasMessage("image/x-be-bitmap");
233		}
234
235		be_clipboard->Unlock();
236	}
237
238	BMessage msg(B_CLIPBOARD_CHANGED);
239	msg.AddBool("data_available", dataAvailable);
240	_BroadcastToWindows(&msg);
241}
242
243
244void
245ShowImageApp::_UpdateLastWindowFrame()
246{
247	fLastWindowFrame = fSettings.GetRect("WindowFrame", fLastWindowFrame);
248	// Compensate the offset which we always add to new windows.
249	fLastWindowFrame.OffsetBy(-20, -20);
250}
251
252
253//	#pragma mark -
254
255
256int
257main(int, char**)
258{
259	ShowImageApp app;
260	app.Run();
261	return 0;
262}
263
264