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"
40 #include "pbd/stacktrace.h"
42 #include "gtkmm2ext/actions.h"
43 #include "gtkmm2ext/utils.h"
52 using namespace Gtkmm2ext;
54 typedef std::map<std::string, Glib::RefPtr<Gtk::Action> > ActionMap;
55 static ActionMap actions;
56 typedef std::vector<Glib::RefPtr<Gtk::ActionGroup> > ActionGroups;
57 static ActionGroups groups;
59 RefPtr<UIManager> ActionManager::ui_manager;
60 string ActionManager::unbound_string = X_("--");
65 ActionState (GtkAction* a, bool s) : action (a), sensitive (s) {}
68 typedef std::vector<ActionState> ActionStates;
70 static ActionStates action_states_to_restore;
71 static bool actions_disabled = false;
74 ActionManager::init ()
76 ui_manager = UIManager::create ();
80 ActionManager::save_action_states ()
82 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
84 /* the C++ API for functions used here appears to be broken in
85 gtkmm2.6, so we fall back to the C level.
88 GtkActionGroup* group = (*g)->gobj();
90 for (GList* acts = gtk_action_group_list_actions (group); acts; acts = g_list_next (acts)) {
91 GtkAction* action = (GtkAction*) acts->data;
92 action_states_to_restore.push_back (ActionState (action, gtk_action_get_sensitive (action)));
98 ActionManager::set_sensitive (Glib::RefPtr<ActionGroup> group, bool yn)
100 /* the C++ API for functions used here appears to be broken in
101 gtkmm2.6, so we fall back to the C level.
104 GtkActionGroup* grp = group->gobj();
106 for (GList* acts = gtk_action_group_list_actions (grp); acts; acts = g_list_next (acts)) {
107 GtkAction* action = (GtkAction*) acts->data;
108 gtk_action_set_sensitive (action, yn);
113 ActionManager::enable_active_actions ()
115 if (!actions_disabled) {
119 for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) {
120 if ((*i).action && (*i).sensitive) {
121 gtk_action_set_sensitive ((*i).action, true);
125 action_states_to_restore.clear ();
126 actions_disabled = false;
130 ActionManager::disable_active_actions ()
132 if (actions_disabled == true ) {
135 // save all action's states to action_states_to_restore
136 save_action_states ();
138 // set all action's states disabled
139 for (ActionStates::iterator i = action_states_to_restore.begin(); i != action_states_to_restore.end(); ++i) {
140 if ((*i).sensitive) {
141 gtk_action_set_sensitive ((*i).action, false);
144 actions_disabled = true;
148 ActionManager::get_widget (const char * name)
150 return ui_manager->get_widget (name);
154 ActionManager::set_sensitive (vector<RefPtr<Action> >& actions, bool state)
156 // if actions weren't disabled
157 if (!actions_disabled) {
158 for (vector<RefPtr<Action> >::iterator i = actions.begin(); i != actions.end(); ++i) {
159 (*i)->set_sensitive (state);
163 // actions were disabled
164 // so we should just set necessary action's states in action_states_to_restore
165 for (vector<RefPtr<Action> >::iterator i = actions.begin(); i != actions.end(); ++i) {
166 // go through action_states_to_restore and set state of actions
167 for (ActionStates::iterator j = action_states_to_restore.begin(); j != action_states_to_restore.end(); ++j) {
168 // all actions should have their individual name, so we can use it for comparison
169 if (gtk_action_get_name ((*j).action) == (*i)->get_name ()) {
170 (*j).sensitive = state;
178 ActionManager::check_toggleaction (const string& n)
180 set_toggleaction_state (n, true);
184 ActionManager::uncheck_toggleaction (const string& n)
186 set_toggleaction_state (n, false);
190 ActionManager::set_toggleaction_state (const string& n, bool s)
192 char const * name = n.c_str ();
194 const char *last_slash = strrchr (name, '/');
196 if (last_slash == 0) {
197 fatal << string_compose ("programmer error: %1 %2", "illegal toggle action name", name) << endmsg;
198 abort(); /*NOTREACHED*/
202 /* 10 = strlen ("<Actions>/") */
203 size_t len = last_slash - (name + 10);
205 char* group_name = new char[len+1];
206 memcpy (group_name, name + 10, len);
207 group_name[len] = '\0';
209 const char* action_name = last_slash + 1;
210 if (!set_toggleaction_state (group_name, action_name, s)) {
211 error << string_compose (_("Unknown action name: %1/%2"), group_name, action_name) << endmsg;
214 delete [] group_name;
218 ActionManager::set_toggleaction_state (const char* group_name, const char* action_name, bool s)
220 RefPtr<Action> act = get_action (group_name, action_name);
222 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
224 tact->set_active (s);
232 ActionManager::do_action (const char* group, const char*action)
234 Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (group, action);
241 ActionManager::set_toggle_action (const char* group, const char*action, bool yn)
243 Glib::RefPtr<Gtk::ToggleAction> tact = ActionManager::get_toggle_action (group, action);
244 tact->set_active (yn);
248 ActionManager::get_action (const string& name, bool or_die)
250 ActionMap::const_iterator a = actions.find (name);
252 if (a != actions.end()) {
260 cerr << "Failed to find action: [" << name << ']' << endl;
261 return RefPtr<Action>();
265 ActionManager::get_toggle_action (const string& name, bool or_die)
267 RefPtr<Action> act = get_action (name, or_die);
270 return RefPtr<ToggleAction>();
273 return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
277 ActionManager::get_radio_action (const string& name, bool or_die)
279 RefPtr<Action> act = get_action (name, or_die);
282 return RefPtr<RadioAction>();
285 return Glib::RefPtr<RadioAction>::cast_dynamic (act);
289 ActionManager::get_action (char const * group_name, char const * action_name, bool or_die)
291 string fullpath (group_name);
293 fullpath += action_name;
295 ActionMap::const_iterator a = actions.find (fullpath);
297 if (a != actions.end()) {
305 cerr << "Failed to find action (2): [" << fullpath << ']' << endl;
306 PBD::stacktrace (std::cerr, 20);
307 return RefPtr<Action>();
311 ActionManager::get_toggle_action (char const * group_name, char const * action_name, bool or_die)
313 RefPtr<Action> act = get_action (group_name, action_name, or_die);
316 return RefPtr<ToggleAction>();
319 return Glib::RefPtr<ToggleAction>::cast_dynamic (act);
323 ActionManager::get_radio_action (char const * group_name, char const * action_name, bool or_die)
325 RefPtr<Action> act = get_action (group_name, action_name, or_die);
328 return RefPtr<RadioAction>();
331 return Glib::RefPtr<RadioAction>::cast_dynamic (act);
336 ActionManager::create_action_group (void * owner, string const & name)
338 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
339 if ((*g)->get_name () == name) {
344 RefPtr<ActionGroup> g = ActionGroup::create (name);
346 g->set_data (X_("owner"), owner);
347 groups.push_back (g);
349 /* this is one of the places where our own Action management code
350 has to touch the GTK one, because we want the GtkUIManager to
351 be able to create widgets (particularly Menus) from our actions.
353 This is a a necessary step for that to happen.
357 ActionManager::ui_manager->insert_action_group (g);
364 ActionManager::get_action_group (string const & name)
366 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
367 if ((*g)->get_name () == name) {
372 return RefPtr<ActionGroup> ();
376 ActionManager::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
380 RefPtr<Action> act = Action::create (name, label);
382 fullpath = group->get_name();
386 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
391 /* already registered */
392 return RefPtr<Action> ();
396 ActionManager::register_action (RefPtr<ActionGroup> group,
397 const char* name, const char* label, sigc::slot<void> sl)
401 RefPtr<Action> act = Action::create (name, label);
403 fullpath = group->get_name();
407 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
408 group->add (act, sl);
412 /* already registered */
413 return RefPtr<Action>();
417 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
418 Gtk::RadioAction::Group& rgroup,
419 const char* name, const char* label,
424 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
425 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
427 fullpath = group->get_name();
431 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
432 group->add (act, sl);
436 /* already registered */
437 return RefPtr<Action>();
441 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
442 Gtk::RadioAction::Group& rgroup,
443 const char* name, const char* label,
444 sigc::slot<void,GtkAction*> sl,
449 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
450 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
451 ract->property_value() = value;
453 fullpath = group->get_name();
457 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
458 group->add (act, sigc::bind (sl, act->gobj()));
462 /* already registered */
464 return RefPtr<Action>();
468 ActionManager::register_toggle_action (RefPtr<ActionGroup> group,
469 const char* name, const char* label, sigc::slot<void> sl)
473 fullpath = group->get_name();
477 RefPtr<Action> act = ToggleAction::create (name, label);
479 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
480 group->add (act, sl);
484 /* already registered */
485 return RefPtr<Action>();
489 ActionManager::get_actions (void* owner, std::vector<Glib::RefPtr<Gtk::Action> >& acts)
491 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
493 Glib::RefPtr<Gtk::ActionGroup> group = a->second->property_action_group ();
494 if (group->get_data (X_("owner")) == owner) {
495 acts.push_back (a->second);
498 acts.push_back (a->second);
504 ActionManager::get_all_actions (std::vector<std::string>& paths,
505 std::vector<std::string>& labels,
506 std::vector<std::string>& tooltips,
507 std::vector<std::string>& keys,
508 std::vector<RefPtr<Action> >& acts)
510 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
512 Glib::RefPtr<Action> act = a->second;
514 paths.push_back (act->get_accel_path());
515 labels.push_back (act->get_label());
516 tooltips.push_back (act->get_tooltip());
517 acts.push_back (act);
519 /* foreach binding */
522 Bindings* bindings = (*map)->bindings();
527 Bindings::Operation op;
529 key = bindings->get_binding_for_action (*act, op);
531 if (key == KeyboardKey::null_key()) {
532 keys.push_back (string());
534 keys.push_back (key.display_label());
537 keys.push_back (string());