mirror of https://github.com/KLayout/klayout.git
WIP: technologies now are synced with salt
- The technology list now is synched with the salt package manager so it's basically possible to include technologies into packages. This checkin also contains: - A "NoDeferredMethods" class that blocks execution of deferred methods in a region of code (preferably around message boxes). This prevents side effects when message boxes are shown and deferred methods are processed because of this. That prevention method is used in the macro controller when asking whether to execute autorun macros (that happens in slots and must not interfere with deferred methods). It's also used to protect the exception handlers. - The tech manager dialog's refresh function used to crash because of an invalid tech pointer.
This commit is contained in:
parent
4460819a6c
commit
d5bf24666f
|
|
@ -81,6 +81,9 @@ namespace lay
|
|||
|
||||
static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent)
|
||||
{
|
||||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
|
|
@ -123,6 +126,9 @@ static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent)
|
|||
|
||||
static void ui_exception_handler_std (const std::exception &ex, QWidget *parent)
|
||||
{
|
||||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
|
|
@ -138,6 +144,9 @@ static void ui_exception_handler_std (const std::exception &ex, QWidget *parent)
|
|||
|
||||
static void ui_exception_handler_def (QWidget *parent)
|
||||
{
|
||||
// Prevents severe side effects if there are pending deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
// if any transaction is pending (this may happen when an operation threw an exception)
|
||||
// close transactions.
|
||||
if (lay::MainWindow::instance () && lay::MainWindow::instance ()->manager ().transacting ()) {
|
||||
|
|
@ -597,10 +606,9 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
|
||||
if (sc) {
|
||||
|
||||
// auto-import technologies
|
||||
// auto-import salt grains
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
std::string tp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 ("salt")));
|
||||
sc->add_path (tp);
|
||||
sc->add_path (*p);
|
||||
}
|
||||
|
||||
sc->set_salt_mine_url (tl::salt_mine_url ());
|
||||
|
|
@ -611,8 +619,7 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
|
||||
// auto-import technologies
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
std::string tp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 ("tech")));
|
||||
tc->add_path (tp);
|
||||
tc->add_path (*p);
|
||||
}
|
||||
|
||||
// import technologies from the command line
|
||||
|
|
|
|||
|
|
@ -429,14 +429,19 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
|
||||
if (check_autorun) {
|
||||
|
||||
// This prevents the message dialog below to issue deferred methods
|
||||
tl::NoDeferredMethods silent;
|
||||
|
||||
bool has_autorun = false;
|
||||
for (std::vector<lay::MacroCollection *>::const_iterator m = new_folders.begin (); m != new_folders.end () && ! has_autorun; ++m) {
|
||||
has_autorun = (*m)->has_autorun ();
|
||||
}
|
||||
|
||||
if (has_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 ();
|
||||
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) {
|
||||
for (std::vector<lay::MacroCollection *>::const_iterator m = new_folders.begin (); m != new_folders.end (); ++m) {
|
||||
(*m)->autorun ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "layQtTools.h"
|
||||
#include "tlLog.h"
|
||||
|
||||
#include <QDir>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
|
|
@ -141,7 +143,11 @@ SaltController::show_editor ()
|
|||
}
|
||||
}
|
||||
|
||||
// while running the dialog, don't watch file events - that would interfere with
|
||||
// the changes applied by the dialog itself.
|
||||
m_file_watcher->enable (false);
|
||||
mp_salt_dialog->exec ();
|
||||
m_file_watcher->enable (true);
|
||||
|
||||
if (mp_mw) {
|
||||
mp_mw->config_set (cfg_salt_manager_window_state, lay::save_dialog_state (mp_salt_dialog));
|
||||
|
|
@ -174,9 +180,14 @@ void
|
|||
SaltController::add_path (const std::string &path)
|
||||
{
|
||||
try {
|
||||
tl::log << tl::to_string (tr ("Scanning %1 for packages").arg (tl::to_qstring (path)));
|
||||
m_salt.add_location (path);
|
||||
|
||||
std::string tp = tl::to_string (QDir (tl::to_qstring (path)).filePath (QString::fromUtf8 ("salt")));
|
||||
|
||||
tl::log << tl::to_string (tr ("Scanning %1 for packages").arg (tl::to_qstring (tp)));
|
||||
m_salt.add_location (tp);
|
||||
|
||||
dm_sync_file_watcher ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ TechMacrosPage::commit ()
|
|||
static bool s_first_show = true;
|
||||
|
||||
TechSetupDialog::TechSetupDialog (QWidget *parent)
|
||||
: QDialog (parent), mp_current_tech (0), mp_current_editor (0), mp_current_tech_component (0)
|
||||
: QDialog (parent), mp_current_tech (0), mp_current_editor (0), mp_current_tech_component (0), m_current_tech_changed_enabled (true)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 ("tech_setup_dialog"));
|
||||
|
||||
|
|
@ -532,12 +532,60 @@ TechSetupDialog::clear_components ()
|
|||
void
|
||||
TechSetupDialog::refresh_clicked ()
|
||||
{
|
||||
m_current_tech_changed_enabled = false;
|
||||
|
||||
BEGIN_PROTECTED
|
||||
|
||||
commit_tech_component ();
|
||||
update_tech (0);
|
||||
|
||||
std::string tech_name;
|
||||
if (selected_tech ()) {
|
||||
tech_name = selected_tech ()->name ();
|
||||
}
|
||||
|
||||
// Save the expanded state of the items
|
||||
std::set<std::string> expanded_techs;
|
||||
for (int i = 0; i < tech_tree->topLevelItemCount (); ++i) {
|
||||
QTreeWidgetItem *item = tech_tree->topLevelItem (i);
|
||||
if (item && item->isExpanded ()) {
|
||||
QVariant d = item->data (0, Qt::UserRole);
|
||||
if (d != QVariant ()) {
|
||||
expanded_techs.insert (tl::to_string (d.toString ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lay::TechnologyController::instance ()->rescan (m_technologies);
|
||||
update ();
|
||||
|
||||
update_tech_tree ();
|
||||
|
||||
QTreeWidgetItem *new_item = 0;
|
||||
|
||||
for (int i = 0; i < tech_tree->topLevelItemCount () && !new_item; ++i) {
|
||||
QTreeWidgetItem *item = tech_tree->topLevelItem (i);
|
||||
QVariant d = item->data (0, Qt::UserRole);
|
||||
if (d != QVariant () && tech_name == tl::to_string (d.toString ())) {
|
||||
new_item = item;
|
||||
}
|
||||
}
|
||||
|
||||
tech_tree->setCurrentItem (new_item);
|
||||
|
||||
// restore the expanded state
|
||||
for (int i = 0; i < tech_tree->topLevelItemCount (); ++i) {
|
||||
QTreeWidgetItem *item = tech_tree->topLevelItem (i);
|
||||
QVariant d = item->data (0, Qt::UserRole);
|
||||
bool expand = (d != QVariant () && expanded_techs.find (tl::to_string (d.toString ())) != expanded_techs.end ());
|
||||
item->setExpanded (expand);
|
||||
}
|
||||
|
||||
update_tech (selected_tech ());
|
||||
update_tech_component ();
|
||||
|
||||
END_PROTECTED
|
||||
|
||||
m_current_tech_changed_enabled = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -971,6 +1019,10 @@ END_PROTECTED
|
|||
void
|
||||
TechSetupDialog::current_tech_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||
{
|
||||
if (! m_current_tech_changed_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
BEGIN_PROTECTED
|
||||
try {
|
||||
if (current) {
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ private:
|
|||
std::map <std::string, lay::TechnologyComponent *> m_technology_components;
|
||||
lay::TechnologyComponentEditor *mp_current_editor;
|
||||
lay::TechnologyComponent *mp_current_tech_component;
|
||||
bool m_current_tech_changed_enabled;
|
||||
};
|
||||
|
||||
class LAY_PUBLIC TechComponentSetupDialog
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "layTechSetupDialog.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layApplication.h"
|
||||
#include "laySaltController.h"
|
||||
#include "layConfig.h"
|
||||
#include "layQtTools.h"
|
||||
#include "laybasicConfig.h"
|
||||
|
|
@ -82,6 +83,10 @@ TechnologyController::initialized (lay::PluginRoot * /*root*/)
|
|||
{
|
||||
update_menu ();
|
||||
connect_events ();
|
||||
|
||||
if (lay::SaltController::instance ()) {
|
||||
connect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -89,6 +94,10 @@ TechnologyController::uninitialize (lay::PluginRoot * /*root*/)
|
|||
{
|
||||
m_tech_actions.clear ();
|
||||
tl::Object::detach_from_all_events ();
|
||||
|
||||
if (lay::SaltController::instance ()) {
|
||||
disconnect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -466,6 +475,12 @@ TechnologyController::load ()
|
|||
rescan (*lay::Technologies::instance ());
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::sync_with_external_sources ()
|
||||
{
|
||||
rescan (*lay::Technologies::instance ());
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::rescan (lay::Technologies &technologies)
|
||||
{
|
||||
|
|
@ -479,7 +494,17 @@ TechnologyController::rescan (lay::Technologies &technologies)
|
|||
}
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator p = m_paths.begin (); p != m_paths.end (); ++p) {
|
||||
std::vector<std::string> paths = m_paths;
|
||||
|
||||
// add the salt grains as potential sources for tech 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 ());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator p = paths.begin (); p != paths.end (); ++p) {
|
||||
|
||||
QDir dir (tl::to_qstring (*p));
|
||||
if (! dir.exists ()) {
|
||||
|
|
@ -540,7 +565,8 @@ TechnologyController::add_temp_tech (const lay::Technology &t)
|
|||
void
|
||||
TechnologyController::add_path (const std::string &p)
|
||||
{
|
||||
m_paths.push_back (p);
|
||||
std::string tp = tl::to_string (QDir (tl::to_qstring (p)).filePath (QString::fromUtf8 ("tech")));
|
||||
m_paths.push_back (tp);
|
||||
}
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new TechnologyController (), 110, "TechnologyController");
|
||||
|
|
|
|||
|
|
@ -119,6 +119,12 @@ signals:
|
|||
*/
|
||||
void technologies_edited ();
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Called when the salt got changed
|
||||
*/
|
||||
void sync_with_external_sources ();
|
||||
|
||||
private:
|
||||
tl::stable_vector <lay::Action> m_tech_actions;
|
||||
std::string m_current_technology;
|
||||
|
|
|
|||
|
|
@ -140,6 +140,40 @@ private:
|
|||
void do_execute ();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A protected region that ensures that deferred methods are not executed
|
||||
*
|
||||
* This class employs the RAII pattern to block a region of code for execution of
|
||||
* deferred methods. This is useful to protect message boxes against having a side
|
||||
* effects of issuing deferred method calls:
|
||||
*
|
||||
* @code
|
||||
* {
|
||||
* tl::NoDeferredMethods block;
|
||||
* QMessageBox::warning (...);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class TL_PUBLIC NoDeferredMethods
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
NoDeferredMethods ()
|
||||
{
|
||||
DeferredMethodScheduler::enable (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~NoDeferredMethods ()
|
||||
{
|
||||
DeferredMethodScheduler::enable (true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deferred execution of a const method
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue