From 1b0dcb5bf939504b6bc0d6e7e1d9465f8ff8a3f0 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 5 Jun 2017 12:54:09 +0200 Subject: [PATCH] Better installation feedback for package manager Now the confirmation dialog stays open and will show a log with the installation progress and results. The "marked" icon has been changed to look a bit less painted. --- .../SaltManagerInstallConfirmationDialog.ui | 389 +++++++++++++----- src/lay/images/marked_64.png | Bin 3353 -> 1001 bytes src/lay/laySaltDownloadManager.cc | 143 +++++-- src/lay/laySaltDownloadManager.h | 59 ++- src/lay/laySaltManagerDialog.cc | 6 +- 5 files changed, 448 insertions(+), 149 deletions(-) diff --git a/src/lay/SaltManagerInstallConfirmationDialog.ui b/src/lay/SaltManagerInstallConfirmationDialog.ui index d8dcf20e4..104ed0ae7 100644 --- a/src/lay/SaltManagerInstallConfirmationDialog.ui +++ b/src/lay/SaltManagerInstallConfirmationDialog.ui @@ -13,7 +13,7 @@ Ready for Installation - + @@ -25,66 +25,304 @@ - - - Qt::NoFocus - - - false - - - true - - - - Package - - - - - Action - - - - - Version - - - - - Download link - - - - - - - - Press "Ok" to install or update these packages or "Cancel" to abort. - - - - - + Qt::Vertical - - QSizePolicy::Fixed - - - - 20 - 6 - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - + + + + + + Qt::NoFocus + + + false + + + true + + + + Package + + + + + Action + + + + + Version + + + + + Download link + + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Press "Ok" to install or update these packages or "Cancel" to abort. + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 6 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 300 + 20 + + + + + + + + Ok + + + + + + + Cancel + + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 16 + 16 + + + + false + + + QListView::Adjust + + + true + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + :/warn_16.png + + + + + + + There are errors or warnings + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + + + @@ -128,38 +366,5 @@ - - - buttonBox - accepted() - SaltManagerInstallConfirmationDialog - accept() - - - 273 - 431 - - - 276 - 448 - - - - - buttonBox - rejected() - SaltManagerInstallConfirmationDialog - reject() - - - 351 - 426 - - - 363 - 445 - - - - + diff --git a/src/lay/images/marked_64.png b/src/lay/images/marked_64.png index 02c23d6030c68a6bb3ccdfe7a101e21d132df602..52103f767c762ecd5c9c7074bdf601410748e43a 100644 GIT binary patch delta 920 zcmbO!^^$#p4Ob!q16LyBpEF*n6W!G7nbSO7978JRyq)ErArdZg+&({DnA=HM+$N;S zbRuciEok9R`x`0(ZHSuj>UpYb*KIMz9>}RNkc@XyFRK| zrA0HRZl5mnr~62lO6I2B>)C~GT=g}dy~lii%bDk9`S+^#pRbu|pWoJ4*~jGZ`b%Q( zuX=~5WBww)3Y}DU9b(Yu*0;a?`})7oOF?x-NiWU!Gv_mDyjoOc^-X8XqrFd;PCGVj z(uUcgZ0_vNJ15qxSkcX;5VOztV_o&b%dXLU+EAT0wHsAKnwe8_du}^aq?YZjRW4B#6p=6(Rwfif>qs(ngYj1w# zxwXzz_TEkwAEEM}OlRj67-#2Po5^{NsbklhYXxr3m!eP4SZif`^pvVVv8Sd5cg#Eg zPu;yz%M9ck&OBu(kdn|6eQ9F5KeLBT!1pqz47)?I!S2p{Ji}fnbsrme_ z*?Nw->2}|=`a0n&D{h>x=}voJ;T@P=R@`E_aml(Wwl!s$-QPEDdzR7LwbU}Q?8AZ| z`|6qJS-S2H;eAjyDM$0jz8AiF$JcM%@#=&*dp*~WO>4ex3|&lvDbLx`o+@f)1EO+(2`&LV0E?hkK2pZ7pn0-*xoN$zvu|x0?r?L;t%t5 z&brIqwb;oa-gsV{Eu(6$iv6uATMz!XW8KsHXVt?aKhk7;)x;IKbM)UYPdvgII*+%w zbyoku>x*TWGp*jIQuRjt{d1WMmM;n{KI;8w*0fKPSL(NlM)hv;K0Nv3wE8J& z`(<_iuXr7M;P#nf_A;g@ZN5tBnV;qTU)M?Qn*U^1(2}V5f@^IP?)$t>J>gxDcTVS9 z_Jh;m4{!PiG;C=wab&o}bcu!0gWE%xML}1=7n@)`R#9}p&*%O#vT~g^vI?FsVdGhe z->P0J?$wCZ3;OXk;vX0p)p$Pyq1F4As delta 3290 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 Y->Bm{*{p=nh5!Hn07*qoM6N<$f&m&q`Tzg` diff --git a/src/lay/laySaltDownloadManager.cc b/src/lay/laySaltDownloadManager.cc index 08956c7f6..efe5066b5 100644 --- a/src/lay/laySaltDownloadManager.cc +++ b/src/lay/laySaltDownloadManager.cc @@ -25,8 +25,7 @@ #include "tlFileUtils.h" #include "tlWebDAV.h" -#include "ui_SaltManagerInstallConfirmationDialog.h" - +#include #include #include @@ -35,32 +34,81 @@ namespace lay // ---------------------------------------------------------------------------------- -class ConfirmationDialog - : public QDialog, private Ui::SaltManagerInstallConfirmationDialog +ConfirmationDialog::ConfirmationDialog (QWidget *parent) + : QDialog (parent), m_confirmed (false), m_cancelled (false), m_closed (false), m_file (50000, true) { -public: - ConfirmationDialog (QWidget *parent) - : QDialog (parent) - { - Ui::SaltManagerInstallConfirmationDialog::setupUi (this); + Ui::SaltManagerInstallConfirmationDialog::setupUi (this); + + connect (ok_button, SIGNAL (clicked ()), this, SLOT (confirm_pressed ())); + connect (cancel_button, SIGNAL (clicked ()), this, SLOT (cancel_pressed ())); + connect (close_button, SIGNAL (clicked ()), this, SLOT (close_pressed ())); + + log_panel->hide (); + attn_frame->hide (); + log_view->setModel (&m_file); + + connect (&m_file, SIGNAL (layoutChanged ()), log_view, SLOT (scrollToBottom ())); + connect (&m_file, SIGNAL (attention_changed (bool)), attn_frame, SLOT (setVisible (bool))); +} + +void +ConfirmationDialog::add_info (const std::string &name, bool update, const std::string &version, const std::string &url) +{ + QTreeWidgetItem *item = new QTreeWidgetItem (list); + m_items_by_name.insert (std::make_pair (name, item)); + + item->setFlags (item->flags () & ~Qt::ItemIsSelectable); + + item->setText (0, tl::to_qstring (name)); + item->setText (1, update ? tr ("UPDATE") : tr ("INSTALL")); + item->setText (2, tl::to_qstring (version)); + item->setText (3, tl::to_qstring (url)); + + for (int column = 0; column < list->colorCount (); ++column) { + item->setData (column, Qt::ForegroundRole, update ? Qt::blue : Qt::black); } +} - void add_info (const std::string &name, bool update, const std::string &version, const std::string &url) - { - QTreeWidgetItem *item = new QTreeWidgetItem (list); +void +ConfirmationDialog::separator () +{ + m_file.separator (); +} - item->setFlags (item->flags () & ~Qt::ItemIsSelectable); +void +ConfirmationDialog::mark_error (const std::string &name) +{ + set_icon_for_name (name, QIcon (QString::fromUtf8 (":/error_16.png"))); +} - item->setText (0, tl::to_qstring (name)); - item->setText (1, update ? tr ("UPDATE") : tr ("INSTALL")); - item->setText (2, tl::to_qstring (version)); - item->setText (3, tl::to_qstring (url)); +void +ConfirmationDialog::mark_success (const std::string &name) +{ + set_icon_for_name (name, QIcon (QString::fromUtf8 (":/marked_16.png"))); +} - for (int column = 0; column < list->colorCount (); ++column) { - item->setData (column, Qt::ForegroundRole, update ? Qt::blue : Qt::black); - } +void +ConfirmationDialog::set_icon_for_name (const std::string &name, const QIcon &icon) +{ + std::map::const_iterator i = m_items_by_name.find (name); + if (i != m_items_by_name.end ()) { + i->second->setData (0, Qt::DecorationRole, icon); } -}; +} + +void +ConfirmationDialog::start () +{ + confirm_panel->hide (); + log_panel->show (); + close_button->setEnabled (false); +} + +void +ConfirmationDialog::finish () +{ + close_button->setEnabled (true); +} // ---------------------------------------------------------------------------------- @@ -182,23 +230,17 @@ SaltDownloadManager::fetch_missing (const lay::Salt &salt_mine, tl::AbsoluteProg } } -bool -SaltDownloadManager::show_confirmation_dialog (QWidget *parent, const lay::Salt &salt) +lay::ConfirmationDialog * +SaltDownloadManager::make_confirmation_dialog (QWidget *parent, const lay::Salt &salt) { - // Stop with a warning if there is nothing to do - if (m_registry.empty()) { - QMessageBox::warning (parent, tr ("Nothing to do"), tr ("No packages need update or are marked for installation")); - return false; - } - - lay::ConfirmationDialog dialog (parent); + lay::ConfirmationDialog *dialog = new lay::ConfirmationDialog (parent); // First the packages to update for (std::map::const_iterator p = m_registry.begin (); p != m_registry.end (); ++p) { const lay::SaltGrain *g = salt.grain_by_name (p->first); if (g) { // \342\206\222 is UTF-8 "right arrow" - dialog.add_info (p->first, true, g->version () + " \342\206\222 " + p->second.version, p->second.url); + dialog->add_info (p->first, true, g->version () + " \342\206\222 " + p->second.version, p->second.url); } } @@ -206,19 +248,37 @@ SaltDownloadManager::show_confirmation_dialog (QWidget *parent, const lay::Salt for (std::map::const_iterator p = m_registry.begin (); p != m_registry.end (); ++p) { const lay::SaltGrain *g = salt.grain_by_name (p->first); if (!g) { - dialog.add_info (p->first, false, p->second.version, p->second.url); + dialog->add_info (p->first, false, p->second.version, p->second.url); } } - return dialog.exec (); + return dialog; } bool -SaltDownloadManager::execute (lay::Salt &salt) +SaltDownloadManager::execute (QWidget *parent, lay::Salt &salt) { - bool result = true; + // Stop with a warning if there is nothing to do + if (m_registry.empty()) { + QMessageBox::warning (parent, tr ("Nothing to do"), tr ("No packages need update or are marked for installation")); + return true; + } - tl::RelativeProgress progress (tl::to_string (QObject::tr ("Downloading packages")), m_registry.size (), 1); + std::auto_ptr dialog (make_confirmation_dialog (parent, salt)); + + dialog->setModal (true); + dialog->show (); + + while (! dialog->is_confirmed ()) { + QCoreApplication::processEvents (QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, 100); + if (dialog->is_cancelled () || ! dialog->isVisible ()) { + return false; + } + } + + dialog->start (); + + bool result = true; for (std::map::const_iterator p = m_registry.begin (); p != m_registry.end (); ++p) { @@ -230,13 +290,22 @@ SaltDownloadManager::execute (lay::Salt &salt) } if (! salt.create_grain (p->second.grain, target)) { + dialog->mark_error (p->first); result = false; + } else { + dialog->mark_success (p->first); } - ++progress; + dialog->separator (); } + dialog->finish (); + + while (! dialog->is_closed () && dialog->isVisible ()) { + QCoreApplication::processEvents (QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, 100); + } + return result; } diff --git a/src/lay/laySaltDownloadManager.h b/src/lay/laySaltDownloadManager.h index 89fd74620..43490537e 100644 --- a/src/lay/laySaltDownloadManager.h +++ b/src/lay/laySaltDownloadManager.h @@ -25,8 +25,11 @@ #include "layCommon.h" #include "laySaltGrain.h" +#include "layLogViewerDialog.h" #include "tlProgress.h" +#include "ui_SaltManagerInstallConfirmationDialog.h" + #include #include #include @@ -36,6 +39,40 @@ namespace lay class Salt; +class ConfirmationDialog + : public QDialog, private Ui::SaltManagerInstallConfirmationDialog +{ +Q_OBJECT + +public: + ConfirmationDialog (QWidget *parent); + + void add_info (const std::string &name, bool update, const std::string &version, const std::string &url); + + bool is_confirmed () const { return m_confirmed; } + bool is_cancelled () const { return m_cancelled; } + bool is_closed () const { return m_closed; } + + void start (); + void separator (); + void finish (); + + void mark_error (const std::string &name); + void mark_success (const std::string &name); + +private slots: + void confirm_pressed () { m_confirmed = true; } + void cancel_pressed () { m_cancelled = true; } + void close_pressed () { m_closed = true; } + +private: + bool m_confirmed, m_cancelled, m_closed; + lay::LogFile m_file; + std::map m_items_by_name; + + void set_icon_for_name (const std::string &name, const QIcon &icon); +}; + /** * @brief The download manager * @@ -73,25 +110,16 @@ public: */ void compute_dependencies (const lay::Salt &salt, const Salt &salt_mine); - /** - * @brief Presents a dialog showing the packages scheduled for download - * - * This method requires all dependencies to be computed. It will return false - * if the dialog is not confirmed. - * - * "salt" needs to be the currently installed packages so the dialog can - * indicate which packages will be updated. - */ - bool show_confirmation_dialog (QWidget *parent, const lay::Salt &salt); - /** * @brief Actually execute the downloads * - * This method will return false if anything goes wrong. - * Failed packages will be removed entirely after they have been listed in - * an error dialog. + * This method will show a confirmation dialog and start installation + * if this dialog is confirmed. It will return false if + * the dialog was cancelled and an exception if something goes + * wrong. + * It will return true if the packages were installed successfully. */ - bool execute (lay::Salt &salt); + bool execute (QWidget *parent, lay::Salt &salt); private: struct Descriptor @@ -110,6 +138,7 @@ private: bool needs_iteration (); void fetch_missing (const lay::Salt &salt_mine, tl::AbsoluteProgress &progress); + lay::ConfirmationDialog *make_confirmation_dialog (QWidget *parent, const lay::Salt &salt); }; } diff --git a/src/lay/laySaltManagerDialog.cc b/src/lay/laySaltManagerDialog.cc index 2fbcd53aa..6e07bb979 100644 --- a/src/lay/laySaltManagerDialog.cc +++ b/src/lay/laySaltManagerDialog.cc @@ -529,16 +529,12 @@ BEGIN_PROTECTED } manager.compute_dependencies (*mp_salt, m_salt_mine); - - if (manager.show_confirmation_dialog (this, *mp_salt)) { + if (manager.execute (this, *mp_salt)) { if (update) { unmark_all_update (); } else { unmark_all_new (); } - if (! manager.execute (*mp_salt)) { - throw tl::Exception (tl::to_string (tr ("Failed to install some of the selected packages. Please see log for details."))); - } } END_PROTECTED