/*
* Copyright 2017 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill
*/
#include "TaskTimer.h"
#include <Application.h>
#include <Catalog.h>
#include "constants.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "TaskTimer"
static int32 sAlertStackCount = 0;
TaskTimer::TaskTimer(const BMessenger& target, Task* owner)
:
BLooper(),
fTimeoutMicroSeconds(kTimerTimeoutSeconds * 1000000),
fTimerIsRunning(false),
fReplyTarget(target),
fMessageRunner(NULL),
fTimeoutMessage(TASK_TIMEOUT),
fTimeoutAlert(NULL),
fOwner(owner)
{
Run();
// Messenger for the Message Runner to use to send its message to the timer
fMessenger.SetTo(this);
// Invoker for the Alerts to use to send their messages to the timer
fTimeoutAlertInvoker.SetMessage(
new BMessage(TIMEOUT_ALERT_BUTTON_SELECTION));
fTimeoutAlertInvoker.SetTarget(this);
}
TaskTimer::~TaskTimer()
{
if (fTimeoutAlert) {
fTimeoutAlert->Lock();
fTimeoutAlert->Quit();
}
if (fMessageRunner)
fMessageRunner->SetCount(0);
}
bool
TaskTimer::QuitRequested()
{
return true;
}
void
TaskTimer::MessageReceived(BMessage* message)
{
switch (message->what)
{
case TASK_TIMEOUT:
{
fMessageRunner = NULL;
if (fTimerIsRunning) {
BString text(B_TRANSLATE_COMMENT("The task for repository"
" %name% is taking a long time to complete.",
"Alert message. Do not translate %name%"));
BString nameString("\"");
nameString.Append(fRepositoryName).Append("\"");
text.ReplaceFirst("%name%", nameString);
fTimeoutAlert = new BAlert("timeout", text,
B_TRANSLATE_COMMENT("Keep trying", "Button label"),
B_TRANSLATE_COMMENT("Cancel task", "Button label"),
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
fTimeoutAlert->SetShortcut(0, B_ESCAPE);
// Calculate the position to correctly stack this alert
BRect windowFrame = be_app->WindowAt(0)->Frame();
int32 stackPos = _NextAlertStackCount();
float xPos = windowFrame.left
+ windowFrame.Width()/2 + stackPos * kTimerAlertOffset;
float yPos = windowFrame.top
+ (stackPos + 1) * kTimerAlertOffset;
fTimeoutAlert->Go(&fTimeoutAlertInvoker);
xPos -= fTimeoutAlert->Frame().Width()/2;
// The correct frame for the alert is not available until
// after Go is called
fTimeoutAlert->MoveTo(xPos, yPos);
}
break;
}
case TIMEOUT_ALERT_BUTTON_SELECTION:
{
fTimeoutAlert = NULL;
// Timeout alert was invoked by user and timer still has not
// been stopped
if (fTimerIsRunning) {
// find which button was pressed
int32 selection = -1;
message->FindInt32("which", &selection);
if (selection == 1) {
BMessage reply(TASK_KILL_REQUEST);
reply.AddPointer(key_taskptr, fOwner);
fReplyTarget.SendMessage(&reply);
} else if (selection == 0) {
// Create new timer
fMessageRunner = new BMessageRunner(fMessenger,
&fTimeoutMessage, kTimerRetrySeconds * 1000000, 1);
}
}
break;
}
}
}
void
TaskTimer::Start(const char* name)
{
fTimerIsRunning = true;
fRepositoryName.SetTo(name);
// Create a message runner that will send a TASK_TIMEOUT message if the
// timer is not stopped
if (fMessageRunner == NULL) {
fMessageRunner = new BMessageRunner(fMessenger, &fTimeoutMessage,
fTimeoutMicroSeconds, 1);
}
else
fMessageRunner->SetInterval(fTimeoutMicroSeconds);
}
void
TaskTimer::Stop(const char* name)
{
fTimerIsRunning = false;
// Reset max timeout so we can reuse the runner at the next Start call
if (fMessageRunner != NULL)
fMessageRunner->SetInterval(LLONG_MAX);
// If timeout alert is showing replace it
if (fTimeoutAlert) {
// Remove current alert
BRect frame = fTimeoutAlert->Frame();
fTimeoutAlert->Quit();
fTimeoutAlert = NULL;
// Display new alert that won't send a message
BString text(B_TRANSLATE_COMMENT("Good news! The task for repository "
"%name% completed.", "Alert message. Do not translate %name%"));
BString nameString("\"");
nameString.Append(name).Append("\"");
text.ReplaceFirst("%name%", nameString);
BAlert* newAlert = new BAlert("timeout", text, kOKLabel, NULL, NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
newAlert->SetShortcut(0, B_ESCAPE);
newAlert->MoveTo(frame.left, frame.top);
newAlert->Go(NULL);
}
}
int32
TaskTimer::_NextAlertStackCount()
{
if (sAlertStackCount > 9)
sAlertStackCount = 0;
return sAlertStackCount++;
}
↑ V773 Visibility scope of the 'newAlert' pointer was exited without releasing the memory. A memory leak is possible.