More range for NoQt option - covers lym (without MacroCollection), drc, lvs and buddies now

This commit is contained in:
Matthias Koefferlein 2022-04-24 23:27:33 +02:00
parent 449a12adad
commit 1b129758d8
15 changed files with 1657 additions and 1492 deletions

View File

@ -408,7 +408,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
db::Layout layout_b;
{
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file (A): ")) + infile_a);
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Loading file (A): ")) + infile_a);
db::LoadLayoutOptions load_options;
generic_reader_options_a.configure (load_options);
@ -416,7 +416,7 @@ BD_PUBLIC int strmxor (int argc, char *argv[])
}
{
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file (B): ")) + infile_b);
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (tr ("Loading file (B): ")) + infile_b);
db::LoadLayoutOptions load_options;
generic_reader_options_b.configure (load_options);

View File

@ -11,6 +11,8 @@ SUBDIRS = \
lib \
plugins \
unit_tests \
buddies \
lym \
!equals(HAVE_QT, "0") {
@ -20,8 +22,6 @@ SUBDIRS = \
laybasic \
lay \
ant \
buddies \
lym \
img \
edt \
fontgen \
@ -60,21 +60,22 @@ lib.depends += db
plugins.depends += lib rdb db
!equals(HAVE_QT, "0") {
buddies.depends += plugins lym $$LANG_DEPENDS
lym.depends += gsi $$LANG_DEPENDS
buddies.depends += plugins lym $$LANG_DEPENDS
equals(HAVE_RUBY, "1") {
SUBDIRS += drc lvs
MAIN_DEPENDS += drc lvs
drc.depends += rdb lym
lvs.depends += drc
}
!equals(HAVE_QT, "0") {
equals(HAVE_PYTHON, "1") {
pymod.depends += lay
}
equals(HAVE_RUBY, "1") {
SUBDIRS += drc lvs
MAIN_DEPENDS += drc lvs
drc.depends += rdb lym
lvs.depends += drc
}
equals(HAVE_QTBINDINGS, "1") {
SUBDIRS += gsiqt
@ -89,7 +90,6 @@ plugins.depends += lib rdb db
plugins.depends += lay ant
lym.depends += gsi $$LANG_DEPENDS
laybasic.depends += rdb lym
ant.depends += laybasic
img.depends += laybasic

View File

@ -26,7 +26,7 @@
#include "layCommon.h"
#include "layPlugin.h"
#include "lymMacro.h"
#include "lymMacroCollection.h"
#include "tlObject.h"
#include "tlDeferredExecution.h"
#include "tlFileSystemWatcher.h"

View File

@ -23,7 +23,7 @@
#include "layMacroEditorTree.h"
#include "layMacroEditorDialog.h"
#include "lymMacro.h"
#include "lymMacroCollection.h"
#include "tlExceptions.h"
#include "tlInternational.h"
#include "tlException.h"

View File

@ -171,8 +171,6 @@ public:
void update_image ();
virtual void paintEvent (QPaintEvent *);
/**
* @brief Specifies the global transformation which is always applied first
*/
@ -386,6 +384,7 @@ private:
QMutex m_mutex;
virtual void paintEvent (QPaintEvent *);
virtual void resizeEvent (QResizeEvent *);
virtual bool event (QEvent *e);
virtual void key_event (unsigned int key, unsigned int buttons);

View File

@ -2673,6 +2673,7 @@ public slots:
void min_hier_changed (int i);
void max_hier_changed (int i);
private:
// event handlers used to connect to the layout object's events
void signal_hier_changed ();
void signal_bboxes_from_layer_changed (unsigned int cv_index, unsigned int layer_index);

View File

@ -27,6 +27,7 @@
#include "gsiEnums.h"
#include "lymMacroInterpreter.h"
#include "lymMacro.h"
#include "lymMacroCollection.h"
#include "rba.h"
#include "tlClassRegistry.h"
@ -204,7 +205,7 @@ public:
lym::Macro *create_template (const std::string &url)
{
if (! mp_registration) {
throw std::runtime_error (tl::to_string (QObject::tr ("MacroInterpreter::create_template must be called after register")));
throw std::runtime_error (tl::to_string (tr ("MacroInterpreter::create_template must be called after register")));
}
lym::Macro *m = new lym::Macro ();
@ -472,7 +473,11 @@ gsi::ClassExt<MacroInterpreterImpl> inject_Format_in_parent (decl_FormatEnum.def
static lym::Macro *macro_by_path (const std::string &path)
{
#if defined(HAVE_QT)
return lym::MacroCollection::root ().find_macro (path);
#else
return 0;
#endif
}
static std::string real_path (const std::string &path, int line)

View File

@ -9,12 +9,14 @@ DEFINES += MAKE_LYM_LIBRARY
SOURCES = \
gsiDeclLymMacro.cc \
lymMacroInterpreter.cc \
lymMacroCollection.cc \
lymMacro.cc \
HEADERS = \
lymCommon.h \
lymInclude.h \
lymMacroInterpreter.h \
lymMacroCollection.h \
lymMacro.h \
INCLUDEPATH += $$TL_INC $$GSI_INC

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,9 @@
#include <map>
#include <set>
#include <QObject>
#if defined(HAVE_QT)
# include <QObject>
#endif
namespace lym
{
@ -55,11 +57,15 @@ class MacroCollection;
* a macro can be bound to an arbitrary interpreter and decides
* by itself which interpreter to use.
*/
class LYM_PUBLIC Macro
: public QObject,
class LYM_PUBLIC Macro :
#if defined(HAVE_QT)
public QObject,
#endif
public tl::Object
{
Q_OBJECT
#if defined(HAVE_QT)
Q_OBJECT
#endif
public:
/**
@ -587,12 +593,14 @@ public:
return !(*this == other);
}
#if defined(HAVE_QT)
signals:
/**
* @brief This signal is sent when the macro changes
*/
void changed ();
#endif
private:
friend class MacroCollection;
@ -646,517 +654,6 @@ private:
Macro &operator= (const Macro &d);
};
/**
* @brief Represents a collection of macros
*
* A collection is representing a set of macros, usually associated with
* a folder containing *.lym, *.rb or other script files.
*/
class LYM_PUBLIC MacroCollection
: public QObject
{
Q_OBJECT
public:
typedef std::multimap <std::string, Macro *>::iterator iterator;
typedef std::multimap <std::string, Macro *>::const_iterator const_iterator;
typedef std::map <std::string, MacroCollection *>::iterator child_iterator;
typedef std::map <std::string, MacroCollection *>::const_iterator const_child_iterator;
/**
* @brief Some constants for virtual_mode
*/
enum FolderType {
NotVirtual = 0,
ProjectFolder = 1,
TechFolder = 2,
SaltFolder = 3
};
/**
* @brief Constructor
*
* The default constructor create
*/
MacroCollection ();
/**
* @brief Destructor
*/
~MacroCollection ();
/**
* @brief Add a folder (will also scan the folder)
*
* @return A pointer to the new collection if successful
*
* If force_create is true (the default), the folder will be created if it does not
* exist yet. On error, 0 is returned.
*/
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly, bool force_create = true);
/**
* @brief Gets the category tag of the collection
*
* A category tag can be used to categorize the collections. For example, DRC categories are handled differently
* from the other categories.
*/
const std::string &category () const
{
return m_category;
}
/**
* @brief Sets the category tags
*/
void set_category (const std::string &d)
{
m_category = d;
}
/**
* @brief Collect all Macro and MacroCollection objects inside a tree starting from this collection
*/
void collect_used_nodes(std::set <Macro *> &macros, std::set <MacroCollection *> &macro_collections);
/**
* @brief Saves all macros in the collection
*
* Saves only those macros that have is_modified and whose path is set.
*/
void save ();
/**
* @brief Delete the original folder (the directory behind the macro)
*
* Returns true if the folder was deleted successfully.
* The folder cannot be deleted if it contains any files, also some that are not listed because
* they don't end with .lym, .rb or similar.
*/
bool del ();
/**
* @brief Gets the name of the collection
*
* For virtual collections this is the path.
*/
std::string name () const
{
return m_path;
}
/**
* @brief Gets the path of the folder representing that collection
*/
std::string path () const;
/**
* @brief Returns the parent of the macro collection
*
* Returns 0, if there is no parent of this collection (this is the root)
*/
lym::MacroCollection *parent ()
{
return mp_parent;
}
/**
* @brief Returns the parent of the macro collection (const version)
*
* Returns 0, if there is no parent of this collection (this is the root)
*/
const lym::MacroCollection *parent () const
{
return mp_parent;
}
/**
* @brief Returns != 0, if the macro collection is a virtual node
*
* A virtual node does not correspond to a location in the file system.
* A virtual node cannot have macros but only children.
* The return value indicates the kind of virtual use.
*/
int virtual_mode () const
{
return m_virtual_mode;
}
/**
* @brief Sets the virtual mode
*
* See virtual_mode for details about the virtual mode.
*/
void set_virtual_mode (int m)
{
m_virtual_mode = m;
}
/**
* @brief Gets a value indicating whether the macro collection is readonly
*/
bool is_readonly () const
{
return m_readonly;
}
/**
* @brief Sets a value indicating whether the macro is readonly
* In contrast to the private \set_readonly method, this version delivers a "changed" signal when
* the flag changed.
*/
void make_readonly (bool f);
/**
* @brief Gets the macro collection's description text
*/
const std::string &description () const
{
return m_description;
}
/**
* @brief Sets the description
*/
void set_description (const std::string &d)
{
m_description = d;
}
/**
* @brief Gets the display string
*/
std::string display_string () const;
/**
* @brief Rename a Macro
*
* Renames the macro. If the macro is a file, the file will be renamed as well.
* This method will return true, if the rename was successful.
*/
bool rename (const std::string &n);
/**
* @brief Adds a macro to the collection
*
* If a macro with the name of the new macro already exists, it is replaced
* (like in the file system). This method will traverse the tree to find
* the location of the macro using the path information of the macro and insert
* the macro there.
*
* The collection becomes the owner of the object passed to this method
*
* @return true, if the macro could be added successfully.
*/
bool add (lym::Macro *m);
/**
* @brief Adds a macro in an unspecific way
*
* "unspecific" means that the path is not looked up - the macro is
* added irregardless whether the path matches or not.
* This is a way to build macro collections without connection
* to some file system point.
*/
void add_unspecific (lym::Macro *m);
/**
* @brief Empties the collection
* Note: only the unspecific on_changed event is generated.
*/
void clear ();
/**
* @brief Erases the given macro from the list
*
* This does not remove the file but just remove the macro object.
* This will also delete the macro object.
*/
void erase (lym::Macro *m);
/**
* @brief Erases the entry with the given iterator
*/
void erase (iterator i);
/**
* @brief Erases the given macro collection from the list of child collections
*
* This does not remove the directory but just removes the macro collection object.
* This will also delete the macro collection object.
*/
void erase (lym::MacroCollection *m);
/**
* @brief Erases the folder with the given iterator
*/
void erase (child_iterator i);
/**
* @brief Creates a new macro in that collection (with a new name)
*
* If a name is given, it is used as a prefix to create a unique name for a macro with that format.
*/
lym::Macro *create (const char *name = 0, Macro::Format format = Macro::NoFormat);
/**
* @brief Creates a new macro collection in that collection (with a new name)
*
* If a name is given, it is used as a prefix to create a unique name.
* This method will also create the directory for this folder.
* If not successful, it will return 0.
*/
lym::MacroCollection *create_folder (const char *name = 0, bool mkdir = true);
/**
* @brief Gets the begin iterator of the macros
*/
iterator begin ()
{
return m_macros.begin ();
}
/**
* @brief Gets the end iterator of the macros
*/
iterator end ()
{
return m_macros.end ();
}
/**
* @brief Gets the begin iterator of the macros (const version)
*/
const_iterator begin () const
{
return m_macros.begin ();
}
/**
* @brief Gets the end iterator of the macros (const version)
*/
const_iterator end () const
{
return m_macros.end ();
}
/**
* @brief Gets the begin iterator of the folders
*/
child_iterator begin_children ()
{
return m_folders.begin ();
}
/**
* @brief Gets the end iterator of the folders
*/
child_iterator end_children ()
{
return m_folders.end ();
}
/**
* @brief Gets the begin iterator of the folders (const version)
*/
const_child_iterator begin_children () const
{
return m_folders.begin ();
}
/**
* @brief Gets the end iterator of the folders (const version)
*/
const_child_iterator end_children () const
{
return m_folders.end ();
}
/**
* @brief Gets a macro by name
*
* If no macro with that name exists, this method will return 0.
*/
Macro *macro_by_name (const std::string &name, Macro::Format format);
/**
* @brief Gets a macro by name
*
* If no macro with that name exists, this method will return 0.
*/
const Macro *macro_by_name (const std::string &name, Macro::Format format) const;
/**
* @brief Gets a folder by name
*
* If no folder with that name exists, this method will return 0.
*/
MacroCollection *folder_by_name (const std::string &name);
/**
* @brief Gets a folder by name
*
* If no folder with that name exists, this method will return 0.
*/
const MacroCollection *folder_by_name (const std::string &name) const;
/**
* @brief Finds a macro by path
*
* This method is called from the root collection and delivers the macro which
* matches the given path or 0.
*/
lym::Macro *find_macro (const std::string &path);
/**
* @brief Returns true, if the collection has an autorun macro
*/
bool has_autorun () const;
/**
* @brief Runs all macros marked with auto-run
*/
void autorun (std::set<std::string> *already_executed = 0);
/**
* @brief Returns true, if the collection has an early autorun macro
*/
bool has_autorun_early () const;
/**
* @brief Runs all macros marked with early auto-run
*/
void autorun_early (std::set<std::string> *already_executed = 0);
/**
* @brief Redo the scan (will add new files or folders)
*
* This method must be called on root.
*/
void rescan ();
/**
* @brief Reloads the macro collection
*
* This method is similar to rescan, but it will also remove folders and macros.
* In safe mode (safe = true), modified macros won't be overwritten.
*/
void reload (bool safe);
/**
* @brief Gets the root of the macro hierarchy corresponding to the configuration space
*/
static MacroCollection &root ();
/**
* @brief Dump the macro tree (for debugging)
*/
void dump (int l = 0);
signals:
/**
* @brief This signal is sent when the collection changes
*/
void changed ();
/**
* @brief This signal is sent by collection when a child collection is deleted in this collection
*/
void child_deleted (lym::MacroCollection *);
/**
* @brief This signal is sent by the root object when a macro collection is deleted
*/
void macro_collection_deleted (lym::MacroCollection *);
/**
* @brief This signal is sent by collection when a macro is deleted in this collection
*/
void macro_deleted_here (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro is deleted
*/
void macro_deleted (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro changes
*
* This signal is only emitted by the root, but it may originate from a
* macro inside the tree.
*/
void macro_changed (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro collection changes
*
* This signal is only emitted by the root, but it may originate from a
* macro collection inside the tree.
*/
void macro_collection_changed (lym::MacroCollection *);
/**
* @brief This signal is sent by the root object befor the macro collection changes
*/
void about_to_change ();
/**
* @brief This signal is emitted from the collection root if the menu needs to be updated
*/
void menu_needs_update ();
private:
friend class Macro;
std::string m_path;
std::string m_description;
std::string m_category;
std::multimap <std::string, Macro *> m_macros;
std::map <std::string, MacroCollection *> m_folders;
lym::MacroCollection *mp_parent;
int m_virtual_mode;
bool m_readonly;
void on_child_deleted (MacroCollection *mc);
void on_macro_collection_deleted (MacroCollection *mc);
void on_macro_deleted_here (Macro *macro);
void on_macro_deleted (Macro *macro);
void on_macro_changed (Macro *macro);
void on_macro_collection_changed (MacroCollection *mc);
void on_changed ();
void on_menu_needs_update ();
/**
* @brief Scans a folder creating the macro collection
*/
void scan (const std::string &path);
void rename_macro (Macro *macro, const std::string &new_name);
void begin_changes ();
void set_name (const std::string &n)
{
m_path = n;
}
void set_parent (lym::MacroCollection *parent)
{
mp_parent = parent;
}
void set_readonly (bool f)
{
m_readonly = f;
}
void do_clear ();
// no copying
MacroCollection (const MacroCollection &d);
MacroCollection &operator= (const MacroCollection &d);
};
}
#endif

View File

@ -0,0 +1,987 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lymMacroCollection.h"
#if defined(HAVE_QT)
#include "lymMacroInterpreter.h"
#include "tlExceptions.h"
#include "gsiDecl.h"
#include "gsiInterpreter.h"
#include "tlString.h"
#include "tlStableVector.h"
#include "tlClassRegistry.h"
#include "tlLog.h"
#include "tlXMLParser.h"
#include "tlGlobPattern.h"
#include "tlInclude.h"
#include "tlProgress.h"
#include "rba.h"
#include "pya.h"
#include <QFile>
#include <QDir>
#include <QUrl>
#include <QResource>
#include <fstream>
#include <memory>
#include <string>
#include <set>
namespace lym
{
// ----------------------------------------------------------------------
static MacroCollection ms_root;
MacroCollection::MacroCollection ()
: mp_parent (0), m_virtual_mode (ProjectFolder), m_readonly (false)
{
// .. nothing yet ..
}
MacroCollection::~MacroCollection ()
{
do_clear ();
}
void MacroCollection::do_clear ()
{
for (iterator m = begin (); m != end (); ++m) {
delete m->second;
}
m_macros.clear ();
for (child_iterator mm = begin_children (); mm != end_children (); ++mm) {
delete mm->second;
}
m_folders.clear ();
}
void MacroCollection::begin_changes ()
{
// Note: it is very important that each on_changed occurs after exactly one begin_changes.
// (See #459 for example)
if (mp_parent) {
mp_parent->begin_changes ();
} else {
emit about_to_change ();
}
}
void MacroCollection::on_menu_needs_update ()
{
emit menu_needs_update ();
}
void MacroCollection::on_changed ()
{
// Note: it is very important that each on_changed occurs after exactly one begin_changes.
// (See #459 for example)
emit changed ();
on_macro_collection_changed (this);
}
void MacroCollection::on_macro_collection_changed (MacroCollection *mc)
{
if (mp_parent) {
mp_parent->on_macro_collection_changed (mc);
} else {
emit macro_collection_changed (mc);
}
}
void MacroCollection::on_child_deleted (MacroCollection *mc)
{
emit child_deleted (mc);
on_macro_collection_deleted (mc);
}
void MacroCollection::on_macro_collection_deleted (MacroCollection *mc)
{
if (mp_parent) {
mp_parent->on_macro_collection_deleted (mc);
} else {
emit macro_collection_deleted (mc);
}
}
void MacroCollection::on_macro_deleted_here (Macro *macro)
{
emit macro_deleted_here (macro);
on_macro_deleted (macro);
}
void MacroCollection::on_macro_deleted (Macro *macro)
{
if (mp_parent) {
mp_parent->on_macro_deleted (macro);
} else {
emit macro_deleted (macro);
}
}
void MacroCollection::on_macro_changed (Macro *macro)
{
if (mp_parent) {
mp_parent->on_macro_changed (macro);
} else {
emit macro_changed (macro);
}
}
void MacroCollection::collect_used_nodes (std::set <Macro *> &macros, std::set <MacroCollection *> &macro_collections)
{
for (MacroCollection::child_iterator c = begin_children (); c != end_children (); ++c) {
macro_collections.insert (c->second);
c->second->collect_used_nodes (macros, macro_collections);
}
for (MacroCollection::iterator c = begin (); c != end (); ++c) {
macros.insert (c->second);
}
}
Macro *MacroCollection::macro_by_name (const std::string &name, Macro::Format format)
{
std::multimap <std::string, Macro *>::iterator i = m_macros.find (name);
while (i != m_macros.end () && i->first == name) {
if (format == Macro::NoFormat || i->second->format () == format) {
return i->second;
}
++i;
}
return 0;
}
const Macro *MacroCollection::macro_by_name (const std::string &name, Macro::Format format) const
{
std::multimap <std::string, Macro *>::const_iterator i = m_macros.find (name);
while (i != m_macros.end () && i->first == name) {
if (format == Macro::NoFormat || i->second->format () == format) {
return i->second;
}
++i;
}
return 0;
}
MacroCollection *MacroCollection::folder_by_name (const std::string &name)
{
std::map <std::string, MacroCollection *>::iterator i = m_folders.find (name);
if (i != m_folders.end ()) {
return i->second;
} else {
return 0;
}
}
const MacroCollection *MacroCollection::folder_by_name (const std::string &name) const
{
std::map <std::string, MacroCollection *>::const_iterator i = m_folders.find (name);
if (i != m_folders.end ()) {
return i->second;
} else {
return 0;
}
}
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 ());
} else {
return m_path;
}
}
std::string MacroCollection::display_string () const
{
if (m_virtual_mode) {
return "[" + m_description + "]";
} else {
std::string r = name ();
if (! m_description.empty ()) {
r += " - " + m_description;
}
return r;
}
}
void
MacroCollection::make_readonly (bool f)
{
if (m_readonly != f) {
begin_changes ();
m_readonly = f;
on_changed ();
}
}
MacroCollection *
MacroCollection::add_folder (const std::string &description, const std::string &path, const std::string &cat, bool readonly, bool force_create)
{
if (! path.empty () && path[0] == ':') {
readonly = true;
} else {
QFileInfo file_info (tl::to_qstring (path));
if (! file_info.exists ()) {
// 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;
}
return 0;
} else {
if (tl::verbosity () >= 20) {
tl::log << "Folder does not exist yet - trying to create it: " << path;
}
if (! QDir::root ().mkpath (file_info.absoluteFilePath ())) {
if (tl::verbosity () >= 10) {
tl::error << "Unable to create folder path: " << path;
}
return 0;
}
}
file_info.refresh ();
}
if (! file_info.isDir ()) {
if (tl::verbosity () >= 10) {
tl::error << "Folder is not a directory: " << path;
}
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) {
return 0;
}
}
if (! readonly && ! file_info.isWritable ()) {
readonly = true;
if (tl::verbosity () >= 20) {
tl::log << "Folder is read-only: " << path;
}
}
}
begin_changes ();
MacroCollection *mc = m_folders.insert (std::make_pair (path, new MacroCollection ())).first->second;
mc->set_name (path);
mc->set_description (description);
mc->set_category (cat);
mc->set_readonly (readonly);
mc->scan (path);
mc->set_parent (this);
on_changed ();
on_macro_changed (0);
return mc;
}
void MacroCollection::rescan ()
{
for (std::map <std::string, MacroCollection *>::const_iterator m = m_folders.begin (); m != m_folders.end (); ++m) {
m->second->scan (m->first);
}
}
namespace {
/**
* @brief A QResource variant that allows access to the children
*/
class ResourceWithChildren
: public QResource
{
public:
ResourceWithChildren (const QString &path) : QResource (path) { }
using QResource::children;
};
}
void MacroCollection::scan (const std::string &path)
{
if (tl::verbosity () >= 20) {
tl::info << "Scanning macro path " << path << " (readonly=" << m_readonly << ")";
}
if (! path.empty () && path[0] == ':') {
ResourceWithChildren res (tl::to_qstring (path));
QStringList children = res.children ();
children.sort ();
for (QStringList::const_iterator c = children.begin (); c != children.end (); ++c) {
std::string url = path + "/" + 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 ();
}
}
}
} else {
QDir dir (tl::to_qstring (path));
QStringList filters;
filters << QString::fromUtf8 ("*.lym");
filters << QString::fromUtf8 ("*.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");
// add the suffixes in the DSL interpreter declarations
for (tl::Registrar<lym::MacroInterpreter>::iterator cls = tl::Registrar<lym::MacroInterpreter>::begin (); cls != tl::Registrar<lym::MacroInterpreter>::end (); ++cls) {
if (! cls->suffix ().empty ()) {
filters << tl::to_qstring ("*." + cls->suffix ());
}
}
QStringList files = dir.entryList (filters, QDir::Files);
for (QStringList::ConstIterator f = files.begin (); f != files.end (); ++f) {
std::unique_ptr<lym::Macro> 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 ();
}
}
QStringList folders = dir.entryList (QDir::Dirs | QDir::NoDotAndDotDot);
for (QStringList::ConstIterator f = folders.begin (); f != folders.end (); ++f) {
try {
std::string n = tl::to_string (*f);
MacroCollection *&mc = m_folders.insert (std::make_pair (n, (MacroCollection *) 0)).first->second;
if (! mc) {
mc = new MacroCollection ();
mc->set_name (n);
mc->set_virtual_mode (NotVirtual);
bool ro = (m_readonly || ! QFileInfo (dir.filePath (*f)).isWritable ());
mc->set_readonly (ro);
mc->scan (tl::to_string (dir.filePath (*f)));
mc->set_parent (this);
}
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
}
}
}
}
void MacroCollection::clear ()
{
begin_changes ();
do_clear ();
on_changed ();
}
void MacroCollection::erase (lym::Macro *mp)
{
for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) {
if (m->second == mp) {
begin_changes ();
on_macro_deleted_here (mp);
m_macros.erase (m);
delete mp;
on_changed ();
return;
}
}
}
void MacroCollection::erase (lym::MacroCollection *mp)
{
for (child_iterator f = m_folders.begin (); f != m_folders.end (); ++f) {
if (f->second == mp) {
begin_changes ();
on_child_deleted (mp);
m_folders.erase (f);
delete mp;
on_changed ();
return;
}
}
}
void MacroCollection::erase (iterator i)
{
begin_changes ();
on_macro_deleted_here (i->second);
delete i->second;
m_macros.erase (i);
on_changed ();
}
void MacroCollection::erase (child_iterator i)
{
begin_changes ();
on_child_deleted (i->second);
delete i->second;
m_folders.erase (i);
on_changed ();
}
void MacroCollection::save ()
{
for (child_iterator f = m_folders.begin (); f != m_folders.end (); ++f) {
f->second->save ();
}
for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) {
if (m->second->is_modified () && ! m->second->is_readonly () && ! m->second->path ().empty ()) {
try {
m->second->save ();
} catch (tl::Exception &ex) {
tl::error << ex.msg ();
}
}
}
}
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 ())) {
on_changed ();
return false;
} else {
m_path = n;
on_changed ();
return true;
}
}
lym::MacroCollection *MacroCollection::create_folder (const char *prefix, bool mkdir)
{
std::string name;
int n = 0;
do {
name = (prefix ? prefix : "new_folder");
if (n > 0) {
name += "_" + tl::to_string (n);
}
if (m_folders.find (name) == m_folders.end ()) {
break;
}
++n;
} while (true);
if (mkdir && ! QDir (tl::to_qstring (path ())).mkdir (tl::to_qstring (name))) {
return 0;
}
begin_changes ();
lym::MacroCollection *m = m_folders.insert (std::make_pair (name, new lym::MacroCollection ())).first->second;
m->set_virtual_mode (NotVirtual);
m->set_name (name);
m->set_parent (this);
on_changed ();
return m;
}
lym::Macro *MacroCollection::create (const char *prefix, Macro::Format format)
{
std::string name;
int n = 0;
do {
name = (prefix ? prefix : "new_macro");
if (n > 0) {
name += "_" + tl::to_string (n);
}
if (! macro_by_name (name, format)) {
break;
}
++n;
} while (true);
begin_changes ();
lym::Macro *m = m_macros.insert (std::make_pair (name, new lym::Macro ()))->second;
m->set_name (name);
m->set_parent (this);
on_changed ();
return m;
}
void MacroCollection::add_unspecific (lym::Macro *m)
{
begin_changes ();
m_macros.insert (std::make_pair (m->name (), m));
m->set_parent (this);
on_changed ();
}
bool MacroCollection::add (lym::Macro *m)
{
QDir d (tl::to_qstring (path ()));
QDir dd = QFileInfo (tl::to_qstring (m->path ())).dir ();
if (d == dd) {
begin_changes ();
m_macros.insert (std::make_pair (m->name (), m));
m->set_parent (this);
on_changed ();
return true;
} else {
for (child_iterator c = begin_children (); c != end_children (); ++c) {
if (c->second->add (m)) {
return true;
}
}
// 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 ()));
while (true) {
std::string folder_name = tl::to_string (dm.dirName ());
if (! dm.cdUp ()) {
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_parent (this);
on_changed ();
return mc->add (m);
}
}
}
return false;
}
bool MacroCollection::del ()
{
if (tl::verbosity () >= 20) {
tl::info << "Deleting macro folder " << path ();
}
return QDir ().rmdir (tl::to_qstring (path ()));
}
void MacroCollection::rename_macro (Macro *macro, const std::string &new_name)
{
iterator m = m_macros.find (macro->name ());
while (m != m_macros.end () && m->first == macro->name ()) {
if (m->second == macro) {
m_macros.erase (m);
m_macros.insert (std::make_pair (new_name, macro));
return;
}
++m;
}
}
lym::Macro *MacroCollection::find_macro (const std::string &path)
{
for (iterator m = begin (); m != end (); ++m) {
if (m->second->path () == path) {
return m->second;
}
}
for (child_iterator mc = begin_children (); mc != end_children (); ++mc) {
lym::Macro *macro = mc->second->find_macro (path);
if (macro) {
return macro;
}
}
return 0;
}
MacroCollection &MacroCollection::root ()
{
return ms_root;
}
static bool sync_macros (lym::MacroCollection *current, lym::MacroCollection *actual, bool safe)
{
bool ret = false;
if (actual) {
current->make_readonly (actual->is_readonly ());
}
std::vector<lym::MacroCollection *> folders_to_delete;
for (lym::MacroCollection::child_iterator m = current->begin_children (); m != current->end_children (); ++m) {
lym::MacroCollection *cm = actual ? actual->folder_by_name (m->first) : 0;
if (! cm) {
folders_to_delete.push_back (m->second);
}
}
if (actual) {
for (lym::MacroCollection::child_iterator m = actual->begin_children (); m != actual->end_children (); ++m) {
lym::MacroCollection *cm = current->folder_by_name (m->first);
if (! cm) {
cm = current->create_folder (m->first.c_str (), false);
ret = true;
}
if (sync_macros(cm, m->second, safe)) {
ret = true;
}
}
}
// delete folders which do no longer exist
for (std::vector<lym::MacroCollection *>::iterator m = folders_to_delete.begin (); m != folders_to_delete.end (); ++m) {
ret = true;
sync_macros (*m, 0, safe);
current->erase (*m);
}
std::vector<lym::Macro *> macros_to_delete;
for (lym::MacroCollection::iterator m = current->begin (); m != current->end (); ++m) {
lym::Macro *cm = actual ? actual->macro_by_name (m->first, m->second->format ()) : 0;
if (! cm) {
macros_to_delete.push_back (m->second);
}
}
if (actual) {
for (lym::MacroCollection::iterator m = actual->begin (); m != actual->end (); ++m) {
lym::Macro *cm = current->macro_by_name (m->first, m->second->format ());
if (cm) {
if (*cm != *m->second && (! safe || ! cm->is_modified ())) {
cm->assign (*m->second);
}
cm->set_readonly (m->second->is_readonly ());
} else {
cm = current->create (m->first.c_str (), m->second->format ());
cm->assign (*m->second);
cm->set_readonly (m->second->is_readonly ());
ret = true;
}
}
}
// erase macros from collection which are no longer used
for (std::vector<lym::Macro *>::const_iterator m = macros_to_delete.begin (); m != macros_to_delete.end (); ++m) {
current->erase (*m);
ret = true;
}
return ret;
}
void MacroCollection::reload (bool safe)
{
// create a new collection and synchronize
lym::MacroCollection new_collection;
for (lym::MacroCollection::child_iterator c = begin_children (); c != end_children (); ++c) {
new_collection.add_folder (c->second->description (), c->second->path (), c->second->category (), c->second->is_readonly (), false /* don't force to create */);
}
// and synchronize current with the actual one
sync_macros (this, &new_collection, safe);
}
static bool has_autorun_for (const lym::MacroCollection &collection, bool early)
{
for (lym::MacroCollection::const_child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
if (has_autorun_for (*c->second, early)) {
return true;
}
}
for (lym::MacroCollection::const_iterator c = collection.begin (); c != collection.end (); ++c) {
if ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ())) {
return true;
}
}
return false;
}
bool MacroCollection::has_autorun () const
{
return has_autorun_for (*this, false);
}
bool MacroCollection::has_autorun_early () const
{
return has_autorun_for (*this, true);
}
static int collect_priority (lym::MacroCollection &collection, bool early, int from_prio)
{
int p = -1;
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
int pp = collect_priority (*c->second, early, from_prio);
if (pp >= from_prio && (p < 0 || pp < p)) {
p = pp;
}
}
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
int pp = c->second->priority ();
if (pp >= from_prio && (p < 0 || pp < p)) {
p = pp;
}
}
}
return p;
}
static void autorun_for_prio (lym::MacroCollection &collection, bool early, std::set<std::string> *executed_already, int prio)
{
for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
autorun_for_prio (*c->second, early, executed_already, prio);
}
for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
if (c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) {
if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) {
BEGIN_PROTECTED_SILENT
c->second->run ();
c->second->install_doc ();
END_PROTECTED_SILENT
if (executed_already) {
executed_already->insert (c->second->path ());
}
}
}
}
}
static void autorun_for (lym::MacroCollection &collection, bool early, std::set<std::string> *executed_already)
{
int prio = 0;
while (true) {
int p = collect_priority (collection, early, prio);
if (p < prio) {
break;
}
autorun_for_prio (collection, early, executed_already, p);
prio = p + 1;
}
}
void MacroCollection::autorun (std::set<std::string> *already_executed)
{
autorun_for (*this, false, already_executed);
}
void MacroCollection::autorun_early (std::set<std::string> *already_executed)
{
autorun_for (*this, true, already_executed);
}
void MacroCollection::dump (int l)
{
for (int i = 0; i < l; ++i) { printf (" "); }
printf ("----\n");
for (int i = 0; i < l; ++i) { printf (" "); }
printf ("Collection: %s\n", name ().c_str ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf ("Collection-path: %s\n", path ().c_str ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf ("Collection-description: %s\n", description ().c_str ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf("Collection-readonly: %d\n", is_readonly ());
printf ("\n");
for (iterator m = begin (); m != end (); ++m) {
for (int i = 0; i < l; ++i) { printf (" "); }
printf("Name: %s%s\n", m->second->name ().c_str (), m->second->is_modified() ? "*" : "");
for (int i = 0; i < l; ++i) { printf (" "); }
printf(" Path: %s\n", m->second->path ().c_str ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf(" Readonly: %d\n", m->second->is_readonly ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf(" Autorun: %d\n", m->second->is_autorun ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf(" Autorun-early: %d\n", m->second->is_autorun_early ());
for (int i = 0; i < l; ++i) { printf (" "); }
printf(" Description: %s\n", m->second->description ().c_str ());
}
for (child_iterator m = begin_children (); m != end_children (); ++m) {
m->second->dump (l + 1);
}
}
}
#endif

View File

@ -0,0 +1,594 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_lymMacroCollection
#define HDR_lymMacroCollection
#include "lymCommon.h"
#include "lymMacro.h"
#if defined(HAVE_QT)
#include <string>
#include <map>
#include <set>
#include <QObject>
namespace lym
{
/**
* @brief Represents a collection of macros
*
* A collection is representing a set of macros, usually associated with
* a folder containing *.lym, *.rb or other script files.
*/
class LYM_PUBLIC MacroCollection
: public QObject
{
Q_OBJECT
public:
typedef std::multimap <std::string, Macro *>::iterator iterator;
typedef std::multimap <std::string, Macro *>::const_iterator const_iterator;
typedef std::map <std::string, MacroCollection *>::iterator child_iterator;
typedef std::map <std::string, MacroCollection *>::const_iterator const_child_iterator;
/**
* @brief Some constants for virtual_mode
*/
enum FolderType {
NotVirtual = 0,
ProjectFolder = 1,
TechFolder = 2,
SaltFolder = 3
};
/**
* @brief Constructor
*
* The default constructor create
*/
MacroCollection ();
/**
* @brief Destructor
*/
~MacroCollection ();
/**
* @brief Add a folder (will also scan the folder)
*
* @return A pointer to the new collection if successful
*
* If force_create is true (the default), the folder will be created if it does not
* exist yet. On error, 0 is returned.
*/
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly, bool force_create = true);
/**
* @brief Gets the category tag of the collection
*
* A category tag can be used to categorize the collections. For example, DRC categories are handled differently
* from the other categories.
*/
const std::string &category () const
{
return m_category;
}
/**
* @brief Sets the category tags
*/
void set_category (const std::string &d)
{
m_category = d;
}
/**
* @brief Collect all Macro and MacroCollection objects inside a tree starting from this collection
*/
void collect_used_nodes(std::set <Macro *> &macros, std::set <MacroCollection *> &macro_collections);
/**
* @brief Saves all macros in the collection
*
* Saves only those macros that have is_modified and whose path is set.
*/
void save ();
/**
* @brief Delete the original folder (the directory behind the macro)
*
* Returns true if the folder was deleted successfully.
* The folder cannot be deleted if it contains any files, also some that are not listed because
* they don't end with .lym, .rb or similar.
*/
bool del ();
/**
* @brief Gets the name of the collection
*
* For virtual collections this is the path.
*/
std::string name () const
{
return m_path;
}
/**
* @brief Gets the path of the folder representing that collection
*/
std::string path () const;
/**
* @brief Returns the parent of the macro collection
*
* Returns 0, if there is no parent of this collection (this is the root)
*/
lym::MacroCollection *parent ()
{
return mp_parent;
}
/**
* @brief Returns the parent of the macro collection (const version)
*
* Returns 0, if there is no parent of this collection (this is the root)
*/
const lym::MacroCollection *parent () const
{
return mp_parent;
}
/**
* @brief Returns != 0, if the macro collection is a virtual node
*
* A virtual node does not correspond to a location in the file system.
* A virtual node cannot have macros but only children.
* The return value indicates the kind of virtual use.
*/
int virtual_mode () const
{
return m_virtual_mode;
}
/**
* @brief Sets the virtual mode
*
* See virtual_mode for details about the virtual mode.
*/
void set_virtual_mode (int m)
{
m_virtual_mode = m;
}
/**
* @brief Gets a value indicating whether the macro collection is readonly
*/
bool is_readonly () const
{
return m_readonly;
}
/**
* @brief Sets a value indicating whether the macro is readonly
* In contrast to the private \set_readonly method, this version delivers a "changed" signal when
* the flag changed.
*/
void make_readonly (bool f);
/**
* @brief Gets the macro collection's description text
*/
const std::string &description () const
{
return m_description;
}
/**
* @brief Sets the description
*/
void set_description (const std::string &d)
{
m_description = d;
}
/**
* @brief Gets the display string
*/
std::string display_string () const;
/**
* @brief Rename a Macro
*
* Renames the macro. If the macro is a file, the file will be renamed as well.
* This method will return true, if the rename was successful.
*/
bool rename (const std::string &n);
/**
* @brief Adds a macro to the collection
*
* If a macro with the name of the new macro already exists, it is replaced
* (like in the file system). This method will traverse the tree to find
* the location of the macro using the path information of the macro and insert
* the macro there.
*
* The collection becomes the owner of the object passed to this method
*
* @return true, if the macro could be added successfully.
*/
bool add (lym::Macro *m);
/**
* @brief Adds a macro in an unspecific way
*
* "unspecific" means that the path is not looked up - the macro is
* added irregardless whether the path matches or not.
* This is a way to build macro collections without connection
* to some file system point.
*/
void add_unspecific (lym::Macro *m);
/**
* @brief Empties the collection
* Note: only the unspecific on_changed event is generated.
*/
void clear ();
/**
* @brief Erases the given macro from the list
*
* This does not remove the file but just remove the macro object.
* This will also delete the macro object.
*/
void erase (lym::Macro *m);
/**
* @brief Erases the entry with the given iterator
*/
void erase (iterator i);
/**
* @brief Erases the given macro collection from the list of child collections
*
* This does not remove the directory but just removes the macro collection object.
* This will also delete the macro collection object.
*/
void erase (lym::MacroCollection *m);
/**
* @brief Erases the folder with the given iterator
*/
void erase (child_iterator i);
/**
* @brief Creates a new macro in that collection (with a new name)
*
* If a name is given, it is used as a prefix to create a unique name for a macro with that format.
*/
lym::Macro *create (const char *name = 0, Macro::Format format = Macro::NoFormat);
/**
* @brief Creates a new macro collection in that collection (with a new name)
*
* If a name is given, it is used as a prefix to create a unique name.
* This method will also create the directory for this folder.
* If not successful, it will return 0.
*/
lym::MacroCollection *create_folder (const char *name = 0, bool mkdir = true);
/**
* @brief Gets the begin iterator of the macros
*/
iterator begin ()
{
return m_macros.begin ();
}
/**
* @brief Gets the end iterator of the macros
*/
iterator end ()
{
return m_macros.end ();
}
/**
* @brief Gets the begin iterator of the macros (const version)
*/
const_iterator begin () const
{
return m_macros.begin ();
}
/**
* @brief Gets the end iterator of the macros (const version)
*/
const_iterator end () const
{
return m_macros.end ();
}
/**
* @brief Gets the begin iterator of the folders
*/
child_iterator begin_children ()
{
return m_folders.begin ();
}
/**
* @brief Gets the end iterator of the folders
*/
child_iterator end_children ()
{
return m_folders.end ();
}
/**
* @brief Gets the begin iterator of the folders (const version)
*/
const_child_iterator begin_children () const
{
return m_folders.begin ();
}
/**
* @brief Gets the end iterator of the folders (const version)
*/
const_child_iterator end_children () const
{
return m_folders.end ();
}
/**
* @brief Gets a macro by name
*
* If no macro with that name exists, this method will return 0.
*/
Macro *macro_by_name (const std::string &name, Macro::Format format);
/**
* @brief Gets a macro by name
*
* If no macro with that name exists, this method will return 0.
*/
const Macro *macro_by_name (const std::string &name, Macro::Format format) const;
/**
* @brief Gets a folder by name
*
* If no folder with that name exists, this method will return 0.
*/
MacroCollection *folder_by_name (const std::string &name);
/**
* @brief Gets a folder by name
*
* If no folder with that name exists, this method will return 0.
*/
const MacroCollection *folder_by_name (const std::string &name) const;
/**
* @brief Finds a macro by path
*
* This method is called from the root collection and delivers the macro which
* matches the given path or 0.
*/
lym::Macro *find_macro (const std::string &path);
/**
* @brief Returns true, if the collection has an autorun macro
*/
bool has_autorun () const;
/**
* @brief Runs all macros marked with auto-run
*/
void autorun (std::set<std::string> *already_executed = 0);
/**
* @brief Returns true, if the collection has an early autorun macro
*/
bool has_autorun_early () const;
/**
* @brief Runs all macros marked with early auto-run
*/
void autorun_early (std::set<std::string> *already_executed = 0);
/**
* @brief Redo the scan (will add new files or folders)
*
* This method must be called on root.
*/
void rescan ();
/**
* @brief Reloads the macro collection
*
* This method is similar to rescan, but it will also remove folders and macros.
* In safe mode (safe = true), modified macros won't be overwritten.
*/
void reload (bool safe);
/**
* @brief Gets the root of the macro hierarchy corresponding to the configuration space
*/
static MacroCollection &root ();
/**
* @brief Dump the macro tree (for debugging)
*/
void dump (int l = 0);
signals:
/**
* @brief This signal is sent when the collection changes
*/
void changed ();
/**
* @brief This signal is sent by collection when a child collection is deleted in this collection
*/
void child_deleted (lym::MacroCollection *);
/**
* @brief This signal is sent by the root object when a macro collection is deleted
*/
void macro_collection_deleted (lym::MacroCollection *);
/**
* @brief This signal is sent by collection when a macro is deleted in this collection
*/
void macro_deleted_here (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro is deleted
*/
void macro_deleted (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro changes
*
* This signal is only emitted by the root, but it may originate from a
* macro inside the tree.
*/
void macro_changed (lym::Macro *);
/**
* @brief This signal is sent by the root object when a macro collection changes
*
* This signal is only emitted by the root, but it may originate from a
* macro collection inside the tree.
*/
void macro_collection_changed (lym::MacroCollection *);
/**
* @brief This signal is sent by the root object befor the macro collection changes
*/
void about_to_change ();
/**
* @brief This signal is emitted from the collection root if the menu needs to be updated
*/
void menu_needs_update ();
private:
friend class Macro;
std::string m_path;
std::string m_description;
std::string m_category;
std::multimap <std::string, Macro *> m_macros;
std::map <std::string, MacroCollection *> m_folders;
lym::MacroCollection *mp_parent;
int m_virtual_mode;
bool m_readonly;
void on_child_deleted (MacroCollection *mc);
void on_macro_collection_deleted (MacroCollection *mc);
void on_macro_deleted_here (Macro *macro);
void on_macro_deleted (Macro *macro);
void on_macro_changed (Macro *macro);
void on_macro_collection_changed (MacroCollection *mc);
void on_changed ();
void on_menu_needs_update ();
/**
* @brief Scans a folder creating the macro collection
*/
void scan (const std::string &path);
void rename_macro (Macro *macro, const std::string &new_name);
void begin_changes ();
void set_name (const std::string &n)
{
m_path = n;
}
void set_parent (lym::MacroCollection *parent)
{
mp_parent = parent;
}
void set_readonly (bool f)
{
m_readonly = f;
}
void do_clear ();
// no copying
MacroCollection (const MacroCollection &d);
MacroCollection &operator= (const MacroCollection &d);
};
}
#else // without QT:
#include <string>
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

View File

@ -29,13 +29,15 @@
#include "tlClassRegistry.h"
#include "tlInclude.h"
#include <cstring>
namespace lym
{
tl::Executable *
MacroInterpreter::executable (const lym::Macro *) const
{
throw tl::Exception (tl::to_string (QObject::tr ("executable() implementation missing for DSL interpreter")));
throw tl::Exception (tl::to_string (tr ("executable() implementation missing for DSL interpreter")));
}
bool
@ -131,7 +133,7 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
}
}
throw tl::Exception (tl::to_string (QObject::tr ("No interpreter registered for DSL type '")) + macro->dsl_interpreter () + "'");
throw tl::Exception (tl::to_string (tr ("No interpreter registered for DSL type '")) + macro->dsl_interpreter () + "'");
}
std::string

View File

@ -1,12 +1,16 @@
TEMPLATE = subdirs
contains(QT_CONFIG, opengl) {
!equals(HAVE_QT, "0") {
contains(QT_CONFIG, opengl) {
greaterThan(QT_MAJOR_VERSION, 4) {
SUBDIRS = lay_plugin unit_tests
}
unit_tests.depends += lay_plugin
greaterThan(QT_MAJOR_VERSION, 4) {
SUBDIRS = lay_plugin unit_tests
}
unit_tests.depends += lay_plugin
}

View File

@ -20,6 +20,7 @@
*/
#if defined(HAVE_QT)
#include "tlFileSystemWatcher.h"
#include "tlString.h"
@ -218,3 +219,4 @@ TEST(3)
EXPECT_EQ (changed_spy.count (), 0);
}
#endif