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;
|
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;
|
db::LoadLayoutOptions load_options;
|
||||||
generic_reader_options_a.configure (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;
|
db::LoadLayoutOptions load_options;
|
||||||
generic_reader_options_b.configure (load_options);
|
generic_reader_options_b.configure (load_options);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ SUBDIRS = \
|
||||||
lib \
|
lib \
|
||||||
plugins \
|
plugins \
|
||||||
unit_tests \
|
unit_tests \
|
||||||
|
buddies \
|
||||||
|
lym \
|
||||||
|
|
||||||
!equals(HAVE_QT, "0") {
|
!equals(HAVE_QT, "0") {
|
||||||
|
|
||||||
|
|
@ -20,8 +22,6 @@ SUBDIRS = \
|
||||||
laybasic \
|
laybasic \
|
||||||
lay \
|
lay \
|
||||||
ant \
|
ant \
|
||||||
buddies \
|
|
||||||
lym \
|
|
||||||
img \
|
img \
|
||||||
edt \
|
edt \
|
||||||
fontgen \
|
fontgen \
|
||||||
|
|
@ -60,21 +60,22 @@ lib.depends += db
|
||||||
|
|
||||||
plugins.depends += lib rdb 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") {
|
equals(HAVE_PYTHON, "1") {
|
||||||
pymod.depends += lay
|
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") {
|
equals(HAVE_QTBINDINGS, "1") {
|
||||||
|
|
||||||
SUBDIRS += gsiqt
|
SUBDIRS += gsiqt
|
||||||
|
|
@ -89,7 +90,6 @@ plugins.depends += lib rdb db
|
||||||
|
|
||||||
plugins.depends += lay ant
|
plugins.depends += lay ant
|
||||||
|
|
||||||
lym.depends += gsi $$LANG_DEPENDS
|
|
||||||
laybasic.depends += rdb lym
|
laybasic.depends += rdb lym
|
||||||
ant.depends += laybasic
|
ant.depends += laybasic
|
||||||
img.depends += laybasic
|
img.depends += laybasic
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
#include "layCommon.h"
|
#include "layCommon.h"
|
||||||
#include "layPlugin.h"
|
#include "layPlugin.h"
|
||||||
#include "lymMacro.h"
|
#include "lymMacroCollection.h"
|
||||||
#include "tlObject.h"
|
#include "tlObject.h"
|
||||||
#include "tlDeferredExecution.h"
|
#include "tlDeferredExecution.h"
|
||||||
#include "tlFileSystemWatcher.h"
|
#include "tlFileSystemWatcher.h"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#include "layMacroEditorTree.h"
|
#include "layMacroEditorTree.h"
|
||||||
#include "layMacroEditorDialog.h"
|
#include "layMacroEditorDialog.h"
|
||||||
#include "lymMacro.h"
|
#include "lymMacroCollection.h"
|
||||||
#include "tlExceptions.h"
|
#include "tlExceptions.h"
|
||||||
#include "tlInternational.h"
|
#include "tlInternational.h"
|
||||||
#include "tlException.h"
|
#include "tlException.h"
|
||||||
|
|
|
||||||
|
|
@ -171,8 +171,6 @@ public:
|
||||||
|
|
||||||
void update_image ();
|
void update_image ();
|
||||||
|
|
||||||
virtual void paintEvent (QPaintEvent *);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Specifies the global transformation which is always applied first
|
* @brief Specifies the global transformation which is always applied first
|
||||||
*/
|
*/
|
||||||
|
|
@ -386,6 +384,7 @@ private:
|
||||||
|
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
|
|
||||||
|
virtual void paintEvent (QPaintEvent *);
|
||||||
virtual void resizeEvent (QResizeEvent *);
|
virtual void resizeEvent (QResizeEvent *);
|
||||||
virtual bool event (QEvent *e);
|
virtual bool event (QEvent *e);
|
||||||
virtual void key_event (unsigned int key, unsigned int buttons);
|
virtual void key_event (unsigned int key, unsigned int buttons);
|
||||||
|
|
|
||||||
|
|
@ -2673,6 +2673,7 @@ public slots:
|
||||||
void min_hier_changed (int i);
|
void min_hier_changed (int i);
|
||||||
void max_hier_changed (int i);
|
void max_hier_changed (int i);
|
||||||
|
|
||||||
|
private:
|
||||||
// event handlers used to connect to the layout object's events
|
// event handlers used to connect to the layout object's events
|
||||||
void signal_hier_changed ();
|
void signal_hier_changed ();
|
||||||
void signal_bboxes_from_layer_changed (unsigned int cv_index, unsigned int layer_index);
|
void signal_bboxes_from_layer_changed (unsigned int cv_index, unsigned int layer_index);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "gsiEnums.h"
|
#include "gsiEnums.h"
|
||||||
#include "lymMacroInterpreter.h"
|
#include "lymMacroInterpreter.h"
|
||||||
#include "lymMacro.h"
|
#include "lymMacro.h"
|
||||||
|
#include "lymMacroCollection.h"
|
||||||
#include "rba.h"
|
#include "rba.h"
|
||||||
|
|
||||||
#include "tlClassRegistry.h"
|
#include "tlClassRegistry.h"
|
||||||
|
|
@ -204,7 +205,7 @@ public:
|
||||||
lym::Macro *create_template (const std::string &url)
|
lym::Macro *create_template (const std::string &url)
|
||||||
{
|
{
|
||||||
if (! mp_registration) {
|
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 ();
|
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)
|
static lym::Macro *macro_by_path (const std::string &path)
|
||||||
{
|
{
|
||||||
|
#if defined(HAVE_QT)
|
||||||
return lym::MacroCollection::root ().find_macro (path);
|
return lym::MacroCollection::root ().find_macro (path);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string real_path (const std::string &path, int line)
|
static std::string real_path (const std::string &path, int line)
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,14 @@ DEFINES += MAKE_LYM_LIBRARY
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
gsiDeclLymMacro.cc \
|
gsiDeclLymMacro.cc \
|
||||||
lymMacroInterpreter.cc \
|
lymMacroInterpreter.cc \
|
||||||
|
lymMacroCollection.cc \
|
||||||
lymMacro.cc \
|
lymMacro.cc \
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
lymCommon.h \
|
lymCommon.h \
|
||||||
lymInclude.h \
|
lymInclude.h \
|
||||||
lymMacroInterpreter.h \
|
lymMacroInterpreter.h \
|
||||||
|
lymMacroCollection.h \
|
||||||
lymMacro.h \
|
lymMacro.h \
|
||||||
|
|
||||||
INCLUDEPATH += $$TL_INC $$GSI_INC
|
INCLUDEPATH += $$TL_INC $$GSI_INC
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -31,7 +31,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include <QObject>
|
#if defined(HAVE_QT)
|
||||||
|
# include <QObject>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace lym
|
namespace lym
|
||||||
{
|
{
|
||||||
|
|
@ -55,11 +57,15 @@ class MacroCollection;
|
||||||
* a macro can be bound to an arbitrary interpreter and decides
|
* a macro can be bound to an arbitrary interpreter and decides
|
||||||
* by itself which interpreter to use.
|
* by itself which interpreter to use.
|
||||||
*/
|
*/
|
||||||
class LYM_PUBLIC Macro
|
class LYM_PUBLIC Macro :
|
||||||
: public QObject,
|
#if defined(HAVE_QT)
|
||||||
|
public QObject,
|
||||||
|
#endif
|
||||||
public tl::Object
|
public tl::Object
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
#if defined(HAVE_QT)
|
||||||
|
Q_OBJECT
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -587,12 +593,14 @@ public:
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_QT)
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* @brief This signal is sent when the macro changes
|
* @brief This signal is sent when the macro changes
|
||||||
*/
|
*/
|
||||||
void changed ();
|
void changed ();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MacroCollection;
|
friend class MacroCollection;
|
||||||
|
|
||||||
|
|
@ -646,517 +654,6 @@ private:
|
||||||
Macro &operator= (const Macro &d);
|
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
|
#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 "tlClassRegistry.h"
|
||||||
#include "tlInclude.h"
|
#include "tlInclude.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace lym
|
namespace lym
|
||||||
{
|
{
|
||||||
|
|
||||||
tl::Executable *
|
tl::Executable *
|
||||||
MacroInterpreter::executable (const lym::Macro *) const
|
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
|
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
|
std::string
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
|
|
||||||
TEMPLATE = subdirs
|
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 "tlFileSystemWatcher.h"
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
|
|
@ -218,3 +219,4 @@ TEST(3)
|
||||||
EXPECT_EQ (changed_spy.count (), 0);
|
EXPECT_EQ (changed_spy.count (), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue