mirror of https://github.com/KLayout/klayout.git
WIP: technologies are file based by default now
* Introduced "refresh" method of tech setup dialog * Some refactoring -> tech management is part of tech controller * Macro category management moved to macro controller
This commit is contained in:
parent
83b2c150d9
commit
5b422440a1
|
|
@ -34,6 +34,7 @@
|
|||
#include "layTextProgress.h"
|
||||
#include "layBackgroundAwareTreeStyle.h"
|
||||
#include "layMacroController.h"
|
||||
#include "layTechnologyController.h"
|
||||
#include "gtf.h"
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiInterpreter.h"
|
||||
|
|
@ -55,7 +56,6 @@
|
|||
|
||||
#include <QIcon>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
#include <QAction>
|
||||
|
|
@ -895,41 +895,26 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
}
|
||||
|
||||
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 ());
|
||||
}
|
||||
|
||||
// Scan built-in macros
|
||||
// These macros are always taken, even if there are no macros requested (they are required to
|
||||
// fully form the API).
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true);
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true);
|
||||
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("macros", tl::to_string (QObject::tr ("Ruby"))));
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("pymacros", tl::to_string (QObject::tr ("Python"))));
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("drc", tl::to_string (QObject::tr ("DRC"))));
|
||||
|
||||
// Scan for macros and set interpreter path
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
|
||||
for (size_t c = 0; c < m_macro_categories.size (); ++c) {
|
||||
|
||||
std::string mp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (tl::to_qstring (m_macro_categories [c].first)));
|
||||
|
||||
// don't scan if macros are disabled
|
||||
if (! m_no_macros) {
|
||||
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 ()) {
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Local")), mp, m_macro_categories [c].first, false);
|
||||
mc->add_path (*p, tl::to_string (QObject::tr ("Local")), std::string (), false);
|
||||
} else if (m_klayout_path.size () == 2) {
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Global")), mp, m_macro_categories [c].first, true);
|
||||
mc->add_path (*p, tl::to_string (QObject::tr ("Global")), std::string (), true);
|
||||
} else {
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Global")) + " - " + *p, mp, m_macro_categories [c].first, true);
|
||||
mc->add_path (*p, tl::to_string (QObject::tr ("Global")) + " - " + *p, std::string (), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ruby_interpreter ().add_path (mp);
|
||||
python_interpreter ().add_path (mp);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -979,81 +964,43 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
|
||||
}
|
||||
|
||||
// auto-import technologies
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
lay::TechnologyController *tc = lay::TechnologyController::instance ();
|
||||
|
||||
QDir inst_path_dir (tl::to_qstring (*p));
|
||||
if (! inst_path_dir.cd (QString::fromUtf8 ("tech"))) {
|
||||
continue;
|
||||
if (tc) {
|
||||
|
||||
tc->enable_macros (! m_no_macros);
|
||||
|
||||
// auto-import technologies
|
||||
for (std::vector <std::string>::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
|
||||
std::string tp = tl::to_string (QDir (tl::to_qstring (*p)).filePath (QString::fromUtf8 ("tech")));
|
||||
tc->add_path (tp);
|
||||
}
|
||||
|
||||
QStringList name_filters;
|
||||
name_filters << QString::fromUtf8 ("*.lyt");
|
||||
// import technologies from the command line
|
||||
for (std::vector <std::pair<file_type, std::pair<std::string, std::string> > >::iterator f = m_files.begin (); f != m_files.end (); ++f) {
|
||||
|
||||
QStringList lyt_files;
|
||||
|
||||
QDirIterator di (inst_path_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 (f->first == layout_file_with_tech_file) {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Auto-importing technology from " << tl::to_string (*lf);
|
||||
tl::info << "Importing technology from " << f->second.second;
|
||||
}
|
||||
|
||||
lay::Technology t;
|
||||
t.load (tl::to_string (*lf));
|
||||
t.set_persisted (false); // don't save that one in the configuration
|
||||
lay::Technologies::instance ()->add (new lay::Technology (t));
|
||||
t.load (f->second.second);
|
||||
|
||||
tc->add_temp_tech (t);
|
||||
|
||||
f->first = layout_file_with_tech;
|
||||
f->second.second = t.name ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::warn << tl::to_string (QObject::tr ("Unable to auto-import technology file ")) << tl::to_string (*lf) << ": " << ex.msg ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// import technologies from the command line
|
||||
for (std::vector <std::pair<file_type, std::pair<std::string, std::string> > >::iterator f = m_files.begin (); f != m_files.end (); ++f) {
|
||||
|
||||
if (f->first == layout_file_with_tech_file) {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Importing technology from " << f->second.second;
|
||||
}
|
||||
|
||||
lay::Technology t;
|
||||
t.load (f->second.second);
|
||||
t.set_persisted (false); // don't save that one in the configuration
|
||||
lay::Technologies::instance ()->add (new lay::Technology (t));
|
||||
|
||||
f->first = layout_file_with_tech;
|
||||
f->second.second = t.name ();
|
||||
|
||||
}
|
||||
tc->refresh ();
|
||||
|
||||
}
|
||||
|
||||
// Install the custom folders
|
||||
if (! m_no_macros) {
|
||||
for (std::vector <std::pair<std::string, std::string> >::const_iterator p = custom_macro_paths.begin (); p != custom_macro_paths.end (); ++p) {
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Project")) + " - " + p->first, p->first, p->second, false);
|
||||
// TODO: put somewhere else:
|
||||
ruby_interpreter ().add_path (p->first);
|
||||
python_interpreter ().add_path (p->first);
|
||||
}
|
||||
}
|
||||
|
||||
// Add locations defined by the technologies
|
||||
sync_tech_macro_locations ();
|
||||
|
||||
// If the editable flag was not set, use it from the
|
||||
// configuration. Since it is too early now, we cannot use the
|
||||
// configuration once it is read
|
||||
|
|
@ -1722,120 +1669,5 @@ Application::special_app_flag (const std::string &name)
|
|||
return (env && *env);
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *>
|
||||
Application::sync_tech_macro_locations ()
|
||||
{
|
||||
if (m_no_macros) {
|
||||
return std::vector<lay::MacroCollection *> ();
|
||||
}
|
||||
|
||||
std::set<std::pair<std::string, std::string> > tech_macro_paths;
|
||||
std::map<std::pair<std::string, std::string>, std::string> tech_names_by_path;
|
||||
|
||||
// Add additional places where the technologies define some macros
|
||||
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
|
||||
|
||||
if (t->base_path ().empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < m_macro_categories.size (); ++c) {
|
||||
|
||||
QDir base_dir (tl::to_qstring (t->base_path ()));
|
||||
if (base_dir.exists ()) {
|
||||
|
||||
QDir macro_dir (base_dir.filePath (tl::to_qstring (m_macro_categories [c].first)));
|
||||
if (macro_dir.exists ()) {
|
||||
|
||||
std::string mp = tl::to_string (macro_dir.path ());
|
||||
std::pair<std::string, std::string> cp (m_macro_categories [c].first, mp);
|
||||
tech_macro_paths.insert (cp);
|
||||
std::string &tn = tech_names_by_path [cp];
|
||||
if (! tn.empty ()) {
|
||||
tn += ",";
|
||||
}
|
||||
tn += t->name ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// delete macro collections which are no longer required or update description
|
||||
std::vector<lay::MacroCollection *> folders_to_delete;
|
||||
std::string desc_prefix = tl::to_string (QObject::tr ("Technology")) + " - ";
|
||||
|
||||
lay::MacroCollection *root = &lay::MacroCollection::root ();
|
||||
|
||||
for (lay::MacroCollection::child_iterator m = root->begin_children (); m != root->end_children (); ++m) {
|
||||
|
||||
std::pair<std::string, std::string> cp (m->second->category (), m->second->path ());
|
||||
if (m->second->virtual_mode () == lay::MacroCollection::TechFolder && m_tech_macro_paths.find (cp) != m_tech_macro_paths.end ()) {
|
||||
|
||||
if (tech_macro_paths.find (cp) == tech_macro_paths.end ()) {
|
||||
// no longer used
|
||||
folders_to_delete.push_back (m->second);
|
||||
} else {
|
||||
// used: update description if required
|
||||
std::string desc = desc_prefix + tech_names_by_path [cp];
|
||||
m->second->set_description (desc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<lay::MacroCollection *>::iterator m = folders_to_delete.begin (); m != folders_to_delete.end (); ++m) {
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Removing macro folder " << (*m)->path () << ", category '" << (*m)->category () << "' because no longer in use";
|
||||
}
|
||||
root->erase (*m);
|
||||
}
|
||||
|
||||
// store new paths
|
||||
m_tech_macro_paths = tech_macro_paths;
|
||||
|
||||
// add new folders
|
||||
for (lay::MacroCollection::child_iterator m = root->begin_children (); m != root->end_children (); ++m) {
|
||||
if (m->second->virtual_mode () == lay::MacroCollection::TechFolder) {
|
||||
std::pair<std::string, std::string> cp (m->second->category (), m->second->path ());
|
||||
tech_macro_paths.erase (cp);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *> new_folders;
|
||||
|
||||
for (std::set<std::pair<std::string, std::string> >::const_iterator p = tech_macro_paths.begin (); p != tech_macro_paths.end (); ++p) {
|
||||
|
||||
const std::string &tn = tech_names_by_path [*p];
|
||||
|
||||
// TODO: is it wise to make it writeable?
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Adding macro folder " << p->second << ", category '" << p->first << "' for technologies " << tn;
|
||||
}
|
||||
|
||||
// Add the folder. Note: it may happen that a macro folder for the tech specific macros already exists in
|
||||
// a non-tech context.
|
||||
// In that case, the add_folder method will return 0.
|
||||
lay::MacroCollection *mc = lay::MacroCollection::root ().add_folder (desc_prefix + tn, p->second, p->first, false);
|
||||
if (mc) {
|
||||
|
||||
mc->set_virtual_mode (lay::MacroCollection::TechFolder);
|
||||
new_folders.push_back (mc);
|
||||
|
||||
// TODO: put somewhere else:
|
||||
ruby_interpreter ().add_path (p->second);
|
||||
python_interpreter ().add_path (p->second);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_folders;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,14 +202,6 @@ public:
|
|||
*/
|
||||
bool special_app_flag (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Obtain the list of macro categories
|
||||
*/
|
||||
const std::vector< std::pair<std::string, std::string> > ¯o_categories () const
|
||||
{
|
||||
return m_macro_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a reference to the Ruby interpreter
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -44,6 +44,38 @@ MacroController::MacroController ()
|
|||
connect (&m_temp_macros, SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::initialize (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
// Scan built-in macros
|
||||
// These macros are always taken, even if there are no macros requested (they are required to
|
||||
// fully form the API).
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true);
|
||||
lay::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true);
|
||||
|
||||
// TODO: consider adding "drc" dynamically and allow more dynamic categories
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("macros", tl::to_string (QObject::tr ("Ruby"))));
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("pymacros", tl::to_string (QObject::tr ("Python"))));
|
||||
m_macro_categories.push_back (std::pair<std::string, std::string> ("drc", tl::to_string (QObject::tr ("DRC"))));
|
||||
|
||||
// Scan for macros and set interpreter path
|
||||
for (std::vector <std::pair<std::string, std::pair<std::string, std::pair<std::string, bool> > > >::const_iterator p = m_paths.begin (); p != m_paths.end (); ++p) {
|
||||
|
||||
std::string path = p->first;
|
||||
std::string description = p->second.first;
|
||||
std::string cat = p->second.second.first;
|
||||
bool readonly = p->second.second.second;
|
||||
|
||||
for (size_t c = 0; c < m_macro_categories.size (); ++c) {
|
||||
if (cat.empty () || cat == m_macro_categories [c].first) {
|
||||
std::string mp = tl::to_string (QDir (tl::to_qstring (p->first)).filePath (tl::to_qstring (m_macro_categories [c].first)));
|
||||
lay::MacroCollection::root ().add_folder (description, mp, m_macro_categories [c].first, readonly);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::initialized (lay::PluginRoot *root)
|
||||
{
|
||||
|
|
@ -236,6 +268,12 @@ MacroController::refresh ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::add_path (const std::string &path, const std::string &description, const std::string &category, bool readonly)
|
||||
{
|
||||
m_paths.push_back (std::make_pair (path, std::make_pair (description, std::make_pair (category, readonly))));
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::add_temp_macro (lay::Macro *m)
|
||||
{
|
||||
|
|
@ -252,7 +290,7 @@ MacroController::add_macro_items_to_menu (lay::MacroCollection &collection, int
|
|||
if (! tech || c->second->virtual_mode () != lay::MacroCollection::TechFolder) {
|
||||
consider = true;
|
||||
} else {
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::Application::instance ()->macro_categories ();
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator cc = mc.begin (); cc != mc.end () && !consider; ++cc) {
|
||||
consider = (c->second->path () == tl::to_string (QDir (tl::to_qstring (tech->base_path ())).filePath (tl::to_qstring (cc->first))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ public:
|
|||
*/
|
||||
MacroController ();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void initialize (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
|
|
@ -117,6 +122,11 @@ public:
|
|||
*/
|
||||
void refresh ();
|
||||
|
||||
/**
|
||||
* @brief Adds a search path to the macros
|
||||
*/
|
||||
void add_path (const std::string &path, const std::string &description, const std::string &category, bool readonly);
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary macro
|
||||
*
|
||||
|
|
@ -128,6 +138,14 @@ public:
|
|||
*/
|
||||
void add_temp_macro (lay::Macro *m);
|
||||
|
||||
/**
|
||||
* @brief Obtain the list of macro categories
|
||||
*/
|
||||
const std::vector< std::pair<std::string, std::string> > ¯o_categories () const
|
||||
{
|
||||
return m_macro_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the singleton instance for this object
|
||||
*/
|
||||
|
|
@ -146,6 +164,8 @@ private:
|
|||
std::vector<lay::Action> m_macro_actions;
|
||||
std::map<QAction *, lay::Macro *> m_action_to_macro;
|
||||
lay::MacroCollection m_temp_macros;
|
||||
std::vector< std::pair<std::string, std::pair<std::string, std::pair<std::string, bool> > > > m_paths;
|
||||
std::vector< std::pair<std::string, std::string> > m_macro_categories;
|
||||
|
||||
void add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech, std::vector<std::pair<std::string, std::string> > *key_bindings);
|
||||
void do_update_menu_with_macros ();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "ui_MacroTemplateSelectionDialog.h"
|
||||
#include "layMacroController.h"
|
||||
#include "layMacroEditorTree.h"
|
||||
#include "layMacroEditorDialog.h"
|
||||
#include "layMacroEditorSetupDialog.h"
|
||||
|
|
@ -263,7 +264,7 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
|||
connect (mp_root, SIGNAL (macro_changed (Macro *)), this, SLOT (macro_changed (Macro *)));
|
||||
connect (mp_root, SIGNAL (macro_deleted (Macro *)), this, SLOT (macro_deleted (Macro *)));
|
||||
|
||||
m_categories = lay::Application::instance ()->macro_categories ();
|
||||
m_categories = lay::MacroController::instance ()->macro_categories ();
|
||||
|
||||
treeTab->clear ();
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include "layApplication.h"
|
||||
#include "layMacroEditorTree.h"
|
||||
#include "layMacro.h"
|
||||
#include "layMacroController.h"
|
||||
#include "layTechnologyController.h"
|
||||
#include "tlAssert.h"
|
||||
#include "tlStream.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -479,15 +481,23 @@ TechSetupDialog::TechSetupDialog (QWidget *parent)
|
|||
connect (import_action, SIGNAL (triggered ()), this, SLOT (import_clicked ()));
|
||||
QAction *export_action = new QAction (QObject::tr ("Export Technology"), this);
|
||||
connect (export_action, SIGNAL (triggered ()), this, SLOT (export_clicked ()));
|
||||
QAction *refresh_action = new QAction (QObject::tr ("Refresh"), this);
|
||||
connect (refresh_action, SIGNAL (triggered ()), this, SLOT (refresh_clicked ()));
|
||||
|
||||
QAction *separator;
|
||||
|
||||
tech_tree->addAction (add_action);
|
||||
tech_tree->addAction (delete_action);
|
||||
tech_tree->addAction (rename_action);
|
||||
QAction *separator = new QAction (this);
|
||||
separator = new QAction (this);
|
||||
separator->setSeparator (true);
|
||||
tech_tree->addAction (separator);
|
||||
tech_tree->addAction (import_action);
|
||||
tech_tree->addAction (export_action);
|
||||
separator = new QAction (this);
|
||||
separator->setSeparator (true);
|
||||
tech_tree->addAction (separator);
|
||||
tech_tree->addAction (refresh_action);
|
||||
|
||||
tech_tree->header ()->hide ();
|
||||
connect (tech_tree, SIGNAL (currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT (current_tech_changed (QTreeWidgetItem *, QTreeWidgetItem *)));
|
||||
|
|
@ -527,23 +537,87 @@ TechSetupDialog::clear_components ()
|
|||
mp_current_tech_component = 0;
|
||||
}
|
||||
|
||||
int
|
||||
TechSetupDialog::exec ()
|
||||
void
|
||||
TechSetupDialog::refresh_clicked ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
commit ();
|
||||
lay::TechnologyController::instance ()->refresh ();
|
||||
update ();
|
||||
|
||||
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 ()
|
||||
{
|
||||
update ();
|
||||
|
||||
tc_stack->setMinimumSize (tc_stack->sizeHint ());
|
||||
|
||||
int ret = QDialog::exec ();
|
||||
if (ret) {
|
||||
*lay::Technologies ().instance () = m_technologies;
|
||||
commit ();
|
||||
}
|
||||
|
||||
// clean up
|
||||
update_tech (0);
|
||||
clear_components ();
|
||||
m_technologies = lay::Technologies ();
|
||||
update_tech_tree ();
|
||||
|
||||
|
|
@ -583,7 +657,19 @@ BEGIN_PROTECTED
|
|||
throw tl::Exception (tl::to_string (QObject::tr ("A technology with this name already exists")));
|
||||
}
|
||||
|
||||
QDir root = QDir (tl::to_qstring (lay::TechnologyController::instance ()->default_root ()));
|
||||
QDir tech_dir (root.filePath (tn));
|
||||
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);
|
||||
|
||||
nt->set_tech_file_path (tl::to_string (tech_dir.absoluteFilePath (tn + QString::fromUtf8 (".lyt"))));
|
||||
nt->set_persisted (false);
|
||||
nt->set_name (tl::to_string (tn));
|
||||
nt->set_description (std::string ());
|
||||
m_technologies.add (nt);
|
||||
|
|
@ -610,8 +696,8 @@ BEGIN_PROTECTED
|
|||
throw tl::Exception (tl::to_string (QObject::tr ("The default technology cannot be deleted")));
|
||||
}
|
||||
|
||||
if (! t->is_persisted ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Auto-imported technologies cannot be deleted")));
|
||||
if (t->is_readonly ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("This technology is read-only and cannot be deleted")));
|
||||
}
|
||||
|
||||
if (QMessageBox::question (this, QObject::tr ("Deleting Technology"),
|
||||
|
|
@ -623,6 +709,7 @@ BEGIN_PROTECTED
|
|||
if (i->name () == t->name ()) {
|
||||
|
||||
m_technologies.remove (i->name ());
|
||||
|
||||
update_tech_tree ();
|
||||
select_tech (*m_technologies.technology_by_name (std::string ()));
|
||||
|
||||
|
|
@ -652,8 +739,8 @@ BEGIN_PROTECTED
|
|||
throw tl::Exception (tl::to_string (QObject::tr ("The default technology cannot be renamed")));
|
||||
}
|
||||
|
||||
if (! t->is_persisted ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Auto-imported technologies cannot be renamed")));
|
||||
if (t->is_readonly ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("This technology is read-only and cannot be renamed")));
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
|
@ -670,10 +757,21 @@ BEGIN_PROTECTED
|
|||
throw tl::Exception (tl::to_string (QObject::tr ("A technology with this name already exists")));
|
||||
}
|
||||
|
||||
t->set_name (tl::to_string (tn));
|
||||
if (t->name () != tl::to_string (tn)) {
|
||||
|
||||
update_tech_tree ();
|
||||
select_tech (*t);
|
||||
t->set_name (tl::to_string (tn));
|
||||
|
||||
if (! t->is_persisted () && ! t->tech_file_path().empty ()) {
|
||||
TipDialog td (this,
|
||||
tl::to_string (QObject::tr ("<html><body>Renaming of a technology will neither rename the technology file or the folder the file is stored in.<br/>The file or folder needs to be renamed manually.</body></html>")),
|
||||
"tech-manager-rename-tip");
|
||||
td.exec_dialog ();
|
||||
}
|
||||
|
||||
update_tech_tree ();
|
||||
select_tech (*t);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -740,7 +838,7 @@ TechSetupDialog::update_tech_tree ()
|
|||
for (std::map <std::string, const lay::Technology *>::const_iterator t = tech_by_name.begin (); t != tech_by_name.end (); ++t) {
|
||||
|
||||
QFont f (tech_tree->font ());
|
||||
f.setItalic (! t->second->is_persisted ());
|
||||
f.setItalic (t->second->is_readonly ());
|
||||
|
||||
std::string d;
|
||||
d += t->first;
|
||||
|
|
@ -753,6 +851,9 @@ TechSetupDialog::update_tech_tree ()
|
|||
ti->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (d)));
|
||||
ti->setData (0, Qt::UserRole, QVariant (tl::to_qstring (t->first)));
|
||||
ti->setData (0, Qt::FontRole, QVariant (f));
|
||||
if (! t->second->tech_file_path ().empty ()) {
|
||||
ti->setData (0, Qt::ToolTipRole, QVariant (tl::to_qstring (t->second->tech_file_path ())));
|
||||
}
|
||||
|
||||
std::vector <std::string> tc_names = t->second->component_names ();
|
||||
std::map <std::string, const lay::TechnologyComponent *> tc_by_name;
|
||||
|
|
@ -775,12 +876,14 @@ TechSetupDialog::update_tech_tree ()
|
|||
tci->setData (0, Qt::UserRole + 1, QVariant (tl::to_qstring ("_save_options")));
|
||||
tci->setData (0, Qt::FontRole, QVariant (f));
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::Application::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator c = mc.begin (); c != mc.end (); ++c) {
|
||||
tci = new QTreeWidgetItem (ti);
|
||||
tci->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (c->second)));
|
||||
tci->setData (0, Qt::UserRole + 1, QVariant (tl::to_qstring (std::string ("_macros_") + c->first)));
|
||||
tci->setData (0, Qt::FontRole, QVariant (f));
|
||||
if (lay::MacroController::instance ()) {
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::MacroController::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator c = mc.begin (); c != mc.end (); ++c) {
|
||||
tci = new QTreeWidgetItem (ti);
|
||||
tci->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (c->second)));
|
||||
tci->setData (0, Qt::UserRole + 1, QVariant (tl::to_qstring (std::string ("_macros_") + c->first)));
|
||||
tci->setData (0, Qt::FontRole, QVariant (f));
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map <std::string, const lay::TechnologyComponent *>::const_iterator c = tc_by_name.begin (); c != tc_by_name.end (); ++c) {
|
||||
|
|
@ -791,7 +894,6 @@ TechSetupDialog::update_tech_tree ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -808,28 +910,30 @@ TechSetupDialog::update_tech (lay::Technology *t)
|
|||
if (t) {
|
||||
|
||||
lay::TechnologyComponentEditor *tce_widget = new TechBaseEditorPage (this);
|
||||
tce_widget->setEnabled (t->is_persisted ());
|
||||
tce_widget->setEnabled (!t->is_readonly ());
|
||||
tce_widget->set_technology (t, 0);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (std::string ("_general"), tce_widget));
|
||||
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::Application::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator c = mc.begin (); c != mc.end (); ++c) {
|
||||
tce_widget = new TechMacrosPage (this, c->first, c->second);
|
||||
tce_widget->setEnabled (t->is_persisted ());
|
||||
tce_widget->set_technology (t, 0);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (std::string ("_macros_") + c->first, tce_widget));
|
||||
if (lay::MacroController::instance ()) {
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::MacroController::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator c = mc.begin (); c != mc.end (); ++c) {
|
||||
tce_widget = new TechMacrosPage (this, c->first, c->second);
|
||||
tce_widget->setEnabled (!t->is_readonly ());
|
||||
tce_widget->set_technology (t, 0);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (std::string ("_macros_") + c->first, tce_widget));
|
||||
}
|
||||
}
|
||||
|
||||
tce_widget = new TechLoadOptionsEditorPage (this);
|
||||
tce_widget->setEnabled (t->is_persisted ());
|
||||
tce_widget->setEnabled (!t->is_readonly ());
|
||||
tce_widget->set_technology (t, 0);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (std::string ("_load_options"), tce_widget));
|
||||
|
||||
tce_widget = new TechSaveOptionsEditorPage (this);
|
||||
tce_widget->setEnabled (t->is_persisted ());
|
||||
tce_widget->setEnabled (!t->is_readonly ());
|
||||
tce_widget->set_technology (t, 0);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (std::string ("_save_options"), tce_widget));
|
||||
|
|
@ -842,7 +946,7 @@ TechSetupDialog::update_tech (lay::Technology *t)
|
|||
|
||||
tce_widget = tc->create_editor (this);
|
||||
if (tce_widget) {
|
||||
tce_widget->setEnabled (t->is_persisted ());
|
||||
tce_widget->setEnabled (!t->is_readonly ());
|
||||
tce_widget->set_technology (t, tc);
|
||||
tc_stack->addWidget (tce_widget);
|
||||
m_component_editors.insert (std::make_pair (tc->name (), tce_widget));
|
||||
|
|
@ -936,7 +1040,7 @@ TechSetupDialog::commit_tech_component ()
|
|||
mp_current_editor->commit ();
|
||||
}
|
||||
|
||||
if (mp_current_tech && mp_current_tech_component && mp_current_tech->is_persisted ()) {
|
||||
if (mp_current_tech && mp_current_tech_component && !mp_current_tech->is_readonly ()) {
|
||||
|
||||
mp_current_tech->set_component (mp_current_tech_component->clone ());
|
||||
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ protected slots:
|
|||
void rename_clicked ();
|
||||
void import_clicked ();
|
||||
void export_clicked ();
|
||||
void refresh_clicked ();
|
||||
|
||||
private:
|
||||
void update_tech_tree ();
|
||||
|
|
@ -148,6 +149,8 @@ private:
|
|||
std::string selected_tech_component_name ();
|
||||
void commit_tech_component ();
|
||||
void clear_components ();
|
||||
bool commit ();
|
||||
void update ();
|
||||
|
||||
lay::Technologies m_technologies;
|
||||
lay::Technology *mp_current_tech;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
#include "laybasicConfig.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
@ -43,11 +46,17 @@ std::string tech_string_from_name (const std::string &tn)
|
|||
}
|
||||
|
||||
TechnologyController::TechnologyController ()
|
||||
: PluginDeclaration (), mp_editor (0), mp_mw (0)
|
||||
: PluginDeclaration (), mp_editor (0), mp_mw (0), m_no_macros (false)
|
||||
{
|
||||
m_current_technology_updated = false;
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::enable_macros (bool enable)
|
||||
{
|
||||
m_no_macros = !enable;
|
||||
}
|
||||
|
||||
TechnologyController *
|
||||
TechnologyController::instance ()
|
||||
{
|
||||
|
|
@ -60,9 +69,17 @@ TechnologyController::instance ()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::initialize (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::initialized (lay::PluginRoot *root)
|
||||
{
|
||||
sync_tech_macro_locations ();
|
||||
|
||||
mp_mw = dynamic_cast <lay::MainWindow *> (root);
|
||||
if (mp_mw) {
|
||||
mp_editor = new lay::TechSetupDialog (mp_mw);
|
||||
|
|
@ -272,7 +289,7 @@ TechnologyController::show_editor ()
|
|||
{
|
||||
if (mp_editor && mp_editor->exec ()) {
|
||||
|
||||
std::vector<lay::MacroCollection *> nm = lay::Application::instance ()->sync_tech_macro_locations ();
|
||||
std::vector<lay::MacroCollection *> nm = sync_tech_macro_locations ();
|
||||
|
||||
bool has_autorun = false;
|
||||
for (std::vector<lay::MacroCollection *>::const_iterator m = nm.begin (); m != nm.end () && ! has_autorun; ++m) {
|
||||
|
|
@ -295,6 +312,204 @@ TechnologyController::show_editor ()
|
|||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
TechnologyController::default_root ()
|
||||
{
|
||||
tl_assert (!m_paths.empty ());
|
||||
return m_paths.front ();
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::refresh ()
|
||||
{
|
||||
try {
|
||||
|
||||
lay::Technologies::instance ()->begin_updates ();
|
||||
lay::Technologies::instance ()->clear ();
|
||||
|
||||
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 ();
|
||||
|
||||
} catch (...) {
|
||||
lay::Technologies::instance ()->end_updates ();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::add_temp_tech (const lay::Technology &t)
|
||||
{
|
||||
m_temp_tech.push_back (t);
|
||||
}
|
||||
|
||||
void
|
||||
TechnologyController::add_path (const std::string &p)
|
||||
{
|
||||
m_paths.push_back (p);
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *>
|
||||
TechnologyController::sync_tech_macro_locations ()
|
||||
{
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
|
||||
if (! mc || m_no_macros) {
|
||||
return std::vector<lay::MacroCollection *> ();
|
||||
}
|
||||
|
||||
std::set<std::pair<std::string, std::string> > tech_macro_paths;
|
||||
std::map<std::pair<std::string, std::string>, std::string> tech_names_by_path;
|
||||
|
||||
// Add additional places where the technologies define some macros
|
||||
for (lay::Technologies::const_iterator t = lay::Technologies::instance ()->begin (); t != lay::Technologies::instance ()->end (); ++t) {
|
||||
|
||||
if (t->base_path ().empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < mc->macro_categories ().size (); ++c) {
|
||||
|
||||
QDir base_dir (tl::to_qstring (t->base_path ()));
|
||||
if (base_dir.exists ()) {
|
||||
|
||||
QDir macro_dir (base_dir.filePath (tl::to_qstring (mc->macro_categories () [c].first)));
|
||||
if (macro_dir.exists ()) {
|
||||
|
||||
std::string mp = tl::to_string (macro_dir.path ());
|
||||
std::pair<std::string, std::string> cp (mc->macro_categories () [c].first, mp);
|
||||
tech_macro_paths.insert (cp);
|
||||
std::string &tn = tech_names_by_path [cp];
|
||||
if (! tn.empty ()) {
|
||||
tn += ",";
|
||||
}
|
||||
tn += t->name ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// delete macro collections which are no longer required or update description
|
||||
std::vector<lay::MacroCollection *> folders_to_delete;
|
||||
std::string desc_prefix = tl::to_string (QObject::tr ("Technology")) + " - ";
|
||||
|
||||
lay::MacroCollection *root = &lay::MacroCollection::root ();
|
||||
|
||||
for (lay::MacroCollection::child_iterator m = root->begin_children (); m != root->end_children (); ++m) {
|
||||
|
||||
std::pair<std::string, std::string> cp (m->second->category (), m->second->path ());
|
||||
if (m->second->virtual_mode () == lay::MacroCollection::TechFolder && m_tech_macro_paths.find (cp) != m_tech_macro_paths.end ()) {
|
||||
|
||||
if (tech_macro_paths.find (cp) == tech_macro_paths.end ()) {
|
||||
// no longer used
|
||||
folders_to_delete.push_back (m->second);
|
||||
} else {
|
||||
// used: update description if required
|
||||
std::string desc = desc_prefix + tech_names_by_path [cp];
|
||||
m->second->set_description (desc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (std::vector<lay::MacroCollection *>::iterator m = folders_to_delete.begin (); m != folders_to_delete.end (); ++m) {
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Removing macro folder " << (*m)->path () << ", category '" << (*m)->category () << "' because no longer in use";
|
||||
}
|
||||
root->erase (*m);
|
||||
}
|
||||
|
||||
// store new paths
|
||||
m_tech_macro_paths = tech_macro_paths;
|
||||
|
||||
// add new folders
|
||||
for (lay::MacroCollection::child_iterator m = root->begin_children (); m != root->end_children (); ++m) {
|
||||
if (m->second->virtual_mode () == lay::MacroCollection::TechFolder) {
|
||||
std::pair<std::string, std::string> cp (m->second->category (), m->second->path ());
|
||||
tech_macro_paths.erase (cp);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *> new_folders;
|
||||
|
||||
for (std::set<std::pair<std::string, std::string> >::const_iterator p = tech_macro_paths.begin (); p != tech_macro_paths.end (); ++p) {
|
||||
|
||||
const std::string &tn = tech_names_by_path [*p];
|
||||
|
||||
// TODO: is it wise to make it writeable?
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::info << "Adding macro folder " << p->second << ", category '" << p->first << "' for technologies " << tn;
|
||||
}
|
||||
|
||||
// Add the folder. Note: it may happen that a macro folder for the tech specific macros already exists in
|
||||
// a non-tech context.
|
||||
// In that case, the add_folder method will return 0.
|
||||
lay::MacroCollection *mc = lay::MacroCollection::root ().add_folder (desc_prefix + tn, p->second, p->first, false);
|
||||
if (mc) {
|
||||
|
||||
mc->set_virtual_mode (lay::MacroCollection::TechFolder);
|
||||
new_folders.push_back (mc);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_folders;
|
||||
}
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new TechnologyController (), 110, "TechnologyController");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,11 +29,14 @@
|
|||
#include "layTechnology.h"
|
||||
#include "layAbstractMenu.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class TechSetupDialog;
|
||||
class MainWindow;
|
||||
class MacroCollection;
|
||||
|
||||
/**
|
||||
* @brief A "controller" for the technologies
|
||||
|
|
@ -52,6 +55,7 @@ public:
|
|||
*/
|
||||
TechnologyController ();
|
||||
|
||||
void initialize (lay::PluginRoot *root);
|
||||
void initialized (lay::PluginRoot *root);
|
||||
void uninitialize (lay::PluginRoot *root);
|
||||
|
||||
|
|
@ -69,6 +73,41 @@ public:
|
|||
return m_active_technology;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables or disables macros
|
||||
* If macros are enabled, the macro tree contains the macros defined within the technologies.
|
||||
* This flag needs to be set initially and before the technology tree is updated.
|
||||
*/
|
||||
void enable_macros (bool enable);
|
||||
|
||||
/**
|
||||
* @brief Adds a path as a search path for technologies
|
||||
* "refresh" needs to be called after search paths have been added.
|
||||
*/
|
||||
void add_path (const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary technology
|
||||
* Temporary technologies are additional technologies which are added to the list of technologies
|
||||
* but are not persisted or editable.
|
||||
* "refresh" needs to be called after temp technologies have been added.
|
||||
*/
|
||||
void add_temp_tech (const lay::Technology &t);
|
||||
|
||||
/**
|
||||
* @brief Updates the technology collection with the technologies from the search path and teh temp technologies
|
||||
*/
|
||||
void refresh ();
|
||||
|
||||
/**
|
||||
* @brief Gets the default root folder
|
||||
* The default root is the first one of the paths added with add_path.
|
||||
*/
|
||||
const std::string &default_root ();
|
||||
|
||||
/**
|
||||
* @brief Gets the singleton instance of the controller
|
||||
*/
|
||||
static TechnologyController *instance ();
|
||||
|
||||
signals:
|
||||
|
|
@ -92,6 +131,10 @@ private:
|
|||
bool m_current_technology_updated;
|
||||
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;
|
||||
|
||||
void update_after_change ();
|
||||
void technologies_changed ();
|
||||
|
|
@ -101,6 +144,7 @@ private:
|
|||
bool menu_activated (const std::string &symbol) const;
|
||||
void update_current_technology ();
|
||||
void update_menu ();
|
||||
std::vector<lay::MacroCollection *> sync_tech_macro_locations ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ namespace lay
|
|||
Technologies::Technologies ()
|
||||
{
|
||||
m_technologies.push_back (new Technology (std::string (""), "(Default)"));
|
||||
m_changed = false;
|
||||
m_in_update = false;
|
||||
}
|
||||
|
||||
Technologies::Technologies (const Technologies &other)
|
||||
|
|
@ -128,7 +130,7 @@ Technologies::add (Technology *technology)
|
|||
technology->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
|
||||
}
|
||||
|
||||
technologies_changed_event ();
|
||||
technologies_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -137,12 +139,52 @@ Technologies::remove (const std::string &name)
|
|||
for (tl::stable_vector<Technology>::iterator t = m_technologies.begin (); t != m_technologies.end (); ++t) {
|
||||
if (t->name () == name) {
|
||||
m_technologies.erase (t);
|
||||
technologies_changed_event ();
|
||||
technologies_changed ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Technologies::clear ()
|
||||
{
|
||||
if (! m_technologies.empty ()) {
|
||||
m_technologies.clear ();
|
||||
technologies_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Technologies::technologies_changed ()
|
||||
{
|
||||
if (m_in_update) {
|
||||
m_changed = true;
|
||||
} else {
|
||||
technologies_changed_event ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Technologies::begin_updates ()
|
||||
{
|
||||
tl_assert (! m_in_update);
|
||||
m_in_update = true;
|
||||
m_changed = false;
|
||||
}
|
||||
|
||||
void
|
||||
Technologies::end_updates ()
|
||||
{
|
||||
if (m_in_update) {
|
||||
m_in_update = false;
|
||||
if (m_changed) {
|
||||
m_changed = false;
|
||||
technologies_changed ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Technologies::has_technology (const std::string &name) const
|
||||
{
|
||||
|
|
@ -171,13 +213,13 @@ Technologies::technology_by_name (const std::string &name)
|
|||
// Technology implementation
|
||||
|
||||
Technology::Technology ()
|
||||
: m_name (), m_description (), m_dbu (0.001), m_persisted (true)
|
||||
: m_name (), m_description (), m_dbu (0.001), m_persisted (true), m_readonly (false)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
Technology::Technology (const std::string &name, const std::string &description)
|
||||
: m_name (name), m_description (description), m_dbu (0.001), m_persisted (true)
|
||||
: m_name (name), m_description (description), m_dbu (0.001), m_persisted (true), m_readonly (false)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
|
@ -350,7 +392,9 @@ Technology::load (const std::string &fn)
|
|||
xml_struct.parse (source, *this);
|
||||
|
||||
// use the tech file's path as the default base path
|
||||
set_default_base_path (tl::to_string (QFileInfo (tl::to_qstring (fn)).absoluteDir ().path ()));
|
||||
std::string lyt_file = tl::to_string (QFileInfo (tl::to_qstring (fn)).absoluteDir ().path ());
|
||||
set_default_base_path (lyt_file);
|
||||
set_tech_file_path (lyt_file);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -133,6 +133,22 @@ public:
|
|||
*/
|
||||
void remove (const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Clears the list of technologies
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Begins a bulk operation
|
||||
* This method will disable "technologies_changed" events until (later) end_updates () is called.
|
||||
*/
|
||||
void begin_updates ();
|
||||
|
||||
/**
|
||||
* @brief Ends a bulk operation
|
||||
*/
|
||||
void end_updates ();
|
||||
|
||||
/**
|
||||
* @brief Checks, if a technology with the given name exists
|
||||
*/
|
||||
|
|
@ -191,8 +207,15 @@ protected:
|
|||
technology_changed_event (t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends the technologies_changed event
|
||||
*/
|
||||
void technologies_changed ();
|
||||
|
||||
private:
|
||||
tl::stable_vector<Technology> m_technologies;
|
||||
bool m_changed;
|
||||
bool m_in_update;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -308,6 +331,23 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the path of the tech file if the technology was loaded from a tech file
|
||||
*/
|
||||
const std::string &tech_file_path () const
|
||||
{
|
||||
return m_lyt_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the path of the tech file
|
||||
* This method is intended for internal use only.
|
||||
*/
|
||||
void set_tech_file_path (const std::string &lyt_file)
|
||||
{
|
||||
m_lyt_file = lyt_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the description
|
||||
*/
|
||||
|
|
@ -497,6 +537,24 @@ public:
|
|||
m_persisted = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a flag indicating whether the technology is readonly
|
||||
*
|
||||
* If the flag is false, the technology can be edited. Otherwise it's locked for editing.
|
||||
*/
|
||||
bool is_readonly () const
|
||||
{
|
||||
return m_readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a flag indicating whether the technology is readonly
|
||||
*/
|
||||
void set_readonly (bool f)
|
||||
{
|
||||
m_readonly = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief An event indicating that the technology has changed
|
||||
*/
|
||||
|
|
@ -514,9 +572,12 @@ private:
|
|||
db::LoadLayoutOptions m_load_layout_options;
|
||||
db::SaveLayoutOptions m_save_layout_options;
|
||||
std::string m_lyp_path;
|
||||
std::string m_lyt_path;
|
||||
bool m_add_other_layers;
|
||||
std::vector <TechnologyComponent *> m_components;
|
||||
bool m_persisted;
|
||||
bool m_readonly;
|
||||
std::string m_lyt_file;
|
||||
|
||||
void init ();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue