1/*
2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Jonas Sundstr��m, jonas@kirilla.com
7 */
8
9
10#include "ZipOMatic.h"
11
12#include <Alert.h>
13#include <Roster.h>
14#include <StringFormat.h>
15#include <TrackerAddOnAppLaunch.h>
16
17#include "ZipOMaticMisc.h"
18#include "ZipOMaticWindow.h"
19
20
21#undef B_TRANSLATION_CONTEXT
22#define B_TRANSLATION_CONTEXT "file:ZipOMatic.cpp"
23
24
25int
26main()
27{
28	ZipOMatic app;
29	app.Run();
30
31	return 0;
32}
33
34
35ZipOMatic::ZipOMatic()
36	:
37	BApplication(ZIPOMATIC_APP_SIG),
38	fGotRefs(false),
39	fInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL, this))
40{
41}
42
43
44ZipOMatic::~ZipOMatic()
45{
46}
47
48
49void
50ZipOMatic::RefsReceived(BMessage* message)
51{
52	entry_ref ref;
53	if (message->FindRef("refs", &ref) == B_OK) {
54		_UseExistingOrCreateNewWindow(message);
55		fGotRefs = true;
56	} else if (!IsLaunching()) {
57		PostMessage(B_SILENT_RELAUNCH);
58	}
59}
60
61
62void
63ZipOMatic::ReadyToRun()
64{
65	if (!fGotRefs)
66		_UseExistingOrCreateNewWindow();
67}
68
69
70void
71ZipOMatic::MessageReceived(BMessage* message)
72{
73	switch (message->what) {
74		case ZIPPO_WINDOW_QUIT:
75		{
76			snooze(200000);
77			if (CountWindows() == 0)
78				Quit();
79			break;
80		}
81		case B_SILENT_RELAUNCH:
82			_SilentRelaunch();
83			break;
84
85		case ZIPPO_QUIT_OR_CONTINUE:
86		{
87			int32 button;
88			if (message->FindInt32("which", &button) == B_OK) {
89				if (button == 0) {
90					_StopZipping();
91				} else {
92					if (CountWindows() == 0)
93						Quit();
94				}
95			}
96			break;
97		}
98
99		default:
100			BApplication::MessageReceived(message);
101			break;
102	}
103}
104
105
106bool
107ZipOMatic::QuitRequested(void)
108{
109	if (CountWindows() <= 0)
110		return true;
111
112	BWindow* window;
113	ZippoWindow* zippo;
114	ZippoWindow* lastFoundZippo = NULL;
115	int32 zippoCount = 0;
116
117	for (int32 i = 0;; i++) {
118		window = WindowAt(i);
119		if (window == NULL)
120			break;
121
122		zippo = dynamic_cast<ZippoWindow*>(window);
123		if (zippo == NULL)
124			continue;
125
126		lastFoundZippo = zippo;
127
128		if (zippo->Lock()) {
129			if (zippo->IsZipping())
130				zippoCount++;
131			else
132				zippo->PostMessage(B_QUIT_REQUESTED);
133
134			zippo->Unlock();
135		}
136	}
137
138	if (zippoCount == 1) {
139		// This is likely the most frequent case - a single zipper.
140		// We post a message to the window so it can put up its own
141		// BAlert instead of the app-wide BAlert. This avoids making
142		// a difference between having pressed Commmand-W or Command-Q.
143		// Closing or quitting, it doesn't matter for a single window.
144
145		if (lastFoundZippo->Lock()) {
146			lastFoundZippo->Activate();
147			lastFoundZippo->PostMessage(B_QUIT_REQUESTED);
148			lastFoundZippo->Unlock();
149		}
150		return false;
151	}
152
153	if (zippoCount > 0) {
154		// The multi-zipper case differs from the single-zipper case
155		// in that zippers are not paused while the BAlert is up.
156
157		static BStringFormat format(
158			B_TRANSLATE("You have {0, plural, one{# Zip-O-Matic} "
159				"other{# Zip-O-Matics}} running.\n\n"));
160
161		BString question;
162
163		format.Format(question, zippoCount);
164
165		question << B_TRANSLATE("Do you want to stop them?");
166
167		BAlert* alert = new BAlert(NULL, question.String(),
168			B_TRANSLATE("Stop them"), B_TRANSLATE("Let them continue"), NULL,
169			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
170		alert->Go(fInvoker);
171		alert->Activate();
172			// BAlert, being modal, does not show on the current workspace
173			// if the application has no window there. Activate() triggers
174			// a switch to a workspace where it does have a window.
175
176			// TODO: See if AS_ACTIVATE_WINDOW should be handled differently
177			// in src/servers/app/Desktop.cpp Desktop::ActivateWindow()
178			// or if maybe BAlert should (and does not?) activate itself.
179
180		return false;
181	}
182
183	if (CountWindows() <= 0)
184		return true;
185
186	return false;
187}
188
189
190void
191ZipOMatic::_SilentRelaunch()
192{
193	_UseExistingOrCreateNewWindow();
194}
195
196
197void
198ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message)
199{
200	int32 windowCount = 0;
201	BWindow* bWindow;
202	ZippoWindow* zWindow;
203	BList list;
204
205	while (1) {
206		bWindow = WindowAt(windowCount++);
207		if (bWindow == NULL)
208			break;
209
210		zWindow = dynamic_cast<ZippoWindow*>(bWindow);
211		if (zWindow == NULL)
212			continue;
213
214		list.AddItem(zWindow);
215
216		if (zWindow->Lock()) {
217			if (!zWindow->IsZipping()) {
218				if (message != NULL)
219					zWindow->PostMessage(message);
220				zWindow->SetWorkspaces(B_CURRENT_WORKSPACE);
221				zWindow->Activate();
222				zWindow->Unlock();
223				return;
224			}
225			zWindow->Unlock();
226		}
227	}
228
229	if (message) {
230		zWindow = new ZippoWindow(list);
231		zWindow->PostMessage(message);
232	} else {
233		zWindow = new ZippoWindow(list, true);
234	}
235
236	zWindow->Show();
237}
238
239
240void
241ZipOMatic::_StopZipping()
242{
243	BWindow* window;
244	ZippoWindow* zippo;
245	BList list;
246
247	for (int32 i = 0;; i++) {
248		window = WindowAt(i);
249		if (window == NULL)
250			break;
251
252		zippo = dynamic_cast<ZippoWindow*>(window);
253		if (zippo == NULL)
254			continue;
255
256		list.AddItem(zippo);
257	}
258
259	for (int32 i = 0;; i++) {
260		zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
261		if (zippo == NULL)
262			break;
263
264		if (zippo->Lock()) {
265			if (zippo->IsZipping())
266				zippo->StopZipping();
267
268			zippo->PostMessage(B_QUIT_REQUESTED);
269			zippo->Unlock();
270		}
271	}
272}
273
274