mirror of https://github.com/KLayout/klayout.git
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:
parent
5b422440a1
commit
e6f696b8dc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 += ".";
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue