klayout/src/laybasic/layPlugin.h

848 lines
23 KiB
C
Raw Normal View History

/*
KLayout Layout Viewer
Copyright (C) 2006-2016 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_layPlugin
#define HDR_layPlugin
#include "laybasicCommon.h"
#include <QFrame>
#include "tlString.h"
#include "tlClassRegistry.h"
#include "tlDeferredExecution.h"
#include "gsiObject.h"
#include "layAbstractMenu.h"
#include <map>
#include <vector>
#include <string>
namespace db
{
class Manager;
}
namespace lay
{
class Plugin;
class PluginRoot;
class LayoutView;
class Browser;
class ViewService;
class Editable;
class Drawing;
class TechnologyComponentProvider;
/**
* @brief The base class for configuration pages
*
* This interface defines some services the configuration page
* must provide (i.e. setup, commit)
*/
class LAYBASIC_PUBLIC ConfigPage
: public QFrame
{
public:
ConfigPage (QWidget *parent)
: QFrame (parent)
{
// .. nothing else ..
}
/**
* @brief Load the page
*
* The implementation is supposed to fetch the configuration from the
* Plugin object provided and load the widgets accordingly.
*/
virtual void setup (PluginRoot * /*root*/)
{
// the default implementation does nothing.
}
/**
* @brief Commit the page
*
* The implementation is supposed to read the configuration (and
* throw exceptions if the configuration something is invalid)
* and commit the changes through
*/
virtual void commit (PluginRoot * /*root*/)
{
// the default implementation does nothing.
}
};
/**
* @brief A menu entry declaration
*/
struct LAYBASIC_PUBLIC MenuEntry
{
/**
* @brief A declaration for a separator
*
* @param menu_name The name of the menu item (see layAbstractMenu.h)
* @param insert_pos The position where to insert (see layAbstractMenu.h)
*/
MenuEntry (const std::string &menu_name_, const std::string &insert_pos_)
: menu_name (menu_name_), insert_pos (insert_pos_), sub_menu (false)
{
// ..
}
/**
* @brief A declaration for a menu entry
*
* @param symbol The symbol to send when this menu item is selected
* @param menu_name The name of the menu item (see layAbstractMenu.h)
* @param insert_pos The position where to insert (see layAbstractMenu.h)
* @param title The title to display plus optional icon resource and keyboard shortcut. The format of the string is: <text>["("shortcut")"]["<"icon-resource">"][{"tool-tip"}].
*/
MenuEntry (const std::string &symbol_, const std::string &menu_name_, const std::string &insert_pos_, const std::string &title_, bool sub_menu_ = false)
: menu_name (menu_name_), symbol (symbol_), insert_pos (insert_pos_), title (title_), sub_menu (sub_menu_)
{
// ..
}
std::string menu_name;
std::string symbol;
std::string insert_pos;
std::string title;
bool sub_menu;
};
/**
* @brief The configuration declaration
*
* For each configurable class a declaration object derived from
* this class must be provided through the tl::Registrar registration
* mechanism (instantiate a tl::Registrar<tl::Plugin>::Class<Y>
* object).
*/
class LAYBASIC_PUBLIC PluginDeclaration
: public QObject,
public gsi::ObjectBase
{
Q_OBJECT
public:
/**
* @brief Constructor
*/
PluginDeclaration ();
/**
* @brief Destructor
*/
virtual ~PluginDeclaration ();
/**
* @brief This method is supposed to deliver the option names available
*
* @param options A vector of names and default value strings.
*/
virtual void get_options (std::vector < std::pair<std::string, std::string> > & /*options*/) const
{
// the default implementation does not add any options
}
/**
* @brief Fetch the configuration page for the configuration dialog
*
* @param title The title to display in the corresponding tab of
* the configuration dialog.
* @return The configuration page or 0 if there is no page.
*/
virtual ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
{
return 0;
}
/**
* @brief Fetch the configuration pages for the configuration dialog
*
* @return A list of titles and ConfigPage instances
*
* This method can be reimplemented alternatively to "config_page" when multiple pages shall be
* used. The pages are inserted in the order they are defined.
*/
virtual std::vector<std::pair <std::string, ConfigPage *> > config_pages (QWidget * /*parent*/) const
{
return std::vector<std::pair <std::string, ConfigPage *> > ();
}
/**
* @brief The global configuration
*
* By implementing this method, a configuration can be treated globally.
* Otherwise the individual plugin object (associated with a view) must handle
* the configuration. One example for handling the configuration globally is
* dynamic menu configuration.
*/
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
/**
* @brief Global menu handler
*
* This menu handler is called before the view specific handler is
* called (lay::Plugin::menu_activated).
* The implementation is supposed to return true if it handles the menu entry.
*/
virtual bool menu_activated (const std::string & /*symbol*/) const
{
// The default implementation does nothing.
return false;
}
/**
* @brief Configuration finalization
*
* This method is called after all configuration changes have been applied.
* A derived class might implement this method in order to do some post-
* processing of the configuration.
*/
virtual void config_finalize ()
{
// .. the default implementation does nothing ..
}
/**
* @brief Basic initialization
*
* Reimplementation of this method offers a chance to initialize static resources such as
* dialogs etc.
*/
virtual void initialize (lay::PluginRoot * /*root*/)
{
// .. the default implementation does nothing ..
}
/**
* @brief Basic initialization
*
* Reimplementation of this method offers a chance to initialize static resources such as
* dialogs etc.
* While initialize is called before any configuration is loaded, "initialized" will be
* called after the pugin system has been initially configured.
*/
virtual void initialized (lay::PluginRoot * /*root*/)
{
// .. the default implementation does nothing ..
}
/**
* @brief Uninitialize the plugin
*/
virtual void uninitialize (lay::PluginRoot * /*root*/)
{
// .. the default implementation does nothing ..
}
/**
* @brief Fetch the menu objects for this plugin
*
* The implementation of this method is supposed to call the base
* class'es "get_menu_entries" method and add it's own entries.
*/
virtual void get_menu_entries (std::vector<lay::MenuEntry> & /*menu_entries*/) const
{
// .. nothing yet ..
}
/**
* @brief Create a plugin object of the respective kind
*
* This method may return 0 for "dummy" plugins that just register menu entries
* or configuration options.
*/
virtual lay::Plugin *create_plugin (db::Manager * /*manager*/, lay::PluginRoot * /*plugin_root*/, lay::LayoutView * /*view*/) const
{
return 0;
}
/**
* @brief Tell if the plugin implements the "lay::Editable" interface
*
* This method is supposed to return true if the plugin implements the
* lay::Editable interface and wants to be listed as an "edit" mode in the
* "Edit" menu. The string returned in "title" is displayed in the "Edit" menu's
* corresponding mode entry.
*/
virtual bool implements_editable (std::string & /*title*/) const
{
return false;
}
/**
* @brief Tell if the plugin implements a "lay::ViewService" active mouse mode
*
* This method is supposed to return true if the plugin implements the
* lay::ViewService interface and wants to be listed as an mouse mode in the
* "Edit" menu. The string returned in "title" is displayed in the "Edit" menu's
* corresponding mode entry.
*/
virtual bool implements_mouse_mode (std::string & /*title*/) const
{
return false;
}
/**
* @brief Returns the technology component provider
*
* If this plugin wants to register a technology component, it's declaration must
* include a technology component provider. This is responsible for creating
* a technology component and an associated editor.
*
* @return The provide object (no ownership is taken) or 0 if no technology component is created.
*/
virtual const TechnologyComponentProvider *technology_component_provider () const
{
return 0;
}
/**
* @brief Delivers a unique ID
*
* This ID can be used to connect plugins to menus for example.
* Currently the ID is just the address of the declaration object.
* The ID is guaranteed to be larger than 0, so negative ID's can be
* used for different purposed.
*/
int id () const
{
return m_id;
}
/**
* @brief Creates the menu resources for this plugin
*
* This method will create the menu resources for the plugin and perform the
* required connect operations.
*/
void init_menu ();
/**
* @brief Removes the menu resources associated with this plugin
*/
void remove_menu_items ();
/**
* @brief Enables this editable part of the plugin
*
* If the editable part of this plugin is enabled, the objects managed by this mode can be manipulated.
* Otherwise, the are not considered for selection.
* This property can be monitored with the editable_enabled observer.
*/
void set_editable_enabled (bool f);
/**
* @brief Gets a value indicating whether the editable part of the plugin is enabled
*/
bool editable_enabled () const
{
return m_editable_enabled;
}
/**
* @brief Notifies that plugin root that a new plugin was registered
*
* This method must be called when a plugin is dynamically created. It is important
* that when this method is called, the menu items and other properties are set already.
*/
void register_plugin ();
/**
* @brief An event indicating that the editable state has changed
*/
tl::Event editable_enabled_changed_event;
private slots:
void toggle_editable_enabled ();
void generic_menu ();
void mode_triggered ();
private:
int m_id;
std::vector <lay::Action> m_menu_actions;
lay::Action m_editable_mode_action;
lay::Action m_mouse_mode_action;
bool m_editable_enabled;
};
/**
* @brief The plugin interface
*
* Each configurable object must be derived from this interface.
* An configurable object can have a parent. This way, a hierarchy
* of configurable objects is created. The root object not having a
* parent acts as the main entry point: it will try to dispatch
* configuration requests to the children.
* A node may have a local configuration - it will override any
* parent configurations.
*/
class LAYBASIC_PUBLIC Plugin
: public gsi::ObjectBase,
virtual public tl::Object
{
public:
typedef std::map <std::string, std::string>::const_iterator iterator;
/**
* @brief The constructor
*
* See above for a explanation of the parent-child relationship.
*/
Plugin (Plugin *parent, bool standalone = false);
/**
* @brief The destructor
*/
virtual ~Plugin ();
/**
* @brief Gets a value indicating whether this plugin is a standlone plugin
*
* Standalone-Plugins don't receive common events such as menu requests or
* mode changes.
*/
bool is_standalone () const
{
return m_standalone;
}
/**
* @brief Setup
*
* Calling this method will make the root configurable object dump
* it's current configuration to this object. The setup method can
* be called in the derived object's constructor for example.
*/
void config_setup ();
/**
* @brief Clear (reset to default) the configuration
*
* If called on a child, local configurations are cleared.
* If called on the root, the default configuration is restored.
*/
void clear_config ();
/**
* @brief Set a certain configuration parameter
*
* This method will promote the configuration to the first child
* that accepts it and store the value in the repository for the
* root element.
*/
void config_set (const std::string &name, const std::string &value);
/**
* @brief Set a certain configuration parameter
*
* This method will promote the configuration to the first child
* that accepts it and store the value in the repository for the
* root element.
*/
void config_set (const std::string &name, const char *value);
/**
* @brief Set a certain configuration parameter with a given type
*
* This method will promote the configuration to the first child
* that accepts it and store the value in the repository for the
* root element. It will use tl::to_string to convert the type into
* a string.
*/
template <class T>
void config_set (const std::string &name, const T &value)
{
config_set (name, tl::to_string (value));
}
/**
* @brief Set a certain configuration parameter with a given type using a custom string converter
*
* This method will promote the configuration to the first child
* that accepts it and store the value in the repository for the
* root element. It will use conv.to_string to convert the type into
* a string.
*/
template <class T, class C>
void config_set (const std::string &name, const T &value, C conv)
{
config_set (name, conv.to_string (value));
}
/**
* @brief Terminat a sequence of configuration setups
*
* In order to make configuration changes effective, this method
* must be called. It calls config_finalize recursively on the
* children.
*/
void config_end ();
/**
* @brief Get a certain configuration parameter
*
* This method will fetch the parameter from the repository.
* It can only be called on the root element.
* If no parameter with the given name is known, this method will
* return false and set "value" to empty.
*/
bool config_get (const std::string &name, std::string &value) const;
/**
* @brief Get a certain configuration parameter
*
* This is a convenience method which behaves similar. It will return the
* configuration value for the given configuration option name. However, if the
* configuration option with the given name does not exist, simply an
* empty string is returned.
*/
std::string config_get (const std::string &name) const
{
std::string v;
config_get (name, v);
return v;
}
/**
* @brief Get a certain configuration parameter
*
* This method will fetch the parameter from the repository
* and try to convert it into the value requested. To convert
* it, tl::from_string is used. If an exception is thrown during
* the conversion or the value is not present, false is returned.
*/
template <class T>
bool config_get (const std::string &name, T &value) const
{
T t;
std::string s;
if (! config_get (name, s)) {
return false;
}
try {
tl::from_string (s, t);
value = t;
return true;
} catch (...) {
return false;
}
}
/**
* @brief Get a certain configuration parameter using a custom converter
*
* This method will fetch the parameter from the repository
* and try to convert it into the value requested. To convert
* it, conv.from_string is used. If an exception is thrown during
* the conversion or the value is not present, false is returned.
*/
template <class T, class C>
bool config_get (const std::string &name, T &value, C conv) const
{
T t;
std::string s;
if (! config_get (name, s)) {
return false;
}
try {
conv.from_string (s, t);
value = t;
return true;
} catch (...) {
return false;
}
}
/**
* @brief Iterator for the key/value pairs: begin iterator
*/
iterator begin () const
{
return m_repository.begin ();
}
/**
* @brief Iterator for the key/value pairs: end iterator
*/
iterator end () const
{
return m_repository.end ();
}
/**
* @brief Get the names of all configuration options available
*/
void get_config_names (std::vector<std::string> &names) const;
/**
* @brief Menu command handler
*
* This method is called if a menu entry registered in the
* plugin declaration is activated. The string passed is the
* symbol of the menu entry.
*/
virtual void menu_activated (const std::string & /*symbol*/)
{
// .. this implementation does nothing ..
}
/**
* @brief Return the lay::Browser interface if this object has one
*
* If the object implements the lay::Browser interface, return the pointer to this.
* Otherwise the implementation is supposed to return 0.
*/
virtual lay::Browser *browser_interface ()
{
return 0;
}
/**
* @brief Return the lay::ViewService interface if this object has one
*
* If the object implements the lay::ViewService interface, return the pointer to this.
* Otherwise the implementation is supposed to return 0.
*/
virtual lay::ViewService *view_service_interface ()
{
return 0;
}
/**
* @brief Return the lay::Drawing interface if this object has one
*
* If the object implements the lay::Drawing interface, return the pointer to this.
* Otherwise the implementation is supposed to return 0.
*/
virtual lay::Drawing *drawing_interface ()
{
return 0;
}
/**
* @brief Return the lay::Editable interface if this object has one
*
* If the object implements the lay::Editable interface, return the pointer to this.
* Otherwise the implementation is supposed to return 0.
*/
virtual lay::Editable *editable_interface ()
{
return 0;
}
/**
* @brief Associate a plugin with the plugin declaration for that service (getter)
*/
const PluginDeclaration *plugin_declaration () const
{
return mp_plugin_declaration;
}
/**
* @brief Associate a service with the plugin declaration for that service (setter)
*
* The association is done when the plugin is created. It should not be changed.
*/
void set_plugin_declaration (const PluginDeclaration *pd)
{
mp_plugin_declaration = pd;
}
protected:
/**
* @brief Configure method
*
* This method must be supplied by derived classes. If the class
* knows about the configuration option it must consume the value
* and return 'true'.
* No selection is made for "matching" configuration options for
* this class.
*/
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)
{
return false;
}
/**
* @brief Configuration finalization
*
* This method is called after all configuration changes have been applied.
* A derived class might implement this method in order to do some post-
* processing of the configuration.
*/
virtual void config_finalize ()
{
// .. the default implementation does nothing ..
}
private:
Plugin (const Plugin &);
Plugin &operator= (const Plugin &);
/**
* @brief Do the actual setup or pass to the parent if not the root
*/
void do_config_setup (Plugin *target);
/**
* @brief Do the actual set or pass to the children if not taken
*/
bool do_config_set (const std::string &name, const std::string &value);
/**
* @brief Recursively call config_finalize
*/
void do_config_end ();
Plugin *mp_parent;
const PluginDeclaration *mp_plugin_declaration;
tl::weak_collection<Plugin> m_children;
std::map <std::string, std::string> m_repository;
tl::DeferredMethod<lay::Plugin> dm_finalize_config;
bool m_standalone;
};
/**
* @brief The plugin root element
*
* The first (root) object must be derived from this class.
* This class offers the full "plugin" functionality like
* configuration interface etc. but cannot have a parent.
*/
class LAYBASIC_PUBLIC PluginRoot
: public Plugin
{
public:
/**
* @brief The constructor
*/
PluginRoot (bool standalone = false);
/**
* @brief Destructor
*/
~PluginRoot ();
/**
* @brief Write configuration to a file
*
* If the configuration file cannot be written, false
* is returned but no exception is thrown.
*
* @return false, if an error occured.
*/
bool write_config (const std::string &config_file);
/**
* @brief Read the configuration from a file
*
* This method siletly does nothing, if the config file does not
* exist. If it does and an error occured, the error message is printed
* on stderr. In both cases, false is returned.
*
* @return false, if an error occured.
*/
bool read_config (const std::string &config_file);
/**
* @brief The singleton instance of the plugin root
*/
static PluginRoot *instance ();
/**
* @brief Notifies the plugin root that a new plugin class has been registered
*
* This method is called when a plugin is loaded dynamically during runtime.
*/
virtual void plugin_registered (lay::PluginDeclaration * /*cls*/) { }
/**
* @brief Notifies the plugin root that a plugin class is about to be removed
*/
virtual void plugin_removed (lay::PluginDeclaration * /*cls*/) { }
/**
* @brief Selects the given mode
*
* The implementation is supposed to select the given mode on all related plugins.
*/
virtual void select_mode (int /*mode*/) { }
private:
PluginRoot (const PluginRoot &);
PluginRoot &operator= (const PluginRoot &);
};
/**
* @brief A handy function for implementing the configure method
*
* This template compares two values and overwrites the target
* with the source if both are different. It returns true, if
* the target was updated indicating that something needs to be
* updated.
*/
template <class T>
inline bool test_and_set (T &target, const T &source)
{
if (target != source) {
target = source;
return true;
} else {
return false;
}
}
}
namespace tl
{
// make registration available to external DLL's
template class LAYBASIC_PUBLIC tl::RegisteredClass<lay::PluginDeclaration>;
// disable copy ctor for PluginRoot
template <> struct type_traits<lay::PluginRoot> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
// disable copy ctor for Plugin
template <> struct type_traits<lay::Plugin> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
};
}
#endif