mirror of https://github.com/KLayout/klayout.git
584 lines
15 KiB
C++
584 lines
15 KiB
C++
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
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
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
#include "layAbstractMenuProvider.h"
|
||
|
|
#include "laybasicCommon.h"
|
||
|
|
|
||
|
|
#include "tlException.h"
|
||
|
|
#include "tlAssert.h"
|
||
|
|
#include "tlXMLParser.h"
|
||
|
|
|
||
|
|
#include "layPlugin.h"
|
||
|
|
#include "tlExceptions.h"
|
||
|
|
#include "tlClassRegistry.h"
|
||
|
|
|
||
|
|
#include "gtf.h"
|
||
|
|
|
||
|
|
#include <iostream>
|
||
|
|
#include <fstream>
|
||
|
|
#include <memory>
|
||
|
|
|
||
|
|
namespace lay
|
||
|
|
{
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------
|
||
|
|
// PluginDeclaration implementation
|
||
|
|
|
||
|
|
static int s_next_id = 0;
|
||
|
|
template<> LAYBASIC_PUBLIC tl::Registrar<lay::PluginDeclaration> *tl::Registrar<lay::PluginDeclaration>::instance = 0;
|
||
|
|
|
||
|
|
PluginDeclaration::PluginDeclaration ()
|
||
|
|
: m_id (++s_next_id), m_editable_enabled (true)
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
PluginDeclaration::~PluginDeclaration ()
|
||
|
|
{
|
||
|
|
if (PluginRoot::instance ()) {
|
||
|
|
PluginRoot::instance ()->plugin_removed (this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::toggle_editable_enabled ()
|
||
|
|
{
|
||
|
|
BEGIN_PROTECTED
|
||
|
|
set_editable_enabled (! editable_enabled ());
|
||
|
|
END_PROTECTED
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::generic_menu ()
|
||
|
|
{
|
||
|
|
BEGIN_PROTECTED
|
||
|
|
|
||
|
|
QAction *action = dynamic_cast <QAction *> (sender ());
|
||
|
|
tl_assert (action);
|
||
|
|
|
||
|
|
std::string symbol = tl::to_string (action->data ().toString ());
|
||
|
|
|
||
|
|
// Global handler: give the declaration a chance to handle the menu request globally
|
||
|
|
if (menu_activated (symbol)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Forward the request to the plugin root which will propagate it down to the plugins
|
||
|
|
lay::PluginRoot::instance ()->menu_activated (symbol);
|
||
|
|
|
||
|
|
END_PROTECTED
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::mode_triggered ()
|
||
|
|
{
|
||
|
|
BEGIN_PROTECTED
|
||
|
|
|
||
|
|
QAction *action = dynamic_cast<QAction *> (sender ());
|
||
|
|
if (action) {
|
||
|
|
|
||
|
|
int mode = action->data ().toInt ();
|
||
|
|
|
||
|
|
if (lay::PluginRoot::instance ()) {
|
||
|
|
lay::PluginRoot::instance ()->select_mode (mode);
|
||
|
|
}
|
||
|
|
|
||
|
|
action->setChecked (true);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
END_PROTECTED
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::init_menu ()
|
||
|
|
{
|
||
|
|
if (! lay::AbstractMenuProvider::instance () || ! lay::AbstractMenuProvider::instance ()->menu ()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
lay::AbstractMenu &menu = *lay::AbstractMenuProvider::instance ()->menu ();
|
||
|
|
|
||
|
|
// pre-initialize to allow to multiple init_menu calls
|
||
|
|
m_editable_mode_action = lay::Action ();
|
||
|
|
m_mouse_mode_action = lay::Action ();
|
||
|
|
m_menu_actions.clear ();
|
||
|
|
|
||
|
|
std::string title;
|
||
|
|
|
||
|
|
// make all plugins that return true on "implements_editable" into menu entries and
|
||
|
|
// set up the actions accordingly
|
||
|
|
|
||
|
|
if (implements_editable (title) && menu.is_valid ("edit_menu.select_menu")) {
|
||
|
|
|
||
|
|
// extract first part, which is the name, separated by a tab from the title.
|
||
|
|
std::string name = tl::sprintf ("pi_enable_%d", id ());
|
||
|
|
std::string t (title);
|
||
|
|
const char *tab = strchr (t.c_str (), '\t');
|
||
|
|
if (tab) {
|
||
|
|
name = std::string (t, 0, tab - t.c_str ());
|
||
|
|
title = tab + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
m_editable_mode_action = AbstractMenu::create_action (title);
|
||
|
|
gtf::action_connect (m_editable_mode_action.qaction (), SIGNAL (triggered ()), this, SLOT (toggle_editable_enabled ()));
|
||
|
|
m_editable_mode_action.qaction ()->setData (id ());
|
||
|
|
m_editable_mode_action.set_checkable (true);
|
||
|
|
m_editable_mode_action.set_checked (m_editable_enabled);
|
||
|
|
|
||
|
|
menu.insert_item ("edit_menu.select_menu.end", name, m_editable_mode_action);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// add all the custom menus from the plugins
|
||
|
|
std::vector<lay::MenuEntry> menu_entries;
|
||
|
|
get_menu_entries (menu_entries);
|
||
|
|
|
||
|
|
for (std::vector<lay::MenuEntry>::const_iterator m = menu_entries.begin (); m != menu_entries.end (); ++m) {
|
||
|
|
|
||
|
|
if (m->title.empty ()) {
|
||
|
|
menu.insert_separator (m->insert_pos, m->menu_name);
|
||
|
|
} else {
|
||
|
|
|
||
|
|
if (m->sub_menu) {
|
||
|
|
menu.insert_menu (m->insert_pos, m->menu_name, m->title);
|
||
|
|
} else {
|
||
|
|
|
||
|
|
Action action (AbstractMenu::create_action (m->title));
|
||
|
|
action.qaction ()->setData (QVariant (tl::to_qstring (m->symbol)));
|
||
|
|
gtf::action_connect (action.qaction (), SIGNAL (triggered ()), this, SLOT (generic_menu ()));
|
||
|
|
menu.insert_item (m->insert_pos, m->menu_name, action);
|
||
|
|
|
||
|
|
m_menu_actions.push_back (action);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill the mode menu file items from the mouse modes
|
||
|
|
|
||
|
|
title = std::string ();
|
||
|
|
if (implements_mouse_mode (title)) {
|
||
|
|
|
||
|
|
// extract first part, which is the name, separated by a tab from the title.
|
||
|
|
std::string name = tl::sprintf ("mode_%d", id ());
|
||
|
|
const char *tab = strchr (title.c_str (), '\t');
|
||
|
|
if (tab) {
|
||
|
|
name = std::string (title, 0, tab - title.c_str ());
|
||
|
|
title = std::string (tab + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
m_mouse_mode_action = AbstractMenu::create_action (title);
|
||
|
|
m_mouse_mode_action.add_to_exclusive_group (&menu, "mouse_mode_exclusive_group");
|
||
|
|
|
||
|
|
m_mouse_mode_action.set_checkable (true);
|
||
|
|
m_mouse_mode_action.qaction ()->setData (QVariant (id ()));
|
||
|
|
|
||
|
|
menu.insert_item ("edit_menu.mode_menu.end", name, m_mouse_mode_action);
|
||
|
|
menu.insert_item ("@toolbar.end", name, m_mouse_mode_action);
|
||
|
|
|
||
|
|
gtf::action_connect (m_mouse_mode_action.qaction (), SIGNAL (triggered ()), this, SLOT (mode_triggered ()));
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::remove_menu_items ()
|
||
|
|
{
|
||
|
|
if (! lay::AbstractMenuProvider::instance () || ! lay::AbstractMenuProvider::instance ()->menu ()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
lay::AbstractMenu *menu = lay::AbstractMenuProvider::instance ()->menu ();
|
||
|
|
menu->delete_items (m_editable_mode_action);
|
||
|
|
menu->delete_items (m_mouse_mode_action);
|
||
|
|
for (std::vector <lay::Action>::const_iterator a = m_menu_actions.begin (); a != m_menu_actions.end (); ++a) {
|
||
|
|
menu->delete_items (*a);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::set_editable_enabled (bool f)
|
||
|
|
{
|
||
|
|
if (f != m_editable_enabled) {
|
||
|
|
m_editable_enabled = f;
|
||
|
|
m_editable_mode_action.set_checked (f);
|
||
|
|
editable_enabled_changed_event ();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
PluginDeclaration::register_plugin ()
|
||
|
|
{
|
||
|
|
if (PluginRoot::instance ()) {
|
||
|
|
PluginRoot::instance ()->plugin_registered (this);
|
||
|
|
initialize (PluginRoot::instance ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------
|
||
|
|
// Plugin implementation
|
||
|
|
|
||
|
|
Plugin::Plugin (Plugin *parent, bool standalone)
|
||
|
|
: mp_parent (parent), mp_plugin_declaration (0), dm_finalize_config (this, &lay::Plugin::config_end), m_standalone (standalone)
|
||
|
|
{
|
||
|
|
if (! parent) {
|
||
|
|
if (! standalone) {
|
||
|
|
// load the root with the default configuration
|
||
|
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||
|
|
std::vector< std::pair<std::string, std::string> > pairs;
|
||
|
|
cls->get_options (pairs);
|
||
|
|
m_repository.insert (pairs.begin (), pairs.end ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
mp_parent->m_children.push_back (this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Plugin::~Plugin ()
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::config_setup ()
|
||
|
|
{
|
||
|
|
do_config_setup (this);
|
||
|
|
do_config_end ();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::config_set (const std::string &name, const char *value)
|
||
|
|
{
|
||
|
|
config_set (name, std::string (value));
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::config_set (const std::string &name, const std::string &value)
|
||
|
|
{
|
||
|
|
std::map <std::string, std::string>::iterator m = m_repository.find (name);
|
||
|
|
if (m != m_repository.end ()) {
|
||
|
|
// if the value did not change, do nothing
|
||
|
|
if (m->second == value) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
m->second = value;
|
||
|
|
} else {
|
||
|
|
// install the value in the repository
|
||
|
|
m_repository.insert (std::make_pair (name, value));
|
||
|
|
}
|
||
|
|
|
||
|
|
// look for plugins that receive that configuration statically if the root is addressed
|
||
|
|
if (! mp_parent && ! m_standalone) {
|
||
|
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||
|
|
if ((const_cast<lay::PluginDeclaration *> (&*cls))->configure (name, value)) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
do_config_set (name, value);
|
||
|
|
|
||
|
|
// schedule a configuration finalization call (once for all config_set calls)
|
||
|
|
dm_finalize_config ();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::config_end ()
|
||
|
|
{
|
||
|
|
// finish static conifgurations for plugins if the root is addressed
|
||
|
|
if (! mp_parent && ! m_standalone) {
|
||
|
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||
|
|
(const_cast<lay::PluginDeclaration *> (&*cls))->config_finalize ();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
do_config_end ();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::clear_config ()
|
||
|
|
{
|
||
|
|
m_repository.clear ();
|
||
|
|
if (! mp_parent && ! m_standalone) {
|
||
|
|
// load the root with the default configuration
|
||
|
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||
|
|
std::vector< std::pair<std::string, std::string> > pairs;
|
||
|
|
cls->get_options (pairs);
|
||
|
|
m_repository.insert (pairs.begin (), pairs.end ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
config_setup ();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
Plugin::config_get (const std::string &name, std::string &value) const
|
||
|
|
{
|
||
|
|
std::map<std::string, std::string>::const_iterator p = m_repository.find (name);
|
||
|
|
if (p != m_repository.end ()) {
|
||
|
|
value = p->second;
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
value = "";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::get_config_names (std::vector<std::string> &names) const
|
||
|
|
{
|
||
|
|
names.reserve (m_repository.size ());
|
||
|
|
|
||
|
|
// retrieve the configuration names
|
||
|
|
for (std::map<std::string, std::string>::const_iterator p = m_repository.begin (); p != m_repository.end (); ++p) {
|
||
|
|
names.push_back (p->first);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::do_config_setup (Plugin *target)
|
||
|
|
{
|
||
|
|
if (mp_parent) {
|
||
|
|
mp_parent->do_config_setup (target);
|
||
|
|
}
|
||
|
|
// local configurations override the parent's configuration, i.e. are applied after the parents settings
|
||
|
|
for (std::map<std::string, std::string>::const_iterator p = m_repository.begin (); p != m_repository.end (); ++p) {
|
||
|
|
target->do_config_set (p->first, p->second);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
Plugin::do_config_end ()
|
||
|
|
{
|
||
|
|
config_finalize ();
|
||
|
|
for (tl::weak_collection<Plugin>::iterator c = m_children.begin (); c != m_children.end (); ++c) {
|
||
|
|
c->do_config_end ();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
Plugin::do_config_set (const std::string &name, const std::string &value)
|
||
|
|
{
|
||
|
|
if (configure (name, value)) {
|
||
|
|
// taken by us - don't propagate to the children
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// propagate to all children (not only the first that takes it!)
|
||
|
|
for (tl::weak_collection<Plugin>::iterator c = m_children.begin (); c != m_children.end (); ++c) {
|
||
|
|
c->do_config_set (name, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ----------------------------------------------------------------
|
||
|
|
// PluginRoot implementation
|
||
|
|
|
||
|
|
static PluginRoot *ms_root_instance = 0;
|
||
|
|
|
||
|
|
PluginRoot::PluginRoot (bool standalone)
|
||
|
|
: Plugin (0, standalone)
|
||
|
|
{
|
||
|
|
ms_root_instance = this;
|
||
|
|
}
|
||
|
|
|
||
|
|
PluginRoot::~PluginRoot ()
|
||
|
|
{
|
||
|
|
if (ms_root_instance == this) {
|
||
|
|
ms_root_instance = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Writing and Reading of configuration
|
||
|
|
|
||
|
|
struct ConfigGetAdaptor
|
||
|
|
{
|
||
|
|
ConfigGetAdaptor (const std::string &name)
|
||
|
|
: mp_owner (0), m_done (false), m_name (name)
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string operator () () const
|
||
|
|
{
|
||
|
|
std::string s;
|
||
|
|
mp_owner->config_get (m_name, s);
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool at_end () const
|
||
|
|
{
|
||
|
|
return m_done;
|
||
|
|
}
|
||
|
|
|
||
|
|
void start (const lay::PluginRoot &owner)
|
||
|
|
{
|
||
|
|
mp_owner = &owner;
|
||
|
|
m_done = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void next ()
|
||
|
|
{
|
||
|
|
m_done = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
const lay::PluginRoot *mp_owner;
|
||
|
|
bool m_done;
|
||
|
|
std::string m_name;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigGetNullAdaptor
|
||
|
|
{
|
||
|
|
ConfigGetNullAdaptor ()
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string operator () () const
|
||
|
|
{
|
||
|
|
return std::string ();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool at_end () const
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void start (const lay::PluginRoot & /*owner*/) { }
|
||
|
|
void next () { }
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigNamedSetAdaptor
|
||
|
|
{
|
||
|
|
ConfigNamedSetAdaptor ()
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
void operator () (lay::PluginRoot &w, tl::XMLReaderState &reader, const std::string &name) const
|
||
|
|
{
|
||
|
|
tl::XMLObjTag<std::string> tag;
|
||
|
|
w.config_set (name, *reader.back (tag));
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
struct ConfigSetAdaptor
|
||
|
|
{
|
||
|
|
ConfigSetAdaptor (const std::string &name)
|
||
|
|
: m_name (name)
|
||
|
|
{
|
||
|
|
// .. nothing yet ..
|
||
|
|
}
|
||
|
|
|
||
|
|
void operator () (lay::PluginRoot &w, tl::XMLReaderState &reader) const
|
||
|
|
{
|
||
|
|
tl::XMLObjTag<std::string> tag;
|
||
|
|
w.config_set (m_name, *reader.back (tag));
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
std::string m_name;
|
||
|
|
};
|
||
|
|
|
||
|
|
// the configuration file's XML structure is built dynamically
|
||
|
|
static tl::XMLStruct<lay::PluginRoot>
|
||
|
|
config_structure (const lay::PluginRoot *plugin)
|
||
|
|
{
|
||
|
|
tl::XMLElementList body;
|
||
|
|
std::string n_with_underscores;
|
||
|
|
|
||
|
|
std::vector <std::string> names;
|
||
|
|
plugin->get_config_names (names);
|
||
|
|
|
||
|
|
for (std::vector <std::string>::const_iterator n = names.begin (); n != names.end (); ++n) {
|
||
|
|
|
||
|
|
body.append (tl::XMLMember<std::string, lay::PluginRoot, ConfigGetAdaptor, ConfigSetAdaptor, tl::XMLStdConverter <std::string> > (
|
||
|
|
ConfigGetAdaptor (*n), ConfigSetAdaptor (*n), *n));
|
||
|
|
|
||
|
|
// for compatibility, provide an alternative with underscores (i.e. 0.20->0.21 because of default_grids)
|
||
|
|
n_with_underscores.clear ();
|
||
|
|
for (const char *c = n->c_str (); *c; ++c) {
|
||
|
|
n_with_underscores += (*c == '-' ? '_' : *c);
|
||
|
|
}
|
||
|
|
|
||
|
|
body.append (tl::XMLMember<std::string, lay::PluginRoot, ConfigGetNullAdaptor, ConfigSetAdaptor, tl::XMLStdConverter <std::string> > (
|
||
|
|
ConfigGetNullAdaptor (), ConfigSetAdaptor (*n), n_with_underscores));
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// add a wildcard member to read all others unspecifically into the repository
|
||
|
|
body.append (tl::XMLWildcardMember<std::string, lay::PluginRoot, ConfigNamedSetAdaptor, tl::XMLStdConverter <std::string> > (ConfigNamedSetAdaptor ()));
|
||
|
|
|
||
|
|
return tl::XMLStruct<lay::PluginRoot> ("config", body);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool
|
||
|
|
PluginRoot::write_config (const std::string &config_file)
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
tl::OutputStream os (config_file, tl::OutputStream::OM_Plain);
|
||
|
|
config_structure (this).write (os, *this);
|
||
|
|
return true;
|
||
|
|
} catch (...) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
PluginRoot::read_config (const std::string &config_file)
|
||
|
|
{
|
||
|
|
std::auto_ptr<tl::XMLFileSource> file;
|
||
|
|
|
||
|
|
try {
|
||
|
|
file.reset (new tl::XMLFileSource (config_file));
|
||
|
|
} catch (...) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
config_structure (this).parse (*file, *this);
|
||
|
|
} catch (tl::Exception &ex) {
|
||
|
|
std::string msg = tl::to_string (QObject::tr ("Problem reading config file ")) + config_file + ": " + ex.msg ();
|
||
|
|
throw tl::Exception (msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
config_end ();
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
PluginRoot *
|
||
|
|
PluginRoot::instance ()
|
||
|
|
{
|
||
|
|
return ms_root_instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|