WIP: bugfixed tech controller, more refactoring

Resolved the dependencies between MainWindow, TechController
and MacroController somewhat more.

* The macro controller now listens to the tech controller
  for the active technology
* The tech controller has more responsibility now
* Some functionality has been taken out of the MainWindow
  and put into the controller's implementation
This commit is contained in:
Matthias Koefferlein 2017-04-15 17:51:04 +02:00
parent 5b422440a1
commit e6f696b8dc
14 changed files with 335 additions and 244 deletions

View File

@ -239,7 +239,7 @@ public:
menu_entries.push_back (lay::MenuEntry ("edt::sel_convert_to_pcell", "convert_to_pcell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Convert To PCell"))));
menu_entries.push_back (lay::MenuEntry ("edt::sel_convert_to_cell", "convert_to_cell:edit_mode", "edit_menu.selection_menu.end", tl::to_string (QObject::tr ("Convert To Static Cell"))));
menu_entries.push_back (lay::MenuEntry ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end", tl::to_string (QObject::tr ("Combine{Select background combination mode}"))));
menu_entries.push_back (lay::MenuEntry ("edt::combine_mode", "combine_mode:edit_mode", "@toolbar.end_modes", tl::to_string (QObject::tr ("Combine{Select background combination mode}"))));
}
bool configure (const std::string &name, const std::string &value)

View File

