Updates to SoftwareUpdater

Committing work done to make SoftwareUpdater functional.  The
application will find available updates, confirm with the user to
apply updates, download packages and apply them.  There are a few bugs
and features remaining to be fixed and completed:

*Bug with window resizing after packages start downloading- list view
	does not resize down
*Tooltips to be implemented (showing repository and other details)
*Proper handling of no network or failed repository connections
*Testing of the problem solver
*Mode to only check for availability of updates and post notification
	with results
This commit is contained in:
Brian Hill 2017-03-11 15:16:09 -05:00
parent 74972d36d5
commit ad7783e44d
14 changed files with 1412 additions and 153 deletions

View File

@ -1,10 +1,20 @@
SubDir HAIKU_TOP src apps softwareupdater ;
UsePrivateHeaders interface shared package ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers package ] ;
Application SoftwareUpdater :
SoftwareUpdaterApp.cpp
SoftwareUpdaterWindow.cpp
StripeView.cpp
UpdateAction.cpp
UpdateManager.cpp
WorkingLooper.cpp
# package_daemon
ProblemWindow.cpp
: be localestub package translation [ TargetLibsupc++ ]
: SoftwareUpdater.rdef
;

View File

@ -9,7 +9,7 @@ resource app_version {
variety = B_APPV_BETA,
internal = 0,
short_info = "SoftwareUpdater",
long_info = "Software Updater ©2008-2016 Haiku"
long_info = "Software Updater ©2008-2017 Haiku"
};
resource vector_icon {

View File

@ -1,41 +1,75 @@
/*
* Copyright 2016 Haiku, Inc. All rights reserved.
* Copyright 2016-2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license
*
* Authors:
* Alexander von Gluck IV <kallisti5@unixzen.com>
* Brian Hill <supernova@warpmail.net>
*/
#include "SoftwareUpdaterApp.h"
#include <stdio.h>
#include <AppDefs.h>
#include "SoftwareUpdaterWindow.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SoftwareUpdater"
#include "constants.h"
SoftwareUpdaterApp::SoftwareUpdaterApp()
:
BApplication("application/x-vnd.haiku-softwareupdater")
BApplication("application/x-vnd.haiku-softwareupdater"),
fWorker(NULL),
fFinalQuitFlag(false)
{
}
SoftwareUpdaterApp::~SoftwareUpdaterApp()
{
if (fWorker) {
fWorker->Lock();
fWorker->Quit();
}
}
bool
SoftwareUpdaterApp::QuitRequested()
{
if (fFinalQuitFlag)
return true;
// Simulate a cancel request from window- this gives the updater a chance
// to quit cleanly
if (fWindowMessenger.IsValid()) {
fWindowMessenger.SendMessage(kMsgCancel);
return false;
}
return true;
}
void
SoftwareUpdaterApp::ReadyToRun()
{
SoftwareUpdaterWindow* window = new SoftwareUpdaterWindow();
if (window)
window->Show();
fWorker = new WorkingLooper();
}
void
SoftwareUpdaterApp::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgRegister:
message->FindMessenger(kKeyMessenger, &fWindowMessenger);
break;
case kMsgFinalQuit:
fFinalQuitFlag = true;
PostMessage(B_QUIT_REQUESTED);
break;
default:
BApplication::MessageReceived(message);
}
}

View File

@ -1,22 +1,32 @@
/*
* Copyright 2016 Haiku, Inc. All rights reserved.
* Copyright 2016-2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license
*
* Authors:
* Alexander von Gluck IV <kallisti5@unixzen.com>
* Brian Hill <supernova@warpmail.net>
*/
#ifndef _SOFTWARE_UPDATER_APP_H
#define _SOFTWARE_UPDATER_APP_H
#include <Application.h>
#include "WorkingLooper.h"
class SoftwareUpdaterApp : public BApplication {
public:
SoftwareUpdaterApp();
~SoftwareUpdaterApp();
SoftwareUpdaterApp();
~SoftwareUpdaterApp();
virtual bool QuitRequested();
void ReadyToRun();
void MessageReceived(BMessage* message);
void ReadyToRun();
private:
WorkingLooper* fWorker;
BMessenger fWindowMessenger;
bool fFinalQuitFlag;
};

View File

