Move all progress indicator handling to progress manager.

Part of it was managed in ProgressView, which only complicates things.

Change-Id: Ia9ca03e3228f3662864749da751f7ec4bdf23297
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Eike Ziller
2013-04-09 14:22:28 +02:00
parent e0f05e3b33
commit 9e714006ee
4 changed files with 147 additions and 164 deletions

View File

@@ -27,6 +27,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "futureprogress.h"
#include "progressmanager_p.h" #include "progressmanager_p.h"
#include "progressbar.h" #include "progressbar.h"
#include "progressview.h" #include "progressview.h"
@@ -267,8 +268,6 @@ ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
m_hovered(false) m_hovered(false)
{ {
m_progressView = new ProgressView; m_progressView = new ProgressView;
connect(m_progressView, SIGNAL(hasErrorChanged()), this, SLOT(updateSummaryProgressBar()));
connect(m_progressView, SIGNAL(fadeOfLastProgressStarted()), this, SLOT(updateSummaryProgressBar()));
// withDelay, so the statusBarWidget has the chance to get the enter event // withDelay, so the statusBarWidget has the chance to get the enter event
connect(m_progressView, SIGNAL(hoveredChanged(bool)), this, SLOT(updateVisibilityWithDelay())); connect(m_progressView, SIGNAL(hoveredChanged(bool)), this, SLOT(updateVisibilityWithDelay()));
connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(cancelAllRunningTasks())); connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(cancelAllRunningTasks()));
@@ -276,6 +275,8 @@ ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
ProgressManagerPrivate::~ProgressManagerPrivate() ProgressManagerPrivate::~ProgressManagerPrivate()
{ {
qDeleteAll(m_taskList);
m_taskList.clear();
ExtensionSystem::PluginManager::removeObject(m_statusBarWidgetContainer); ExtensionSystem::PluginManager::removeObject(m_statusBarWidgetContainer);
delete m_statusBarWidgetContainer; delete m_statusBarWidgetContainer;
cleanup(); cleanup();
@@ -379,11 +380,15 @@ void ProgressManagerPrivate::cancelAllRunningTasks()
FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, const QString &title, FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, const QString &title,
const QString &type, ProgressFlags flags) const QString &type, ProgressFlags flags)
{ {
// watch
QFutureWatcher<void> *watcher = new QFutureWatcher<void>(); QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
m_runningTasks.insert(watcher, type); m_runningTasks.insert(watcher, type);
connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(updateSummaryProgressBar())); connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(updateSummaryProgressBar()));
connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(updateSummaryProgressBar())); connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(updateSummaryProgressBar()));
connect(watcher, SIGNAL(finished()), this, SLOT(taskFinished())); connect(watcher, SIGNAL(finished()), this, SLOT(taskFinished()));
watcher->setFuture(future);
// handle application task
if (flags & ShowInApplicationIcon) { if (flags & ShowInApplicationIcon) {
if (m_applicationTask) if (m_applicationTask)
disconnectApplicationTask(); disconnectApplicationTask();
@@ -396,9 +401,28 @@ FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, con
this, SLOT(setApplicationProgressValue(int))); this, SLOT(setApplicationProgressValue(int)));
setApplicationProgressVisible(true); setApplicationProgressVisible(true);
} }
watcher->setFuture(future);
// create FutureProgress and manage task list
removeOldTasks(type);
if (m_taskList.size() == 10)
removeOneOldTask();
FutureProgress *progress = new FutureProgress;
progress->setTitle(title);
progress->setFuture(future);
m_progressView->addProgressWidget(progress);
m_taskList.append(progress);
progress->setType(type);
if (flags.testFlag(ProgressManager::KeepOnFinish))
progress->setKeepOnFinish(FutureProgress::KeepOnFinishTillUserInteraction);
else
progress->setKeepOnFinish(FutureProgress::HideOnFinish);
connect(progress, SIGNAL(hasErrorChanged()), this, SLOT(updateSummaryProgressBar()));
connect(progress, SIGNAL(removeMe()), this, SLOT(slotRemoveTask()));
connect(progress, SIGNAL(fadeStarted()), this, SLOT(updateSummaryProgressBar()));
emit taskStarted(type); emit taskStarted(type);
return m_progressView->addTask(future, title, type, flags); return progress;
} }
ProgressView *ProgressManagerPrivate::progressView() ProgressView *ProgressManagerPrivate::progressView()
@@ -434,16 +458,16 @@ void ProgressManagerPrivate::disconnectApplicationTask()
void ProgressManagerPrivate::updateSummaryProgressBar() void ProgressManagerPrivate::updateSummaryProgressBar()
{ {
m_summaryProgressBar->setError(m_progressView->hasError()); m_summaryProgressBar->setError(hasError());
updateVisibility(); updateVisibility();
if (m_runningTasks.isEmpty()) { if (m_runningTasks.isEmpty()) {
m_summaryProgressBar->setFinished(true); m_summaryProgressBar->setFinished(true);
if (m_progressView->isEmpty() || m_progressView->isFading()) if (m_taskList.isEmpty() || isLastFading())
fadeAway(); fadeAwaySummaryProgress();
return; return;
} }
stopFade(); stopFadeOfSummaryProgress();
m_summaryProgressBar->setFinished(false); m_summaryProgressBar->setFinished(false);
QMapIterator<QFutureWatcher<void> *, QString> it(m_runningTasks); QMapIterator<QFutureWatcher<void> *, QString> it(m_runningTasks);
@@ -460,17 +484,17 @@ void ProgressManagerPrivate::updateSummaryProgressBar()
m_summaryProgressBar->setValue(value); m_summaryProgressBar->setValue(value);
} }
void ProgressManagerPrivate::fadeAway() void ProgressManagerPrivate::fadeAwaySummaryProgress()
{ {
stopFade(); stopFadeOfSummaryProgress();
m_opacityAnimation = new QPropertyAnimation(m_opacityEffect, "opacity"); m_opacityAnimation = new QPropertyAnimation(m_opacityEffect, "opacity");
m_opacityAnimation->setDuration(Utils::StyleHelper::progressFadeAnimationDuration); m_opacityAnimation->setDuration(Utils::StyleHelper::progressFadeAnimationDuration);
m_opacityAnimation->setEndValue(0.); m_opacityAnimation->setEndValue(0.);
connect(m_opacityAnimation, SIGNAL(finished()), this, SLOT(fadeFinished())); connect(m_opacityAnimation, SIGNAL(finished()), this, SLOT(summaryProgressFinishedFading()));
m_opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped); m_opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
} }
void ProgressManagerPrivate::stopFade() void ProgressManagerPrivate::stopFadeOfSummaryProgress()
{ {
if (m_opacityAnimation) { if (m_opacityAnimation) {
m_opacityAnimation->stop(); m_opacityAnimation->stop();
@@ -479,10 +503,100 @@ void ProgressManagerPrivate::stopFade()
} }
} }
bool ProgressManagerPrivate::hasError() const
{
foreach (FutureProgress *progress, m_taskList)
if (progress->hasError())
return true;
return false;
}
bool ProgressManagerPrivate::isLastFading() const
{
if (m_taskList.isEmpty())
return false;
foreach (FutureProgress *progress, m_taskList) {
if (!progress->isFading()) // we still have progress bars that are not fading
return false;
}
return true;
}
void ProgressManagerPrivate::slotRemoveTask()
{
FutureProgress *progress = qobject_cast<FutureProgress *>(sender());
QTC_ASSERT(progress, return);
QString type = progress->type();
removeTask(progress);
removeOldTasks(type, true);
}
void ProgressManagerPrivate::removeOldTasks(const QString &type, bool keepOne)
{
bool firstFound = !keepOne; // start with false if we want to keep one
QList<FutureProgress *>::iterator i = m_taskList.end();
while (i != m_taskList.begin()) {
--i;
if ((*i)->type() == type) {
if (firstFound && ((*i)->future().isFinished() || (*i)->future().isCanceled())) {
deleteTask(*i);
i = m_taskList.erase(i);
}
firstFound = true;
}
}
}
void ProgressManagerPrivate::removeOneOldTask()
{
if (m_taskList.isEmpty())
return;
// look for oldest ended process
for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
if ((*i)->future().isFinished()) {
deleteTask(*i);
i = m_taskList.erase(i);
return;
}
}
// no ended process, look for a task type with multiple running tasks and remove the oldest one
for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
QString type = (*i)->type();
int taskCount = 0;
foreach (FutureProgress *p, m_taskList)
if (p->type() == type)
++taskCount;
if (taskCount > 1) { // don't care for optimizations it's only a handful of entries
deleteTask(*i);
i = m_taskList.erase(i);
return;
}
}
// no ended process, no type with multiple processes, just remove the oldest task
FutureProgress *task = m_taskList.takeFirst();
deleteTask(task);
}
void ProgressManagerPrivate::removeTask(FutureProgress *task)
{
m_taskList.removeAll(task);
deleteTask(task);
}
void ProgressManagerPrivate::deleteTask(FutureProgress *progress)
{
m_progressView->removeProgressWidget(progress);
progress->hide();
progress->deleteLater();
}
void ProgressManagerPrivate::updateVisibility() void ProgressManagerPrivate::updateVisibility()
{ {
m_progressView->setVisible(m_progressViewPinned || m_hovered || m_progressView->isHovered()); m_progressView->setVisible(m_progressViewPinned || m_hovered || m_progressView->isHovered());
m_summaryProgressBar->setVisible((!m_runningTasks.isEmpty() || !m_progressView->isEmpty()) m_summaryProgressBar->setVisible((!m_runningTasks.isEmpty() || !m_taskList.isEmpty())
&& !m_progressViewPinned); && !m_progressViewPinned);
} }
@@ -491,7 +605,7 @@ void ProgressManagerPrivate::updateVisibilityWithDelay()
QTimer::singleShot(150, this, SLOT(updateVisibility())); QTimer::singleShot(150, this, SLOT(updateVisibility()));
} }
void ProgressManagerPrivate::fadeFinished() void ProgressManagerPrivate::summaryProgressFinishedFading()
{ {
m_summaryProgressBar->setVisible(false); m_summaryProgressBar->setVisible(false);
m_opacityEffect->setOpacity(1.); m_opacityEffect->setOpacity(1.);

View File

@@ -77,17 +77,27 @@ private slots:
void setApplicationProgressVisible(bool visible); void setApplicationProgressVisible(bool visible);
void disconnectApplicationTask(); void disconnectApplicationTask();
void updateSummaryProgressBar(); void updateSummaryProgressBar();
void fadeAway(); void fadeAwaySummaryProgress();
void fadeFinished(); void summaryProgressFinishedFading();
void progressDetailsToggled(bool checked); void progressDetailsToggled(bool checked);
void updateVisibility(); void updateVisibility();
void updateVisibilityWithDelay(); void updateVisibilityWithDelay();
void slotRemoveTask();
private: private:
void initInternal(); void initInternal();
void stopFade(); void stopFadeOfSummaryProgress();
bool hasError() const;
bool isLastFading() const;
void removeOldTasks(const QString &type, bool keepOne = false);
void removeOneOldTask();
void removeTask(FutureProgress *task);
void deleteTask(FutureProgress *task);
QPointer<ProgressView> m_progressView; QPointer<ProgressView> m_progressView;
QList<FutureProgress *> m_taskList;
QMap<QFutureWatcher<void> *, QString> m_runningTasks; QMap<QFutureWatcher<void> *, QString> m_runningTasks;
QFutureWatcher<void> *m_applicationTask; QFutureWatcher<void> *m_applicationTask;
Core::StatusBarWidget *m_statusBarWidgetContainer; Core::StatusBarWidget *m_statusBarWidgetContainer;

View File

@@ -28,9 +28,6 @@
****************************************************************************/ ****************************************************************************/
#include "progressview.h" #include "progressview.h"
#include "futureprogress.h"
#include <utils/qtcassert.h>
#include <QEvent> #include <QEvent>
#include <QVBoxLayout> #include <QVBoxLayout>
@@ -53,57 +50,16 @@ ProgressView::ProgressView(QWidget *parent)
ProgressView::~ProgressView() ProgressView::~ProgressView()
{ {
qDeleteAll(m_taskList);
m_taskList.clear();
} }
FutureProgress *ProgressView::addTask(const QFuture<void> &future, void ProgressView::addProgressWidget(QWidget *widget)
const QString &title,
const QString &type,
ProgressManager::ProgressFlags flags)
{ {
removeOldTasks(type); m_layout->insertWidget(0, widget);
if (m_taskList.size() == 10)
removeOneOldTask();
FutureProgress *progress = new FutureProgress(this);
progress->setTitle(title);
progress->setFuture(future);
m_layout->insertWidget(0, progress);
m_taskList.append(progress);
progress->setType(type);
if (flags.testFlag(ProgressManager::KeepOnFinish))
progress->setKeepOnFinish(FutureProgress::KeepOnFinishTillUserInteraction);
else
progress->setKeepOnFinish(FutureProgress::HideOnFinish);
connect(progress, SIGNAL(hasErrorChanged()), this, SIGNAL(hasErrorChanged()));
connect(progress, SIGNAL(removeMe()), this, SLOT(slotRemoveTask()));
connect(progress, SIGNAL(fadeStarted()), this, SLOT(checkForLastProgressFading()));
return progress;
} }
bool ProgressView::hasError() const void ProgressView::removeProgressWidget(QWidget *widget)
{ {
foreach (FutureProgress *progress, m_taskList) m_layout->removeWidget(widget);
if (progress->hasError())
return true;
return false;
}
bool ProgressView::isFading() const
{
if (m_taskList.isEmpty())
return false;
foreach (FutureProgress *progress, m_taskList) {
if (!progress->isFading()) // we still have progress bars that are not fading, do nothing
return false;
}
return true;
}
bool ProgressView::isEmpty() const
{
return m_taskList.isEmpty();
} }
bool ProgressView::isHovered() const bool ProgressView::isHovered() const
@@ -146,29 +102,6 @@ bool ProgressView::eventFilter(QObject *obj, QEvent *event)
return false; return false;
} }
void ProgressView::removeOldTasks(const QString &type, bool keepOne)
{
bool firstFound = !keepOne; // start with false if we want to keep one
QList<FutureProgress *>::iterator i = m_taskList.end();
while (i != m_taskList.begin()) {
--i;
if ((*i)->type() == type) {
if (firstFound && ((*i)->future().isFinished() || (*i)->future().isCanceled())) {
deleteTask(*i);
i = m_taskList.erase(i);
}
firstFound = true;
}
}
}
void ProgressView::deleteTask(FutureProgress *progress)
{
layout()->removeWidget(progress);
progress->hide();
progress->deleteLater();
}
void ProgressView::reposition() void ProgressView::reposition()
{ {
if (!parentWidget() || !m_referenceWidget) if (!parentWidget() || !m_referenceWidget)
@@ -177,57 +110,3 @@ void ProgressView::reposition()
m_referenceWidget->mapTo(parentWidget(), m_referenceWidget->rect().topRight()); m_referenceWidget->mapTo(parentWidget(), m_referenceWidget->rect().topRight());
move(topRightReferenceInParent - rect().bottomRight()); move(topRightReferenceInParent - rect().bottomRight());
} }
void ProgressView::removeOneOldTask()
{
if (m_taskList.isEmpty())
return;
// look for oldest ended process
for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
if ((*i)->future().isFinished()) {
deleteTask(*i);
i = m_taskList.erase(i);
return;
}
}
// no ended process, look for a task type with multiple running tasks and remove the oldest one
for (QList<FutureProgress *>::iterator i = m_taskList.begin(); i != m_taskList.end(); ++i) {
QString type = (*i)->type();
int taskCount = 0;
foreach (FutureProgress *p, m_taskList)
if (p->type() == type)
++taskCount;
if (taskCount > 1) { // don't care for optimizations it's only a handful of entries
deleteTask(*i);
i = m_taskList.erase(i);
return;
}
}
// no ended process, no type with multiple processes, just remove the oldest task
FutureProgress *task = m_taskList.takeFirst();
deleteTask(task);
}
void ProgressView::removeTask(FutureProgress *task)
{
m_taskList.removeAll(task);
deleteTask(task);
}
void ProgressView::slotRemoveTask()
{
FutureProgress *progress = qobject_cast<FutureProgress *>(sender());
QTC_ASSERT(progress, return);
QString type = progress->type();
removeTask(progress);
removeOldTasks(type, true);
}
void ProgressView::checkForLastProgressFading()
{
if (isEmpty() || isFading())
emit fadeOfLastProgressStarted();
}

