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::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
368 RefPtr<Action> act = Action::create (name, label);
370 fullpath = group->get_name();
374 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
379 /* already registered */
380 return RefPtr<Action> ();
384 ActionManager::register_action (RefPtr<ActionGroup> group,
385 const char* name, const char* label, sigc::slot<void> sl)
389 RefPtr<Action> act = Action::create (name, label);
391 fullpath = group->get_name();
395 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
396 group->add (act, sl);
400 /* already registered */
401 return RefPtr<Action>();
405 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
406 Gtk::RadioAction::Group& rgroup,
407 const char* name, const char* label,
412 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
413 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
415 fullpath = group->get_name();
419 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
420 group->add (act, sl);
424 /* already registered */
425 return RefPtr<Action>();
429 ActionManager::register_radio_action (RefPtr<ActionGroup> group,
430 Gtk::RadioAction::Group& rgroup,
431 const char* name, const char* label,
432 sigc::slot<void,GtkAction*> sl,
437 RefPtr<Action> act = RadioAction::create (rgroup, name, label);
438 RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
439 ract->property_value() = value;
441 fullpath = group->get_name();
445 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
446 group->add (act, sigc::bind (sl, act->gobj()));
450 /* already registered */
452 return RefPtr<Action>();
456 ActionManager::register_toggle_action (RefPtr<ActionGroup> group,
457 const char* name, const char* label, sigc::slot<void> sl)
461 fullpath = group->get_name();
465 RefPtr<Action> act = ToggleAction::create (name, label);
467 if (actions.insert (ActionMap::value_type (fullpath, act)).second) {
468 group->add (act, sl);
472 /* already registered */
473 return RefPtr<Action>();
477 ActionManager::get_all_actions (std::vector<std::string>& paths,
478 std::vector<std::string>& labels,
479 std::vector<std::string>& tooltips,
480 std::vector<std::string>& keys,
481 std::vector<RefPtr<Action> >& acts)
483 for (ActionMap::const_iterator a = actions.begin(); a != actions.end(); ++a) {
485 Glib::RefPtr<Action> act = a->second;
487 paths.push_back (act->get_accel_path());
488 labels.push_back (act->get_label());
489 tooltips.push_back (act->get_tooltip());
490 acts.push_back (act);
492 /* foreach binding */
495 Bindings* bindings = (*map)->bindings();
500 Bindings::Operation op;
502 key = bindings->get_binding_for_action (*act, op);
504 if (key == KeyboardKey::null_key()) {
505 keys.push_back (string());
507 keys.push_back (key.display_label());
510 keys.push_back (string());