@ -1,121 +1,138 @@
/*
* Copyright 2016 Haiku, Inc. All rights reserved.
* Copyright 2016-2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license
*
* Authors:
* Alexander von Gluck IV <kallisti5@unixzen.com>
* Brian Hill <supernova@warpmail.net>
*/
#include "SoftwareUpdaterWindow.h"
#include <stdio.h>
#include <Alert.h>
#include <AppDefs.h>
#include <Application.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <NodeInfo.h>
#include <Catalog.h>
#include <ControlLook.h>
#include <LayoutBuilder.h>
#include <LayoutUtils.h>
#include <Message.h>
#include <package/Context.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/PackageRoster.h>
#include <Resources.h>
#include <SeparatorView.h>
#include <NodeInfo.h>
#include <Roster.h>
#include <String.h>
#include "constants.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SoftwareUpdater"
const uint32 kMsgUpdate = 'iUPD';
const uint32 kMsgExit = 'iEXT';
using namespace BPackageKit;
#define B_TRANSLATION_CONTEXT "SoftwareUpdaterWindow"
SoftwareUpdaterWindow::SoftwareUpdaterWindow()
:
BWindow(BRect(0, 0, 0, 300), "Software Update",
B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE),
// fUpdateManager(NULL),
BWindow(BRect(0, 0, 300, 100),
B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater"), B_TITLED_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE | B_NOT_CLOSABLE),
fStripeView(NULL),
fHeaderView(NULL),
fDetailView(NULL),
fUpdateButton(NULL),
fCancelButton(NULL)
fCancelButton(NULL),
fStatusBar(NULL),
fIcon(NULL),
fCurrentState(STATE_HEAD),
fWaitingSem(-1),
fWaitingForButton(false),
fUserCancelRequested(false)
{
fUpdateManager = new UpdateManager(
BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_HOME);
fUpdateManager->SetDebugLevel(10);
fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES);
BBitmap* icon = new BBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32);
fIcon = new BBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32);
team_info teamInfo;
get_team_info(B_CURRENT_TEAM, &teamInfo);
app_info appInfo;
be_roster->GetRunningAppInfo(teamInfo.team, &appInfo);
BNodeInfo::GetTrackerIcon(&appInfo.ref, icon, B_LARGE_ICON);
BNodeInfo::GetTrackerIcon(&appInfo.ref, fIcon, B_LARGE_ICON);
fStripeView = new StripeView(icon);
fStripeView = new StripeView(fIcon);
BButton* fUpdateButton = new BButton("Update now",
new BMessage(kMsgUpdate));
fUpdateButton->Hide();
BButton* fCancelButton = new BButton("Cancel",
new BMessage(kMsgExit));
fUpdateButton = new BButton(B_TRANSLATE("Update now"),
new BMessage(kMsgUpdateConfirmed));
fUpdateButton->MakeDefault(true);
// fUpdateButton->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_UNSET,
// B_ALIGN_BOTTOM));
fCancelButton = new BButton(B_TRANSLATE("Cancel"),
new BMessage(kMsgCancel));
// fCancelButton->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_UNSET,
// B_ALIGN_BOTTOM));
fHeaderView = new BStringView("header",
"Checking for updates...", B_WILL_DRAW);
fDetailView = new BStringView("detail", "Contacting software repositories"
" to check for package updates.", B_WILL_DRAW);
B_TRANSLATE("Checking for updates"), B_WILL_DRAW);
fHeaderView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fHeaderView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
fDetailView = new BStringView("detail", B_TRANSLATE("Contacting software "
"repositories to check for package updates."), B_WILL_DRAW);
fDetailView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fDetailView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
fStatusBar = new BStatusBar("progress");
fStatusBar->SetMaxValue(1.0);
fListView = new PackageListView();
fScrollView = new BScrollView("scrollview", fListView, B_WILL_DRAW,
false, true);
BFont font;
fHeaderView->GetFont(&font);
font.SetFace(B_BOLD_FACE);
font.SetSize(font.Size() * 1.5);
fHeaderView->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
| B_FONT_FLAGS);
fHeaderView->SetFont(&font,
B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE | B_FONT_FLAGS);
BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
.Add(fStripeView)
.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
.SetInsets(0, B_USE_DEFAULT_SPACING,
B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING)
.Add(fHeaderView)
.Add(fDetailView)
.AddStrut(B_USE_DEFAULT_SPACING)
.AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING)
.AddGroup(B_VERTICAL, 0)
.SetInsets(0, B_USE_WINDOW_SPACING,
B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
.AddGroup(new BGroupView(B_VERTICAL, B_USE_ITEM_SPACING))
.Add(fHeaderView)
.Add(fDetailView)
.Add(fStatusBar)
.Add(fScrollView)
.End()
.AddStrut(B_USE_SMALL_SPACING)
.AddGroup(new BGroupView(B_HORIZONTAL))
.AddGlue()
.Add(fCancelButton)
.Add(fUpdateButton)
.End()
.End()
.AddGlue()
//.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
;
.End();
fDetailsLayoutItem = layout_item_for(fDetailView);
fProgressLayoutItem = layout_item_for(fStatusBar);
fPackagesLayoutItem = layout_item_for(fScrollView);
fUpdateButtonLayoutItem = layout_item_for(fUpdateButton);
_SetState(STATE_DISPLAY_STATUS);
CenterOnScreen();
Show();
// Refresh our repos and update UI
_Refresh();
SetFlags(Flags() ^ B_AUTO_UPDATE_SIZE_LIMITS);
// Prevent resizing for now
fDefaultRect = Bounds();
SetSizeLimits(fDefaultRect.Width(), fDefaultRect.Width(),
fDefaultRect.Height(), fDefaultRect.Height());
BMessage registerMessage(kMsgRegister);
registerMessage.AddMessenger(kKeyMessenger, BMessenger(this));
be_app->PostMessage(&registerMessage);
fCancelAlertResponse.SetMessage(new BMessage(kMsgCancelResponse));
fCancelAlertResponse.SetTarget(this);
}
SoftwareUpdaterWindow::~SoftwareUpdaterWindow()
{
}
bool
SoftwareUpdaterWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
delete fIcon;
}
@ -123,54 +140,628 @@ void
SoftwareUpdaterWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgExit:
QuitRequested();
case kMsgTextUpdate:
{
if (fCurrentState == STATE_DISPLAY_PROGRESS)
_SetState(STATE_DISPLAY_STATUS);
else if (fCurrentState != STATE_DISPLAY_STATUS)
break;
BString header;
BString detail;
Lock();
status_t result = message->FindString(kKeyHeader, &header);
if (result == B_OK && header != fHeaderView->Text())
fHeaderView->SetText(header.String());
result = message->FindString(kKeyDetail, &detail);
if (result == B_OK)
fDetailView->SetText(detail.String());
Unlock();
break;
case kMsgUpdate:
}
case kMsgProgressUpdate:
{
if (fCurrentState == STATE_DISPLAY_STATUS)
_SetState(STATE_DISPLAY_PROGRESS);
else if (fCurrentState != STATE_DISPLAY_PROGRESS)
break;
BString packageName;
status_t result = message->FindString(kKeyPackageName, &packageName);
if (result != B_OK)
break;
BString packageCount;
result = message->FindString(kKeyPackageCount, &packageCount);
if (result != B_OK)
break;
float percent;
result = message->FindFloat(kKeyPercentage, &percent);
if (result != B_OK)
break;
BString header;
Lock();
result = message->FindString(kKeyHeader, &header);
if (result == B_OK && header != fHeaderView->Text())
fHeaderView->SetText(header.String());
fStatusBar->SetTo(percent, packageName.String(),
packageCount.String());
Unlock();
break;
}
case kMsgCancel:
{
BAlert* alert = new BAlert("cancel request", B_TRANSLATE("Updates"
" have not been completed, are you sure you want to quit?"),
B_TRANSLATE("Quit"), B_TRANSLATE("Don't quit"), NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go(&fCancelAlertResponse);
break;
}
case kMsgCancelResponse:
{
// Verify whether the cancel request was confirmed
int32 selection = -1;
message->FindInt32("which", &selection);
if (selection != 0)
break;
Lock();
fHeaderView->SetText(B_TRANSLATE("Cancelling updates"));
fDetailView->SetText(
B_TRANSLATE("Attempting to cancel the updates..."));
Unlock();
fUserCancelRequested = true;
if (fWaitingForButton) {
fButtonResult = message->what;
delete_sem(fWaitingSem);
fWaitingSem = -1;
}
break;
}
case kMsgUpdateConfirmed:
{
if (fWaitingForButton) {
fButtonResult = message->what;
delete_sem(fWaitingSem);
fWaitingSem = -1;
}
break;
}
default:
BWindow::MessageReceived(message);
}
}
void
SoftwareUpdaterWindow::_Error(const char* error)
bool
SoftwareUpdaterWindow::ConfirmUpdates(const char* text)
{
fHeaderView->SetText("Error encountered!");
fDetailView->SetText(error);
fUpdateButton->Hide();
fCancelButton->Show();
Lock();
fHeaderView->SetText(B_TRANSLATE("Updates found"));
fDetailView->SetText(text);
fListView->SortItems();
Unlock();
uint32 priorState = _GetState();
_SetState(STATE_GET_CONFIRMATION);
_WaitForButtonClick();
_SetState(priorState);
return fButtonResult == kMsgUpdateConfirmed;
}
void
SoftwareUpdaterWindow::_Refresh()
{
BPackageRoster roster;
BStringList repoNames(20);
status_t result = roster.GetRepositoryNames(repoNames);
if (result != B_OK) {
_Error("Unable to obtain repository names.");
void
SoftwareUpdaterWindow::UpdatesApplying(const char* header, const char* detail)
{
Lock();
fHeaderView->SetText(header);
fDetailView->SetText(detail);
Unlock();
_SetState(STATE_APPLY_UPDATES);
}
bool
SoftwareUpdaterWindow::UserCancelRequested()
{
if (_GetState() > STATE_GET_CONFIRMATION)
return false;
return fUserCancelRequested;
}
void
SoftwareUpdaterWindow::AddPackageInfo(uint32 install_type,
const char* package_name, const char* cur_ver, const char* new_ver,
const char* summary, const char* repository)
{
Lock();
fListView->AddPackage(install_type, package_name, cur_ver, new_ver,
summary, repository);
Unlock();
}
BLayoutItem*
SoftwareUpdaterWindow::layout_item_for(BView* view)
{
BLayout* layout = view->Parent()->GetLayout();
int32 index = layout->IndexOfView(view);
return layout->ItemAt(index);
}
uint32
SoftwareUpdaterWindow::_WaitForButtonClick()
{
fButtonResult = 0;
fWaitingForButton = true;
fWaitingSem = create_sem(0, "WaitingSem");
while (acquire_sem(fWaitingSem) == B_INTERRUPTED) {
}
fWaitingForButton = false;
return fButtonResult;
}
void
SoftwareUpdaterWindow::_SetState(uint32 state)
{
if (state <= STATE_HEAD || state >= STATE_MAX)
return;
Lock();
// Initial settings
if (fCurrentState == STATE_HEAD) {
fProgressLayoutItem->SetVisible(false);
fPackagesLayoutItem->SetVisible(false);
}
fCurrentState = state;
// Update confirmation button
// Show only when asking for confirmation to update
if (fCurrentState == STATE_GET_CONFIRMATION)
fUpdateButtonLayoutItem->SetVisible(true);
else
fUpdateButtonLayoutItem->SetVisible(false);
// View package info view
// Show at confirmation prompt, hide at final update
if (fCurrentState == STATE_GET_CONFIRMATION) {
fPackagesLayoutItem->SetVisible(true);
// Re-enable resizing
SetSizeLimits(fDefaultRect.Width(), 9999,
fDefaultRect.Height() + fListView->MinSize().Height() + 30, 9999);
ResizeTo(Bounds().Width(), 400);
}
// Progress bar and string view
// Hide detail text while showing status bar
if (fCurrentState == STATE_DISPLAY_PROGRESS) {
fDetailsLayoutItem->SetVisible(false);
fProgressLayoutItem->SetVisible(true);
}
else {
fProgressLayoutItem->SetVisible(false);
fDetailsLayoutItem->SetVisible(true);
}
// Cancel button
fCancelButton->SetEnabled(fCurrentState != STATE_APPLY_UPDATES);
Unlock();
}
for (int i = 0; i < repoNames.CountStrings(); i++) {
const BString& repoName = repoNames.StringAt(i);
BRepositoryConfig repoConfig;
result = roster.GetRepositoryConfig(repoName, &repoConfig);
if (result != B_OK) {
printf("Skipping '%s' repo due to unknown config\n",
repoName.String());
continue;
}
/*
BRefreshRepositoryRequest request(context, repoConfig);
result = request.Process();
if (result != B_OK) {
printf("Skipping %s repo due to unreachable repo");
continue;
}
*/
uint32
SoftwareUpdaterWindow::_GetState()
{
return fCurrentState;
}
SuperItem::SuperItem(const char* label)
:
BListItem(),
fLabel(label),
fPackageIcon(NULL)
{
}
SuperItem::~SuperItem()
{
delete fPackageIcon;
}
void
SuperItem::DrawItem(BView* owner, BRect item_rect, bool complete)
{
float width;
owner->GetPreferredSize(&width, NULL);
BString label(fLabel);
owner->TruncateString(&label, B_TRUNCATE_END, width);
owner->SetFont(&fBoldFont);
owner->DrawString(label.String(), BPoint(item_rect.left,
item_rect.bottom - fFontHeight.descent - 1));
owner->SetFont(&fRegularFont);
}
void
SuperItem::Update(BView *owner, const BFont *font)
{
fRegularFont = *font;
fBoldFont = *font;
fBoldFont.SetFace(B_BOLD_FACE);
BListItem::Update(owner, &fBoldFont);
// Calculate height for PackageItem
fRegularFont.GetHeight(&fFontHeight);
fPackageItemHeight = 2 * (fFontHeight.ascent + fFontHeight.descent
+ fFontHeight.leading);
// Calculate height for this item
fBoldFont.GetHeight(&fFontHeight);
SetHeight(fFontHeight.ascent + fFontHeight.descent
+ fFontHeight.leading + 4);
_GetPackageIcon();
}
void
SuperItem::_GetPackageIcon()
{
delete fPackageIcon;
fIconSize = int(fPackageItemHeight * .7);
status_t result = B_ERROR;
BRect iconRect(0, 0, fIconSize - 1, fIconSize - 1);
fPackageIcon = new BBitmap(iconRect, 0, B_RGBA32);
BMimeType nodeType;
nodeType.SetTo("application/x-vnd.haiku-package");
result = nodeType.GetIcon(fPackageIcon, icon_size(fIconSize));
// Get super type icon
if (result != B_OK) {
BMimeType superType;
if (nodeType.GetSupertype(&superType) == B_OK)
result = superType.GetIcon(fPackageIcon, icon_size(fIconSize));
}
if (result != B_OK) {
delete fPackageIcon;
fPackageIcon = NULL;
}
}
PackageItem::PackageItem(const char* name, const char* version,
const char* summary, const char* tooltip, SuperItem* super)
:
BListItem(),
fName(name),
fVersion(version),
fSummary(summary),
fTooltip(tooltip),
fSuperItem(super)
{
fLabelOffset = be_control_look->DefaultLabelSpacing();
// SetToolTip(fTooltip);
}
void
PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete)
{
float width;
owner->GetPreferredSize(&width, NULL);
float nameWidth = width / 2.0;
float offset_width = 0;
BBitmap* icon = fSuperItem->GetIcon();
if (icon != NULL && icon->IsValid()) {
int16 iconSize = fSuperItem->GetIconSize();
float offsetMarginHeight = floor((Height() - iconSize) / 2);
//owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
owner->SetDrawingMode(B_OP_ALPHA);
owner->DrawBitmap(icon, BPoint(item_rect.left,
item_rect.top + offsetMarginHeight));
owner->SetDrawingMode(B_OP_COPY);
offset_width += iconSize + fLabelOffset;
}
// Package name
font_height fontHeight = fSuperItem->GetFontHeight();
BString name(fName);
owner->TruncateString(&name, B_TRUNCATE_END, nameWidth);
BPoint cursor(item_rect.left + offset_width,
item_rect.bottom - fSmallTotalHeight - fontHeight.descent - 1);
owner->DrawString(name.String(), cursor);
cursor.x += owner->StringWidth(name.String()) + fLabelOffset;
// Change font and color
owner->SetFont(&fSmallFont);
owner->SetHighColor(tint_color(ui_color(B_LIST_ITEM_TEXT_COLOR), 0.7));
// Version
BString version(fVersion);
owner->TruncateString(&version, B_TRUNCATE_END, width - cursor.x);
owner->DrawString(version.String(), cursor);
// Summary
BString summary(fSummary);
cursor.x = item_rect.left + offset_width;
cursor.y = item_rect.bottom - fontHeight.descent;
owner->TruncateString(&summary, B_TRUNCATE_END, width - cursor.x);
owner->DrawString(summary.String(), cursor);
owner->SetFont(&fRegularFont);
}
void
PackageItem::Update(BView *owner, const BFont *font)
{
BListItem::Update(owner, font);
SetItemHeight(font);
}
void
PackageItem::SetItemHeight(const BFont* font)
{
SetHeight(fSuperItem->GetPackageItemHeight());
fRegularFont = *font;
fSmallFont = *font;
fSmallFont.SetSize(font->Size() - 2);
fSmallFont.GetHeight(&fSmallFontHeight);
fSmallTotalHeight = fSmallFontHeight.ascent + fSmallFontHeight.descent
+ fSmallFontHeight.leading;
}
int
PackageItem::ICompare(PackageItem* item)
{
// sort by package name
return fName.ICompare(item->fName);
}
int
SortPackageItems(const BListItem* item1, const BListItem* item2)
{
PackageItem* first = (PackageItem*)item1;
PackageItem* second = (PackageItem*)item2;
return first->ICompare(second);
}
PackageListView::PackageListView()
:
BOutlineListView("Package list"),
fSuperUpdateItem(NULL),
fSuperInstallItem(NULL),
fSuperUninstallItem(NULL)
{
SetExplicitMinSize(BSize(B_SIZE_UNSET, 40));
SetExplicitPreferredSize(BSize(B_SIZE_UNSET, 400));
}
void
PackageListView::FrameResized(float newWidth, float newHeight)
{
BListView::FrameResized(newWidth, newHeight);
float count = CountItems();
for (int32 i = 0; i < count; i++) {
BListItem *item = ItemAt(i);
item->Update(this, be_plain_font);
}
Invalidate();
}
void
PackageListView::AddPackage(uint32 install_type, const char* name,
const char* cur_ver, const char* new_ver, const char* summary,
const char* repository)
{
SuperItem* super;
BString version;
BString tooltip;
switch (install_type) {
case PACKAGE_UPDATE:
{
if (fSuperUpdateItem == NULL) {
fSuperUpdateItem = new SuperItem(
B_TRANSLATE("Packages to be updated"));
AddItem(fSuperUpdateItem);
}
super = fSuperUpdateItem;
version.SetTo(new_ver);
tooltip.SetTo(B_TRANSLATE("Repository:"));
tooltip.Append(" ").Append(repository)
.Append("\n").Append(B_TRANSLATE("Update version"))
.Append(" ").Append(cur_ver)
.Append(" ").Append(B_TRANSLATE("to"))
.Append(" ").Append(new_ver);
break;
}
case PACKAGE_INSTALL:
{
if (fSuperInstallItem == NULL) {
fSuperInstallItem = new SuperItem(
B_TRANSLATE("New packages to be installed"));
AddItem(fSuperInstallItem);
}
super = fSuperInstallItem;
version.SetTo(new_ver);
tooltip.SetTo(B_TRANSLATE("Repository:"));
tooltip.Append(" ").Append(repository)
.Append("\n").Append(B_TRANSLATE("Install version"))
.Append(" ").Append(new_ver);
break;
}
case PACKAGE_UNINSTALL:
{
if (fSuperUninstallItem == NULL) {
fSuperUninstallItem = new SuperItem(
B_TRANSLATE("Packages to be uninstalled"));
AddItem(fSuperUninstallItem);
}
super = fSuperUninstallItem;
version.SetTo("");
tooltip.SetTo(B_TRANSLATE("Repository:"));
tooltip.Append(" ").Append(repository)
.Append("\n").Append(B_TRANSLATE("Uninstall version"))
.Append(" ").Append(new_ver);
break;
}
default:
return;
}
PackageItem* item = new PackageItem(name, version.String(), summary,
tooltip.String(), super);
AddUnder(item, super);
}
void
PackageListView::SortItems()
{
if (fSuperUpdateItem != NULL)
SortItemsUnder(fSuperUpdateItem, true, SortPackageItems);
}
/*
BSize
PackageListView::PreferredSize()
{
return BSize(B_SIZE_UNSET, 200);
}*/
/*
void
PackageListView::GetPreferredSize(float* _width, float* _height)
{
// TODO: Something more nice as default? I need to see how this looks
// when there are actually any packages...
if (_width != NULL)
*_width = 400.0;
if (_height != NULL)
*_height = 200.0;
}*/
/*
BSize
PackageListView::MaxSize()
{
return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
}
*/
FinalWindow::FinalWindow(BRect rect, BPoint location, const char* header,
const char* detail)
:
BWindow(rect,
B_TRANSLATE_SYSTEM_NAME("SoftwareUpdater"), B_TITLED_WINDOW,
B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE
| B_NOT_CLOSABLE | B_NOT_RESIZABLE),
fHeaderView(NULL),
fDetailView(NULL),
fCancelButton(NULL)
{
fIcon = new BBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32);
team_info teamInfo;
get_team_info(B_CURRENT_TEAM, &teamInfo);
app_info appInfo;
be_roster->GetRunningAppInfo(teamInfo.team, &appInfo);
BNodeInfo::GetTrackerIcon(&appInfo.ref, fIcon, B_LARGE_ICON);
SetSizeLimits(rect.Width(), B_SIZE_UNLIMITED, 0, B_SIZE_UNLIMITED);
fStripeView = new StripeView(fIcon);
fHeaderView = new BStringView("header", header, B_WILL_DRAW);
fHeaderView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fHeaderView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
fDetailView = new BStringView("detail", detail, B_WILL_DRAW);
fDetailView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fDetailView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
fCancelButton = new BButton(B_TRANSLATE("Quit"),
new BMessage(kMsgCancel));
fCancelButton->MakeDefault(true);
BFont font;
fHeaderView->GetFont(&font);
font.SetFace(B_BOLD_FACE);
font.SetSize(font.Size() * 1.5);
fHeaderView->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE
| B_FONT_FLAGS);
BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0)
.Add(fStripeView)
.AddGroup(B_VERTICAL, 0)
.SetInsets(0, B_USE_WINDOW_SPACING,
B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING)
.AddGroup(B_VERTICAL, B_USE_ITEM_SPACING)
.Add(fHeaderView)
.Add(fDetailView)
.AddGroup(B_HORIZONTAL)
.AddGlue()
.Add(fCancelButton)
.End()
.End()
.End()
.End();
MoveTo(location);
Show();
}
FinalWindow::~FinalWindow()
{
delete fIcon;
}
void
FinalWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgCancel:
PostMessage(B_QUIT_REQUESTED);
be_app->PostMessage(kMsgFinalQuit);
break;
default:
BWindow::MessageReceived(message);
}
}

