mirror of https://github.com/KLayout/klayout.git
WIP: various enhancements for salt manager
* double-click * salt mine context menu * bug fixes * etc.
This commit is contained in:
parent
cb589dc2d3
commit
7228efc7bd
|
|
@ -231,8 +231,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>537</width>
|
||||
<height>284</height>
|
||||
<width>343</width>
|
||||
<height>207</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
|
|
@ -673,6 +673,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="apply_label">
|
||||
<property name="text">
|
||||
<string>Set in code</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
|
@ -725,16 +732,19 @@
|
|||
<string>Delete package</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport">
|
||||
<property name="icon">
|
||||
<iconset resource="layResources.qrc">
|
||||
<normaloff>:/import.png</normaloff>:/import.png</iconset>
|
||||
</property>
|
||||
<action name="actionUnmarkAll">
|
||||
<property name="text">
|
||||
<string>Import</string>
|
||||
<string>Unmark all</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Import package</string>
|
||||
</action>
|
||||
<action name="actionShowMarkedOnly">
|
||||
<property name="text">
|
||||
<string>Show marked only</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShowAll">
|
||||
<property name="text">
|
||||
<string>Show all</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="list">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="rootIsDecorated">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Package</string>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 336 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 424 B |
|
|
@ -49,6 +49,7 @@ Salt &Salt::operator= (const Salt &other)
|
|||
{
|
||||
if (this != &other) {
|
||||
m_root = other.m_root;
|
||||
invalidate ();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "ui_SaltManagerInstallConfirmationDialog.h"
|
||||
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QMessageBox>
|
||||
|
||||
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<std::string, Descriptor> registry;
|
||||
|
||||
// remove those registered entries which don't need to be updated
|
||||
|
||||
registry = m_registry;
|
||||
for (std::map<std::string, Descriptor>::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<std::string, Descriptor> registry = m_registry;
|
||||
registry = m_registry;
|
||||
for (std::map<std::string, Descriptor>::const_iterator p = registry.begin (); p != registry.end (); ++p) {
|
||||
|
||||
for (std::vector<SaltGrain::Dependency>::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<std::string, Descriptor>::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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -226,8 +226,11 @@ SaltGrainDetailsTextWidget::details_text ()
|
|||
stream << "<p><b>" << QObject::tr ("Depends on: ") << "</b><br/>";
|
||||
for (std::vector<lay::SaltGrain::Dependency>::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)) << "]<br/>";
|
||||
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)) << "]<br/>";
|
||||
}
|
||||
}
|
||||
stream << "</p>";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,12 +169,19 @@ SaltGrainPropertiesDialog::update_controls ()
|
|||
|
||||
dependencies->clear ();
|
||||
for (std::vector<SaltGrain::Dependency>::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);
|
||||
|
|
|
|||
|
|
@ -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 <SaltModel *> (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 <SaltModel *> (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 <SaltModel *> (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 <SaltModel *> (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 <SaltModel *> (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 <SaltModel *> (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 <SaltModel *> (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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#define HDR_laySaltManagerDialog
|
||||
|
||||
#include "ui_SaltManagerDialog.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
|
|
@ -105,14 +106,32 @@ private slots:
|
|||
*/
|
||||
void search_text_changed (const QString &text);
|
||||
|
||||
private:
|
||||
lay::Salt *mp_salt, *mp_salt_mine;
|
||||
std::auto_ptr<lay::SaltGrain> 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<SaltGrain> m_remote_grain;
|
||||
bool m_current_changed_enabled;
|
||||
SaltGrainPropertiesDialog *mp_properties_dialog;
|
||||
tl::DeferredMethod<SaltManagerDialog> dm_update_models;
|
||||
|
||||
SaltGrain *current_grain ();
|
||||
SaltGrain *mine_current_grain ();
|
||||
void update_models ();
|
||||
void update_apply_state ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = "<html><body>";
|
||||
text += "<h4>";
|
||||
|
|
@ -121,9 +143,15 @@ SaltModel::data (const QModelIndex &index, int role) const
|
|||
text += "</p>";
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>::const_iterator m = m_messages.find (g->name ());
|
||||
std::map<std::string, std::pair<Severity, std::string> >::const_iterator m = m_messages.find (g->name ());
|
||||
if (m != m_messages.end ()) {
|
||||
text += "<p><font color=\"#ff0000\"><b>" + tl::escaped_to_html (m->second) + "</b></font></p>";
|
||||
if (m->second.first == Warning || m->second.first == Error) {
|
||||
text += "<p><font color=\"#ff0000\"><b>" + tl::escaped_to_html (m->second.second) + "</b></font></p>";
|
||||
} else if (m->second.first == Info) {
|
||||
text += "<p><font color=\"#c0c0c0\">" + tl::escaped_to_html (m->second.second) + "</font></p>";
|
||||
} else {
|
||||
text += "<p>" + tl::escaped_to_html (m->second.second) + "</p>";
|
||||
}
|
||||
}
|
||||
|
||||
text += "</body></html>";
|
||||
|
|
@ -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<std::string, std::pair<Severity, std::string> >::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<std::string, std::pair<Severity, std::string> >::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<std::string, int>::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<std::string, int>::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<std::string> m_marked;
|
||||
std::map<std::string, std::string> m_messages;
|
||||
std::set<std::string> m_disabled;
|
||||
std::map<std::string, std::pair<Severity, std::string> > m_messages;
|
||||
std::map<std::string, int> m_display_order;
|
||||
std::vector<SaltGrain *> m_ordered_grains;
|
||||
|
||||
bool is_marked (const std::string &name) const;
|
||||
bool is_enabled (const std::string &name) const;
|
||||
void create_ordered_list ();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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 += "<";
|
||||
|
|
|
|||
|
|
@ -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<DownloadItem>::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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue