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 <Alert.h>
#include <Roster.h>
#include <Screen.h>
#include <TrackerAddOn.h>
#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<ZippoWindow*>(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<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 <Invoker.h>
#include <Message.h>
#include <Rect.h>
#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_
@@ -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,
@@ -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;
@@ -8,7 +8,6 @@
#include <MenuItem.h>
#include <Window.h>
#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;
@@ -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();
@@ -14,6 +14,7 @@
#include <Message.h>
#include <Messenger.h>
#include <String.h>
#include <Window.h>
#include "GenericThread.h"