View File

@ -1,44 +1,181 @@
/*
* Copyright 2016 Haiku, Inc. All rights reserved.
* Copyright 2016-2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license
*
* Authors:
* Alexander von Gluck IV <kallisti5@unixzen.com>
* Brian Hill <supernova@warpmail.net>
*/
#ifndef _SOFTWARE_UPDATER_WINDOW_H
#define _SOFTWARE_UPDATER_WINDOW_H
#include <Button.h>
#include <Roster.h>
#include <GroupView.h>
#include <OutlineListView.h>
#include <Point.h>
#include <ScrollView.h>
#include <StatusBar.h>
#include <StringView.h>
#include <Window.h>
#include "StripeView.h"
#include "UpdateManager.h"
using namespace BPrivate;
enum {
PACKAGE_UPDATE,
PACKAGE_INSTALL,
PACKAGE_UNINSTALL
};
class SuperItem : public BListItem {
public:
SuperItem(const char* label);
~SuperItem();
virtual void DrawItem(BView*, BRect, bool);
virtual void Update(BView *owner, const BFont *font);
font_height GetFontHeight() { return fFontHeight; };
float GetPackageItemHeight()
{ return fPackageItemHeight; };
BBitmap* GetIcon() { return fPackageIcon; };
int16 GetIconSize() { return fIconSize; };
private:
void _GetPackageIcon();
BString fLabel;
BFont fRegularFont;
BFont fBoldFont;
font_height fFontHeight;
float fPackageItemHeight;
BBitmap* fPackageIcon;
int16 fIconSize;
};
class PackageItem : public BListItem {
public:
PackageItem(const char* name,
const char* version,
const char* summary,
const char* tooltip,
SuperItem* super);
virtual void DrawItem(BView*, BRect, bool);
virtual void Update(BView *owner, const BFont *font);
void SetItemHeight(const BFont* font);
int ICompare(PackageItem* item);
private:
BString fName;
BString fVersion;
BString fSummary;
BString fTooltip;
BFont fRegularFont;
BFont fSmallFont;
font_height fSmallFontHeight;
float fSmallTotalHeight;
float fLabelOffset;
SuperItem* fSuperItem;
};
class PackageListView : public BOutlineListView {
public:
PackageListView();
virtual void FrameResized(float newWidth, float newHeight);
// virtual BSize PreferredSize();
// virtual void GetPreferredSize(float* _width, float* _height);
// virtual BSize MaxSize();
void AddPackage(uint32 install_type,
const char* name,
const char* cur_ver,
const char* new_ver,
const char* summary,
const char* repository);
void SortItems();
private:
SuperItem* fSuperUpdateItem;
SuperItem* fSuperInstallItem;
SuperItem* fSuperUninstallItem;
};
class SoftwareUpdaterWindow : public BWindow {
public:
SoftwareUpdaterWindow();
~SoftwareUpdaterWindow();
bool QuitRequested();
void MessageReceived(BMessage* message);
bool ConfirmUpdates(const char* text);
void UpdatesApplying(const char* header,
const char* detail);
bool UserCancelRequested();
void AddPackageInfo(uint32 install_type,
const char* package_name,
const char* cur_ver,
const char* new_ver,
const char* summary,
const char* repository);
const BBitmap* GetIcon() { return fIcon; };
BRect GetDefaultRect() { return fDefaultRect; };
BPoint GetLocation() { return Frame().LeftTop(); };
BLayoutItem* layout_item_for(BView* view);
private:
void _Error(const char* error);
void _Refresh();
UpdateManager* fUpdateManager;
uint32 _WaitForButtonClick();
void _SetState(uint32 state);
uint32 _GetState();
BRect fDefaultRect;
StripeView* fStripeView;
app_info* fAppInfo;
BStringView* fHeaderView;
BStringView* fDetailView;
BButton* fUpdateButton;
BButton* fCancelButton;
BStatusBar* fStatusBar;
#if USE_PANE_SWITCH
PaneSwitch* fPackagesSwitch;
BLayoutItem* fPkgSwitchLayoutItem;
#endif
PackageListView* fListView;
BScrollView* fScrollView;
BLayoutItem* fDetailsLayoutItem;
BLayoutItem* fPackagesLayoutItem;
BLayoutItem* fProgressLayoutItem;
BLayoutItem* fUpdateButtonLayoutItem;
BBitmap* fIcon;
uint32 fCurrentState;
sem_id fWaitingSem;
bool fWaitingForButton;
uint32 fButtonResult;
bool fUserCancelRequested;
BInvoker fCancelAlertResponse;
};
#endif
int SortPackageItems(const BListItem* item1, const BListItem* item2);
class FinalWindow : public BWindow {
public:
FinalWindow(BRect rect, BPoint location,
const char* header, const char* detail);
~FinalWindow();
void MessageReceived(BMessage* message);
private:
StripeView* fStripeView;
BStringView* fHeaderView;
BStringView* fDetailView;
BButton* fCancelButton;
BBitmap* fIcon;
};
#endif // _SOFTWARE_UPDATER_WINDOW_H

