diff --git a/src/laybasic/laybasic/layAbstractMenu.cc b/src/laybasic/laybasic/layAbstractMenu.cc index cad1e30a6..5c0089904 100644 --- a/src/laybasic/laybasic/layAbstractMenu.cc +++ b/src/laybasic/laybasic/layAbstractMenu.cc @@ -590,7 +590,7 @@ Action::no_shortcut () Action::Action (const std::string &title) { - mp_handle = AbstractMenu::create_action (title); + mp_handle = AbstractMenu::create_action (title, 0); gtf::action_connect (mp_handle->ptr (), SIGNAL (triggered ()), this, SLOT (triggered_slot ())); mp_handle->add_ref (); } @@ -1008,9 +1008,12 @@ ConfigureAction::configure (const std::string &value) // AbstractMenu implementation ActionHandle * -AbstractMenu::create_action (const std::string &s) +AbstractMenu::create_action (const std::string &s, AbstractMenuProvider *provider) { - tl_assert (lay::AbstractMenuProvider::instance () != 0); + if (! provider) { + provider = lay::AbstractMenuProvider::instance (); + } + tl_assert (provider != 0); std::string title; std::string shortcut; @@ -1019,7 +1022,7 @@ AbstractMenu::create_action (const std::string &s) parse_menu_title (s, title, shortcut, res, tool_tip); - ActionHandle *ah = new ActionHandle (lay::AbstractMenuProvider::instance ()->menu_parent_widget ()); + ActionHandle *ah = new ActionHandle (provider->menu_parent_widget ()); ah->ptr ()->setText (tl::to_qstring (title)); if (! tool_tip.empty ()) { @@ -1129,15 +1132,17 @@ AbstractMenu::build_detached (const std::string &name, QFrame *mbar) void AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) { - tl_assert (mp_provider != 0); - m_helper_menu_items.clear (); - tbar->clear (); + if (tbar) { + tbar->clear (); + } std::set > present_actions; - QList a = mbar->actions (); - for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { - present_actions.insert (std::make_pair (id_from_action (*i), *i)); + if (mbar) { + QList a = mbar->actions (); + for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { + present_actions.insert (std::make_pair (id_from_action (*i), *i)); + } } for (std::list::iterator c = m_root.children.begin (); c != m_root.children.end (); ++c) { @@ -1146,7 +1151,9 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) if (c->name () == "@toolbar") { - build (tbar, c->children); + if (tbar) { + build (tbar, c->children); + } } else if (c->name ().find ("@@") == 0) { @@ -1160,14 +1167,16 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) // Otherwise, the keyboard shortcuts do not work for menu items inside such a // popup menu. It seems not to have a negative effect to add the menu to the // main widget. - mp_provider->menu_parent_widget ()->addAction (menu->menuAction ()); + if (mp_provider) { + mp_provider->menu_parent_widget ()->addAction (menu->menuAction ()); + } c->set_action (Action (new ActionHandle (menu)), true); } // prepare a detached menu which can be used as context menues build (c->menu (), c->children); - } else { + } else if (mbar) { if (c->menu () == 0) { QMenu *menu = new QMenu (); @@ -1192,7 +1201,7 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } - } else { + } else if (mbar) { // Move the action to the end if present in the menu already std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->action ().qaction ()), c->action ().qaction ())); if (a != present_actions.end ()) { @@ -1209,8 +1218,10 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } // Remove all actions that have vanished - for (std::set >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { - mbar->removeAction (a->second); + if (mbar) { + for (std::set >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { + mbar->removeAction (a->second); + } } } @@ -1399,8 +1410,6 @@ AbstractMenu::insert_item (const std::string &p, const std::string &name, const void AbstractMenu::insert_separator (const std::string &p, const std::string &name) { - tl_assert (mp_provider != 0); // required to get the parent for the new QAction (via ActionHandle) - typedef std::vector::iterator > > path_type; path_type path = find_item (p); if (! path.empty ()) { @@ -1410,7 +1419,7 @@ AbstractMenu::insert_separator (const std::string &p, const std::string &name) parent->children.insert (iter, AbstractMenuItem ()); --iter; - Action action (new ActionHandle (mp_provider->menu_parent_widget ())); + Action action (new ActionHandle (mp_provider ? mp_provider->menu_parent_widget () : 0)); action.set_separator (true); iter->setup_item (parent->name (), name, action); @@ -1452,7 +1461,7 @@ AbstractMenu::insert_menu (const std::string &p, const std::string &name, const void AbstractMenu::insert_menu (const std::string &path, const std::string &name, const std::string &title) { - insert_menu (path, name, create_action (title)); + insert_menu (path, name, create_action (title, mp_provider)); } void @@ -1715,8 +1724,6 @@ AbstractMenu::find_item (const std::string &p) void AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) { - tl_assert (mp_provider != 0); - while (layout->name) { item.children.push_back (AbstractMenuItem ()); @@ -1724,7 +1731,9 @@ AbstractMenu::transfer (const MenuLayoutEntry *layout, AbstractMenuItem &item) lay::Action a; - if (layout->slot) { + if (! mp_provider) { + a = lay::Action (new ActionHandle ((QWidget *) 0)); + } else if (layout->slot) { // reuse any actions already registered for this slot a = mp_provider->action_for_slot (layout->slot); } else if (! layout->kv_pair.first.empty ()) { diff --git a/src/laybasic/laybasic/layAbstractMenu.h b/src/laybasic/laybasic/layAbstractMenu.h index d919cc9cc..588d60afd 100644 --- a/src/laybasic/laybasic/layAbstractMenu.h +++ b/src/laybasic/laybasic/layAbstractMenu.h @@ -887,10 +887,10 @@ private: * The format of the string is: ["("shortcut")"]["<"icon-resource">"] * * @param s The title, key and icon resource string in the format given above - * @param parent The widget to which to attach the QAction object + * @param provider The abstract menu provider (the global one will be used if this instance is 0) * @return The ActionHandle object created */ - static ActionHandle *create_action (const std::string &s); + static ActionHandle *create_action (const std::string &s, lay::AbstractMenuProvider *provider); AbstractMenuProvider *mp_provider; AbstractMenuItem m_root; diff --git a/src/laybasic/laybasic/layAbstractMenuProvider.cc b/src/laybasic/laybasic/layAbstractMenuProvider.cc index 2b7a90ce2..543a6f84e 100644 --- a/src/laybasic/laybasic/layAbstractMenuProvider.cc +++ b/src/laybasic/laybasic/layAbstractMenuProvider.cc @@ -28,9 +28,9 @@ namespace lay static AbstractMenuProvider *ms_instance = 0; -AbstractMenuProvider::AbstractMenuProvider () +AbstractMenuProvider::AbstractMenuProvider (bool reg_inst) { - if (! ms_instance) { + if (reg_inst && ! ms_instance) { ms_instance = this; } } diff --git a/src/laybasic/laybasic/layAbstractMenuProvider.h b/src/laybasic/laybasic/layAbstractMenuProvider.h index 6f16521bb..4c2d6b26e 100644 --- a/src/laybasic/laybasic/layAbstractMenuProvider.h +++ b/src/laybasic/laybasic/layAbstractMenuProvider.h @@ -45,8 +45,9 @@ class LAYBASIC_PUBLIC AbstractMenuProvider public: /** * @brief Constructor + * If "reg_inst" is true, this instance will become the global instance */ - AbstractMenuProvider (); + AbstractMenuProvider (bool reg_inst = true); /** * @brief Destructor @@ -71,14 +72,14 @@ public: /** * @brief Create a configuration action with the given title, parameter name and value * - * The action will be owned by the main window but can be deleted to remove the action from the main window. + * The action will be owned by the abstract menu provider but can be deleted to remove it from there. */ virtual lay::Action *create_config_action (const std::string &title, const std::string &cname, const std::string &cvalue) = 0; /** * @brief Create a configuration action with the given parameter name and value * - * The action will be owned by the main window but can be deleted to remove the action from the main window. + * The action will be owned by the abstract menu provider but can be deleted to remove it from there. * This version is provided for applications, where the title is set later. */ virtual lay::Action *create_config_action (const std::string &cname, const std::string &cvalue) = 0; diff --git a/src/laybasic/laybasic/layLayoutView.cc b/src/laybasic/laybasic/layLayoutView.cc index 7d14bd803..33845acd0 100644 --- a/src/laybasic/laybasic/layLayoutView.cc +++ b/src/laybasic/laybasic/layLayoutView.cc @@ -256,23 +256,29 @@ static LayoutView *ms_current = 0; LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin_parent, QWidget *parent, const char *name, unsigned int options) : QFrame (parent), lay::Plugin (plugin_parent), - m_menu (0), + lay::AbstractMenuProvider (false /* don't register as global instance */), + m_menu (this), m_editable (editable), m_options (options), m_annotation_shapes (manager), dm_prop_changed (this, &LayoutView::do_prop_changed) { + if (! plugin_root_maybe_null ()) { + mp_plugin_root.reset (new lay::PluginRoot (true, false)); + } + // ensures the deferred method scheduler is present tl::DeferredMethodScheduler::instance (); setObjectName (QString::fromUtf8 (name)); - init (manager, plugin_root_maybe_null (), parent); + init (manager, plugin_root_maybe_null () ? plugin_root_maybe_null () : mp_plugin_root.get (), parent); } LayoutView::LayoutView (lay::LayoutView *source, db::Manager *manager, bool editable, lay::PluginRoot *root, QWidget *parent, const char *name, unsigned int options) : QFrame (parent), lay::Plugin (root), - m_menu (0), + lay::AbstractMenuProvider (false /* don't register as global instance */), + m_menu (this), m_editable (editable), m_options (options), m_annotation_shapes (manager), @@ -353,6 +359,8 @@ LayoutView::init (db::Manager *mgr, lay::PluginRoot *root, QWidget * /*parent*/) if (! lay::AbstractMenuProvider::instance () || ! lay::AbstractMenuProvider::instance ()->menu ()) { init_menu (m_menu); + // build the context menus, nothing else so far. + m_menu.build (0, 0); } m_annotation_shapes.manager (mgr); @@ -691,6 +699,67 @@ LayoutView::~LayoutView () mp_bookmarks_view = 0; } +QWidget *LayoutView::menu_parent_widget () +{ + return this; +} + +lay::Action & +LayoutView::action_for_slot (const char *slot) +{ + std::map::iterator a = m_actions_for_slot.find (std::string (slot)); + if (a != m_actions_for_slot.end ()) { + return a->second; + } else { + Action a = Action::create_free_action (this); + gtf::action_connect (a.qaction (), SIGNAL (triggered ()), this, slot); + return m_actions_for_slot.insert (std::make_pair (std::string (slot), a)).first->second; + } +} + +lay::Action * +LayoutView::create_config_action (const std::string &title, const std::string &cname, const std::string &cvalue) +{ + lay::ConfigureAction *ca = new lay::ConfigureAction(plugin_root (), title, cname, cvalue); + m_ca_collection.push_back (ca); + return ca; +} + +lay::Action * +LayoutView::create_config_action (const std::string &cname, const std::string &cvalue) +{ + lay::ConfigureAction *ca = new lay::ConfigureAction(plugin_root (), std::string (), cname, cvalue); + m_ca_collection.push_back (ca); + return ca; +} + +void +LayoutView::register_config_action (const std::string &name, lay::ConfigureAction *action) +{ + std::map >::iterator ca = m_configuration_actions.insert (std::make_pair (name, std::vector ())).first; + for (std::vector::iterator a = ca->second.begin (); a != ca->second.end (); ++a) { + if (*a == action) { + return; // already registered + } + } + + ca->second.push_back (action); +} + +void +LayoutView::unregister_config_action (const std::string &name, lay::ConfigureAction *action) +{ + std::map >::iterator ca = m_configuration_actions.find (name); + if (ca != m_configuration_actions.end ()) { + for (std::vector::iterator a = ca->second.begin (); a != ca->second.end (); ++a) { + if (*a == action) { + ca->second.erase (a); + return; + } + } + } +} + void LayoutView::side_panel_destroyed () { if (sender () == mp_control_frame) { diff --git a/src/laybasic/laybasic/layLayoutView.h b/src/laybasic/laybasic/layLayoutView.h index fe7e34e1d..f3fa53245 100644 --- a/src/laybasic/laybasic/layLayoutView.h +++ b/src/laybasic/laybasic/layLayoutView.h @@ -31,12 +31,14 @@ #include #include #include +#include #include #include #include "layLayerProperties.h" #include "layAbstractMenu.h" +#include "layAbstractMenuProvider.h" #include "layAnnotationShapes.h" #include "layLayoutCanvas.h" #include "layColorPalette.h" @@ -79,6 +81,8 @@ class SelectionService; class MoveService; class Browser; class ColorButton; +class PluginRoot; +class ConfigureAction; /** * @brief Stores a layer reference to create layers which have been added by some action @@ -155,7 +159,8 @@ struct LAYBASIC_PUBLIC LayerDisplayProperties class LAYBASIC_PUBLIC LayoutView : public QFrame, public lay::Editables, - public lay::Plugin + public lay::Plugin, + public lay::AbstractMenuProvider { Q_OBJECT @@ -217,6 +222,12 @@ public: */ static LayoutView *current (); + /** + * @brief Gets the abstract menu object for this view + * This is either the global menu object or the local one. + */ + AbstractMenu *menu (); + /** * @brief Determine if there is something to copy * @@ -1667,12 +1678,6 @@ public: */ static void update_menu (lay::LayoutView *view, lay::AbstractMenu &menu); - /** - * @brief Get the menu abstraction object - * This is either the global abstract menu or a view-local one if the view is not embedded into a main window. - */ - AbstractMenu *menu (); - /** * @brief Query the default mode */ @@ -2758,6 +2763,10 @@ protected: private: lay::AbstractMenu m_menu; + std::auto_ptr mp_plugin_root; + std::map m_actions_for_slot; + std::map > m_configuration_actions; + tl::shared_collection m_ca_collection; bool m_editable; int m_disabled_edits; @@ -2939,6 +2948,14 @@ private: std::list::iterator cellview_iter (int cv_index); std::list::const_iterator cellview_iter (int cv_index) const; + + // implementation of AbstractMenuProvider + virtual QWidget *menu_parent_widget (); + virtual lay::Action &action_for_slot (const char *slot); + virtual lay::Action *create_config_action (const std::string &title, const std::string &cname, const std::string &cvalue); + virtual lay::Action *create_config_action (const std::string &cname, const std::string &cvalue); + virtual void register_config_action (const std::string &name, lay::ConfigureAction *action); + virtual void unregister_config_action (const std::string &name, lay::ConfigureAction *action); }; } diff --git a/src/laybasic/laybasic/layPlugin.cc b/src/laybasic/laybasic/layPlugin.cc index 7beb06a14..0743f2504 100644 --- a/src/laybasic/laybasic/layPlugin.cc +++ b/src/laybasic/laybasic/layPlugin.cc @@ -368,9 +368,12 @@ Plugin::get_config_names (std::vector &names) const PluginRoot * Plugin::plugin_root () { - PluginRoot *pr = plugin_root_maybe_null (); - tl_assert (pr != 0); - return pr; + Plugin *p = this; + while (p->mp_parent) { + p = p->mp_parent; + } + + return dynamic_cast (p); } PluginRoot * @@ -436,10 +439,12 @@ Plugin::do_config_set (const std::string &name, const std::string &value, bool f static PluginRoot *ms_root_instance = 0; -PluginRoot::PluginRoot (bool standalone) +PluginRoot::PluginRoot (bool standalone, bool reg_inst) : Plugin (0, standalone) { - ms_root_instance = this; + if (reg_inst) { + ms_root_instance = this; + } } PluginRoot::~PluginRoot () diff --git a/src/laybasic/laybasic/layPlugin.h b/src/laybasic/laybasic/layPlugin.h index 0f1413187..4922da7b7 100644 --- a/src/laybasic/laybasic/layPlugin.h +++ b/src/laybasic/laybasic/layPlugin.h @@ -805,7 +805,7 @@ public: /** * @brief The constructor */ - PluginRoot (bool standalone = false); + PluginRoot (bool standalone = false, bool reg_inst = true); /** * @brief Destructor