From 8e21dab345a8d6d3a31f4250b1482dcd7c113d4f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 28 May 2022 19:27:40 +0200 Subject: [PATCH] Reworked lym::MacroCollection for not using Qt (too much) --- scripts/pyqrc.py | 6 +- src/buddies/src/bd/strmrun.cc | 2 + src/drc/drc/built-in-macros/_drc_engine.rb | 2 +- src/drc/drc/built-in-macros/drc_install.lym | 2 +- .../drc/built-in-macros/drc_interpreters.lym | 4 +- .../layview/gsiDeclLayLayoutView_noqt.cc | 36 ++ src/layview/layview/layLayoutView_noqt.cc | 12 + src/layview/layview/layLayoutView_noqt.h | 10 + src/lvs/lvs/built-in-macros/lvs_install.lym | 2 +- .../lvs/built-in-macros/lvs_interpreters.lym | 4 +- src/lvs/lvs/lvs.pro | 2 +- src/lym/lym/lymMacroCollection.cc | 321 +++++++++--------- src/lym/lym/lymMacroCollection.h | 64 +--- src/tl/tl/tlFileUtils.cc | 11 + src/tl/tl/tlFileUtils.h | 6 + src/tl/tl/tlResources.cc | 62 +++- src/tl/tl/tlResources.h | 18 + src/tl/tl/tlStream.cc | 27 +- src/tl/tl/tlStream.h | 5 - src/unit_tests/unit_test_main.cc | 14 +- src/with_all_libs.pri | 12 +- 21 files changed, 360 insertions(+), 262 deletions(-) diff --git a/scripts/pyqrc.py b/scripts/pyqrc.py index f0cbe3f9f..168748e30 100755 --- a/scripts/pyqrc.py +++ b/scripts/pyqrc.py @@ -30,7 +30,7 @@ class RCFile(object): file.write(f"\n// Resource file {self.path} as {self.alias}\n") file.write( "namespace {\n") file.write( "\n") - file.write(f" class {cls}\n") + file.write(f" struct {cls}\n") file.write( " {\n") file.write(f" {cls}() {cb}\n") file.write(f" static bool compressed = {compressed};\n") @@ -49,10 +49,10 @@ class RCFile(object): file.write( " m_id = tl::register_resource(name, compressed, data, sizeof(data) / sizeof(data[0]));\n") file.write( " }\n") file.write(f" ~{cls}() {cb}\n") - file.write( " tl::unregister_resource(m_id)\n") + file.write( " tl::unregister_resource(m_id);\n") file.write( " }\n") file.write( " tl::resource_id_type m_id;\n") - file.write(f" {bc} resource_instance{index}\n") + file.write(f" {bc} resource_instance{index};\n") file.write( "\n") file.write( "}\n") diff --git a/src/buddies/src/bd/strmrun.cc b/src/buddies/src/bd/strmrun.cc index 0d58374a9..dac4a9981 100644 --- a/src/buddies/src/bd/strmrun.cc +++ b/src/buddies/src/bd/strmrun.cc @@ -83,6 +83,8 @@ BD_PUBLIC int strmrun (int argc, char *argv[]) python.define_variable (v->first, v->second); } + // @@@ ... add Python and Ruby built-in macro collections, autorun-early and autorun ... + std::string script = tl::absolute_file_path (data.script); lym::Macro macro; diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index a168a5442..1382f2524 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -2685,7 +2685,7 @@ CODE end def _process_events - if RBA::Application.instance + if RBA.constants.member?(:Application) && RBA::Application.instance RBA::Application.instance.process_events end end diff --git a/src/drc/drc/built-in-macros/drc_install.lym b/src/drc/drc/built-in-macros/drc_install.lym index 78d1ef3b0..24f67c2f4 100644 --- a/src/drc/drc/built-in-macros/drc_install.lym +++ b/src/drc/drc/built-in-macros/drc_install.lym @@ -19,7 +19,7 @@ module DRC # Installs the home menu entries (needs to be done on autorun, not autorun-early) - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window cat = "drc" diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index a5c4d13ed..dbd8591dd 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -88,7 +88,7 @@ module DRC create_template(":/drc-templates/drc.lym") # if available, create a menu branch - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window mw = RBA::Application::instance.main_window mw.menu.insert_menu("tools_menu.verification_group+", "drc", "DRC") end @@ -160,7 +160,7 @@ module DRC DRCPlainTextInterpreter::new(drc_recipe) # Creates a new macro category - if RBA::Application::instance + if RBA.constants.member?(:Application) && RBA::Application::instance RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ]) end diff --git a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc index a0eaf8235..7af7cdc21 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc @@ -66,6 +66,18 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "\n" "This event has been introduced in version 0.28." ) + + gsi::method ("current", &lay::LayoutView::current, + "@brief Returns the current view\n" + "The current view is the one that is made current by using \\current=.\n" + "\n" + "This variation has been introduced for the non-Qt case in version 0.28." + ) + + gsi::method ("current=", &lay::LayoutView::set_current, gsi::arg ("view"), + "@brief Sets the current view\n" + "See \\current for details.\n" + "\n" + "This method has been introduced for the non-Qt case in version 0.28." + ) + gsi::method ("timer", static_cast (&lay::LayoutView::timer), "@brief A callback required to be called regularily in the non-Qt case.\n" "\n" @@ -84,12 +96,36 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); +static lay::CellViewRef get_active_cellview_ref () +{ + lay::LayoutView *view = 0; // @@@ lay::LayoutView::current (); + if (! view) { + return lay::CellViewRef (); + } + if (view->active_cellview_index () >= 0) { + return view->active_cellview_ref (); + } else { + return lay::CellViewRef (); + } +} + static lay::LayoutView *get_view (lay::CellViewRef *cv) { return cv->view ()->ui (); } static ClassExt extdecl_CellView ( + method ("active", &get_active_cellview_ref, + "@brief Gets the active CellView\n" + "The active CellView is the one that is selected in the current layout view. This method is " + "equivalent to\n" + "@code\n" + "RBA::LayoutView::current.active_cellview\n" + "@/code\n" + "If no CellView is active, this method returns nil.\n" + "\n" + "This method has been introduced in version 0.23." + ) + method_ext ("view", &get_view, "@brief Gets the view the cellview resides in\n" "This reference will be nil if the cellview is not a valid one.\n" diff --git a/src/layview/layview/layLayoutView_noqt.cc b/src/layview/layview/layLayoutView_noqt.cc index 6b8743a40..da85aab88 100644 --- a/src/layview/layview/layLayoutView_noqt.cc +++ b/src/layview/layview/layLayoutView_noqt.cc @@ -59,6 +59,18 @@ LayoutView::timer () } } +static tl::weak_ptr s_current_view; + +LayoutView *LayoutView::current () +{ + return s_current_view.get (); +} + +void LayoutView::set_current (LayoutView *view) +{ + s_current_view.reset (view); +} + } // namespace lay #endif diff --git a/src/layview/layview/layLayoutView_noqt.h b/src/layview/layview/layLayoutView_noqt.h index 0288d6081..959748bbb 100644 --- a/src/layview/layview/layLayoutView_noqt.h +++ b/src/layview/layview/layLayoutView_noqt.h @@ -66,6 +66,16 @@ public: */ void timer (); + /** + * @brief Gets the current view + */ + static LayoutView *current (); + + /** + * @brief Sets the current view + */ + static void set_current (LayoutView *view); + protected: /** * @brief Gets the LayoutView interface diff --git a/src/lvs/lvs/built-in-macros/lvs_install.lym b/src/lvs/lvs/built-in-macros/lvs_install.lym index d2b17657f..967ea1d5e 100644 --- a/src/lvs/lvs/built-in-macros/lvs_install.lym +++ b/src/lvs/lvs/built-in-macros/lvs_install.lym @@ -19,7 +19,7 @@ module LVS # Installs the home menu entries (needs to be done on autorun, not autorun-early) - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window cat = "lvs" diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index 24cd20021..c99c21e98 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -88,7 +88,7 @@ module LVS create_template(":/lvs-templates/lvs.lym") # if available, create a menu branch - if RBA::Application::instance && RBA::Application::instance.main_window + if RBA.constants.member?(:Application) && RBA::Application::instance && RBA::Application::instance.main_window mw = RBA::Application::instance.main_window mw.menu.insert_menu("tools_menu.verification_group+", "lvs", "LVS") end @@ -160,7 +160,7 @@ module LVS LVSPlainTextInterpreter::new(lvs_recipe) # Creates a new macro category - if RBA::Application::instance + if RBA.constants.member?(:Application) && RBA::Application::instance RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ]) end diff --git a/src/lvs/lvs/lvs.pro b/src/lvs/lvs/lvs.pro index 722270f84..5a8c53f27 100644 --- a/src/lvs/lvs/lvs.pro +++ b/src/lvs/lvs/lvs.pro @@ -13,7 +13,7 @@ HEADERS = \ lvsCommon.h \ lvsForceLink.h \ -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ lvsResources.qrc } diff --git a/src/lym/lym/lymMacroCollection.cc b/src/lym/lym/lymMacroCollection.cc index 5ea264937..7955f7ce4 100644 --- a/src/lym/lym/lymMacroCollection.cc +++ b/src/lym/lym/lymMacroCollection.cc @@ -23,8 +23,6 @@ #include "lymMacroCollection.h" -#if defined(HAVE_QT) - #include "lymMacroInterpreter.h" #include "tlExceptions.h" #include "gsiDecl.h" @@ -38,14 +36,15 @@ #include "tlGlobPattern.h" #include "tlInclude.h" #include "tlProgress.h" +#include "tlFileUtils.h" +#include "tlResources.h" #include "rba.h" #include "pya.h" -#include -#include -#include -#include +#if defined(HAVE_QT) +# include +#endif #include #include @@ -90,20 +89,26 @@ void MacroCollection::begin_changes () if (mp_parent) { mp_parent->begin_changes (); } else { +#if defined(HAVE_QT) emit about_to_change (); +#endif } } void MacroCollection::on_menu_needs_update () { +#if defined(HAVE_QT) emit menu_needs_update (); +#endif } void MacroCollection::on_changed () { // Note: it is very important that each on_changed occurs after exactly one begin_changes. // (See #459 for example) +#if defined(HAVE_QT) emit changed (); +#endif on_macro_collection_changed (this); } @@ -112,13 +117,17 @@ void MacroCollection::on_macro_collection_changed (MacroCollection *mc) if (mp_parent) { mp_parent->on_macro_collection_changed (mc); } else { +#if defined(HAVE_QT) emit macro_collection_changed (mc); +#endif } } void MacroCollection::on_child_deleted (MacroCollection *mc) { +#if defined(HAVE_QT) emit child_deleted (mc); +#endif on_macro_collection_deleted (mc); } @@ -127,13 +136,17 @@ void MacroCollection::on_macro_collection_deleted (MacroCollection *mc) if (mp_parent) { mp_parent->on_macro_collection_deleted (mc); } else { +#if defined(HAVE_QT) emit macro_collection_deleted (mc); +#endif } } void MacroCollection::on_macro_deleted_here (Macro *macro) { +#if defined(HAVE_QT) emit macro_deleted_here (macro); +#endif on_macro_deleted (macro); } @@ -142,7 +155,9 @@ void MacroCollection::on_macro_deleted (Macro *macro) if (mp_parent) { mp_parent->on_macro_deleted (macro); } else { +#if defined(HAVE_QT) emit macro_deleted (macro); +#endif } } @@ -151,7 +166,9 @@ void MacroCollection::on_macro_changed (Macro *macro) if (mp_parent) { mp_parent->on_macro_changed (macro); } else { +#if defined(HAVE_QT) emit macro_changed (macro); +#endif } } @@ -215,7 +232,7 @@ std::string MacroCollection::path () const if (m_virtual_mode) { return m_path; } else if (mp_parent) { - return tl::to_string (QFileInfo (QDir (tl::to_qstring (mp_parent->path ())), tl::to_qstring (m_path)).filePath ()); + return tl::combine_path (mp_parent->path (), m_path); } else { return m_path; } @@ -245,64 +262,62 @@ MacroCollection::make_readonly (bool f) } MacroCollection * -MacroCollection::add_folder (const std::string &description, const std::string &path, const std::string &cat, bool readonly, bool force_create) +MacroCollection::add_folder (const std::string &description, const std::string &p, const std::string &cat, bool readonly, bool force_create) { - if (! path.empty () && path[0] == ':') { + if (! p.empty () && p[0] == ':') { + readonly = true; + } else { - QFileInfo file_info (tl::to_qstring (path)); + std::string fp = p; + if (! tl::is_absolute (fp)) { + fp = tl::combine_path (path (), fp); + } - if (! file_info.exists ()) { + if (! tl::file_exists (fp)) { // Try to create the folder since it does not exist yet or skip that one if (! force_create) { if (tl::verbosity () >= 20) { - tl::log << "Folder does not exist - skipping: " << path; + tl::log << "Folder does not exist - skipping: " << fp; } return 0; } else { if (tl::verbosity () >= 20) { - tl::log << "Folder does not exist yet - trying to create it: " << path; + tl::log << "Folder does not exist yet - trying to create it: " << fp; } - if (! QDir::root ().mkpath (file_info.absoluteFilePath ())) { + if (! tl::mkpath (fp)) { if (tl::verbosity () >= 10) { - tl::error << "Unable to create folder path: " << path; + tl::error << "Unable to create folder path: " << fp; } return 0; } } - file_info.refresh (); - } - if (! file_info.isDir ()) { + if (! tl::is_dir (fp)) { if (tl::verbosity () >= 10) { - tl::error << "Folder is not a directory: " << path; + tl::error << "Folder is not a directory: " << fp; } return 0; } - QString cp = file_info.canonicalFilePath (); - if (cp.isEmpty ()) { - return 0; - } - for (child_iterator f = m_folders.begin (); f != m_folders.end (); ++f) { // skip, if that folder is in the collection already - if (QFileInfo (tl::to_qstring (f->first)).canonicalFilePath () == cp) { + if (f->second->path () == fp) { return 0; } } - if (! readonly && ! file_info.isWritable ()) { + if (! readonly && ! tl::is_writable (fp)) { readonly = true; if (tl::verbosity () >= 20) { - tl::log << "Folder is read-only: " << path; + tl::log << "Folder is read-only: " << fp; } } @@ -310,12 +325,12 @@ MacroCollection::add_folder (const std::string &description, const std::string & begin_changes (); - MacroCollection *mc = m_folders.insert (std::make_pair (path, new MacroCollection ())).first->second; - mc->set_name (path); + MacroCollection *mc = m_folders.insert (std::make_pair (p, new MacroCollection ())).first->second; + mc->set_name (p); mc->set_description (description); mc->set_category (cat); mc->set_readonly (readonly); - mc->scan (path); + mc->scan (); mc->set_parent (this); on_changed (); @@ -327,10 +342,11 @@ MacroCollection::add_folder (const std::string &description, const std::string & void MacroCollection::rescan () { for (std::map ::const_iterator m = m_folders.begin (); m != m_folders.end (); ++m) { - m->second->scan (m->first); + m->second->scan (); } } +#if defined(HAVE_QT) namespace { /** @@ -345,168 +361,85 @@ namespace { }; } +#endif -void MacroCollection::scan (const std::string &path) +void MacroCollection::scan () { + std::string p = path (); + if (tl::verbosity () >= 20) { - tl::info << "Scanning macro path " << path << " (readonly=" << m_readonly << ")"; + tl::info << "Scanning macro path " << p << " (readonly=" << m_readonly << ")"; } - if (! path.empty () && path[0] == ':') { + if (! p.empty () && p[0] == ':') { - ResourceWithChildren res (tl::to_qstring (path)); +#if defined(HAVE_QT) + + ResourceWithChildren res (tl::to_qstring (p)); QStringList children = res.children (); children.sort (); - for (QStringList::const_iterator c = children.begin (); c != children.end (); ++c) { + for (auto c = children.begin (); c != children.end (); ++c) { - std::string url = path + "/" + tl::to_string (*c); + std::string url = p + "/" + tl::to_string (*c); QResource res (tl::to_qstring (url)); if (res.size () > 0) { - - QByteArray data; -#if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { -#else - if (res.isCompressed ()) { -#endif - data = qUncompress ((const unsigned char *)res.data (), (int)res.size ()); - } else { - data = QByteArray ((const char *)res.data (), (int)res.size ()); - } - - try { - - Macro::Format format = Macro::NoFormat; - Macro::Interpreter interpreter = Macro::None; - std::string dsl_name; - bool autorun = false; - - if (Macro::format_from_suffix (tl::to_string (*c), interpreter, dsl_name, autorun, format)) { - - std::string n = tl::to_string (QFileInfo (*c).baseName ()); - - iterator mm = m_macros.find (n); - bool found = false; - while (mm != m_macros.end () && mm->first == n && ! found) { - if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && - (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && - mm->second->format () == format) { - found = true; - } - ++mm; - } - if (! found) { - Macro *m = m_macros.insert (std::make_pair (n, new Macro ()))->second; - m->set_interpreter (interpreter); - m->set_autorun_default (autorun); - m->set_autorun (autorun); - m->set_dsl_interpreter (dsl_name); - m->set_format (format); - m->set_name (n); - m->load_from_string (std::string (data.constData (), data.size ()), url); - m->set_readonly (m_readonly); - m->reset_modified (); - m->set_is_file (); - m->set_parent (this); - } - - } - - } catch (tl::Exception &ex) { - tl::error << "Reading " << url << ": " << ex.msg (); - } - + create_entry (url); } } +#else + + std::vector res = tl::find_resources (std::string (p, 1) + "/*"); + for (auto c = res.begin (); c != res.end (); ++c) { + create_entry (":" + *c); + } + +#endif + } else { - QDir dir (tl::to_qstring (path)); - QStringList filters; - filters << QString::fromUtf8 ("*.lym"); - filters << QString::fromUtf8 ("*.txt"); + std::set suffixes; + suffixes.insert ("lym"); + suffixes.insert ("txt"); // TODO: should be either *.rb or *.python, depending on the category. // Right now we rely on the folders not containing foreign files. - filters << QString::fromUtf8 ("*.rb"); - filters << QString::fromUtf8 ("*.py"); + suffixes.insert ("rb"); + suffixes.insert ("py"); // add the suffixes in the DSL interpreter declarations for (tl::Registrar::iterator cls = tl::Registrar::begin (); cls != tl::Registrar::end (); ++cls) { if (! cls->suffix ().empty ()) { - filters << tl::to_qstring ("*." + cls->suffix ()); + suffixes.insert (cls->suffix ()); } } - QStringList files = dir.entryList (filters, QDir::Files); - for (QStringList::ConstIterator f = files.begin (); f != files.end (); ++f) { - - std::unique_ptr new_macro; - - try { - - std::string n = tl::to_string (QFileInfo (*f).completeBaseName ()); - std::string mp = tl::to_string (dir.absoluteFilePath (*f)); - - Macro::Format format = Macro::NoFormat; - Macro::Interpreter interpreter = Macro::None; - std::string dsl_name; - bool autorun = false; - - if (Macro::format_from_suffix (tl::to_string (*f), interpreter, dsl_name, autorun, format)) { - - iterator mm = m_macros.find (n); - bool found = false; - while (mm != m_macros.end () && mm->first == n && ! found) { - if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && - (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && - mm->second->format () == format) { - found = true; - } - ++mm; - } - if (! found) { - Macro *m = new Macro (); - new_macro.reset (m); - m->set_format (format); - m->set_autorun_default (autorun); - m->set_autorun (autorun); - m->set_interpreter (interpreter); - m->set_dsl_interpreter (dsl_name); - m->set_name (n); - m->load_from (mp); - m->reset_modified (); - m->set_readonly (m_readonly); - m->set_parent (this); - } - - } - - if (new_macro.get ()) { - m_macros.insert (std::make_pair (n, new_macro.release ())); - } - - } catch (tl::Exception &ex) { - tl::error << "Reading " << tl::to_string (*f) << " in " << path << ": " << ex.msg (); + std::vector files = tl::dir_entries (p, true /*with_files*/, false /*with_dirs*/, true /*without_dotfiles*/); + for (auto f = files.begin (); f != files.end (); ++f) { + if (suffixes.find (tl::extension (*f)) != suffixes.end ()) { + create_entry (tl::combine_path (p, *f)); } - } - QStringList folders = dir.entryList (QDir::Dirs | QDir::NoDotAndDotDot); - for (QStringList::ConstIterator f = folders.begin (); f != folders.end (); ++f) { + std::vector dirs = tl::dir_entries (p, false /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/); + for (auto f = files.begin (); f != files.end (); ++f) { + + std::string fp = tl::combine_path (p, *f); + if (! tl::is_dir (fp)) { + continue; + } try { - std::string n = tl::to_string (*f); - MacroCollection *&mc = m_folders.insert (std::make_pair (n, (MacroCollection *) 0)).first->second; + MacroCollection *&mc = m_folders.insert (std::make_pair (*f, (MacroCollection *) 0)).first->second; if (! mc) { mc = new MacroCollection (); - mc->set_name (n); + mc->set_name (*f); mc->set_virtual_mode (NotVirtual); - bool ro = (m_readonly || ! QFileInfo (dir.filePath (*f)).isWritable ()); + bool ro = (m_readonly || ! tl::is_writable (fp)); mc->set_readonly (ro); - mc->scan (tl::to_string (dir.filePath (*f))); + mc->scan (); mc->set_parent (this); } @@ -519,6 +452,59 @@ void MacroCollection::scan (const std::string &path) } } +void +MacroCollection::create_entry (const std::string &path) +{ + try { + + std::string n = tl::complete_basename (path); + + Macro::Format format = Macro::NoFormat; + Macro::Interpreter interpreter = Macro::None; + std::string dsl_name; + bool autorun = false; + + std::unique_ptr new_macro; + + if (Macro::format_from_suffix (path, interpreter, dsl_name, autorun, format)) { + + iterator mm = m_macros.find (n); + bool found = false; + while (mm != m_macros.end () && mm->first == n && ! found) { + if ((interpreter == Macro::None || mm->second->interpreter () == interpreter) && + (dsl_name.empty () || mm->second->dsl_interpreter () == dsl_name) && + mm->second->format () == format) { + found = true; + } + ++mm; + } + if (! found) { + Macro *m = new Macro (); + new_macro.reset (m); + m->set_interpreter (interpreter); + m->set_autorun_default (autorun); + m->set_autorun (autorun); + m->set_dsl_interpreter (dsl_name); + m->set_format (format); + m->set_name (n); + m->load_from (path); + m->set_readonly (m_readonly); + m->reset_modified (); + m->set_is_file (); + m->set_parent (this); + } + + } + + if (new_macro.get ()) { + m_macros.insert (std::make_pair (n, new_macro.release ())); + } + + } catch (tl::Exception &ex) { + tl::error << "Reading " << path << ": " << ex.msg (); + } +} + void MacroCollection::clear () { begin_changes (); @@ -594,9 +580,8 @@ bool MacroCollection::rename (const std::string &n) if (tl::verbosity () >= 20) { tl::info << "Renaming macro folder " << path () << " to " << n; } - QFile f (tl::to_qstring (path ())); begin_changes (); - if (! f.rename (QFileInfo (QDir (tl::to_qstring (mp_parent->path ())), tl::to_qstring (n)).filePath ())) { + if (! tl::rename_file (path (), n)) { on_changed (); return false; } else { @@ -621,7 +606,7 @@ lym::MacroCollection *MacroCollection::create_folder (const char *prefix, bool m ++n; } while (true); - if (mkdir && ! QDir (tl::to_qstring (path ())).mkdir (tl::to_qstring (name))) { + if (mkdir && ! tl::mkpath (tl::combine_path (path (), name))) { return 0; } @@ -673,8 +658,8 @@ void MacroCollection::add_unspecific (lym::Macro *m) bool MacroCollection::add (lym::Macro *m) { - QDir d (tl::to_qstring (path ())); - QDir dd = QFileInfo (tl::to_qstring (m->path ())).dir (); + std::string d = tl::normalize_path (path ()); + std::string dd = tl::normalize_path (m->dir ()); if (d == dd) { @@ -694,21 +679,26 @@ bool MacroCollection::add (lym::Macro *m) // try to detect new child folders. If that is the case, create that folder and add // the macro there. - QDir dm (tl::to_qstring (m->dir ())); + std::string dm = tl::normalize_path (m->dir ()); while (true) { - std::string folder_name = tl::to_string (dm.dirName ()); - if (! dm.cdUp ()) { + std::string folder_name = tl::filename (dm); + dm = tl::dirname (dm); + if (dm.empty () || dm == ".") { break; } if (dm == d) { + begin_changes (); lym::MacroCollection *mc = m_folders.insert (std::make_pair (folder_name, new MacroCollection ())).first->second; mc->set_virtual_mode (NotVirtual); + mc->set_name (folder_name); mc->set_parent (this); on_changed (); + return mc->add (m); + } } @@ -723,7 +713,7 @@ bool MacroCollection::del () if (tl::verbosity () >= 20) { tl::info << "Deleting macro folder " << path (); } - return QDir ().rmdir (tl::to_qstring (path ())); + return tl::rm_dir_recursive (path ()); } void MacroCollection::rename_macro (Macro *macro, const std::string &new_name) @@ -984,4 +974,3 @@ void MacroCollection::dump (int l) } -#endif diff --git a/src/lym/lym/lymMacroCollection.h b/src/lym/lym/lymMacroCollection.h index 9df9f3d87..aea4b2f7e 100644 --- a/src/lym/lym/lymMacroCollection.h +++ b/src/lym/lym/lymMacroCollection.h @@ -27,13 +27,13 @@ #include "lymCommon.h" #include "lymMacro.h" -#if defined(HAVE_QT) - #include #include #include -#include +#if defined(HAVE_QT) +# include +#endif namespace lym { @@ -45,9 +45,13 @@ namespace lym * a folder containing *.lym, *.rb or other script files. */ class LYM_PUBLIC MacroCollection +#if defined(HAVE_QT) : public QObject +#endif { +#if defined(HAVE_QT) Q_OBJECT +#endif public: typedef std::multimap ::iterator iterator; @@ -334,6 +338,11 @@ public: /** * @brief Gets the begin iterator of the folders + * + * The iterator will deliver a pair of a string and a MacroCollection object. + * The string is the absolute path of the child folder. Child folders do not + * necessarily live inside the directory of the parent folder. Specifically for + * the root folder, children with any kind of paths may be present. */ child_iterator begin_children () { @@ -382,6 +391,7 @@ public: * @brief Gets a folder by name * * If no folder with that name exists, this method will return 0. + * The name is either relative to the folders path or it is an absolute path. */ MacroCollection *folder_by_name (const std::string &name); @@ -389,6 +399,7 @@ public: * @brief Gets a folder by name * * If no folder with that name exists, this method will return 0. + * The name is either relative to the folders path or it is an absolute path. */ const MacroCollection *folder_by_name (const std::string &name) const; @@ -445,6 +456,7 @@ public: */ void dump (int l = 0); +#if defined(HAVE_QT) signals: /** * @brief This signal is sent when the collection changes @@ -496,6 +508,7 @@ signals: * @brief This signal is emitted from the collection root if the menu needs to be updated */ void menu_needs_update (); +#endif private: friend class Macro; @@ -518,10 +531,8 @@ private: void on_changed (); void on_menu_needs_update (); - /** - * @brief Scans a folder creating the macro collection - */ - void scan (const std::string &path); + void scan (); + void create_entry (const std::string &path); void rename_macro (Macro *macro, const std::string &new_name); @@ -551,44 +562,5 @@ private: } -#else // without QT: - -#include - -namespace lym -{ - -/** - * @brief Dummy implementation for Qt-less builds. - * - * This dummy implementation does not provide any services but acts as a dummy anchor - * for lym::Macro. - * - * Without Qt, the MacroCollection does not make much sense as there is no - * application specific file system without an Application object. - */ -class LYM_PUBLIC MacroCollection -{ -public: - MacroCollection () - { - // .. nothing yet .. - } - - std::string path () const - { - return std::string (); - } - - void rename_macro (lym::Macro *, const std::string &) - { - // .. nothing yet .. - } -}; - -} - -#endif - #endif diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index 163df8aaf..19cce3c2e 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -314,6 +314,17 @@ std::string basename (const std::string &s) } } +std::string complete_basename (const std::string &s) +{ + std::vector fnp = split_filename (filename (s)); + if (fnp.size () > 0) { + fnp.pop_back (); + return tl::join (fnp, "."); + } else { + return std::string (); + } +} + std::string extension (const std::string &s) { std::vector fnp = split_filename (filename (s)); diff --git a/src/tl/tl/tlFileUtils.h b/src/tl/tl/tlFileUtils.h index 4b628006c..da6bd50ae 100644 --- a/src/tl/tl/tlFileUtils.h +++ b/src/tl/tl/tlFileUtils.h @@ -85,6 +85,12 @@ std::string TL_PUBLIC filename (const std::string &s); */ std::string TL_PUBLIC basename (const std::string &s); +/** + * @brief Gets the basename for a given file path (file name without the last extensions) + * This will strip all extensions (i.e. "archive.tar.gz" will become "archive.tar"). + */ +std::string TL_PUBLIC complete_basename (const std::string &s); + /** * @brief Gets the complete extension for a given file path */ diff --git a/src/tl/tl/tlResources.cc b/src/tl/tl/tlResources.cc index b09febe0d..c37cb4e5d 100644 --- a/src/tl/tl/tlResources.cc +++ b/src/tl/tl/tlResources.cc @@ -21,6 +21,7 @@ */ #include "tlResources.h" +#include "tlGlobPattern.h" #include #include @@ -35,17 +36,21 @@ class ResourceDict public: struct DictEntry { + std::string name; const unsigned char *data; size_t data_size; bool compressed; }; + typedef std::vector::const_iterator iterator; + ResourceDict () { } resource_id_type add (const char *name, bool compressed, const unsigned char *data, size_t data_size) { m_dict[std::string (name)] = m_entries.size (); m_entries.push_back (DictEntry ()); + m_entries.back ().name = name; m_entries.back ().data = data; m_entries.back ().data_size = data_size; m_entries.back ().compressed = compressed; @@ -55,6 +60,7 @@ public: void remove (resource_id_type id) { if (id < m_entries.size ()) { + m_entries [id].name.clear (); m_entries [id].data = 0; m_entries [id].data_size = 0; } @@ -70,6 +76,16 @@ public: } } + iterator begin () + { + return m_entries.begin (); + } + + iterator end () + { + return m_entries.end (); + } + private: std::map m_dict; std::vector m_entries; @@ -94,15 +110,15 @@ void unregister_resource (size_t id) } } -tl::InputStream *get_resource (const char *name) +std::pair get_resource_reader (const char *name) { if (! ms_dict) { - return 0; + return std::pair (0, false); } ResourceDict::DictEntry *entry = ms_dict->entry (name); if (! entry || ! entry->data) { - return 0; + return std::pair (0, false); } if (entry->compressed) { @@ -111,16 +127,48 @@ tl::InputStream *get_resource (const char *name) // NOTE: zlib compression (used in pyqrc) adds two bytes header before the data block and // 4 bytes after (CRC32) - auto stream = new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data + 2, entry->data_size - 6)); - stream->inflate (); - return stream; + return std::make_pair (new tl::InputMemoryStream ((const char *) entry->data + 2, entry->data_size - 6), true); } else { // raw data - return new tl::InputStream (new tl::InputMemoryStream ((const char *) entry->data, entry->data_size)); + return std::make_pair (new tl::InputMemoryStream ((const char *) entry->data, entry->data_size), false); } + +} + +tl::InputStream *get_resource (const char *name) +{ + std::pair rr = get_resource_reader (name); + if (! rr.first) { + return 0; + } else { + auto stream = new tl::InputStream (rr.first); + if (rr.second) { + stream->inflate (); + } + return stream; + } +} + +std::vector +find_resources (const std::string &pattern) +{ + if (! ms_dict) { + return std::vector (); + } + + std::vector res; + tl::GlobPattern p (pattern); + + for (ResourceDict::iterator i = ms_dict->begin (); i != ms_dict->end (); ++i) { + if (i->data && p.match (i->name)) { + res.push_back (i->name); + } + } + + return res; } } diff --git a/src/tl/tl/tlResources.h b/src/tl/tl/tlResources.h index 3fbdaef0d..699e2089b 100644 --- a/src/tl/tl/tlResources.h +++ b/src/tl/tl/tlResources.h @@ -68,6 +68,24 @@ TL_PUBLIC void unregister_resource (size_t id); */ TL_PUBLIC tl::InputStream *get_resource (const char *name); +/** + * @brief Gets the resource data as a stream reader delegate plus compressed flag + * + * @param name The resource name + * @return A pair of reader delegate and a flag indicating whether the stream is compressed. + * If the resource is not found, the reade delegate is 0. + * It is the responsibility of the called to delete the reader delegate. + */ +TL_PUBLIC std::pair get_resource_reader (const char *name); + +/** + * @brief Get resource names matching a glob pattern + * + * For example, find_resources("/group/*") will find resources below "group". + * "*" also matches "/", so resources from subgroups will be listed too. + */ +TL_PUBLIC std::vector find_resources (const std::string &pattern); + } #endif diff --git a/src/tl/tl/tlStream.cc b/src/tl/tl/tlStream.cc index 6807aaf73..92077af57 100644 --- a/src/tl/tl/tlStream.cc +++ b/src/tl/tl/tlStream.cc @@ -166,6 +166,8 @@ InputStream::InputStream (const std::string &abstract_path) m_blen = 0; mp_buffer = 0; + bool needs_inflate = false; + tl::Extractor ex (abstract_path.c_str ()); if (ex.test (":")) { @@ -197,13 +199,13 @@ InputStream::InputStream (const std::string &abstract_path) #else - tl::InputStream *stream = tl::get_resource (ex.get ()); - if (! stream) { + std::pair rr = tl::get_resource_reader (ex.get ()); + if (! rr.first) { throw tl::Exception (tl::to_string (tr ("Resource not found: ")) + abstract_path); } - swap (*stream); - delete stream; + mp_delegate = rr.first; + needs_inflate = rr.second; #endif @@ -236,6 +238,10 @@ InputStream::InputStream (const std::string &abstract_path) } m_owns_delegate = true; + + if (needs_inflate) { + inflate (); + } } InputStream::~InputStream () @@ -279,19 +285,6 @@ std::string InputStream::absolute_path (const std::string &abstract_path) } } -void -InputStream::swap (InputStream &other) -{ - std::swap (m_pos, other.m_pos); - std::swap (mp_buffer, other.mp_buffer); - std::swap (m_bcap, other.m_bcap); - std::swap (m_blen, other.m_blen); - std::swap (mp_bptr, other.mp_bptr); - std::swap (mp_delegate, other.mp_delegate); - std::swap (m_owns_delegate, other.m_owns_delegate); - std::swap (mp_inflate, other.mp_inflate); -} - const char * InputStream::get (size_t n, bool bypass_inflate) { diff --git a/src/tl/tl/tlStream.h b/src/tl/tl/tlStream.h index a49704eab..0747a4b7e 100644 --- a/src/tl/tl/tlStream.h +++ b/src/tl/tl/tlStream.h @@ -540,11 +540,6 @@ public: return mp_delegate; } - /** - * @brief Swaps two streams - */ - void swap (InputStream &other); - protected: void reset_pos () { diff --git a/src/unit_tests/unit_test_main.cc b/src/unit_tests/unit_test_main.cc index 9000037d9..4bc19ed7f 100644 --- a/src/unit_tests/unit_test_main.cc +++ b/src/unit_tests/unit_test_main.cc @@ -30,6 +30,7 @@ #include "tlCommandLineParser.h" #include "tlFileUtils.h" #include "tlGlobPattern.h" +#include "lymMacroCollection.h" #include "rba.h" #include "pya.h" #include "gsiDecl.h" @@ -66,9 +67,9 @@ // (some in non-Qt case) #include "libForceLink.h" #include "rdbForceLink.h" -#if defined(HAVE_RUBY) && defined(HAVE_QT) -#include "drcForceLink.h" -#include "lvsForceLink.h" +#if defined(HAVE_RUBY) +# include "drcForceLink.h" +# include "lvsForceLink.h" #endif static int main_cont (int &argc, char **argv); @@ -530,6 +531,13 @@ main_cont (int &argc, char **argv) python_interpreter.reset (new pya::PythonInterpreter ()); python_interpreter->push_console (&console); + lym::MacroCollection &lym_root = lym::MacroCollection::root (); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-macros", "macros", true); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); + + lym_root.autorun_early (); + lym_root.autorun (); + #endif bool editable = false, non_editable = false; diff --git a/src/with_all_libs.pri b/src/with_all_libs.pri index 23ea4963e..72085c5a7 100644 --- a/src/with_all_libs.pri +++ b/src/with_all_libs.pri @@ -29,13 +29,11 @@ equals(HAVE_PYTHON, "1") { LIBS += -lklayout_pyastub } -!equals(HAVE_QT, "0") { - equals(HAVE_RUBY, "1") { - # DRC is only available with Ruby - INCLUDEPATH += $$DRC_INC $$LVS_INC - DEPENDPATH += $$DRC_INC $$LVS_INC - LIBS += -lklayout_drc -lklayout_lvs - } +equals(HAVE_RUBY, "1") { + # DRC is only available with Ruby + INCLUDEPATH += $$DRC_INC $$LVS_INC + DEPENDPATH += $$DRC_INC $$LVS_INC + LIBS += -lklayout_drc -lklayout_lvs } msvc {