View File

@@ -32,7 +32,6 @@
#include "progressmanager.h" #include "progressmanager.h"
#include <QFuture>
#include <QWidget> #include <QWidget>
@@ -42,8 +41,6 @@ QT_END_NAMESPACE
namespace Core { namespace Core {
class FutureProgress;
namespace Internal { namespace Internal {
class ProgressView : public QWidget class ProgressView : public QWidget
@@ -54,15 +51,9 @@ public:
ProgressView(QWidget *parent = 0); ProgressView(QWidget *parent = 0);
~ProgressView(); ~ProgressView();
/** The returned FutureProgress instance is guaranteed to live till next main loop event processing (deleteLater). */ void addProgressWidget(QWidget *widget);
FutureProgress *addTask(const QFuture<void> &future, void removeProgressWidget(QWidget *widget);
const QString &title,
const QString &type,
ProgressManager::ProgressFlags flags);
bool hasError() const;
bool isFading() const;
bool isEmpty() const;
bool isHovered() const; bool isHovered() const;
void setReferenceWidget(QWidget *widget); void setReferenceWidget(QWidget *widget);
@@ -72,23 +63,12 @@ protected:
bool eventFilter(QObject *obj, QEvent *event); bool eventFilter(QObject *obj, QEvent *event);
signals: signals:
void hasErrorChanged();
void fadeOfLastProgressStarted();
void hoveredChanged(bool hovered); void hoveredChanged(bool hovered);
private slots:
void slotRemoveTask();
void checkForLastProgressFading();
private: private:
void removeOldTasks(const QString &type, bool keepOne = false);
void removeOneOldTask();
void removeTask(FutureProgress *task);
void deleteTask(FutureProgress *task);
void reposition(); void reposition();
QVBoxLayout *m_layout; QVBoxLayout *m_layout;
QList<FutureProgress *> m_taskList;
QWidget *m_referenceWidget; QWidget *m_referenceWidget;
bool m_hovered; bool m_hovered;
}; };