HaikuDepot: add work status view
* Add new WorkStatusView which keeps the user informed about what's happening. It's a status bar at the bottom of the window which shows on the left side either a spinning barber pole (for operations without a progress), or a progress bar (for download progress). Next to that is a text view showing a descriptive status text. * Currently, it will notify of the following operations: - Repository refresh (barber pole) - Background packet actions, like preparation of install or uninstall (barber pole) - Package downloads, including downloads of dependencies (progress bar). Status text indicates the name of the package currently being downloaded (if any), and how many more packages are queued for download after it (if any). * Hooks into PackageListView to be notified of package status changes (such as becoming pending or download progress) * When the package currently being downloaded is also selected in the list view, the user sees the progress bar in WorkStatusView as well as the one in the PackageInfoView, which is redundant. This still needs a good solution...
This commit is contained in:
parent
d737433974
commit
125d42d95b
@ -84,7 +84,8 @@ Application HaikuDepot :
|
||||
ScrollableGroupView.cpp
|
||||
SharedBitmap.cpp
|
||||
UserLoginWindow.cpp
|
||||
|
||||
WorkStatusView.cpp
|
||||
|
||||
# network + server - model
|
||||
DumpExportPkg.cpp
|
||||
DumpExportPkgCategory.cpp
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2013, Rene Gollent, rene@gollent.com.
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2016, Andrew Lindesay <apl@lindesay.co.nz>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@ -56,6 +57,7 @@
|
||||
#include "support.h"
|
||||
#include "ScreenshotWindow.h"
|
||||
#include "UserLoginWindow.h"
|
||||
#include "WorkStatusView.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
@ -162,6 +164,9 @@ MainWindow::MainWindow(const BMessage& settings)
|
||||
.Add(fFeaturedPackagesView)
|
||||
;
|
||||
|
||||
fWorkStatusView = new WorkStatusView("work status");
|
||||
fPackageListView->AttachWorkStatusView(fWorkStatusView);
|
||||
|
||||
BView* listArea = new BView("list area", 0);
|
||||
fListLayout = new BCardLayout();
|
||||
listArea->SetLayout(fListLayout);
|
||||
@ -183,6 +188,7 @@ MainWindow::MainWindow(const BMessage& settings)
|
||||
.End()
|
||||
.Add(fPackageInfoView)
|
||||
.End()
|
||||
.Add(fWorkStatusView)
|
||||
;
|
||||
|
||||
fSplitView->SetCollapsible(0, false);
|
||||
@ -305,6 +311,7 @@ MainWindow::MessageReceived(BMessage* message)
|
||||
fModelWorker = B_BAD_THREAD_ID;
|
||||
_AdoptModel();
|
||||
fFilterView->AdoptModel(fModel);
|
||||
fWorkStatusView->SetIdle();
|
||||
break;
|
||||
}
|
||||
case B_SIMPLE_DATA:
|
||||
@ -500,6 +507,20 @@ MainWindow::MessageReceived(BMessage* message)
|
||||
_ShowScreenshot();
|
||||
break;
|
||||
|
||||
case MSG_PACKAGE_WORKER_BUSY:
|
||||
{
|
||||
BString reason;
|
||||
status_t status = message->FindString("reason", &reason);
|
||||
if (status != B_OK)
|
||||
break;
|
||||
fWorkStatusView->SetBusy(reason);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_PACKAGE_WORKER_IDLE:
|
||||
fWorkStatusView->SetIdle();
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
break;
|
||||
@ -1093,6 +1114,8 @@ MainWindow::_StartRefreshWorker(bool force)
|
||||
if (parameters == NULL)
|
||||
return;
|
||||
|
||||
fWorkStatusView->SetBusy(B_TRANSLATE("Refreshing..."));
|
||||
|
||||
ObjectDeleter<RefreshWorkerParameters> deleter(parameters);
|
||||
fModelWorker = spawn_thread(&_RefreshModelThreadWorker, "model loader",
|
||||
B_LOW_PRIORITY, parameters);
|
||||
@ -1142,7 +1165,15 @@ MainWindow::_PackageActionWorker(void* arg)
|
||||
window->fPendingActions.Remove(0);
|
||||
}
|
||||
|
||||
BMessenger messenger(window);
|
||||
BMessage busyMessage(MSG_PACKAGE_WORKER_BUSY);
|
||||
BString text(ref->Label());
|
||||
text << "...";
|
||||
busyMessage.AddString("reason", text);
|
||||
|
||||
messenger.SendMessage(&busyMessage);
|
||||
ref->Perform();
|
||||
messenger.SendMessage(MSG_PACKAGE_WORKER_IDLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
|
||||
* Copyright 2013, Rene Gollent <rene@gollent.com>.
|
||||
* Copyright 2017, Julian Harnath <julian.harnath@rwth-aachen.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef MAIN_WINDOW_H
|
||||
@ -24,11 +25,14 @@ class PackageActionsView;
|
||||
class PackageInfoView;
|
||||
class PackageListView;
|
||||
class ScreenshotWindow;
|
||||
class WorkStatusView;
|
||||
|
||||
|
||||
enum {
|
||||
MSG_MAIN_WINDOW_CLOSED = 'mwcl',
|
||||
MSG_PACKAGE_SELECTED = 'pkgs',
|
||||
MSG_PACKAGE_WORKER_BUSY = 'pkwb',
|
||||
MSG_PACKAGE_WORKER_IDLE = 'pkwi',
|
||||
};
|
||||
|
||||
|
||||
@ -95,6 +99,7 @@ private:
|
||||
PackageListView* fPackageListView;
|
||||
PackageInfoView* fPackageInfoView;
|
||||
BSplitView* fSplitView;
|
||||
WorkStatusView* fWorkStatusView;
|
||||
|
||||
ScreenshotWindow* fScreenshotWindow;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <Window.h>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "WorkStatusView.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
@ -723,7 +724,8 @@ PackageListView::PackageListView(BLocker* modelLock)
|
||||
:
|
||||
BColumnListView("package list view", 0, B_FANCY_BORDER, true),
|
||||
fModelLock(modelLock),
|
||||
fPackageListener(new(std::nothrow) PackageListener(this))
|
||||
fPackageListener(new(std::nothrow) PackageListener(this)),
|
||||
fWorkStatusView(NULL)
|
||||
{
|
||||
float scale = be_plain_font->Size() / 12.f;
|
||||
float spacing = be_control_look->DefaultItemSpacing() * 2;
|
||||
@ -802,8 +804,13 @@ PackageListView::MessageReceived(BMessage* message)
|
||||
row->UpdateSummary();
|
||||
if ((changes & PKG_CHANGED_RATINGS) != 0)
|
||||
row->UpdateRating();
|
||||
if ((changes & PKG_CHANGED_STATE) != 0)
|
||||
if ((changes & PKG_CHANGED_STATE) != 0) {
|
||||
row->UpdateState();
|
||||
if (fWorkStatusView != NULL) {
|
||||
fWorkStatusView->PackageStatusChanged(
|
||||
row->Package());
|
||||
}
|
||||
}
|
||||
if ((changes & PKG_CHANGED_SIZE) != 0)
|
||||
row->UpdateSize();
|
||||
if ((changes & PKG_CHANGED_ICON) != 0)
|
||||
@ -897,6 +904,13 @@ PackageListView::SelectPackage(const PackageInfoRef& package)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageListView::AttachWorkStatusView(WorkStatusView* view)
|
||||
{
|
||||
fWorkStatusView = view;
|
||||
}
|
||||
|
||||
|
||||
PackageRow*
|
||||
PackageListView::_FindRow(const PackageInfoRef& package, PackageRow* parent)
|
||||
{
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
class PackageRow;
|
||||
class PackageListener;
|
||||
class WorkStatusView;
|
||||
|
||||
|
||||
class PackageListView : public BColumnListView {
|
||||
public:
|
||||
@ -35,6 +37,8 @@ public:
|
||||
|
||||
void SelectPackage(const PackageInfoRef& package);
|
||||
|
||||
void AttachWorkStatusView(WorkStatusView* view);
|
||||
|
||||
private:
|
||||
PackageRow* _FindRow(const PackageInfoRef& package,
|
||||
PackageRow* parent = NULL);
|
||||
@ -47,6 +51,8 @@ private:
|
||||
BLocker* fModelLock;
|
||||
ItemCountView* fItemCountView;
|
||||
PackageListener* fPackageListener;
|
||||
|
||||
WorkStatusView* fWorkStatusView;
|
||||
};
|
||||
|
||||
#endif // PACKAGE_LIST_VIEW_H
|
||||
|
165
src/apps/haikudepot/ui/WorkStatusView.cpp
Normal file
165
src/apps/haikudepot/ui/WorkStatusView.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2017 Julian Harnath <julian.harnath@rwth-aachen.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "WorkStatusView.h"
|
||||
|
||||
#include <CardLayout.h>
|
||||
#include <Catalog.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <SeparatorView.h>
|
||||
#include <StatusBar.h>
|
||||
#include <StringView.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "BarberPole.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "WorkStatusView"
|
||||
|
||||
|
||||
WorkStatusView::WorkStatusView(const char* name)
|
||||
:
|
||||
BView(name, 0),
|
||||
fProgressBar(new BStatusBar("progress bar")),
|
||||
fBarberPole(new BarberPole("barber pole")),
|
||||
fProgressLayout(new BCardLayout()),
|
||||
fProgressView(new BView("progress view", 0)),
|
||||
fStatusText(new BStringView("status text", NULL))
|
||||
{
|
||||
fProgressView->SetLayout(fProgressLayout);
|
||||
fProgressLayout->AddView(fBarberPole);
|
||||
fProgressLayout->AddView(fProgressBar);
|
||||
|
||||
fProgressBar->SetMaxValue(1.0f);
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
.Add(new BSeparatorView())
|
||||
.AddGroup(B_HORIZONTAL)
|
||||
.SetInsets(5, 5, 5, 5)
|
||||
.Add(fProgressLayout, 0.2f)
|
||||
.Add(fStatusText)
|
||||
.AddGlue()
|
||||
.End()
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
WorkStatusView::~WorkStatusView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::SetBusy(const BString& text)
|
||||
{
|
||||
SetText(text);
|
||||
SetBusy();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::SetBusy()
|
||||
{
|
||||
fBarberPole->Start();
|
||||
if (fProgressLayout->VisibleIndex() != 0)
|
||||
fProgressLayout->SetVisibleItem((int32)0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::SetIdle()
|
||||
{
|
||||
fBarberPole->Stop();
|
||||
fProgressLayout->SetVisibleItem((int32)0);
|
||||
SetText(NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::SetProgress(float value)
|
||||
{
|
||||
fProgressBar->SetTo(value);
|
||||
if (fProgressLayout->VisibleIndex() != 1)
|
||||
fProgressLayout->SetVisibleItem(1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::SetText(const BString& text)
|
||||
{
|
||||
fStatusText->SetText(text);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::PackageStatusChanged(const PackageInfoRef& package)
|
||||
{
|
||||
switch (package->State()) {
|
||||
case DOWNLOADING:
|
||||
fPendingPackages.erase(package->Name());
|
||||
if (package->Name() != fDownloadingPackage) {
|
||||
fDownloadingPackage = package->Name();
|
||||
_SetTextDownloading(package->Title());
|
||||
}
|
||||
SetProgress(package->DownloadProgress());
|
||||
break;
|
||||
|
||||
case PENDING:
|
||||
fPendingPackages.insert(package->Name());
|
||||
if (package->Name() == fDownloadingPackage)
|
||||
fDownloadingPackage = "";
|
||||
if (fDownloadingPackage.IsEmpty()) {
|
||||
_SetTextPendingDownloads();
|
||||
SetBusy();
|
||||
}
|
||||
break;
|
||||
|
||||
case NONE:
|
||||
case ACTIVATED:
|
||||
case INSTALLED:
|
||||
case UNINSTALLED:
|
||||
if (package->Name() == fDownloadingPackage)
|
||||
fDownloadingPackage = "";
|
||||
fPendingPackages.erase(package->Name());
|
||||
if (fPendingPackages.empty())
|
||||
SetIdle();
|
||||
else {
|
||||
_SetTextPendingDownloads();
|
||||
SetBusy();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::_SetTextPendingDownloads()
|
||||
{
|
||||
BString text;
|
||||
const size_t pendingCount = fPendingPackages.size();
|
||||
text << pendingCount;
|
||||
if (pendingCount > 1)
|
||||
text << B_TRANSLATE(" packages to download");
|
||||
else
|
||||
text << B_TRANSLATE(" package to download");
|
||||
SetText(text);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WorkStatusView::_SetTextDownloading(const BString& title)
|
||||
{
|
||||
BString text(B_TRANSLATE("Downloading package "));
|
||||
text << title;
|
||||
if (!fPendingPackages.empty()) {
|
||||
text << " (";
|
||||
text << fPendingPackages.size();
|
||||
text << B_TRANSLATE(" more to download)");
|
||||
}
|
||||
SetText(text);
|
||||
}
|
53
src/apps/haikudepot/ui/WorkStatusView.h
Normal file
53
src/apps/haikudepot/ui/WorkStatusView.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2017 Julian Harnath <julian.harnath@rwth-aachen.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef WORK_STATUS_VIEW_H
|
||||
#define WORK_STATUS_VIEW_H
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "PackageInfo.h"
|
||||
|
||||
|
||||
class BarberPole;
|
||||
class BCardLayout;
|
||||
class BMessageRunner;
|
||||
class BStatusBar;
|
||||
class BStringView;
|
||||
|
||||
|
||||
class WorkStatusView : public BView {
|
||||
public:
|
||||
WorkStatusView(const char* name);
|
||||
~WorkStatusView();
|
||||
|
||||
void SetBusy(const BString& text);
|
||||
void SetBusy();
|
||||
void SetIdle();
|
||||
void SetProgress(float value);
|
||||
void SetText(const BString& text);
|
||||
|
||||
void PackageStatusChanged(
|
||||
const PackageInfoRef& package);
|
||||
|
||||
private:
|
||||
void _SetTextPendingDownloads();
|
||||
void _SetTextDownloading(const BString& title);
|
||||
|
||||
private:
|
||||
BStatusBar* fProgressBar;
|
||||
BarberPole* fBarberPole;
|
||||
BCardLayout* fProgressLayout;
|
||||
BView* fProgressView;
|
||||
BStringView* fStatusText;
|
||||
|
||||
BString fDownloadingPackage;
|
||||
std::set<BString> fPendingPackages;
|
||||
};
|
||||
|
||||
|
||||
#endif // WORK_STATUS_VIEW_H
|
Loading…
x
Reference in New Issue
Block a user