15bf2b6ebSBrian Hill /*
25bf2b6ebSBrian Hill * Copyright 2017 Haiku Inc. All rights reserved.
35bf2b6ebSBrian Hill * Distributed under the terms of the MIT License.
45bf2b6ebSBrian Hill *
55bf2b6ebSBrian Hill * Authors:
65bf2b6ebSBrian Hill * Brian Hill
75bf2b6ebSBrian Hill */
85bf2b6ebSBrian Hill
95bf2b6ebSBrian Hill
105bf2b6ebSBrian Hill #include "TaskTimer.h"
115bf2b6ebSBrian Hill
125bf2b6ebSBrian Hill #include <Application.h>
135bf2b6ebSBrian Hill #include <Catalog.h>
145bf2b6ebSBrian Hill
155bf2b6ebSBrian Hill #include "constants.h"
165bf2b6ebSBrian Hill
175bf2b6ebSBrian Hill #undef B_TRANSLATION_CONTEXT
185bf2b6ebSBrian Hill #define B_TRANSLATION_CONTEXT "TaskTimer"
195bf2b6ebSBrian Hill
205bf2b6ebSBrian Hill static int32 sAlertStackCount = 0;
215bf2b6ebSBrian Hill
225bf2b6ebSBrian Hill
TaskTimer(const BMessenger & target,Task * owner)235bf2b6ebSBrian Hill TaskTimer::TaskTimer(const BMessenger& target, Task* owner)
245bf2b6ebSBrian Hill :
255bf2b6ebSBrian Hill BLooper(),
265bf2b6ebSBrian Hill fTimeoutMicroSeconds(kTimerTimeoutSeconds * 1000000),
275bf2b6ebSBrian Hill fTimerIsRunning(false),
285bf2b6ebSBrian Hill fReplyTarget(target),
295bf2b6ebSBrian Hill fMessageRunner(NULL),
305bf2b6ebSBrian Hill fTimeoutMessage(TASK_TIMEOUT),
315bf2b6ebSBrian Hill fTimeoutAlert(NULL),
325bf2b6ebSBrian Hill fOwner(owner)
335bf2b6ebSBrian Hill {
345bf2b6ebSBrian Hill Run();
355bf2b6ebSBrian Hill
365bf2b6ebSBrian Hill // Messenger for the Message Runner to use to send its message to the timer
375bf2b6ebSBrian Hill fMessenger.SetTo(this);
385bf2b6ebSBrian Hill // Invoker for the Alerts to use to send their messages to the timer
395bf2b6ebSBrian Hill fTimeoutAlertInvoker.SetMessage(
405bf2b6ebSBrian Hill new BMessage(TIMEOUT_ALERT_BUTTON_SELECTION));
415bf2b6ebSBrian Hill fTimeoutAlertInvoker.SetTarget(this);
425bf2b6ebSBrian Hill }
435bf2b6ebSBrian Hill
445bf2b6ebSBrian Hill
~TaskTimer()455bf2b6ebSBrian Hill TaskTimer::~TaskTimer()
465bf2b6ebSBrian Hill {
475bf2b6ebSBrian Hill if (fTimeoutAlert) {
485bf2b6ebSBrian Hill fTimeoutAlert->Lock();
495bf2b6ebSBrian Hill fTimeoutAlert->Quit();
505bf2b6ebSBrian Hill }
515bf2b6ebSBrian Hill if (fMessageRunner)
525bf2b6ebSBrian Hill fMessageRunner->SetCount(0);
535bf2b6ebSBrian Hill }
545bf2b6ebSBrian Hill
555bf2b6ebSBrian Hill
565bf2b6ebSBrian Hill bool
QuitRequested()575bf2b6ebSBrian Hill TaskTimer::QuitRequested()
585bf2b6ebSBrian Hill {
595bf2b6ebSBrian Hill return true;
605bf2b6ebSBrian Hill }
615bf2b6ebSBrian Hill
625bf2b6ebSBrian Hill
635bf2b6ebSBrian Hill void
MessageReceived(BMessage * message)645bf2b6ebSBrian Hill TaskTimer::MessageReceived(BMessage* message)
655bf2b6ebSBrian Hill {
665bf2b6ebSBrian Hill switch (message->what)
675bf2b6ebSBrian Hill {
68*856ecc7bSBrian Hill case TASK_TIMEOUT:
69*856ecc7bSBrian Hill {
705bf2b6ebSBrian Hill fMessageRunner = NULL;
715bf2b6ebSBrian Hill if (fTimerIsRunning) {
725bf2b6ebSBrian Hill BString text(B_TRANSLATE_COMMENT("The task for repository"
735bf2b6ebSBrian Hill " %name% is taking a long time to complete.",
745bf2b6ebSBrian Hill "Alert message. Do not translate %name%"));
755bf2b6ebSBrian Hill BString nameString("\"");
765bf2b6ebSBrian Hill nameString.Append(fRepositoryName).Append("\"");
775bf2b6ebSBrian Hill text.ReplaceFirst("%name%", nameString);
785bf2b6ebSBrian Hill fTimeoutAlert = new BAlert("timeout", text,
795bf2b6ebSBrian Hill B_TRANSLATE_COMMENT("Keep trying", "Button label"),
805bf2b6ebSBrian Hill B_TRANSLATE_COMMENT("Cancel task", "Button label"),
815bf2b6ebSBrian Hill NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
825bf2b6ebSBrian Hill fTimeoutAlert->SetShortcut(0, B_ESCAPE);
835bf2b6ebSBrian Hill // Calculate the position to correctly stack this alert
845bf2b6ebSBrian Hill BRect windowFrame = be_app->WindowAt(0)->Frame();
855bf2b6ebSBrian Hill int32 stackPos = _NextAlertStackCount();
865bf2b6ebSBrian Hill float xPos = windowFrame.left
875bf2b6ebSBrian Hill + windowFrame.Width()/2 + stackPos * kTimerAlertOffset;
885bf2b6ebSBrian Hill float yPos = windowFrame.top
895bf2b6ebSBrian Hill + (stackPos + 1) * kTimerAlertOffset;
905bf2b6ebSBrian Hill fTimeoutAlert->Go(&fTimeoutAlertInvoker);
915bf2b6ebSBrian Hill xPos -= fTimeoutAlert->Frame().Width()/2;
925bf2b6ebSBrian Hill // The correct frame for the alert is not available until
935bf2b6ebSBrian Hill // after Go is called
945bf2b6ebSBrian Hill fTimeoutAlert->MoveTo(xPos, yPos);
955bf2b6ebSBrian Hill }
965bf2b6ebSBrian Hill break;
975bf2b6ebSBrian Hill }
98*856ecc7bSBrian Hill
99*856ecc7bSBrian Hill case TIMEOUT_ALERT_BUTTON_SELECTION:
100*856ecc7bSBrian Hill {
1015bf2b6ebSBrian Hill fTimeoutAlert = NULL;
1025bf2b6ebSBrian Hill // Timeout alert was invoked by user and timer still has not
1035bf2b6ebSBrian Hill // been stopped
1045bf2b6ebSBrian Hill if (fTimerIsRunning) {
1055bf2b6ebSBrian Hill // find which button was pressed
1065bf2b6ebSBrian Hill int32 selection = -1;
1075bf2b6ebSBrian Hill message->FindInt32("which", &selection);
1085bf2b6ebSBrian Hill if (selection == 1) {
1095bf2b6ebSBrian Hill BMessage reply(TASK_KILL_REQUEST);
1105bf2b6ebSBrian Hill reply.AddPointer(key_taskptr, fOwner);
1115bf2b6ebSBrian Hill fReplyTarget.SendMessage(&reply);
1125bf2b6ebSBrian Hill } else if (selection == 0) {
1135bf2b6ebSBrian Hill // Create new timer
1145bf2b6ebSBrian Hill fMessageRunner = new BMessageRunner(fMessenger,
1155bf2b6ebSBrian Hill &fTimeoutMessage, kTimerRetrySeconds * 1000000, 1);
1165bf2b6ebSBrian Hill }
1175bf2b6ebSBrian Hill }
1185bf2b6ebSBrian Hill break;
1195bf2b6ebSBrian Hill }
1205bf2b6ebSBrian Hill }
1215bf2b6ebSBrian Hill }
1225bf2b6ebSBrian Hill
1235bf2b6ebSBrian Hill
1245bf2b6ebSBrian Hill void
Start(const char * name)1255bf2b6ebSBrian Hill TaskTimer::Start(const char* name)
1265bf2b6ebSBrian Hill {
1275bf2b6ebSBrian Hill fTimerIsRunning = true;
1285bf2b6ebSBrian Hill fRepositoryName.SetTo(name);
1295bf2b6ebSBrian Hill
1305bf2b6ebSBrian Hill // Create a message runner that will send a TASK_TIMEOUT message if the
1315bf2b6ebSBrian Hill // timer is not stopped
132*856ecc7bSBrian Hill if (fMessageRunner == NULL) {
1335bf2b6ebSBrian Hill fMessageRunner = new BMessageRunner(fMessenger, &fTimeoutMessage,
1345bf2b6ebSBrian Hill fTimeoutMicroSeconds, 1);
135*856ecc7bSBrian Hill }
1365bf2b6ebSBrian Hill else
1375bf2b6ebSBrian Hill fMessageRunner->SetInterval(fTimeoutMicroSeconds);
1385bf2b6ebSBrian Hill }
1395bf2b6ebSBrian Hill
1405bf2b6ebSBrian Hill
1415bf2b6ebSBrian Hill void
Stop(const char * name)1425bf2b6ebSBrian Hill TaskTimer::Stop(const char* name)
1435bf2b6ebSBrian Hill {
1445bf2b6ebSBrian Hill fTimerIsRunning = false;
1455bf2b6ebSBrian Hill
1465bf2b6ebSBrian Hill // Reset max timeout so we can reuse the runner at the next Start call
1475bf2b6ebSBrian Hill if (fMessageRunner != NULL)
1485bf2b6ebSBrian Hill fMessageRunner->SetInterval(LLONG_MAX);
1495bf2b6ebSBrian Hill
1505bf2b6ebSBrian Hill // If timeout alert is showing replace it
1515bf2b6ebSBrian Hill if (fTimeoutAlert) {
1525bf2b6ebSBrian Hill // Remove current alert
1535bf2b6ebSBrian Hill BRect frame = fTimeoutAlert->Frame();
1545bf2b6ebSBrian Hill fTimeoutAlert->Quit();
1555bf2b6ebSBrian Hill fTimeoutAlert = NULL;
1565bf2b6ebSBrian Hill
1575bf2b6ebSBrian Hill // Display new alert that won't send a message
1585bf2b6ebSBrian Hill BString text(B_TRANSLATE_COMMENT("Good news! The task for repository "
1595bf2b6ebSBrian Hill "%name% completed.", "Alert message. Do not translate %name%"));
1605bf2b6ebSBrian Hill BString nameString("\"");
1615bf2b6ebSBrian Hill nameString.Append(name).Append("\"");
1625bf2b6ebSBrian Hill text.ReplaceFirst("%name%", nameString);
1635bf2b6ebSBrian Hill BAlert* newAlert = new BAlert("timeout", text, kOKLabel, NULL, NULL,
1645bf2b6ebSBrian Hill B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1655bf2b6ebSBrian Hill newAlert->SetShortcut(0, B_ESCAPE);
1665bf2b6ebSBrian Hill newAlert->MoveTo(frame.left, frame.top);
1675bf2b6ebSBrian Hill newAlert->Go(NULL);
1685bf2b6ebSBrian Hill }
1695bf2b6ebSBrian Hill }
1705bf2b6ebSBrian Hill
1715bf2b6ebSBrian Hill
1725bf2b6ebSBrian Hill int32
_NextAlertStackCount()1735bf2b6ebSBrian Hill TaskTimer::_NextAlertStackCount()
1745bf2b6ebSBrian Hill {
1755bf2b6ebSBrian Hill if (sAlertStackCount > 9)
1765bf2b6ebSBrian Hill sAlertStackCount = 0;
1775bf2b6ebSBrian Hill return sAlertStackCount++;
1785bf2b6ebSBrian Hill }
179