Implement showing the estimated time to finish a file process. It will toggle
automatically between showing amount copied + speed and estimated finish time + time left. It could be implemented to toggle on mouse click, but then it would be a hidden feature. Comments welcome. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35136 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -57,8 +57,12 @@ All rights reserved.
|
|||||||
const float kDefaultStatusViewHeight = 50;
|
const float kDefaultStatusViewHeight = 50;
|
||||||
const bigtime_t kMaxUpdateInterval = 100000LL;
|
const bigtime_t kMaxUpdateInterval = 100000LL;
|
||||||
const bigtime_t kSpeedReferenceInterval = 2000000LL;
|
const bigtime_t kSpeedReferenceInterval = 2000000LL;
|
||||||
|
const bigtime_t kShowSpeedInterval = 8000000LL;
|
||||||
|
const bigtime_t kShowEstimatedFinishInterval = 4000000LL;
|
||||||
const BRect kStatusRect(200, 200, 550, 200);
|
const BRect kStatusRect(200, 200, 550, 200);
|
||||||
|
|
||||||
|
static bigtime_t sLastEstimatedFinishSpeedToggleTime = -1;
|
||||||
|
static bool sShowSpeed = true;
|
||||||
|
|
||||||
class TCustomButton : public BButton {
|
class TCustomButton : public BButton {
|
||||||
public:
|
public:
|
||||||
@@ -145,6 +149,38 @@ TCustomButton::Draw(BRect updateRect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
class StatusBackgroundView : public BView {
|
||||||
|
public:
|
||||||
|
StatusBackgroundView(BRect frame)
|
||||||
|
: BView(frame, "BackView", B_FOLLOW_ALL, B_WILL_DRAW | B_PULSE_NEEDED)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Pulse()
|
||||||
|
{
|
||||||
|
bigtime_t now = system_time();
|
||||||
|
if (sShowSpeed
|
||||||
|
&& sLastEstimatedFinishSpeedToggleTime + kShowSpeedInterval
|
||||||
|
<= now) {
|
||||||
|
sShowSpeed = false;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime = now;
|
||||||
|
} else if (!sShowSpeed
|
||||||
|
&& sLastEstimatedFinishSpeedToggleTime
|
||||||
|
+ kShowEstimatedFinishInterval <= now) {
|
||||||
|
sShowSpeed = true;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
BStatusWindow::BStatusWindow()
|
BStatusWindow::BStatusWindow()
|
||||||
:
|
:
|
||||||
BWindow(kStatusRect, "Tracker status", B_TITLED_WINDOW,
|
BWindow(kStatusRect, "Tracker status", B_TITLED_WINDOW,
|
||||||
@@ -156,12 +192,11 @@ BStatusWindow::BStatusWindow()
|
|||||||
fMouseDownFilter = new BStatusMouseFilter();
|
fMouseDownFilter = new BStatusMouseFilter();
|
||||||
AddCommonFilter(fMouseDownFilter);
|
AddCommonFilter(fMouseDownFilter);
|
||||||
|
|
||||||
BRect bounds(Bounds());
|
BView* view = new StatusBackgroundView(Bounds());
|
||||||
|
|
||||||
BView* view = new BView(bounds, "BackView", B_FOLLOW_ALL, B_WILL_DRAW);
|
|
||||||
view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
||||||
AddChild(view);
|
AddChild(view);
|
||||||
|
|
||||||
|
SetPulseRate(1000000);
|
||||||
|
|
||||||
Hide();
|
Hide();
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
@@ -180,6 +215,11 @@ BStatusWindow::CreateStatusItem(thread_id thread, StatusWindowState type)
|
|||||||
BRect rect(Bounds());
|
BRect rect(Bounds());
|
||||||
if (BStatusView* lastView = fViewList.LastItem())
|
if (BStatusView* lastView = fViewList.LastItem())
|
||||||
rect.top = lastView->Frame().bottom + 1;
|
rect.top = lastView->Frame().bottom + 1;
|
||||||
|
else {
|
||||||
|
// This is the first status item, reset speed/estimated finish toggle.
|
||||||
|
sShowSpeed = true;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime = system_time();
|
||||||
|
}
|
||||||
rect.bottom = rect.top + kDefaultStatusViewHeight - 1;
|
rect.bottom = rect.top + kDefaultStatusViewHeight - 1;
|
||||||
|
|
||||||
BStatusView* view = new BStatusView(rect, thread, type);
|
BStatusView* view = new BStatusView(rect, thread, type);
|
||||||
@@ -507,9 +547,11 @@ BStatusView::Init()
|
|||||||
fCurrentBytesPerSecondSlot = 0;
|
fCurrentBytesPerSecondSlot = 0;
|
||||||
fItemSize = 0;
|
fItemSize = 0;
|
||||||
fSizeProcessed = 0;
|
fSizeProcessed = 0;
|
||||||
|
|
||||||
fProcessStartTime = fLastSpeedReferenceTime = system_time();
|
|
||||||
fLastSpeedReferenceSize = 0;
|
fLastSpeedReferenceSize = 0;
|
||||||
|
fEstimatedFinishReferenceSize = 0;
|
||||||
|
|
||||||
|
fProcessStartTime = fLastSpeedReferenceTime = fEstimatedFinishReferenceTime
|
||||||
|
= system_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -642,41 +684,100 @@ BStatusView::Draw(BRect updateRect)
|
|||||||
SetHighColor(0, 0, 0);
|
SetHighColor(0, 0, 0);
|
||||||
DrawString(buffer.String(), tp);
|
DrawString(buffer.String(), tp);
|
||||||
|
|
||||||
// Draw speed info
|
SetHighColor(tint_color(LowColor(), B_DARKEN_4_TINT));
|
||||||
|
|
||||||
|
BFont font;
|
||||||
|
GetFont(&font);
|
||||||
|
float oldFontSize = font.Size();
|
||||||
|
float fontSize = oldFontSize * 0.8f;
|
||||||
|
font.SetSize(max_c(8.0f, fontSize));
|
||||||
|
SetFont(&font, B_FONT_SIZE);
|
||||||
|
|
||||||
float rightDivider = tp.x + StringWidth(buffer.String()) + 5.0f;
|
float rightDivider = tp.x + StringWidth(buffer.String()) + 5.0f;
|
||||||
if (fBytesPerSecond != 0.0) {
|
|
||||||
SetHighColor(tint_color(LowColor(), B_DARKEN_4_TINT));
|
|
||||||
|
|
||||||
BFont font;
|
if (sShowSpeed) {
|
||||||
GetFont(&font);
|
// Draw speed info
|
||||||
float oldFontSize = font.Size();
|
if (fBytesPerSecond != 0.0) {
|
||||||
float fontSize = oldFontSize * 0.8f;
|
char sizeBuffer[128];
|
||||||
font.SetSize(max_c(8.0f, fontSize));
|
buffer = "(";
|
||||||
SetFont(&font, B_FONT_SIZE);
|
buffer << string_for_size((double)fSizeProcessed, sizeBuffer);
|
||||||
|
buffer << " of ";
|
||||||
|
buffer << string_for_size((double)fTotalSize, sizeBuffer);
|
||||||
|
buffer << ", ";
|
||||||
|
buffer << string_for_size(fBytesPerSecond, sizeBuffer);
|
||||||
|
buffer << "/s)";
|
||||||
|
tp.x = fStatusBar->Frame().right - StringWidth(buffer.String());
|
||||||
|
if (tp.x > rightDivider)
|
||||||
|
DrawString(buffer.String(), tp);
|
||||||
|
else {
|
||||||
|
// complete string too wide, try with shorter version
|
||||||
|
buffer << string_for_size(fBytesPerSecond, sizeBuffer);
|
||||||
|
buffer << "/s";
|
||||||
|
tp.x = fStatusBar->Frame().right
|
||||||
|
- StringWidth(buffer.String());
|
||||||
|
if (tp.x > rightDivider)
|
||||||
|
DrawString(buffer.String(), tp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
double totalBytesPerSecond = (double)(fSizeProcessed
|
||||||
|
- fEstimatedFinishReferenceSize)
|
||||||
|
* 1000000LL / (system_time() - fEstimatedFinishReferenceTime);
|
||||||
|
double secondsRemaining = (fTotalSize - fSizeProcessed)
|
||||||
|
/ totalBytesPerSecond;
|
||||||
|
time_t now = (time_t)real_time_clock();
|
||||||
|
time_t finishTime = (time_t)(now + secondsRemaining);
|
||||||
|
|
||||||
|
tm _time;
|
||||||
|
tm* time = localtime_r(&finishTime, &_time);
|
||||||
|
int32 year = time->tm_year + 1900;
|
||||||
|
|
||||||
|
char timeText[32];
|
||||||
|
time_t secondsPerDay = 24 * 60 * 60;
|
||||||
|
// TODO: Localization of time string...
|
||||||
|
if (now < finishTime - secondsPerDay) {
|
||||||
|
// process is going to take more than a day!
|
||||||
|
sprintf(timeText, "%0*d:%0*d %0*d/%0*d/%ld",
|
||||||
|
2, time->tm_hour, 2, time->tm_min,
|
||||||
|
2, time->tm_mon + 1, 2, time->tm_mday, year);
|
||||||
|
} else {
|
||||||
|
sprintf(timeText, "%0*d:%0*d",
|
||||||
|
2, time->tm_hour, 2, time->tm_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
BString buffer1("Finish: ");
|
||||||
|
buffer1 << timeText;
|
||||||
|
finishTime -= now;
|
||||||
|
time = gmtime(&finishTime);
|
||||||
|
|
||||||
|
BString buffer2;
|
||||||
|
if (finishTime > secondsPerDay)
|
||||||
|
buffer2 << "Over " << finishTime / secondsPerDay << " days";
|
||||||
|
else if (finishTime > 60 * 60)
|
||||||
|
buffer2 << "Over " << finishTime / (60 * 60) << " hours";
|
||||||
|
else if (finishTime > 60)
|
||||||
|
buffer2 << finishTime / 60 << " minutes";
|
||||||
|
else
|
||||||
|
buffer2 << finishTime << " seconds";
|
||||||
|
|
||||||
|
buffer2 << " left";
|
||||||
|
|
||||||
char sizeBuffer[128];
|
|
||||||
buffer = "(";
|
buffer = "(";
|
||||||
buffer << string_for_size((double)fSizeProcessed, sizeBuffer);
|
buffer << buffer1 << " - " << buffer2 << ")";
|
||||||
buffer << " of ";
|
|
||||||
buffer << string_for_size((double)fTotalSize, sizeBuffer);
|
|
||||||
buffer << ", ";
|
|
||||||
buffer << string_for_size(fBytesPerSecond, sizeBuffer);
|
|
||||||
buffer << "/s)";
|
|
||||||
tp.x = fStatusBar->Frame().right - StringWidth(buffer.String());
|
tp.x = fStatusBar->Frame().right - StringWidth(buffer.String());
|
||||||
if (tp.x > rightDivider)
|
if (tp.x > rightDivider)
|
||||||
DrawString(buffer.String(), tp);
|
DrawString(buffer.String(), tp);
|
||||||
else {
|
else {
|
||||||
// complete string too wide, try with shorter version
|
// complete string too wide, try with shorter version
|
||||||
buffer << string_for_size(fBytesPerSecond, sizeBuffer);
|
buffer = "(";
|
||||||
buffer << "/s";
|
buffer << buffer1 << ")";
|
||||||
tp.x = fStatusBar->Frame().right - StringWidth(buffer.String());
|
tp.x = fStatusBar->Frame().right - StringWidth(buffer.String());
|
||||||
if (tp.x > rightDivider)
|
if (tp.x > rightDivider)
|
||||||
DrawString(buffer.String(), tp);
|
DrawString(buffer.String(), tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
font.SetSize(oldFontSize);
|
|
||||||
SetFont(&font, B_FONT_SIZE);
|
|
||||||
}
|
}
|
||||||
|
font.SetSize(oldFontSize);
|
||||||
|
SetFont(&font, B_FONT_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,6 +804,8 @@ BStatusView::MessageReceived(BMessage *message)
|
|||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
if (!fIsPaused) {
|
if (!fIsPaused) {
|
||||||
|
fEstimatedFinishReferenceTime = system_time();
|
||||||
|
fEstimatedFinishReferenceSize = fSizeProcessed;
|
||||||
|
|
||||||
// force window update
|
// force window update
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ private:
|
|||||||
off_t fItemSize;
|
off_t fItemSize;
|
||||||
off_t fSizeProcessed;
|
off_t fSizeProcessed;
|
||||||
off_t fLastSpeedReferenceSize;
|
off_t fLastSpeedReferenceSize;
|
||||||
|
off_t fEstimatedFinishReferenceSize;
|
||||||
int32 fCurItem;
|
int32 fCurItem;
|
||||||
int32 fType;
|
int32 fType;
|
||||||
BBitmap* fBitmap;
|
BBitmap* fBitmap;
|
||||||
@@ -144,6 +145,7 @@ private:
|
|||||||
bigtime_t fLastSpeedReferenceTime;
|
bigtime_t fLastSpeedReferenceTime;
|
||||||
bigtime_t fProcessStartTime;
|
bigtime_t fProcessStartTime;
|
||||||
bigtime_t fLastSpeedUpdateTime;
|
bigtime_t fLastSpeedUpdateTime;
|
||||||
|
bigtime_t fEstimatedFinishReferenceTime;
|
||||||
static const size_t kBytesPerSecondSlots = 5;
|
static const size_t kBytesPerSecondSlots = 5;
|
||||||
size_t fCurrentBytesPerSecondSlot;
|
size_t fCurrentBytesPerSecondSlot;
|
||||||
double fBytesPerSecondSlot[kBytesPerSecondSlots];
|
double fBytesPerSecondSlot[kBytesPerSecondSlots];
|
||||||
|
|||||||
Reference in New Issue
Block a user