2 * Copyright 2016-2017 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license
6 * Alexander von Gluck IV <kallisti5@unixzen.com>
7 * Brian Hill <supernova@tycho.email>
11 #include "SoftwareUpdaterWindow.h"
15 #include <Application.h>
17 #include <ControlLook.h>
18 #include <FindDirectory.h>
19 #include <LayoutBuilder.h>
20 #include <LayoutUtils.h>
26 #include "constants.h"
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "SoftwareUpdaterWindow"
32 SoftwareUpdaterWindow::SoftwareUpdaterWindow()
34 BWindow(BRect(0, 0, 300, 10),
35 B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater"), B_TITLED_WINDOW
,
36 B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_ZOOMABLE
| B_NOT_RESIZABLE
),
43 fCurrentState(STATE_HEAD
),
45 fWaitingForButton(false),
46 fUpdateConfirmed(false),
47 fUserCancelRequested(false),
48 fWarningAlertCount(0),
49 fSettingsReadStatus(B_ERROR
),
50 fSaveFrameChanges(false),
52 fFrameChangeMessage(kMsgWindowFrameChanged
)
55 BBitmap icon
= GetIcon(32 * icon_layout_scale());
56 fStripeView
= new StripeView(icon
);
58 fUpdateButton
= new BButton(B_TRANSLATE("Update now"),
59 new BMessage(kMsgUpdateConfirmed
));
60 fUpdateButton
->MakeDefault(true);
61 fCancelButton
= new BButton(B_TRANSLATE("Cancel"),
62 new BMessage(kMsgCancel
));
64 fHeaderView
= new BStringView("header",
65 B_TRANSLATE("Checking for updates"), B_WILL_DRAW
);
66 fHeaderView
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
67 fHeaderView
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
, B_ALIGN_TOP
));
68 fDetailView
= new BStringView("detail", B_TRANSLATE("Contacting software "
69 "repositories to check for package updates."), B_WILL_DRAW
);
70 fDetailView
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
71 fDetailView
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
, B_ALIGN_TOP
));
72 fStatusBar
= new BStatusBar("progress");
73 fStatusBar
->SetMaxValue(100);
75 fListView
= new PackageListView();
76 fScrollView
= new BScrollView("scrollview", fListView
, B_WILL_DRAW
,
79 fDetailsCheckbox
= new BCheckBox("detailscheckbox",
80 B_TRANSLATE("Show more details"),
81 new BMessage(kMsgMoreDetailsToggle
));
84 fHeaderView
->GetFont(&font
);
85 font
.SetFace(B_BOLD_FACE
);
86 font
.SetSize(font
.Size() * 1.5);
87 fHeaderView
->SetFont(&font
,
88 B_FONT_FAMILY_AND_STYLE
| B_FONT_SIZE
| B_FONT_FLAGS
);
90 BLayoutBuilder::Group
<>(this, B_HORIZONTAL
, B_USE_ITEM_SPACING
)
92 .AddGroup(B_VERTICAL
, 0)
93 .SetInsets(0, B_USE_WINDOW_SPACING
,
94 B_USE_WINDOW_SPACING
, B_USE_WINDOW_SPACING
)
95 .AddGroup(new BGroupView(B_VERTICAL
, B_USE_ITEM_SPACING
))
101 .AddStrut(B_USE_SMALL_SPACING
)
102 .AddGroup(new BGroupView(B_HORIZONTAL
))
103 .Add(fDetailsCheckbox
)
111 fDetailsLayoutItem
= layout_item_for(fDetailView
);
112 fProgressLayoutItem
= layout_item_for(fStatusBar
);
113 fPackagesLayoutItem
= layout_item_for(fScrollView
);
114 fCancelButtonLayoutItem
= layout_item_for(fCancelButton
);
115 fUpdateButtonLayoutItem
= layout_item_for(fUpdateButton
);
116 fDetailsCheckboxLayoutItem
= layout_item_for(fDetailsCheckbox
);
118 _SetState(STATE_DISPLAY_STATUS
);
120 SetFlags(Flags() ^ B_AUTO_UPDATE_SIZE_LIMITS
);
122 // Prevent resizing for now
123 fDefaultRect
= Bounds();
124 SetSizeLimits(fDefaultRect
.Width(), fDefaultRect
.Width(),
125 fDefaultRect
.Height(), fDefaultRect
.Height());
127 // Read settings file
128 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &fSettingsPath
);
129 if (status
== B_OK
) {
130 fSettingsPath
.Append(kSettingsFilename
);
131 fSettingsReadStatus
= _ReadSettings(fInitialSettings
);
133 // Move to saved setting position
134 if (fSettingsReadStatus
== B_OK
) {
136 status
= fInitialSettings
.FindRect(kKeyWindowFrame
, &windowFrame
);
137 if (status
== B_OK
) {
138 BScreen
screen(this);
139 if (screen
.Frame().Contains(windowFrame
.LeftTop()))
140 MoveTo(windowFrame
.LeftTop());
145 BMessage
registerMessage(kMsgRegister
);
146 registerMessage
.AddMessenger(kKeyMessenger
, BMessenger(this));
147 be_app
->PostMessage(®isterMessage
);
149 fCancelAlertResponse
.SetMessage(new BMessage(kMsgCancelResponse
));
150 fCancelAlertResponse
.SetTarget(this);
151 fWarningAlertDismissed
.SetMessage(new BMessage(kMsgWarningDismissed
));
152 fWarningAlertDismissed
.SetTarget(this);
154 // Common elements used for the zoom height and width calculations
155 fZoomHeightBaseline
= 6
156 + be_control_look
->ComposeSpacing(B_USE_SMALL_SPACING
)
157 + 2 * be_control_look
->ComposeSpacing(B_USE_WINDOW_SPACING
);
158 fZoomWidthBaseline
= fStripeView
->PreferredSize().Width()
159 + be_control_look
->ComposeSpacing(B_USE_ITEM_SPACING
)
160 + fScrollView
->ScrollBar(B_VERTICAL
)->PreferredSize().Width()
161 + be_control_look
->ComposeSpacing(B_USE_WINDOW_SPACING
);
166 SoftwareUpdaterWindow::QuitRequested()
168 PostMessage(kMsgCancel
);
174 SoftwareUpdaterWindow::FrameMoved(BPoint newPosition
)
176 BWindow::FrameMoved(newPosition
);
178 // Create a message runner to consolidate all function calls from a
179 // move into one message post after moving has ceased for .5 seconds
180 if (fSaveFrameChanges
) {
181 if (fMessageRunner
== NULL
) {
182 fMessageRunner
= new BMessageRunner(this, &fFrameChangeMessage
,
185 fMessageRunner
->SetInterval(500000);
191 SoftwareUpdaterWindow::FrameResized(float newWidth
, float newHeight
)
193 BWindow::FrameResized(newWidth
, newHeight
);
195 // Create a message runner to consolidate all function calls from a
196 // resize into one message post after resizing has ceased for .5 seconds
197 if (fSaveFrameChanges
) {
198 if (fMessageRunner
== NULL
) {
199 fMessageRunner
= new BMessageRunner(this, &fFrameChangeMessage
,
202 fMessageRunner
->SetInterval(500000);
208 SoftwareUpdaterWindow::Zoom(BPoint origin
, float width
, float height
)
210 // Override default zoom behavior and keep window at same position instead
211 // of centering on screen
212 BWindow::Zoom(Frame().LeftTop(), width
, height
);
217 SoftwareUpdaterWindow::MessageReceived(BMessage
* message
)
219 switch (message
->what
) {
223 if (fCurrentState
== STATE_DISPLAY_PROGRESS
)
224 _SetState(STATE_DISPLAY_STATUS
);
225 else if (fCurrentState
!= STATE_DISPLAY_STATUS
)
231 status_t result
= message
->FindString(kKeyHeader
, &header
);
232 if (result
== B_OK
&& header
!= fHeaderView
->Text())
233 fHeaderView
->SetText(header
.String());
234 result
= message
->FindString(kKeyDetail
, &detail
);
236 fDetailView
->SetText(detail
.String());
241 case kMsgProgressUpdate
:
243 if (fCurrentState
== STATE_DISPLAY_STATUS
)
244 _SetState(STATE_DISPLAY_PROGRESS
);
245 else if (fCurrentState
!= STATE_DISPLAY_PROGRESS
)
249 status_t result
= message
->FindString(kKeyPackageName
,
253 BString packageCount
;
254 result
= message
->FindString(kKeyPackageCount
, &packageCount
);
258 result
= message
->FindFloat(kKeyPercentage
, &percent
);
264 result
= message
->FindString(kKeyHeader
, &header
);
265 if (result
== B_OK
&& header
!= fHeaderView
->Text())
266 fHeaderView
->SetText(header
.String());
267 fStatusBar
->SetTo(percent
, packageName
.String(),
268 packageCount
.String());
271 fListView
->UpdatePackageProgress(packageName
.String(), percent
);
277 if (_GetState() == STATE_FINAL_MESSAGE
) {
278 be_app
->PostMessage(kMsgFinalQuit
);
281 if (!fUpdateConfirmed
) {
282 // Downloads have not started yet, we will request to cancel
283 // without confirming
285 fHeaderView
->SetText(B_TRANSLATE("Cancelling updates"));
286 fDetailView
->SetText(
287 B_TRANSLATE("Attempting to cancel the updates..."));
289 fUserCancelRequested
= true;
291 if (fWaitingForButton
) {
292 fButtonResult
= message
->what
;
293 delete_sem(fWaitingSem
);
299 // Confirm with the user to cancel
300 BAlert
* alert
= new BAlert("cancel request", B_TRANSLATE("Updates"
301 " have not been completed, are you sure you want to quit?"),
302 B_TRANSLATE("Quit"), B_TRANSLATE("Don't quit"), NULL
,
303 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
304 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
305 alert
->Go(&fCancelAlertResponse
);
309 case kMsgCancelResponse
:
311 // Verify whether the cancel alert was confirmed
312 int32 selection
= -1;
313 message
->FindInt32("which", &selection
);
318 fHeaderView
->SetText(B_TRANSLATE("Cancelling updates"));
319 fDetailView
->SetText(
320 B_TRANSLATE("Attempting to cancel the updates..."));
322 fUserCancelRequested
= true;
324 if (fWaitingForButton
) {
325 fButtonResult
= message
->what
;
326 delete_sem(fWaitingSem
);
332 case kMsgUpdateConfirmed
:
334 if (fWaitingForButton
) {
335 fButtonResult
= message
->what
;
336 delete_sem(fWaitingSem
);
338 fUpdateConfirmed
= true;
343 case kMsgMoreDetailsToggle
:
344 fListView
->SetMoreDetails(fDetailsCheckbox
->Value() != 0);
345 PostMessage(kMsgSetZoomLimits
);
349 case kMsgSetZoomLimits
:
351 int32 count
= fListView
->CountItems();
354 // Convert last item's bottom point to its layout group coordinates
355 BPoint zoomPoint
= fListView
->ZoomPoint();
356 fScrollView
->ConvertToParent(&zoomPoint
);
357 // Determine which BControl object height to use
359 if (fUpdateButtonLayoutItem
->IsVisible())
360 fUpdateButton
->GetPreferredSize(NULL
, &controlHeight
);
362 fDetailsCheckbox
->GetPreferredSize(NULL
, &controlHeight
);
363 // Calculate height and width values
364 float zoomHeight
= fZoomHeightBaseline
+ zoomPoint
.y
366 float zoomWidth
= fZoomWidthBaseline
+ zoomPoint
.x
;
367 SetZoomLimits(zoomWidth
, zoomHeight
);
371 case kMsgWarningDismissed
:
372 fWarningAlertCount
--;
375 case kMsgWindowFrameChanged
:
376 delete fMessageRunner
;
377 fMessageRunner
= NULL
;
381 case kMsgGetUpdateType
:
384 B_TRANSLATE("Please choose from these update options:\n\n"
386 " Updates all installed packages.\n"
388 " Synchronizes the installed packages with the repositories."
390 BAlert
* alert
= new BAlert("update_type",
392 B_TRANSLATE_COMMENT("Cancel", "Alert button label"),
393 B_TRANSLATE_COMMENT("Full sync","Alert button label"),
394 B_TRANSLATE_COMMENT("Update","Alert button label"),
395 B_WIDTH_AS_USUAL
, B_INFO_ALERT
);
396 int32 result
= alert
->Go();
397 int32 action
= INVALID_SELECTION
;
400 action
= CANCEL_UPDATE
;
412 reply
.AddInt32(kKeyAlertResult
, action
);
413 message
->SendReply(&reply
);
417 case kMsgNoRepositories
:
421 "No remote repositories are available. Please verify that some"
422 " repositories are enabled using the Repositories preflet or"
423 " the \'pkgman\' command.", "Error message"));
424 BAlert
* alert
= new BAlert("repositories", text
,
425 B_TRANSLATE_COMMENT("Quit", "Alert button label"),
426 B_TRANSLATE_COMMENT("Open Repositories","Alert button label"),
427 NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
428 int32 result
= alert
->Go();
430 reply
.AddInt32(kKeyAlertResult
, result
);
431 message
->SendReply(&reply
);
436 BWindow::MessageReceived(message
);
442 SoftwareUpdaterWindow::ConfirmUpdates()
445 fHeaderView
->SetText(B_TRANSLATE("Updates found"));
446 fDetailView
->SetText(B_TRANSLATE("The following changes will be made:"));
447 fListView
->SortItems();
450 uint32 priorState
= _GetState();
451 _SetState(STATE_GET_CONFIRMATION
);
453 _WaitForButtonClick();
454 _SetState(priorState
);
455 return fButtonResult
== kMsgUpdateConfirmed
;
460 SoftwareUpdaterWindow::UpdatesApplying(const char* header
, const char* detail
)
463 fHeaderView
->SetText(header
);
464 fDetailView
->SetText(detail
);
466 _SetState(STATE_APPLY_UPDATES
);
471 SoftwareUpdaterWindow::UserCancelRequested()
473 if (_GetState() > STATE_GET_CONFIRMATION
)
476 return fUserCancelRequested
;
481 SoftwareUpdaterWindow::AddPackageInfo(uint32 install_type
,
482 const char* package_name
, const char* cur_ver
, const char* new_ver
,
483 const char* summary
, const char* repository
, const char* file_name
)
486 fListView
->AddPackage(install_type
, package_name
, cur_ver
, new_ver
,
487 summary
, repository
, file_name
);
493 SoftwareUpdaterWindow::ShowWarningAlert(const char* text
)
495 BAlert
* alert
= new BAlert("warning", text
, B_TRANSLATE("OK"), NULL
, NULL
,
496 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
497 alert
->Go(&fWarningAlertDismissed
);
498 alert
->CenterIn(Frame());
499 // Offset multiple alerts
500 alert
->MoveBy(fWarningAlertCount
* 15, fWarningAlertCount
* 15);
501 fWarningAlertCount
++;
506 SoftwareUpdaterWindow::GetIcon(int32 iconSize
)
508 BBitmap
icon(BRect(0, 0, iconSize
- 1, iconSize
- 1), 0, B_RGBA32
);
510 get_team_info(B_CURRENT_TEAM
, &teamInfo
);
512 be_roster
->GetRunningAppInfo(teamInfo
.team
, &appInfo
);
513 BNodeInfo::GetTrackerIcon(&appInfo
.ref
, &icon
, icon_size(iconSize
));
519 SoftwareUpdaterWindow::FinalUpdate(const char* header
, const char* detail
)
521 if (_GetState() == STATE_FINAL_MESSAGE
)
524 _SetState(STATE_FINAL_MESSAGE
);
526 fHeaderView
->SetText(header
);
527 fDetailView
->SetText(detail
);
533 SoftwareUpdaterWindow::layout_item_for(BView
* view
)
535 BLayout
* layout
= view
->Parent()->GetLayout();
536 int32 index
= layout
->IndexOfView(view
);
537 return layout
->ItemAt(index
);
542 SoftwareUpdaterWindow::_WaitForButtonClick()
545 fWaitingForButton
= true;
546 fWaitingSem
= create_sem(0, "WaitingSem");
547 while (acquire_sem(fWaitingSem
) == B_INTERRUPTED
) {
549 fWaitingForButton
= false;
550 return fButtonResult
;
555 SoftwareUpdaterWindow::_SetState(uint32 state
)
557 if (state
<= STATE_HEAD
|| state
>= STATE_MAX
)
563 if (fCurrentState
== STATE_HEAD
) {
564 fProgressLayoutItem
->SetVisible(false);
565 fPackagesLayoutItem
->SetVisible(false);
566 fDetailsCheckboxLayoutItem
->SetVisible(false);
567 fCancelButtonLayoutItem
->SetVisible(false);
569 fCurrentState
= state
;
571 // Update confirmation button
572 // Show only when asking for confirmation to update
573 if (fCurrentState
== STATE_GET_CONFIRMATION
)
574 fUpdateButtonLayoutItem
->SetVisible(true);
576 fUpdateButtonLayoutItem
->SetVisible(false);
578 // View package info view and checkbox
579 // Show at confirmation prompt, hide at final update
580 if (fCurrentState
== STATE_GET_CONFIRMATION
) {
581 fPackagesLayoutItem
->SetVisible(true);
582 fDetailsCheckboxLayoutItem
->SetVisible(true);
583 if (fSettingsReadStatus
== B_OK
) {
584 bool showMoreDetails
;
585 status_t result
= fInitialSettings
.FindBool(kKeyShowDetails
,
587 if (result
== B_OK
) {
588 fDetailsCheckbox
->SetValue(showMoreDetails
? 1 : 0);
589 fListView
->SetMoreDetails(showMoreDetails
);
592 } else if (fCurrentState
== STATE_FINAL_MESSAGE
) {
593 fPackagesLayoutItem
->SetVisible(false);
594 fDetailsCheckboxLayoutItem
->SetVisible(false);
597 // Progress bar and string view
598 // Hide detail text while showing status bar
599 if (fCurrentState
== STATE_DISPLAY_PROGRESS
) {
600 fDetailsLayoutItem
->SetVisible(false);
601 fProgressLayoutItem
->SetVisible(true);
603 fProgressLayoutItem
->SetVisible(false);
604 fDetailsLayoutItem
->SetVisible(true);
607 // Resizing and zooming
608 if (fCurrentState
== STATE_GET_CONFIRMATION
) {
609 // Enable resizing and zooming
610 float defaultWidth
= fDefaultRect
.Width();
611 SetSizeLimits(defaultWidth
, B_SIZE_UNLIMITED
,
612 fDefaultRect
.Height() + 4 * fListView
->ItemHeight(),
614 SetFlags(Flags() ^ (B_NOT_RESIZABLE
| B_NOT_ZOOMABLE
));
615 PostMessage(kMsgSetZoomLimits
);
616 // Recall saved settings
617 BScreen
screen(this);
618 BRect screenFrame
= screen
.Frame();
619 bool windowResized
= false;
620 if (fSettingsReadStatus
== B_OK
) {
622 status_t result
= fInitialSettings
.FindRect(kKeyWindowFrame
,
624 if (result
== B_OK
) {
625 if (screenFrame
.Contains(windowFrame
)) {
626 ResizeTo(windowFrame
.Width(), windowFrame
.Height());
627 windowResized
= true;
632 ResizeTo(defaultWidth
, .75 * defaultWidth
);
633 // Check that the bottom of window is on screen
634 float screenBottom
= screenFrame
.bottom
;
635 float windowBottom
= DecoratorFrame().bottom
;
636 if (windowBottom
> screenBottom
)
637 MoveBy(0, screenBottom
- windowBottom
);
638 fSaveFrameChanges
= true;
639 } else if (fUpdateConfirmed
&& (fCurrentState
== STATE_DISPLAY_PROGRESS
640 || fCurrentState
== STATE_DISPLAY_STATUS
)) {
641 PostMessage(kMsgSetZoomLimits
);
642 } else if (fCurrentState
== STATE_APPLY_UPDATES
)
643 fSaveFrameChanges
= false;
644 else if (fCurrentState
== STATE_FINAL_MESSAGE
) {
645 // Disable resizing and zooming
646 fSaveFrameChanges
= false;
647 ResizeTo(fDefaultRect
.Width(), fDefaultRect
.Height());
648 SetFlags(Flags() | B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_RESIZABLE
653 if (fCurrentState
== STATE_FINAL_MESSAGE
) {
654 fCancelButtonLayoutItem
->SetVisible(true);
655 fCancelButton
->SetLabel(B_TRANSLATE_COMMENT("Quit", "Button label"));
656 fCancelButton
->MakeDefault(true);
664 SoftwareUpdaterWindow::_GetState()
666 return fCurrentState
;
671 SoftwareUpdaterWindow::_WriteSettings()
674 status_t status
= file
.SetTo(fSettingsPath
.Path(),
675 B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
676 if (status
== B_OK
) {
678 settings
.AddBool(kKeyShowDetails
, fDetailsCheckbox
->Value() != 0);
679 settings
.AddRect(kKeyWindowFrame
, Frame());
680 status
= settings
.Flatten(&file
);
688 SoftwareUpdaterWindow::_ReadSettings(BMessage
& settings
)
691 status_t status
= file
.SetTo(fSettingsPath
.Path(), B_READ_ONLY
);
693 status
= settings
.Unflatten(&file
);
699 SuperItem::SuperItem(const char* label
)
703 fRegularFont(be_plain_font
),
704 fBoldFont(be_plain_font
),
705 fShowMoreDetails(false),
706 fPackageLessIcon(NULL
),
707 fPackageMoreIcon(NULL
),
710 fBoldFont
.SetFace(B_BOLD_FACE
);
711 fBoldFont
.GetHeight(&fBoldFontHeight
);
712 font_height fontHeight
;
713 fRegularFont
.GetHeight(&fontHeight
);
714 fPackageItemLineHeight
= fontHeight
.ascent
+ fontHeight
.descent
715 + fontHeight
.leading
;
716 fPackageLessIcon
= _GetPackageIcon(GetPackageItemHeight(false));
717 fPackageMoreIcon
= _GetPackageIcon(GetPackageItemHeight(true));
721 SuperItem::~SuperItem()
723 delete fPackageLessIcon
;
724 delete fPackageMoreIcon
;
729 SuperItem::DrawItem(BView
* owner
, BRect item_rect
, bool complete
)
734 owner
->GetPreferredSize(&width
, NULL
);
735 BString
text(fItemText
);
736 owner
->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR
));
737 owner
->SetFont(&fBoldFont
);
738 owner
->TruncateString(&text
, B_TRUNCATE_END
, width
);
739 owner
->DrawString(text
.String(), BPoint(item_rect
.left
,
740 item_rect
.bottom
- fBoldFontHeight
.descent
));
747 SuperItem::GetPackageItemHeight()
749 return GetPackageItemHeight(fShowMoreDetails
);
754 SuperItem::GetPackageItemHeight(bool showMoreDetails
)
756 int lineCount
= showMoreDetails
? 3 : 2;
757 return lineCount
* fPackageItemLineHeight
;
762 SuperItem::GetIcon(bool showMoreDetails
)
765 return fPackageMoreIcon
;
767 return fPackageLessIcon
;
772 SuperItem::GetIconSize(bool showMoreDetails
)
775 return fPackageMoreIcon
->Bounds().Height();
777 return fPackageLessIcon
->Bounds().Height();
782 SuperItem::SetDetailLevel(bool showMoreDetails
)
784 fShowMoreDetails
= showMoreDetails
;
789 SuperItem::SetItemCount(int32 count
)
793 fItemText
.Append(" (");
794 fItemText
<< fItemCount
;
795 fItemText
.Append(")");
800 SuperItem::ZoomWidth(BView
*owner
)
803 owner
->SetFont(&fBoldFont
);
804 float width
= owner
->StringWidth(fItemText
.String());
811 SuperItem::_GetPackageIcon(float listItemHeight
)
813 int32 iconSize
= int(listItemHeight
* .8);
814 status_t result
= B_ERROR
;
815 BRect
iconRect(0, 0, iconSize
- 1, iconSize
- 1);
816 BBitmap
* packageIcon
= new BBitmap(iconRect
, 0, B_RGBA32
);
818 nodeType
.SetTo("application/x-vnd.haiku-package");
819 result
= nodeType
.GetIcon(packageIcon
, icon_size(iconSize
));
820 // Get super type icon
821 if (result
!= B_OK
) {
823 if (nodeType
.GetSupertype(&superType
) == B_OK
)
824 result
= superType
.GetIcon(packageIcon
, icon_size(iconSize
));
826 if (result
!= B_OK
) {
834 PackageItem::PackageItem(const char* name
, const char* simple_version
,
835 const char* detailed_version
, const char* repository
, const char* summary
,
836 const char* file_name
, SuperItem
* super
)
840 fSimpleVersion(simple_version
),
841 fDetailedVersion(detailed_version
),
842 fRepository(repository
),
844 fSmallFont(be_plain_font
),
846 fFileName(file_name
),
847 fDownloadProgress(0),
849 fMoreDetailsWidth(0),
852 fLabelOffset
= be_control_look
->DefaultLabelSpacing();
853 fSmallFont
.SetSize(be_plain_font
->Size() - 2);
854 fSmallFont
.GetHeight(&fSmallFontHeight
);
855 fSmallTotalHeight
= fSmallFontHeight
.ascent
+ fSmallFontHeight
.descent
856 + fSmallFontHeight
.leading
;
861 PackageItem::DrawItem(BView
* owner
, BRect item_rect
, bool complete
)
865 float width
= owner
->Frame().Width();
866 float nameWidth
= width
/ 2.0;
867 float offsetWidth
= 0;
868 bool showMoreDetails
= fSuperItem
->GetDetailLevel();
870 BBitmap
* icon
= fSuperItem
->GetIcon(showMoreDetails
);
871 if (icon
!= NULL
&& icon
->IsValid()) {
872 float iconSize
= icon
->Bounds().Height();
873 float offsetMarginHeight
= floor((Height() - iconSize
) / 2);
874 owner
->SetDrawingMode(B_OP_ALPHA
);
875 BPoint location
= BPoint(item_rect
.left
,
876 item_rect
.top
+ offsetMarginHeight
);
877 owner
->DrawBitmap(icon
, location
);
878 owner
->SetDrawingMode(B_OP_COPY
);
879 offsetWidth
= iconSize
+ fLabelOffset
;
882 _DrawBar(location
, owner
, icon_size(iconSize
));
885 owner
->SetFont(be_plain_font
);
886 owner
->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR
));
890 owner
->TruncateString(&name
, B_TRUNCATE_END
, nameWidth
);
891 BPoint
cursor(item_rect
.left
+ offsetWidth
,
892 item_rect
.bottom
- fSmallTotalHeight
- fSmallFontHeight
.descent
- 2);
894 cursor
.y
-= fSmallTotalHeight
+ 1;
895 owner
->DrawString(name
.String(), cursor
);
896 cursor
.x
+= owner
->StringWidth(name
.String()) + fLabelOffset
;
898 // Change font and color
899 owner
->SetFont(&fSmallFont
);
900 owner
->SetHighColor(tint_color(ui_color(B_LIST_ITEM_TEXT_COLOR
), 0.7));
902 // Simple version or repository
903 BString versionOrRepo
;
905 versionOrRepo
.SetTo(fRepository
);
907 versionOrRepo
.SetTo(fSimpleVersion
);
908 owner
->TruncateString(&versionOrRepo
, B_TRUNCATE_END
, width
- cursor
.x
);
909 owner
->DrawString(versionOrRepo
.String(), cursor
);
912 BString
summary(fSummary
);
913 cursor
.x
= item_rect
.left
+ offsetWidth
;
914 cursor
.y
+= fSmallTotalHeight
;
915 owner
->TruncateString(&summary
, B_TRUNCATE_END
, width
- cursor
.x
);
916 owner
->DrawString(summary
.String(), cursor
);
919 if (showMoreDetails
) {
920 BString
version(fDetailedVersion
);
921 cursor
.y
+= fSmallTotalHeight
;
922 owner
->TruncateString(&version
, B_TRUNCATE_END
, width
- cursor
.x
);
923 owner
->DrawString(version
.String(), cursor
);
930 // Modified slightly from Tracker's BPose::DrawBar
932 PackageItem::_DrawBar(BPoint where
, BView
* view
, icon_size which
)
935 int32 size
= which
- 1;
936 int32 barWidth
= (int32
)(7.0f
/ 32.0f
* (float)which
);
942 int32 barHeight
= size
- 3 - 2 * yOffset
;
945 // the black shadowed line
946 view
->SetHighColor(32, 32, 32, 92);
947 view
->MovePenTo(BPoint(where
.x
+ size
, where
.y
+ 1 + yOffset
));
948 view
->StrokeLine(BPoint(where
.x
+ size
, where
.y
+ size
- yOffset
));
949 view
->StrokeLine(BPoint(where
.x
+ size
- barWidth
+ 1,
950 where
.y
+ size
- yOffset
));
952 view
->SetDrawingMode(B_OP_ALPHA
);
955 view
->SetHighColor(76, 76, 76, 192);
956 BRect
rect(where
.x
+ size
- barWidth
,where
.y
+ yOffset
,
957 where
.x
+ size
- 1,where
.y
+ size
- 1 - yOffset
);
958 view
->StrokeRect(rect
);
960 // calculate bar height
961 int32 barPos
= barHeight
- int32(barHeight
* fDownloadProgress
/ 100.0);
964 else if (barPos
> barHeight
)
967 // the free space bar
968 view
->SetHighColor(255, 255, 255, 192);
972 bar
.bottom
= bar
.top
+ barPos
- 1;
976 // the used space bar
977 bar
.top
= bar
.bottom
+ 1;
978 bar
.bottom
= rect
.bottom
;
979 view
->SetHighColor(0, 203, 0, 192);
985 PackageItem::Update(BView
*owner
, const BFont
*font
)
987 BListItem::Update(owner
, font
);
988 SetHeight(fSuperItem
->GetPackageItemHeight());
993 PackageItem::CalculateZoomWidths(BView
*owner
)
998 float offsetWidth
= 2 * be_control_look
->DefaultItemSpacing()
999 + be_plain_font
->Size()
1000 + fSuperItem
->GetIconSize(true) + fLabelOffset
;
1002 owner
->SetFont(be_plain_font
);
1003 float stringWidth
= owner
->StringWidth(fName
.String());
1004 owner
->SetFont(&fSmallFont
);
1005 stringWidth
+= fLabelOffset
+ owner
->StringWidth(fRepository
.String());
1007 float summaryWidth
= owner
->StringWidth(fSummary
.String());
1008 if (summaryWidth
> stringWidth
)
1009 stringWidth
= summaryWidth
;
1011 float versionWidth
= owner
->StringWidth(fDetailedVersion
.String());
1012 if (versionWidth
> stringWidth
)
1013 stringWidth
= versionWidth
;
1014 fMoreDetailsWidth
= offsetWidth
+ stringWidth
;
1017 offsetWidth
= 2 * be_control_look
->DefaultItemSpacing()
1018 + be_plain_font
->Size()
1019 + fSuperItem
->GetIconSize(false) + fLabelOffset
;
1021 owner
->SetFont(be_plain_font
);
1022 stringWidth
= owner
->StringWidth(fName
.String());
1023 owner
->SetFont(&fSmallFont
);
1024 stringWidth
+= fLabelOffset
+ owner
->StringWidth(fSimpleVersion
.String());
1026 if (summaryWidth
> stringWidth
)
1027 stringWidth
= summaryWidth
;
1028 fLessDetailsWidth
= offsetWidth
+ stringWidth
;
1035 PackageItem::NameCompare(PackageItem
* item
)
1037 // sort by package name
1038 return fName
.ICompare(item
->fName
);
1043 PackageItem::SetDownloadProgress(float percent
)
1045 fDownloadProgress
= percent
;
1050 SortPackageItems(const BListItem
* item1
, const BListItem
* item2
)
1052 PackageItem
* first
= (PackageItem
*)item1
;
1053 PackageItem
* second
= (PackageItem
*)item2
;
1054 return first
->NameCompare(second
);
1058 PackageListView::PackageListView()
1060 BOutlineListView("Package list"),
1061 fSuperUpdateItem(NULL
),
1062 fSuperInstallItem(NULL
),
1063 fSuperUninstallItem(NULL
),
1064 fShowMoreDetails(false),
1065 fLastProgressItem(NULL
),
1066 fLastProgressValue(-1)
1068 SetExplicitMinSize(BSize(B_SIZE_UNSET
, 40));
1069 SetExplicitPreferredSize(BSize(B_SIZE_UNSET
, 400));
1074 PackageListView::FrameResized(float newWidth
, float newHeight
)
1076 BOutlineListView::FrameResized(newWidth
, newHeight
);
1082 PackageListView::ExpandOrCollapse(BListItem
*superItem
, bool expand
)
1084 BOutlineListView::ExpandOrCollapse(superItem
, expand
);
1085 Window()->PostMessage(kMsgSetZoomLimits
);
1090 PackageListView::AddPackage(uint32 install_type
, const char* name
,
1091 const char* cur_ver
, const char* new_ver
, const char* summary
,
1092 const char* repository
, const char* file_name
)
1095 BString simpleVersion
;
1096 BString
detailedVersion("");
1097 BString
repositoryText(B_TRANSLATE_COMMENT("from repository",
1099 repositoryText
.Append(" ").Append(repository
);
1101 switch (install_type
) {
1102 case PACKAGE_UPDATE
:
1104 if (fSuperUpdateItem
== NULL
) {
1105 fSuperUpdateItem
= new SuperItem(B_TRANSLATE_COMMENT(
1106 "Packages to be updated", "List super item label"));
1107 AddItem(fSuperUpdateItem
);
1109 super
= fSuperUpdateItem
;
1111 simpleVersion
.SetTo(new_ver
);
1112 detailedVersion
.Append(B_TRANSLATE_COMMENT("Updating version",
1114 .Append(" ").Append(cur_ver
)
1115 .Append(" ").Append(B_TRANSLATE_COMMENT("to",
1117 .Append(" ").Append(new_ver
);
1121 case PACKAGE_INSTALL
:
1123 if (fSuperInstallItem
== NULL
) {
1124 fSuperInstallItem
= new SuperItem(B_TRANSLATE_COMMENT(
1125 "New packages to be installed", "List super item label"));
1126 AddItem(fSuperInstallItem
);
1128 super
= fSuperInstallItem
;
1130 simpleVersion
.SetTo(new_ver
);
1131 detailedVersion
.Append(B_TRANSLATE_COMMENT("Installing version",
1133 .Append(" ").Append(new_ver
);
1137 case PACKAGE_UNINSTALL
:
1139 if (fSuperUninstallItem
== NULL
) {
1140 fSuperUninstallItem
= new SuperItem(B_TRANSLATE_COMMENT(
1141 "Packages to be uninstalled", "List super item label"));
1142 AddItem(fSuperUninstallItem
);
1144 super
= fSuperUninstallItem
;
1146 simpleVersion
.SetTo("");
1147 detailedVersion
.Append(B_TRANSLATE_COMMENT("Uninstalling version",
1149 .Append(" ").Append(cur_ver
);
1157 PackageItem
* item
= new PackageItem(name
, simpleVersion
.String(),
1158 detailedVersion
.String(), repositoryText
.String(), summary
, file_name
,
1160 AddUnder(item
, super
);
1161 super
->SetItemCount(CountItemsUnder(super
, true));
1162 item
->CalculateZoomWidths(this);
1167 PackageListView::UpdatePackageProgress(const char* packageName
, float percent
)
1169 // Update only every 1 percent change
1170 int16 wholePercent
= int16(percent
);
1171 if (wholePercent
== fLastProgressValue
)
1173 fLastProgressValue
= wholePercent
;
1175 // A new package started downloading, find the PackageItem by name
1177 fLastProgressItem
= NULL
;
1178 int32 count
= FullListCountItems();
1179 for (int32 i
= 0; i
< count
; i
++) {
1180 PackageItem
* item
= dynamic_cast<PackageItem
*>(FullListItemAt(i
));
1181 if (item
!= NULL
&& strcmp(item
->FileName(), packageName
) == 0) {
1182 fLastProgressItem
= item
;
1183 fLastProgressItem
->ShowProgressBar();
1189 if (fLastProgressItem
!= NULL
) {
1190 fLastProgressItem
->SetDownloadProgress(percent
);
1197 PackageListView::SortItems()
1199 if (fSuperUpdateItem
!= NULL
)
1200 SortItemsUnder(fSuperUpdateItem
, true, SortPackageItems
);
1201 if (fSuperInstallItem
!= NULL
)
1202 SortItemsUnder(fSuperInstallItem
, true, SortPackageItems
);
1203 if (fSuperUninstallItem
!= NULL
)
1204 SortItemsUnder(fSuperUninstallItem
, true, SortPackageItems
);
1209 PackageListView::ItemHeight()
1211 if (fSuperUpdateItem
!= NULL
)
1212 return fSuperUpdateItem
->GetPackageItemHeight();
1213 if (fSuperInstallItem
!= NULL
)
1214 return fSuperInstallItem
->GetPackageItemHeight();
1215 if (fSuperUninstallItem
!= NULL
)
1216 return fSuperUninstallItem
->GetPackageItemHeight();
1222 PackageListView::SetMoreDetails(bool showMore
)
1224 if (showMore
== fShowMoreDetails
)
1226 fShowMoreDetails
= showMore
;
1229 ResizeToPreferred();
1234 PackageListView::ZoomPoint()
1236 BPoint
zoomPoint(0, 0);
1237 int32 count
= CountItems();
1238 for (int32 i
= 0; i
< count
; i
++)
1240 BListItem
* item
= ItemAt(i
);
1241 float itemWidth
= 0;
1242 if (item
->OutlineLevel() == 0) {
1243 SuperItem
* sItem
= dynamic_cast<SuperItem
*>(item
);
1244 itemWidth
= sItem
->ZoomWidth(this);
1246 PackageItem
* pItem
= dynamic_cast<PackageItem
*>(item
);
1247 itemWidth
= fShowMoreDetails
? pItem
->MoreDetailsWidth()
1248 : pItem
->LessDetailsWidth();
1250 if (itemWidth
> zoomPoint
.x
)
1251 zoomPoint
.x
= itemWidth
;
1254 zoomPoint
.y
= ItemFrame(count
- 1).bottom
;
1261 PackageListView::_SetItemHeights()
1263 int32 itemCount
= 0;
1264 float itemHeight
= 0;
1265 BListItem
* item
= NULL
;
1266 if (fSuperUpdateItem
!= NULL
) {
1267 fSuperUpdateItem
->SetDetailLevel(fShowMoreDetails
);
1268 itemHeight
= fSuperUpdateItem
->GetPackageItemHeight();
1269 itemCount
= CountItemsUnder(fSuperUpdateItem
, true);
1270 for (int32 i
= 0; i
< itemCount
; i
++) {
1271 item
= ItemUnderAt(fSuperUpdateItem
, true, i
);
1272 item
->SetHeight(itemHeight
);
1275 if (fSuperInstallItem
!= NULL
) {
1276 fSuperInstallItem
->SetDetailLevel(fShowMoreDetails
);
1277 itemHeight
= fSuperInstallItem
->GetPackageItemHeight();
1278 itemCount
= CountItemsUnder(fSuperInstallItem
, true);
1279 for (int32 i
= 0; i
< itemCount
; i
++) {
1280 item
= ItemUnderAt(fSuperInstallItem
, true, i
);
1281 item
->SetHeight(itemHeight
);
1285 if (fSuperUninstallItem
!= NULL
) {
1286 fSuperUninstallItem
->SetDetailLevel(fShowMoreDetails
);
1287 itemHeight
= fSuperUninstallItem
->GetPackageItemHeight();
1288 itemCount
= CountItemsUnder(fSuperUninstallItem
, true);
1289 for (int32 i
= 0; i
< itemCount
; i
++) {
1290 item
= ItemUnderAt(fSuperUninstallItem
, true, i
);
1291 item
->SetHeight(itemHeight
);