diff --git a/src/edt/edtPlugin.cc b/src/edt/edtPlugin.cc index 1021c61c5..8e56b8e94 100644 --- a/src/edt/edtPlugin.cc +++ b/src/edt/edtPlugin.cc @@ -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) diff --git a/src/lay/layApplication.cc b/src/lay/layApplication.cc index 058d52615..bf4b65abf 100644 --- a/src/lay/layApplication.cc +++ b/src/lay/layApplication.cc @@ -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 ::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 >::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 ::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 >::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::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { lay::PluginDeclaration *pd = const_cast (&*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 (); } diff --git a/src/lay/layMacroController.cc b/src/lay/layMacroController.cc index 4f433910e..fe220ca71 100644 --- a/src/lay/layMacroController.cc +++ b/src/lay/layMacroController.cc @@ -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 > key_bindings = unpack_key_binding (mp_mw->config_get (cfg_key_bindings)); diff --git a/src/lay/layMacroController.h b/src/lay/layMacroController.h index c148c6265..90b683358 100644 --- a/src/lay/layMacroController.h +++ b/src/lay/layMacroController.h @@ -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 * diff --git a/src/lay/layMainWindow.cc b/src/lay/layMainWindow.cc index 7f95968f9..d0c98f402 100644 --- a/src/lay/layMainWindow.cc +++ b/src/lay/layMainWindow.cc @@ -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::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { // TODO: get rid of the const_cast hack diff --git a/src/lay/layTechSetupDialog.cc b/src/lay/layTechSetupDialog.cc index c563f1906..3f94132bf 100644 --- a/src/lay/layTechSetupDialog.cc +++ b/src/lay/layTechSetupDialog.cc @@ -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 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); diff --git a/src/lay/layTechSetupDialog.h b/src/lay/layTechSetupDialog.h index ada25e6a2..0c65840ae 100644 --- a/src/lay/layTechSetupDialog.h +++ b/src/lay/layTechSetupDialog.h @@ -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; diff --git a/src/lay/layTechnologyController.cc b/src/lay/layTechnologyController.cc index b3d22d2cc..f4b753c9d 100644 --- a/src/lay/layTechnologyController.cc +++ b/src/lay/layTechnologyController.cc @@ -26,6 +26,7 @@ #include "layMainWindow.h" #include "layMacroController.h" #include "layApplication.h" +#include "layConfig.h" #include "laybasicConfig.h" #include @@ -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 &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 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 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::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::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::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::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) { diff --git a/src/lay/layTechnologyController.h b/src/lay/layTechnologyController.h index c6bf7ab57..ea5d7f00f 100644 --- a/src/lay/layTechnologyController.h +++ b/src/lay/layTechnologyController.h @@ -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 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 m_paths; std::vector m_temp_tech; std::set > 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); diff --git a/src/laybasic/layAbstractMenu.cc b/src/laybasic/layAbstractMenu.cc index fac446f05..c0516fa87 100644 --- a/src/laybasic/layAbstractMenu.cc +++ b/src/laybasic/layAbstractMenu.cc @@ -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 += "."; diff --git a/src/laybasic/layPlugin.cc b/src/laybasic/layPlugin.cc index ea2858034..9596d5873 100644 --- a/src/laybasic/layPlugin.cc +++ b/src/laybasic/layPlugin.cc @@ -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 ())); diff --git a/src/laybasic/layTechnology.cc b/src/laybasic/layTechnology.cc index e3a10a54d..5cc9434e7 100644 --- a/src/laybasic/layTechnology.cc +++ b/src/laybasic/layTechnology.cc @@ -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 diff --git a/src/laybasic/layTechnology.h b/src/laybasic/layTechnology.h index ac78b593d..50fc61c1e 100644 --- a/src/laybasic/layTechnology.h +++ b/src/laybasic/layTechnology.h @@ -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 */ diff --git a/src/tl/tlClassRegistry.h b/src/tl/tlClassRegistry.h index b03eebfe0..059d76200 100644 --- a/src/tl/tlClassRegistry.h +++ b/src/tl/tlClassRegistry.h @@ -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);