|
| 1 | + |
| 2 | +#include "ProgressDlg.hpp" |
| 3 | +#include "ui_ProgressDlg.h" |
| 4 | +#include "ui_ProgressWdgt.h" |
| 5 | + |
| 6 | +#include <QCloseEvent> |
| 7 | +#include <QPushButton> |
| 8 | +#include <QStringBuilder> |
| 9 | + |
| 10 | +namespace Private |
| 11 | +{ |
| 12 | + |
| 13 | + class ProgressWdgt : public QWidget, public Ui::ProgressWdgt |
| 14 | + { |
| 15 | + public: |
| 16 | + enum class Result { Undefined = 0, Ok, Error }; |
| 17 | + |
| 18 | + typedef QMap< QString, QPointer<ProgressWdgt> > Steps; |
| 19 | + |
| 20 | + public: |
| 21 | + ProgressWdgt(const QString& description) |
| 22 | + : mActive(true) |
| 23 | + , mPercentage(0.) |
| 24 | + { |
| 25 | + setupUi(this); |
| 26 | + setAttribute(Qt::WA_NoSystemBackground); |
| 27 | + resultChanged(Result::Undefined); |
| 28 | + progressBar->setMinimum(0); |
| 29 | + progressBar->setMaximum(100); |
| 30 | + txtHeader->setText( description ); |
| 31 | + } |
| 32 | + |
| 33 | + public: |
| 34 | + void resultChanged(Result result) |
| 35 | + { |
| 36 | + QColor barColor; |
| 37 | + |
| 38 | + switch (result) { |
| 39 | + case Result::Ok: |
| 40 | + barColor = QColor(0x55, 0xFF, 0x55); |
| 41 | + break; |
| 42 | + |
| 43 | + case Result::Error: |
| 44 | + barColor = QColor(0xFF, 0x55, 0x55); |
| 45 | + break; |
| 46 | + |
| 47 | + case Result::Undefined: |
| 48 | + default: |
| 49 | + barColor = QColor(0x99, 0x99, 0x99); |
| 50 | + break; |
| 51 | + } |
| 52 | + |
| 53 | + progressBar->setStyleSheet( |
| 54 | + QStringLiteral( |
| 55 | + "QProgressBar{" |
| 56 | + "text-align: center;" |
| 57 | + "border: 2px solid silver;" |
| 58 | + "border-radius: 5px;" |
| 59 | + "background: QLinearGradient(" |
| 60 | + "x1: 0, y1: 0, x2: 0, y2: 1," |
| 61 | + "stop: 0 %1," |
| 62 | + "stop: 1 %2);" |
| 63 | + "}") |
| 64 | + .arg(barColor.darker(150).name()).arg(barColor.name()) % |
| 65 | + |
| 66 | + QStringLiteral( |
| 67 | + "QProgressBar::chunk{" |
| 68 | + "background: QLinearGradient(" |
| 69 | + "x1: 0, y1: 0, x2: 0, y2: 1," |
| 70 | + "stop: 0 %1," |
| 71 | + "stop: 1 %2);" |
| 72 | + "}") |
| 73 | + .arg(barColor.lighter(150).name()).arg(barColor.name()) |
| 74 | + ); |
| 75 | + } |
| 76 | + |
| 77 | + public: |
| 78 | + bool mActive; |
| 79 | + qreal mPercentage; |
| 80 | + |
| 81 | + Steps mSteps; |
| 82 | + }; |
| 83 | + |
| 84 | +} |
| 85 | + |
| 86 | + |
| 87 | +ProgressDlg::ProgressDlg() |
| 88 | + : BlueSky::Dialog() |
| 89 | + , ui( new Ui::ProgressDlg ) |
| 90 | + , mDone( false ) |
| 91 | +{ |
| 92 | + ui->setupUi( this ); |
| 93 | + |
| 94 | + QPushButton* close = ui->buttonBox->button(QDialogButtonBox::Close); |
| 95 | + close->setEnabled( false ); |
| 96 | + connect(close, &QPushButton::clicked, this, &ProgressDlg::close); |
| 97 | + |
| 98 | + connect(&mUpdater, &QTimer::timeout, this, &ProgressDlg::updateActivities); |
| 99 | + mUpdater.start(250); |
| 100 | +} |
| 101 | + |
| 102 | +ProgressDlg::~ProgressDlg() |
| 103 | +{ |
| 104 | + delete ui; |
| 105 | +} |
| 106 | + |
| 107 | +int ProgressDlg::updateInterval() const |
| 108 | +{ |
| 109 | + return mUpdater.interval(); |
| 110 | +} |
| 111 | + |
| 112 | +void ProgressDlg::setUpdateInterval(int msec) |
| 113 | +{ |
| 114 | + if (mUpdater.isActive()) { |
| 115 | + // restart timer with the new interval |
| 116 | + mUpdater.start(msec); |
| 117 | + } |
| 118 | + else { |
| 119 | + mUpdater.setInterval(msec); |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +void ProgressDlg::addActivity(const QString& description, QObject* activity, |
| 124 | + const StepInfo::List& steps) |
| 125 | +{ |
| 126 | + Q_ASSERT(activity); |
| 127 | + |
| 128 | + Private::ProgressWdgt* a = new Private::ProgressWdgt(description); |
| 129 | + mActivities[activity] = a; |
| 130 | + |
| 131 | + QTreeWidgetItem* activityItem(new QTreeWidgetItem); |
| 132 | + ui->treeProgress->addTopLevelItem(activityItem); |
| 133 | + ui->treeProgress->setItemWidget(activityItem, 0, a); |
| 134 | + |
| 135 | + foreach (const StepInfo& sir, steps) { |
| 136 | + Private::ProgressWdgt* s = new Private::ProgressWdgt(sir.desc); |
| 137 | + a->mSteps[sir.name] = s; |
| 138 | + |
| 139 | + QTreeWidgetItem* stepItem(new QTreeWidgetItem); |
| 140 | + activityItem->addChild(stepItem); |
| 141 | + ui->treeProgress->setItemWidget(stepItem, 0, s); |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +void ProgressDlg::setStatusInfo(QObject* activity, const QString& step, |
| 146 | + const QString& text) |
| 147 | +{ |
| 148 | + Private::ProgressWdgt* s = findStep(activity, step); |
| 149 | + Q_ASSERT(s); |
| 150 | + |
| 151 | + s->progressBar->setFormat(text); |
| 152 | +} |
| 153 | + |
| 154 | +void ProgressDlg::setPercentage(QObject* activity, const QString& step, |
| 155 | + qreal percent) |
| 156 | +{ |
| 157 | + Private::ProgressWdgt* s = findStep(activity, step); |
| 158 | + Q_ASSERT(s); |
| 159 | + |
| 160 | + s->mPercentage = qMin( qMax(percent, 0.), 1. ) * 100.; |
| 161 | + |
| 162 | + if (s->mPercentage >= 100.) { |
| 163 | + s->resultChanged(Private::ProgressWdgt::Result::Ok); |
| 164 | + } |
| 165 | +} |
| 166 | + |
| 167 | +void ProgressDlg::closeEvent( QCloseEvent* ev ) |
| 168 | +{ |
| 169 | + if( !mDone ) |
| 170 | + { |
| 171 | + ev->ignore(); |
| 172 | + return; |
| 173 | + } |
| 174 | + |
| 175 | + QDialog::closeEvent( ev ); |
| 176 | +} |
| 177 | + |
| 178 | +void ProgressDlg::finished(QObject* activity) |
| 179 | +{ |
| 180 | + Private::ProgressWdgt* a = mActivities[activity]; |
| 181 | + Q_ASSERT(a); |
| 182 | + |
| 183 | + a->mActive = false; |
| 184 | + a->resultChanged(Private::ProgressWdgt::Result::Ok); |
| 185 | +} |
| 186 | + |
| 187 | +void ProgressDlg::setError(QObject* activity, const QString& message) |
| 188 | +{ |
| 189 | + Private::ProgressWdgt* a = mActivities[activity]; |
| 190 | + Q_ASSERT(a); |
| 191 | + a->mActive = false; |
| 192 | + a->progressBar->setFormat(tr("Failed. See tool tip for details.")); |
| 193 | + a->setToolTip(tr("<b>Activity failed.</b><hr/>%1").arg(message)); |
| 194 | + a->resultChanged(Private::ProgressWdgt::Result::Error); |
| 195 | +} |
| 196 | + |
| 197 | +void ProgressDlg::updateActivities() |
| 198 | +{ |
| 199 | + Activities::Iterator it = mActivities.begin(); |
| 200 | + while ( it != mActivities.end() ) { |
| 201 | + Private::ProgressWdgt* a = *it; |
| 202 | + Q_ASSERT(a); |
| 203 | + |
| 204 | + a->mPercentage = 0.; |
| 205 | + |
| 206 | + foreach (Private::ProgressWdgt* s, a->mSteps) { |
| 207 | + s->progressBar->setValue(qRound(s->mPercentage)); |
| 208 | + qreal stepPercent = s->mPercentage / a->mSteps.size(); |
| 209 | + a->mPercentage += qMin( qMax(stepPercent, 0.), 100.); |
| 210 | + } |
| 211 | + |
| 212 | + a->progressBar->setValue(qRound(a->mPercentage)); |
| 213 | + |
| 214 | + // remove invalid activities after updating |
| 215 | + if (!it.key()) { |
| 216 | + it = mActivities.erase(it); |
| 217 | + } |
| 218 | + else { |
| 219 | + ++it; |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + setCanClose(); |
| 224 | +} |
| 225 | + |
| 226 | +void ProgressDlg::accept() |
| 227 | +{ |
| 228 | + if (isDone()) { |
| 229 | + BlueSky::Dialog::accept(); |
| 230 | + } |
| 231 | +} |
| 232 | + |
| 233 | +void ProgressDlg::reject() |
| 234 | +{ |
| 235 | + if (isDone()) { |
| 236 | + BlueSky::Dialog::reject(); |
| 237 | + } |
| 238 | +} |
| 239 | + |
| 240 | +Private::ProgressWdgt* ProgressDlg::findStep(QObject* activity, const QString& step) const |
| 241 | +{ |
| 242 | + Private::ProgressWdgt* a = mActivities[activity]; |
| 243 | + return step.isEmpty() || !a ? nullptr : a->mSteps[step]; |
| 244 | +} |
| 245 | + |
| 246 | +void ProgressDlg::setCanClose() |
| 247 | +{ |
| 248 | + const bool wasDone = mDone; |
| 249 | + mDone = isDone(); |
| 250 | + |
| 251 | + if (mDone != wasDone) { |
| 252 | + ui->buttonBox->button( QDialogButtonBox::Close )->setEnabled( mDone ); |
| 253 | + } |
| 254 | +} |
0 commit comments