SoftwareUpdater updates

*Added a check-only option to check for updates and display a
  notification when updates are available.
*Added argv commands to specify an action when using Terminal or
  BRoster to launch app: commands [update | check | full-sync]
*Draw a download progress bar on the package icon
*Increased the size of the package icon to improve the bar look
*Added package counts to each list category
This commit is contained in:
Brian Hill
2017-04-20 18:08:51 -04:00
parent 0fb349bc5d
commit 73c2c7b4b5
16 changed files with 761 additions and 81 deletions
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <[email protected]>
*/
#include "CheckAction.h"
#include <Application.h>
#include <Catalog.h>
#include <package/manager/Exceptions.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "CheckAction"
using namespace BPackageKit;
//using namespace BPackageKit::BPrivate;
using namespace BPackageKit::BManager::BPrivate;
CheckAction::CheckAction()
{
fCheckManager = new(std::nothrow)
CheckManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
}
CheckAction::~CheckAction()
{
delete fCheckManager;
}
status_t
CheckAction::Perform()
{
try {
fCheckManager->CheckNetworkConnection();
fCheckManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES
| BPackageManager::B_REFRESH_REPOSITORIES);
// fUpdateManager->SetDebugLevel(1);
// These values indicate that all updates should be installed
int packageCount = 0;
const char* const packages = "";
fCheckManager->Update(&packages, packageCount);
} catch (BFatalErrorException ex) {
fprintf(stderr, B_TRANSLATE(
"Fatal error while checking for updates: %s\n"),
ex.Message().String());
be_app->PostMessage(kMsgFinalQuit);
return ex.Error();
} catch (BAbortedByUserException ex) {
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BNothingToDoException ex) {
fprintf(stdout, B_TRANSLATE("There were no updates found."));
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BException ex) {
fprintf(stderr, B_TRANSLATE(
"Exception occurred while checking for updates: %s\n"),
ex.Message().String());
be_app->PostMessage(kMsgFinalQuit);
return B_ERROR;
}
return B_OK;
}
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright 2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Brian Hill <[email protected]>
*/
#ifndef CHECK_ACTION_H
#define CHECK_ACTION_H
#include "CheckManager.h"
class CheckAction {
public:
CheckAction();
~CheckAction();
status_t Perform();
private:
CheckManager* fCheckManager;
};
#endif // CHECK_ACTION_H
+297
View File
@@ -0,0 +1,297 @@
/*
* Copyright 2013-2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler <[email protected]>
* Rene Gollent <[email protected]>
* Ingo Weinhold <[email protected]>
* Brian Hill <[email protected]>
*/
#include "CheckManager.h"
#include <sys/ioctl.h>
#include <unistd.h>
#include <Catalog.h>
#include <Message.h>
#include <Messenger.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include <NodeInfo.h>
#include <Notification.h>
#include <Roster.h>
#include <package/manager/Exceptions.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include "constants.h"
using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate;
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "CheckManager"
CheckManager::CheckManager(BPackageInstallationLocation location)
:
BPackageManager(location, &fClientInstallationInterface, this),
BPackageManager::UserInteractionHandler(),
fClientInstallationInterface()
{
}
void
CheckManager::CheckNetworkConnection()
{
BNetworkRoster& roster = BNetworkRoster::Default();
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
uint32 flags = interface.Flags();
if ((flags & IFF_LOOPBACK) == 0
&& (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) {
return;
}
}
// No network connection detected, cannot continue
fprintf(stderr, B_TRANSLATE("No active network connection was found.\n"));
throw BAbortedByUserException();
}
void
CheckManager::JobFailed(BSupportKit::BJob* job)
{
BString error = job->ErrorString();
if (error.Length() > 0) {
error.ReplaceAll("\n", "\n*** ");
fprintf(stderr, "%s", error.String());
}
}
void
CheckManager::JobAborted(BSupportKit::BJob* job)
{
printf("Job aborted\n");
BString error = job->ErrorString();
if (error.Length() > 0) {
error.ReplaceAll("\n", "\n*** ");
fprintf(stderr, "%s", error.String());
}
}
void
CheckManager::HandleProblems()
{
printf("Encountered problems:\n");
int32 problemCount = fSolver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
BSolverProblem* problem = fSolver->ProblemAt(i);
printf("problem %" B_PRId32 ": %s\n", i + 1,
problem->ToString().String());
}
BString title(B_TRANSLATE("Available updates found"));
BString text(B_TRANSLATE("Click here to run SoftwareUpdater. Some updates "
"will require a problem solution to be selected."));
_SendNotification(title, text);
throw BAbortedByUserException();
}
void
CheckManager::ConfirmChanges(bool fromMostSpecific)
{
int32 count = fInstalledRepositories.CountItems();
int32 updateCount = 0;
if (fromMostSpecific) {
for (int32 i = count - 1; i >= 0; i--)
_CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount);
} else {
for (int32 i = 0; i < count; i++)
_CountUpdates(*fInstalledRepositories.ItemAt(i), updateCount);
}
printf("Update count=%" B_PRId32 "\n", updateCount);
if (updateCount > 0) {
BString title(B_TRANSLATE("%count% packages have available updates"));
BString count;
count << updateCount;
title.ReplaceFirst("%count%", count);
BString text(B_TRANSLATE("Click here to install updates."));
_SendNotification(title, text);
}
throw BAbortedByUserException();
}
void
CheckManager::Warn(status_t error, const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
if (error == B_OK)
printf("\n");
else
printf(": %s\n", strerror(error));
}
void
CheckManager::ProgressPackageDownloadStarted(const char* packageName)
{
printf("Downloading %s...\n", packageName);
}
void
CheckManager::ProgressPackageDownloadActive(const char* packageName,
float completionPercentage, off_t bytes, off_t totalBytes)
{
static const char* progressChars[] = {
"\xE2\x96\x8F",
"\xE2\x96\x8E",
"\xE2\x96\x8D",
"\xE2\x96\x8C",
"\xE2\x96\x8B",
"\xE2\x96\x8A",
"\xE2\x96\x89",
"\xE2\x96\x88",
};
int width = 70;
struct winsize winSize;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winSize) == 0
&& winSize.ws_col < 77) {
// We need 7 characters for the percent display
width = winSize.ws_col - 7;
}
int position;
int ipart = (int)(completionPercentage * width);
int fpart = (int)(((completionPercentage * width) - ipart) * 8);
printf("\r"); // return to the beginning of the line
for (position = 0; position < width; position++) {
if (position < ipart) {
// This part is fully downloaded, show a full block
printf(progressChars[7]);
} else if (position > ipart) {
// This part is not downloaded, show a space
printf(" ");
} else {
// This part is partially downloaded
printf(progressChars[fpart]);
}
}
// Also print the progress percentage
printf(" %3d%%", (int)(completionPercentage * 100));
fflush(stdout);
}
void
CheckManager::ProgressPackageDownloadComplete(const char* packageName)
{
// Overwrite the progress bar with whitespace
printf("\r");
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
for (int i = 0; i < (w.ws_col); i++)
printf(" ");
printf("\r\x1b[1A"); // Go to previous line.
printf("Downloading %s...done.\n", packageName);
}
void
CheckManager::ProgressPackageChecksumStarted(const char* title)
{
printf("%s...", title);
}
void
CheckManager::ProgressPackageChecksumComplete(const char* title)
{
printf("done.\n");
}
void
CheckManager::_CountUpdates(InstalledRepository& installationRepository,
int32& updateCount)
{
if (!installationRepository.HasChanges())
return;
PackageList& packagesToActivate
= installationRepository.PackagesToActivate();
PackageList& packagesToDeactivate
= installationRepository.PackagesToDeactivate();
for (int32 i = 0;
BSolverPackage* installPackage = packagesToActivate.ItemAt(i);
i++) {
for (int32 j = 0;
BSolverPackage* uninstallPackage = packagesToDeactivate.ItemAt(j);
j++) {
if (installPackage->Info().Name() == uninstallPackage->Info().Name()) {
updateCount++;
break;
}
}
}
}
void
CheckManager::_SendNotification(const char* title, const char* text)
{
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup("SoftwareUpdater");
notification.SetTitle(title);
notification.SetContent(text);
notification.SetOnClickApp(kAppSignature);
BBitmap icon(_GetIcon());
if (icon.IsValid())
notification.SetIcon(&icon);
bigtime_t timeout = 30000000;
notification.Send(timeout);
}
BBitmap
CheckManager::_GetIcon()
{
int32 iconSize = B_LARGE_ICON;
BBitmap icon(BRect(0, 0, iconSize - 1, iconSize - 1), 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, icon_size(iconSize));
return icon;
}
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright 2013-2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <[email protected]>
* Rene Gollent <[email protected]>
* Brian Hill <[email protected]>
*/
#ifndef CHECK_MANAGER_H
#define CHECK_MANAGER_H
#include <Bitmap.h>
#include <package/DaemonClient.h>
#include <package/manager/PackageManager.h>
#include "constants.h"
#include "SoftwareUpdaterWindow.h"
class ProblemWindow;
//using namespace BPackageKit;
using BPackageKit::BPackageInstallationLocation;
using BPackageKit::BPrivate::BDaemonClient;
using BPackageKit::BManager::BPrivate::BPackageManager;
class CheckManager : public BPackageManager,
private BPackageManager::UserInteractionHandler {
public:
CheckManager(
BPackageInstallationLocation location);
void CheckNetworkConnection();
virtual void JobFailed(BSupportKit::BJob* job);
virtual void JobAborted(BSupportKit::BJob* job);
private:
// UserInteractionHandler
virtual void HandleProblems();
virtual void ConfirmChanges(bool fromMostSpecific);
virtual void Warn(status_t error, const char* format, ...);
virtual void ProgressPackageDownloadStarted(
const char* packageName);
virtual void ProgressPackageDownloadActive(
const char* packageName,
float completionPercentage,
off_t bytes, off_t totalBytes);
virtual void ProgressPackageDownloadComplete(
const char* packageName);
virtual void ProgressPackageChecksumStarted(
const char* packageName);
virtual void ProgressPackageChecksumComplete(
const char* packageName);
private:
void _CountUpdates(InstalledRepository&
installationRepository,
int32& updateCount);
void _SendNotification(const char* title,
const char* text);
BBitmap _GetIcon();
private:
BPackageManager::ClientInstallationInterface
fClientInstallationInterface;
ProblemWindow* fProblemWindow;
};
#endif // CHECK_MANAGER_H
+2
View File
@@ -10,6 +10,8 @@ Application SoftwareUpdater :
StripeView.cpp StripeView.cpp
UpdateAction.cpp UpdateAction.cpp
UpdateManager.cpp UpdateManager.cpp
CheckAction.cpp
CheckManager.cpp
WorkingLooper.cpp WorkingLooper.cpp
# package_daemon # package_daemon
@@ -9,14 +9,31 @@
#include "SoftwareUpdaterApp.h" #include "SoftwareUpdaterApp.h"
#include "constants.h" #include <Catalog.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SoftwareUpdaterApp"
static const char* const kUsage = B_TRANSLATE_COMMENT(
"Usage: SoftwareUpdater <command>\n"
"Updates installed packages.\n"
"\n"
"Commands:\n"
" update - Search repositories for updates on all packages.\n"
" check - Check for available updates but only display a "
"notification with results.\n"
" full-sync - Synchronize the installed packages with the "
"repositories.\n", "Command line usage help")
;
SoftwareUpdaterApp::SoftwareUpdaterApp() SoftwareUpdaterApp::SoftwareUpdaterApp()
: :
BApplication("application/x-vnd.haiku-softwareupdater"), BApplication(kAppSignature),
fWorker(NULL), fWorker(NULL),
fFinalQuitFlag(false) fFinalQuitFlag(false),
fActionRequested(UPDATE)
{ {
} }
@@ -50,7 +67,30 @@ SoftwareUpdaterApp::QuitRequested()
void void
SoftwareUpdaterApp::ReadyToRun() SoftwareUpdaterApp::ReadyToRun()
{ {
fWorker = new WorkingLooper(); fWorker = new WorkingLooper(fActionRequested);
}
void
SoftwareUpdaterApp::ArgvReceived(int32 argc, char **argv)
{
// Only one command allowed
if (argc > 2) {
fprintf(stderr, kUsage);
PostMessage(B_QUIT_REQUESTED);
return;
} else if (argc == 2) {
fActionRequested = USER_SELECTION_NEEDED;
const char* command = argv[1];
if (strcmp("update", command) == 0)
fActionRequested = UPDATE;
else if (strcmp("check", command) == 0)
fActionRequested = UPDATE_CHECK_ONLY;
else if (strcmp("full-sync", command) == 0)
fActionRequested = FULLSYNC;
else
fprintf(stderr, kUsage);
}
} }
@@ -74,8 +114,13 @@ SoftwareUpdaterApp::MessageReceived(BMessage* message)
int int
main() main(int argc, const char* const* argv)
{ {
if (argc > 2) {
fprintf(stderr, kUsage);
return 1;
}
SoftwareUpdaterApp app; SoftwareUpdaterApp app;
return app.Run(); return app.Run();
} }
@@ -20,13 +20,15 @@ public:
SoftwareUpdaterApp(); SoftwareUpdaterApp();
~SoftwareUpdaterApp(); ~SoftwareUpdaterApp();
virtual bool QuitRequested(); virtual bool QuitRequested();
void ReadyToRun(); virtual void ReadyToRun();
virtual void ArgvReceived(int32 argc, char **argv);
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
private: private:
WorkingLooper* fWorker; WorkingLooper* fWorker;
BMessenger fWindowMessenger; BMessenger fWindowMessenger;
bool fFinalQuitFlag; bool fFinalQuitFlag;
update_type fActionRequested;
}; };
@@ -18,7 +18,6 @@
#include <LayoutBuilder.h> #include <LayoutBuilder.h>
#include <LayoutUtils.h> #include <LayoutUtils.h>
#include <Message.h> #include <Message.h>
#include <NodeInfo.h>
#include <Roster.h> #include <Roster.h>
#include <String.h> #include <String.h>
@@ -63,7 +62,7 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow()
fDetailView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); fDetailView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
fDetailView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP)); fDetailView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
fStatusBar = new BStatusBar("progress"); fStatusBar = new BStatusBar("progress");
fStatusBar->SetMaxValue(1.0); fStatusBar->SetMaxValue(100);
fListView = new PackageListView(); fListView = new PackageListView();
fScrollView = new BScrollView("scrollview", fListView, B_WILL_DRAW, fScrollView = new BScrollView("scrollview", fListView, B_WILL_DRAW,
@@ -175,6 +174,8 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message)
fStatusBar->SetTo(percent, packageName.String(), fStatusBar->SetTo(percent, packageName.String(),
packageCount.String()); packageCount.String());
Unlock(); Unlock();
fListView->UpdatePackageProgress(packageName.String(), percent);
break; break;
} }
@@ -332,11 +333,11 @@ SoftwareUpdaterWindow::UserCancelRequested()
void void
SoftwareUpdaterWindow::AddPackageInfo(uint32 install_type, SoftwareUpdaterWindow::AddPackageInfo(uint32 install_type,
const char* package_name, const char* cur_ver, const char* new_ver, const char* package_name, const char* cur_ver, const char* new_ver,
const char* summary, const char* repository) const char* summary, const char* repository, const char* file_name)
{ {
Lock(); Lock();
fListView->AddPackage(install_type, package_name, cur_ver, new_ver, fListView->AddPackage(install_type, package_name, cur_ver, new_ver,
summary, repository); summary, repository, file_name);
Unlock(); Unlock();
} }
@@ -481,7 +482,8 @@ SuperItem::SuperItem(const char* label)
BListItem(), BListItem(),
fLabel(label), fLabel(label),
fShowMoreDetails(false), fShowMoreDetails(false),
fPackageIcon(NULL) fPackageIcon(NULL),
fItemCount(0)
{ {
} }
@@ -495,15 +497,21 @@ SuperItem::~SuperItem()
void void
SuperItem::DrawItem(BView* owner, BRect item_rect, bool complete) SuperItem::DrawItem(BView* owner, BRect item_rect, bool complete)
{ {
owner->PushState();
float width; float width;
owner->GetPreferredSize(&width, NULL); owner->GetPreferredSize(&width, NULL);
BString label(fLabel); BString label(fLabel);
label.Append(" (");
label << fItemCount;
label.Append(")");
owner->TruncateString(&label, B_TRUNCATE_END, width); owner->TruncateString(&label, B_TRUNCATE_END, width);
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR)); owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
owner->SetFont(&fBoldFont); owner->SetFont(&fBoldFont);
owner->DrawString(label.String(), BPoint(item_rect.left, owner->DrawString(label.String(), BPoint(item_rect.left,
item_rect.bottom - fFontHeight.descent - 1)); item_rect.bottom - fFontHeight.descent - 1));
owner->SetFont(&fRegularFont);
owner->PopState();
} }
@@ -548,7 +556,7 @@ void
SuperItem::_GetPackageIcon() SuperItem::_GetPackageIcon()
{ {
delete fPackageIcon; delete fPackageIcon;
fIconSize = int(fPackageItemHeight * .7); fIconSize = int(fPackageItemHeight * .8);
status_t result = B_ERROR; status_t result = B_ERROR;
BRect iconRect(0, 0, fIconSize - 1, fIconSize - 1); BRect iconRect(0, 0, fIconSize - 1, fIconSize - 1);
@@ -571,7 +579,7 @@ SuperItem::_GetPackageIcon()
PackageItem::PackageItem(const char* name, const char* simple_version, PackageItem::PackageItem(const char* name, const char* simple_version,
const char* detailed_version, const char* repository, const char* summary, const char* detailed_version, const char* repository, const char* summary,
SuperItem* super) const char* file_name, SuperItem* super)
: :
BListItem(), BListItem(),
fName(name), fName(name),
@@ -579,7 +587,10 @@ PackageItem::PackageItem(const char* name, const char* simple_version,
fDetailedVersion(detailed_version), fDetailedVersion(detailed_version),
fRepository(repository), fRepository(repository),
fSummary(summary), fSummary(summary),
fSuperItem(super) fSuperItem(super),
fFileName(file_name),
fDownloadProgress(0),
fDrawBarFlag(false)
{ {
fLabelOffset = be_control_look->DefaultLabelSpacing(); fLabelOffset = be_control_look->DefaultLabelSpacing();
} }
@@ -588,6 +599,8 @@ PackageItem::PackageItem(const char* name, const char* simple_version,
void void
PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete) PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete)
{ {
owner->PushState();
float width; float width;
owner->GetPreferredSize(&width, NULL); owner->GetPreferredSize(&width, NULL);
float nameWidth = width / 2.0; float nameWidth = width / 2.0;
@@ -601,13 +614,20 @@ PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete)
//owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); //owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
owner->SetDrawingMode(B_OP_ALPHA); owner->SetDrawingMode(B_OP_ALPHA);
owner->DrawBitmap(icon, BPoint(item_rect.left, BPoint location = BPoint(item_rect.left,
item_rect.top + offsetMarginHeight)); item_rect.top + offsetMarginHeight);
owner->DrawBitmap(icon, location);
owner->SetDrawingMode(B_OP_COPY); owner->SetDrawingMode(B_OP_COPY);
if (fDrawBarFlag)
_DrawBar(location, owner, icon_size(iconSize));
offset_width += iconSize + fLabelOffset; offset_width += iconSize + fLabelOffset;
} }
owner->SetFont(&fRegularFont);
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR)); owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
// Package name // Package name
font_height fontHeight = fSuperItem->GetFontHeight(); font_height fontHeight = fSuperItem->GetFontHeight();
BString name(fName); BString name(fName);
@@ -647,7 +667,61 @@ PackageItem::DrawItem(BView* owner, BRect item_rect, bool complete)
owner->DrawString(version.String(), cursor); owner->DrawString(version.String(), cursor);
} }
owner->SetFont(&fRegularFont); owner->PopState();
}
// Modified slightly from Tracker's BPose::DrawBar
void
PackageItem::_DrawBar(BPoint where, BView* view, icon_size which)
{
int32 yOffset;
int32 size = which - 1;
int32 barWidth = (int32)(7.0f / 32.0f * (float)which);
if (barWidth < 4) {
barWidth = 4;
yOffset = 0;
} else
yOffset = 2;
int32 barHeight = size - 3 - 2 * yOffset;
// the black shadowed line
view->SetHighColor(32, 32, 32, 92);
view->MovePenTo(BPoint(where.x + size, where.y + 1 + yOffset));
view->StrokeLine(BPoint(where.x + size, where.y + size - yOffset));
view->StrokeLine(BPoint(where.x + size - barWidth + 1,
where.y + size - yOffset));
view->SetDrawingMode(B_OP_ALPHA);
// the gray frame
view->SetHighColor(76, 76, 76, 192);
BRect rect(where.x + size - barWidth,where.y + yOffset,
where.x + size - 1,where.y + size - 1 - yOffset);
view->StrokeRect(rect);
// calculate bar height
int32 barPos = barHeight - int32(barHeight * fDownloadProgress / 100.0);
if (barPos < 0)
barPos = 0;
else if (barPos > barHeight)
barPos = barHeight;
// the free space bar
view->SetHighColor(255, 255, 255, 192);
rect.InsetBy(1,1);
BRect bar(rect);
bar.bottom = bar.top + barPos - 1;
if (barPos > 0)
view->FillRect(bar);
// the used space bar
bar.top = bar.bottom + 1;
bar.bottom = rect.bottom;
view->SetHighColor(0, 203, 0, 192);
view->FillRect(bar);
} }
@@ -681,6 +755,13 @@ PackageItem::NameCompare(PackageItem* item)
} }
void
PackageItem::SetDownloadProgress(float percent)
{
fDownloadProgress = percent;
}
int int
SortPackageItems(const BListItem* item1, const BListItem* item2) SortPackageItems(const BListItem* item1, const BListItem* item2)
{ {
@@ -696,7 +777,9 @@ PackageListView::PackageListView()
fSuperUpdateItem(NULL), fSuperUpdateItem(NULL),
fSuperInstallItem(NULL), fSuperInstallItem(NULL),
fSuperUninstallItem(NULL), fSuperUninstallItem(NULL),
fShowMoreDetails(false) fShowMoreDetails(false),
fLastProgressItem(NULL),
fLastProgressValue(-1)
{ {
fMenu = new BPopUpMenu(B_EMPTY_STRING, false, false); fMenu = new BPopUpMenu(B_EMPTY_STRING, false, false);
fDetailMenuItem = new BMenuItem("Show more details", new BMessage()); fDetailMenuItem = new BMenuItem("Show more details", new BMessage());
@@ -778,7 +861,7 @@ PackageListView::MouseDown(BPoint where)
void void
PackageListView::AddPackage(uint32 install_type, const char* name, PackageListView::AddPackage(uint32 install_type, const char* name,
const char* cur_ver, const char* new_ver, const char* summary, const char* cur_ver, const char* new_ver, const char* summary,
const char* repository) const char* repository, const char* file_name)
{ {
SuperItem* super; SuperItem* super;
BString simpleVersion; BString simpleVersion;
@@ -844,11 +927,43 @@ PackageListView::AddPackage(uint32 install_type, const char* name,
} }
PackageItem* item = new PackageItem(name, simpleVersion.String(), PackageItem* item = new PackageItem(name, simpleVersion.String(),
detailedVersion.String(), repositoryText.String(), summary, super); detailedVersion.String(), repositoryText.String(), summary, file_name,
super);
AddUnder(item, super); AddUnder(item, super);
super->SetItemCount(CountItemsUnder(super, true));
} }
void
PackageListView::UpdatePackageProgress(const char* packageName, float percent)
{
// Update only every 1 percent change
int16 wholePercent = int16(percent);
if (wholePercent == fLastProgressValue)
return;
fLastProgressValue = wholePercent;
// A new package started downloading, find the PackageItem by name
if (percent == 0) {
fLastProgressItem = NULL;
int32 count = FullListCountItems();
for (int32 i = 0; i < count; i++) {
PackageItem* item = dynamic_cast<PackageItem*>(FullListItemAt(i));
if (item != NULL && strcmp(item->FileName(), packageName) == 0) {
fLastProgressItem = item;
fLastProgressItem->ShowProgressBar();
break;
}
}
}
if (fLastProgressItem != NULL) {
fLastProgressItem->SetDownloadProgress(percent);
Invalidate();
}
}
void void
PackageListView::SortItems() PackageListView::SortItems()
{ {
@@ -14,6 +14,7 @@
#include <GroupView.h> #include <GroupView.h>
#include <OutlineListView.h> #include <OutlineListView.h>
#include <MenuItem.h> #include <MenuItem.h>
#include <NodeInfo.h>
#include <Point.h> #include <Point.h>
#include <PopUpMenu.h> #include <PopUpMenu.h>
#include <ScrollView.h> #include <ScrollView.h>
@@ -45,6 +46,8 @@ public:
int16 GetIconSize() { return fIconSize; }; int16 GetIconSize() { return fIconSize; };
void SetDetailLevel(bool showMoreDetails); void SetDetailLevel(bool showMoreDetails);
bool GetDetailLevel() { return fShowMoreDetails; }; bool GetDetailLevel() { return fShowMoreDetails; };
void SetItemCount(int32 count)
{ fItemCount = count; };
private: private:
void _SetHeights(); void _SetHeights();
@@ -58,6 +61,7 @@ private:
float fPackageItemHeight; float fPackageItemHeight;
BBitmap* fPackageIcon; BBitmap* fPackageIcon;
int16 fIconSize; int16 fIconSize;
int32 fItemCount;
}; };
@@ -68,13 +72,20 @@ public:
const char* detailed_version, const char* detailed_version,
const char* repository, const char* repository,
const char* summary, const char* summary,
const char* file_name,
SuperItem* super); SuperItem* super);
virtual void DrawItem(BView*, BRect, bool); virtual void DrawItem(BView*, BRect, bool);
virtual void Update(BView *owner, const BFont *font); virtual void Update(BView *owner, const BFont *font);
void SetItemHeight(const BFont* font); void SetItemHeight(const BFont* font);
int NameCompare(PackageItem* item); int NameCompare(PackageItem* item);
const char* FileName() { return fFileName.String(); };
void SetDownloadProgress(float percent);
void ShowProgressBar() { fDrawBarFlag = true; };
private: private:
void _DrawBar(BPoint where, BView* view,
icon_size which);
BString fName; BString fName;
BString fSimpleVersion; BString fSimpleVersion;
BString fDetailedVersion; BString fDetailedVersion;
@@ -86,6 +97,9 @@ private:
float fSmallTotalHeight; float fSmallTotalHeight;
float fLabelOffset; float fLabelOffset;
SuperItem* fSuperItem; SuperItem* fSuperItem;
BString fFileName;
float fDownloadProgress;
bool fDrawBarFlag;
}; };
@@ -101,7 +115,10 @@ public:
const char* cur_ver, const char* cur_ver,
const char* new_ver, const char* new_ver,
const char* summary, const char* summary,
const char* repository); const char* repository,
const char* file_name);
void UpdatePackageProgress(const char* packageName,
float percent);
void SortItems(); void SortItems();
float ItemHeight(); float ItemHeight();
@@ -114,6 +131,8 @@ private:
bool fShowMoreDetails; bool fShowMoreDetails;
BPopUpMenu *fMenu; BPopUpMenu *fMenu;
BMenuItem *fDetailMenuItem; BMenuItem *fDetailMenuItem;
PackageItem* fLastProgressItem;
int16 fLastProgressValue;
}; };
@@ -130,7 +149,8 @@ public:
const char* cur_ver, const char* cur_ver,
const char* new_ver, const char* new_ver,
const char* summary, const char* summary,
const char* repository); const char* repository,
const char* file_name);
void ShowWarningAlert(const char* text); void ShowWarningAlert(const char* text);
BBitmap GetIcon(int32 iconSize); BBitmap GetIcon(int32 iconSize);
BBitmap GetNotificationIcon(); BBitmap GetNotificationIcon();
+16 -7
View File
@@ -13,8 +13,6 @@
#include <Catalog.h> #include <Catalog.h>
#include <package/manager/Exceptions.h> #include <package/manager/Exceptions.h>
#include "constants.h"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "UpdateAction" #define B_TRANSLATION_CONTEXT "UpdateAction"
@@ -39,15 +37,21 @@ UpdateAction::~UpdateAction()
status_t status_t
UpdateAction::Perform() UpdateAction::Perform(update_type action_request)
{ {
try { try {
fUpdateManager->CheckNetworkConnection(); fUpdateManager->CheckNetworkConnection();
int32 action = fUpdateManager->GetUpdateType();
update_type action = action_request;
// Prompt the user if needed
if (action == USER_SELECTION_NEEDED)
action = fUpdateManager->GetUpdateType();
if (action == CANCEL_UPDATE) if (action == CANCEL_UPDATE)
throw BAbortedByUserException(); throw BAbortedByUserException();
else if (action <= INVALID_SELECTION || action >= UPDATE_TYPE_END) else if (action <= INVALID_SELECTION || action >= UPDATE_TYPE_END)
throw BException("Invalid update type, cannot continue with updates"); throw BException(B_TRANSLATE(
"Invalid update type, cannot continue with updates"));
fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES | BPackageManager::B_ADD_REMOTE_REPOSITORIES
@@ -61,7 +65,11 @@ UpdateAction::Perform()
fUpdateManager->Update(&packages, packageCount); fUpdateManager->Update(&packages, packageCount);
} else if (action == FULLSYNC) } else if (action == FULLSYNC)
fUpdateManager->FullSync(); fUpdateManager->FullSync();
else
// Should not happen but just in case
throw BException(B_TRANSLATE(
"Invalid update type, cannot continue with updates"));
} catch (BFatalErrorException ex) { } catch (BFatalErrorException ex) {
fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"), fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"),
ex.Message()); ex.Message());
@@ -79,7 +87,8 @@ UpdateAction::Perform()
B_TRANSLATE("There were no updates found.")); B_TRANSLATE("There were no updates found."));
return B_OK; return B_OK;
} catch (BException ex) { } catch (BException ex) {
fprintf(stderr, "Exception occurred while updating packages : %s\n", fprintf(stderr, B_TRANSLATE(
"Exception occurred while updating packages : %s\n"),
ex.Message().String()); ex.Message().String());
fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"), fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"),
ex.Message()); ex.Message());
+1 -1
View File
@@ -16,7 +16,7 @@ class UpdateAction {
public: public:
UpdateAction(); UpdateAction();
~UpdateAction(); ~UpdateAction();
status_t Perform(); status_t Perform(update_type action_request);
private: private:
UpdateManager* fUpdateManager; UpdateManager* fUpdateManager;
+28 -38
View File
@@ -23,18 +23,11 @@
#include <NetworkRoster.h> #include <NetworkRoster.h>
#include <Notification.h> #include <Notification.h>
#include <package/CommitTransactionResult.h>
#include <package/DownloadFileRequest.h>
#include <package/RefreshRepositoryRequest.h>
#include <package/manager/Exceptions.h> #include <package/manager/Exceptions.h>
#include <package/solver/SolverPackage.h> #include <package/solver/SolverPackage.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverProblemSolution.h>
#include "constants.h" #include "constants.h"
#include "AutoDeleter.h"
#include "ProblemWindow.h" #include "ProblemWindow.h"
#include "ResultWindow.h"
using namespace BPackageKit; using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate; using namespace BPackageKit::BManager::BPrivate;
@@ -102,7 +95,7 @@ UpdateManager::CheckNetworkConnection()
} }
int32 update_type
UpdateManager::GetUpdateType() UpdateManager::GetUpdateType()
{ {
int32 action = USER_SELECTION_NEEDED; int32 action = USER_SELECTION_NEEDED;
@@ -113,7 +106,7 @@ UpdateManager::GetUpdateType()
messenger.SendMessage(&message, &reply); messenger.SendMessage(&message, &reply);
reply.FindInt32(kKeyAlertResult, &action); reply.FindInt32(kKeyAlertResult, &action);
} }
return action; return (update_type)action;
} }
@@ -278,13 +271,7 @@ UpdateManager::ProgressPackageDownloadStarted(const char* packageName)
{ {
if (fCurrentStep == ACTION_STEP_DOWNLOAD) { if (fCurrentStep == ACTION_STEP_DOWNLOAD) {
BString header(B_TRANSLATE("Downloading packages")); BString header(B_TRANSLATE("Downloading packages"));
BString packageCount; _UpdateDownloadProgress(header.String(), packageName, 0.0);
packageCount.SetToFormat(
B_TRANSLATE_COMMENT("%i of %i", "Do not translate %i"),
fPackageDownloadsCount,
fPackageDownloadsTotal);
_UpdateDownloadProgress(header.String(), packageName, packageCount,
0.0);
fNewDownloadStarted = false; fNewDownloadStarted = false;
} }
@@ -294,24 +281,18 @@ UpdateManager::ProgressPackageDownloadStarted(const char* packageName)
void void
UpdateManager::ProgressPackageDownloadActive(const char* packageName, UpdateManager::ProgressPackageDownloadActive(const char* packageName,
float completionPercentage, off_t bytes, off_t totalBytes) float completionValue, off_t bytes, off_t totalBytes)
{ {
if (fCurrentStep == ACTION_STEP_DOWNLOAD) { if (fCurrentStep == ACTION_STEP_DOWNLOAD) {
// Fix a bug where a 100% completion percentage gets sent at the start // Fix a bug where a 100% completion percentage gets sent at the start
// of a package download // of a package download
if (!fNewDownloadStarted) { if (!fNewDownloadStarted) {
if (completionPercentage > 0 && completionPercentage < 1) if (completionValue > 0 && completionValue < 1)
fNewDownloadStarted = true; fNewDownloadStarted = true;
else else
completionPercentage = 0.0; completionValue = 0.0;
} }
BString packageCount; _UpdateDownloadProgress(NULL, packageName, completionValue * 100.0);
packageCount.SetToFormat(
B_TRANSLATE_COMMENT("%i of %i", "Do not translate %i"),
fPackageDownloadsCount,
fPackageDownloadsTotal);
_UpdateDownloadProgress(NULL, packageName, packageCount,
completionPercentage);
} }
static const char* progressChars[] = { static const char* progressChars[] = {
@@ -335,8 +316,8 @@ UpdateManager::ProgressPackageDownloadActive(const char* packageName,
} }
int position; int position;
int ipart = (int)(completionPercentage * width); int ipart = (int)(completionValue * width);
int fpart = (int)(((completionPercentage * width) - ipart) * 8); int fpart = (int)(((completionValue * width) - ipart) * 8);
printf("\r"); // return to the beginning of the line printf("\r"); // return to the beginning of the line
@@ -354,7 +335,7 @@ UpdateManager::ProgressPackageDownloadActive(const char* packageName,
} }
// Also print the progress percentage // Also print the progress percentage
printf(" %3d%%", (int)(completionPercentage * 100)); printf(" %3d%%", (int)(completionValue * 100));
fflush(stdout); fflush(stdout);
@@ -364,8 +345,10 @@ UpdateManager::ProgressPackageDownloadActive(const char* packageName,
void void
UpdateManager::ProgressPackageDownloadComplete(const char* packageName) UpdateManager::ProgressPackageDownloadComplete(const char* packageName)
{ {
if (fCurrentStep == ACTION_STEP_DOWNLOAD) if (fCurrentStep == ACTION_STEP_DOWNLOAD) {
_UpdateDownloadProgress(NULL, packageName, 100.0);
fPackageDownloadsCount++; fPackageDownloadsCount++;
}
// Overwrite the progress bar with whitespace // Overwrite the progress bar with whitespace
printf("\r"); printf("\r");
@@ -497,7 +480,8 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
upgradedPackageVersions.StringAt(position).String(), upgradedPackageVersions.StringAt(position).String(),
package->Info().Version().ToString().String(), package->Info().Version().ToString().String(),
package->Info().Summary().String(), package->Info().Summary().String(),
package->Repository()->Name().String()); package->Repository()->Name().String(),
package->Info().FileName().String());
upgradeCount++; upgradeCount++;
} else { } else {
printf(" install package %s-%s from %s\n", printf(" install package %s-%s from %s\n",
@@ -509,7 +493,8 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
NULL, NULL,
package->Info().Version().ToString().String(), package->Info().Version().ToString().String(),
package->Info().Summary().String(), package->Info().Summary().String(),
package->Repository()->Name().String()); package->Repository()->Name().String(),
package->Info().FileName().String());
installCount++; installCount++;
} }
} }
@@ -525,7 +510,8 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
package->Info().Version().ToString(), package->Info().Version().ToString(),
NULL, NULL,
package->Info().Summary().String(), package->Info().Summary().String(),
package->Repository()->Name().String()); package->Repository()->Name().String(),
package->Info().FileName().String());
uninstallCount++; uninstallCount++;
} }
} }
@@ -551,21 +537,25 @@ UpdateManager::_UpdateStatusWindow(const char* header, const char* detail)
void void
UpdateManager::_UpdateDownloadProgress(const char* header, UpdateManager::_UpdateDownloadProgress(const char* header,
const char* packageName, const char* packageCount, const char* packageName, float percentageComplete)
float completionPercentage)
{ {
if (packageName == NULL || packageCount == NULL) if (packageName == NULL)
return; return;
if (fStatusWindow->UserCancelRequested()) if (fStatusWindow->UserCancelRequested())
throw BAbortedByUserException(); throw BAbortedByUserException();
BString packageCount;
packageCount.SetToFormat(
B_TRANSLATE_COMMENT("%i of %i", "Do not translate %i"),
fPackageDownloadsCount,
fPackageDownloadsTotal);
BMessage message(kMsgProgressUpdate); BMessage message(kMsgProgressUpdate);
if (header != NULL) if (header != NULL)
message.AddString(kKeyHeader, header); message.AddString(kKeyHeader, header);
message.AddString(kKeyPackageName, packageName); message.AddString(kKeyPackageName, packageName);
message.AddString(kKeyPackageCount, packageCount); message.AddString(kKeyPackageCount, packageCount.String());
message.AddFloat(kKeyPercentage, completionPercentage); message.AddFloat(kKeyPercentage, percentageComplete);
fStatusWindow->PostMessage(&message); fStatusWindow->PostMessage(&message);
} }
+6 -5
View File
@@ -14,11 +14,13 @@
#include <package/DaemonClient.h> #include <package/DaemonClient.h>
#include <package/manager/PackageManager.h> #include <package/manager/PackageManager.h>
#include "constants.h"
#include "SoftwareUpdaterWindow.h" #include "SoftwareUpdaterWindow.h"
class ProblemWindow; class ProblemWindow;
//using namespace BPackageKit; //using namespace BPackageKit;
using BPackageKit::BPackageInstallationLocation;
using BPackageKit::BPrivate::BDaemonClient; using BPackageKit::BPrivate::BDaemonClient;
using BPackageKit::BManager::BPrivate::BPackageManager; using BPackageKit::BManager::BPrivate::BPackageManager;
@@ -27,11 +29,11 @@ class UpdateManager : public BPackageManager,
private BPackageManager::UserInteractionHandler { private BPackageManager::UserInteractionHandler {
public: public:
UpdateManager( UpdateManager(
BPackageKit::BPackageInstallationLocation location); BPackageInstallationLocation location);
~UpdateManager(); ~UpdateManager();
void CheckNetworkConnection(); void CheckNetworkConnection();
int32 GetUpdateType(); update_type GetUpdateType();
virtual void JobFailed(BSupportKit::BJob* job); virtual void JobFailed(BSupportKit::BJob* job);
virtual void JobAborted(BSupportKit::BJob* job); virtual void JobAborted(BSupportKit::BJob* job);
void FinalUpdate(const char* header, void FinalUpdate(const char* header,
@@ -46,7 +48,7 @@ private:
const char* packageName); const char* packageName);
virtual void ProgressPackageDownloadActive( virtual void ProgressPackageDownloadActive(
const char* packageName, const char* packageName,
float completionPercentage, float completionValue,
off_t bytes, off_t totalBytes); off_t bytes, off_t totalBytes);
virtual void ProgressPackageDownloadComplete( virtual void ProgressPackageDownloadComplete(
const char* packageName); const char* packageName);
@@ -73,8 +75,7 @@ private:
const char* detail); const char* detail);
void _UpdateDownloadProgress(const char* header, void _UpdateDownloadProgress(const char* header,
const char* packageName, const char* packageName,
const char* packageCount, float percentageComplete);
float completionPercentage);
void _FinalUpdate(const char* header, void _FinalUpdate(const char* header,
const char* text); const char* text);
void _SetCurrentStep(int32 step); void _SetCurrentStep(int32 step);
+19 -3
View File
@@ -10,22 +10,38 @@
#include "WorkingLooper.h" #include "WorkingLooper.h"
WorkingLooper::WorkingLooper() WorkingLooper::WorkingLooper(update_type action)
: :
BLooper("WorkingLooper") BLooper("WorkingLooper"),
fUpdateAction(NULL),
fCheckAction(NULL),
fActionRequested(action)
{ {
Run(); Run();
PostMessage(kMsgStart); PostMessage(kMsgStart);
} }
WorkingLooper::~WorkingLooper()
{
delete fUpdateAction;
delete fCheckAction;
}
void void
WorkingLooper::MessageReceived(BMessage* message) WorkingLooper::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case kMsgStart: case kMsgStart:
{ {
fAction.Perform(); if (fActionRequested == UPDATE_CHECK_ONLY) {
fCheckAction = new CheckAction;
fCheckAction->Perform();
} else {
fUpdateAction = new UpdateAction();
fUpdateAction->Perform(fActionRequested);
}
break; break;
} }
+7 -2
View File
@@ -12,6 +12,7 @@
#include <Looper.h> #include <Looper.h>
#include <Message.h> #include <Message.h>
#include "CheckAction.h"
#include "UpdateAction.h" #include "UpdateAction.h"
@@ -20,11 +21,15 @@ const uint32 kMsgStart = 'iSTA';
class WorkingLooper : public BLooper { class WorkingLooper : public BLooper {
public: public:
WorkingLooper(); WorkingLooper(update_type action);
~WorkingLooper();
void MessageReceived(BMessage* message); void MessageReceived(BMessage* message);
private: private:
UpdateAction fAction; UpdateAction* fUpdateAction;
CheckAction* fCheckAction;
update_type fActionRequested;
}; };
+3 -2
View File
@@ -8,6 +8,8 @@
#ifndef CONSTANTS_H #ifndef CONSTANTS_H
#define CONSTANTS_H #define CONSTANTS_H
#define kAppSignature "application/x-vnd.haiku-softwareupdater"
enum { enum {
ACTION_STEP_INIT = 0, ACTION_STEP_INIT = 0,
ACTION_STEP_START, ACTION_STEP_START,
@@ -34,9 +36,8 @@ enum update_type {
UPDATE, UPDATE,
UPDATE_CHECK_ONLY, UPDATE_CHECK_ONLY,
FULLSYNC, FULLSYNC,
FULLSYNC_CHECK_ONLY,
UPDATE_TYPE_END UPDATE_TYPE_END
} ; };
// Message what values // Message what values
static const uint32 kMsgTextUpdate = 'iUPD'; static const uint32 kMsgTextUpdate = 'iUPD';