Implemented displaying the download speed and estimated finish time. Looks and
behaves the same as in Tracker's status window. git-svn-id: http://svn.haiku-os.org/webpositive/webkit/trunk@352 94f232f2-1747-11df-bad5-a5bfde151594
This commit is contained in:
committed by
Alexandre Deckner
parent
7998882116
commit
90ac9c309c
@@ -35,15 +35,17 @@
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <GridLayoutBuilder.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <Roster.h>
|
||||
#include <SpaceLayoutItem.h>
|
||||
#include <StatusBar.h>
|
||||
#include <StringView.h>
|
||||
|
||||
#include "WebDownload.h"
|
||||
#include "WebPage.h"
|
||||
#include "StringForSize.h"
|
||||
|
||||
|
||||
enum {
|
||||
@@ -53,6 +55,14 @@ enum {
|
||||
REMOVE_DOWNLOAD = 'rmdn',
|
||||
};
|
||||
|
||||
const bigtime_t kMaxUpdateInterval = 100000LL;
|
||||
const bigtime_t kSpeedReferenceInterval = 500000LL;
|
||||
const bigtime_t kShowSpeedInterval = 8000000LL;
|
||||
const bigtime_t kShowEstimatedFinishInterval = 4000000LL;
|
||||
|
||||
bigtime_t DownloadProgressView::sLastEstimatedFinishSpeedToggleTime = -1;
|
||||
bool DownloadProgressView::sShowSpeed = true;
|
||||
|
||||
|
||||
class IconView : public BView {
|
||||
public:
|
||||
@@ -167,22 +177,20 @@ public:
|
||||
|
||||
DownloadProgressView::DownloadProgressView(BWebDownload* download)
|
||||
:
|
||||
BGridView(8, 3),
|
||||
BGroupView(B_HORIZONTAL, 8),
|
||||
fDownload(download),
|
||||
fURL(download->URL()),
|
||||
fPath(download->Path()),
|
||||
fExpectedSize(download->ExpectedSize())
|
||||
fPath(download->Path())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DownloadProgressView::DownloadProgressView(const BMessage* archive)
|
||||
:
|
||||
BGridView(8, 3),
|
||||
BGroupView(B_HORIZONTAL, 8),
|
||||
fDownload(NULL),
|
||||
fURL(),
|
||||
fPath(),
|
||||
fExpectedSize(0)
|
||||
fPath()
|
||||
{
|
||||
const char* string;
|
||||
if (archive->FindString("path", &string) == B_OK)
|
||||
@@ -195,10 +203,22 @@ DownloadProgressView::DownloadProgressView(const BMessage* archive)
|
||||
bool
|
||||
DownloadProgressView::Init(BMessage* archive)
|
||||
{
|
||||
fCurrentSize = 0;
|
||||
fExpectedSize = 0;
|
||||
fLastUpdateTime = 0;
|
||||
fBytesPerSecond = 0.0;
|
||||
for (size_t i = 0; i < kBytesPerSecondSlots; i++)
|
||||
fBytesPerSecondSlot[i] = 0.0;
|
||||
fCurrentBytesPerSecondSlot = 0;
|
||||
fLastSpeedReferenceSize = 0;
|
||||
fEstimatedFinishReferenceSize = 0;
|
||||
|
||||
fProcessStartTime = fLastSpeedReferenceTime = fEstimatedFinishReferenceTime
|
||||
= system_time();
|
||||
|
||||
SetViewColor(245, 245, 245);
|
||||
SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW);
|
||||
|
||||
BGridLayout* layout = GridLayout();
|
||||
if (archive) {
|
||||
fStatusBar = new BStatusBar("download progress", fPath.Leaf());
|
||||
float value;
|
||||
@@ -233,11 +253,37 @@ DownloadProgressView::Init(BMessage* archive)
|
||||
fBottomButton->SetEnabled(fDownload == NULL);
|
||||
}
|
||||
|
||||
fInfoView = new BStringView("info view", "");
|
||||
|
||||
BGroupLayout* layout = GroupLayout();
|
||||
layout->SetInsets(8, 5, 5, 6);
|
||||
layout->AddView(fIconView, 0, 0, 1, 2);
|
||||
layout->AddView(fStatusBar, 1, 0, 1, 2);
|
||||
layout->AddView(fTopButton, 2, 0);
|
||||
layout->AddView(fBottomButton, 2, 1);
|
||||
layout->AddView(fIconView);
|
||||
BView* verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
|
||||
.Add(fStatusBar)
|
||||
.Add(fInfoView)
|
||||
;
|
||||
verticalGroup->SetViewColor(ViewColor());
|
||||
layout->AddView(verticalGroup);
|
||||
verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
|
||||
.Add(fTopButton)
|
||||
.Add(fBottomButton)
|
||||
;
|
||||
verticalGroup->SetViewColor(ViewColor());
|
||||
layout->AddView(verticalGroup);
|
||||
|
||||
BFont font;
|
||||
fInfoView->GetFont(&font);
|
||||
float fontSize = font.Size() * 0.8f;
|
||||
font.SetSize(max_c(8.0f, fontSize));
|
||||
fInfoView->SetFont(&font, B_FONT_SIZE);
|
||||
fInfoView->SetHighColor(tint_color(fInfoView->LowColor(),
|
||||
B_DARKEN_4_TINT));
|
||||
// font_height fontHeight;
|
||||
// font.GetHeight(&fontHeight);
|
||||
// float textHeight = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
|
||||
// fInfoView->SetExplicitMinSize(BSize(B_SIZE_UNSET, textHeight));
|
||||
// fInfoView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, textHeight));
|
||||
fInfoView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -314,13 +360,23 @@ DownloadProgressView::MessageReceived(BMessage* message)
|
||||
fIconView->SetTo(entry);
|
||||
fStatusBar->Reset(fPath.Leaf());
|
||||
_StartNodeMonitor(entry);
|
||||
|
||||
// Immediately switch to speed display whenever a new download
|
||||
// starts.
|
||||
sShowSpeed = true;
|
||||
sLastEstimatedFinishSpeedToggleTime
|
||||
= fProcessStartTime = fLastSpeedReferenceTime
|
||||
= fEstimatedFinishReferenceTime = system_time();
|
||||
break;
|
||||
};
|
||||
case B_DOWNLOAD_PROGRESS:
|
||||
{
|
||||
float progress;
|
||||
if (message->FindFloat("progress", &progress) == B_OK)
|
||||
fStatusBar->SetTo(progress);
|
||||
int64 currentSize;
|
||||
int64 expectedSize;
|
||||
if (message->FindInt64("current size", ¤tSize) == B_OK
|
||||
&& message->FindInt64("expected size", &expectedSize) == B_OK) {
|
||||
_UpdateStatus(currentSize, expectedSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OPEN_DOWNLOAD:
|
||||
@@ -427,7 +483,7 @@ DownloadProgressView::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BGridView::MessageReceived(message);
|
||||
BGroupView::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,6 +524,7 @@ DownloadProgressView::DownloadFinished()
|
||||
fBottomButton->SetLabel("Remove");
|
||||
fBottomButton->SetMessage(new BMessage(REMOVE_DOWNLOAD));
|
||||
fBottomButton->SetEnabled(true);
|
||||
fInfoView->SetText("");
|
||||
}
|
||||
|
||||
|
||||
@@ -484,9 +541,171 @@ DownloadProgressView::DownloadCanceled()
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
DownloadProgressView::SpeedVersusEstimatedFinishTogglePulse()
|
||||
{
|
||||
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 - private
|
||||
|
||||
|
||||
void
|
||||
DownloadProgressView::_UpdateStatus(off_t currentSize, off_t expectedSize)
|
||||
{
|
||||
fCurrentSize = currentSize;
|
||||
fExpectedSize = expectedSize;
|
||||
|
||||
fStatusBar->SetTo(100.0 * currentSize / expectedSize);
|
||||
|
||||
bigtime_t currentTime = system_time();
|
||||
if ((currentTime - fLastUpdateTime) > kMaxUpdateInterval) {
|
||||
fLastUpdateTime = currentTime;
|
||||
|
||||
if (currentTime >= fLastSpeedReferenceTime + kSpeedReferenceInterval) {
|
||||
// update current speed every kSpeedReferenceInterval
|
||||
fCurrentBytesPerSecondSlot
|
||||
= (fCurrentBytesPerSecondSlot + 1) % kBytesPerSecondSlots;
|
||||
fBytesPerSecondSlot[fCurrentBytesPerSecondSlot]
|
||||
= (double)(currentSize - fLastSpeedReferenceSize)
|
||||
* 1000000LL / (currentTime - fLastSpeedReferenceTime);
|
||||
fLastSpeedReferenceSize = currentSize;
|
||||
fLastSpeedReferenceTime = currentTime;
|
||||
fBytesPerSecond = 0.0;
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < kBytesPerSecondSlots; i++) {
|
||||
if (fBytesPerSecondSlot[i] != 0.0) {
|
||||
fBytesPerSecond += fBytesPerSecondSlot[i];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0)
|
||||
fBytesPerSecond /= count;
|
||||
}
|
||||
_UpdateStatusText();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DownloadProgressView::_UpdateStatusText()
|
||||
{
|
||||
fInfoView->SetText("");
|
||||
BString buffer;
|
||||
if (sShowSpeed && fBytesPerSecond != 0.0) {
|
||||
// Draw speed info
|
||||
char sizeBuffer[128];
|
||||
buffer = "(";
|
||||
buffer << string_for_size((double)fCurrentSize, sizeBuffer,
|
||||
sizeof(sizeBuffer));
|
||||
buffer << " of ";
|
||||
buffer << string_for_size((double)fExpectedSize, sizeBuffer,
|
||||
sizeof(sizeBuffer));
|
||||
buffer << ", ";
|
||||
buffer << string_for_size(fBytesPerSecond, sizeBuffer,
|
||||
sizeof(sizeBuffer));
|
||||
buffer << "/s)";
|
||||
float stringWidth = fInfoView->StringWidth(buffer.String());
|
||||
if (stringWidth < fInfoView->Bounds().Width())
|
||||
fInfoView->SetText(buffer.String());
|
||||
else {
|
||||
// complete string too wide, try with shorter version
|
||||
buffer << string_for_size(fBytesPerSecond, sizeBuffer,
|
||||
sizeof(sizeBuffer));
|
||||
buffer << "/s";
|
||||
stringWidth = fInfoView->StringWidth(buffer.String());
|
||||
if (stringWidth < fInfoView->Bounds().Width())
|
||||
fInfoView->SetText(buffer.String());
|
||||
}
|
||||
} else if (!sShowSpeed && fCurrentSize < fExpectedSize) {
|
||||
double totalBytesPerSecond = (double)(fCurrentSize
|
||||
- fEstimatedFinishReferenceSize)
|
||||
* 1000000LL / (system_time() - fEstimatedFinishReferenceTime);
|
||||
double secondsRemaining = (fExpectedSize - fCurrentSize)
|
||||
/ 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) {
|
||||
int64 days = finishTime / secondsPerDay;
|
||||
if (days == 1)
|
||||
buffer2 << "Over 1 day";
|
||||
else
|
||||
buffer2 << "Over " << days << " days";
|
||||
} else if (finishTime > 60 * 60) {
|
||||
int64 hours = finishTime / (60 * 60);
|
||||
if (hours == 1)
|
||||
buffer2 << "Over 1 hour";
|
||||
else
|
||||
buffer2 << "Over " << hours << " hours";
|
||||
} else if (finishTime > 60) {
|
||||
int64 minutes = finishTime / 60;
|
||||
if (minutes == 1)
|
||||
buffer2 << "Over 1 minute";
|
||||
else
|
||||
buffer2 << minutes << " minutes";
|
||||
} else {
|
||||
if (finishTime == 1)
|
||||
buffer2 << "1 second";
|
||||
else
|
||||
buffer2 << finishTime << " seconds";
|
||||
}
|
||||
|
||||
buffer2 << " left";
|
||||
|
||||
buffer = "(";
|
||||
buffer << buffer1 << " - " << buffer2 << ")";
|
||||
|
||||
float stringWidth = fInfoView->StringWidth(buffer.String());
|
||||
if (stringWidth < fInfoView->Bounds().Width())
|
||||
fInfoView->SetText(buffer.String());
|
||||
else {
|
||||
// complete string too wide, try with shorter version
|
||||
buffer = "(";
|
||||
buffer << buffer1 << ")";
|
||||
stringWidth = fInfoView->StringWidth(buffer.String());
|
||||
if (stringWidth < fInfoView->Bounds().Width())
|
||||
fInfoView->SetText(buffer.String());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DownloadProgressView::_StartNodeMonitor(const BEntry& entry)
|
||||
{
|
||||
|
||||
@@ -28,12 +28,13 @@
|
||||
#define DOWNLOAD_PROGRESS_VIEW_H
|
||||
|
||||
|
||||
#include <GridView.h>
|
||||
#include <GroupView.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
|
||||
class BEntry;
|
||||
class BStatusBar;
|
||||
class BStringView;
|
||||
class BWebDownload;
|
||||
class IconView;
|
||||
class SmallButton;
|
||||
@@ -44,7 +45,7 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
class DownloadProgressView : public BGridView {
|
||||
class DownloadProgressView : public BGroupView {
|
||||
public:
|
||||
DownloadProgressView(BWebDownload* download);
|
||||
DownloadProgressView(const BMessage* archive);
|
||||
@@ -68,19 +69,41 @@ public:
|
||||
void DownloadFinished();
|
||||
void DownloadCanceled();
|
||||
|
||||
static void SpeedVersusEstimatedFinishTogglePulse();
|
||||
|
||||
private:
|
||||
void _UpdateStatus(off_t currentSize,
|
||||
off_t expectedSize);
|
||||
void _UpdateStatusText();
|
||||
void _StartNodeMonitor(const BEntry& entry);
|
||||
void _StopNodeMonitor();
|
||||
|
||||
private:
|
||||
IconView* fIconView;
|
||||
BStatusBar* fStatusBar;
|
||||
BStringView* fInfoView;
|
||||
SmallButton* fTopButton;
|
||||
SmallButton* fBottomButton;
|
||||
BWebDownload* fDownload;
|
||||
BString fURL;
|
||||
BPath fPath;
|
||||
|
||||
off_t fCurrentSize;
|
||||
off_t fExpectedSize;
|
||||
off_t fLastSpeedReferenceSize;
|
||||
off_t fEstimatedFinishReferenceSize;
|
||||
bigtime_t fLastUpdateTime;
|
||||
bigtime_t fLastSpeedReferenceTime;
|
||||
bigtime_t fProcessStartTime;
|
||||
bigtime_t fLastSpeedUpdateTime;
|
||||
bigtime_t fEstimatedFinishReferenceTime;
|
||||
static const size_t kBytesPerSecondSlots = 10;
|
||||
size_t fCurrentBytesPerSecondSlot;
|
||||
double fBytesPerSecondSlot[kBytesPerSecondSlots];
|
||||
double fBytesPerSecond;
|
||||
|
||||
static bigtime_t sLastEstimatedFinishSpeedToggleTime;
|
||||
static bool sShowSpeed;
|
||||
};
|
||||
|
||||
#endif // DOWNLOAD_PROGRESS_VIEW_H
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Button.h>
|
||||
#include <ControlLook.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
:
|
||||
BGroupView(B_VERTICAL)
|
||||
{
|
||||
SetFlags(Flags() | B_PULSE_NEEDED);
|
||||
SetViewColor(245, 245, 245);
|
||||
AddChild(BSpaceLayoutItem::CreateGlue());
|
||||
}
|
||||
@@ -75,6 +77,11 @@ public:
|
||||
return BSize(minSize.width, 80);
|
||||
}
|
||||
|
||||
virtual void Pulse()
|
||||
{
|
||||
DownloadProgressView::SpeedVersusEstimatedFinishTogglePulse();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void DoLayout()
|
||||
{
|
||||
@@ -129,6 +136,8 @@ DownloadWindow::DownloadWindow(BRect frame, bool visible,
|
||||
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE)
|
||||
{
|
||||
SetPulseRate(1000000);
|
||||
|
||||
settings->AddListener(BMessenger(this));
|
||||
BPath downloadPath;
|
||||
if (find_directory(B_DESKTOP_DIRECTORY, &downloadPath) != B_OK)
|
||||
@@ -159,15 +168,17 @@ DownloadWindow::DownloadWindow(BRect frame, bool visible,
|
||||
new BMessage(REMOVE_MISSING_DOWNLOADS));
|
||||
fRemoveMissingButton->SetEnabled(false);
|
||||
|
||||
const float spacing = be_control_look->DefaultItemSpacing();
|
||||
|
||||
AddChild(BGroupLayoutBuilder(B_VERTICAL)
|
||||
.Add(menuBar)
|
||||
.Add(scrollView)
|
||||
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
|
||||
.Add(BGroupLayoutBuilder(B_HORIZONTAL)
|
||||
.Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing)
|
||||
.AddGlue()
|
||||
.Add(fRemoveMissingButton)
|
||||
.Add(fRemoveFinishedButton)
|
||||
.SetInsets(5, 5, 5, 5)
|
||||
.SetInsets(12, 5, 12, 5)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user