mirror of https://github.com/KLayout/klayout.git
WIP: Library controller plus a bugfix
The bug was that a crash happened when a package was deleted. Essentially that was an effect of too many message boxes asking to run autorun macros (also a bug - solved by deferred execution of the macro update). This is solved by putting the salt model into a "under construction" state while the model is not updated yet.
This commit is contained in:
parent
9c2c3301cf
commit
a7038282ce
|
|
@ -57,7 +57,8 @@ HEADERS = \
|
|||
laySaltDownloadManager.h \
|
||||
laySaltModel.h \
|
||||
laySaltController.h \
|
||||
laySignalHandler.h
|
||||
laySignalHandler.h \
|
||||
layLibraryController.h
|
||||
|
||||
FORMS = \
|
||||
ClipDialog.ui \
|
||||
|
|
@ -160,7 +161,8 @@ SOURCES = \
|
|||
laySaltDownloadManager.cc \
|
||||
laySaltModel.cc \
|
||||
laySaltController.cc \
|
||||
laySignalHandler.cc
|
||||
laySignalHandler.cc \
|
||||
layLibraryController.cc
|
||||
|
||||
RESOURCES = layBuildInMacros.qrc \
|
||||
layHelpResources.qrc \
|
||||
|
|
|
|||
|
|
@ -1055,48 +1055,6 @@ Application::run ()
|
|||
|
||||
}
|
||||
|
||||
// scan for libraries
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
|
||||
QDir lp = QDir (tl::to_qstring (*p)).filePath (tl::to_qstring ("libraries"));
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*");
|
||||
|
||||
QStringList libs = lp.entryList (name_filters, QDir::Files);
|
||||
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
|
||||
|
||||
std::string filename = tl::to_string (*im);
|
||||
|
||||
try {
|
||||
|
||||
std::auto_ptr<db::Library> lib (new db::Library ());
|
||||
lib->set_description (filename);
|
||||
lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
|
||||
|
||||
tl::log << "Reading library '" << filename << "'";
|
||||
tl::InputStream stream (tl::to_string (lp.filePath (*im)));
|
||||
db::Reader reader (stream);
|
||||
reader.read (lib->layout ());
|
||||
|
||||
// Use the libname if there is one
|
||||
for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) {
|
||||
if (m->name == "libname" && ! m->value.empty ()) {
|
||||
lib->set_name (m->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
db::LibraryManager::instance ().register_lib (lib.release ());
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// run all autorun macros
|
||||
lay::MacroCollection::root ().autorun ();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,261 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layLibraryController.h"
|
||||
#include "layApplication.h"
|
||||
#include "laySaltController.h"
|
||||
#include "layConfig.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layQtTools.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbReader.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
LibraryController::LibraryController ()
|
||||
: m_file_watcher (0),
|
||||
dm_sync_files (this, &LibraryController::sync_files)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::initialize (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
// NOTE: we initialize the libraries in the stage once to have them available for the autorun
|
||||
// macros. We'll do that later again in order to pull in the libraries from the packages.
|
||||
sync_files ();
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::initialized (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
if (lay::SaltController::instance ()) {
|
||||
connect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
|
||||
if (! m_file_watcher) {
|
||||
m_file_watcher = new tl::FileSystemWatcher (this);
|
||||
connect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
connect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
}
|
||||
|
||||
sync_files ();
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::uninitialize (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
if (m_file_watcher) {
|
||||
disconnect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
disconnect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
delete m_file_watcher;
|
||||
m_file_watcher = 0;
|
||||
}
|
||||
|
||||
if (lay::SaltController::instance ()) {
|
||||
disconnect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::get_menu_entries (std::vector<lay::MenuEntry> & /*menu_entries*/) const
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
LibraryController::configure (const std::string & /*name*/, const std::string & /*value*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::config_finalize()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
LibraryController::can_exit (lay::PluginRoot * /*root*/) const
|
||||
{
|
||||
// .. nothing yet ..
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::sync_files ()
|
||||
{
|
||||
if (! m_file_watcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
|
||||
std::map<std::string, std::pair<std::string, QDateTime> > new_lib_files;
|
||||
|
||||
std::vector<std::string> paths = lay::Application::instance ()->klayout_path ();
|
||||
|
||||
// add the salt grains as potential sources for library definitions
|
||||
|
||||
lay::SaltController *sc = lay::SaltController::instance ();
|
||||
if (sc) {
|
||||
for (lay::Salt::flat_iterator g = sc->salt ().begin_flat (); g != sc->salt ().end_flat (); ++g) {
|
||||
paths.push_back ((*g)->path ());
|
||||
}
|
||||
}
|
||||
|
||||
// scan for libraries
|
||||
|
||||
for (std::vector <std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
|
||||
QDir lp = QDir (tl::to_qstring (*p)).filePath (tl::to_qstring ("libraries"));
|
||||
m_file_watcher->add_file (tl::to_string (lp.absolutePath ()));
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*");
|
||||
|
||||
QStringList libs = lp.entryList (name_filters, QDir::Files);
|
||||
for (QStringList::const_iterator im = libs.begin (); im != libs.end (); ++im) {
|
||||
|
||||
std::string filename = tl::to_string (*im);
|
||||
std::string lib_path = tl::to_string (lp.absoluteFilePath (*im));
|
||||
|
||||
try {
|
||||
|
||||
QFileInfo fi (tl::to_qstring (lib_path));
|
||||
|
||||
bool needs_load = false;
|
||||
std::map<std::string, std::pair<std::string, QDateTime> >::iterator ll = m_lib_files.find (lib_path);
|
||||
if (ll == m_lib_files.end ()) {
|
||||
needs_load = true;
|
||||
} else {
|
||||
if (fi.lastModified () > ll->second.second) {
|
||||
needs_load = true;
|
||||
} else {
|
||||
new_lib_files.insert (*ll);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_load) {
|
||||
|
||||
std::auto_ptr<db::Library> lib (new db::Library ());
|
||||
lib->set_description (filename);
|
||||
lib->set_name (tl::to_string (QFileInfo (*im).baseName ()));
|
||||
|
||||
tl::log << "Reading library '" << filename << "'";
|
||||
tl::InputStream stream (lib_path);
|
||||
db::Reader reader (stream);
|
||||
reader.read (lib->layout ());
|
||||
|
||||
// Use the libname if there is one
|
||||
for (db::Layout::meta_info_iterator m = lib->layout ().begin_meta (); m != lib->layout ().end_meta (); ++m) {
|
||||
if (m->name == "libname" && ! m->value.empty ()) {
|
||||
lib->set_name (m->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new_lib_files.insert (std::make_pair (lib_path, std::make_pair (lib->get_name (), fi.lastModified ())));
|
||||
|
||||
db::LibraryManager::instance ().register_lib (lib.release ());
|
||||
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_file_watcher->enable (true);
|
||||
|
||||
// remove libraries which are no longer present
|
||||
|
||||
std::set<std::string> new_names;
|
||||
|
||||
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = new_lib_files.begin (); lf != new_lib_files.end (); ++lf) {
|
||||
new_names.insert (lf->second.first);
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::pair<std::string, QDateTime> >::const_iterator lf = m_lib_files.begin (); lf != m_lib_files.end (); ++lf) {
|
||||
if (new_names.find (lf->second.first) == new_names.end ()) {
|
||||
try {
|
||||
std::pair<bool, db::lib_id_type> li = db::LibraryManager::instance ().lib_by_name (lf->second.first);
|
||||
if (li.first) {
|
||||
db::LibraryManager::instance ().delete_lib (db::LibraryManager::instance ().lib (li.second));
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// establish the new libraries
|
||||
|
||||
m_lib_files = new_lib_files;
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::sync_with_external_sources ()
|
||||
{
|
||||
tl::log << tl::to_string (tr ("Package updates - updating libraries"));
|
||||
dm_sync_files ();
|
||||
}
|
||||
|
||||
void
|
||||
LibraryController::file_watcher_triggered ()
|
||||
{
|
||||
tl::log << tl::to_string (tr ("Detected file system change in libraries - updating"));
|
||||
dm_sync_files ();
|
||||
}
|
||||
|
||||
LibraryController *
|
||||
LibraryController::instance ()
|
||||
{
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
LibraryController *sc = dynamic_cast <LibraryController *> (cls.operator-> ());
|
||||
if (sc) {
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The singleton instance of the library controller
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> salt_controller_decl (new lay::LibraryController (), 150, "LibraryController");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_layLibraryController
|
||||
#define HDR_layLibraryController
|
||||
|
||||
#include "layCommon.h"
|
||||
#include "layPlugin.h"
|
||||
#include "tlFileSystemWatcher.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class LibraryManagerDialog;
|
||||
class MainWindow;
|
||||
|
||||
/**
|
||||
* @brief A controller for the libraries
|
||||
*
|
||||
* This object is a singleton that acts as a controller
|
||||
* for the library management. The controller is responsible
|
||||
* to managing the libraries and notifying library consumers
|
||||
* of changes.
|
||||
*
|
||||
* By making the controller a PluginDeclaration it will receive
|
||||
* initialization and configuration calls.
|
||||
*/
|
||||
class LibraryController
|
||||
: public lay::PluginDeclaration, public tl::Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
LibraryController ();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void initialize (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void initialized (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void uninitialize (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
void get_options (std::vector < std::pair<std::string, std::string> > &options) const;
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const;
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
bool configure (const std::string &key, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
void config_finalize();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
bool can_exit (lay::PluginRoot *root) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the singleton instance for this object
|
||||
*/
|
||||
static LibraryController *instance ();
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Called when the file watcher detects a change in the file system
|
||||
*/
|
||||
void file_watcher_triggered ();
|
||||
|
||||
/**
|
||||
* @brief Called when the salt (packages) has changed
|
||||
*/
|
||||
void sync_with_external_sources ();
|
||||
|
||||
private:
|
||||
tl::FileSystemWatcher *m_file_watcher;
|
||||
tl::DeferredMethod<LibraryController> dm_sync_files;
|
||||
std::map<std::string, std::pair<std::string, QDateTime> > m_lib_files;
|
||||
|
||||
void sync_files ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ namespace lay
|
|||
MacroController::MacroController ()
|
||||
: mp_macro_editor (0), mp_mw (0), m_no_implicit_macros (false), m_file_watcher (0),
|
||||
dm_do_update_menu_with_macros (this, &MacroController::do_update_menu_with_macros),
|
||||
dm_do_sync_with_external_sources (this, &MacroController::do_sync_with_external_sources),
|
||||
dm_sync_file_watcher (this, &MacroController::sync_file_watcher),
|
||||
dm_sync_files (this, &MacroController::sync_files)
|
||||
{
|
||||
|
|
@ -288,7 +289,7 @@ MacroController::enable_implicit_macros (bool enable)
|
|||
}
|
||||
|
||||
void
|
||||
MacroController::sync_implicit_macros (bool check_autorun)
|
||||
MacroController::sync_implicit_macros (bool ask_before_autorun)
|
||||
{
|
||||
if (m_no_implicit_macros) {
|
||||
return;
|
||||
|
|
@ -427,7 +428,7 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
|
||||
}
|
||||
|
||||
if (check_autorun) {
|
||||
{
|
||||
|
||||
// This prevents the message dialog below to issue deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
|
@ -438,7 +439,7 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
}
|
||||
|
||||
if (has_autorun) {
|
||||
if (QMessageBox::question (mp_mw, QObject::tr ("Run Macros"), QObject::tr ("Some macros associated with new items are configured to run automatically.\n\nChoose 'Yes' to run these macros now. Choose 'No' to not run them."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
if (! ask_before_autorun || QMessageBox::question (mp_mw, QObject::tr ("Run Macros"), QObject::tr ("Some macros associated with new items are configured to run automatically.\n\nChoose 'Yes' to run these macros now. Choose 'No' to not run them."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
for (std::vector<lay::MacroCollection *>::const_iterator m = new_folders.begin (); m != new_folders.end (); ++m) {
|
||||
(*m)->autorun ();
|
||||
}
|
||||
|
|
@ -547,6 +548,12 @@ MacroController::add_macro_items_to_menu (lay::MacroCollection &collection, int
|
|||
|
||||
void
|
||||
MacroController::sync_with_external_sources ()
|
||||
{
|
||||
dm_do_sync_with_external_sources ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::do_sync_with_external_sources ()
|
||||
{
|
||||
try {
|
||||
sync_implicit_macros (true);
|
||||
|
|
|
|||
|
|
@ -220,12 +220,14 @@ private:
|
|||
std::vector<ExternalPathDescriptor> m_external_paths;
|
||||
tl::FileSystemWatcher *m_file_watcher;
|
||||
tl::DeferredMethod<MacroController> dm_do_update_menu_with_macros;
|
||||
tl::DeferredMethod<MacroController> dm_do_sync_with_external_sources;
|
||||
tl::DeferredMethod<MacroController> dm_sync_file_watcher;
|
||||
tl::DeferredMethod<MacroController> dm_sync_files;
|
||||
|
||||
void sync_implicit_macros (bool check_autorun);
|
||||
void sync_implicit_macros (bool ask_before_autorun);
|
||||
void add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech, std::vector<std::pair<std::string, std::string> > *key_bindings);
|
||||
void do_update_menu_with_macros ();
|
||||
void do_sync_with_external_sources ();
|
||||
void sync_file_watcher ();
|
||||
void sync_files ();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ Salt::Salt (const Salt &other)
|
|||
Salt &Salt::operator= (const Salt &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
emit collections_about_to_change ();
|
||||
m_root = other.m_root;
|
||||
invalidate ();
|
||||
}
|
||||
|
|
@ -97,6 +98,7 @@ Salt::add_location (const std::string &path)
|
|||
}
|
||||
|
||||
lay::SaltGrains gg = lay::SaltGrains::from_path (path);
|
||||
emit collections_about_to_change ();
|
||||
m_root.add_collection (gg);
|
||||
invalidate ();
|
||||
}
|
||||
|
|
@ -107,6 +109,7 @@ Salt::remove_location (const std::string &path)
|
|||
QFileInfo fi (tl::to_qstring (path));
|
||||
for (lay::SaltGrains::collection_iterator g = m_root.begin_collections (); g != m_root.end_collections (); ++g) {
|
||||
if (QFileInfo (tl::to_qstring (g->path ())) == fi) {
|
||||
emit collections_about_to_change ();
|
||||
m_root.remove_collection (g, false);
|
||||
invalidate ();
|
||||
return;
|
||||
|
|
@ -122,6 +125,7 @@ Salt::refresh ()
|
|||
new_root.add_collection (lay::SaltGrains::from_path (g->path ()));
|
||||
}
|
||||
if (new_root != m_root) {
|
||||
emit collections_about_to_change ();
|
||||
m_root = new_root;
|
||||
invalidate ();
|
||||
}
|
||||
|
|
@ -208,21 +212,18 @@ bool remove_from_collection (SaltGrains &collection, const std::string &name)
|
|||
bool
|
||||
Salt::remove_grain (const SaltGrain &grain)
|
||||
{
|
||||
emit collections_about_to_change ();
|
||||
|
||||
tl::info << QObject::tr ("Removing package '%1' ..").arg (tl::to_qstring (grain.name ()));
|
||||
if (remove_from_collection (m_root, grain.name ())) {
|
||||
|
||||
bool res = remove_from_collection (m_root, grain.name ());
|
||||
if (res) {
|
||||
tl::info << QObject::tr ("Package '%1' removed.").arg (tl::to_qstring (grain.name ()));
|
||||
|
||||
// NOTE: this is a bit brute force .. we could as well try to insert the new grain into the existing structure
|
||||
refresh ();
|
||||
|
||||
invalidate ();
|
||||
return true;
|
||||
|
||||
} else {
|
||||
tl::warn << QObject::tr ("Failed to remove package '%1'.").arg (tl::to_qstring (grain.name ()));
|
||||
return false;
|
||||
}
|
||||
|
||||
invalidate ();
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
|
|||
|
|
@ -186,6 +186,11 @@ public:
|
|||
bool create_grain (const SaltGrain &templ, SaltGrain &target);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief A signal triggered before one of the collections changed
|
||||
*/
|
||||
void collections_about_to_change ();
|
||||
|
||||
/**
|
||||
* @brief A signal triggered when one of the collections changed
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -137,7 +137,9 @@ SaltManagerDialog::SaltManagerDialog (QWidget *parent, lay::Salt *salt, lay::Sal
|
|||
connect (mode_tab, SIGNAL (currentChanged (int)), this, SLOT (mode_changed ()));
|
||||
|
||||
connect (mp_salt, SIGNAL (collections_changed ()), this, SLOT (salt_changed ()));
|
||||
connect (mp_salt, SIGNAL (collections_about_to_change ()), this, SLOT (salt_about_to_change ()));
|
||||
connect (mp_salt_mine, SIGNAL (collections_changed ()), this, SLOT (salt_mine_changed ()));
|
||||
connect (mp_salt_mine, SIGNAL (collections_about_to_change ()), this, SLOT (salt_mine_about_to_change ()));
|
||||
|
||||
update_models ();
|
||||
|
||||
|
|
@ -407,12 +409,28 @@ BEGIN_PROTECTED
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
SaltManagerDialog::salt_about_to_change ()
|
||||
{
|
||||
SaltModel *model = dynamic_cast <SaltModel *> (salt_view->model ());
|
||||
tl_assert (model != 0);
|
||||
model->begin_update ();
|
||||
}
|
||||
|
||||
void
|
||||
SaltManagerDialog::salt_changed ()
|
||||
{
|
||||
dm_update_models ();
|
||||
}
|
||||
|
||||
void
|
||||
SaltManagerDialog::salt_mine_about_to_change ()
|
||||
{
|
||||
SaltModel *mine_model = dynamic_cast <SaltModel *> (salt_mine_view->model ());
|
||||
tl_assert (mine_model != 0);
|
||||
mine_model->begin_update ();
|
||||
}
|
||||
|
||||
void
|
||||
SaltManagerDialog::salt_mine_changed ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,11 +51,21 @@ public:
|
|||
SaltManagerDialog (QWidget *parent, lay::Salt *salt, lay::Salt *salt_mine);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Called when the list of packages (grains) is about to change
|
||||
*/
|
||||
void salt_about_to_change ();
|
||||
|
||||
/**
|
||||
* @brief Called when the list of packages (grains) has changed
|
||||
*/
|
||||
void salt_changed ();
|
||||
|
||||
/**
|
||||
* @brief Called when the repository (salt mine) is about to change
|
||||
*/
|
||||
void salt_mine_about_to_change ();
|
||||
|
||||
/**
|
||||
* @brief Called when the repository (salt mine) has changed
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ SaltItemDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelInde
|
|||
// --------------------------------------------------------------------------------------
|
||||
|
||||
SaltModel::SaltModel (QObject *parent, lay::Salt *salt)
|
||||
: QAbstractItemModel (parent), mp_salt (salt)
|
||||
: QAbstractItemModel (parent), mp_salt (salt), m_in_update (false)
|
||||
{
|
||||
create_ordered_list ();
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ SaltModel::index (int row, int column, const QModelIndex &parent) const
|
|||
if (parent.isValid ()) {
|
||||
return QModelIndex ();
|
||||
} else {
|
||||
return createIndex (row, column, m_ordered_grains [row]);
|
||||
return createIndex (row, column);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,8 +250,8 @@ SaltModel::rowCount (const QModelIndex &parent) const
|
|||
SaltGrain *
|
||||
SaltModel::grain_from_index (const QModelIndex &index) const
|
||||
{
|
||||
if (index.isValid ()) {
|
||||
return static_cast<SaltGrain *> (index.internalPointer ());
|
||||
if (index.isValid () && index.row () >= 0 && index.row () < int (m_ordered_grains.size ())) {
|
||||
return m_ordered_grains [index.row ()];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -362,11 +362,23 @@ SaltModel::clear_messages ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SaltModel::begin_update ()
|
||||
{
|
||||
if (! m_in_update) {
|
||||
m_ordered_grains.clear ();
|
||||
beginResetModel ();
|
||||
m_in_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SaltModel::update ()
|
||||
{
|
||||
begin_update ();
|
||||
create_ordered_list ();
|
||||
reset ();
|
||||
endResetModel ();
|
||||
m_in_update = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -98,6 +98,13 @@ public:
|
|||
*/
|
||||
SaltGrain *grain_from_index (const QModelIndex &index) const;
|
||||
|
||||
/**
|
||||
* @brief Marks the model as "under construction"
|
||||
* This method can be called (multiple times) before update to mark the model
|
||||
* as being under construction. update() will end this state.
|
||||
*/
|
||||
void begin_update ();
|
||||
|
||||
/**
|
||||
* @brief Updates the model
|
||||
* Needs to be called when the salt has changed.
|
||||
|
|
@ -169,6 +176,7 @@ public:
|
|||
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 m_in_update;
|
||||
|
||||
bool is_marked (const std::string &name) const;
|
||||
bool is_enabled (const std::string &name) const;
|
||||
|
|
|
|||
Loading…
Reference in New Issue