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<ToggleAction> act = Glib::RefPtr<ToggleAction>::cast_dynamic (get_action (group_name, action_name, or_die));
323 return RefPtr<ToggleAction>();
327 ActionManager::get_radio_action (char const * group_name, char const * action_name, bool or_die)
329 RefPtr<RadioAction> act = Glib::RefPtr<RadioAction>::cast_dynamic (get_action (group_name, action_name, or_die));
339 return RefPtr<RadioAction>();
343 ActionManager::create_action_group (void * owner, string const & name)
345 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
346 if ((*g)->get_name () == name) {
351 RefPtr<ActionGroup> g = ActionGroup::create (name);
353 g->set_data (X_("owner"), owner);
354 groups.push_back (g);
356 /* this is one of the places where our own Action management code
357 has to touch the GTK one, because we want the GtkUIManager to
358 be able to create widgets (particularly Menus) from our actions.
360 This is a a necessary step for that to happen.
364 ActionManager::ui_manager->insert_action_group (g);
371 ActionManager::get_action_group (string const & name)
373 for (ActionGroups::iterator g = groups.begin(); g != groups.end(); ++g) {
374 if ((*g)->get_name () == name) {
379 return RefPtr<ActionGroup> ();
383 ActionManager::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
387 RefPtr<Action> act = Action::create (name, label);
389 fullpath = group->get_name();
393 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
398 /* already registered */
399 return RefPtr<Action> ();
403 ActionManager::register_action (RefPtr<ActionGroup> group,
404 const char* name, const char* label,
409 RefPtr<Action> act = Action::create (name, label);
411 fullpath = group->get_name();
415 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
416 group->add (act, sl);
420 /* already registered */
421 return RefPtr<Action>();
425 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
426 Gtk::RadioAction::Group& rgroup,
427 const char* name, const char* label,
432 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
433 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
435 fullpath = group->get_name();
439 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
440 group->add (act, sl);
444 /* already registered */
445 return RefPtr<Action>();
449 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
450 Gtk::RadioAction::Group& rgroup,
451 const char* name, const char* label,
452 sigc::slot<void,GtkAction*> sl,
457 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
458 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
459 ract->property_value() = value;
461 fullpath = group->get_name();
465 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
466 group->add (act, sigc::bind (sl, act->gobj()));
470 /* already registered */
472 return RefPtr<Action>();
476 ActionManager::register_toggle_action (RefPtr<ActionGroup> group,
477 const char* name, const char* label, sigc::slot<void> sl)
481 fullpath = group->get_name();
485 RefPtr<Action> act = ToggleAction::create (name, label);
487 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
488 group->add (act, sl);
492 /* already registered */
493 return RefPtr<Action>();
497 ActionManager::get_actions (void* owner, std::vector<Glib::RefPtr<Gtk::Action> >& acts)
499 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
501 Glib::RefPtr<Gtk::ActionGroup> group = a->second->property_action_group ();
502 if (group->get_data (X_("owner")) == owner) {
503 acts.push_back (a->second);
506 acts.push_back (a->second);
512 ActionManager::get_all_actions (std::vector<std::string>& paths,
513 std::vector<std::string>& labels,
514 std::vector<std::string>& tooltips,
515 std::vector<std::string>& keys,
516 std::vector<RefPtr<Action> >& acts)
518 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
520 Glib::RefPtr<Action> act = a->second;
522 paths.push_back (act->get_accel_path());
523 labels.push_back (act->get_label());
524 tooltips.push_back (act->get_tooltip());
525 acts.push_back (act);
527 /* foreach binding */
530 Bindings* bindings = (*map)->bindings();
535 Bindings::Operation op;
537 key = bindings->get_binding_for_action (*act, op);
539 if (key == KeyboardKey::null_key()) {
540 keys.push_back (string());
542 keys.push_back (key.display_label());
545 keys.push_back (string());