View File

@ -26,7 +26,7 @@ StripeView::StripeView(BBitmap* icon)
if (icon != NULL)
width += icon->Bounds().Width() + 32.0f;
SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
SetExplicitSize(BSize(width, B_SIZE_UNSET));
SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED));
}
@ -68,6 +68,6 @@ StripeView::SetIcon(BBitmap* icon)
if (icon != NULL)
width += icon->Bounds().Width() + 32.0f;
SetExplicitMinSize(BSize(width, B_SIZE_UNSET));
SetExplicitSize(BSize(width, B_SIZE_UNSET));
SetExplicitPreferredSize(BSize(width, B_SIZE_UNLIMITED));
}

View File

@ -0,0 +1,96 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <supernova@warpmail.net>
*/
#include "UpdateAction.h"
#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <package/manager/Exceptions.h>
#include "constants.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "UpdateAction"
using namespace BPackageKit;
//using namespace BPackageKit::BPrivate;
using namespace BPackageKit::BManager::BPrivate;
UpdateAction::UpdateAction()
{
fUpdateManager = new(std::nothrow)
UpdateManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
}
UpdateAction::~UpdateAction()
{
delete fUpdateManager;
}
status_t
UpdateAction::Perform()
{
fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES
| BPackageManager::B_REFRESH_REPOSITORIES);
try {
// These values indicate that all updates should be installed
int packageCount = 0;
const char* const packages = "";
// perform the update
// fUpdateManager->SetDebugLevel(1);
fUpdateManager->Update(&packages, packageCount);
} catch (BFatalErrorException ex) {
BString errorString;
errorString.SetToFormat(
"Fatal error occurred while updating packages: "
"%s (%s)\n", ex.Message().String(),
ex.Details().String());
BAlert* alert(new(std::nothrow) BAlert(B_TRANSLATE("Fatal error"),
errorString, B_TRANSLATE("Close"), NULL, NULL,
B_WIDTH_AS_USUAL, B_STOP_ALERT));
if (alert != NULL)
alert->Go();
fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"),
ex.Message());
return ex.Error();
} catch (BAbortedByUserException ex) {
fprintf(stderr, "Updates aborted by user: %s\n",
ex.Message().String());
// No need for a final message since user initiated cancel request
// Note: activate FinalUpdate() call for testing final message window
//fUpdateManager->FinalUpdate(B_TRANSLATE("Updates cancelled"),
// B_TRANSLATE("No packages have been updated."));
// Note: comment out when testing final message window
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BNothingToDoException ex) {
fprintf(stderr, "Nothing to do while updating packages : %s\n",
ex.Message().String());
fUpdateManager->FinalUpdate(B_TRANSLATE("No updates available"),
B_TRANSLATE("There were no updates found."));
return B_OK;
} catch (BException ex) {
fprintf(stderr, "Exception occurred while updating packages : %s\n",
ex.Message().String());
fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"),
ex.Message());
return B_ERROR;
}
return B_OK;
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <supernova@warpmail.net>
*/
#ifndef UPDATE_ACTION_H
#define UPDATE_ACTION_H
#include "UpdateManager.h"
class UpdateAction {
public:
UpdateAction();
~UpdateAction();
status_t Perform();
private:
UpdateManager* fUpdateManager;
};
#endif // UPDATE_ACTION_H

