create a two-way association between an action map and a bindings object, rather...
[ardour.git] / libs / gtkmm2ext / bindings.cc
1 /*
2     Copyright (C) 2012 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <iostream>
21
22 #include "pbd/gstdio_compat.h"
23 #include <gtkmm/accelmap.h>
24 #include <gtkmm/uimanager.h>
25
26 #include "pbd/convert.h"
27 #include "pbd/debug.h"
28 #include "pbd/error.h"
29 #include "pbd/xml++.h"
30
31 #include "gtkmm2ext/actions.h"
32 #include "gtkmm2ext/bindings.h"
33 #include "gtkmm2ext/debug.h"
34 #include "gtkmm2ext/keyboard.h"
35 #include "gtkmm2ext/utils.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace Glib;
41 using namespace Gtk;
42 using namespace Gtkmm2ext;
43 using namespace PBD;
44
45 list<Bindings*> Bindings::bindings; /* global. Gulp */
46 uint32_t Bindings::_ignored_state = 0;
47 list<ActionMap*> ActionMap::action_maps; /* global. Gulp */
48 PBD::Signal1<void,Bindings*> Bindings::BindingsChanged;
49
50 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
51 {
52         uint32_t ignore = Bindings::ignored_state();
53
54         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
55                 /* key is not subject to case, so ignore SHIFT
56                  */
57                 ignore |= GDK_SHIFT_MASK;
58         }
59
60         _val = (state & ~ignore);
61         _val <<= 32;
62         _val |= keycode;
63 };
64
65 bool
66 MouseButton::make_button (const string& str, MouseButton& b)
67 {
68         int s = 0;
69
70         if (str.find ("Primary") != string::npos) {
71                 s |= Keyboard::PrimaryModifier;
72         }
73
74         if (str.find ("Secondary") != string::npos) {
75                 s |= Keyboard::SecondaryModifier;
76         }
77
78         if (str.find ("Tertiary") != string::npos) {
79                 s |= Keyboard::TertiaryModifier;
80         }
81
82         if (str.find ("Level4") != string::npos) {
83                 s |= Keyboard::Level4Modifier;
84         }
85
86         string::size_type lastmod = str.find_last_of ('-');
87         uint32_t button_number;
88
89         if (lastmod == string::npos) {
90                 button_number = PBD::atoi (str);
91         } else {
92                 button_number = PBD::atoi (str.substr (lastmod+1));
93         }
94
95         b = MouseButton (s, button_number);
96         return true;
97 }
98
99 string
100 MouseButton::name () const
101 {
102         int s = state();
103
104         string str;
105
106         if (s & Keyboard::PrimaryModifier) {
107                 str += "Primary";
108         }
109         if (s & Keyboard::SecondaryModifier) {
110                 if (!str.empty()) {
111                         str += '-';
112                 }
113                 str += "Secondary";
114         }
115         if (s & Keyboard::TertiaryModifier) {
116                 if (!str.empty()) {
117                         str += '-';
118                 }
119                 str += "Tertiary";
120         }
121         if (s & Keyboard::Level4Modifier) {
122                 if (!str.empty()) {
123                         str += '-';
124                 }
125                 str += "Level4";
126         }
127
128         if (!str.empty()) {
129                 str += '-';
130         }
131
132         char buf[16];
133         snprintf (buf, sizeof (buf), "%u", button());
134         str += buf;
135
136         return str;
137 }
138
139 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
140 {
141         uint32_t ignore = Bindings::ignored_state();
142
143         _val = (state & ~ignore);
144         _val <<= 32;
145         _val |= keycode;
146 }
147
148 string
149 KeyboardKey::display_label () const
150 {
151         if (key() == 0) {
152                 return string();
153         }
154
155         /* This magically returns a string that will display the right thing
156          *  on all platforms, notably the command key on OS X.
157          */
158         
159         return gtk_accelerator_get_label (key(), (GdkModifierType) state());
160 }
161
162 string
163 KeyboardKey::name () const
164 {
165         int s = state();
166
167         string str;
168
169         if (s & Keyboard::PrimaryModifier) {
170                 str += "Primary";
171         }
172         if (s & Keyboard::SecondaryModifier) {
173                 if (!str.empty()) {
174                         str += '-';
175                 }
176                 str += "Secondary";
177         }
178         if (s & Keyboard::TertiaryModifier) {
179                 if (!str.empty()) {
180                         str += '-';
181                 }
182                 str += "Tertiary";
183         }
184         if (s & Keyboard::Level4Modifier) {
185                 if (!str.empty()) {
186                         str += '-';
187                 }
188                 str += "Level4";
189         }
190
191         if (!str.empty()) {
192                 str += '-';
193         }
194
195         char const *gdk_name = gdk_keyval_name (key());
196
197         if (gdk_name) {
198                 str += gdk_name;
199         } else {
200                 /* fail! */
201                 return string();
202         }
203                 
204         return str;
205 }
206
207 bool
208 KeyboardKey::make_key (const string& str, KeyboardKey& k)
209 {
210         int s = 0;
211
212         if (str.find ("Primary") != string::npos) {
213                 s |= Keyboard::PrimaryModifier;
214         }
215
216         if (str.find ("Secondary") != string::npos) {
217                 s |= Keyboard::SecondaryModifier;
218         }
219
220         if (str.find ("Tertiary") != string::npos) {
221                 s |= Keyboard::TertiaryModifier;
222         }
223
224         if (str.find ("Level4") != string::npos) {
225                 s |= Keyboard::Level4Modifier;
226         }
227
228         string::size_type lastmod = str.find_last_of ('-');
229         guint keyval;
230         
231         if (lastmod == string::npos) {
232                 keyval = gdk_keyval_from_name (str.c_str());
233         } else {
234                 keyval = gdk_keyval_from_name (str.substr (lastmod+1).c_str());
235         }
236
237         if (keyval == GDK_VoidSymbol || keyval == 0) {
238                 return false;
239         }
240
241         k = KeyboardKey (s, keyval);
242
243         return true;
244 }
245
246 Bindings::Bindings (std::string const& name)
247         : _name (name)
248         , _action_map (0)
249 {
250         bindings.push_back (this);
251 }
252
253 Bindings::~Bindings()
254 {
255         bindings.remove (this);
256 }
257
258 string
259 Bindings::ardour_action_name (RefPtr<Action> action)
260 {
261         /* Skip "<Actions>/" */
262         return action->get_accel_path ().substr (10);
263 }
264
265 KeyboardKey
266 Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
267 {
268         const string action_name = ardour_action_name (action);
269         
270         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
271
272                 /* option one: action has already been associated with the
273                  * binding
274                  */
275
276                 if (k->second.action == action) {
277                         return k->first;
278                 }
279
280                 /* option two: action name matches, so lookup the action,
281                  * setup the association while we're here, and return the binding.
282                  */
283
284                 if (_action_map && k->second.action_name == action_name) {
285                         k->second.action = _action_map->find_action (action_name);
286                         return k->first;
287                 }
288                  
289         }
290
291         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
292                 
293                 /* option one: action has already been associated with the
294                  * binding
295                  */
296
297                 if (k->second.action == action) {
298                         return k->first;
299                 }
300
301                 /* option two: action name matches, so lookup the action,
302                  * setup the association while we're here, and return the binding.
303                  */
304
305                 if (_action_map && k->second.action_name == action_name) {
306                          k->second.action = _action_map->find_action (action_name);
307                          return k->first;
308                  }
309                  
310         }
311         
312         return KeyboardKey::null_key();
313 }
314
315 void
316 Bindings::set_action_map (ActionMap& actions)
317 {
318         if (_action_map) {
319                 _action_map->set_bindings (0);
320         }
321         
322         _action_map = &actions;
323         _action_map->set_bindings (this);
324         
325         dissociate ();
326         associate ();
327 }
328
329 bool
330 Bindings::empty_keys() const
331 {
332         return press_bindings.empty() && release_bindings.empty();
333 }
334
335 bool
336 Bindings::empty_mouse () const
337 {
338         return button_press_bindings.empty() && button_release_bindings.empty();
339 }
340
341 bool
342 Bindings::empty() const
343 {
344         return empty_keys() && empty_mouse ();
345 }
346
347 bool
348 Bindings::activate (KeyboardKey kb, Operation op)
349 {
350         KeybindingMap* kbm = 0;
351
352         switch (op) {
353         case Press:
354                 kbm = &press_bindings;
355                 break;
356         case Release:
357                 kbm = &release_bindings;
358                 break;
359         }
360         
361         KeybindingMap::iterator k = kbm->find (kb);
362
363         if (k == kbm->end()) {
364                 /* no entry for this key in the state map */
365                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("no binding for %1\n", kb));
366                 return false;
367         }
368
369         RefPtr<Action> action;
370         
371         if (k->second.action) {
372                 action = k->second.action;
373         } else {
374                 if (_action_map) {
375                         action = _action_map->find_action (k->second.action_name);
376                 }
377         }
378
379         if (action) {
380                 /* lets do it ... */
381                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", kb, k->second.action_name));
382                 action->activate ();
383         }
384
385         /* return true even if the action could not be found */
386
387         return true;
388 }
389
390 void
391 Bindings::associate ()
392 {
393         KeybindingMap::iterator k;
394
395         if (!_action_map) {
396                 return;
397         }
398
399         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
400                 k->second.action = _action_map->find_action (k->second.action_name);
401                 if (k->second.action) {
402                         push_to_gtk (k->first, k->second.action);
403                 } else {
404                         cerr << _name << " didn't find " << k->second.action_name << " in " << _action_map->name() << endl;
405                 }
406         }
407
408         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
409                 k->second.action = _action_map->find_action (k->second.action_name);
410                 /* no working support in GTK for release bindings */
411         }
412
413         MouseButtonBindingMap::iterator b;
414         
415         for (b = button_press_bindings.begin(); b != button_press_bindings.end(); ++b) {
416                 b->second.action = _action_map->find_action (b->second.action_name);
417         }
418
419         for (b = button_release_bindings.begin(); b != button_release_bindings.end(); ++b) {
420                 b->second.action = _action_map->find_action (b->second.action_name);
421         }
422 }
423
424 void
425 Bindings::dissociate ()
426 {
427         KeybindingMap::iterator k;
428
429         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
430                 k->second.action.clear ();
431         }
432         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
433                 k->second.action.clear ();
434         }
435 }
436
437 void
438 Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
439 {
440         /* GTK has the useful feature of showing key bindings for actions in
441          * menus. As of August 2015, we have no interest in trying to
442          * reimplement this functionality, so we will use it even though we no
443          * longer use GTK accelerators for handling key events. To do this, we
444          * need to make sure that there is a fully populated GTK AccelMap set
445          * up with all bindings/actions. 
446          */
447
448         uint32_t gtk_legal_keyval = kb.key();
449         possibly_translate_keyval_to_make_legal_accelerator (gtk_legal_keyval);
450         KeyboardKey gtk_binding (kb.state(), gtk_legal_keyval);
451         Gtk::AccelKey gtk_key;
452         
453         bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key);
454
455         if (!entry_exists) {
456
457                 /* there is a trick happening here. It turns out that
458                  * gtk_accel_map_add_entry() performs no validation checks on
459                  * the accelerator keyval. This means we can use it to define
460                  * ANY accelerator, even if they violate GTK's rules
461                  * (e.g. about not using navigation keys). This works ONLY when
462                  * the entry in the GTK accelerator map has not already been
463                  * added. The entries will be added by the GTK UIManager when
464                  * building menus, so this code must be called before that
465                  * happens.
466                  */
467
468                 Gtk::AccelMap::add_entry (what->get_accel_path(), gtk_binding.key(), (Gdk::ModifierType) gtk_binding.state());
469         }
470 }
471
472 bool
473 Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
474 {
475         if (!_action_map) {
476                 return false;
477         }
478
479         /* We have to search the existing binding map by both action and
480          * keybinding, because the following are possible:
481          *
482          *   - key is already used for a different action
483          *   - action has a different binding
484          *   - key is not used
485          *   - action is not bound
486          */
487         
488         RefPtr<Action> action = _action_map->find_action (action_name);
489
490         if (!action) {
491                 return false;
492         }
493
494         KeybindingMap* kbm = 0;
495
496         switch (op) {
497         case Press:
498                 kbm = &press_bindings;
499                 break;
500         case Release:
501                 kbm = &release_bindings;
502                 break;
503         }
504
505         KeybindingMap::iterator k = kbm->find (kb);
506
507         if (k != kbm->end()) {
508                 kbm->erase (k);
509         }
510
511         /* now linear search by action */
512
513         for (k = kbm->begin(); k != kbm->end(); ++k) {
514                 if (k->second.action_name == action_name) {
515                         kbm->erase (k);
516                         break;
517                 }
518         }
519
520         add (kb, op, action_name, can_save);
521
522         /* for now, this never fails */
523         
524         return true;
525 }
526
527 void
528 Bindings::add (KeyboardKey kb, Operation op, string const& action_name, bool can_save)
529 {
530         KeybindingMap* kbm = 0;
531
532         switch (op) {
533         case Press:
534                 kbm = &press_bindings;
535                 break;
536         case Release:
537                 kbm = &release_bindings;
538                 break;
539         }
540
541         KeybindingMap::iterator k = kbm->find (kb);
542
543         if (k != kbm->end()) {
544                 kbm->erase (k);
545         } 
546         KeybindingMap::value_type new_pair (kb, ActionInfo (action_name));
547         
548         kbm->insert (new_pair).first;
549
550         if (can_save) {
551                 Keyboard::keybindings_changed ();
552         }
553
554         BindingsChanged (this); /* EMIT SIGNAL */
555 }
556
557 void
558 Bindings::remove (KeyboardKey kb, Operation op, bool can_save)
559 {
560         KeybindingMap* kbm = 0;
561
562         switch (op) {
563         case Press:
564                 kbm = &press_bindings;
565                 break;
566         case Release:
567                 kbm = &release_bindings;
568                 break;
569         }
570
571         KeybindingMap::iterator k = kbm->find (kb);
572
573         if (k != kbm->end()) {
574                 kbm->erase (k);
575         }
576
577         if (can_save) {
578                 Keyboard::keybindings_changed ();
579         }
580
581         BindingsChanged (this); /* EMIT SIGNAL */
582 }
583
584 void
585 Bindings::remove (RefPtr<Action> action, Operation op, bool can_save)
586 {
587         KeybindingMap* kbm = 0;
588
589         switch (op) {
590         case Press:
591                 kbm = &press_bindings;
592                 break;
593         case Release:
594                 kbm = &release_bindings;
595                 break;
596         }
597
598         for (KeybindingMap::iterator k = kbm->begin(); k != kbm->end(); ++k) {
599                 if (k->second.action == action) {
600                         kbm->erase (k);
601                         break;
602                 }
603         }
604
605         if (can_save) {
606                 Keyboard::keybindings_changed ();
607         }
608
609         BindingsChanged (this); /* EMIT SIGNAL */
610 }
611
612 bool
613 Bindings::activate (MouseButton bb, Operation op)
614 {
615         MouseButtonBindingMap* bbm = 0;
616
617         switch (op) {
618         case Press:
619                 bbm = &button_press_bindings;
620                 break;
621         case Release:
622                 bbm = &button_release_bindings;
623                 break;
624         }
625
626         MouseButtonBindingMap::iterator b = bbm->find (bb);
627
628         if (b == bbm->end()) {
629                 /* no entry for this key in the state map */
630                 return false;
631         }
632
633         RefPtr<Action> action;
634         
635         if (b->second.action) {
636                 action = b->second.action;
637         } else {
638                 if (_action_map) {
639                         action = _action_map->find_action (b->second.action_name);
640                 }
641         }
642
643         if (action) {
644                 /* lets do it ... */
645                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("activating action %1\n", ardour_action_name (action)));
646                 action->activate ();
647         }
648
649         /* return true even if the action could not be found */
650
651         return true;
652 }
653
654 void
655 Bindings::add (MouseButton bb, Operation op, string const& action_name)
656 {
657         MouseButtonBindingMap* bbm = 0;
658
659         switch (op) {
660         case Press:
661                 bbm = &button_press_bindings;
662                 break;
663         case Release:
664                 bbm = &button_release_bindings;
665                 break;
666         }
667
668         MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
669         bbm->insert (newpair);
670 }
671
672 void
673 Bindings::remove (MouseButton bb, Operation op)
674 {
675         MouseButtonBindingMap* bbm = 0;
676
677         switch (op) {
678         case Press:
679                 bbm = &button_press_bindings;
680                 break;
681         case Release:
682                 bbm = &button_release_bindings;
683                 break;
684         }
685
686         MouseButtonBindingMap::iterator b = bbm->find (bb);
687
688         if (b != bbm->end()) {
689                 bbm->erase (b);
690         }
691 }
692
693 void
694 Bindings::save (XMLNode& root)
695 {
696         XMLNode* presses = new XMLNode (X_("Press"));
697
698         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
699                 XMLNode* child;
700
701                 if (k->first.name().empty()) {
702                         continue;
703                 }
704
705                 child = new XMLNode (X_("Binding"));
706                 child->add_property (X_("key"), k->first.name());
707                 child->add_property (X_("action"), k->second.action_name);
708                 presses->add_child_nocopy (*child);
709         }
710
711         for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
712                 XMLNode* child;
713                 child = new XMLNode (X_("Binding"));
714                 child->add_property (X_("button"), k->first.name());
715                 child->add_property (X_("action"), k->second.action_name);
716                 presses->add_child_nocopy (*child);
717         }
718
719         XMLNode* releases = new XMLNode (X_("Release"));
720
721         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
722                 XMLNode* child;
723
724                 if (k->first.name().empty()) {
725                         continue;
726                 }
727
728                 child = new XMLNode (X_("Binding"));
729                 child->add_property (X_("key"), k->first.name());
730                 child->add_property (X_("action"), k->second.action_name);
731                 releases->add_child_nocopy (*child);
732         }
733
734         for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
735                 XMLNode* child;
736                 child = new XMLNode (X_("Binding"));
737                 child->add_property (X_("button"), k->first.name());
738                 child->add_property (X_("action"), k->second.action_name);
739                 releases->add_child_nocopy (*child);
740         }
741
742         root.add_child_nocopy (*presses);
743         root.add_child_nocopy (*releases);
744 }
745
746 bool
747 Bindings::load (XMLNode const& node)
748 {
749         const XMLNodeList& children (node.children());
750         
751         press_bindings.clear ();
752         release_bindings.clear ();
753
754         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
755                 /* each node could be Press or Release */
756                 load_operation (**i);
757         }
758
759         return true;
760 }
761
762 void
763 Bindings::load_operation (XMLNode const& node)
764 {
765         if (node.name() == X_("Press") || node.name() == X_("Release")) {
766
767                 Operation op;
768
769                 if (node.name() == X_("Press")) {
770                         op = Press;
771                 } else {
772                         op = Release;
773                 }
774
775                 const XMLNodeList& children (node.children());
776
777                 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
778
779                         XMLProperty* ap;
780                         XMLProperty* kp;
781                         XMLProperty* bp;
782
783                         ap = (*p)->property ("action");
784                         kp = (*p)->property ("key");
785                         bp = (*p)->property ("button");
786
787                         if (!ap || (!kp && !bp)) {
788                                 continue;
789                         }
790
791                         if (kp) {
792                                 KeyboardKey k;
793                                 if (!KeyboardKey::make_key (kp->value(), k)) {
794                                         continue;
795                                 }
796                                 add (k, op, ap->value());
797                         } else {
798                                 MouseButton b;
799                                 if (!MouseButton::make_button (bp->value(), b)) {
800                                         continue;
801                                 }
802                                 add (b, op, ap->value());
803                         }
804                 }
805         }
806 }
807
808 void
809 Bindings::get_all_actions (std::vector<std::string>& paths,
810                            std::vector<std::string>& labels,
811                            std::vector<std::string>& tooltips,
812                            std::vector<std::string>& keys,
813                            std::vector<RefPtr<Action> >& actions)
814 {
815         if (!_action_map) {
816                 return;
817         }
818
819         /* build a reverse map from actions to bindings */
820
821         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
822         ReverseMap rmap;
823
824         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
825                 rmap.insert (make_pair (k->second.action, k->first));
826         }
827
828         /* get a list of all actions */
829
830         ActionMap::Actions all_actions;
831         _action_map->get_actions (all_actions);
832         
833         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
834
835                 paths.push_back ((*act)->get_accel_path());
836                 labels.push_back ((*act)->get_label());
837                 tooltips.push_back ((*act)->get_tooltip());
838
839                 ReverseMap::iterator r = rmap.find (*act);
840
841                 if (r != rmap.end()) {
842                         keys.push_back (r->second.display_label());
843                 } else {
844                         keys.push_back (string());
845                 }
846
847                 actions.push_back (*act);
848         }
849 }
850
851 void
852 Bindings::get_all_actions (std::vector<std::string>& names,
853                            std::vector<std::string>& paths,
854                            std::vector<std::string>& keys)
855 {
856         if (!_action_map) {
857                 return;
858         }
859
860         /* build a reverse map from actions to bindings */
861
862         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
863         ReverseMap rmap;
864
865         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
866                 rmap.insert (make_pair (k->second.action, k->first));
867         }
868
869         /* get a list of all actions */
870
871         ActionMap::Actions all_actions;
872         _action_map->get_actions (all_actions);
873         
874         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
875                 
876                 names.push_back ((*act)->get_name());
877                 paths.push_back ((*act)->get_accel_path());
878
879                 ReverseMap::iterator r = rmap.find (*act);
880                 if (r != rmap.end()) {
881                         keys.push_back (r->second.display_label());
882                 } else {
883                         keys.push_back (string());
884                 }
885         }
886 }
887
888 Bindings*
889 Bindings::get_bindings (string const& name, ActionMap& map)
890 {
891         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
892                 if ((*b)->name() == name) {
893                         (*b)->set_action_map (map);
894                         return *b;
895                 }
896         }
897
898         return 0;
899 }
900
901 void
902 Bindings::associate_all ()
903 {
904         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
905                 (*b)->associate ();
906         }
907 }
908
909 /*==========================================ACTION MAP =========================================*/
910
911 ActionMap::ActionMap (string const & name)
912         : _name (name)
913         , _bindings (0)
914 {
915         action_maps.push_back (this);
916 }
917
918 ActionMap::~ActionMap ()
919 {
920         action_maps.remove (this);
921 }
922
923 void
924 ActionMap::set_bindings (Bindings* b)
925 {
926         _bindings = b;
927 }
928
929 void
930 ActionMap::get_actions (ActionMap::Actions& acts)
931 {
932         for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
933                 acts.push_back (a->second);
934         }
935 }
936
937 RefPtr<Action>
938 ActionMap::find_action (const string& name)
939 {
940         _ActionMap::iterator a = _actions.find (name);
941
942         if (a != _actions.end()) {
943                 return a->second;
944         }
945
946         return RefPtr<Action>();
947 }
948
949 RefPtr<ActionGroup>
950 ActionMap::create_action_group (const string& name)
951 {
952         RefPtr<ActionGroup> g = ActionGroup::create (name);
953
954         /* this is one of the places where our own Action management code
955            has to touch the GTK one, because we want the GtkUIManager to
956            be able to create widgets (particularly Menus) from our actions.
957            
958            This is a a necessary step for that to happen.
959         */
960         
961         if (g) {
962                 ActionManager::ui_manager->insert_action_group (g);
963         }
964
965         return g;
966 }
967
968 RefPtr<Action> 
969 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
970 {
971         string fullpath;
972
973         RefPtr<Action> act = Action::create (name, label);
974
975         fullpath = group->get_name();
976         fullpath += '/';
977         fullpath += name;
978         
979         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
980                 group->add (act);
981                 return act;
982         }
983
984         /* already registered */
985         return RefPtr<Action> ();
986 }
987
988 RefPtr<Action> 
989 ActionMap::register_action (RefPtr<ActionGroup> group,
990                             const char* name, const char* label, sigc::slot<void> sl)
991 {
992         string fullpath;
993
994         RefPtr<Action> act = Action::create (name, label);
995
996         fullpath = group->get_name();
997         fullpath += '/';
998         fullpath += name;
999
1000         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1001                 group->add (act, sl);
1002                 return act;
1003         }
1004
1005         /* already registered */
1006         return RefPtr<Action>();
1007 }
1008
1009 RefPtr<Action> 
1010 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1011                                   Gtk::RadioAction::Group& rgroup,
1012                                   const char* name, const char* label, 
1013                                   sigc::slot<void> sl)
1014 {
1015         string fullpath;
1016
1017         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1018         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1019         
1020         fullpath = group->get_name();
1021         fullpath += '/';
1022         fullpath += name;
1023
1024         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1025                 group->add (act, sl);
1026                 return act;
1027         }
1028
1029         /* already registered */
1030         return RefPtr<Action>();
1031 }
1032
1033 RefPtr<Action> 
1034 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1035                                   Gtk::RadioAction::Group& rgroup,
1036                                   const char* name, const char* label, 
1037                                   sigc::slot<void,GtkAction*> sl,
1038                                   int value)
1039 {
1040         string fullpath;
1041
1042         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1043         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1044         ract->property_value() = value;
1045
1046         fullpath = group->get_name();
1047         fullpath += '/';
1048         fullpath += name;
1049
1050         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1051                 group->add (act, sigc::bind (sl, act->gobj()));
1052                 return act;
1053         }
1054
1055         /* already registered */
1056
1057         return RefPtr<Action>();
1058 }
1059
1060 RefPtr<Action> 
1061 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1062                                    const char* name, const char* label, sigc::slot<void> sl)
1063 {
1064         string fullpath;
1065
1066         fullpath = group->get_name();
1067         fullpath += '/';
1068         fullpath += name;
1069
1070         RefPtr<Action> act = ToggleAction::create (name, label);
1071
1072         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1073                 group->add (act, sl);
1074                 return act;
1075         }
1076
1077         /* already registered */
1078         return RefPtr<Action>();
1079 }
1080
1081 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1082         char const *gdk_name = gdk_keyval_name (k.key());
1083         return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state " << k.state();
1084 }
1085