6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
35 /*! A subclass of BWindow that is used to display the status of the Tracker
36 operations (copying, deleting, etc.).
40 #include <Application.h>
43 #include <ControlLook.h>
45 #include <DurationFormat.h>
47 #include <MessageFilter.h>
48 #include <StringView.h>
50 #include <TimeFormat.h>
57 #include "StatusWindow.h"
58 #include "StringForSize.h"
59 #include "DeskWindow.h"
62 #undef B_TRANSLATION_CONTEXT
63 #define B_TRANSLATION_CONTEXT "StatusWindow"
66 const float kDefaultStatusViewHeight
= 50;
67 const bigtime_t kMaxUpdateInterval
= 100000LL;
68 const bigtime_t kSpeedReferenceInterval
= 2000000LL;
69 const bigtime_t kShowSpeedInterval
= 8000000LL;
70 const bigtime_t kShowEstimatedFinishInterval
= 4000000LL;
71 const BRect
kStatusRect(200, 200, 550, 200);
73 static bigtime_t sLastEstimatedFinishSpeedToggleTime
= -1;
74 static bool sShowSpeed
= true;
75 static const time_t kSecondsPerDay
= 24 * 60 * 60;
78 class TCustomButton
: public BButton
{
80 TCustomButton(BRect frame
, uint32 command
);
81 virtual void Draw(BRect updateRect
);
83 typedef BButton _inherited
;
87 class BStatusMouseFilter
: public BMessageFilter
{
90 virtual filter_result
Filter(BMessage
* message
, BHandler
** target
);
95 BStatusWindow
* gStatusWindow
= NULL
;
99 // #pragma mark - BStatusMouseFilter
102 BStatusMouseFilter::BStatusMouseFilter()
104 BMessageFilter(B_ANY_DELIVERY
, B_ANY_SOURCE
, B_MOUSE_DOWN
)
110 BStatusMouseFilter::Filter(BMessage
* message
, BHandler
** target
)
112 // If the target is the status bar, make sure the message goes to the
113 // parent view instead.
114 if ((*target
)->Name() != NULL
115 && strcmp((*target
)->Name(), "StatusBar") == 0) {
116 BView
* view
= dynamic_cast<BView
*>(*target
);
118 view
= view
->Parent();
124 return B_DISPATCH_MESSAGE
;
128 // #pragma mark - TCustomButton
131 TCustomButton::TCustomButton(BRect frame
, uint32 what
)
133 BButton(frame
, "", "", new BMessage(what
), B_FOLLOW_LEFT
| B_FOLLOW_TOP
,
140 TCustomButton::Draw(BRect updateRect
)
142 _inherited::Draw(updateRect
);
144 if (Message()->what
== kStopButton
) {
145 updateRect
= Bounds();
146 updateRect
.InsetBy(9, 8);
147 SetHighColor(0, 0, 0);
148 if (Value() == B_CONTROL_ON
)
149 updateRect
.OffsetBy(1, 1);
150 FillRect(updateRect
);
152 updateRect
= Bounds();
153 updateRect
.InsetBy(9, 7);
154 BRect
rect(updateRect
);
157 updateRect
.left
+= 3;
158 updateRect
.OffsetBy(1, 0);
159 SetHighColor(0, 0, 0);
160 if (Value() == B_CONTROL_ON
) {
161 updateRect
.OffsetBy(1, 1);
164 FillRect(updateRect
);
170 // #pragma mark - StatusBackgroundView
173 class StatusBackgroundView
: public BView
{
175 StatusBackgroundView(BRect frame
)
177 BView(frame
, "BackView", B_FOLLOW_ALL
, B_WILL_DRAW
| B_PULSE_NEEDED
)
179 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
184 bigtime_t now
= system_time();
186 && sLastEstimatedFinishSpeedToggleTime
+ kShowSpeedInterval
189 sLastEstimatedFinishSpeedToggleTime
= now
;
190 } else if (!sShowSpeed
191 && sLastEstimatedFinishSpeedToggleTime
192 + kShowEstimatedFinishInterval
<= now
) {
194 sLastEstimatedFinishSpeedToggleTime
= now
;
200 // #pragma mark - BStatusWindow
203 BStatusWindow::BStatusWindow()
205 BWindow(kStatusRect
, B_TRANSLATE("Tracker status"), B_TITLED_WINDOW
,
206 B_NOT_CLOSABLE
| B_NOT_RESIZABLE
| B_NOT_ZOOMABLE
, B_ALL_WORKSPACES
),
207 fRetainDesktopFocus(false)
209 SetSizeLimits(0, 100000, 0, 100000);
210 fMouseDownFilter
= new BStatusMouseFilter();
211 AddCommonFilter(fMouseDownFilter
);
213 BView
* view
= new StatusBackgroundView(Bounds());
216 SetPulseRate(1000000);
223 BStatusWindow::~BStatusWindow()
229 BStatusWindow::CreateStatusItem(thread_id thread
, StatusWindowState type
)
231 AutoLock
<BWindow
> lock(this);
233 BRect
rect(Bounds());
234 if (BStatusView
* lastView
= fViewList
.LastItem())
235 rect
.top
= lastView
->Frame().bottom
+ 1;
237 // This is the first status item, reset speed/estimated finish toggle.
239 sLastEstimatedFinishSpeedToggleTime
= system_time();
241 rect
.bottom
= rect
.top
+ kDefaultStatusViewHeight
- 1;
243 BStatusView
* view
= new BStatusView(rect
, thread
, type
);
244 // the BStatusView will resize itself if needed in its constructor
245 ChildAt(0)->AddChild(view
);
246 fViewList
.AddItem(view
);
248 ResizeTo(Bounds().Width(), view
->Frame().bottom
);
250 // find out if the desktop is the active window
251 // if the status window is the only thing to take over active state and
252 // desktop was active to begin with, return focus back to desktop
254 bool desktopActive
= false;
256 AutoLock
<BLooper
> lock(be_app
);
257 int32 count
= be_app
->CountWindows();
258 for (int32 index
= 0; index
< count
; index
++) {
259 BWindow
* window
= be_app
->WindowAt(index
);
260 if (dynamic_cast<BDeskWindow
*>(window
) != NULL
261 && window
->IsActive()) {
262 desktopActive
= true;
269 fRetainDesktopFocus
= desktopActive
;
273 fRetainDesktopFocus
&= desktopActive
;
278 BStatusWindow::InitStatusItem(thread_id thread
, int32 totalItems
,
279 off_t totalSize
, const entry_ref
* destDir
, bool showCount
)
281 AutoLock
<BWindow
> lock(this);
283 int32 numItems
= fViewList
.CountItems();
284 for (int32 index
= 0; index
< numItems
; index
++) {
285 BStatusView
* view
= fViewList
.ItemAt(index
);
286 if (view
->Thread() == thread
) {
287 view
->InitStatus(totalItems
, totalSize
, destDir
, showCount
);
296 BStatusWindow::UpdateStatus(thread_id thread
, const char* curItem
,
297 off_t itemSize
, bool optional
)
299 AutoLock
<BWindow
> lock(this);
301 int32 numItems
= fViewList
.CountItems();
302 for (int32 index
= 0; index
< numItems
; index
++) {
303 BStatusView
* view
= fViewList
.ItemAt(index
);
304 if (view
->Thread() == thread
) {
305 view
->UpdateStatus(curItem
, itemSize
, optional
);
313 BStatusWindow::RemoveStatusItem(thread_id thread
)
315 AutoLock
<BWindow
> lock(this);
316 BStatusView
* winner
= NULL
;
318 int32 numItems
= fViewList
.CountItems();
320 for (index
= 0; index
< numItems
; index
++) {
321 BStatusView
* view
= fViewList
.ItemAt(index
);
322 if (view
->Thread() == thread
) {
328 if (winner
!= NULL
) {
329 // The height by which the other views will have to be moved
331 float height
= winner
->Bounds().Height() + 1;
332 fViewList
.RemoveItem(winner
);
333 winner
->RemoveSelf();
336 if (--numItems
== 0 && !IsHidden()) {
337 BDeskWindow
* desktop
= NULL
;
338 if (fRetainDesktopFocus
) {
339 AutoLock
<BLooper
> lock(be_app
);
340 int32 count
= be_app
->CountWindows();
341 for (int32 index
= 0; index
< count
; index
++) {
342 desktop
= dynamic_cast<BDeskWindow
*>(
343 be_app
->WindowAt(index
));
349 if (desktop
!= NULL
) {
350 // desktop was active when we first started,
351 // make it active again
356 for (; index
< numItems
; index
++)
357 fViewList
.ItemAt(index
)->MoveBy(0, -height
);
359 ResizeTo(Bounds().Width(), Bounds().Height() - height
);
365 BStatusWindow::CheckCanceledOrPaused(thread_id thread
)
367 bool wasCanceled
= false;
368 bool isPaused
= false;
370 BStatusView
* view
= NULL
;
372 AutoLock
<BWindow
> lock(this);
373 // check if cancel or pause hit
374 for (int32 index
= fViewList
.CountItems() - 1; index
>= 0; index
--) {
375 view
= fViewList
.ItemAt(index
);
376 if (view
&& view
->Thread() == thread
) {
377 isPaused
= view
->IsPaused();
378 wasCanceled
= view
->WasCanceled();
383 if (wasCanceled
|| !isPaused
)
386 if (isPaused
&& view
!= NULL
) {
389 thread_id thread
= view
->Thread();
393 // and suspend ourselves
394 // we will get resumed from BStatusView::MessageReceived
395 ASSERT(find_thread(NULL
) == thread
);
396 suspend_thread(thread
);
404 BStatusWindow::AttemptToQuit()
406 // called when tracker is quitting
407 // try to cancel all the move/copy/empty trash threads in a nice way
408 // by issuing cancels
409 int32 count
= fViewList
.CountItems();
414 for (int32 index
= 0; index
< count
; index
++)
415 fViewList
.ItemAt(index
)->SetWasCanceled();
417 // maybe next time everything will have been canceled
423 BStatusWindow::WindowActivated(bool state
)
426 fRetainDesktopFocus
= false;
428 return _inherited::WindowActivated(state
);
432 // #pragma mark - BStatusView
435 BStatusView::BStatusView(BRect bounds
, thread_id thread
, StatusWindowState type
)
437 BView(bounds
, "StatusView", B_FOLLOW_NONE
, B_WILL_DRAW
),
447 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
448 SetLowUIColor(ViewUIColor());
449 SetHighColor(20, 20, 20);
450 SetDrawingMode(B_OP_ALPHA
);
452 const float buttonWidth
= 22;
453 const float buttonHeight
= 20;
456 rect
.OffsetTo(B_ORIGIN
);
458 rect
.right
-= buttonWidth
* 2 + 12;
460 rect
.bottom
= rect
.top
+ 15;
467 caption
= B_TRANSLATE("Preparing to copy items" B_UTF8_ELLIPSIS
);
468 id
= R_CopyStatusIcon
;
472 caption
= B_TRANSLATE("Preparing to move items" B_UTF8_ELLIPSIS
);
473 id
= R_MoveStatusIcon
;
476 case kCreateLinkState
:
477 caption
= B_TRANSLATE("Preparing to create links"
479 id
= R_MoveStatusIcon
;
483 caption
= B_TRANSLATE("Preparing to empty Trash" B_UTF8_ELLIPSIS
);
488 caption
= B_TRANSLATE("Searching for disks to mount"
493 caption
= B_TRANSLATE("Preparing to delete items"
498 case kRestoreFromTrashState
:
499 caption
= B_TRANSLATE("Preparing to restore items"
508 if (caption
.Length() != 0) {
509 fStatusBar
= new BStatusBar(rect
, "StatusBar", caption
.String());
510 fStatusBar
->SetBarHeight(12);
512 fStatusBar
->GetPreferredSize(&width
, &height
);
513 fStatusBar
->ResizeTo(fStatusBar
->Frame().Width(), height
);
514 AddChild(fStatusBar
);
516 // Figure out how much room we need to display the additional status
517 // message below the bar
520 BRect f
= fStatusBar
->Frame();
521 // Height is 3 x the "room from the top" + bar height + room for
523 ResizeTo(Bounds().Width(), f
.top
+ f
.Height() + fh
.leading
+ fh
.ascent
524 + fh
.descent
+ f
.top
);
528 fBitmap
= new BBitmap(BRect(0, 0, 16, 16), B_RGBA32
);
529 GetTrackerResources()->GetIconResource(id
, B_MINI_ICON
,
534 rect
.left
= rect
.right
- buttonWidth
* 2 - 7;
535 rect
.right
= rect
.left
+ buttonWidth
;
536 rect
.top
= floorf((rect
.top
+ rect
.bottom
) / 2 + 0.5) - buttonHeight
/ 2;
537 rect
.bottom
= rect
.top
+ buttonHeight
;
539 fPauseButton
= new TCustomButton(rect
, kPauseButton
);
540 fPauseButton
->ResizeTo(buttonWidth
, buttonHeight
);
541 AddChild(fPauseButton
);
543 rect
.OffsetBy(buttonWidth
+ 2, 0);
544 fStopButton
= new TCustomButton(rect
, kStopButton
);
545 fStopButton
->ResizeTo(buttonWidth
, buttonHeight
);
546 AddChild(fStopButton
);
550 BStatusView::~BStatusView()
559 fTotalSize
= fItemSize
= fSizeProcessed
= fLastSpeedReferenceSize
560 = fEstimatedFinishReferenceSize
= 0;
562 fLastUpdateTime
= fLastSpeedReferenceTime
= fProcessStartTime
563 = fLastSpeedUpdateTime
= fEstimatedFinishReferenceTime
565 fCurrentBytesPerSecondSlot
= 0;
566 for (size_t i
= 0; i
< kBytesPerSecondSlots
; i
++)
567 fBytesPerSecondSlot
[i
] = 0.0;
569 fBytesPerSecond
= 0.0;
570 fShowCount
= fWasCanceled
= fIsPaused
= false;
572 fPendingStatusString
[0] = '\0';
577 BStatusView::InitStatus(int32 totalItems
, off_t totalSize
,
578 const entry_ref
* destDir
, bool showCount
)
581 fTotalSize
= totalSize
;
582 fShowCount
= showCount
;
585 char name
[B_FILE_NAME_LENGTH
];
586 if (destDir
!= NULL
&& entry
.SetTo(destDir
) == B_OK
) {
588 fDestDir
.SetTo(name
);
592 if (totalItems
> 0) {
594 buffer
.SetTo(B_TRANSLATE("of %items"));
595 snprintf(totalStr
, sizeof(totalStr
), "%" B_PRId32
, totalItems
);
596 buffer
.ReplaceFirst("%items", totalStr
);
601 fStatusBar
->Reset(B_TRANSLATE("Copying: "), buffer
.String());
604 case kCreateLinkState
:
605 fStatusBar
->Reset(B_TRANSLATE("Creating links: "),
610 fStatusBar
->Reset(B_TRANSLATE("Moving: "), buffer
.String());
615 B_TRANSLATE("Emptying Trash" B_UTF8_ELLIPSIS
" "),
620 fStatusBar
->Reset(B_TRANSLATE("Deleting: "), buffer
.String());
623 case kRestoreFromTrashState
:
624 fStatusBar
->Reset(B_TRANSLATE("Restoring: "), buffer
.String());
628 fStatusBar
->SetMaxValue(1);
629 // SetMaxValue has to be here because Reset changes it to 100
635 BStatusView::Draw(BRect updateRect
)
637 if (fBitmap
!= NULL
) {
639 location
.x
= (fStatusBar
->Frame().left
640 - fBitmap
->Bounds().Width()) / 2;
641 location
.y
= (Bounds().Height()- fBitmap
->Bounds().Height()) / 2;
642 DrawBitmap(fBitmap
, location
);
645 BRect
bounds(Bounds());
646 be_control_look
->DrawRaisedBorder(this, bounds
, updateRect
, ViewColor());
648 SetHighColor(0, 0, 0);
650 BPoint tp
= fStatusBar
->Frame().LeftBottom();
653 tp
.y
+= ceilf(fh
.leading
) + ceilf(fh
.ascent
);
655 DrawString(B_TRANSLATE("Paused: click to resume or stop"), tp
);
661 float normalFontSize
= font
.Size();
662 float smallFontSize
= max_c(normalFontSize
* 0.8f
, 8.0f
);
663 float availableSpace
= fStatusBar
->Frame().Width();
664 availableSpace
-= be_control_look
->DefaultLabelSpacing();
665 // subtract to provide some room between our two strings
667 float destinationStringWidth
= 0.f
;
668 BString
destinationString(_DestinationString(&destinationStringWidth
));
669 availableSpace
-= destinationStringWidth
;
671 float statusStringWidth
= 0.f
;
672 BString
statusString(_StatusString(availableSpace
, smallFontSize
,
673 &statusStringWidth
));
675 if (statusStringWidth
> availableSpace
) {
676 TruncateString(&destinationString
, B_TRUNCATE_MIDDLE
,
677 availableSpace
+ destinationStringWidth
- statusStringWidth
);
680 BPoint textPoint
= fStatusBar
->Frame().LeftBottom();
681 textPoint
.y
+= ceilf(fh
.leading
) + ceilf(fh
.ascent
);
683 if (destinationStringWidth
> 0) {
684 DrawString(destinationString
.String(), textPoint
);
687 SetHighColor(tint_color(LowColor(), B_DARKEN_4_TINT
));
688 font
.SetSize(smallFontSize
);
689 SetFont(&font
, B_FONT_SIZE
);
691 textPoint
.x
= fStatusBar
->Frame().right
- statusStringWidth
;
692 DrawString(statusString
.String(), textPoint
);
694 font
.SetSize(normalFontSize
);
695 SetFont(&font
, B_FONT_SIZE
);
700 BStatusView::_DestinationString(float* _width
)
702 if (fDestDir
.Length() > 0) {
703 BString
buffer(B_TRANSLATE("To: %dir"));
704 buffer
.ReplaceFirst("%dir", fDestDir
);
706 *_width
= ceilf(StringWidth(buffer
.String()));
716 BStatusView::_StatusString(float availableSpace
, float fontSize
,
721 float oldSize
= font
.Size();
722 font
.SetSize(fontSize
);
723 SetFont(&font
, B_FONT_SIZE
);
727 status
= _SpeedStatusString(availableSpace
, _width
);
729 status
= _TimeStatusString(availableSpace
, _width
);
731 font
.SetSize(oldSize
);
732 SetFont(&font
, B_FONT_SIZE
);
738 BStatusView::_SpeedStatusString(float availableSpace
, float* _width
)
740 BString
string(_FullSpeedString());
741 *_width
= StringWidth(string
.String());
742 if (*_width
> availableSpace
) {
743 string
.SetTo(_ShortSpeedString());
744 *_width
= StringWidth(string
.String());
746 *_width
= ceilf(*_width
);
752 BStatusView::_FullSpeedString()
755 if (fBytesPerSecond
!= 0.0) {
756 char sizeBuffer
[128];
757 buffer
.SetTo(B_TRANSLATE(
758 "%SizeProcessed of %TotalSize, %BytesPerSecond/s"));
759 buffer
.ReplaceFirst("%SizeProcessed",
760 string_for_size((double)fSizeProcessed
, sizeBuffer
,
761 sizeof(sizeBuffer
)));
762 buffer
.ReplaceFirst("%TotalSize",
763 string_for_size((double)fTotalSize
, sizeBuffer
,
764 sizeof(sizeBuffer
)));
765 buffer
.ReplaceFirst("%BytesPerSecond",
766 string_for_size(fBytesPerSecond
, sizeBuffer
, sizeof(sizeBuffer
)));
774 BStatusView::_ShortSpeedString()
777 if (fBytesPerSecond
!= 0.0) {
778 char sizeBuffer
[128];
779 buffer
<< B_TRANSLATE("%BytesPerSecond/s");
780 buffer
.ReplaceFirst("%BytesPerSecond",
781 string_for_size(fBytesPerSecond
, sizeBuffer
, sizeof(sizeBuffer
)));
789 BStatusView::_TimeStatusString(float availableSpace
, float* _width
)
791 double totalBytesPerSecond
= (double)(fSizeProcessed
792 - fEstimatedFinishReferenceSize
)
793 * 1000000LL / (system_time() - fEstimatedFinishReferenceTime
);
794 double secondsRemaining
= (fTotalSize
- fSizeProcessed
)
795 / totalBytesPerSecond
;
796 time_t now
= (time_t)real_time_clock();
797 time_t finishTime
= (time_t)(now
+ secondsRemaining
);
800 if (finishTime
- now
> kSecondsPerDay
) {
801 BDateTimeFormat().Format(timeText
, sizeof(timeText
), finishTime
,
802 B_MEDIUM_DATE_FORMAT
, B_MEDIUM_TIME_FORMAT
);
804 BTimeFormat().Format(timeText
, sizeof(timeText
), finishTime
,
805 B_MEDIUM_TIME_FORMAT
);
808 BString
string(_FullTimeRemainingString(now
, finishTime
, timeText
));
809 float width
= StringWidth(string
.String());
810 if (width
> availableSpace
) {
811 string
.SetTo(_ShortTimeRemainingString(timeText
));
812 width
= StringWidth(string
.String());
823 BStatusView::_ShortTimeRemainingString(const char* timeText
)
827 // complete string too wide, try with shorter version
828 buffer
.SetTo(B_TRANSLATE("Finish: %time"));
829 buffer
.ReplaceFirst("%time", timeText
);
836 BStatusView::_FullTimeRemainingString(time_t now
, time_t finishTime
,
837 const char* timeText
)
839 BDurationFormat formatter
;
842 if (finishTime
- now
> 60 * 60) {
843 buffer
.SetTo(B_TRANSLATE("Finish: %time - Over %finishtime left"));
844 formatter
.Format(finishStr
, now
* 1000000LL, finishTime
* 1000000LL);
846 buffer
.SetTo(B_TRANSLATE("Finish: %time - %finishtime left"));
847 formatter
.Format(finishStr
, now
* 1000000LL, finishTime
* 1000000LL);
850 buffer
.ReplaceFirst("%time", timeText
);
851 buffer
.ReplaceFirst("%finishtime", finishStr
);
858 BStatusView::AttachedToWindow()
860 fPauseButton
->SetTarget(this);
861 fStopButton
->SetTarget(this);
866 BStatusView::MessageReceived(BMessage
* message
)
868 switch (message
->what
) {
870 fIsPaused
= !fIsPaused
;
871 fPauseButton
->SetValue(fIsPaused
? B_CONTROL_ON
: B_CONTROL_OFF
);
872 if (fBytesPerSecond
!= 0.0) {
873 fBytesPerSecond
= 0.0;
874 for (size_t i
= 0; i
< kBytesPerSecondSlots
; i
++)
875 fBytesPerSecondSlot
[i
] = 0.0;
879 fEstimatedFinishReferenceTime
= system_time();
880 fEstimatedFinishReferenceSize
= fSizeProcessed
;
882 // force window update
886 resume_thread(Thread());
893 // resume so that the copy loop gets a chance to finish up
896 // force window update
900 resume_thread(Thread());
905 _inherited::MessageReceived(message
);
912 BStatusView::UpdateStatus(const char* curItem
, off_t itemSize
, bool optional
)
915 fStatusBar
->Update((float)fItemSize
/ fTotalSize
);
923 fItemSize
+= itemSize
;
924 fSizeProcessed
+= itemSize
;
926 bigtime_t currentTime
= system_time();
927 if (!optional
|| ((currentTime
- fLastUpdateTime
) > kMaxUpdateInterval
)) {
928 if (curItem
!= NULL
|| fPendingStatusString
[0]) {
929 // forced update or past update time
932 buffer
<< fCurItem
<< " ";
934 // if we don't have curItem, take the one from the stash
935 const char* statusItem
= curItem
!= NULL
936 ? curItem
: fPendingStatusString
;
938 fStatusBar
->Update((float)fItemSize
/ fTotalSize
, statusItem
,
941 // we already displayed this item, clear the stash
942 fPendingStatusString
[0] = '\0';
944 fLastUpdateTime
= currentTime
;
946 // don't have a file to show, just update the bar
947 fStatusBar
->Update((float)fItemSize
/ fTotalSize
);
951 >= fLastSpeedReferenceTime
+ kSpeedReferenceInterval
) {
952 // update current speed every kSpeedReferenceInterval
953 fCurrentBytesPerSecondSlot
954 = (fCurrentBytesPerSecondSlot
+ 1) % kBytesPerSecondSlots
;
955 fBytesPerSecondSlot
[fCurrentBytesPerSecondSlot
]
956 = (double)(fSizeProcessed
- fLastSpeedReferenceSize
)
957 * 1000000LL / (currentTime
- fLastSpeedReferenceTime
);
958 fLastSpeedReferenceSize
= fSizeProcessed
;
959 fLastSpeedReferenceTime
= currentTime
;
960 fBytesPerSecond
= 0.0;
962 for (size_t i
= 0; i
< kBytesPerSecondSlots
; i
++) {
963 if (fBytesPerSecondSlot
[i
] != 0.0) {
964 fBytesPerSecond
+= fBytesPerSecondSlot
[i
];
969 fBytesPerSecond
/= count
;
971 BString toolTip
= _TimeStatusString(1024.f
, NULL
);
972 toolTip
<< "\n" << _FullSpeedString();
973 SetToolTip(toolTip
.String());
979 } else if (curItem
!= NULL
) {
980 // stash away the name of the item we are currently processing
981 // so we can show it when the time comes
982 strncpy(fPendingStatusString
, curItem
, 127);
983 fPendingStatusString
[127] = '0';
985 SetToolTip((const char*)NULL
);
990 BStatusView::SetWasCanceled()