View File

@ -1,11 +1,12 @@
/*
* Copyright 2013-2015, Haiku, Inc. All Rights Reserved.
* Copyright 2013-2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler <axeld@pinc-software.de>
* Rene Gollent <rene@gollent.com>
* Ingo Weinhold <ingo_weinhold@gmx.de>
* Brian Hill <supernova@warpmail.net>
*/
@ -14,28 +15,53 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <Alert.h>
#include <Catalog.h>
#include <Notification.h>
#include <package/CommitTransactionResult.h>
#include <package/DownloadFileRequest.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/manager/Exceptions.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include "constants.h"
#include "AutoDeleter.h"
#include "ProblemWindow.h"
#include "ResultWindow.h"
using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate;
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "UpdateManager"
UpdateManager::UpdateManager(BPackageInstallationLocation location)
:
BPackageManager(location, &fClientInstallationInterface, this),
BPackageManager::UserInteractionHandler(),
fClientInstallationInterface()
fClientInstallationInterface(),
fStatusWindow(NULL),
fFinalWindow(NULL),
fCurrentStep(ACTION_STEP_INIT),
fChangesConfirmed(false)
{
fStatusWindow = new SoftwareUpdaterWindow();
_SetCurrentStep(ACTION_STEP_START);
}
UpdateManager::~UpdateManager()
{
if (fStatusWindow != NULL)
fStatusWindow->PostMessage(B_QUIT_REQUESTED);
if (fFinalWindow != NULL)
fFinalWindow->PostMessage(B_QUIT_REQUESTED);
if (fProblemWindow != NULL)
fProblemWindow->PostMessage(B_QUIT_REQUESTED);
}
@ -54,13 +80,29 @@ void
UpdateManager::JobAborted(BSupportKit::BJob* job)
{
//DIE(job->Result(), "aborted");
printf("Job aborted\n");
}
void
UpdateManager::FinalUpdate(const char* header, const char* text)
{
_FinalUpdate(header, text);
}
void
UpdateManager::HandleProblems()
{
int32 problemCount = fSolver->CountProblems();
if (fProblemWindow == NULL)
fProblemWindow = new ProblemWindow;
ProblemWindow::SolverPackageSet installPackages;
ProblemWindow::SolverPackageSet uninstallPackages;
if (!fProblemWindow->Go(fSolver,installPackages, uninstallPackages))
throw BAbortedByUserException();
/* int32 problemCount = fSolver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
// print problem and possible solutions
BSolverProblem* problem = fSolver->ProblemAt(i);
@ -96,7 +138,7 @@ UpdateManager::HandleProblems()
if (strcmp(buffer, "s\n") == 0)
break;
/*
char* end;
long selected = strtol(buffer, &end, 0);
if (end == buffer || *end != '\n' || selected < 1
@ -109,10 +151,10 @@ UpdateManager::HandleProblems()
problem->SolutionAt(selected - 1));
if (error != B_OK)
DIE(error, "failed to set solution");
*/
break;
}
}
}*/
}
@ -122,20 +164,55 @@ UpdateManager::ConfirmChanges(bool fromMostSpecific)
printf("The following changes will be made:\n");
int32 count = fInstalledRepositories.CountItems();
int32 upgradeCount = 0;
int32 installCount = 0;
int32 uninstallCount = 0;
if (fromMostSpecific) {
for (int32 i = count - 1; i >= 0; i--)
_PrintResult(*fInstalledRepositories.ItemAt(i));
_PrintResult(*fInstalledRepositories.ItemAt(i), upgradeCount,
installCount, uninstallCount);
} else {
for (int32 i = 0; i < count; i++)
_PrintResult(*fInstalledRepositories.ItemAt(i));
_PrintResult(*fInstalledRepositories.ItemAt(i), upgradeCount,
installCount, uninstallCount);
}
/*
if (!fDecisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "yes",
"no", "yes")) {
//exit(1);
printf("Upgrade count=%" B_PRId32 ", Install count=%" B_PRId32
", Uninstall count=%" B_PRId32 "\n",
upgradeCount, installCount, uninstallCount);
BString text;
if (upgradeCount == 1)
text.SetTo(B_TRANSLATE_COMMENT("There is 1 update "
"%dependancies%available.",
"Do not translate %dependancies%"));
else
text.SetTo(B_TRANSLATE_COMMENT("There are %count% updates "
"%dependancies%available.",
"Do not translate %count% or %dependancies%"));
BString countString;
countString << upgradeCount;
text.ReplaceFirst("%count%", countString);
BString dependancies("");
if (installCount) {
dependancies.SetTo("(");
dependancies.Append(B_TRANSLATE("with")).Append(" ");
if (installCount == 1)
dependancies.Append(B_TRANSLATE("1 new dependancy"));
else {
dependancies << installCount;
dependancies.Append(" ").Append(B_TRANSLATE("new dependancies"));
}
dependancies.Append(") ");
}
*/
text.ReplaceFirst("%dependancies%", dependancies);
fChangesConfirmed = fStatusWindow->ConfirmUpdates(text.String());
if (!fChangesConfirmed)
throw BAbortedByUserException();
_SetCurrentStep(ACTION_STEP_DOWNLOAD);
fPackageDownloadsTotal = upgradeCount + installCount;
fPackageDownloadsCount = 1;
}
@ -157,6 +234,18 @@ UpdateManager::Warn(status_t error, const char* format, ...)
void
UpdateManager::ProgressPackageDownloadStarted(const char* packageName)
{
if (fCurrentStep == ACTION_STEP_DOWNLOAD) {
BString header(B_TRANSLATE("Downloading packages"));
BString packageCount;
packageCount.SetToFormat(
B_TRANSLATE_COMMENT("%i of %i", "Do not translate %i"),
fPackageDownloadsCount,
fPackageDownloadsTotal);
_UpdateDownloadProgress(header.String(), packageName, packageCount,
0.0);
fNewDownloadStarted = false;
}
printf("Downloading %s...\n", packageName);
}
@ -165,10 +254,23 @@ void
UpdateManager::ProgressPackageDownloadActive(const char* packageName,
float completionPercentage, off_t bytes, off_t totalBytes)
{
return;
/*
if (!fInteractive)
return;
if (fCurrentStep == ACTION_STEP_DOWNLOAD) {
// Fix a bug where a 100% completion percentage gets sent at the start
// of a package download
if (!fNewDownloadStarted) {
if (completionPercentage > 0 && completionPercentage < 1)
fNewDownloadStarted = true;
else
completionPercentage = 0.0;
}
BString packageCount;
packageCount.SetToFormat(
B_TRANSLATE_COMMENT("%i of %i", "Do not translate %i"),
fPackageDownloadsCount,
fPackageDownloadsTotal);
_UpdateDownloadProgress(NULL, packageName, packageCount,
completionPercentage);
}
static const char* progressChars[] = {
"\xE2\x96\x8F",
@ -213,13 +315,16 @@ UpdateManager::ProgressPackageDownloadActive(const char* packageName,
printf(" %3d%%", (int)(completionPercentage * 100));
fflush(stdout);
*/
}
void
UpdateManager::ProgressPackageDownloadComplete(const char* packageName)
{
if (fCurrentStep == ACTION_STEP_DOWNLOAD)
fPackageDownloadsCount++;
// Overwrite the progress bar with whitespace
printf("\r");
struct winsize w;
@ -235,6 +340,10 @@ UpdateManager::ProgressPackageDownloadComplete(const char* packageName)
void
UpdateManager::ProgressPackageChecksumStarted(const char* title)
{
// Repository checksums
if (fCurrentStep == ACTION_STEP_START)
_UpdateStatusWindow(NULL, title);
printf("%s...", title);
}
@ -249,6 +358,11 @@ UpdateManager::ProgressPackageChecksumComplete(const char* title)
void
UpdateManager::ProgressStartApplyingChanges(InstalledRepository& repository)
{
_SetCurrentStep(ACTION_STEP_APPLY);
BString header(B_TRANSLATE("Applying changes"));
BString detail(B_TRANSLATE("Packages are being updated"));
fStatusWindow->UpdatesApplying(header.String(), detail.String());
printf("[%s] Applying changes ...\n", repository.Name().String());
}
@ -257,6 +371,12 @@ void
UpdateManager::ProgressTransactionCommitted(InstalledRepository& repository,
const BCommitTransactionResult& result)
{
_SetCurrentStep(ACTION_STEP_COMPLETE);
BString header(B_TRANSLATE("Updates completed"));
BString detail(B_TRANSLATE("A reboot may be necessary to complete some "
"updates."));
_FinalUpdate(header.String(), detail.String());
const char* repositoryName = repository.Name().String();
int32 issueCount = result.CountIssues();
@ -285,7 +405,8 @@ UpdateManager::ProgressApplyingChangesDone(InstalledRepository& repository)
void
UpdateManager::_PrintResult(InstalledRepository& installationRepository)
UpdateManager::_PrintResult(InstalledRepository& installationRepository,
int32& upgradeCount, int32& installCount, int32& uninstallCount)
{
if (!installationRepository.HasChanges())
return;
@ -319,7 +440,8 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository)
if (dynamic_cast<MiscLocalRepository*>(package->Repository()) != NULL)
repository = "local file";
else
repository.SetToFormat("repository %s", package->Repository()->Name().String());
repository.SetToFormat("repository %s",
package->Repository()->Name().String());
int position = upgradedPackages.IndexOf(package->Info().Name());
if (position >= 0) {
@ -328,18 +450,106 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository)
upgradedPackageVersions.StringAt(position).String(),
package->Info().Version().ToString().String(),
repository.String());
fStatusWindow->AddPackageInfo(PACKAGE_UPDATE,
package->Info().Name().String(),
upgradedPackageVersions.StringAt(position).String(),
package->Info().Version().ToString().String(),
package->Info().Summary().String(),
package->Repository()->Name().String());
upgradeCount++;
} else {
printf(" install package %s-%s from %s\n",
package->Info().Name().String(),
package->Info().Version().ToString().String(),
repository.String());
fStatusWindow->AddPackageInfo(PACKAGE_INSTALL,
package->Info().Name().String(),
NULL,
package->Info().Version().ToString().String(),
package->Info().Summary().String(),
package->Repository()->Name().String());
installCount++;
}
}
BStringList uninstallList;
for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
i++) {
if (upgradedPackages.HasString(package->Info().Name()))
continue;
printf(" uninstall package %s\n", package->VersionedName().String());
fStatusWindow->AddPackageInfo(PACKAGE_UNINSTALL,
package->Info().Name().String(),
package->Info().Version().ToString(),
NULL,
package->Info().Summary().String(),
package->Repository()->Name().String());
uninstallCount++;
}
}
void
UpdateManager::_UpdateStatusWindow(const char* header, const char* detail)
{
if (header == NULL && detail == NULL)
return;
if (fStatusWindow->UserCancelRequested())
throw BAbortedByUserException();
BMessage message(kMsgTextUpdate);
if (header != NULL)
message.AddString(kKeyHeader, header);
if (detail != NULL)
message.AddString(kKeyDetail, detail);
fStatusWindow->PostMessage(&message);
}
void
UpdateManager::_UpdateDownloadProgress(const char* header,
const char* packageName, const char* packageCount,
float completionPercentage)
{
if (packageName == NULL || packageCount == NULL)
return;
if (fStatusWindow->UserCancelRequested())
throw BAbortedByUserException();
BMessage message(kMsgProgressUpdate);
if (header != NULL)
message.AddString(kKeyHeader, header);
message.AddString(kKeyPackageName, packageName);
message.AddString(kKeyPackageCount, packageCount);
message.AddFloat(kKeyPercentage, completionPercentage);
fStatusWindow->PostMessage(&message);
}
void
UpdateManager::_FinalUpdate(const char* header, const char* text)
{
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup("SoftwareUpdater");
notification.SetTitle(header);
notification.SetContent(text);
const BBitmap* icon = fStatusWindow->GetIcon();
if (icon != NULL)
notification.SetIcon(icon);
notification.Send();
BPoint location(fStatusWindow->GetLocation());
BRect rect(fStatusWindow->GetDefaultRect());
fStatusWindow->PostMessage(B_QUIT_REQUESTED);
fStatusWindow = NULL;
fFinalWindow = new FinalWindow(rect, location, header, text);
}
void
UpdateManager::_SetCurrentStep(int32 step)
{
fCurrentStep = step;
}

