1 /* 2 * Copyright 2016-2017 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT license 4 * 5 * Authors: 6 * Alexander von Gluck IV <kallisti5@unixzen.com> 7 * Brian Hill <supernova@warpmail.net> 8 */ 9 10 11 #include "SoftwareUpdaterWindow.h" 12 13 #include <Alert.h> 14 #include <AppDefs.h> 15 #include <Application.h> 16 #include <Catalog.h> 17 #include <ControlLook.h> 18 #include <LayoutBuilder.h> 19 #include <LayoutUtils.h> 20 #include <Message.h> 21 #include <NodeInfo.h> 22 #include <Roster.h> 23 #include <String.h> 24 25 #include "constants.h" 26 27 #undef B_TRANSLATION_CONTEXT 28 #define B_TRANSLATION_CONTEXT "SoftwareUpdaterWindow" 29 30 31 SoftwareUpdaterWindow::SoftwareUpdaterWindow() 32 : 33 BWindow(BRect(0, 0, 300, 100), 34 B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater"), B_TITLED_WINDOW, 35 B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE | B_NOT_CLOSABLE), 36 fStripeView(NULL), 37 fHeaderView(NULL), 38 fDetailView(NULL), 39 fUpdateButton(NULL), 40 fCancelButton(NULL), 41 fStatusBar(NULL), 42 fCurrentState(STATE_HEAD), 43 fWaitingSem(-1), 44 fWaitingForButton(false), 45 fUserCancelRequested(false), 46 fWarningAlertCount(0) 47 { 48 int32 iconSize = int(be_plain_font->Size() * 32.0 / 12.0); 49 // At 12 point font, icon size is 32, at 24 point it is 64 50 BBitmap icon = GetIcon(iconSize); 51 fStripeView = new StripeView(icon); 52 53 fUpdateButton = new BButton(B_TRANSLATE("Update now"), 54 new BMessage(kMsgUpdateConfirmed)); 55 fUpdateButton->MakeDefault(true); 56 fCancelButton = new BButton(B_TRANSLATE("Cancel"), 57 new BMessage(kMsgCancel)); 58 59 fHeaderView = new BStringView("header", 60 B_TRANSLATE("Checking for updates"), B_WILL_DRAW); 61 fHeaderView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 62 fHeaderView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); 63 fDetailView = new BStringView("detail", B_TRANSLATE("Contacting software " 64 "repositories to check for package updates."), B_WILL_DRAW); 65 fDetailView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); 66 fDetailView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); 67 fStatusBar = new BStatusBar("progress"); 68 fStatusBar->SetMaxValue(1.0); 69 70 fListView = new PackageListView(); 71 fScrollView = new BScrollView("scrollview", fListView, B_WILL_DRAW, 72 false, true); 73 74 BFont font; 75 fHeaderView->GetFont(&font); 76 font.SetFace(B_BOLD_FACE); 77 font.SetSize(font.Size() * 1.5); 78 fHeaderView->SetFont(&font, 79 B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE | B_FONT_FLAGS); 80 81 BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0) 82 .Add(fStripeView) 83 .AddGroup(B_VERTICAL, 0) 84 .SetInsets(0, B_USE_WINDOW_SPACING, 85 B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING) 86 .AddGroup(new BGroupView(B_VERTICAL, B_USE_ITEM_SPACING)) 87 .Add(fHeaderView) 88 .Add(fDetailView) 89 .Add(fStatusBar) 90 .Add(fScrollView) 91 .End() 92 .AddStrut(B_USE_SMALL_SPACING) 93 .AddGroup(new BGroupView(B_HORIZONTAL)) 94 .AddGlue() 95 .Add(fCancelButton) 96 .Add(fUpdateButton) 97 .End() 98 .End() 99 .End(); 100 101 fDetailsLayoutItem = layout_item_for(fDetailView); 102 fProgressLayoutItem = layout_item_for(fStatusBar); 103 fPackagesLayoutItem = layout_item_for(fScrollView); 104 fUpdateButtonLayoutItem = layout_item_for(fUpdateButton); 105 106 _SetState(STATE_DISPLAY_STATUS); 107 CenterOnScreen(); 108 Show(); 109 SetFlags(Flags() ^ B_AUTO_UPDATE_SIZE_LIMITS); 110 111 // Prevent resizing for now 112 fDefaultRect = Bounds(); 113 SetSizeLimits(fDefaultRect.Width(), fDefaultRect.Width(), 114 fDefaultRect.Height(), fDefaultRect.Height()); 115 116 BMessage registerMessage(kMsgRegister); 117 registerMessage.AddMessenger(kKeyMessenger, BMessenger(this)); 118 be_app->PostMessage(®isterMessage); 119 120 fCancelAlertResponse.SetMessage(new BMessage(kMsgCancelResponse)); 121 fCancelAlertResponse.SetTarget(this); 122 fWarningAlertDismissed.SetMessage(new BMessage(kMsgWarningDismissed)); 123 fWarningAlertDismissed.SetTarget(this); 124 } 125 126 127 void 128 SoftwareUpdaterWindow::MessageReceived(BMessage* message) 129 { 130 switch (message->what) { 131 132 case kMsgTextUpdate: 133 { 134 if (fCurrentState == STATE_DISPLAY_PROGRESS) 135 _SetState(STATE_DISPLAY_STATUS); 136 else if (fCurrentState != STATE_DISPLAY_STATUS) 137 break; 138 139 BString header; 140 BString detail; 141 Lock(); 142 status_t result = message->FindString(kKeyHeader, &header); 143 if (result == B_OK && header != fHeaderView->Text()) 144 fHeaderView->SetText(header.String()); 145 result = message->FindString(kKeyDetail, &detail); 146 if (result == B_OK) 147 fDetailView->SetText(detail.String()); 148 Unlock(); 149 break; 150 } 151 152 case kMsgProgressUpdate: 153 { 154 if (fCurrentState == STATE_DISPLAY_STATUS) 155 _SetState(STATE_DISPLAY_PROGRESS); 156 else if (fCurrentState != STATE_DISPLAY_PROGRESS) 157 break; 158 159 BString packageName; 160 status_t result = message->FindString(kKeyPackageName, &packageName); 161 if (result != B_OK) 162 break; 163 BString packageCount; 164 result = message->FindString(kKeyPackageCount, &packageCount); 165 if (result != B_OK) 166 break; 167 float percent; 168 result = message->FindFloat(kKeyPercentage, &percent); 169 if (result != B_OK) 170 break; 171 172 BString header; 173 Lock(); 174 result = message->FindString(kKeyHeader, &header); 175 if (result == B_OK && header != fHeaderView->Text()) 176 fHeaderView->SetText(header.String()); 177 fStatusBar->SetTo(percent, packageName.String(), 178 packageCount.String()); 179 Unlock(); 180 break; 181 } 182 183 case kMsgCancel: 184 { 185 if (_GetState() == STATE_FINAL_MESSAGE) { 186 PostMessage(B_QUIT_REQUESTED); 187 be_app->PostMessage(kMsgFinalQuit); 188 break; 189 } 190 191 BAlert* alert = new BAlert("cancel request", B_TRANSLATE("Updates" 192 " have not been completed, are you sure you want to quit?"), 193 B_TRANSLATE("Quit"), B_TRANSLATE("Don't quit"), NULL, 194 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 195 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 196 alert->Go(&fCancelAlertResponse); 197 break; 198 } 199 200 case kMsgCancelResponse: 201 { 202 // Verify whether the cancel request was confirmed 203 int32 selection = -1; 204 message->FindInt32("which", &selection); 205 if (selection != 0) 206 break; 207 208 Lock(); 209 fHeaderView->SetText(B_TRANSLATE("Cancelling updates")); 210 fDetailView->SetText( 211 B_TRANSLATE("Attempting to cancel the updates...")); 212 fCancelButton->SetEnabled(false); 213 Unlock(); 214 fUserCancelRequested = true; 215 216 if (fWaitingForButton) { 217 fButtonResult = message->what; 218 delete_sem(fWaitingSem); 219 fWaitingSem = -1; 220 } 221 break; 222 } 223 224 case kMsgUpdateConfirmed: 225 { 226 if (fWaitingForButton) { 227 fButtonResult = message->what; 228 delete_sem(fWaitingSem); 229 fWaitingSem = -1; 230 } 231 break; 232 } 233 234 case kMsgWarningDismissed: 235 fWarningAlertCount--; 236 break; 237 238 case kMsgNetworkAlert: 239 { 240 BAlert* alert = new BAlert("network_connection", 241 B_TRANSLATE_COMMENT("No active network connection was found", 242 "Alert message"), 243 B_TRANSLATE_COMMENT("Continue anyway", "Alert button label"), 244 B_TRANSLATE_COMMENT("Quit","Alert button label"), 245 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 246 int32 result = alert->Go(); 247 BMessage reply; 248 reply.AddInt32(kKeyAlertResult, result); 249 message->SendReply(&reply); 250 break; 251 } 252 253 default: 254 BWindow::MessageReceived(message); 255 } 256 } 257 258 259 bool 260 SoftwareUpdaterWindow::ConfirmUpdates(const char* text) 261 { 262 Lock(); 263 fHeaderView->SetText(B_TRANSLATE("Updates found")); 264 fDetailView->SetText(text); 265 fListView->SortItems(); 266 Unlock(); 267 268 uint32 priorState = _GetState(); 269 _SetState(STATE_GET_CONFIRMATION); 270 271 _WaitForButtonClick(); 272 _SetState(priorState); 273 return fButtonResult == kMsgUpdateConfirmed; 274 } 275 276 277 void 278 SoftwareUpdaterWindow::UpdatesApplying(const char* header, const char* detail) 279 { 280 Lock(); 281 fHeaderView->SetText(header); 282 fDetailView->SetText(detail); 283 Unlock(); 284 _SetState(STATE_APPLY_UPDATES); 285 } 286 287 288 bool 289 SoftwareUpdaterWindow::UserCancelRequested() 290 { 291 if (_GetState() > STATE_GET_CONFIRMATION) 292 return false; 293 294 return fUserCancelRequested; 295 } 296 297 298 void 299 SoftwareUpdaterWindow::AddPackageInfo(uint32 install_type, 300 const char* package_name, const char* cur_ver, const char* new_ver, 301 const char* summary, const char* repository) 302 { 303 Lock(); 304 fListView->AddPackage(install_type, package_name, cur_ver, new_ver, 305 summary, repository); 306 Unlock(); 307 } 308 309 310 void 311 SoftwareUpdaterWindow::ShowWarningAlert(const char* text) 312 { 313 BAlert* alert = new BAlert("warning", text, B_TRANSLATE("OK"), NULL, NULL, 314 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 315 alert->Go(&fWarningAlertDismissed); 316 alert->CenterIn(Frame()); 317 // Offset multiple alerts 318 alert->MoveBy(fWarningAlertCount * 15, fWarningAlertCount * 15); 319 fWarningAlertCount++; 320 } 321 322 323 BBitmap 324 SoftwareUpdaterWindow::GetIcon(int32 iconSize) 325 { 326 BBitmap icon(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); 327 team_info teamInfo; 328 get_team_info(B_CURRENT_TEAM, &teamInfo); 329 app_info appInfo; 330 be_roster->GetRunningAppInfo(teamInfo.team, &appInfo); 331 BNodeInfo::GetTrackerIcon(&appInfo.ref, &icon, icon_size(iconSize)); 332 return icon; 333 } 334 335 336 BBitmap 337 SoftwareUpdaterWindow::GetNotificationIcon() 338 { 339 return GetIcon(B_LARGE_ICON); 340 } 341 342 343 void 344 SoftwareUpdaterWindow::FinalUpdate(const char* header, const char* detail) 345 { 346 if (_GetState() == STATE_FINAL_MESSAGE) 347 return; 348 349 _SetState(STATE_FINAL_MESSAGE); 350 Lock(); 351 fHeaderView->SetText(header); 352 fDetailView->SetText(detail); 353 Unlock(); 354 } 355 356 357 BLayoutItem* 358 SoftwareUpdaterWindow::layout_item_for(BView* view) 359 { 360 BLayout* layout = view->Parent()->GetLayout(); 361 int32 index = layout->IndexOfView(view); 362 return layout->ItemAt(index); 363 } 364 365 366 uint32 367 SoftwareUpdaterWindow::_WaitForButtonClick() 368 { 369 fButtonResult = 0; 370 fWaitingForButton = true; 371 fWaitingSem = create_sem(0, "WaitingSem"); 372 while (acquire_sem(fWaitingSem) == B_INTERRUPTED) { 373 } 374 fWaitingForButton = false; 375 return fButtonResult; 376 } 377 378 379 void 380 SoftwareUpdaterWindow::_SetState(uint32 state) 381 { 382 if (state <= STATE_HEAD || state >= STATE_MAX) 383 return; 384 385 Lock(); 386 387 // Initial settings 388 if (fCurrentState == STATE_HEAD) { 389 fProgressLayoutItem->SetVisible(false); 390 fPackagesLayoutItem->SetVisible(false); 391 } 392 fCurrentState = state; 393 394 // Update confirmation button 395 // Show only when asking for confirmation to update 396 if (fCurrentState == STATE_GET_CONFIRMATION) 397 fUpdateButtonLayoutItem->SetVisible(true); 398 else 399 fUpdateButtonLayoutItem->SetVisible(false); 400 401 // View package info view 402 // Show at confirmation prompt, hide at final update 403 if (fCurrentState == STATE_GET_CONFIRMATION) { 404 fPackagesLayoutItem->SetVisible(true); 405 // Re-enable resizing 406 float defaultWidth = fDefaultRect.Width(); 407 SetSizeLimits(defaultWidth, 9999, 408 fDefaultRect.Height() + 4 * fListView->ItemHeight(), 9999); 409 ResizeTo(defaultWidth, .75 * defaultWidth); 410 } else if (fCurrentState == STATE_FINAL_MESSAGE) { 411 fPackagesLayoutItem->SetVisible(false); 412 float defaultWidth = fDefaultRect.Width(); 413 float defaultHeight = fDefaultRect.Height(); 414 SetSizeLimits(defaultWidth, defaultWidth, defaultHeight, 415 defaultHeight); 416 ResizeTo(defaultWidth, defaultHeight); 417 } 418 419 // Progress bar and string view 420 // Hide detail text while showing status bar 421 if (fCurrentState == STATE_DISPLAY_PROGRESS) { 422 fDetailsLayoutItem->SetVisible(false); 423 fProgressLayoutItem->SetVisible(true); 424 } else { 425 fProgressLayoutItem->SetVisible(false); 426 fDetailsLayoutItem->SetVisible(true); 427 } 428 429 // Cancel button 430 if (fCurrentState == STATE_FINAL_MESSAGE) 431 fCancelButton->SetLabel(B_TRANSLATE("Quit")); 432 fCancelButton->SetEnabled(fCurrentState != STATE_APPLY_UPDATES); 433 434 Unlock(); 435 } 436 437 438 uint32 439 SoftwareUpdaterWindow::_GetState() 440 { 441 return fCurrentState; 442 } 443 444 445 SuperItem::SuperItem(const char* label) 446 : 447 BListItem(), 448 fLabel(label), 449 fPackageIcon(NULL) 450 { 451 } 452 453 454 SuperItem::~SuperItem() 455 { 456 delete fPackageIcon; 457 } 458 459 460 void 461 SuperItem::DrawItem(BView* owner, BRect item_rect, bool complete) 462 { 463 float width; 464 owner->GetPreferredSize(&width, NULL); 465 BString label(fLabel); 466 owner->TruncateString(&label, B_TRUNCATE_END, width); 467 owner->SetFont(&fBoldFont); 468 owner->DrawString(label.String(), BPoint(item_rect.left, 469 item_rect.bottom - fFontHeight.descent - 1)); 470 owner->SetFont(&fRegularFont); 471 } 472 473 474 void 475 SuperItem::Update(BView *owner, const BFont *font) 476 { 477 fRegularFont = *font; 478 fBoldFont = *font; 479 fBoldFont.SetFace(B_BOLD_FACE); 480 BListItem::Update(owner, &fBoldFont); 481 482 // Calculate height for PackageItem 483 fRegularFont.GetHeight(&fFontHeight); 484 fPackageItemHeight = 2 * (fFontHeight.ascent + fFontHeight.descent 485 + fFontHeight.leading); 486 487 // Calculate height for this item 488 fBoldFont.GetHeight(&fFontHeight); 489 SetHeight(fFontHeight.ascent + fFontHeight.descent 490 + fFontHeight.leading + 4); 491 492 _GetPackageIcon(); 493 } 494 495 496 void 497 SuperItem::_GetPackageIcon() 498 { 499 delete fPackageIcon; 500 fIconSize = int(fPackageItemHeight * .7); 501 502 status_t result = B_ERROR; 503 BRect iconRect(0, 0, fIconSize - 1, fIconSize - 1); 504 fPackageIcon = new BBitmap(iconRect, 0, B_RGBA32); 505 BMimeType nodeType; 506 nodeType.SetTo("application/x-vnd.haiku-package"); 507 result = nodeType.GetIcon(fPackageIcon, icon_size(fIconSize)); 508 // Get super type icon 509 if (result != B_OK) { 510 BMimeType superType; 511 if (nodeType.GetSupertype(&superType) == B_OK) 512 result = superType.GetIcon(fPackageIcon, icon_size(fIconSize)); 513 } 514 if (result != B_OK) { 515 delete fPackageIcon; 516 fPackageIcon = NULL; 517 } 518 } 519 520 521 PackageItem::PackageItem(const char* name, const char* version, 522 const char* summary, const char* tooltip, SuperItem* super) 523 : 524 BListItem(), 525 fName(name), 526 fVersion(version), 527 fSummary(summary), 528 fToolTip(NULL), 529 fSuperItem(super) 530 { 531 fLabelOffset = be_control_look->DefaultLabelSpacing(); 532 if (tooltip != NULL) 533 fToolTip = new BTextToolTip(tooltip); 534 } 535 536 537 PackageItem::~PackageItem() 538 { 539 if (fToolTip != NULL) 540 fToolTip->ReleaseReference(); 541 } 542 543 544 void 545 PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete) 546 { 547 float width; 548 owner->GetPreferredSize(&width, NULL); 549 float nameWidth = width / 2.0; 550 float offset_width = 0; 551 552 BBitmap* icon = fSuperItem->GetIcon(); 553 if (icon != NULL && icon->IsValid()) { 554 int16 iconSize = fSuperItem->GetIconSize(); 555 float offsetMarginHeight = floor((Height() - iconSize) / 2); 556 557 //owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 558 owner->SetDrawingMode(B_OP_ALPHA); 559 owner->DrawBitmap(icon, BPoint(item_rect.left, 560 item_rect.top + offsetMarginHeight)); 561 owner->SetDrawingMode(B_OP_COPY); 562 offset_width += iconSize + fLabelOffset; 563 } 564 565 // Package name 566 font_height fontHeight = fSuperItem->GetFontHeight(); 567 BString name(fName); 568 owner->TruncateString(&name, B_TRUNCATE_END, nameWidth); 569 BPoint cursor(item_rect.left + offset_width, 570 item_rect.bottom - fSmallTotalHeight - fontHeight.descent - 1); 571 owner->DrawString(name.String(), cursor); 572 cursor.x += owner->StringWidth(name.String()) + fLabelOffset; 573 574 // Change font and color 575 owner->SetFont(&fSmallFont); 576 owner->SetHighColor(tint_color(ui_color(B_LIST_ITEM_TEXT_COLOR), 0.7)); 577 578 // Version 579 BString version(fVersion); 580 owner->TruncateString(&version, B_TRUNCATE_END, width - cursor.x); 581 owner->DrawString(version.String(), cursor); 582 583 // Summary 584 BString summary(fSummary); 585 cursor.x = item_rect.left + offset_width; 586 cursor.y = item_rect.bottom - fontHeight.descent; 587 owner->TruncateString(&summary, B_TRUNCATE_END, width - cursor.x); 588 owner->DrawString(summary.String(), cursor); 589 590 owner->SetFont(&fRegularFont); 591 } 592 593 594 void 595 PackageItem::Update(BView *owner, const BFont *font) 596 { 597 BListItem::Update(owner, font); 598 SetItemHeight(font); 599 } 600 601 602 void 603 PackageItem::SetItemHeight(const BFont* font) 604 { 605 SetHeight(fSuperItem->GetPackageItemHeight()); 606 607 fRegularFont = *font; 608 fSmallFont = *font; 609 fSmallFont.SetSize(font->Size() - 2); 610 fSmallFont.GetHeight(&fSmallFontHeight); 611 fSmallTotalHeight = fSmallFontHeight.ascent + fSmallFontHeight.descent 612 + fSmallFontHeight.leading; 613 } 614 615 616 int 617 PackageItem::NameCompare(PackageItem* item) 618 { 619 // sort by package name 620 return fName.ICompare(item->fName); 621 } 622 623 624 int 625 SortPackageItems(const BListItem* item1, const BListItem* item2) 626 { 627 PackageItem* first = (PackageItem*)item1; 628 PackageItem* second = (PackageItem*)item2; 629 return first->NameCompare(second); 630 } 631 632 633 PackageListView::PackageListView() 634 : 635 BOutlineListView("Package list"), 636 fSuperUpdateItem(NULL), 637 fSuperInstallItem(NULL), 638 fSuperUninstallItem(NULL) 639 { 640 SetExplicitMinSize(BSize(B_SIZE_UNSET, 40)); 641 SetExplicitPreferredSize(BSize(B_SIZE_UNSET, 400)); 642 } 643 644 645 void 646 PackageListView::FrameResized(float newWidth, float newHeight) 647 { 648 BListView::FrameResized(newWidth, newHeight); 649 650 float count = CountItems(); 651 for (int32 i = 0; i < count; i++) { 652 BListItem *item = ItemAt(i); 653 item->Update(this, be_plain_font); 654 } 655 Invalidate(); 656 } 657 658 659 void 660 PackageListView::MouseDown(BPoint where) 661 { 662 BOutlineListView::MouseDown(where); 663 BToolTip* tooltip = NULL; 664 bool found = GetToolTipAt(where, &tooltip); 665 if (found) 666 ShowToolTip(tooltip); 667 } 668 669 670 bool 671 PackageListView::GetToolTipAt(BPoint point, BToolTip** _tip) 672 { 673 BListItem* item = ItemAt(IndexOf(point)); 674 if (item == NULL) 675 return false; 676 PackageItem* pItem = dynamic_cast<PackageItem*>(item); 677 if (pItem != NULL) { 678 *_tip = pItem->ToolTip(); 679 return true; 680 } 681 return false; 682 } 683 684 685 void 686 PackageListView::AddPackage(uint32 install_type, const char* name, 687 const char* cur_ver, const char* new_ver, const char* summary, 688 const char* repository) 689 { 690 SuperItem* super; 691 BString version; 692 BString tooltip(B_TRANSLATE_COMMENT("Package:", "Tooltip text")); 693 tooltip.Append(" ").Append(name).Append("\n") 694 .Append(B_TRANSLATE_COMMENT("Repository:", "Tooltip text")) 695 .Append(" ").Append(repository).Append("\n"); 696 switch (install_type) { 697 case PACKAGE_UPDATE: 698 { 699 if (fSuperUpdateItem == NULL) { 700 fSuperUpdateItem = new SuperItem(B_TRANSLATE_COMMENT( 701 "Packages to be updated", "List super item label")); 702 AddItem(fSuperUpdateItem); 703 } 704 super = fSuperUpdateItem; 705 706 version.SetTo(new_ver); 707 tooltip.Append(B_TRANSLATE_COMMENT("Updating version", 708 "Tooltip text")) 709 .Append(" ").Append(cur_ver) 710 .Append(" ").Append(B_TRANSLATE_COMMENT("to", "Tooltip text")) 711 .Append(" ").Append(new_ver); 712 break; 713 } 714 715 case PACKAGE_INSTALL: 716 { 717 if (fSuperInstallItem == NULL) { 718 fSuperInstallItem = new SuperItem(B_TRANSLATE_COMMENT( 719 "New packages to be installed", "List super item label")); 720 AddItem(fSuperInstallItem); 721 } 722 super = fSuperInstallItem; 723 724 version.SetTo(new_ver); 725 tooltip.Append(B_TRANSLATE_COMMENT("Installing version", 726 "Tooltip text")) 727 .Append(" ").Append(new_ver); 728 break; 729 } 730 731 case PACKAGE_UNINSTALL: 732 { 733 if (fSuperUninstallItem == NULL) { 734 fSuperUninstallItem = new SuperItem(B_TRANSLATE_COMMENT( 735 "Packages to be uninstalled", "List super item label")); 736 AddItem(fSuperUninstallItem); 737 } 738 super = fSuperUninstallItem; 739 740 version.SetTo(""); 741 tooltip.Append(B_TRANSLATE_COMMENT("Uninstalling version", 742 "Tooltip text")) 743 .Append(" ").Append(cur_ver); 744 break; 745 } 746 747 default: 748 return; 749 750 } 751 PackageItem* item = new PackageItem(name, version.String(), summary, 752 tooltip.String(), super); 753 AddUnder(item, super); 754 } 755 756 757 void 758 PackageListView::SortItems() 759 { 760 if (fSuperUpdateItem != NULL) 761 SortItemsUnder(fSuperUpdateItem, true, SortPackageItems); 762 if (fSuperInstallItem != NULL) 763 SortItemsUnder(fSuperInstallItem, true, SortPackageItems); 764 if (fSuperUninstallItem != NULL) 765 SortItemsUnder(fSuperUninstallItem, true, SortPackageItems); 766 } 767 768 769 float 770 PackageListView::ItemHeight() 771 { 772 if (fSuperUpdateItem != NULL) 773 return fSuperUpdateItem->GetPackageItemHeight(); 774 if (fSuperInstallItem != NULL) 775 return fSuperInstallItem->GetPackageItemHeight(); 776 if (fSuperUninstallItem != NULL) 777 return fSuperUninstallItem->GetPackageItemHeight(); 778 return 0; 779 } 780