diff --git a/src/add-ons/tracker/zipomatic/ZipOMatic.cpp b/src/add-ons/tracker/zipomatic/ZipOMatic.cpp index 387b93a973..9a5af4a95a 100644 --- a/src/add-ons/tracker/zipomatic/ZipOMatic.cpp +++ b/src/add-ons/tracker/zipomatic/ZipOMatic.cpp @@ -4,7 +4,9 @@ #include "ZipOMatic.h" +#include #include +#include #include #include "ZipOMaticMisc.h" @@ -39,15 +41,24 @@ main() ZipOMatic::ZipOMatic() : 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() { - + status_t status = _WriteSettings(); + + if (status != B_OK) + ErrorMessage("_WriteSettings()", status); } @@ -76,15 +87,32 @@ ZipOMatic::MessageReceived(BMessage* message) { switch (message->what) { case ZIPPO_WINDOW_QUIT: + { + BRect frame; + if (message->FindRect("frame", &frame) == B_OK) + fWindowFrame = frame; snooze(200000); if (CountWindows() == 0) Quit(); break; - + } case B_SILENT_RELAUNCH: _SilentRelaunch(); 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: BApplication::MessageReceived(message); break; @@ -95,33 +123,73 @@ ZipOMatic::MessageReceived(BMessage* message) bool ZipOMatic::QuitRequested (void) { - // Overriding BApplication's default behaviour on purpose - // so we can have multiple zippers pause in unison. - if (CountWindows() <= 0) return true; - BList list(5); BWindow* window; + ZippoWindow* zippo; + ZippoWindow* lastFoundZippo; + int32 zippoCount = 0; for (int32 i = 0;; i++) { - window = WindowAt(i); - if (window == NULL) - break; - - list.AddItem(window); - } - - while (true) { - window = (BWindow*) list.RemoveItem(int32(0)); + window = WindowAt(i); if (window == NULL) break; - if (window->Lock()) { - window->PostMessage(B_QUIT_REQUESTED); - window->Unlock(); + zippo = dynamic_cast(window); + if (zippo == NULL) + 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) return true; @@ -154,6 +222,7 @@ ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message) foundNonBusyWindow = true; if (message != NULL) window->PostMessage(message); + window->SetWorkspaces(B_CURRENT_WORKSPACE); window->Activate(); window->Unlock(); break; @@ -164,8 +233,143 @@ ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message) 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(); } } + +void +ZipOMatic::_StopZipping() +{ + BWindow* window; + ZippoWindow* zippo; + BList list; + + for (int32 i = 0;; i++) { + window = WindowAt(i); + if (window == NULL) + break; + + zippo = dynamic_cast(window); + if (zippo == NULL) + continue; + + list.AddItem(zippo); + } + + for (int32 i = 0;; i++) { + zippo = static_cast(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(window); + if (zippo == NULL) + continue; + + list.AddItem(zippo); + } + + for (int32 i = 0;; i++) { + zippo = static_cast(list.ItemAt(i)); + if (zippo == NULL) + break; + + if (zippo->Lock()) { + if (frame->LeftTop() == zippo->Frame().LeftTop()) + frame->OffsetBy(20, 20); + zippo->Unlock(); + } + } +} + diff --git a/src/add-ons/tracker/zipomatic/ZipOMatic.h b/src/add-ons/tracker/zipomatic/ZipOMatic.h index c516f9c665..70a36b8563 100644 --- a/src/add-ons/tracker/zipomatic/ZipOMatic.h +++ b/src/add-ons/tracker/zipomatic/ZipOMatic.h @@ -3,7 +3,11 @@ #include +#include #include +#include + +#include "ZipOMaticSettings.h" class ZipOMatic : public BApplication @@ -18,11 +22,18 @@ public: virtual bool QuitRequested(); private: + status_t _ReadSettings(); + status_t _WriteSettings(); + void _CascadeOnFrameCollision(BRect* frame); void _SilentRelaunch(); void _UseExistingOrCreateNewWindow(BMessage* message = NULL); + void _StopZipping(); + ZippoSettings fSettings; bool fGotRefs; + BInvoker* fInvoker; + BRect fWindowFrame; }; #endif // _ZIPOMATIC_H_ diff --git a/src/add-ons/tracker/zipomatic/ZipOMaticMisc.h b/src/add-ons/tracker/zipomatic/ZipOMaticMisc.h index a3603266d8..4f08c3e49f 100644 --- a/src/add-ons/tracker/zipomatic/ZipOMaticMisc.h +++ b/src/add-ons/tracker/zipomatic/ZipOMaticMisc.h @@ -18,6 +18,11 @@ #define ZIPOMATIC_APP_SIG "application/x-vnd.haiku.zip-o-matic" #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, BVolume* volume = NULL, const char* relativePath = NULL, diff --git a/src/add-ons/tracker/zipomatic/ZipOMaticWindow.cpp b/src/add-ons/tracker/zipomatic/ZipOMaticWindow.cpp index ccddab6d97..49acb85a55 100644 --- a/src/add-ons/tracker/zipomatic/ZipOMaticWindow.cpp +++ b/src/add-ons/tracker/zipomatic/ZipOMaticWindow.cpp @@ -28,39 +28,26 @@ #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, - B_NOT_V_RESIZABLE), + BWindow(frame, "Zip-O-Matic", B_TITLED_WINDOW, B_NOT_V_RESIZABLE), fView(NULL), - fSettings(), fThread(NULL), fWindowGotRefs(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()); AddChild(fView); SetSizeLimits(Bounds().Width(), 15000, Bounds().Height(), Bounds().Height()); - _ReadSettings(); - - if (message != NULL) + if (refs != NULL) { fWindowGotRefs = true; - _StartZipping(message); + _StartZipping(refs); } } @@ -88,8 +75,7 @@ ZippoWindow::MessageReceived(BMessage* message) } break; - case 'exit': - // thread has finished - (finished, quit, killed, we don't know) + case ZIPPO_THREAD_EXIT: fThread = NULL; fView->fActivityView->Stop(); fView->fStopButton->SetEnabled(false); @@ -102,7 +88,8 @@ ZippoWindow::MessageReceived(BMessage* message) _CloseWindowOrKeepOpen(); 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; fView->fActivityView->Stop(); fView->fStopButton->SetEnabled(false); @@ -110,7 +97,7 @@ ZippoWindow::MessageReceived(BMessage* message) fView->fZipOutputView->SetText("Error creating archive"); break; - case 'strt': + case ZIPPO_TASK_DESCRIPTION: { BString string; if (message->FindString("archive_filename", &string) == B_OK) @@ -118,7 +105,7 @@ ZippoWindow::MessageReceived(BMessage* message) break; } - case 'outp': + case ZIPPO_LINE_OF_STDOUT: { BString string; if (message->FindString("zip_output", &string) == B_OK) @@ -126,12 +113,12 @@ ZippoWindow::MessageReceived(BMessage* message) break; } - case 'alrt': + case ZIPPO_QUIT_OR_CONTINUE: { int32 which_button = -1; if (message->FindInt32("which", &which_button) == B_OK) { if (which_button == 0) { - _StopZipping(); + StopZipping(); } else { if (fThread != NULL) fThread->ResumeExternalZip(); @@ -152,85 +139,25 @@ ZippoWindow::MessageReceived(BMessage* message) bool ZippoWindow::QuitRequested() { - if (fThread == NULL) { - _WriteSettings(); - be_app_messenger.SendMessage(ZIPPO_WINDOW_QUIT); + if (!IsZipping()) { + BMessage message(ZIPPO_WINDOW_QUIT); + message.AddRect("frame", Frame()); + be_app_messenger.SendMessage(&message); return true; } else { - if (fThread != NULL) - fThread->SuspendExternalZip(); - + fThread->SuspendExternalZip(); fView->fActivityView->Pause(); - + BAlert* alert = new BAlert("Stop or Continue", "Are you sure you want to stop creating this archive?", "Stop", "Continue", NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); alert->Go(fWindowInvoker); + 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 ZippoWindow::_StartZipping(BMessage* message) { @@ -245,7 +172,7 @@ ZippoWindow::_StartZipping(BMessage* message) void -ZippoWindow::_StopZipping() +ZippoWindow::StopZipping() { fZippingWasStopped = true; diff --git a/src/add-ons/tracker/zipomatic/ZipOMaticWindow.h b/src/add-ons/tracker/zipomatic/ZipOMaticWindow.h index 2876b3b6ce..18c9f14af0 100644 --- a/src/add-ons/tracker/zipomatic/ZipOMaticWindow.h +++ b/src/add-ons/tracker/zipomatic/ZipOMaticWindow.h @@ -8,7 +8,6 @@ #include #include -#include "ZipOMaticSettings.h" #include "ZipOMaticView.h" #include "ZipperThread.h" @@ -16,7 +15,7 @@ class ZippoWindow : public BWindow { public: - ZippoWindow(BMessage* message = NULL); + ZippoWindow(BRect frame, BMessage* refs = NULL); ~ZippoWindow(); virtual void MessageReceived(BMessage* message); @@ -24,18 +23,14 @@ public: virtual void Zoom(BPoint origin, float width, float height); bool IsZipping(); + void StopZipping(); private: - status_t _ReadSettings(); - status_t _WriteSettings(); void _StartZipping(BMessage* message); - void _StopZipping(); - void _CloseWindowOrKeepOpen(); ZippoView* fView; - ZippoSettings fSettings; ZipperThread* fThread; bool fWindowGotRefs; diff --git a/src/add-ons/tracker/zipomatic/ZipperThread.cpp b/src/add-ons/tracker/zipomatic/ZipperThread.cpp index 530ca2b769..a9e50a0901 100644 --- a/src/add-ons/tracker/zipomatic/ZipperThread.cpp +++ b/src/add-ons/tracker/zipomatic/ZipperThread.cpp @@ -140,8 +140,10 @@ ZipperThread::ThreadStartup() archiveName.Prepend("Creating archive: "); - _SendMessageToWindow('strt', "archive_filename", archiveName.String()); - _SendMessageToWindow('outp', "zip_output", "Preparing to archive"); + _SendMessageToWindow(ZIPPO_TASK_DESCRIPTION, "archive_filename", + archiveName.String()); + _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", + "Preparing to archive"); return B_OK; } @@ -164,12 +166,12 @@ ZipperThread::ExecuteUnit() if (!strncmp(" a", output, 3)) { output[2] = 'A'; - _SendMessageToWindow('outp', "zip_output", output + 2); + _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output + 2); } else if (!strncmp("up", output, 2)) { output[0] = 'U'; - _SendMessageToWindow('outp', "zip_output", output); + _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output); } else { - _SendMessageToWindow('outp', "zip_output", output); + _SendMessageToWindow(ZIPPO_LINE_OF_STDOUT, "zip_output", output); } return B_OK; @@ -202,10 +204,10 @@ ZipperThread::ExecuteUnitFailed(status_t status) if (status == EOF) { // thread has finished, been quit or killed, we don't know - _SendMessageToWindow('exit'); + _SendMessageToWindow(ZIPPO_THREAD_EXIT); } else { // explicit error - communicate error to Window - _SendMessageToWindow('exrr'); + _SendMessageToWindow(ZIPPO_THREAD_EXIT_ERROR); } Quit(); diff --git a/src/add-ons/tracker/zipomatic/ZipperThread.h b/src/add-ons/tracker/zipomatic/ZipperThread.h index c0f099b084..d6476cc4c4 100644 --- a/src/add-ons/tracker/zipomatic/ZipperThread.h +++ b/src/add-ons/tracker/zipomatic/ZipperThread.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "GenericThread.h"