View File

@ -1,10 +1,11 @@
/*
* Copyright 2013-2015, Haiku, Inc. All Rights Reserved.
* Copyright 2013-2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
* Rene Gollent <rene@gollent.com>
* Brian Hill <supernova@warpmail.net>
*/
#ifndef UPDATE_MANAGER_H
#define UPDATE_MANAGER_H
@ -13,6 +14,9 @@
#include <package/DaemonClient.h>
#include <package/manager/PackageManager.h>
#include "SoftwareUpdaterWindow.h"
class ProblemWindow;
//using namespace BPackageKit;
using BPackageKit::BPrivate::BDaemonClient;
@ -28,7 +32,9 @@ public:
virtual void JobFailed(BSupportKit::BJob* job);
virtual void JobAborted(BSupportKit::BJob* job);
void FinalUpdate(const char* header,
const char* text);
private:
// UserInteractionHandler
virtual void HandleProblems();
@ -60,11 +66,32 @@ private:
private:
void _PrintResult(InstalledRepository&
installationRepository);
installationRepository,
int32& upgradeCount,
int32& installCount,
int32& uninstallCount);
void _UpdateStatusWindow(const char* header,
const char* detail);
void _UpdateDownloadProgress(const char* header,
const char* packageName,
const char* packageCount,
float completionPercentage);
void _FinalUpdate(const char* header,
const char* text);
void _SetCurrentStep(int32 step);
private:
BPackageManager::ClientInstallationInterface
fClientInstallationInterface;
SoftwareUpdaterWindow* fStatusWindow;
FinalWindow* fFinalWindow;
ProblemWindow* fProblemWindow;
uint32 fCurrentStep;
bool fChangesConfirmed;
bool fNewDownloadStarted;
int32 fPackageDownloadsTotal;
int32 fPackageDownloadsCount;
};

