diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile index d2859db07c..ee980f9acb 100644 --- a/src/servers/package/Jamfile +++ b/src/servers/package/Jamfile @@ -12,6 +12,7 @@ Server package_daemon PackageDaemon.cpp PackageManager.cpp ProblemWindow.cpp + ResultWindow.cpp Root.cpp Volume.cpp : diff --git a/src/servers/package/PackageManager.cpp b/src/servers/package/PackageManager.cpp index 7696b05dae..3c09e51c51 100644 --- a/src/servers/package/PackageManager.cpp +++ b/src/servers/package/PackageManager.cpp @@ -6,7 +6,6 @@ #include "PackageManager.h" -#include #include #include #include @@ -15,11 +14,13 @@ #include #include +#include #include #include #include #include "ProblemWindow.h" +#include "ResultWindow.h" #include "Root.h" #include "Volume.h" @@ -290,29 +291,27 @@ void PackageManager::ConfirmChanges(bool fromMostSpecific) { // Check whether there are any changes other than those made by the user. - BString alertText( - "The following additional package changes have to be made:"); + _InitGui(); + ResultWindow* window = new ResultWindow; + ObjectDeleter windowDeleter(window); + bool hasOtherChanges = false; int32 count = fInstalledRepositories.CountItems(); if (fromMostSpecific) { for (int32 i = count - 1; i >= 0; i--) hasOtherChanges - |= _GetResultText(*fInstalledRepositories.ItemAt(i), alertText); + |= _AddResults(*fInstalledRepositories.ItemAt(i), window); } else { for (int32 i = 0; i < count; i++) hasOtherChanges - |= _GetResultText(*fInstalledRepositories.ItemAt(i), alertText); + |= _AddResults(*fInstalledRepositories.ItemAt(i), window); } if (!hasOtherChanges) return; - // show an alert - _InitGui(); - BAlert* alert = new BAlert("Package changes", alertText, - "Cancel", "Apply changes"); - alert->SetShortcut(0, B_ESCAPE); - if (alert->Go() == 0) + // show the window + if (windowDeleter.Detach()->Go() == 0) throw BAbortedByUserException(); } @@ -381,55 +380,15 @@ PackageManager::JobAborted(BJob* job) bool -PackageManager::_GetResultText(InstalledRepository& repository, - BString& _text) +PackageManager::_AddResults(InstalledRepository& repository, + ResultWindow* window) { if (!repository.HasChanges()) return false; - bool hasOtherChanges = false; - bool isTargetLocation - = repository.Location() == fVolume->Location(); - - BString text = BString().SetToFormat("\n in %s:", - repository.Name().String()); - - PackageList& packagesToActivate = repository.PackagesToActivate(); - PackageList& packagesToDeactivate = repository.PackagesToDeactivate(); - - for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i); - i++) { - if (isTargetLocation - && fPackagesAddedByUser.find(package) - != fPackagesAddedByUser.end()) { - continue; - } - - text << BString().SetToFormat( - "\n install package %s from repository %s\n", - package->Info().FileName().String(), - package->Repository()->Name().String()); - hasOtherChanges = true; - } - - for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i); - i++) { - if (isTargetLocation - && fPackagesRemovedByUser.find(package) - != fPackagesRemovedByUser.end()) { - continue; - } - - text << BString().SetToFormat( - "\n uninstall package %s\n", package->VersionedName().String()); - hasOtherChanges = true; - } - - if (!hasOtherChanges) - return false; - - _text << text; - return true; + return window->AddLocationChanges(repository.Name(), + repository.PackagesToActivate(), fPackagesAddedByUser, + repository.PackagesToDeactivate(), fPackagesRemovedByUser); } diff --git a/src/servers/package/PackageManager.h b/src/servers/package/PackageManager.h index 4737b7a451..3a7b7d5179 100644 --- a/src/servers/package/PackageManager.h +++ b/src/servers/package/PackageManager.h @@ -30,6 +30,7 @@ using BPackageKit::BManager::BPrivate::BPackageManager; class Package; class ProblemWindow; +class ResultWindow; class Root; class Volume; @@ -95,8 +96,8 @@ private: typedef std::map SolverPackageMap; private: - bool _GetResultText(InstalledRepository& repository, - BString& _text); + bool _AddResults(InstalledRepository& repository, + ResultWindow* window); BSolverPackage* _SolverPackageFor(Package* package) const; diff --git a/src/servers/package/ResultWindow.cpp b/src/servers/package/ResultWindow.cpp new file mode 100644 index 0000000000..bc6099f7ef --- /dev/null +++ b/src/servers/package/ResultWindow.cpp @@ -0,0 +1,215 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ResultWindow.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +using namespace BPackageKit; + + +static const uint32 kApplyMessage = 'rtry'; + + +ResultWindow::ResultWindow() + : + BWindow(BRect(0, 0, 400, 300), "Package changes", B_TITLED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL, + B_ASYNCHRONOUS_CONTROLS | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS, + B_ALL_WORKSPACES), + fDoneSemaphore(-1), + fClientWaiting(false), + fAccepted(false), + fContainerView(NULL), + fCancelButton(NULL), + fApplyButton(NULL) + +{ + fDoneSemaphore = create_sem(0, "package changes"); + if (fDoneSemaphore < 0) + throw std::bad_alloc(); + + BStringView* topTextView = NULL; + BViewPort* viewPort = NULL; + + BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING) + .SetInsets(B_USE_SMALL_INSETS) + .Add(topTextView = new BStringView(NULL, + "The following additional package changes have to be made:")) + .Add(new BScrollView(NULL, viewPort = new BViewPort(), 0, false, true)) + .AddGroup(B_HORIZONTAL) + .Add(fCancelButton = new BButton("Cancel", new BMessage(B_CANCEL))) + .AddGlue() + .Add(fApplyButton = new BButton("Apply changes", + new BMessage(kApplyMessage))) + .End(); + + topTextView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + + viewPort->SetChildView(fContainerView = new BGroupView(B_VERTICAL, 0)); + + // set small scroll step (large step will be set by the view port) + font_height fontHeight; + topTextView->GetFontHeight(&fontHeight); + float smallStep = ceilf(fontHeight.ascent + fontHeight.descent); + viewPort->ScrollBar(B_VERTICAL)->SetSteps(smallStep, smallStep); +} + + +ResultWindow::~ResultWindow() +{ + if (fDoneSemaphore >= 0) + delete_sem(fDoneSemaphore); +} + + +bool +ResultWindow::AddLocationChanges(const char* location, + const PackageList& packagesToInstall, + const PackageSet& packagesAlreadyAdded, + const PackageList& packagesToUninstall, + const PackageSet& packagesAlreadyRemoved) +{ + BGroupView* locationGroup = new BGroupView(B_VERTICAL); + ObjectDeleter locationGroupDeleter(locationGroup); + + locationGroup->GroupLayout()->SetInsets(B_USE_SMALL_INSETS); + + rgb_color background = ui_color(B_LIST_BACKGROUND_COLOR); + if ((fContainerView->CountChildren() & 1) != 0) + background = tint_color(background, 1.04); + locationGroup->SetViewColor(background); + + BStringView* locationView = new BStringView(NULL, + BString().SetToFormat("in %s:", location)); + locationGroup->AddChild(locationView); + locationView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + BFont locationFont; + locationView->GetFont(&locationFont); + locationFont.SetFace(B_BOLD_FACE); + locationView->SetFont(&locationFont); + + BGroupLayout* packagesGroup = new BGroupLayout(B_VERTICAL); + locationGroup->GroupLayout()->AddItem(packagesGroup); + packagesGroup->SetInsets(20, 0, 0, 0); + + bool packagesAdded = _AddPackages(packagesGroup, packagesToInstall, + packagesAlreadyAdded, true); + packagesAdded |= _AddPackages(packagesGroup, packagesToUninstall, + packagesAlreadyRemoved, false); + + if (!packagesAdded) + return false; + + fContainerView->AddChild(locationGroup); + locationGroupDeleter.Detach(); + + return true; +} + + +bool +ResultWindow::Go() +{ + AutoLocker locker(this); + + CenterOnScreen(); + Show(); + + fAccepted = false; + fClientWaiting = true; + + locker.Unlock(); + + while (acquire_sem(fDoneSemaphore) == B_INTERRUPTED) { + } + + locker.Lock(); + bool result = false; + if (locker.IsLocked()) { + result = fAccepted; + Quit(); + locker.Detach(); + } else + PostMessage(B_QUIT_REQUESTED); + + return result; +} + + +bool +ResultWindow::QuitRequested() +{ + if (fClientWaiting) { + Hide(); + fClientWaiting = false; + release_sem(fDoneSemaphore); + return false; + } + + return true; +} + + +void +ResultWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case B_CANCEL: + case kApplyMessage: + Hide(); + fAccepted = message->what == kApplyMessage; + fClientWaiting = false; + release_sem(fDoneSemaphore); + break; + default: + BWindow::MessageReceived(message); + break; + } +} + + +bool +ResultWindow::_AddPackages(BGroupLayout* packagesGroup, + const PackageList& packages, const PackageSet& ignorePackages, bool install) +{ + bool packagesAdded = false; + + for (int32 i = 0; BSolverPackage* package = packages.ItemAt(i); + i++) { + if (ignorePackages.find(package) != ignorePackages.end()) + continue; + + BString text; + if (install) { + text.SetToFormat("install package %s from repository %s\n", + package->Info().FileName().String(), + package->Repository()->Name().String()); + } else { + text.SetToFormat("uninstall package %s\n", + package->VersionedName().String()); + } + + BStringView* packageView = new BStringView(NULL, text); + packagesGroup->AddView(packageView); + packageView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); + + packagesAdded = true; + } + + return packagesAdded; +} diff --git a/src/servers/package/ResultWindow.h b/src/servers/package/ResultWindow.h new file mode 100644 index 0000000000..ccf5d6a090 --- /dev/null +++ b/src/servers/package/ResultWindow.h @@ -0,0 +1,62 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef RESULT_WINDOW_H +#define RESULT_WINDOW_H + + +#include +#include + +#include +#include + + +namespace BPackageKit { + class BSolverPackage; +} + +using BPackageKit::BSolverPackage; + +class BButton; +class BGroupLayout; +class BGroupView; + + +class ResultWindow : public BWindow { +public: + typedef std::set PackageSet; + typedef BObjectList PackageList; + +public: + ResultWindow(); + virtual ~ResultWindow(); + + bool AddLocationChanges(const char* location, + const PackageList& packagesToInstall, + const PackageSet& packagesAlreadyAdded, + const PackageList& packagesToUninstall, + const PackageSet& packagesAlreadyRemoved); + bool Go(); + + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage* message); + +private: + bool _AddPackages(BGroupLayout* packagesGroup, + const PackageList& packages, + const PackageSet& ignorePackages, + bool install); + +private: + sem_id fDoneSemaphore; + bool fClientWaiting; + bool fAccepted; + BGroupView* fContainerView; + BButton* fCancelButton; + BButton* fApplyButton; +}; + + +#endif // RESULT_WINDOW_H