2 Copyright (C) 2005 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <boost/shared_ptr.hpp>
29 #include <gtk/gtkaccelmap.h>
30 #include <gtk/gtkuimanager.h>
31 #include <gtk/gtkactiongroup.h>
34 #include <gtkmm/accelmap.h>
35 #include <gtkmm/uimanager.h>
37 #include <glibmm/miscutils.h>
39 #include "pbd/error.h"
41 #include "gtkmm2ext/actions.h"
42 #include "gtkmm2ext/utils.h"
51 using namespace Gtkmm2ext;
53 typedef std::map<std::string, Glib::RefPtr<Gtk::Action> > ActionMap;
54 static ActionMap actions;
55 typedef std::vector<Glib::RefPtr<Gtk::ActionGroup> > ActionGroups;
56 static ActionGroups groups;
58 RefPtr<UIManager> ActionManager::ui_manager;
59 string ActionManager::unbound_string = X_("--");
64 ActionState (GtkAction* a, bool s) : action (a), sensitive (s) {}
67 typedef std::vector<ActionState> ActionStates;
69 static ActionStates action_states_to_restore;
70 static bool actions_disabled = false;
73 ActionManager::init ()
75 ui_manager = UIManager::create ();
79 ActionManager::save_action_states ()
81 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
83 /* the C++ API for functions used here appears to be broken in
84 gtkmm2.6, so we fall back to the C level.
87 GtkActionGroup* group = (*g)->gobj();
89 for (GList* acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
90 GtkAction* action = (GtkAction*) acts->data;
91 action_states_to_restore.push_back (ActionState (action, gtk_action_get_sensitive (action)));
97 ActionManager::set_sensitive (Glib::RefPtr<ActionGroup> group, bool yn)
99 /* the C++ API for functions used here appears to be broken in
100 gtkmm2.6, so we fall back to the C level.
103 GtkActionGroup* grp = group->gobj();
105 for (GList* acts = gtk_action_group_list_actions (grp); acts; acts = g_list_next (acts)) {
106 GtkAction* action = (GtkAction*) acts->data;
107 gtk_action_set_sensitive (action, yn);
112 ActionManager::enable_active_actions ()
114 if (!actions_disabled) {
118 for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) {
119 if ((*i).action && (*i).sensitive) {
120 gtk_action_set_sensitive ((*i).action, true);
124 action_states_to_restore.clear ();
125 actions_disabled = false;
129 ActionManager::disable_active_actions ()
131 if (actions_disabled == true ) {
134 // save all action's states to action_states_to_restore
135 save_action_states ();
137 // set all action's states disabled
138 for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) {
139 if ((*i).sensitive) {
140 gtk_action_set_sensitive ((*i).action, false);
143 actions_disabled = true;
147 ActionManager::get_widget (const char * name)
149 return ui_manager->get_widget (name);
153 ActionManager::set_sensitive (vector<RefPtr<Action> >& actions, bool state)
155 // if actions weren't disabled
156 if (!actions_disabled) {
157 for (vector<RefPtr<Action> >::iterator i = actions.begin(); i != actions.end(); ++i) {
158 (*i)->set_sensitive (state);
162 // actions were disabled
163 // so we should just set necessary action's states in action_states_to_restore
164 for (vector<RefPtr<Action> >::iterator i = actions.begin(); i != actions.end(); ++i) {
165 // go through action_states_to_restore and set state of actions
166 for (ActionStates::iterator j = action_states_to_restore.begin(); j != action_states_to_restore.end(); ++j) {
167 // all actions should have their individual name, so we can use it for comparison
168 if (gtk_action_get_name ((*j).action) == (*i)->get_name ()) {
169 (*j).sensitive = state;
177 ActionManager::check_toggleaction (const string& n)
179 set_toggleaction_state (n, true);
183 ActionManager::uncheck_toggleaction (const string& n)
185 set_toggleaction_state (n, false);
189 ActionManager::set_toggleaction_state (const string& n, bool s)
191 char const * name = n.c_str ();
193 const char *last_slash = strrchr (name, '/');
195 if (last_slash == 0) {
196 fatal << string_compose ("programmer error: %1 %2", "illegal toggle action name", name) << endmsg;
197 abort(); /*NOTREACHED*/
201 /* 10 = strlen ("<Actions>/") */
202 size_t len = last_slash - (name + 10);
204 char* group_name = new char[len+1];
205 memcpy (group_name, name + 10, len);
206 group_name[len] = '\0';
208 const char* action_name = last_slash + 1;
209 if (!set_toggleaction_state (group_name, action_name, s)) {
210 error << string_compose (_("Unknown action name: %1/%2"), group_name, action_name) << endmsg;
213 delete [] group_name;
217 ActionManager::set_toggleaction_state (const char* group_name, const char* action_name, bool s)
219 RefPtr<Action> act = get_action (group_name, action_name);
221 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
223 tact->set_active (s);
231 ActionManager::do_action (const char* group, const char*action)
233 Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (group, action);
240 ActionManager::set_toggle_action (const char* group, const char*action, bool yn)
242 Glib::RefPtr<Gtk::ToggleAction> tact = ActionManager::get_toggle_action (group, action);
243 tact->set_active (yn);
247 ActionManager::get_action (const string& name, bool or_die)
249 ActionMap::const_iterator a = actions.find (name);
251 if (a != actions.end()) {
259 cerr << "Failed to find action: [" << name << ']' << endl;
260 return RefPtr<Action>();
264 ActionManager::get_toggle_action (const string& name, bool or_die)
266 RefPtr<Action> act = get_action (name, or_die);
269 return RefPtr<ToggleAction>();
272 return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
276 ActionManager::get_radio_action (const string& name, bool or_die)
278 RefPtr<Action> act = get_action (name, or_die);
281 return RefPtr<RadioAction>();
284 return Glib::RefPtr<RadioAction>::cast_dynamic (act);
288 ActionManager::get_action (char const * group_name, char const * action_name, bool or_die)
290 string fullpath (group_name);
292 fullpath += action_name;
294 ActionMap::const_iterator a = actions.find (fullpath);
296 if (a != actions.end()) {
304 cerr << "Failed to find action (2): [" << fullpath << ']' << endl;
305 return RefPtr<Action>();
309 ActionManager::get_toggle_action (char const * group_name, char const * action_name, bool or_die)
311 RefPtr<Action> act = get_action (group_name, action_name, or_die);
314 return RefPtr<ToggleAction>();
317 return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
321 ActionManager::get_radio_action (char const * group_name, char const * action_name, bool or_die)
323 RefPtr<Action> act = get_action (group_name, action_name, or_die);
326 return RefPtr<RadioAction>();
329 return Glib::RefPtr<RadioAction>::cast_dynamic (act);
334 ActionManager::create_action_group (string const & name)
336 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
337 if ((*g)->get_name () == name) {
342 RefPtr<ActionGroup> g = ActionGroup::create (name);
344 groups.push_back (g);
346 /* this is one of the places where our own Action management code
347 has to touch the GTK one, because we want the GtkUIManager to
348 be able to create widgets (particularly Menus) from our actions.
350 This is a a necessary step for that to happen.
354 ActionManager::ui_manager->insert_action_group (g);
361 ActionManager::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
365 RefPtr<Action> act = Action::create (name, label);
367 fullpath = group->get_name();
371 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
376 /* already registered */
377 return RefPtr<Action> ();
381 ActionManager::register_action (RefPtr<ActionGroup> group,
382 const char* name, const char* label, sigc::slot<void> sl)
386 RefPtr<Action> act = Action::create (name, label);
388 fullpath = group->get_name();
392 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
393 group->add (act, sl);
397 /* already registered */
398 return RefPtr<Action>();
402 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
403 Gtk::RadioAction::Group& rgroup,
404 const char* name, const char* label,
409 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
410 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
412 fullpath = group->get_name();
416 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
417 group->add (act, sl);
421 /* already registered */
422 return RefPtr<Action>();
426 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
427 Gtk::RadioAction::Group& rgroup,
428 const char* name, const char* label,
429 sigc::slot<void,GtkAction*> sl,
434 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
435 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
436 ract->property_value() = value;
438 fullpath = group->get_name();
442 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
443 group->add (act, sigc::bind (sl, act->gobj()));
447 /* already registered */
449 return RefPtr<Action>();
453 ActionManager::register_toggle_action (RefPtr<ActionGroup> group,
454 const char* name, const char* label, sigc::slot<void> sl)
458 fullpath = group->get_name();
462 RefPtr<Action> act = ToggleAction::create (name, label);
464 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
465 group->add (act, sl);
469 /* already registered */
470 return RefPtr<Action>();
474 ActionManager::get_all_actions (std::vector<std::string>& paths,
475 std::vector<std::string>& labels,
476 std::vector<std::string>& tooltips,
477 std::vector<std::string>& keys,
478 std::vector<RefPtr<Action> >& acts)
480 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
482 Glib::RefPtr<Action> act = a->second;
484 paths.push_back (act->get_accel_path());
485 labels.push_back (act->get_label());
486 tooltips.push_back (act->get_tooltip());
487 acts.push_back (act);
489 /* foreach binding */
492 Bindings* bindings = (*map)->bindings();
497 Bindings::Operation op;
499 key = bindings->get_binding_for_action (*act, op);
501 if (key == KeyboardKey::null_key()) {
502 keys.push_back (string());
504 keys.push_back (key.display_label());
507 keys.push_back (string());