View File

@ -0,0 +1,35 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <supernova@warpmail.net>
*/
#include "WorkingLooper.h"
WorkingLooper::WorkingLooper()
:
BLooper("WorkingLooper")
{
Run();
PostMessage(kMsgStart);
}
void
WorkingLooper::MessageReceived(BMessage* message)
{
switch (message->what) {
case kMsgStart:
{
fAction.Perform();
break;
}
default:
BLooper::MessageReceived(message);
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <supernova@warpmail.net>
*/
#ifndef _WORKING_LOOPER_H
#define _WORKING_LOOPER_H
#include <Looper.h>
#include <Message.h>
#include "UpdateAction.h"
const uint32 kMsgStart = 'iSTA';
class WorkingLooper : public BLooper {
public:
WorkingLooper();
void MessageReceived(BMessage* message);
private:
UpdateAction fAction;
};
#endif // _WORKING_LOOPER_H

View File

@ -0,0 +1,51 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <supernova@warpmail.net>
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
enum {
ACTION_STEP_INIT = 0,
ACTION_STEP_START,
ACTION_STEP_DOWNLOAD,
ACTION_STEP_APPLY,
ACTION_STEP_COMPLETE,
ACTION_STEP_MAX
};
enum {
STATE_HEAD = 0,
STATE_DISPLAY_STATUS,
STATE_DISPLAY_PROGRESS,
STATE_GET_CONFIRMATION,
STATE_APPLY_UPDATES,
STATE_MAX
};
// Message what values
static const uint32 kMsgTextUpdate = 'iUPD';
static const uint32 kMsgProgressUpdate = 'iPRO';
static const uint32 kMsgCancel = 'iCAN';
static const uint32 kMsgCancelResponse = 'iCRE';
static const uint32 kMsgUpdateConfirmed = 'iCON';
static const uint32 kMsgClose = 'iCLO';
static const uint32 kMsgShow = 'iSHO';
static const uint32 kMsgShowInfo = 'iSHI';
static const uint32 kMsgRegister = 'iREG';
static const uint32 kMsgFinalQuit = 'iFIN';
// Message data keys
#define kKeyHeader "key_header"
#define kKeyDetail "key_detail"
#define kKeyPackageName "key_packagename"
#define kKeyPackageCount "key_packagecount"
#define kKeyPercentage "key_percentage"
#define kKeyFrame "key_frame"
#define kKeyMessenger "key_messenger"
#endif // CONSTANTS_H