diff --git a/src/lay/SaltManagerDialog.ui b/src/lay/SaltManagerDialog.ui
index a51993a12..77651bd95 100644
--- a/src/lay/SaltManagerDialog.ui
+++ b/src/lay/SaltManagerDialog.ui
@@ -231,8 +231,8 @@
0
0
- 537
- 284
+ 343
+ 207
@@ -673,6 +673,13 @@
+ -
+
+
+ Set in code
+
+
+
-
@@ -725,16 +732,19 @@
Delete package
-
-
-
- :/import.png:/import.png
-
+
- Import
+ Unmark all
-
- Import package
+
+
+
+ Show marked only
+
+
+
+
+ Show all
diff --git a/src/lay/SaltManagerInstallConfirmationDialog.ui b/src/lay/SaltManagerInstallConfirmationDialog.ui
index 0920a619b..d8dcf20e4 100644
--- a/src/lay/SaltManagerInstallConfirmationDialog.ui
+++ b/src/lay/SaltManagerInstallConfirmationDialog.ui
@@ -26,6 +26,15 @@
-
+
+ Qt::NoFocus
+
+
+ false
+
+
+ true
+
Package
diff --git a/src/lay/images/marked_16.png b/src/lay/images/marked_16.png
index aa152411b..777a625a7 100644
Binary files a/src/lay/images/marked_16.png and b/src/lay/images/marked_16.png differ
diff --git a/src/lay/images/marked_24.png b/src/lay/images/marked_24.png
index 8a445139b..cf50321a8 100644
Binary files a/src/lay/images/marked_24.png and b/src/lay/images/marked_24.png differ
diff --git a/src/lay/laySalt.cc b/src/lay/laySalt.cc
index 2812d2095..4b1b2174d 100644
--- a/src/lay/laySalt.cc
+++ b/src/lay/laySalt.cc
@@ -49,6 +49,7 @@ Salt &Salt::operator= (const Salt &other)
{
if (this != &other) {
m_root = other.m_root;
+ invalidate ();
}
return *this;
}
diff --git a/src/lay/laySaltDownloadManager.cc b/src/lay/laySaltDownloadManager.cc
index c3e587551..08956c7f6 100644
--- a/src/lay/laySaltDownloadManager.cc
+++ b/src/lay/laySaltDownloadManager.cc
@@ -28,6 +28,7 @@
#include "ui_SaltManagerInstallConfirmationDialog.h"
#include
+#include
namespace lay
{
@@ -47,10 +48,17 @@ public:
void add_info (const std::string &name, bool update, const std::string &version, const std::string &url)
{
QTreeWidgetItem *item = new QTreeWidgetItem (list);
+
+ 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);
+ }
}
};
@@ -72,11 +80,25 @@ SaltDownloadManager::compute_dependencies (const lay::Salt &salt, const lay::Sal
{
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Computing package dependencies ..")));
+ std::map registry;
+
+ // remove those registered entries which don't need to be updated
+
+ registry = m_registry;
+ for (std::map::const_iterator p = registry.begin (); p != registry.end (); ++p) {
+ const SaltGrain *g = salt.grain_by_name (p->first);
+ if (g && SaltGrain::compare_versions (p->second.version, g->version ()) == 0 && p->second.url == g->url ()) {
+ m_registry.erase (p->first);
+ }
+ }
+
+ // add further entries as derived from the dependencies
+
while (needs_iteration ()) {
fetch_missing (salt_mine, progress);
- std::map registry = m_registry;
+ registry = m_registry;
for (std::map::const_iterator p = registry.begin (); p != registry.end (); ++p) {
for (std::vector::const_iterator d = p->second.grain.dependencies ().begin (); d != p->second.grain.dependencies ().end (); ++d) {
@@ -147,7 +169,12 @@ SaltDownloadManager::fetch_missing (const lay::Salt &salt_mine, tl::AbsoluteProg
p->second.url = g->url ();
}
- p->second.grain = SaltGrain::from_url (p->second.url);
+ try {
+ p->second.grain = SaltGrain::from_url (p->second.url);
+ } catch (tl::Exception &ex) {
+ throw tl::Exception (tl::to_string (QObject::tr ("Error fetching spec file for package '%1': %2").arg (tl::to_qstring (p->first)).arg (tl::to_qstring (ex.msg ()))));
+ }
+
p->second.downloaded = true;
}
@@ -158,13 +185,20 @@ SaltDownloadManager::fetch_missing (const lay::Salt &salt_mine, tl::AbsoluteProg
bool
SaltDownloadManager::show_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);
// 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) {
- dialog.add_info (p->first, true, g->version () + "->" + p->second.version, p->second.url);
+ // \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);
}
}
diff --git a/src/lay/laySaltGrain.cc b/src/lay/laySaltGrain.cc
index 61ceb8fef..63c7f5689 100644
--- a/src/lay/laySaltGrain.cc
+++ b/src/lay/laySaltGrain.cc
@@ -392,6 +392,10 @@ SaltGrain::from_path (const std::string &path)
SaltGrain
SaltGrain::from_url (const std::string &url)
{
+ if (url.empty ()) {
+ throw tl::Exception (tl::to_string (QObject::tr ("No download link available")));
+ }
+
tl::InputHttpStream http (SaltGrain::spec_url (url));
tl::InputStream stream (http);
diff --git a/src/lay/laySaltGrainDetailsTextWidget.cc b/src/lay/laySaltGrainDetailsTextWidget.cc
index f71bdda14..310a18a6e 100644
--- a/src/lay/laySaltGrainDetailsTextWidget.cc
+++ b/src/lay/laySaltGrainDetailsTextWidget.cc
@@ -226,8 +226,11 @@ SaltGrainDetailsTextWidget::details_text ()
stream << "
" << QObject::tr ("Depends on: ") << "
";
for (std::vector::const_iterator d = g->dependencies ().begin (); d != g->dependencies ().end (); ++d) {
stream << " " << tl::to_qstring (tl::escaped_to_html (d->name)) << " ";
- stream << tl::to_qstring (tl::escaped_to_html (d->version)) << " - ";
- stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
";
+ stream << tl::to_qstring (tl::escaped_to_html (d->version));
+ if (! d->url.empty ()) {
+ stream << " - ";
+ stream << "[" << tl::to_qstring (tl::escaped_to_html (d->url)) << "]
";
+ }
}
stream << "
";
}
diff --git a/src/lay/laySaltGrainPropertiesDialog.cc b/src/lay/laySaltGrainPropertiesDialog.cc
index 3059cb653..d78ee94bf 100644
--- a/src/lay/laySaltGrainPropertiesDialog.cc
+++ b/src/lay/laySaltGrainPropertiesDialog.cc
@@ -169,12 +169,19 @@ SaltGrainPropertiesDialog::update_controls ()
dependencies->clear ();
for (std::vector::const_iterator d = m_grain.dependencies ().begin (); d != m_grain.dependencies ().end (); ++d) {
+
QTreeWidgetItem *item = new QTreeWidgetItem (dependencies);
item->setFlags (item->flags () | Qt::ItemIsEditable);
+
item->setData (0, Qt::UserRole, tl::to_qstring (d->name));
+ dependency_changed (item, 0);
item->setData (1, Qt::UserRole, tl::to_qstring (d->version));
+ dependency_changed (item, 1);
item->setData (2, Qt::UserRole, tl::to_qstring (d->url));
+ dependency_changed (item, 2);
+
dependencies->addTopLevelItem (item);
+
}
update_icon ();
@@ -249,9 +256,11 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column
}
m_update_enabled = false;
+ std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ());
+ SaltGrain *g = mp_salt->grain_by_name (name);
+
if (column == 0 && mp_salt) {
- std::string name = tl::to_string (item->data (0, Qt::UserRole).toString ().simplified ());
item->setData (0, Qt::EditRole, tl::to_qstring (name));
// set URL and version for known grains
@@ -265,30 +274,48 @@ SaltGrainPropertiesDialog::dependency_changed (QTreeWidgetItem *item, int column
} else {
- SaltGrain *g = 0;
- for (lay::Salt::flat_iterator i = mp_salt->begin_flat (); i != mp_salt->end_flat (); ++i) {
- if ((*i)->name () == name) {
- g = *i;
- }
- }
if (g) {
item->setData (1, Qt::UserRole, tl::to_qstring (g->version ()));
- item->setData (2, Qt::UserRole, tl::to_qstring (g->url ()));
+ item->setData (2, Qt::UserRole, QString ());
// placeholder texts:
item->setData (1, Qt::EditRole, tl::to_qstring (g->version ()));
- item->setData (2, Qt::EditRole, tl::to_qstring (g->url ()));
+ if (! g->url ().empty ()) {
+ item->setData (2, Qt::EditRole, tl::to_qstring ("(" + g->url () + ")"));
+ } else {
+ item->setData (2, Qt::EditRole, tr ("(from repository)"));
+ }
} else {
item->setData (1, Qt::UserRole, QString ());
item->setData (2, Qt::UserRole, QString ());
// placeholder texts:
item->setData (1, Qt::EditRole, QString ());
- item->setData (2, Qt::EditRole, tr ("(unknown packet)"));
+ item->setData (2, Qt::EditRole, tr ("(from repository)"));
}
}
- } else if (column > 0) {
- item->setData (column, Qt::EditRole, item->data (column, Qt::UserRole).toString ());
+ } else if (column == 1) {
+
+ QString text = item->data (column, Qt::UserRole).toString ();
+ if (! text.isEmpty ()) {
+ item->setData (1, Qt::EditRole, text);
+ } else if (g) {
+ item->setData (1, Qt::EditRole, tl::to_qstring (g->version ()));
+ }
+
+ } else if (column == 2) {
+
+ QString text = item->data (column, Qt::UserRole).toString ();
+ if (! text.isEmpty ()) {
+ item->setData (2, Qt::EditRole, text);
+ } else if (g) {
+ if (! g->url ().empty ()) {
+ item->setData (2, Qt::EditRole, tl::to_qstring ("(" + g->url () + ")"));
+ } else {
+ item->setData (2, Qt::EditRole, tr ("(from repository)"));
+ }
+ }
+
}
m_update_enabled = true;
@@ -531,10 +558,7 @@ SaltGrainPropertiesDialog::accept ()
}
dep_seen.insert (d->name);
- if (! dep.is_valid_name (d->name)) {
- dependencies_alert->warn () << tr ("'%1' is not a name of a package loaded already").arg (tl::to_qstring (d->name)) << tl::endl
- << tr ("You need to specify the details (version, URL) manually");
- } else {
+ if (dep.is_valid_name (d->name)) {
try {
dep.check_circular (dep.grain_for_name (m_grain.name ()), dep.grain_for_name (d->name));
} catch (tl::Exception &ex) {
@@ -549,11 +573,7 @@ SaltGrainPropertiesDialog::accept ()
<< tr ("If the dependency package has a version itself, the version is automatically set to it's current version.");
}
- if (d->url.empty ()) {
- dependencies_alert->warn () << tr ("No download URL specified for dependency '%1'").arg (tl::to_qstring (d->name)) << tl::endl
- << tr ("A download URL should be specified to ensure the package dependencies can be resolved.") << tl::endl
- << tr ("If the dependency package was downloaded itself, the URL is automatically set to the download source.");
- } else {
+ if (!d->url.empty ()) {
SaltGrain gdep;
try {
gdep = SaltGrain::from_url (d->url);
diff --git a/src/lay/laySaltManagerDialog.cc b/src/lay/laySaltManagerDialog.cc
index 978dc9c46..aa3ecd745 100644
--- a/src/lay/laySaltManagerDialog.cc
+++ b/src/lay/laySaltManagerDialog.cc
@@ -144,7 +144,7 @@ lay::Salt *get_salt_mine ()
SaltManagerDialog::SaltManagerDialog (QWidget *parent)
: QDialog (parent),
- m_current_changed_enabled (true)
+ m_current_changed_enabled (true), dm_update_models (this, &SaltManagerDialog::update_models)
{
Ui::SaltManagerDialog::setupUi (this);
mp_properties_dialog = new lay::SaltGrainPropertiesDialog (this);
@@ -165,15 +165,6 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent)
salt_mine_view->setModel (mine_model);
salt_mine_view->setItemDelegate (new SaltItemDelegate (this));
- // Establish a message saying that an update is available
- for (Salt::flat_iterator g = mp_salt->begin_flat (); g != mp_salt->end_flat (); ++g) {
- SaltGrain *gm = mp_salt_mine->grain_by_name ((*g)->name ());
- if (gm && SaltGrain::compare_versions (gm->version (), (*g)->version ()) > 0) {
- model->set_message ((*g)->name (), tl::to_string (tr ("An update to version %1 is available").arg (tl::to_qstring (gm->version ()))));
- mine_model->set_message ((*g)->name (), tl::to_string (tr ("The installed version is outdated (%1)").arg (tl::to_qstring ((*g)->version ()))));
- }
- }
-
mode_tab->setCurrentIndex (mp_salt->is_empty () ? 1 : 0);
connect (mode_tab, SIGNAL (currentChanged (int)), this, SLOT (mode_changed ()));
@@ -181,11 +172,12 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent)
connect (mp_salt, SIGNAL (collections_changed ()), this, SLOT (salt_changed ()));
connect (mp_salt_mine, SIGNAL (collections_changed ()), this, SLOT (salt_mine_changed ()));
- salt_changed ();
- salt_mine_changed ();
+ update_models ();
connect (salt_view->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (current_changed ()));
+ connect (salt_view, SIGNAL (doubleClicked (const QModelIndex &)), this, SLOT (edit_properties ()));
connect (salt_mine_view->selectionModel (), SIGNAL (currentChanged (const QModelIndex &, const QModelIndex &)), this, SLOT (mine_current_changed ()), Qt::QueuedConnection);
+ connect (salt_mine_view, SIGNAL (doubleClicked (const QModelIndex &)), this, SLOT (mark_clicked ()));
search_installed_edit->set_clear_button_enabled (true);
search_new_edit->set_clear_button_enabled (true);
@@ -193,6 +185,18 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent)
connect (search_new_edit, SIGNAL (textChanged (const QString &)), this, SLOT (search_text_changed (const QString &)));
connect (mark_button, SIGNAL (clicked ()), this, SLOT (mark_clicked ()));
+
+ salt_mine_view->addAction (actionUnmarkAll);
+ QAction *a = new QAction (this);
+ a->setSeparator (true);
+ salt_mine_view->addAction (a);
+ salt_mine_view->addAction (actionShowMarkedOnly);
+ salt_mine_view->addAction (actionShowAll);
+ salt_mine_view->setContextMenuPolicy (Qt::ActionsContextMenu);
+
+ connect (actionUnmarkAll, SIGNAL (triggered ()), this, SLOT (unmark_all ()));
+ connect (actionShowMarkedOnly, SIGNAL (triggered ()), this, SLOT (show_marked_only ()));
+ connect (actionShowAll, SIGNAL (triggered ()), this, SLOT (show_all ()));
}
void
@@ -201,11 +205,55 @@ SaltManagerDialog::mode_changed ()
// keeps the splitters in sync
if (mode_tab->currentIndex () == 1) {
splitter_new->setSizes (splitter->sizes ());
+ show_all ();
} else if (mode_tab->currentIndex () == 0) {
splitter->setSizes (splitter_new->sizes ());
}
}
+void
+SaltManagerDialog::show_all ()
+{
+ search_new_edit->clear ();
+
+ SaltModel *model = dynamic_cast (salt_mine_view->model ());
+ if (! model) {
+ return;
+ }
+
+ for (int i = model->rowCount (QModelIndex ()); i > 0; ) {
+ --i;
+ salt_mine_view->setRowHidden (i, false);
+ }
+}
+
+void
+SaltManagerDialog::show_marked_only ()
+{
+ search_new_edit->clear ();
+
+ SaltModel *model = dynamic_cast (salt_mine_view->model ());
+ if (! model) {
+ return;
+ }
+
+ for (int i = model->rowCount (QModelIndex ()); i > 0; ) {
+ --i;
+ SaltGrain *g = model->grain_from_index (model->index (i, 0, QModelIndex ()));
+ salt_mine_view->setRowHidden (i, !(g && model->is_marked (g->name ())));
+ }
+}
+
+void
+SaltManagerDialog::unmark_all ()
+{
+ SaltModel *model = dynamic_cast (salt_mine_view->model ());
+ if (model) {
+ model->clear_marked ();
+ update_apply_state ();
+ }
+}
+
void
SaltManagerDialog::search_text_changed (const QString &text)
{
@@ -258,6 +306,36 @@ SaltManagerDialog::mark_clicked ()
}
model->set_marked (g->name (), !model->is_marked (g->name ()));
+ update_apply_state ();
+}
+
+void
+SaltManagerDialog::update_apply_state ()
+{
+ int marked = 0;
+
+ SaltModel *model = dynamic_cast (salt_mine_view->model ());
+ if (! model) {
+ return;
+ }
+
+ for (int i = model->rowCount (QModelIndex ()); i > 0; ) {
+ --i;
+ QModelIndex index = model->index (i, 0, QModelIndex ());
+ SaltGrain *g = model->grain_from_index (index);
+ if (g && model->is_marked (g->name ())) {
+ marked += 1;
+ }
+ }
+
+ apply_button->setEnabled (marked > 0);
+ if (marked == 0) {
+ apply_label->setText (QString ());
+ } else if (marked == 1) {
+ apply_label->setText (tr ("One package selected"));
+ } else if (marked > 1) {
+ apply_label->setText (tr ("%1 packages selected").arg (marked));
+ }
}
void
@@ -290,6 +368,7 @@ BEGIN_PROTECTED
manager.compute_dependencies (*mp_salt, *mp_salt_mine);
if (manager.show_confirmation_dialog (this, *mp_salt)) {
+ unmark_all ();
manager.execute (*mp_salt);
}
@@ -363,16 +442,38 @@ END_PROTECTED
void
SaltManagerDialog::salt_changed ()
+{
+ dm_update_models ();
+}
+
+void
+SaltManagerDialog::salt_mine_changed ()
+{
+ dm_update_models ();
+}
+
+void
+SaltManagerDialog::update_models ()
{
SaltModel *model = dynamic_cast (salt_view->model ());
- if (! model) {
- return;
- }
+ tl_assert (model != 0);
// NOTE: the disabling of the event handler prevents us from
// letting the model connect to the salt's signal directly.
m_current_changed_enabled = false;
+
+ model->clear_messages ();
+
+ // Establish a message saying that an update is available
+ for (Salt::flat_iterator g = mp_salt->begin_flat (); g != mp_salt->end_flat (); ++g) {
+ SaltGrain *gm = mp_salt_mine->grain_by_name ((*g)->name ());
+ if (gm && SaltGrain::compare_versions (gm->version (), (*g)->version ()) > 0) {
+ model->set_message ((*g)->name (), SaltModel::Warning, tl::to_string (tr ("An update to version %1 is available").arg (tl::to_qstring (gm->version ()))));
+ }
+ }
+
model->update ();
+
m_current_changed_enabled = true;
if (mp_salt->is_empty ()) {
@@ -392,7 +493,42 @@ SaltManagerDialog::salt_changed ()
}
+ SaltModel *mine_model = dynamic_cast (salt_mine_view->model ());
+ tl_assert (mine_model != 0);
+
+ // NOTE: the disabling of the event handler prevents us from
+ // letting the model connect to the salt's signal directly.
+ m_current_changed_enabled = false;
+
+ mine_model->clear_order ();
+ mine_model->clear_messages ();
+ mine_model->enable_all ();
+
+ // Establish a message saying that an update is available
+ for (Salt::flat_iterator g = mp_salt->begin_flat (); g != mp_salt->end_flat (); ++g) {
+ SaltGrain *gm = mp_salt_mine->grain_by_name ((*g)->name ());
+ if (gm && SaltGrain::compare_versions (gm->version (), (*g)->version ()) > 0) {
+ mine_model->set_message ((*g)->name (), SaltModel::Warning, tl::to_string (tr ("The installed version is outdated (%1)").arg (tl::to_qstring ((*g)->version ()))));
+ mine_model->set_order ((*g)->name (), -1);
+ } else if (gm) {
+ mine_model->set_message ((*g)->name (), SaltModel::None, tl::to_string (tr ("This package is already installed and up to date")));
+ mine_model->set_order ((*g)->name (), 1);
+ mine_model->set_enabled ((*g)->name (), false);
+ }
+ }
+
+ mine_model->update ();
+
+ m_current_changed_enabled = true;
+
+ // select the first grain
+ if (mine_model->rowCount (QModelIndex ()) > 0) {
+ salt_mine_view->setCurrentIndex (mine_model->index (0, 0, QModelIndex ()));
+ }
+
+ mine_current_changed ();
current_changed ();
+ update_apply_state ();
}
void
@@ -417,28 +553,6 @@ SaltManagerDialog::current_grain ()
return model ? model->grain_from_index (salt_view->currentIndex ()) : 0;
}
-void
-SaltManagerDialog::salt_mine_changed ()
-{
- SaltModel *model = dynamic_cast (salt_mine_view->model ());
- if (! model) {
- return;
- }
-
- // NOTE: the disabling of the event handler prevents us from
- // letting the model connect to the salt's signal directly.
- m_current_changed_enabled = false;
- model->update ();
- m_current_changed_enabled = true;
-
- // select the first grain
- if (model->rowCount (QModelIndex ()) > 0) {
- salt_mine_view->setCurrentIndex (model->index (0, 0, QModelIndex ()));
- }
-
- mine_current_changed ();
-}
-
void
SaltManagerDialog::mine_current_changed ()
{
diff --git a/src/lay/laySaltManagerDialog.h b/src/lay/laySaltManagerDialog.h
index c6e4ff893..6e1f40cf4 100644
--- a/src/lay/laySaltManagerDialog.h
+++ b/src/lay/laySaltManagerDialog.h
@@ -24,6 +24,7 @@
#define HDR_laySaltManagerDialog
#include "ui_SaltManagerDialog.h"
+#include "tlDeferredExecution.h"
#include
#include
@@ -105,14 +106,32 @@ private slots:
*/
void search_text_changed (const QString &text);
-private:
- lay::Salt *mp_salt, *mp_salt_mine;
- std::auto_ptr m_remote_grain;
- bool m_current_changed_enabled;
- lay::SaltGrainPropertiesDialog *mp_properties_dialog;
+ /**
+ * @brief Called to show the marked items only
+ */
+ void show_marked_only ();
- lay::SaltGrain *current_grain ();
- lay::SaltGrain *mine_current_grain ();
+ /**
+ * @brief Called to show all items again
+ */
+ void show_all ();
+
+ /**
+ * @brief Called to unmark all items
+ */
+ void unmark_all ();
+
+private:
+ Salt *mp_salt, *mp_salt_mine;
+ std::auto_ptr m_remote_grain;
+ bool m_current_changed_enabled;
+ SaltGrainPropertiesDialog *mp_properties_dialog;
+ tl::DeferredMethod dm_update_models;
+
+ SaltGrain *current_grain ();
+ SaltGrain *mine_current_grain ();
+ void update_models ();
+ void update_apply_state ();
};
}
diff --git a/src/lay/laySaltModel.cc b/src/lay/laySaltModel.cc
index 57dd44212..fc1a44ef8 100644
--- a/src/lay/laySaltModel.cc
+++ b/src/lay/laySaltModel.cc
@@ -46,6 +46,9 @@ SaltItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option,
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption (&optionV4, index);
+ bool is_enabled = (optionV4.state & QStyle::State_Enabled);
+ optionV4.state |= QStyle::State_Enabled;
+
QStyle *style = optionV4.widget ? optionV4.widget->style () : QApplication::style ();
QTextDocument doc;
@@ -58,6 +61,8 @@ SaltItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option,
if (optionV4.state & QStyle::State_Selected) {
ctx.palette.setColor (QPalette::Text, optionV4.palette.color (QPalette::Active, QPalette::HighlightedText));
+ } else if (! is_enabled) {
+ ctx.palette.setColor (QPalette::Text, optionV4.palette.color (QPalette::Disabled, QPalette::Text));
}
QRect textRect = style->subElementRect (QStyle::SE_ItemViewItemText, &optionV4);
@@ -93,15 +98,32 @@ SaltItemDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelInde
SaltModel::SaltModel (QObject *parent, lay::Salt *salt)
: QAbstractItemModel (parent), mp_salt (salt)
{
- // .. nothing yet ..
+ create_ordered_list ();
}
-QVariant
+Qt::ItemFlags
+SaltModel::flags (const QModelIndex &index) const
+{
+ Qt::ItemFlags f = QAbstractItemModel::flags (index);
+
+ const lay::SaltGrain *g = grain_from_index (index);
+ if (g && ! is_enabled (g->name ())) {
+ f &= ~Qt::ItemIsSelectable;
+ f &= ~Qt::ItemIsEnabled;
+ }
+
+ return f;
+}
+
+QVariant
SaltModel::data (const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
- const lay::SaltGrain *g = mp_salt->begin_flat ()[index.row ()];
+ const lay::SaltGrain *g = grain_from_index (index);
+ if (!g) {
+ return QVariant ();
+ }
std::string text = "";
text += "";
@@ -121,9 +143,15 @@ SaltModel::data (const QModelIndex &index, int role) const
text += "
";
}
- std::map::const_iterator m = m_messages.find (g->name ());
+ std::map >::const_iterator m = m_messages.find (g->name ());
if (m != m_messages.end ()) {
- text += "" + tl::escaped_to_html (m->second) + "
";
+ if (m->second.first == Warning || m->second.first == Error) {
+ text += "" + tl::escaped_to_html (m->second.second) + "
";
+ } else if (m->second.first == Info) {
+ text += "" + tl::escaped_to_html (m->second.second) + "
";
+ } else {
+ text += "" + tl::escaped_to_html (m->second.second) + "
";
+ }
}
text += "";
@@ -134,7 +162,10 @@ SaltModel::data (const QModelIndex &index, int role) const
int icon_dim = 64;
- const lay::SaltGrain *g = mp_salt->begin_flat ()[index.row ()];
+ const lay::SaltGrain *g = grain_from_index (index);
+ if (!g) {
+ return QVariant ();
+ }
QImage img;
if (g->icon ().isNull ()) {
@@ -160,10 +191,21 @@ SaltModel::data (const QModelIndex &index, int role) const
painter.drawImage (0, 0, warn);
}
- if (m_messages.find (g->name ()) != m_messages.end ()) {
- QPainter painter (&img);
- QImage warn (":/warn_16.png");
- painter.drawImage (0, 0, warn);
+ std::map >::const_iterator m = m_messages.find (g->name ());
+ if (m != m_messages.end ()) {
+ if (m->second.first == Warning) {
+ QPainter painter (&img);
+ QImage warn (":/warn_16.png");
+ painter.drawImage (0, 0, warn);
+ } else if (m->second.first == Error) {
+ QPainter painter (&img);
+ QImage warn (":/error_16.png");
+ painter.drawImage (0, 0, warn);
+ } else if (m->second.first == Info) {
+ QPainter painter (&img);
+ QImage warn (":/info_16.png");
+ painter.drawImage (0, 0, warn);
+ }
}
return QPixmap::fromImage (img);
@@ -179,7 +221,7 @@ SaltModel::index (int row, int column, const QModelIndex &parent) const
if (parent.isValid ()) {
return QModelIndex ();
} else {
- return createIndex (row, column, mp_salt->begin_flat () [row]);
+ return createIndex (row, column, m_ordered_grains [row]);
}
}
@@ -201,7 +243,7 @@ SaltModel::rowCount (const QModelIndex &parent) const
if (parent.isValid ()) {
return 0;
} else {
- return mp_salt->end_flat () - mp_salt->begin_flat ();
+ return int (m_ordered_grains.size ());
}
}
@@ -221,32 +263,149 @@ SaltModel::is_marked (const std::string &name) const
return m_marked.find (name) != m_marked.end ();
}
+bool
+SaltModel::is_enabled (const std::string &name) const
+{
+ return m_disabled.find (name) == m_disabled.end ();
+}
+
void
SaltModel::set_marked (const std::string &name, bool marked)
{
- if (! marked) {
- m_marked.erase (name);
- } else {
- m_marked.insert (name);
+ if (marked != is_marked (name)) {
+ if (! marked) {
+ m_marked.erase (name);
+ } else {
+ m_marked.insert (name);
+ }
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
- emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
void
-SaltModel::set_message (const std::string &name, const std::string &message)
+SaltModel::clear_marked ()
{
- if (message.empty ()) {
- m_messages.erase (name);
- } else {
- m_messages.insert (std::make_pair (name, message));
+ if (! m_marked.empty ()) {
+ m_marked.clear ();
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
- emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
}
-void
+void
+SaltModel::set_enabled (const std::string &name, bool enabled)
+{
+ if (enabled != is_enabled (name)) {
+ if (enabled) {
+ m_disabled.erase (name);
+ } else {
+ m_disabled.insert (name);
+ }
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
+ }
+}
+
+void
+SaltModel::enable_all ()
+{
+ if (! m_disabled.empty ()) {
+ m_disabled.clear ();
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
+ }
+}
+
+void
+SaltModel::clear_order ()
+{
+ m_display_order.clear ();
+}
+
+void
+SaltModel::reset_order (const std::string &name)
+{
+ m_display_order.erase (name);
+}
+
+void
+SaltModel::set_order (const std::string &name, int order)
+{
+ m_display_order[name] = order;
+}
+
+void
+SaltModel::set_message (const std::string &name, Severity severity, const std::string &message)
+{
+ bool needs_update = false;
+ if (message.empty ()) {
+ if (m_messages.find (name) != m_messages.end ()) {
+ m_messages.erase (name);
+ needs_update = true;
+ }
+ } else {
+ std::map >::iterator m = m_messages.find (name);
+ if (m == m_messages.end () || m->second.second != message || m->second.first != severity) {
+ m_messages.insert (std::make_pair (name, std::make_pair (severity, message)));
+ needs_update = true;
+ }
+ }
+
+ if (needs_update) {
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
+ }
+}
+
+void
+SaltModel::clear_messages ()
+{
+ if (! m_messages.empty ()) {
+ m_messages.clear ();
+ emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, 0, QModelIndex ()));
+ }
+}
+
+void
SaltModel::update ()
{
+ create_ordered_list ();
reset ();
}
+void
+SaltModel::create_ordered_list ()
+{
+ m_ordered_grains.clear ();
+
+ if (m_display_order.empty ()) {
+
+ for (Salt::flat_iterator i = mp_salt->begin_flat (); i != mp_salt->end_flat (); ++i) {
+ m_ordered_grains.push_back (*i);
+ }
+
+ } else {
+
+ int min_order = m_display_order.begin ()->second;
+ int max_order = min_order;
+ min_order = std::min (min_order, 0);
+ max_order = std::max (max_order, 0);
+
+ for (std::map::const_iterator i = m_display_order.begin (); i != m_display_order.end (); ++i) {
+ min_order = std::min (min_order, i->second);
+ max_order = std::max (max_order, i->second);
+ }
+
+ for (int o = min_order; o <= max_order; ++o) {
+ for (Salt::flat_iterator i = mp_salt->begin_flat (); i != mp_salt->end_flat (); ++i) {
+ std::map::const_iterator d = m_display_order.find ((*i)->name ());
+ int oi = 0;
+ if (d != m_display_order.end ()) {
+ oi = d->second;
+ }
+ if (oi == o) {
+ m_ordered_grains.push_back (*i);
+ }
+ }
+ }
+
+ }
+}
+
}
diff --git a/src/lay/laySaltModel.h b/src/lay/laySaltModel.h
index 20a537e2c..d7ba80d92 100644
--- a/src/lay/laySaltModel.h
+++ b/src/lay/laySaltModel.h
@@ -47,6 +47,17 @@ class SaltModel
Q_OBJECT
public:
+ /**
+ * @brief An enum describing the severity of a message
+ */
+ enum Severity
+ {
+ None = 0,
+ Info = 1,
+ Warning = 2,
+ Error = 3
+ };
+
/**
* @brief Constructor
*/
@@ -57,6 +68,11 @@ public:
*/
QVariant data (const QModelIndex &index, int role) const;
+ /**
+ * @brief Implementation of the QAbstractItemModel interface
+ */
+ Qt::ItemFlags flags (const QModelIndex &index) const;
+
/**
* @brief Implementation of the QAbstractItemModel interface
*/
@@ -93,18 +109,70 @@ public:
*/
void set_marked (const std::string &name, bool marked);
+ /**
+ * @brief Clears the marked state of all grains
+ */
+ void clear_marked ();
+
+ /**
+ * @brief Enables or disables the grain with the given name
+ */
+ void set_enabled (const std::string &name, bool enabled);
+
+ /**
+ * @brief Enables all grains
+ */
+ void enable_all ();
+
/**
* @brief Installs a message on the grain with the given name
* Installing an empty message basically removes the message.
*/
- void set_message (const std::string &name, const std::string &message);
+ void set_message (const std::string &name, Severity severity, const std::string &message);
+
+ /**
+ * @brief Removes a message
+ */
+ void reset_message (const std::string &name)
+ {
+ set_message (name, None, std::string ());
+ }
+
+ /**
+ * @brief Clears all messages
+ */
+ void clear_messages ();
+
+ /**
+ * @brief Sets the display order
+ * Specifying a display order for a name will make the grain appear
+ * before or after other grains.
+ * "update" needs to be called before the order becomes active.
+ * Non-assigned items are considered to have order (0).
+ */
+ void set_order (const std::string &name, int order);
+
+ /**
+ * @brief Resets any display order
+ */
+ void reset_order (const std::string &name);
+
+ /**
+ * @brief Resets all display order specs
+ */
+ void clear_order ();
public:
lay::Salt *mp_salt;
std::set m_marked;
- std::map m_messages;
+ std::set m_disabled;
+ std::map > m_messages;
+ std::map m_display_order;
+ std::vector m_ordered_grains;
bool is_marked (const std::string &name) const;
+ bool is_enabled (const std::string &name) const;
+ void create_ordered_list ();
};
// --------------------------------------------------------------------------------------
diff --git a/src/tl/tlString.cc b/src/tl/tlString.cc
index 22d05402f..3179df4ac 100644
--- a/src/tl/tlString.cc
+++ b/src/tl/tlString.cc
@@ -416,6 +416,20 @@ tl::to_word_or_quoted_string (const std::string &s, const char *non_term)
void
tl::escape_to_html (std::string &out, const std::string &in, bool replace_newlines)
{
+
+
+
+
+
+
+
+
+
+
+
+
+
+
for (const char *cp = in.c_str (); *cp; ++cp) {
if (*cp == '<') {
out += "<";
diff --git a/src/tl/tlWebDAV.cc b/src/tl/tlWebDAV.cc
index 19c2a004e..04706e78e 100644
--- a/src/tl/tlWebDAV.cc
+++ b/src/tl/tlWebDAV.cc
@@ -273,8 +273,10 @@ WebDAVObject::download (const std::string &url, const std::string &target)
bool has_errors = false;
{
- tl::info << tl::to_string (QObject::tr ("Downloading %1 files now").arg (items.size ()));
+ tl::info << tl::to_string (QObject::tr ("Downloading %1 file(s) now ..").arg (items.size ()));
+
tl::RelativeProgress progress (tl::to_string (QObject::tr ("Downloading file(s) from %1").arg (tl::to_qstring (url))), items.size (), 1);
+
for (std::list::const_iterator i = items.begin (); i != items.end (); ++i) {
tl::info << QObject::tr ("Downloading '%1' to '%2' ..").arg (tl::to_qstring (i->url)).arg (tl::to_qstring (i->path));
@@ -307,6 +309,8 @@ WebDAVObject::download (const std::string &url, const std::string &target)
has_errors = true;
}
+ ++progress;
+
}
}