mirror of https://github.com/KLayout/klayout.git
More range for NoQt option - covers lym (without MacroCollection), drc, lvs and buddies now
This commit is contained in:
parent
449a12adad
commit
1b129758d8
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 *> ¯os, std::set <MacroCollection *> ¯o_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
|
||||
|
|
|
|||
|
|
@ -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 *> ¯os, std::set <MacroCollection *> ¯o_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
|
||||
|
|
@ -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 *> ¯os, std::set <MacroCollection *> ¯o_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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue