/* KLayout Layout Viewer Copyright (C) 2006-2017 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_layMacro #define HDR_layMacro #include "layCommon.h" #include #include #include #include namespace lay { class MacroCollection; /** * @brief Represents a macro in the framework * * A macro is basically a piece of script code that is either * executed on startup or on request. * * A macro can be persisted to a file and is located in the * file hierarchy in one of the configuration folders. * The path of the macro is given by the path property. * * A macro can be readonly when it is located in the global * configuration folder. It cannot be saved in that case. * * The basic method of a macro is the "run" method. Basically * a macro can be bound to an arbitrary interpreter and decides * by itself which interpreter to use. */ class LAY_PUBLIC Macro : public QObject { Q_OBJECT public: /** * @brief Interpreter type */ enum Interpreter { /** * @brief Pure Ruby */ Ruby, /** * @brief Pure Python */ Python, /** * @brief Plain text (no interpreter) */ Text, /** * @brief General DSL (uses dsl_interpreter to identify the actual interpreter class) */ DSLInterpreter, /** * @brief No specific language. Interpreter won't be available. */ None }; /** * @brief Specification of how the file is stored */ enum Format { /** * @brief KLayout macro format (XML) */ MacroFormat, /** * @brief Plain text format */ PlainTextFormat, /** * @brief Plain text format with hash comments for inserting properties into the text */ PlainTextWithHashAnnotationsFormat, /** * @brief No file associated */ NoFormat }; /** * @brief Constructor * * The default constructor creates a dummy macro with no file associated */ Macro (); /** * @brief Assignment from another macro * * This will assign the definition of the macro but keep the name. * It will also not modify the parent nor the readonly flag. */ void assign (const lay::Macro &other); /** * @brief Returns the parent of the macro collection * * Returns 0, if there is no parent of this collection (this is the root) */ lay::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 lay::MacroCollection *parent () const { return mp_parent; } /** * @brief Gets the interpreter name */ std::string interpreter_name () const; /** * @brief Gets the summary text * * The summary text is shown in the tooltip of the tabs */ std::string summary () const; /** * @brief Gets the path * * The path is the file where the macro is stored. * The path is changed when the macro is saved. * If the macro was never saved, the path is empty. */ std::string path () const; /** * @brief Saves the macro to the specificed path */ void save (); /** * @brief Delete the original file (the file behind the macro) * * Returns true if the file was deleted successfully. */ bool del (); /** * @brief Loads the macro from a file */ void load (); /** * @brief Load the macro from an arbitrary file * * This method does not change the macro's path nor does it set the is_file property. * It is used for importing macros */ void load_from (const std::string &path); /** * @brief Load the macro from a string * * This method does not change the macro's path nor does it set the is_file property. * It is used for importing macros. * The url must be given in order to determine the format. */ void load_from_string (const std::string &text, const std::string &url); /** * @brief Gets the directory part of the macro's path. */ std::string dir () const; /** * @brief Gets the name of the macro * * The name is a unique string derived from the file name. * This does not include the ".lym" or ".rb" extension. */ std::string name () const { return m_name; } /** * @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. * The name must not contain the suffix. */ bool rename (const std::string &n); /** * @brief Gets the macro's description text */ const std::string &description () const { return m_description; } /** * @brief Sets the macro's description text */ void set_description (const std::string &d); /** * @brief Gets the category tags of the macro * * The category tags string is a comma-separated list of categories to which the * macro shall apply. */ const std::string &category () const { return m_category; } /** * @brief Sets the category tags of the macro */ void set_category (const std::string &c) { m_category = c; } /** * @brief Gets the macro's prolog string * The prolog is the code executed before the macro is run itself. */ const std::string &prolog () const { return m_prolog; } /** * @brief Sets the macro's prolog string */ void set_prolog (const std::string &s); /** * @brief Gets the macro's epilog string * The prolog is the code executed after the macro is run itself. */ const std::string &epilog () const { return m_epilog; } /** * @brief Sets the macro's epilog string */ void set_epilog (const std::string &s); /** * @brief Gets the macro's version string */ const std::string &version () const { return m_version; } /** * @brief Sets the macro's version string */ void set_version (const std::string &s); /** * @brief Gets the macro's documentation text */ const std::string &doc () const { return m_doc; } /** * @brief Sets the macro's documentation text */ void set_doc (const std::string &d); /** * @brief Gets the display string */ std::string display_string () const; /** * @brief Gets the macro's script text */ const std::string &text () const; /** * @brief Sets the macro's script text */ void set_text (const std::string &t); /** * @brief Returns true, if the macro needs to be saved */ bool is_modified () const { return m_modified; } /** * @brief Reset the modified state */ void reset_modified (); /** * @brief make the macro "a file" * This method is supposed to support the case of loading a file through a string. */ void set_is_file (); /** * @brief Set the macro's file path * The file path can be used when the macro is a standalone object and * there is no parent folder by which the path can be derived. */ void set_file_path (const std::string &fp); /** * @brief Installs any add-on documentation that this macro potentially provides * * If the documentation text starts with @class ..., this method installes the documentation * therein in the GSI class/method repository. */ void install_doc () const; /** * @brief Executes the macro * * On error, this method throws an exception. * * If the scripts exits with "exit", the status code will be returned by the run * method. */ int run () const; /** * @brief Returns true, if the macro can be executed */ bool can_run () const; /** * @brief Gets a value indicating whether the macro is readonly */ bool is_readonly () const { return m_readonly; } /** * @brief Sets a value indicating whether the macro is readonly */ void set_readonly (bool f); /** * @brief Gets a value indicating whether the macro shall be executed on startup */ bool is_autorun () const { return m_autorun; } /** * @brief Gets a value indicating whether the macro shall be executed early on startup (before the main window is created) */ bool is_autorun_early () const { return m_autorun_early; } /** * @brief Sets a value indicating whether the macro shall be executed on startup */ void set_autorun (bool f); /** * @brief Sets a value indicating whether the macro shall be executed early on startup */ void set_autorun_early (bool f); /** * @brief Gets a value indicating whether the macro shall be shown in the menu */ bool show_in_menu () const { return m_show_in_menu; } /** * @brief Sets a value indicating whether the macro shall be shown in the menu */ void set_show_in_menu (bool f); /** * @brief Gets the menu group name * * The menu group name identifies a group into which the item it put. * A group has a separator that groups all items with the same group name. */ const std::string &group_name () const { return m_group_name; } /** * @brief Sets the group name */ void set_group_name (const std::string &g); /** * @brief Gets the menu path * * The menu path. This path identifies the place where the macro is put in the * menu. If this path is empty but "show_in_menu" is true, the macro will be put * into the "Tools/Macros" menu. */ const std::string &menu_path () const { return m_menu_path; } /** * @brief Sets the menu path */ void set_menu_path (const std::string &mp); /** * @brief Gets the keyboard shortcut */ const std::string &shortcut () const { return m_shortcut; } /** * @brief Sets the shortcut */ void set_shortcut (const std::string &s); /** * @brief Gets the format of this macro */ Format format () const { return m_format; } /** * @brief Sets the format of this macro */ void set_format (Format f); /** * @brief Gets the suffix for a given interpreter and format */ static std::string suffix_for_format (Macro::Interpreter interpreter, const std::string &dsl_name, Macro::Format format); /** * @brief Gets the interpreter, dsl interpreter name, autorun preference and format for a given file name * * Returns false, if the suffix is not a known suffix. */ static bool format_from_suffix (const std::string &fn, Macro::Interpreter &interpreter, std::string &dsl_name, bool &autorun_pref, Macro::Format &format); /** * @brief Gets the name of the DSL interpreter for the DSL interpreter types */ const std::string &dsl_interpreter () const { return m_dsl_interpreter; } /** * @brief Set the DSL interpreter name */ void set_dsl_interpreter (const std::string &dsl_name); /** * @brief Gets the interpreter set for this macro */ Interpreter interpreter () const { return m_interpreter; } /** * @brief Set the interpreter */ void set_interpreter (Interpreter interpreter); /** * @brief Gets a value indicating whether the macro is backed up by a file * * A macro is not a file as long as it's just constructed by not saved. */ bool is_file () const { return m_is_file; } /** * @brief Synchronize the text with the properties in PlainTextWithHashAnnotationsFormat format */ void sync_text_with_properties (); /** * @brief Synchronize the properties with the text in PlainTextWithHashAnnotationsFormat format */ void sync_properties_with_text (); /** * @brief Compares two macros */ bool operator== (const Macro &other) const; /** * @brief Compares two macros */ bool operator!= (const Macro &other) const { return !(*this == other); } signals: /** * @brief This signal is sent when the macro changes */ void changed (); private: friend class MacroCollection; bool m_modified; std::string m_name; std::string m_description; std::string m_prolog; std::string m_epilog; std::string m_version; std::string m_doc; std::string m_text; std::string m_file_path; std::string m_category; bool m_readonly; bool m_autorun; bool m_autorun_default; bool m_autorun_early; bool m_show_in_menu; std::string m_group_name; std::string m_menu_path; std::string m_shortcut; bool m_is_file; lay::MacroCollection *mp_parent; Interpreter m_interpreter; std::string m_dsl_interpreter; Format m_format; void on_menu_needs_update (); void on_changed (); void save_to (const std::string &path); void set_autorun_default (bool f) { m_autorun_default = f; } void set_name (const std::string &name) { m_name = name; } void set_parent (lay::MacroCollection *parent) { mp_parent = parent; } // no copying Macro (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 LAY_PUBLIC MacroCollection : public QObject { Q_OBJECT public: typedef std::multimap ::iterator iterator; typedef std::multimap ::const_iterator const_iterator; typedef std::map ::iterator child_iterator; typedef std::map ::const_iterator const_child_iterator; /** * @brief Some constants for virtual_mode */ enum { NotVirtual = 0, ProjectFolder = 1, TechFolder = 2 }; /** * @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 */ MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly); /** * @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 ¯os, std::set ¯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) */ lay::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 lay::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 sucessfully. */ bool add (lay::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 (lay::Macro *m); /** * @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 (lay::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 (lay::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. */ lay::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 sucessful, it will return 0. */ lay::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. */ lay::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 (); /** * @brief Runs all macros marked with early auto-run */ void autorun_early (); /** * @brief Redo the scan (will add new files or folders) * * This method must be called on root. */ void rescan (); /** * @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 (MacroCollection *); /** * @brief This signal is sent by the root object when a macro collection is deleted */ void macro_collection_deleted (MacroCollection *); /** * @brief This signal is sent by collection when a macro is deleted in this collection */ void macro_deleted_here (Macro *); /** * @brief This signal is sent by the root object when a macro is deleted */ void macro_deleted (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 (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 (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 m_macros; std::map m_folders; lay::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 (lay::MacroCollection *parent) { mp_parent = parent; } void set_readonly (bool f) { m_readonly = f; } // no copying MacroCollection (const MacroCollection &d); MacroCollection &operator= (const MacroCollection &d); }; /** * @brief A signal to macro adaptor * * This class allows to call a macro from a signal */ class MacroSignalAdaptor : public QObject { Q_OBJECT public: MacroSignalAdaptor (QObject *parent, Macro *macro); public slots: void run (); private: Macro *mp_macro; }; } #endif