diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp index c0a4128..54a3f8d 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp @@ -1,4 +1,5 @@ #include "sampleviewmodel.h" +#include #include #include #include @@ -104,6 +105,37 @@ void SampleViewModel::getColor() }, tr("Select a color:"), true); } +void SampleViewModel::showProgress() +{ + auto control = QtMvvm::showIndeterminateProgress(this, + tr("Some ongoing operation"), + tr("Doing some operation long running job…")); + auto mTimer = new QTimer{control}; + connect(mTimer, &QTimer::timeout, + control, [control](){ + if(control->isIndeterminate()) { + control->setIndeterminate(false); + control->setMinimum(0); + control->setMaximum(5); + control->setProgress(0); + } else if(control->progress() == 4) { + control->setProgress(5); + control->close(); + } else + control->setProgress(control->progress() + 1); + }); + connect(control, &QtMvvm::ProgressControl::canceled, + control, [control, mTimer](){ + control->updateLabel(tr("Canceling, please wait…")); + mTimer->stop(); + QTimer::singleShot(2000, control, &QtMvvm::ProgressControl::close); + }); + connect(control, &QtMvvm::ProgressControl::closed, + mTimer, &QTimer::stop); + + mTimer->start(2000); +} + void SampleViewModel::getResult() { showForResult(ResCode, { diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.h b/examples/mvvmcore/SampleCore/sampleviewmodel.h index 5bb8be6..d575a88 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.h +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.h @@ -38,6 +38,8 @@ public Q_SLOTS: void getInput(); void getFiles(); void getColor(); + void showProgress(); + void getResult(); void clearEvents(); void about(); diff --git a/examples/mvvmwidgets/SampleWidgets/sampleview.cpp b/examples/mvvmwidgets/SampleWidgets/sampleview.cpp index 60d6cac..c956b17 100644 --- a/examples/mvvmwidgets/SampleWidgets/sampleview.cpp +++ b/examples/mvvmwidgets/SampleWidgets/sampleview.cpp @@ -30,6 +30,8 @@ SampleView::SampleView(QtMvvm::ViewModel *viewModel, QWidget *parent) : _viewModel, &SampleViewModel::getFiles); connect(ui->actionAdd_Color, &QAction::triggered, _viewModel, &SampleViewModel::getColor); + connect(ui->actionShow_Progress, &QAction::triggered, + _viewModel, &SampleViewModel::showProgress); connect(ui->actionShow_Tabs, &QAction::triggered, _viewModel, &SampleViewModel::showTabs); connect(ui->actionShow_Settings, &QAction::triggered, diff --git a/examples/mvvmwidgets/SampleWidgets/sampleview.ui b/examples/mvvmwidgets/SampleWidgets/sampleview.ui index ce36925..6d4c9f5 100644 --- a/examples/mvvmwidgets/SampleWidgets/sampleview.ui +++ b/examples/mvvmwidgets/SampleWidgets/sampleview.ui @@ -112,6 +112,7 @@ + @@ -147,6 +148,11 @@ Add &Color + + + Show &Progress + + diff --git a/src/imports/mvvmcore/plugins.qmltypes b/src/imports/mvvmcore/plugins.qmltypes index 882319a..431f2fe 100644 --- a/src/imports/mvvmcore/plugins.qmltypes +++ b/src/imports/mvvmcore/plugins.qmltypes @@ -121,10 +121,18 @@ Module { name: "progressChanged" Parameter { name: "progress"; type: "int" } } + Signal { + name: "changeLabel" + Parameter { name: "text"; type: "string" } + } Signal { name: "closeRequested" } Signal { name: "canceled" } Signal { name: "closed" } Method { name: "close" } + Method { + name: "updateLabel" + Parameter { name: "text"; type: "string" } + } Method { name: "setAutoDelete" Parameter { name: "autoDelete"; type: "bool" } diff --git a/src/mvvmcore/message.cpp b/src/mvvmcore/message.cpp index a208041..3c69cc9 100644 --- a/src/mvvmcore/message.cpp +++ b/src/mvvmcore/message.cpp @@ -346,6 +346,11 @@ void ProgressControl::close() emit closeRequested({}); } +void ProgressControl::updateLabel(const QString &text) +{ + emit changeLabel(text, {}); +} + void ProgressControl::setAutoDelete(bool autoDelete) { if (d->autoDelete == autoDelete) diff --git a/src/mvvmcore/message.h b/src/mvvmcore/message.h index 1f5f18e..8b6dfe4 100644 --- a/src/mvvmcore/message.h +++ b/src/mvvmcore/message.h @@ -268,6 +268,7 @@ public: public Q_SLOTS: void close(); + void updateLabel(const QString &text); void setAutoDelete(bool autoDelete); void setIndeterminate(bool indeterminate); @@ -283,6 +284,7 @@ Q_SIGNALS: void maximumChanged(int maximum, QPrivateSignal); void progressChanged(int progress, QPrivateSignal); + void changeLabel(const QString &text, QPrivateSignal); void closeRequested(QPrivateSignal); void canceled(QPrivateSignal); diff --git a/src/mvvmwidgets/mvvmwidgets.pro b/src/mvvmwidgets/mvvmwidgets.pro index 2f56c3b..85f7151 100644 --- a/src/mvvmwidgets/mvvmwidgets.pro +++ b/src/mvvmwidgets/mvvmwidgets.pro @@ -14,7 +14,8 @@ HEADERS += \ settingsdialog_p.h \ settingsdialog.h \ tooltipslider_p.h \ - coloredit_p.h + coloredit_p.h \ + progressdialog_p.h SOURCES += \ widgetspresenter.cpp \ @@ -23,7 +24,8 @@ SOURCES += \ inputwidgetfactory.cpp \ settingsdialog.cpp \ tooltipslider.cpp \ - coloredit.cpp + coloredit.cpp \ + progressdialog.cpp FORMS += \ settingsdialog.ui diff --git a/src/mvvmwidgets/progressdialog.cpp b/src/mvvmwidgets/progressdialog.cpp new file mode 100644 index 0000000..f5c39dd --- /dev/null +++ b/src/mvvmwidgets/progressdialog.cpp @@ -0,0 +1,150 @@ +#include "progressdialog_p.h" +#include + +#include +#include +#include + +#include +using namespace QtMvvm; + +ProgressDialog::ProgressDialog(const MessageConfig &config, QPointer result, QPointer control, QWidget *parent) : + QDialog{parent}, + _result{std::move(result)}, + _control{std::move(control)}, + _label{new QLabel{this}}, + _progress{new QProgressBar{this}} +{ + auto props = config.viewProperties(); + auto isBusy = (config.subType() == MessageConfig::SubTypeBusy); + + auto layout = new QVBoxLayout{this}; + setLayout(layout); + + //set title and text + auto text = config.text(); + if(text.isNull()) + text = config.title(); + else + setWindowTitle(config.title()); + if(text.isNull()) + _label->setVisible(false); + else + _label->setText(text); + connect(_control, &ProgressControl::changeLabel, + this, &ProgressDialog::updateLabel); + layout->addWidget(_label); + + //add the input + if(props.contains(QStringLiteral("format"))) + _progress->setFormat(props.value(QStringLiteral("format")).toString()); + setIndetem(isBusy || _control->isIndeterminate()); + layout->addWidget(_progress); + + //add the cancel button, in case it was requested + if(config.buttons().testFlag(MessageConfig::Cancel)) { + _btnBox = new QDialogButtonBox{this}; + _btnBox->setStandardButtons(QDialogButtonBox::Cancel); //is ok, as the buttons are the same + auto btnTexts = config.buttonTexts(); + if(btnTexts.contains(MessageConfig::Cancel)) + _btnBox->button(QDialogButtonBox::Cancel)->setText(btnTexts.value(MessageConfig::Cancel)); + layout->addWidget(_btnBox); + // connect the box + connect(_btnBox, &QDialogButtonBox::clicked, + this, [this](QAbstractButton *btn) { + if(_btnBox->standardButton(btn) == QDialogButtonBox::Cancel) + tryCancel(); + }); + } + + //set extra props + for(auto it = props.constBegin(); it != props.constEnd(); it++) + setProperty(qUtf8Printable(it.key()), it.value()); + + //connect stuff + connect(_control, &ProgressControl::closeRequested, + this, &ProgressDialog::accept); + if(!isBusy) { + connect(_control, &ProgressControl::minimumChanged, + this, &ProgressDialog::setMin); + connect(_control, &ProgressControl::maximumChanged, + this, &ProgressDialog::setMax); + connect(_control, &ProgressControl::progressChanged, + this, &ProgressDialog::setProg); + connect(_control, &ProgressControl::indeterminateChanged, + this, &ProgressDialog::setIndetem); + } + + connect(this, &ProgressDialog::canceled, + _control, &ProgressControl::requestCancel); + + adjustSize(); + DialogMaster::masterDialog(this, true, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint); +} + +void ProgressDialog::done(int code) +{ + QDialog::done(code); + if(_control) + _control->notifyClosed(); + if(_result) { + if(_wasCanceled) + _result->complete(MessageConfig::Cancel); + else + _result->complete(MessageConfig::Close); + } +} + +void ProgressDialog::closeEvent(QCloseEvent *event) +{ + event->ignore(); + tryCancel(); +} + +void ProgressDialog::tryCancel() +{ + if(!_wasCanceled && _btnBox) { + _wasCanceled = true; + _btnBox->button(QDialogButtonBox::Cancel)->setEnabled(false); + if(_control) + _control->requestCancel(); + else + done(QDialogButtonBox::Cancel); + } +} + +void ProgressDialog::updateLabel(const QString &text) +{ + _label->setText(text); + _label->setVisible(true); +} + +void ProgressDialog::setIndetem(bool indetem) +{ + if(indetem) { + _progress->setRange(0, 0); + _progress->setTextVisible(false); + } else { + _progress->setRange(_control->minimum(), _control->maximum()); + _progress->setValue(_control->progress()); + _progress->setTextVisible(true); + } +} + +void ProgressDialog::setMin(int min) +{ + if(_control && !_control->isIndeterminate()) + _progress->setMinimum(min); +} + +void ProgressDialog::setMax(int max) +{ + if(_control && !_control->isIndeterminate()) + _progress->setMaximum(max); +} + +void ProgressDialog::setProg(int prog) +{ + if(_control && !_control->isIndeterminate()) + _progress->setValue(prog); +} diff --git a/src/mvvmwidgets/progressdialog_p.h b/src/mvvmwidgets/progressdialog_p.h new file mode 100644 index 0000000..7418dcc --- /dev/null +++ b/src/mvvmwidgets/progressdialog_p.h @@ -0,0 +1,57 @@ +#ifndef QTMVVM_PROGRESSDIALOG_P_H +#define QTMVVM_PROGRESSDIALOG_P_H + +#include + +#include + +#include +#include +#include +#include + +#include "qtmvvmwidgets_global.h" + +namespace QtMvvm { + +class ProgressDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ProgressDialog(const MessageConfig &config, + QPointer result, + QPointer control, + QWidget *parent = nullptr); + +public Q_SLOTS: + void done(int code) override; + +Q_SIGNALS: + void canceled(); + +protected: + void closeEvent(QCloseEvent *event) override; + +private Q_SLOTS: + void tryCancel(); + + void updateLabel(const QString &text); + void setIndetem(bool indetem); + void setMin(int min); + void setMax(int max); + void setProg(int prog); + +private: + QPointer _result; + QPointer _control; + + QLabel *_label; + QProgressBar *_progress; + QDialogButtonBox *_btnBox = nullptr; + bool _wasCanceled = false; +}; + +} + +#endif // QTMVVM_PROGRESSDIALOG_P_H diff --git a/src/mvvmwidgets/widgetspresenter.cpp b/src/mvvmwidgets/widgetspresenter.cpp index 1a52669..fd4acde 100644 --- a/src/mvvmwidgets/widgetspresenter.cpp +++ b/src/mvvmwidgets/widgetspresenter.cpp @@ -2,6 +2,7 @@ #include "widgetspresenter_p.h" #include "ipresentingview.h" #include "settingsdialog.h" +#include "progressdialog_p.h" #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include @@ -489,66 +489,12 @@ void WidgetsPresenter::presentProgressDialog(const MessageConfig &config, const } auto props = config.viewProperties(); - //TODO implement difference to busy dialog? - QWidget *parent = nullptr; //TODO move to seperate method if(!props.value(QStringLiteral("modal"), false).toBool()) parent = QApplication::activeWindow(); - auto dialog = DialogMaster::createProgress(parent, - config.text(), - control->isIndeterminate() ? 0 : control->maximum(), - control->isIndeterminate() ? 0 : control->minimum(), - config.buttons().testFlag(MessageConfig::Cancel), - config.title(), - props.value(QStringLiteral("minimumDuration"), 0).toInt(), - config.buttonTexts().value(MessageConfig::Cancel)); + auto dialog = new ProgressDialog{config, result, control, parent}; dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setAutoReset(false); - dialog->setAutoClose(false); - - //set extra props - for(auto it = props.constBegin(); it != props.constEnd(); it++) - dialog->setProperty(qUtf8Printable(it.key()), it.value()); - - //connect stuff - connect(control, &ProgressControl::closeRequested, - dialog, &QProgressDialog::close); - connect(control, &ProgressControl::minimumChanged, - dialog, &QProgressDialog::setMinimum); - connect(control, &ProgressControl::maximumChanged, - dialog, &QProgressDialog::setMaximum); - connect(control, &ProgressControl::progressChanged, - dialog, &QProgressDialog::setValue); - connect(control, &ProgressControl::indeterminateChanged, - dialog, [dialog, control](bool indeterminate){ - if(indeterminate) - dialog->setRange(0, 0); - else if(control) { - dialog->setRange(control->minimum(), control->maximum()); - dialog->setValue(control->progress()); - } else - dialog->setRange(0, 1); - }); - - connect(dialog, &QProgressDialog::canceled, - dialog, &QProgressDialog::show); //TODO check if working, disable cancel button - connect(dialog, &QProgressDialog::canceled, - control, &ProgressControl::requestCancel); - connect(dialog, &QDialog::finished, - dialog, [dialog, result, control](int){ - if(control) - control->notifyClosed(); - if(result) { - if(dialog->wasCanceled()) - result->complete(MessageConfig::Cancel); - else - result->complete(MessageConfig::Close); - } - }); - - //show dialog->open(); - dialog->setValue(control->progress()); //do after open, as set value causes open } void WidgetsPresenter::presentOtherDialog(const MessageConfig &config, QPointer result) diff --git a/sync.profile b/sync.profile index 6b7fd27..04be367 100644 --- a/sync.profile +++ b/sync.profile @@ -11,7 +11,7 @@ $publicclassregexp = "QtMvvm::(?!__helpertypes|SettingsElements).+"; %classnames = ( - "message.h" => "Messages", + "message.h" => "Messages,MessageConfig,MessageResult,ProgressControl", "settingssetup.h" => "SettingsElements", "injection.h" => "Injection", );