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 "progressbar.h"
#include "progressview.h"
@@ -267,8 +268,6 @@ ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
m_hovered(false)
{
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
connect(m_progressView, SIGNAL(hoveredChanged(bool)), this, SLOT(updateVisibilityWithDelay()));
connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(cancelAllRunningTasks()));
@@ -276,6 +275,8 @@ ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
ProgressManagerPrivate::~ProgressManagerPrivate()
{
qDeleteAll(m_taskList);
m_taskList.clear();
ExtensionSystem::PluginManager::removeObject(m_statusBarWidgetContainer);
delete m_statusBarWidgetContainer;
cleanup();
@@ -379,11 +380,15 @@ void ProgressManagerPrivate::cancelAllRunningTasks()
FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, const QString &title,
const QString &type, ProgressFlags flags)
{
// watch
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
m_runningTasks.insert(watcher, type);
connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(updateSummaryProgressBar()));
connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(updateSummaryProgressBar()));
connect(watcher, SIGNAL(finished()), this, SLOT(taskFinished()));
watcher->setFuture(future);
// handle application task
if (flags & ShowInApplicationIcon) {
if (m_applicationTask)
disconnectApplicationTask();
@@ -396,9 +401,28 @@ FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, con
this, SLOT(setApplicationProgressValue(int)));
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);
return m_progressView->addTask(future, title, type, flags);
return progress;
}
ProgressView *ProgressManagerPrivate::progressView()
@@ -434,16 +458,16 @@ void ProgressManagerPrivate::disconnectApplicationTask()
void ProgressManagerPrivate::updateSummaryProgressBar()
{
m_summaryProgressBar->setError(m_progressView->hasError());
m_summaryProgressBar->setError(hasError());
updateVisibility();
if (m_runningTasks.isEmpty()) {
m_summaryProgressBar->setFinished(true);
if (m_progressView->isEmpty() || m_progressView->isFading())
fadeAway();
if (m_taskList.isEmpty() || isLastFading())
fadeAwaySummaryProgress();
return;
}
stopFade();
stopFadeOfSummaryProgress();
m_summaryProgressBar->setFinished(false);
QMapIterator<QFutureWatcher<void> *, QString> it(m_runningTasks);
@@ -460,17 +484,17 @@ void ProgressManagerPrivate::updateSummaryProgressBar()
m_summaryProgressBar->setValue(value);
}
void ProgressManagerPrivate::fadeAway()
void ProgressManagerPrivate::fadeAwaySummaryProgress()
{
stopFade();
stopFadeOfSummaryProgress();
m_opacityAnimation = new QPropertyAnimation(m_opacityEffect, "opacity");
m_opacityAnimation->setDuration(Utils::StyleHelper::progressFadeAnimationDuration);
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);
}
void ProgressManagerPrivate::stopFade()
void ProgressManagerPrivate::stopFadeOfSummaryProgress()
{
if (m_opacityAnimation) {
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()
{
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);
}
@@ -491,7 +605,7 @@ void ProgressManagerPrivate::updateVisibilityWithDelay()
QTimer::singleShot(150, this, SLOT(updateVisibility()));
}
void ProgressManagerPrivate::fadeFinished()
void ProgressManagerPrivate::summaryProgressFinishedFading()
{
m_summaryProgressBar->setVisible(false);
m_opacityEffect->setOpacity(1.);

View File

@@ -77,17 +77,27 @@ private slots:
void setApplicationProgressVisible(bool visible);
void disconnectApplicationTask();
void updateSummaryProgressBar();
void fadeAway();
void fadeFinished();
void fadeAwaySummaryProgress();
void summaryProgressFinishedFading();
void progressDetailsToggled(bool checked);
void updateVisibility();
void updateVisibilityWithDelay();
void slotRemoveTask();
private:
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;
QList<FutureProgress *> m_taskList;
QMap<QFutureWatcher<void> *, QString> m_runningTasks;
QFutureWatcher<void> *m_applicationTask;
Core::StatusBarWidget *m_statusBarWidgetContainer;

View File

@@ -28,9 +28,6 @@
****************************************************************************/
#include "progressview.h"
#include "futureprogress.h"
#include <utils/qtcassert.h>
#include <QEvent>
#include <QVBoxLayout>
@@ -53,57 +50,16 @@ ProgressView::ProgressView(QWidget *parent)
ProgressView::~ProgressView()
{
qDeleteAll(m_taskList);
m_taskList.clear();
}
FutureProgress *ProgressView::addTask(const QFuture<void> &future,
const QString &title,
const QString &type,
ProgressManager::ProgressFlags flags)
void ProgressView::addProgressWidget(QWidget *widget)
{
removeOldTasks(type);
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;
m_layout->insertWidget(0, widget);
}
bool ProgressView::hasError() const
void ProgressView::removeProgressWidget(QWidget *widget)
{
foreach (FutureProgress *progress, m_taskList)
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();
m_layout->removeWidget(widget);
}
bool ProgressView::isHovered() const
@@ -146,29 +102,6 @@ bool ProgressView::eventFilter(QObject *obj, QEvent *event)
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()
{
if (!parentWidget() || !m_referenceWidget)
@@ -177,57 +110,3 @@ void ProgressView::reposition()
m_referenceWidget->mapTo(parentWidget(), m_referenceWidget->rect().topRight());
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 <QFuture>
#include <QWidget>
@@ -42,8 +41,6 @@ QT_END_NAMESPACE
namespace Core {
class FutureProgress;
namespace Internal {
class ProgressView : public QWidget
@@ -54,15 +51,9 @@ public:
ProgressView(QWidget *parent = 0);
~ProgressView();
/** The returned FutureProgress instance is guaranteed to live till next main loop event processing (deleteLater). */
FutureProgress *addTask(const QFuture<void> &future,
const QString &title,
const QString &type,
ProgressManager::ProgressFlags flags);
void addProgressWidget(QWidget *widget);
void removeProgressWidget(QWidget *widget);
bool hasError() const;
bool isFading() const;
bool isEmpty() const;
bool isHovered() const;
void setReferenceWidget(QWidget *widget);
@@ -72,23 +63,12 @@ protected:
bool eventFilter(QObject *obj, QEvent *event);
signals:
void hasErrorChanged();
void fadeOfLastProgressStarted();
void hoveredChanged(bool hovered);
private slots:
void slotRemoveTask();
void checkForLastProgressFading();
private:
void removeOldTasks(const QString &type, bool keepOne = false);
void removeOneOldTask();
void removeTask(FutureProgress *task);
void deleteTask(FutureProgress *task);
void reposition();
QVBoxLayout *m_layout;
QList<FutureProgress *> m_taskList;
QWidget *m_referenceWidget;
bool m_hovered;
};