@ -888,37 +888,6 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
mp_ruby_interpreter = new rba::RubyInterpreter ();
mp_python_interpreter = new pya::PythonInterpreter ();
if (! m_no_gui) {
// Install the signal handlers after the interpreters, so we can be sure we
// installed our handler.
install_signal_handlers ();
}
if (! m_no_macros) {
// Add the global ruby modules as the first ones.
m_load_macros.insert (m_load_macros.begin (), global_modules.begin (), global_modules.end ());
lay::MacroController *mc = lay::MacroController::instance ();
if (mc) {
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
if (p == m_klayout_path.begin ()) {
mc->add_path (*p, tl::to_string (QObject::tr ("Local")), std::string (), false);
} else if (m_klayout_path.size () == 2) {
mc->add_path (*p, tl::to_string (QObject::tr ("Global")), std::string (), true);
} else {
mc->add_path (*p, tl::to_string (QObject::tr ("Global")) + " - " + *p, std::string (), true);
}
}
}
// Install the custom folders
for (std::vector <std::pair<std::string, std::string> >::const_iterator p = custom_macro_paths.begin (); p != custom_macro_paths.end (); ++p) {
mc->add_path (p->first, tl::to_string (QObject::tr ("Project")) + " - " + p->first, p->second, false);
}
}
// Read some configuration values that we need early
bool editable_from_config = false;
@ -950,18 +919,39 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
}
} catch (...) { }
try {
std::string s;
cfg.config_get (cfg_technologies, s);
lay::Technologies tt;
if (! s.empty ()) {
tt.load_from_xml (s);
}
if (! m_no_gui) {
// Install the signal handlers after the interpreters, so we can be sure we
// installed our handler.
install_signal_handlers ();
}
lay::MacroController *mc = lay::MacroController::instance ();
if (mc && ! m_no_macros) {
// Add the global ruby modules as the first ones.
m_load_macros.insert (m_load_macros.begin (), global_modules.begin (), global_modules.end ());
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
if (p == m_klayout_path.begin ()) {
mc->add_path (*p, tl::to_string (QObject::tr ("Local")), std::string (), false);
} else if (m_klayout_path.size () == 2) {
mc->add_path (*p, tl::to_string (QObject::tr ("Global")), std::string (), true);
} else {
mc->add_path (*p, tl::to_string (QObject::tr ("Global")) + " - " + *p, std::string (), true);
}
*lay::Technologies::instance () = tt;
} catch (tl::Exception &ex) {
tl::warn << tl::to_string (QObject::tr ("Unable to restore technologies: ")) << ex.msg ();
}
// Install the custom folders
for (std::vector <std::pair<std::string, std::string> >::const_iterator p = custom_macro_paths.begin (); p != custom_macro_paths.end (); ++p) {
mc->add_path (p->first, tl::to_string (QObject::tr ("Project")) + " - " + p->first, p->second, false);
}
// Actually load the macros
mc->load ();
}
lay::TechnologyController *tc = lay::TechnologyController::instance ();
@ -1050,8 +1040,14 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
}
// initialize the plugins for the first time
if (tl::verbosity () >= 20) {
tl::info << "Initializing plugins:";
}
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
if (tl::verbosity () >= 20) {
tl::info << " " << cls.current_name () << " [" << cls.current_position () << "]";
}
pd->initialize (mp_plugin_root);
}
@ -1126,9 +1122,6 @@ Application::finish ()
if (mp_plugin_root && m_write_config_file) {
// save the technology setup in the configuration
mp_plugin_root->config_set (cfg_technologies, lay::Technologies::instance ()->to_xml ());
if (! m_config_file_to_write.empty ()) {
if (tl::verbosity () >= 20) {
tl::info << tl::to_string (QObject::tr ("Updating configuration file ")) << m_config_file_to_write;
@ -1605,22 +1598,7 @@ void
Application::set_config (const std::string &name, const std::string &value)
{
if (mp_plugin_root) {
if (name == cfg_technologies) {
// HACK: cfg_technologies is not a real configuration parameter currently. Hence we emulate that
// behavior. But currently this is the only way to access technology data indirectly from a script.
// Note that this method will set only the technologies accessible through the configuration parameter.
// I.e. the ones not auto-imported.
// TODO: rework this one. This is only half-hearted.
if (! value.empty ()) {
lay::Technologies::instance ()->load_from_xml (value);
}
} else {
mp_plugin_root->config_set (name, value);
}
mp_plugin_root->config_set (name, value);
}
}
@ -1636,16 +1614,7 @@ std::string
Application::get_config (const std::string &name) const
{
if (mp_plugin_root) {
if (name == cfg_technologies) {
// HACK: cfg_technologies is not a real configuration parameter currently. Hence we emulate that
// behavior. But currently this is the only way to access technology data indirectly from a script.
// Note that this method will return only the technologies accessible through the configuration parameter.
// I.e. the ones not auto-imported.
// TODO: rework this one.
return lay::Technologies::instance ()->to_xml ();
} else {
return mp_plugin_root->config_get (name);
}
return mp_plugin_root->config_get (name);
} else {
return std::string ();
}

View File

@ -45,7 +45,7 @@ MacroController::MacroController ()
}
void
MacroController::initialize (lay::PluginRoot * /*root*/)
MacroController::load ()
{
// Scan built-in macros
// These macros are always taken, even if there are no macros requested (they are required to
@ -87,8 +87,10 @@ MacroController::initialized (lay::PluginRoot *root)
connect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
connect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
connect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
connect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (update_menu_with_macros ()));
if (lay::TechnologyController::instance ()) {
connect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
connect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (update_menu_with_macros ()));
}
// update the menus with the macro menu bindings as late as possible (now we
// can be sure that the menus are created propertly)
@ -100,8 +102,10 @@ MacroController::uninitialize (lay::PluginRoot * /*root*/)
{
disconnect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
disconnect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
disconnect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
disconnect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (update_menu_with_macros ()));
if (lay::TechnologyController::instance ()) {
disconnect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
disconnect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (update_menu_with_macros ()));
}
delete mp_macro_editor;
mp_macro_editor = 0;
@ -380,11 +384,9 @@ MacroController::do_update_menu_with_macros ()
return;
}
// TODO: implement this by asking the technology manager for the active technology
const lay::Technology *tech = 0;
if (mp_mw->current_view () && mp_mw->current_view ()->active_cellview_index () >= 0 && mp_mw->current_view ()->active_cellview_index () <= int (mp_mw->current_view ()->cellviews ())) {
std::string active_tech = mp_mw->current_view ()->active_cellview ()->tech_name ();
tech = lay::Technologies::instance ()->technology_by_name (active_tech);
if (lay::TechnologyController::instance ()) {
tech = lay::TechnologyController::instance ()->active_technology ();
}
std::vector<std::pair<std::string, std::string> > key_bindings = unpack_key_binding (mp_mw->config_get (cfg_key_bindings));

View File

@ -68,11 +68,6 @@ public:
*/
MacroController ();
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
virtual void initialize (lay::PluginRoot *root);
/**
* @brief Reimplementation of the PluginDeclaration interface
*/
@ -124,9 +119,16 @@ public:
/**
* @brief Adds a search path to the macros
* After adding the paths, "load" needs to be called to actually load the macros.
*/
void add_path (const std::string &path, const std::string &description, const std::string &category, bool readonly);
/**
* @brief Loads the macros from the predefined paths
* This method will also establish the macro categories.
*/
void load ();
/**
* @brief Adds a temporary macro
*

View File

@ -997,6 +997,11 @@ MainWindow::init_menu ()
}
// Add a hook for inserting new items after the modes
Action end_modes;
end_modes.set_separator (true);
mp_menu->insert_item ("@toolbar.end", "end_modes", end_modes);
// make the plugins create their menu items
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
// TODO: get rid of the const_cast hack

View File

@ -542,8 +542,7 @@ TechSetupDialog::refresh_clicked ()
{
BEGIN_PROTECTED
commit ();
lay::TechnologyController::instance ()->refresh ();
lay::TechnologyController::instance ()->refresh (m_technologies);
update ();
END_PROTECTED
@ -552,68 +551,22 @@ END_PROTECTED
void
TechSetupDialog::update ()
{
m_technologies = *lay::Technologies ().instance ();
update_tech_tree ();
tech_tree->setCurrentItem (tech_tree->topLevelItem (0));
update_tech (selected_tech ());
}
bool
TechSetupDialog::commit ()
{
std::string err_msg;
// determine the technology files that need to be deleted and delete them
std::set<std::string> files_before;
for (lay::Technologies::const_iterator t = m_technologies.begin (); t != m_technologies.end (); ++t) {
if (! ! t->tech_file_path ().empty () && ! t->is_persisted ()) {
files_before.insert (t->tech_file_path ());
}
}
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
if (! t->tech_file_path ().empty () && ! t->is_persisted () && files_before.find (t->tech_file_path ()) == files_before.end ()) {
// TODO: issue an error if files could not be removed
QFile (tl::to_qstring (t->tech_file_path ())).remove ();
}
}
*lay::Technologies ().instance () = m_technologies;
// save the technologies that need to be saved
// TODO: save only the ones that really need saving
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
if (! t->tech_file_path ().empty () && ! t->is_persisted ()) {
try {
t->save (t->tech_file_path ());
} catch (...) {
if (! err_msg.empty ()) {
err_msg += "\n";
}
err_msg += t->tech_file_path ();
}
}
}
if (! err_msg.empty ()) {
QMessageBox::critical (this, QObject::tr ("Error Saving Technology Files"),
QObject::tr ("The following files could not be saved:\n\n") + tl::to_qstring (err_msg),
QMessageBox::Ok);
return false;
} else {
return true;
}
}
int
TechSetupDialog::exec ()
TechSetupDialog::exec (lay::Technologies &technologies)
{
m_technologies = technologies;
update ();
tc_stack->setMinimumSize (tc_stack->sizeHint ());
int ret = QDialog::exec ();
if (ret) {
commit ();
technologies = m_technologies;
}
// clean up
@ -662,9 +615,6 @@ BEGIN_PROTECTED
if (tech_dir.exists ()) {
throw tl::Exception (tl::to_string (QObject::tr ("A target folder with path '%1' already exists").arg (tech_dir.path ())));
}
if (! root.mkdir (tn)) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to create target folder '%1'").arg (tech_dir.path ())));
}
lay::Technology *nt = new lay::Technology (*t);

View File

@ -128,7 +128,7 @@ public:
TechSetupDialog (QWidget *parent);
~TechSetupDialog ();
int exec ();
int exec (lay::Technologies &technologies);
protected slots:
void current_tech_changed (QTreeWidgetItem *current, QTreeWidgetItem *previous);
@ -149,7 +149,6 @@ private:
std::string selected_tech_component_name ();
void commit_tech_component ();
void clear_components ();
bool commit ();
void update ();
lay::Technologies m_technologies;

View File

@ -26,6 +26,7 @@
#include "layMainWindow.h"
#include "layMacroController.h"
#include "layApplication.h"
#include "layConfig.h"
#include "laybasicConfig.h"
#include <QMessageBox>
@ -46,9 +47,10 @@ std::string tech_string_from_name (const std::string &tn)
}
TechnologyController::TechnologyController ()
: PluginDeclaration (), mp_editor (0), mp_mw (0), m_no_macros (false)
: PluginDeclaration (), mp_editor (0), mp_mw (0), m_no_macros (false), mp_active_technology (0)
{
m_current_technology_updated = false;
m_technologies_configured = false;
}
void
@ -87,7 +89,7 @@ TechnologyController::initialized (lay::PluginRoot *root)
}
update_menu ();
update_after_change ();
connect_events ();
}
void
@ -111,54 +113,80 @@ TechnologyController::get_menu_entries (std::vector<lay::MenuEntry> &menu_entrie
}
void
TechnologyController::update_after_change ()
TechnologyController::connect_events ()
{
// re-attach all events
// NOTE: the whole concept is a but strange here: the goal is to
// connect to the current view's active_cellview_changed event and
// the active cellview's technology_changed event. We could register
// events tracking the current view and active cellview which detach
// and attach event handlers. This is more tedious than doing this:
// we detach and re-attach the events whenever something changes.
// The event system supports this case, hence we do so.
tl::Object::detach_from_all_events ();
lay::MainWindow *mw = lay::MainWindow::instance ();
lay::MacroController *mc = lay::MacroController::instance ();
if (mw) {
mw->current_view_changed_event.add (this, &TechnologyController::update_after_change);
}
lay::Technologies::instance ()->technology_changed_event.add (this, &TechnologyController::technology_changed);
lay::Technologies::instance ()->technologies_changed_event.add (this, &TechnologyController::technologies_changed);
if (lay::LayoutView::current ()) {
lay::LayoutView::current ()->active_cellview_changed_event.add (this, &TechnologyController::update_after_change);
}
if (mp_mw) {
std::string active_tech;
if (lay::LayoutView::current () && lay::LayoutView::current ()->active_cellview_index () >= 0 && lay::LayoutView::current ()->active_cellview_index () <= int (lay::LayoutView::current ()->cellviews ())) {
lay::LayoutView::current ()->active_cellview ()->technology_changed_event.add (this, &TechnologyController::update_after_change);
active_tech = lay::LayoutView::current ()->active_cellview ()->tech_name ();
}
// NOTE: the "real" call needs to come before the re-connect handler because
// the latter will remove the update call
mp_mw->current_view_changed_event.add (this, &TechnologyController::update_active_technology);
mp_mw->current_view_changed_event.add (this, &TechnologyController::connect_events);
if (m_active_technology != active_tech) {
if (mp_mw->current_view ()) {
m_active_technology = active_tech;
// NOTE: the "real" call needs to come before the re-connect handler because
// the latter will remove the update call
mp_mw->current_view ()->active_cellview_changed_event.add (this, &TechnologyController::update_active_technology);
mp_mw->current_view ()->active_cellview_changed_event.add (this, &TechnologyController::connect_events);
if (mp_mw->current_view ()->active_cellview_index () >= 0 && mp_mw->current_view ()->active_cellview_index () <= int (mp_mw->current_view ()->cellviews ())) {
mp_mw->current_view ()->active_cellview ()->technology_changed_event.add (this, &TechnologyController::update_active_technology);
}
if (mw) {
mw->tech_message (tech_string_from_name (active_tech));
}
if (mc) {
// TODO: let the macro controller monitor the active technology
// need to do this since macros may be bound to the new technology
mc->update_menu_with_macros ();
}
}
lay::Technology *
TechnologyController::active_technology () const
{
return mp_active_technology;
}
void
TechnologyController::update_active_technology ()
{
lay::Technology *active_tech = 0;
if (mp_mw && mp_mw->current_view () && mp_mw->current_view ()->active_cellview_index () >= 0 && mp_mw->current_view ()->active_cellview_index () <= int (mp_mw->current_view ()->cellviews ())) {
active_tech = lay::Technologies::instance ()->technology_by_name (mp_mw->current_view ()->active_cellview ()->tech_name ());
}
if (mp_active_technology != active_tech) {
mp_active_technology = active_tech;
if (mp_mw) {
if (active_tech) {
mp_mw->tech_message (tech_string_from_name (active_tech->name ()));
} else {
mp_mw->tech_message (std::string ());
}
}
emit active_technology_changed ();
}
#if 0
// Hint with this implementation, the current technology follows the current layout.
// Although that's a nice way to display the current technology, it's pretty confusing
lay::PluginRoot *pr = lay::PluginRoot::instance ();
lay::PluginRoot *pr = mp_mw;
if (pr) {
pr->config_set (cfg_initial_technology, active_tech);
pr->config_finalize ();
}
#endif
}
@ -166,14 +194,18 @@ TechnologyController::update_after_change ()
void
TechnologyController::technologies_changed ()
{
// delay actual update of menu so we can compress multiple events
// update the configuration to reflect the persisted technologies
lay::PluginRoot *pr = mp_mw;
if (pr) {
pr->config_set (cfg_technologies, lay::Technologies::instance ()->to_xml ());
}
update_menu ();
}
void
TechnologyController::technology_changed (lay::Technology *)
{
// delay actual update of menu so we can compress multiple events
update_menu ();
}
@ -187,6 +219,23 @@ TechnologyController::configure (const std::string &name, const std::string &val
m_current_technology_updated = true;
}
} else if (name == cfg_technologies) {
if (! value.empty ()) {
// sync the non-persisted technologies with the configuration
lay::Technologies::instance ()->begin_updates ();
try {
lay::Technologies::instance ()->load_from_xml (value);
} catch (...) {
}
lay::Technologies::instance ()->end_updates_no_event ();
// explicitly handle changes -> no recursion
m_technologies_configured = true;
}
}
return false;
}
@ -198,6 +247,12 @@ TechnologyController::config_finalize ()
update_current_technology ();
m_current_technology_updated = false;
}
if (m_technologies_configured) {
update_menu ();
emit technologies_edited ();
m_technologies_configured = false;
}
}
bool
@ -282,12 +337,82 @@ TechnologyController::update_menu ()
}
}
update_active_technology ();
}
void
TechnologyController::show_editor ()
{
if (mp_editor && mp_editor->exec ()) {
lay::Technologies new_tech = *lay::Technologies ().instance ();
if (mp_editor && mp_editor->exec (new_tech)) {
std::string err_msg;
// determine the technology files that need to be deleted and delete them
std::set<std::string> files_before;
for (lay::Technologies::const_iterator t = new_tech.begin (); t != new_tech.end (); ++t) {
if (! ! t->tech_file_path ().empty () && ! t->is_persisted ()) {
files_before.insert (t->tech_file_path ());
}
}
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
if (! t->tech_file_path ().empty () && ! t->is_persisted () && files_before.find (t->tech_file_path ()) == files_before.end ()) {
// TODO: issue an error if files could not be removed
QFile (tl::to_qstring (t->tech_file_path ())).remove ();
}
}
lay::Technologies ().instance ()->begin_updates ();
*lay::Technologies ().instance () = new_tech;
lay::Technologies ().instance ()->end_updates_no_event ();
// save the technologies that need to be saved
// TODO: save only the ones that really need saving
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
if (! t->tech_file_path ().empty () && ! t->is_persisted ()) {
// create the tech folder if required
try {
QDir dir = QFileInfo (tl::to_qstring (t->tech_file_path ())).absoluteDir ();
QStringList to_create;
while (! dir.isRoot() && ! dir.exists ()) {
to_create << dir.dirName ();
dir = QFileInfo (dir.path ()).absoluteDir ();
}
while (! to_create.empty ()) {
if (! dir.mkdir (to_create.back ())) {
throw tl::CancelException ();
}
if (! dir.cd (to_create.back ())) {
throw tl::CancelException ();
}
to_create.pop_back ();
}
t->save (t->tech_file_path ());
} catch (...) {
if (! err_msg.empty ()) {
err_msg += "\n";
}
err_msg += t->tech_file_path ();
}
}
}
if (! err_msg.empty ()) {
QMessageBox::critical (mp_mw, QObject::tr ("Error Saving Technology Files"),
QObject::tr ("The following files could not be saved:\n\n") + tl::to_qstring (err_msg),
QMessageBox::Ok);
}
std::vector<lay::MacroCollection *> nm = sync_tech_macro_locations ();
@ -302,12 +427,8 @@ TechnologyController::show_editor ()
}
}
// because the macro-tech association might have changed, do this:
// TODO: let the macro controller monitor the technologies.
lay::MacroController *mc = lay::MacroController::instance ();
if (mc) {
mc->update_menu_with_macros ();
}
update_menu ();
emit technologies_edited ();
}
}
@ -325,66 +446,83 @@ TechnologyController::refresh ()
try {
lay::Technologies::instance ()->begin_updates ();
lay::Technologies::instance ()->clear ();
refresh (*lay::Technologies::instance ());
lay::Technologies::instance ()->end_updates_no_event ();
for (std::vector<std::string>::const_iterator p = m_paths.begin (); p != m_paths.end (); ++p) {
QDir dir (tl::to_qstring (*p));
if (! dir.exists ()) {
continue;
}
QStringList name_filters;
name_filters << QString::fromUtf8 ("*.lyt");
QStringList lyt_files;
QDirIterator di (dir.path (), name_filters, QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
while (di.hasNext ()) {
lyt_files << di.next ();
}
lyt_files.sort ();
for (QStringList::const_iterator lf = lyt_files.begin (); lf != lyt_files.end (); ++lf) {
try {
if (tl::verbosity () >= 20) {
tl::info << "Auto-importing technology from " << tl::to_string (*lf);
}
lay::Technology t;
t.load (tl::to_string (*lf));
t.set_persisted (false); // don't save that one in the configuration
t.set_readonly (! QFileInfo (dir.filePath (*lf)).isWritable ());
lay::Technologies::instance ()->add (new lay::Technology (t));
} catch (tl::Exception &ex) {
tl::warn << tl::to_string (QObject::tr ("Unable to auto-import technology file ")) << tl::to_string (*lf) << ": " << ex.msg ();
}
}
}
for (std::vector<lay::Technology>::const_iterator t = m_temp_tech.begin (); t != m_temp_tech.end (); ++t) {
lay::Technology *tech = new lay::Technology (*t);
tech->set_persisted (false); // don't save that one in the configuration
tech->set_readonly (true);
lay::Technologies::instance ()->add (tech);
}
lay::Technologies::instance ()->end_updates ();
update_menu ();
emit technologies_edited ();
} catch (...) {
lay::Technologies::instance ()->end_updates ();
lay::Technologies::instance ()->end_updates_no_event ();
throw;
}
}
void
TechnologyController::refresh (lay::Technologies &technologies)
{
lay::Technologies current = technologies;
// start with all persisted technologies (at least "default")
technologies.clear ();
for (lay::Technologies::const_iterator t = current.begin (); t != current.end (); ++t) {
if (t->is_persisted ()) {
technologies.add (new lay::Technology (*t));
}
}
for (std::vector<std::string>::const_iterator p = m_paths.begin (); p != m_paths.end (); ++p) {
QDir dir (tl::to_qstring (*p));
if (! dir.exists ()) {
continue;
}
QStringList name_filters;
name_filters << QString::fromUtf8 ("*.lyt");
QStringList lyt_files;
QDirIterator di (dir.path (), name_filters, QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
while (di.hasNext ()) {
lyt_files << di.next ();
}
lyt_files.sort ();
for (QStringList::const_iterator lf = lyt_files.begin (); lf != lyt_files.end (); ++lf) {
try {
if (tl::verbosity () >= 20) {
tl::info << "Auto-importing technology from " << tl::to_string (*lf);
}
lay::Technology t;
t.load (tl::to_string (*lf));
t.set_persisted (false); // don't save that one in the configuration
t.set_readonly (! QFileInfo (dir.filePath (*lf)).isWritable ());
technologies.add (new lay::Technology (t));
} catch (tl::Exception &ex) {
tl::warn << tl::to_string (QObject::tr ("Unable to auto-import technology file ")) << tl::to_string (*lf) << ": " << ex.msg ();
}
}
}
for (std::vector<lay::Technology>::const_iterator t = m_temp_tech.begin (); t != m_temp_tech.end (); ++t) {
lay::Technology *tech = new lay::Technology (*t);
tech->set_persisted (false); // don't save that one in the configuration
tech->set_tech_file_path (std::string ()); // don't save to a file either
tech->set_readonly (true); // don't edit
technologies.add (tech);
}
}
void
TechnologyController::add_temp_tech (const lay::Technology &t)
{

View File

@ -65,13 +65,10 @@ public:
void show_editor ();
/**
* @brief Gets the name of the active technology
* @brief Gets the active technology object or 0 if none is active
* The active technology is the one the current cellview uses
*/
const std::string &active_technology () const
{
return m_active_technology;
}
lay::Technology *active_technology () const;
/**
* @brief Enables or disables macros
@ -95,7 +92,12 @@ public:
void add_temp_tech (const lay::Technology &t);
/**
* @brief Updates the technology collection with the technologies from the search path and teh temp technologies
* @brief Updates the given technology collection with the technologies from the search path and teh temp technologies
*/
void refresh (lay::Technologies &technologies);
/**
* @brief Refreshes the global list of technologies
*/
void refresh ();
@ -127,16 +129,18 @@ signals:
private:
tl::stable_vector <lay::Action> m_tech_actions;
std::string m_current_technology;
std::string m_active_technology;
bool m_current_technology_updated;
bool m_technologies_configured;
lay::TechSetupDialog *mp_editor;
lay::MainWindow *mp_mw;
bool m_no_macros;
std::vector<std::string> m_paths;
std::vector<lay::Technology> m_temp_tech;
std::set<std::pair<std::string, std::string> > m_tech_macro_paths;
lay::Technology *mp_active_technology;
void update_after_change ();
void update_active_technology ();
void connect_events ();
void technologies_changed ();
void technology_changed (lay::Technology *);
bool configure (const std::string &name, const std::string &value);

View File

@ -1123,14 +1123,17 @@ AbstractMenu::find_item (const std::string &path)
return std::make_pair ((AbstractMenuItem *) 0, m_root.children.end ());
}
} else if (extr.test ("begin")) {
return std::make_pair (parent, parent->children.begin ());
} else if (extr.test ("end")) {
return std::make_pair (parent, parent->children.end ());
} else {
std::string n;
extr.read (n, ".+");
if (n == "begin") {
return std::make_pair (parent, parent->children.begin ());
} else if (n == "end") {
return std::make_pair (parent, parent->children.end ());
}
std::string name (parent->name ());
if (! name.empty ()) {
name += ".";

View File

@ -197,7 +197,7 @@ PluginDeclaration::init_menu ()
m_mouse_mode_action.qaction ()->setData (QVariant (id ()));
menu.insert_item ("edit_menu.mode_menu.end", name, m_mouse_mode_action);
menu.insert_item ("@toolbar.end", name, m_mouse_mode_action);
menu.insert_item ("@toolbar.end_modes", name, m_mouse_mode_action);
gtf::action_connect (m_mouse_mode_action.qaction (), SIGNAL (triggered ()), this, SLOT (mode_triggered ()));

View File

@ -184,6 +184,12 @@ Technologies::end_updates ()
}
}
void
Technologies::end_updates_no_event ()
{
m_in_update = false;
m_changed = false;
}
bool
Technologies::has_technology (const std::string &name) const

View File

@ -149,6 +149,14 @@ public:
*/
void end_updates ();
/**
* @brief Ends a bulk operation
* This version does not send an technologies_changed event but just cancels the bulk
* operation. begin_updates/end_updates_no_event is essentially equivalent to blocking
* signals.
*/
void end_updates_no_event ();
/**
* @brief Checks, if a technology with the given name exists
*/

View File

@ -163,6 +163,11 @@ public:
return mp_pos->m_name;
}
int current_position () const
{
return mp_pos->m_position;
}
X &operator* () const
{
return *(mp_pos->mp_object);