forked from qt-creator/qt-creator
Move progress indicators out of mode bar.
This both allows the mode bar to be hidden optionally, and can give the progress information a bit more room (e.g. for titles). Progress information can either be shown in "pop up" windows in the lower left corner of the main window (hiding window contents below), or in a summary progress bar in the bottom right corner of the status bar. Hovering the summary progress bar temporarily pops up the detailed progress information. Keyboard can be used to switch between the two views. Change-Id: Ic6d6ab4fd43906e84b480c8ddf8eae5f5852e1f3 Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
@@ -30,10 +30,13 @@
|
||||
#include "futureprogress.h"
|
||||
#include "progressbar.h"
|
||||
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFutureWatcher>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPainter>
|
||||
#include <QSequentialAnimationGroup>
|
||||
#include <QTimer>
|
||||
|
||||
@@ -66,13 +69,14 @@ public:
|
||||
FutureProgress::KeepOnFinishType m_keep;
|
||||
bool m_waitingForUserInteraction;
|
||||
FutureProgress *m_q;
|
||||
bool m_fadeStarting;
|
||||
bool m_isFading;
|
||||
};
|
||||
|
||||
FutureProgressPrivate::FutureProgressPrivate(FutureProgress *q) :
|
||||
m_progress(new Internal::ProgressBar), m_widget(0), m_widgetLayout(new QHBoxLayout),
|
||||
m_keep(FutureProgress::HideOnFinish), m_waitingForUserInteraction(false),
|
||||
m_q(q), m_isFading(false)
|
||||
m_q(q), m_fadeStarting(false), m_isFading(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -218,17 +222,19 @@ void FutureProgress::setFinished()
|
||||
|
||||
d->m_progress->setFinished(true);
|
||||
|
||||
if (d->m_watcher.future().isCanceled())
|
||||
if (d->m_watcher.future().isCanceled()) {
|
||||
d->m_progress->setError(true);
|
||||
else
|
||||
emit hasErrorChanged();
|
||||
} else {
|
||||
d->m_progress->setError(false);
|
||||
}
|
||||
emit finished();
|
||||
d->tryToFadeAway();
|
||||
}
|
||||
|
||||
void FutureProgressPrivate::tryToFadeAway()
|
||||
{
|
||||
if (m_isFading)
|
||||
if (m_fadeStarting)
|
||||
return;
|
||||
if (m_keep == FutureProgress::KeepOnFinishTillUserInteraction
|
||||
|| (m_keep == FutureProgress::HideOnFinish && m_progress->hasError())) {
|
||||
@@ -236,10 +242,10 @@ void FutureProgressPrivate::tryToFadeAway()
|
||||
//eventfilter is needed to get user interaction
|
||||
//events to start QTimer::singleShot later
|
||||
qApp->installEventFilter(m_q);
|
||||
m_isFading = true;
|
||||
m_fadeStarting = true;
|
||||
} else if (m_keep == FutureProgress::HideOnFinish) {
|
||||
QTimer::singleShot(shortNotificationTimeout, this, SLOT(fadeAway()));
|
||||
m_isFading = true;
|
||||
m_fadeStarting = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +294,13 @@ void FutureProgress::mousePressEvent(QMouseEvent *event)
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void FutureProgress::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
QLinearGradient grad = Utils::StyleHelper::statusBarGradient(rect());
|
||||
p.fillRect(rect(), grad);
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool FutureProgress::hasError() const
|
||||
Returns the error state of this progress indicator.
|
||||
@@ -328,15 +341,27 @@ QWidget *FutureProgress::widget() const
|
||||
return d->m_widget;
|
||||
}
|
||||
|
||||
bool FutureProgress::isFading() const
|
||||
{
|
||||
return d->m_isFading;
|
||||
}
|
||||
|
||||
QSize FutureProgress::sizeHint() const
|
||||
{
|
||||
return QSize(100, minimumHeight());
|
||||
}
|
||||
|
||||
void FutureProgressPrivate::fadeAway()
|
||||
{
|
||||
m_isFading = true;
|
||||
|
||||
QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect;
|
||||
opacityEffect->setOpacity(1.);
|
||||
m_q->setGraphicsEffect(opacityEffect);
|
||||
|
||||
QSequentialAnimationGroup *group = new QSequentialAnimationGroup(this);
|
||||
QPropertyAnimation *animation = new QPropertyAnimation(opacityEffect, "opacity");
|
||||
animation->setDuration(600);
|
||||
animation->setDuration(Utils::StyleHelper::progressFadeAnimationDuration);
|
||||
animation->setEndValue(0.);
|
||||
group->addAnimation(animation);
|
||||
animation = new QPropertyAnimation(m_q, "maximumHeight");
|
||||
@@ -345,9 +370,10 @@ void FutureProgressPrivate::fadeAway()
|
||||
animation->setStartValue(m_q->sizeHint().height());
|
||||
animation->setEndValue(0.0);
|
||||
group->addAnimation(animation);
|
||||
group->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
|
||||
connect(group, SIGNAL(finished()), m_q, SIGNAL(removeMe()));
|
||||
group->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
emit m_q->fadeStarted();
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -71,14 +71,21 @@ public:
|
||||
void setWidget(QWidget *widget);
|
||||
QWidget *widget() const;
|
||||
|
||||
bool isFading() const;
|
||||
|
||||
QSize sizeHint() const;
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
void finished();
|
||||
void canceled();
|
||||
void removeMe();
|
||||
void hasErrorChanged();
|
||||
void fadeStarted();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void paintEvent(QPaintEvent *);
|
||||
|
||||
private slots:
|
||||
void updateToolTip(const QString &);
|
||||
@@ -90,6 +97,7 @@ private slots:
|
||||
void setProgressText(const QString &text);
|
||||
|
||||
private:
|
||||
friend class FutureProgressPrivate; // for sending signal
|
||||
FutureProgressPrivate *d;
|
||||
};
|
||||
|
||||
|
||||
@@ -44,8 +44,9 @@ using namespace Core::Internal;
|
||||
#define CANCELBUTTON_SIZE 15
|
||||
|
||||
ProgressBar::ProgressBar(QWidget *parent)
|
||||
: QWidget(parent), m_minimum(1), m_maximum(100), m_value(1), m_cancelButtonFader(0),
|
||||
m_finished(false), m_error(false)
|
||||
: QWidget(parent), m_titleVisible(true), m_separatorVisible(true), m_progressHeight(0),
|
||||
m_minimum(1), m_maximum(100), m_value(1), m_cancelButtonFader(0), m_finished(false),
|
||||
m_error(false)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
setMouseTracking(true);
|
||||
@@ -131,6 +132,45 @@ void ProgressBar::setTitle(const QString &title)
|
||||
update();
|
||||
}
|
||||
|
||||
void ProgressBar::setTitleVisible(bool visible)
|
||||
{
|
||||
if (m_titleVisible == visible)
|
||||
return;
|
||||
m_titleVisible = visible;
|
||||
update();
|
||||
}
|
||||
|
||||
bool ProgressBar::isTitleVisible() const
|
||||
{
|
||||
return m_titleVisible;
|
||||
}
|
||||
|
||||
void ProgressBar::setSeparatorVisible(bool visible)
|
||||
{
|
||||
if (m_separatorVisible == visible)
|
||||
return;
|
||||
m_separatorVisible = visible;
|
||||
update();
|
||||
}
|
||||
|
||||
bool ProgressBar::isSeparatorVisible() const
|
||||
{
|
||||
return m_separatorVisible;
|
||||
}
|
||||
|
||||
void ProgressBar::setCancelEnabled(bool enabled)
|
||||
{
|
||||
if (m_cancelEnabled == enabled)
|
||||
return;
|
||||
m_cancelEnabled = enabled;
|
||||
update();
|
||||
}
|
||||
|
||||
bool ProgressBar::isCancelEnabled() const
|
||||
{
|
||||
return m_cancelEnabled;
|
||||
}
|
||||
|
||||
void ProgressBar::setError(bool on)
|
||||
{
|
||||
m_error = on;
|
||||
@@ -149,19 +189,22 @@ namespace { const int INDENT = 6; }
|
||||
|
||||
void ProgressBar::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QFont boldFont(font());
|
||||
boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize());
|
||||
boldFont.setBold(true);
|
||||
QFontMetrics fm(boldFont);
|
||||
int h = fm.height();
|
||||
QRect rect(INDENT - 1, h+8, size().width()-2*INDENT + 1, m_progressHeight-1);
|
||||
QRect cancelRect(rect.adjusted(rect.width() - CANCELBUTTON_SIZE, 1, -1, 0));
|
||||
if (m_cancelEnabled) {
|
||||
QFont boldFont(font());
|
||||
boldFont.setPointSizeF(Utils::StyleHelper::sidebarFontSize());
|
||||
boldFont.setBold(true);
|
||||
QFontMetrics fm(boldFont);
|
||||
int titleHeight = m_titleVisible ? fm.height() : 0;
|
||||
int separatorHeight = m_separatorVisible ? 2 : 0;
|
||||
QRect rect(INDENT - 1, titleHeight + separatorHeight + 6, size().width()-2*INDENT + 1, m_progressHeight-1);
|
||||
QRect cancelRect(rect.adjusted(rect.width() - CANCELBUTTON_SIZE, 1, -1, 0));
|
||||
|
||||
if (event->modifiers() == Qt::NoModifier
|
||||
&& cancelRect.contains(event->pos())) {
|
||||
event->accept();
|
||||
emit clicked();
|
||||
return;
|
||||
if (event->modifiers() == Qt::NoModifier
|
||||
&& cancelRect.contains(event->pos())) {
|
||||
event->accept();
|
||||
emit clicked();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
@@ -198,37 +241,43 @@ void ProgressBar::paintEvent(QPaintEvent *)
|
||||
p.setFont(boldFont);
|
||||
QFontMetrics fm(boldFont);
|
||||
|
||||
int titleHeight = m_titleVisible ? fm.height() : 0;
|
||||
|
||||
// Draw separator
|
||||
int h = fm.height();
|
||||
p.setPen(Utils::StyleHelper::sidebarShadow());
|
||||
p.drawLine(0,0, size().width(), 0);
|
||||
int separatorHeight = m_separatorVisible ? 2 : 0;
|
||||
if (m_separatorVisible) {
|
||||
p.setPen(Utils::StyleHelper::sidebarShadow());
|
||||
p.drawLine(0,0, size().width(), 0);
|
||||
|
||||
p.setPen(Utils::StyleHelper::sidebarHighlight());
|
||||
p.drawLine(1, 1, size().width(), 1);
|
||||
p.setPen(Utils::StyleHelper::sidebarHighlight());
|
||||
p.drawLine(1, 1, size().width(), 1);
|
||||
}
|
||||
|
||||
QRect textBounds = fm.boundingRect(m_title);
|
||||
textBounds.moveCenter(rect().center());
|
||||
int alignment = Qt::AlignHCenter;
|
||||
if (m_titleVisible) {
|
||||
QRect textBounds = fm.boundingRect(m_title);
|
||||
textBounds.moveCenter(rect().center());
|
||||
int alignment = Qt::AlignHCenter;
|
||||
|
||||
int textSpace = rect().width() - 8;
|
||||
// If there is not enough room when centered, we left align and
|
||||
// elide the text
|
||||
QString elidedtitle = fm.elidedText(m_title, Qt::ElideRight, textSpace);
|
||||
int textSpace = rect().width() - 8;
|
||||
// If there is not enough room when centered, we left align and
|
||||
// elide the text
|
||||
QString elidedtitle = fm.elidedText(m_title, Qt::ElideRight, textSpace);
|
||||
|
||||
QRect textRect = rect().adjusted(3, 1, -3, 0);
|
||||
textRect.setHeight(h+5);
|
||||
QRect textRect = rect().adjusted(3, separatorHeight - 1, -3, 0);
|
||||
textRect.setHeight(titleHeight+5);
|
||||
|
||||
p.setPen(QColor(0, 0, 0, 120));
|
||||
p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle);
|
||||
p.translate(0, -1);
|
||||
p.setPen(Utils::StyleHelper::panelTextColor());
|
||||
p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle);
|
||||
p.translate(0, 1);
|
||||
p.setPen(QColor(0, 0, 0, 120));
|
||||
p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle);
|
||||
p.translate(0, -1);
|
||||
p.setPen(Utils::StyleHelper::panelTextColor());
|
||||
p.drawText(textRect, alignment | Qt::AlignBottom, elidedtitle);
|
||||
p.translate(0, 1);
|
||||
}
|
||||
|
||||
m_progressHeight = PROGRESSBAR_HEIGHT;
|
||||
m_progressHeight += ((m_progressHeight % 2) + 1) % 2; // make odd
|
||||
// draw outer rect
|
||||
QRect rect(INDENT - 1, h+6, size().width()-2*INDENT + 1, m_progressHeight-1);
|
||||
QRect rect(INDENT - 1, titleHeight + separatorHeight + 4, size().width()-2*INDENT + 1, m_progressHeight-1);
|
||||
p.setPen(Utils::StyleHelper::panelTextColor());
|
||||
Utils::StyleHelper::drawCornerImage(bar, &p, rect, 4, 2, 3, 2);
|
||||
|
||||
@@ -272,31 +321,33 @@ void ProgressBar::paintEvent(QPaintEvent *)
|
||||
p.drawPoint(inner.bottomLeft());
|
||||
p.drawPoint(inner.bottomRight());
|
||||
|
||||
// Draw cancel button
|
||||
p.setOpacity(m_cancelButtonFader);
|
||||
if (m_cancelEnabled) {
|
||||
// Draw cancel button
|
||||
p.setOpacity(m_cancelButtonFader);
|
||||
|
||||
if (value() < maximum() && !m_error) {
|
||||
QRect cancelRect(rect.adjusted(rect.width() - CANCELBUTTON_SIZE, 1, -1, 0));
|
||||
bool hover = cancelRect.contains(mapFromGlobal(QCursor::pos()));
|
||||
QLinearGradient grad(cancelRect.topLeft(), cancelRect.bottomLeft());
|
||||
int intensity = hover ? 90 : 70;
|
||||
QColor buttonColor(intensity, intensity, intensity, 255);
|
||||
grad.setColorAt(0, buttonColor.lighter(130));
|
||||
grad.setColorAt(1, buttonColor.darker(130));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(grad);
|
||||
p.drawRect(cancelRect.adjusted(1, 1, -1, -1));
|
||||
if (value() < maximum() && !m_error) {
|
||||
QRect cancelRect(rect.adjusted(rect.width() - CANCELBUTTON_SIZE, 1, -1, 0));
|
||||
bool hover = cancelRect.contains(mapFromGlobal(QCursor::pos()));
|
||||
QLinearGradient grad(cancelRect.topLeft(), cancelRect.bottomLeft());
|
||||
int intensity = hover ? 90 : 70;
|
||||
QColor buttonColor(intensity, intensity, intensity, 255);
|
||||
grad.setColorAt(0, buttonColor.lighter(130));
|
||||
grad.setColorAt(1, buttonColor.darker(130));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(grad);
|
||||
p.drawRect(cancelRect.adjusted(1, 1, -1, -1));
|
||||
|
||||
p.setPen(QPen(QColor(0, 0, 0, 30)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(0,1), cancelRect.bottomLeft() + QPoint(0,-1));
|
||||
p.setPen(QPen(QColor(0, 0, 0, 120)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(1,1), cancelRect.bottomLeft() + QPoint(1,-1));
|
||||
p.setPen(QPen(QColor(255, 255, 255, 30)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(2,1), cancelRect.bottomLeft() + QPoint(2,-1));
|
||||
p.setPen(QPen(hover ? Utils::StyleHelper::panelTextColor() : QColor(180, 180, 180), 1));
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.translate(0.5, 0.5);
|
||||
p.drawLine(cancelRect.center()+QPoint(-1,-2), cancelRect.center()+QPoint(+3,+2));
|
||||
p.drawLine(cancelRect.center()+QPoint(+3,-2), cancelRect.center()+QPoint(-1,+2));
|
||||
p.setPen(QPen(QColor(0, 0, 0, 30)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(0,1), cancelRect.bottomLeft() + QPoint(0,-1));
|
||||
p.setPen(QPen(QColor(0, 0, 0, 120)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(1,1), cancelRect.bottomLeft() + QPoint(1,-1));
|
||||
p.setPen(QPen(QColor(255, 255, 255, 30)));
|
||||
p.drawLine(cancelRect.topLeft() + QPoint(2,1), cancelRect.bottomLeft() + QPoint(2,-1));
|
||||
p.setPen(QPen(hover ? Utils::StyleHelper::panelTextColor() : QColor(180, 180, 180), 1));
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.translate(0.5, 0.5);
|
||||
p.drawLine(cancelRect.center()+QPoint(-1,-2), cancelRect.center()+QPoint(+3,+2));
|
||||
p.drawLine(cancelRect.center()+QPoint(+3,-2), cancelRect.center()+QPoint(-1,+2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,12 @@ public:
|
||||
|
||||
QString title() const;
|
||||
void setTitle(const QString &title);
|
||||
void setTitleVisible(bool visible);
|
||||
bool isTitleVisible() const;
|
||||
void setSeparatorVisible(bool visible);
|
||||
bool isSeparatorVisible() const;
|
||||
void setCancelEnabled(bool enabled);
|
||||
bool isCancelEnabled() const;
|
||||
void setError(bool on);
|
||||
bool hasError() const;
|
||||
QSize sizeHint() const;
|
||||
@@ -75,6 +81,9 @@ private:
|
||||
QImage bar;
|
||||
QString m_text;
|
||||
QString m_title;
|
||||
bool m_titleVisible;
|
||||
bool m_separatorVisible;
|
||||
bool m_cancelEnabled;
|
||||
int m_progressHeight;
|
||||
int m_minimum;
|
||||
int m_maximum;
|
||||
|
||||
@@ -28,10 +28,28 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "progressmanager_p.h"
|
||||
#include "progressbar.h"
|
||||
#include "progressview.h"
|
||||
#include "../actionmanager/actionmanager.h"
|
||||
#include "../icontext.h"
|
||||
#include "../coreconstants.h"
|
||||
#include "../icore.h"
|
||||
#include "../statusbarwidget.h"
|
||||
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stylehelper.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core::Internal;
|
||||
@@ -243,17 +261,70 @@ using namespace Core::Internal;
|
||||
|
||||
ProgressManagerPrivate::ProgressManagerPrivate(QObject *parent)
|
||||
: ProgressManager(parent),
|
||||
m_applicationTask(0)
|
||||
m_applicationTask(0),
|
||||
m_opacityEffect(new QGraphicsOpacityEffect(this)),
|
||||
m_progressViewPinned(false),
|
||||
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()));
|
||||
}
|
||||
|
||||
ProgressManagerPrivate::~ProgressManagerPrivate()
|
||||
{
|
||||
ExtensionSystem::PluginManager::removeObject(m_statusBarWidgetContainer);
|
||||
delete m_statusBarWidgetContainer;
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::init()
|
||||
{
|
||||
m_statusBarWidgetContainer = new Core::StatusBarWidget;
|
||||
m_statusBarWidget = new QWidget;
|
||||
QHBoxLayout *layout = new QHBoxLayout(m_statusBarWidget);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
m_statusBarWidget->setLayout(layout);
|
||||
m_summaryProgressBar = new ProgressBar(m_statusBarWidget);
|
||||
m_summaryProgressBar->setMinimumWidth(70);
|
||||
m_summaryProgressBar->setTitleVisible(false);
|
||||
m_summaryProgressBar->setSeparatorVisible(false);
|
||||
m_summaryProgressBar->setCancelEnabled(false);
|
||||
m_summaryProgressBar->setGraphicsEffect(m_opacityEffect);
|
||||
m_summaryProgressBar->setVisible(!m_progressViewPinned);
|
||||
layout->addWidget(m_summaryProgressBar);
|
||||
ToggleButton *toggleButton = new ToggleButton(m_statusBarWidget);
|
||||
layout->addWidget(toggleButton);
|
||||
m_statusBarWidgetContainer->setWidget(m_statusBarWidget);
|
||||
m_statusBarWidgetContainer->setPosition(Core::StatusBarWidget::RightCorner);
|
||||
ExtensionSystem::PluginManager::addObject(m_statusBarWidgetContainer);
|
||||
m_statusBarWidget->installEventFilter(this);
|
||||
|
||||
QAction *toggleProgressView = new QAction(tr("Toggle progress details"), this);
|
||||
toggleProgressView->setCheckable(true);
|
||||
toggleProgressView->setChecked(m_progressViewPinned);
|
||||
// we have to set an transparent icon to prevent the tool button to show text
|
||||
QPixmap p(1, 1);
|
||||
p.fill(Qt::transparent);
|
||||
toggleProgressView->setIcon(QIcon(p));
|
||||
Command *cmd = ActionManager::registerAction(toggleProgressView,
|
||||
Id("QtCreator.ToggleProgressDetails"),
|
||||
Context(Constants::C_GLOBAL));
|
||||
cmd->setDefaultKeySequence(QKeySequence(Utils::HostOsInfo::isMacHost()
|
||||
? tr("Ctrl+Shift+0")
|
||||
: tr("Alt+Shift+0")));
|
||||
connect(toggleProgressView, SIGNAL(toggled(bool)), this, SLOT(progressDetailsToggled(bool)));
|
||||
toggleButton->setDefaultAction(cmd->action());
|
||||
|
||||
m_progressView->setVisible(m_progressViewPinned);
|
||||
|
||||
initInternal();
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::cancelTasks(const QString &type)
|
||||
{
|
||||
bool found = false;
|
||||
@@ -271,8 +342,23 @@ void ProgressManagerPrivate::cancelTasks(const QString &type)
|
||||
delete task.key();
|
||||
task = m_runningTasks.erase(task);
|
||||
}
|
||||
if (found)
|
||||
if (found) {
|
||||
updateSummaryProgressBar();
|
||||
emit allTasksFinished(type);
|
||||
}
|
||||
}
|
||||
|
||||
bool ProgressManagerPrivate::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (obj == m_statusBarWidget && event->type() == QEvent::Enter) {
|
||||
m_hovered = true;
|
||||
updateVisibility();
|
||||
} else if (obj == m_statusBarWidget && event->type() == QEvent::Leave) {
|
||||
m_hovered = false;
|
||||
// give the progress view the chance to get the mouse enter event
|
||||
updateVisibilityWithDelay();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::cancelAllRunningTasks()
|
||||
@@ -287,6 +373,7 @@ void ProgressManagerPrivate::cancelAllRunningTasks()
|
||||
++task;
|
||||
}
|
||||
m_runningTasks.clear();
|
||||
updateSummaryProgressBar();
|
||||
}
|
||||
|
||||
FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, const QString &title,
|
||||
@@ -294,6 +381,8 @@ FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, con
|
||||
{
|
||||
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()));
|
||||
if (flags & ShowInApplicationIcon) {
|
||||
if (m_applicationTask)
|
||||
@@ -312,7 +401,7 @@ FutureProgress *ProgressManagerPrivate::addTask(const QFuture<void> &future, con
|
||||
return m_progressView->addTask(future, title, type, flags);
|
||||
}
|
||||
|
||||
QWidget *ProgressManagerPrivate::progressView()
|
||||
ProgressView *ProgressManagerPrivate::progressView()
|
||||
{
|
||||
return m_progressView;
|
||||
}
|
||||
@@ -327,6 +416,7 @@ void ProgressManagerPrivate::taskFinished()
|
||||
QString type = m_runningTasks.value(task);
|
||||
m_runningTasks.remove(task);
|
||||
delete task;
|
||||
updateSummaryProgressBar();
|
||||
|
||||
if (!m_runningTasks.key(type, 0))
|
||||
emit allTasksFinished(type);
|
||||
@@ -341,3 +431,96 @@ void ProgressManagerPrivate::disconnectApplicationTask()
|
||||
setApplicationProgressVisible(false);
|
||||
m_applicationTask = 0;
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::updateSummaryProgressBar()
|
||||
{
|
||||
m_summaryProgressBar->setError(m_progressView->hasError());
|
||||
updateVisibility();
|
||||
if (m_runningTasks.isEmpty()) {
|
||||
m_summaryProgressBar->setFinished(true);
|
||||
if (m_progressView->isEmpty() || m_progressView->isFading())
|
||||
fadeAway();
|
||||
return;
|
||||
}
|
||||
|
||||
stopFade();
|
||||
|
||||
m_summaryProgressBar->setFinished(false);
|
||||
QMapIterator<QFutureWatcher<void> *, QString> it(m_runningTasks);
|
||||
int range = 0;
|
||||
int value = 0;
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QFutureWatcher<void> *watcher = it.key();
|
||||
int min = watcher->progressMinimum();
|
||||
range += watcher->progressMaximum() - min;
|
||||
value += watcher->progressValue() - min;
|
||||
}
|
||||
m_summaryProgressBar->setRange(0, range);
|
||||
m_summaryProgressBar->setValue(value);
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::fadeAway()
|
||||
{
|
||||
stopFade();
|
||||
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()));
|
||||
m_opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::stopFade()
|
||||
{
|
||||
if (m_opacityAnimation) {
|
||||
m_opacityAnimation->stop();
|
||||
m_opacityEffect->setOpacity(1.);
|
||||
delete m_opacityAnimation;
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::updateVisibility()
|
||||
{
|
||||
m_progressView->setVisible(m_progressViewPinned || m_hovered || m_progressView->isHovered());
|
||||
m_summaryProgressBar->setVisible((!m_runningTasks.isEmpty() || !m_progressView->isEmpty())
|
||||
&& !m_progressViewPinned);
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::updateVisibilityWithDelay()
|
||||
{
|
||||
QTimer::singleShot(150, this, SLOT(updateVisibility()));
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::fadeFinished()
|
||||
{
|
||||
m_summaryProgressBar->setVisible(false);
|
||||
m_opacityEffect->setOpacity(1.);
|
||||
}
|
||||
|
||||
void ProgressManagerPrivate::progressDetailsToggled(bool checked)
|
||||
{
|
||||
m_progressViewPinned = checked;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
ToggleButton::ToggleButton(QWidget *parent)
|
||||
: QToolButton(parent)
|
||||
{
|
||||
setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
}
|
||||
|
||||
QSize ToggleButton::sizeHint() const
|
||||
{
|
||||
return QSize(12, 12);
|
||||
}
|
||||
|
||||
void ToggleButton::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QToolButton::paintEvent(event);
|
||||
QPainter p(this);
|
||||
QStyle *s = style();
|
||||
QStyleOption arrowOpt;
|
||||
arrowOpt.initFrom(this);
|
||||
arrowOpt.rect = QRect(rect().center().x() - 3, rect().center().y() - 6, 9, 9);
|
||||
s->drawPrimitive(QStyle::PE_IndicatorArrowUp, &arrowOpt, &p, this);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "progressmanager_p.h"
|
||||
|
||||
void Core::Internal::ProgressManagerPrivate::init()
|
||||
void Core::Internal::ProgressManagerPrivate::initInternal()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,20 @@
|
||||
|
||||
#include "progressmanager.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QList>
|
||||
#include <QFutureWatcher>
|
||||
#include <QList>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QPointer>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QToolButton>
|
||||
|
||||
namespace Core {
|
||||
|
||||
class StatusBarWidget;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class ProgressBar;
|
||||
class ProgressView;
|
||||
|
||||
class ProgressManagerPrivate : public Core::ProgressManager
|
||||
@@ -54,11 +61,14 @@ public:
|
||||
ProgressFlags flags);
|
||||
|
||||
void setApplicationLabel(const QString &text);
|
||||
QWidget *progressView();
|
||||
ProgressView *progressView();
|
||||
|
||||
public slots:
|
||||
void cancelTasks(const QString &type);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
private slots:
|
||||
void taskFinished();
|
||||
void cancelAllRunningTasks();
|
||||
@@ -66,11 +76,36 @@ private slots:
|
||||
void setApplicationProgressValue(int value);
|
||||
void setApplicationProgressVisible(bool visible);
|
||||
void disconnectApplicationTask();
|
||||
void updateSummaryProgressBar();
|
||||
void fadeAway();
|
||||
void fadeFinished();
|
||||
void progressDetailsToggled(bool checked);
|
||||
void updateVisibility();
|
||||
void updateVisibilityWithDelay();
|
||||
|
||||
private:
|
||||
void initInternal();
|
||||
void stopFade();
|
||||
|
||||
QPointer<ProgressView> m_progressView;
|
||||
QMap<QFutureWatcher<void> *, QString> m_runningTasks;
|
||||
QFutureWatcher<void> *m_applicationTask;
|
||||
Core::StatusBarWidget *m_statusBarWidgetContainer;
|
||||
QWidget *m_statusBarWidget;
|
||||
ProgressBar *m_summaryProgressBar;
|
||||
QGraphicsOpacityEffect *m_opacityEffect;
|
||||
QPointer<QPropertyAnimation> m_opacityAnimation;
|
||||
bool m_progressViewPinned;
|
||||
bool m_hovered;
|
||||
};
|
||||
|
||||
class ToggleButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ToggleButton(QWidget *parent);
|
||||
QSize sizeHint() const;
|
||||
void paintEvent(QPaintEvent *event);
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -84,7 +84,7 @@ static inline HWND hwndOfWidget(const QWidget *w)
|
||||
}
|
||||
#endif
|
||||
|
||||
void Core::Internal::ProgressManagerPrivate::init()
|
||||
void Core::Internal::ProgressManagerPrivate::initInternal()
|
||||
{
|
||||
CoInitialize(NULL);
|
||||
HRESULT hRes = CoCreateInstance(CLSID_TaskbarList,
|
||||
@@ -164,7 +164,7 @@ void Core::Internal::ProgressManagerPrivate::setApplicationProgressVisible(bool
|
||||
|
||||
#else
|
||||
|
||||
void Core::Internal::ProgressManagerPrivate::init()
|
||||
void Core::Internal::ProgressManagerPrivate::initInternal()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "progressmanager_p.h"
|
||||
|
||||
void Core::Internal::ProgressManagerPrivate::init()
|
||||
void Core::Internal::ProgressManagerPrivate::initInternal()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -32,18 +32,22 @@
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core::Internal;
|
||||
|
||||
static const int PROGRESS_WIDTH = 100;
|
||||
|
||||
ProgressView::ProgressView(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent), m_referenceWidget(0), m_hovered(false)
|
||||
{
|
||||
m_layout = new QVBoxLayout;
|
||||
setLayout(m_layout);
|
||||
m_layout->setMargin(0);
|
||||
m_layout->setContentsMargins(0, 0, 0, 1);
|
||||
m_layout->setSpacing(0);
|
||||
m_layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
setWindowTitle(tr("Processes"));
|
||||
}
|
||||
|
||||
@@ -59,7 +63,7 @@ FutureProgress *ProgressView::addTask(const QFuture<void> &future,
|
||||
ProgressManager::ProgressFlags flags)
|
||||
{
|
||||
removeOldTasks(type);
|
||||
if (m_taskList.size() == 3)
|
||||
if (m_taskList.size() == 10)
|
||||
removeOneOldTask();
|
||||
FutureProgress *progress = new FutureProgress(this);
|
||||
progress->setTitle(title);
|
||||
@@ -72,10 +76,76 @@ FutureProgress *ProgressView::addTask(const QFuture<void> &future,
|
||||
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
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
bool ProgressView::isHovered() const
|
||||
{
|
||||
return m_hovered;
|
||||
}
|
||||
|
||||
void ProgressView::setReferenceWidget(QWidget *widget)
|
||||
{
|
||||
if (m_referenceWidget)
|
||||
removeEventFilter(this);
|
||||
m_referenceWidget = widget;
|
||||
if (m_referenceWidget)
|
||||
installEventFilter(this);
|
||||
reposition();
|
||||
}
|
||||
|
||||
bool ProgressView::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::ParentAboutToChange && parentWidget()) {
|
||||
parentWidget()->removeEventFilter(this);
|
||||
} else if (event->type() == QEvent::ParentChange && parentWidget()) {
|
||||
parentWidget()->installEventFilter(this);
|
||||
} else if (event->type() == QEvent::Resize) {
|
||||
reposition();
|
||||
} else if (event->type() == QEvent::Enter) {
|
||||
m_hovered = true;
|
||||
emit hoveredChanged(m_hovered);
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
m_hovered = false;
|
||||
emit hoveredChanged(m_hovered);
|
||||
}
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
bool ProgressView::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if ((obj == parentWidget() || obj == m_referenceWidget) && event->type() == QEvent::Resize)
|
||||
reposition();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProgressView::removeOldTasks(const QString &type, bool keepOne)
|
||||
{
|
||||
bool firstFound = !keepOne; // start with false if we want to keep one
|
||||
@@ -99,6 +169,15 @@ void ProgressView::deleteTask(FutureProgress *progress)
|
||||
progress->deleteLater();
|
||||
}
|
||||
|
||||
void ProgressView::reposition()
|
||||
{
|
||||
if (!parentWidget() || !m_referenceWidget)
|
||||
return;
|
||||
QPoint topRightReferenceInParent =
|
||||
m_referenceWidget->mapTo(parentWidget(), m_referenceWidget->rect().topRight());
|
||||
move(topRightReferenceInParent - rect().bottomRight());
|
||||
}
|
||||
|
||||
void ProgressView::removeOneOldTask()
|
||||
{
|
||||
if (m_taskList.isEmpty())
|
||||
@@ -146,3 +225,9 @@ void ProgressView::slotRemoveTask()
|
||||
removeTask(progress);
|
||||
removeOldTasks(type, true);
|
||||
}
|
||||
|
||||
void ProgressView::checkForLastProgressFading()
|
||||
{
|
||||
if (isEmpty() || isFading())
|
||||
emit fadeOfLastProgressStarted();
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QFuture>
|
||||
#include <QWidget>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QVBoxLayout;
|
||||
QT_END_NAMESPACE
|
||||
@@ -59,17 +60,37 @@ public:
|
||||
const QString &type,
|
||||
ProgressManager::ProgressFlags flags);
|
||||
|
||||
bool hasError() const;
|
||||
bool isFading() const;
|
||||
bool isEmpty() const;
|
||||
bool isHovered() const;
|
||||
|
||||
void setReferenceWidget(QWidget *widget);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event);
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
Reference in New Issue
Block a user