Have the application do a single BAlert on a BApplication::QuitRequested()-event in multi-window situations. Move reading/writing of settings from window to application. Cascade-offset the most recent window when they collide.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32092 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jonas Sundström
2009-08-03 18:17:14 +00:00
parent 358e3e4e8b
commit 2680698b6d
7 changed files with 274 additions and 129 deletions
+225 -21
View File
@@ -4,7 +4,9 @@
#include "ZipOMatic.h" #include "ZipOMatic.h"
#include <Alert.h>
#include <Roster.h> #include <Roster.h>
#include <Screen.h>
#include <TrackerAddOn.h> #include <TrackerAddOn.h>
#include "ZipOMaticMisc.h" #include "ZipOMaticMisc.h"
@@ -39,15 +41,24 @@ main()
ZipOMatic::ZipOMatic() ZipOMatic::ZipOMatic()
: :
BApplication(ZIPOMATIC_APP_SIG), BApplication(ZIPOMATIC_APP_SIG),
fGotRefs(false) fSettings(),
fGotRefs(false),
fInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL, this)),
fWindowFrame(200, 200, 430, 310)
{ {
status_t status = _ReadSettings();
if (status != B_OK)
ErrorMessage("_ReadSettings()", status);
} }
ZipOMatic::~ZipOMatic() ZipOMatic::~ZipOMatic()
{ {
status_t status = _WriteSettings();
if (status != B_OK)
ErrorMessage("_WriteSettings()", status);
} }
@@ -76,15 +87,32 @@ ZipOMatic::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case ZIPPO_WINDOW_QUIT: case ZIPPO_WINDOW_QUIT:
{
BRect frame;
if (message->FindRect("frame", &frame) == B_OK)
fWindowFrame = frame;
snooze(200000); snooze(200000);
if (CountWindows() == 0) if (CountWindows() == 0)
Quit(); Quit();
break; break;
}
case B_SILENT_RELAUNCH: case B_SILENT_RELAUNCH:
_SilentRelaunch(); _SilentRelaunch();
break; break;
case ZIPPO_QUIT_OR_CONTINUE:
{
int32 button;
if (message->FindInt32("which", &button) == B_OK)
if (button == 0) {
_StopZipping();
} else {
if (CountWindows() == 0)
Quit();
}
break;
}
default: default:
BApplication::MessageReceived(message); BApplication::MessageReceived(message);
break; break;
@@ -95,33 +123,73 @@ ZipOMatic::MessageReceived(BMessage* message)
bool bool
ZipOMatic::QuitRequested (void) ZipOMatic::QuitRequested (void)
{ {
// Overriding BApplication's default behaviour on purpose
// so we can have multiple zippers pause in unison.
if (CountWindows() <= 0) if (CountWindows() <= 0)
return true; return true;
BList list(5);
BWindow* window; BWindow* window;
ZippoWindow* zippo;
ZippoWindow* lastFoundZippo;
int32 zippoCount = 0;
for (int32 i = 0;; i++) { for (int32 i = 0;; i++) {
window = WindowAt(i); window = WindowAt(i);
if (window == NULL)
break;
list.AddItem(window);
}
while (true) {
window = (BWindow*) list.RemoveItem(int32(0));
if (window == NULL) if (window == NULL)
break; break;
if (window->Lock()) { zippo = dynamic_cast<ZippoWindow*>(window);
window->PostMessage(B_QUIT_REQUESTED); if (zippo == NULL)
window->Unlock(); continue;
lastFoundZippo = zippo;
if (zippo->Lock()) {
if (zippo->IsZipping())
zippoCount++;
else
zippo->PostMessage(B_QUIT_REQUESTED);
zippo->Unlock();
} }
} }
if (zippoCount == 1) {
// This is likely the most frequent case - a single zipper.
// We post a message to the window so it can put up its own
// BAlert instead of the app-wide BAlert. This avoids making
// a difference between having pressed Commmand-W or Command-Q.
// Closing or quitting, it doesn't matter for a single window.
if (lastFoundZippo->Lock()) {
lastFoundZippo->Activate();
lastFoundZippo->PostMessage(B_QUIT_REQUESTED);
lastFoundZippo->Unlock();
}
return false;
}
if (zippoCount > 0) {
// The multi-zipper case differs from the single-zipper case
// in that zippers are not paused while the BAlert is up.
BString question;
question << "You have " << zippoCount;
question << " Zip-O-Matic running.\n\nDo you want to stop them?";
BAlert* alert = new BAlert("Stop or Continue", question.String(),
"Stop them", "Let them continue", NULL, B_WIDTH_AS_USUAL,
B_WARNING_ALERT);
alert->Go(fInvoker);
alert->Activate();
// BAlert, being modal, does not show on the current workspace
// if the application has no window there. Activate() triggers
// a switch to a workspace where it does have a window.
// TODO: See if AS_ACTIVATE_WINDOW should be handled differently
// in src/servers/app/Desktop.cpp Desktop::ActivateWindow()
// or if maybe BAlert should (and does not?) activate itself.
return false;
}
if (CountWindows() <= 0) if (CountWindows() <= 0)
return true; return true;
@@ -154,6 +222,7 @@ ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message)
foundNonBusyWindow = true; foundNonBusyWindow = true;
if (message != NULL) if (message != NULL)
window->PostMessage(message); window->PostMessage(message);
window->SetWorkspaces(B_CURRENT_WORKSPACE);
window->Activate(); window->Activate();
window->Unlock(); window->Unlock();
break; break;
@@ -164,8 +233,143 @@ ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message)
if (!foundNonBusyWindow) if (!foundNonBusyWindow)
{ {
ZippoWindow * window = new ZippoWindow(message); BScreen screen;
fWindowFrame.OffsetBy(screen.Frame().LeftTop());
_CascadeOnFrameCollision(&fWindowFrame);
if(!screen.Frame().Contains(fWindowFrame)) {
fWindowFrame.OffsetTo(screen.Frame().LeftTop());
fWindowFrame.OffsetBy(20,45);
// TODO: replace with CenterOnScreen()
}
ZippoWindow * window = new ZippoWindow(fWindowFrame, message);
window->Show(); window->Show();
} }
} }
void
ZipOMatic::_StopZipping()
{
BWindow* window;
ZippoWindow* zippo;
BList list;
for (int32 i = 0;; i++) {
window = WindowAt(i);
if (window == NULL)
break;
zippo = dynamic_cast<ZippoWindow*>(window);
if (zippo == NULL)
continue;
list.AddItem(zippo);
}
for (int32 i = 0;; i++) {
zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
if (zippo == NULL)
break;
if (zippo->Lock()) {
if (zippo->IsZipping())
zippo->StopZipping();
zippo->PostMessage(B_QUIT_REQUESTED);
zippo->Unlock();
}
}
}
status_t
ZipOMatic::_ReadSettings()
{
status_t status = B_OK;
status = fSettings.SetTo("zipomatic.msg");
if (status != B_OK)
return status;
status = fSettings.InitCheck();
if (status != B_OK)
return status;
status = fSettings.InitCheck();
if (status != B_OK)
return status;
status = fSettings.ReadSettings();
if (status != B_OK)
return status;
BRect frame;
status = fSettings.FindRect("frame", &frame);
if (status != B_OK)
return status;
fWindowFrame = frame;
return B_OK;
}
status_t
ZipOMatic::_WriteSettings()
{
status_t status = B_OK;
status = fSettings.InitCheck();
if (status != B_OK)
return status;
status = fSettings.MakeEmpty();
if (status != B_OK)
return status;
status = fSettings.AddRect("frame", fWindowFrame);
if (status != B_OK)
return status;
status = fSettings.WriteSettings();
if (status != B_OK)
return status;
return B_OK;
}
void
ZipOMatic::_CascadeOnFrameCollision(BRect* frame)
{
BWindow* window;
ZippoWindow* zippo;
BList list;
for (int32 i = 0;; i++) {
window = WindowAt(i);
if (window == NULL)
break;
zippo = dynamic_cast<ZippoWindow*>(window);
if (zippo == NULL)
continue;
list.AddItem(zippo);
}
for (int32 i = 0;; i++) {
zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
if (zippo == NULL)
break;
if (zippo->Lock()) {
if (frame->LeftTop() == zippo->Frame().LeftTop())
frame->OffsetBy(20, 20);
zippo->Unlock();
}
}
}
+11
View File
@@ -3,7 +3,11 @@
#include <Application.h> #include <Application.h>
#include <Invoker.h>
#include <Message.h> #include <Message.h>
#include <Rect.h>
#include "ZipOMaticSettings.h"
class ZipOMatic : public BApplication class ZipOMatic : public BApplication
@@ -18,11 +22,18 @@ public:
virtual bool QuitRequested(); virtual bool QuitRequested();
private: private:
status_t _ReadSettings();
status_t _WriteSettings();
void _CascadeOnFrameCollision(BRect* frame);
void _SilentRelaunch(); void _SilentRelaunch();
void _UseExistingOrCreateNewWindow(BMessage* void _UseExistingOrCreateNewWindow(BMessage*
message = NULL); message = NULL);
void _StopZipping();
ZippoSettings fSettings;
bool fGotRefs; bool fGotRefs;
BInvoker* fInvoker;
BRect fWindowFrame;
}; };
#endif // _ZIPOMATIC_H_ #endif // _ZIPOMATIC_H_
@@ -18,6 +18,11 @@
#define ZIPOMATIC_APP_SIG "application/x-vnd.haiku.zip-o-matic" #define ZIPOMATIC_APP_SIG "application/x-vnd.haiku.zip-o-matic"
#define ZIPPO_WINDOW_QUIT 'winq' #define ZIPPO_WINDOW_QUIT 'winq'
#define ZIPPO_QUIT_OR_CONTINUE 'alrt'
#define ZIPPO_THREAD_EXIT 'exit'
#define ZIPPO_THREAD_EXIT_ERROR 'exrr'
#define ZIPPO_TASK_DESCRIPTION 'strt'
#define ZIPPO_LINE_OF_STDOUT 'outp'
status_t FindAndCreateDirectory(directory_which which, status_t FindAndCreateDirectory(directory_which which,
BVolume* volume = NULL, const char* relativePath = NULL, BVolume* volume = NULL, const char* relativePath = NULL,
@@ -28,39 +28,26 @@
#include "ZipperThread.h" #include "ZipperThread.h"
ZippoWindow::ZippoWindow(BMessage* message) ZippoWindow::ZippoWindow(BRect frame, BMessage* refs)
: :
BWindow(BRect(200, 200, 430, 310), "Zip-O-Matic", B_TITLED_WINDOW, BWindow(frame, "Zip-O-Matic", B_TITLED_WINDOW, B_NOT_V_RESIZABLE),
B_NOT_V_RESIZABLE),
fView(NULL), fView(NULL),
fSettings(),
fThread(NULL), fThread(NULL),
fWindowGotRefs(false), fWindowGotRefs(false),
fZippingWasStopped(false), fZippingWasStopped(false),
fWindowInvoker(new BInvoker(new BMessage('alrt'), NULL, this)) fWindowInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL,
this))
{ {
status_t status = B_OK;
status = fSettings.SetTo("ZipOMatic.msg");
if (status != B_OK)
ErrorMessage("fSettings.SetTo()", status);
status = fSettings.InitCheck();
if (status != B_OK)
ErrorMessage("fSettings.InitCheck()", status);
fView = new ZippoView(Bounds()); fView = new ZippoView(Bounds());
AddChild(fView); AddChild(fView);
SetSizeLimits(Bounds().Width(), 15000, Bounds().Height(), SetSizeLimits(Bounds().Width(), 15000, Bounds().Height(),
Bounds().Height()); Bounds().Height());
_ReadSettings(); if (refs != NULL)
if (message != NULL)
{ {
fWindowGotRefs = true; fWindowGotRefs = true;
_StartZipping(message); _StartZipping(refs);
} }
} }
@@ -88,8 +75,7 @@ ZippoWindow::MessageReceived(BMessage* message)
} }
break; break;
case 'exit': case ZIPPO_THREAD_EXIT:
// thread has finished - (finished, quit, killed, we don't know)
fThread = NULL; fThread = NULL;
fView->fActivityView->Stop(); fView->fActivityView->Stop();
fView->fStopButton->SetEnabled(false); fView->fStopButton->SetEnabled(false);
@@ -102,7 +88,8 @@ ZippoWindow::MessageReceived(BMessage* message)
_CloseWindowOrKeepOpen(); _CloseWindowOrKeepOpen();
break; break;
case 'exrr': // thread has finished - badly case ZIPPO_THREAD_EXIT_ERROR:
// TODO: figure out why this case does not happen when it should
fThread = NULL; fThread = NULL;
fView->fActivityView->Stop(); fView->fActivityView->Stop();
fView->fStopButton->SetEnabled(false); fView->fStopButton->SetEnabled(false);
@@ -110,7 +97,7 @@ ZippoWindow::MessageReceived(BMessage* message)
fView->fZipOutputView->SetText("Error creating archive"); fView->fZipOutputView->SetText("Error creating archive");
break; break;
case 'strt': case ZIPPO_TASK_DESCRIPTION:
{ {
BString string; BString string;
if (message->FindString("archive_filename", &string) == B_OK) if (message->FindString("archive_filename", &string) == B_OK)
@@ -118,7 +105,7 @@ ZippoWindow::MessageReceived(BMessage* message)
break; break;
} }
case 'outp': case ZIPPO_LINE_OF_STDOUT:
{ {
BString string; BString string;
if (message->FindString("zip_output", &string) == B_OK) if (message->FindString("zip_output", &string) == B_OK)
@@ -126,12 +113,12 @@ ZippoWindow::MessageReceived(BMessage* message)
break; break;
} }
case 'alrt': case ZIPPO_QUIT_OR_CONTINUE:
{ {
int32 which_button = -1; int32 which_button = -1;
if (message->FindInt32("which", &which_button) == B_OK) { if (message->FindInt32("which", &which_button) == B_OK) {
if (which_button == 0) { if (which_button == 0) {
_StopZipping(); StopZipping();
} else { } else {
if (fThread != NULL) if (fThread != NULL)
fThread->ResumeExternalZip(); fThread->ResumeExternalZip();
@@ -152,85 +139,25 @@ ZippoWindow::MessageReceived(BMessage* message)
bool bool
ZippoWindow::QuitRequested() ZippoWindow::QuitRequested()
{ {
if (fThread == NULL) { if (!IsZipping()) {
_WriteSettings(); BMessage message(ZIPPO_WINDOW_QUIT);
be_app_messenger.SendMessage(ZIPPO_WINDOW_QUIT); message.AddRect("frame", Frame());
be_app_messenger.SendMessage(&message);
return true; return true;
} else { } else {
if (fThread != NULL) fThread->SuspendExternalZip();
fThread->SuspendExternalZip();
fView->fActivityView->Pause(); fView->fActivityView->Pause();
BAlert* alert = new BAlert("Stop or Continue", BAlert* alert = new BAlert("Stop or Continue",
"Are you sure you want to stop creating this archive?", "Stop", "Are you sure you want to stop creating this archive?", "Stop",
"Continue", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); "Continue", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->Go(fWindowInvoker); alert->Go(fWindowInvoker);
return false; return false;
} }
} }
status_t
ZippoWindow::_ReadSettings()
{
status_t status = B_OK;
status = fSettings.InitCheck();
if (status != B_OK)
ErrorMessage("fSettings.InitCheck()", status);
status = fSettings.ReadSettings();
if (status != B_OK)
ErrorMessage("fSettings.ReadSettings()", status);
BRect windowRect;
status = fSettings.FindRect("windowRect", &windowRect);
if (status != B_OK)
{
ErrorMessage("fSettings.FindRect(windowRect)", status);
return status;
}
ResizeTo(windowRect.Width(), windowRect.Height());
MoveTo(windowRect.LeftTop());
return B_OK;
}
status_t
ZippoWindow::_WriteSettings()
{
status_t status = B_OK;
status = fSettings.InitCheck();
if (status != B_OK)
ErrorMessage("fSettings.InitCheck()", status);
status = fSettings.MakeEmpty();
if (status != B_OK)
ErrorMessage("fSettings.MakeEmpty()", status);
status = fSettings.AddRect("windowRect", Frame());
if (status != B_OK)
{
ErrorMessage("fSettings.AddRect(windowRect)", status);
return status;
}
status = fSettings.WriteSettings();
if (status != B_OK)
{
ErrorMessage("fSettings.WriteSettings()", status);
return status;
}
return B_OK;
}
void void
ZippoWindow::_StartZipping(BMessage* message) ZippoWindow::_StartZipping(BMessage* message)
{ {
@@ -245,7 +172,7 @@ ZippoWindow::_StartZipping(BMessage* message)
void void
ZippoWindow::_StopZipping() ZippoWindow::StopZipping()
{ {
fZippingWasStopped = true; fZippingWasStopped = true;
@@ -8,7 +8,6 @@
#include <MenuItem.h> #include <MenuItem.h>
#include <Window.h> #include <Window.h>
#include "ZipOMaticSettings.h"
#include "ZipOMaticView.h" #include "ZipOMaticView.h"
#include "ZipperThread.h" #include "ZipperThread.h"
@@ -16,7 +15,7 @@
class ZippoWindow : public BWindow class ZippoWindow : public BWindow
{ {
public: public:
ZippoWindow(BMessage* message = NULL); ZippoWindow(BRect frame, BMessage* refs = NULL);
~ZippoWindow(); ~ZippoWindow();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
@@ -24,18 +23,14 @@ public:
virtual void Zoom(BPoint origin, float width, float height); virtual void Zoom(BPoint origin, float width, float height);
bool IsZipping(); bool IsZipping();
void StopZipping();
private: private:
status_t _ReadSettings();
status_t _WriteSettings();
void _StartZipping(BMessage* message); void _StartZipping(BMessage* message);
void _StopZipping();
void _CloseWindowOrKeepOpen(); void _CloseWindowOrKeepOpen();
ZippoView* fView; ZippoView* fView;
ZippoSettings fSettings;
ZipperThread* fThread; ZipperThread* fThread;
bool fWindowGotRefs; bool fWindowGotRefs;
@@ -140,8 +140,10 @@ ZipperThread::ThreadStartup()
archiveName.Prepend("Creating archive: "); archiveName.Prepend("Creating archive: ");
_SendMessageToWindow('strt', "archive_filename", archiveName.String()); _SendMessageToWindow(ZIPPO_TASK_DESCRIPTION, "archive_filename",
_SendMessageToWindow('outp', "zip_output", "Preparing to archive"); archiveName.String());
_SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output",
"Preparing to archive");
return B_OK; return B_OK;
} }
@@ -164,12 +166,12 @@ ZipperThread::ExecuteUnit()
if (!strncmp(" a", output, 3)) { if (!strncmp(" a", output, 3)) {
output[2] = 'A'; output[2] = 'A';
_SendMessageToWindow('outp', "zip_output", output + 2); _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output + 2);
} else if (!strncmp("up", output, 2)) { } else if (!strncmp("up", output, 2)) {
output[0] = 'U'; output[0] = 'U';
_SendMessageToWindow('outp', "zip_output", output); _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output);
} else { } else {
_SendMessageToWindow('outp', "zip_output", output); _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output);
} }
return B_OK; return B_OK;
@@ -202,10 +204,10 @@ ZipperThread::ExecuteUnitFailed(status_t status)
if (status == EOF) { if (status == EOF) {
// thread has finished, been quit or killed, we don't know // thread has finished, been quit or killed, we don't know
_SendMessageToWindow('exit'); _SendMessageToWindow(ZIPPO_THREAD_EXIT);
} else { } else {
// explicit error - communicate error to Window // explicit error - communicate error to Window
_SendMessageToWindow('exrr'); _SendMessageToWindow(ZIPPO_THREAD_EXIT_ERROR);
} }
Quit(); Quit();
@@ -14,6 +14,7 @@
#include <Message.h> #include <Message.h>
#include <Messenger.h> #include <Messenger.h>
#include <String.h>
#include <Window.h> #include <Window.h>
#include "GenericThread.h" #include "GenericThread.h"