add API to query name of bound action
[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/replace_all.h"
30 #include "pbd/xml++.h"
31
32 #include "gtkmm2ext/actions.h"
33 #include "gtkmm2ext/bindings.h"
34 #include "gtkmm2ext/debug.h"
35 #include "gtkmm2ext/keyboard.h"
36 #include "gtkmm2ext/utils.h"
37
38 #include "pbd/i18n.h"
39
40 using namespace std;
41 using namespace Glib;
42 using namespace Gtk;
43 using namespace Gtkmm2ext;
44 using namespace PBD;
45
46 list<Bindings*> Bindings::bindings; /* global. Gulp */
47 list<ActionMap*> ActionMap::action_maps; /* global. Gulp */
48 PBD::Signal1<void,Bindings*> Bindings::BindingsChanged;
49
50 template <typename IteratorValueType>
51 struct ActionNameRegistered
52 {
53         ActionNameRegistered(std::string const& name)
54                 : action_name(name)
55         {}
56
57         bool operator()(IteratorValueType elem) const {
58                 return elem.second.action_name == action_name;
59         }
60         std::string const& action_name;
61 };
62
63 MouseButton::MouseButton (uint32_t state, uint32_t keycode)
64 {
65         uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
66
67         /* this is a slightly wierd test that relies on
68          * gdk_keyval_is_{upper,lower}() returning true for keys that have no
69          * case-sensitivity. This covers mostly non-alphanumeric keys.
70          */
71
72         if (gdk_keyval_is_upper (keycode) && gdk_keyval_is_lower (keycode)) {
73                 /* key is not subject to case, so ignore SHIFT
74                  */
75                 ignore |= GDK_SHIFT_MASK;
76         }
77
78         _val = (state & ~ignore);
79         _val <<= 32;
80         _val |= keycode;
81 };
82
83 bool
84 MouseButton::make_button (const string& str, MouseButton& b)
85 {
86         int s = 0;
87
88         if (str.find ("Primary") != string::npos) {
89                 s |= Keyboard::PrimaryModifier;
90         }
91
92         if (str.find ("Secondary") != string::npos) {
93                 s |= Keyboard::SecondaryModifier;
94         }
95
96         if (str.find ("Tertiary") != string::npos) {
97                 s |= Keyboard::TertiaryModifier;
98         }
99
100         if (str.find ("Level4") != string::npos) {
101                 s |= Keyboard::Level4Modifier;
102         }
103
104         string::size_type lastmod = str.find_last_of ('-');
105         uint32_t button_number;
106
107         if (lastmod == string::npos) {
108                 button_number = PBD::atoi (str);
109         } else {
110                 button_number = PBD::atoi (str.substr (lastmod+1));
111         }
112
113         b = MouseButton (s, button_number);
114         return true;
115 }
116
117 string
118 MouseButton::name () const
119 {
120         int s = state();
121
122         string str;
123
124         if (s & Keyboard::PrimaryModifier) {
125                 str += "Primary";
126         }
127         if (s & Keyboard::SecondaryModifier) {
128                 if (!str.empty()) {
129                         str += '-';
130                 }
131                 str += "Secondary";
132         }
133         if (s & Keyboard::TertiaryModifier) {
134                 if (!str.empty()) {
135                         str += '-';
136                 }
137                 str += "Tertiary";
138         }
139         if (s & Keyboard::Level4Modifier) {
140                 if (!str.empty()) {
141                         str += '-';
142                 }
143                 str += "Level4";
144         }
145
146         if (!str.empty()) {
147                 str += '-';
148         }
149
150         char buf[16];
151         snprintf (buf, sizeof (buf), "%u", button());
152         str += buf;
153
154         return str;
155 }
156
157 /*================================ KeyboardKey ================================*/
158 KeyboardKey::KeyboardKey (uint32_t state, uint32_t keycode)
159 {
160         uint32_t ignore = ~Keyboard::RelevantModifierKeyMask;
161
162         _val = (state & ~ignore);
163         _val <<= 32;
164         _val |= keycode;
165 }
166
167 string
168 KeyboardKey::display_label () const
169 {
170         if (key() == 0) {
171                 return string();
172         }
173
174         /* This magically returns a string that will display the right thing
175          *  on all platforms, notably the command key on OS X.
176          */
177
178         uint32_t mod = state();
179
180         return gtk_accelerator_get_label (key(), (GdkModifierType) mod);
181 }
182
183 string
184 KeyboardKey::name () const
185 {
186         int s = state();
187
188         string str;
189
190         if (s & Keyboard::PrimaryModifier) {
191                 str += "Primary";
192         }
193         if (s & Keyboard::SecondaryModifier) {
194                 if (!str.empty()) {
195                         str += '-';
196                 }
197                 str += "Secondary";
198         }
199         if (s & Keyboard::TertiaryModifier) {
200                 if (!str.empty()) {
201                         str += '-';
202                 }
203                 str += "Tertiary";
204         }
205         if (s & Keyboard::Level4Modifier) {
206                 if (!str.empty()) {
207                         str += '-';
208                 }
209                 str += "Level4";
210         }
211
212         if (!str.empty()) {
213                 str += '-';
214         }
215
216         char const *gdk_name = gdk_keyval_name (key());
217
218         if (gdk_name) {
219                 str += gdk_name;
220         } else {
221                 /* fail! */
222                 return string();
223         }
224
225         return str;
226 }
227
228 string
229 KeyboardKey::native_name () const
230 {
231         int s = state();
232
233         string str;
234
235         if (s & Keyboard::PrimaryModifier) {
236                 str += Keyboard::primary_modifier_name ();
237         }
238         if (s & Keyboard::SecondaryModifier) {
239                 if (!str.empty()) {
240                         str += '-';
241                 }
242                 str += Keyboard::secondary_modifier_name ();
243         }
244         if (s & Keyboard::TertiaryModifier) {
245                 if (!str.empty()) {
246                         str += '-';
247                 }
248                 str += Keyboard::tertiary_modifier_name ();
249         }
250         if (s & Keyboard::Level4Modifier) {
251                 if (!str.empty()) {
252                         str += '-';
253                 }
254                 str += Keyboard::level4_modifier_name ();
255         }
256
257         if (!str.empty()) {
258                 str += '-';
259         }
260
261         char const *gdk_name = gdk_keyval_name (key());
262
263         if (gdk_name) {
264                 str += gdk_name;
265         } else {
266                 /* fail! */
267                 return string();
268         }
269
270         return str;
271 }
272
273 string
274 KeyboardKey::native_short_name () const
275 {
276         int s = state();
277
278         string str;
279
280         if (s & Keyboard::PrimaryModifier) {
281                 str += Keyboard::primary_modifier_short_name ();
282         }
283         if (s & Keyboard::SecondaryModifier) {
284                 if (!str.empty()) {
285                         str += '-';
286                 }
287                 str += Keyboard::secondary_modifier_short_name ();
288         }
289         if (s & Keyboard::TertiaryModifier) {
290                 if (!str.empty()) {
291                         str += '-';
292                 }
293                 str += Keyboard::tertiary_modifier_short_name ();
294         }
295         if (s & Keyboard::Level4Modifier) {
296                 if (!str.empty()) {
297                         str += '-';
298                 }
299                 str += Keyboard::level4_modifier_short_name ();
300         }
301
302         if (!str.empty()) {
303                 str += '-';
304         }
305
306         char const *gdk_name = gdk_keyval_name (key());
307
308         if (gdk_name) {
309                 str += gdk_name;
310         } else {
311                 /* fail! */
312                 return string();
313         }
314
315         return str;
316 }
317
318 bool
319 KeyboardKey::make_key (const string& str, KeyboardKey& k)
320 {
321         int s = 0;
322
323         if (str.find ("Primary") != string::npos) {
324                 s |= Keyboard::PrimaryModifier;
325         }
326
327         if (str.find ("Secondary") != string::npos) {
328                 s |= Keyboard::SecondaryModifier;
329         }
330
331         if (str.find ("Tertiary") != string::npos) {
332                 s |= Keyboard::TertiaryModifier;
333         }
334
335         if (str.find ("Level4") != string::npos) {
336                 s |= Keyboard::Level4Modifier;
337         }
338
339         /* since all SINGLE key events keycodes are changed to lower case
340          * before looking them up, make sure we only store lower case here. The
341          * Shift part will be stored in the modifier part of the KeyboardKey.
342          *
343          * And yes Mildred, this doesn't cover CapsLock cases. Oh well.
344          */
345
346         string actual;
347
348         string::size_type lastmod = str.find_last_of ('-');
349
350         if (lastmod != string::npos) {
351                 actual = str.substr (lastmod+1);
352         }
353         else {
354                 actual = str;
355         }
356
357         if (actual.size() == 1) {
358                 actual = PBD::downcase (actual);
359         }
360
361         guint keyval;
362         keyval = gdk_keyval_from_name (actual.c_str());
363
364         if (keyval == GDK_VoidSymbol || keyval == 0) {
365                 return false;
366         }
367
368         k = KeyboardKey (s, keyval);
369
370         return true;
371 }
372
373 /*================================= Bindings =================================*/
374 Bindings::Bindings (std::string const& name)
375         : _name (name)
376         , _action_map (0)
377 {
378         bindings.push_back (this);
379 }
380
381 Bindings::~Bindings()
382 {
383         bindings.remove (this);
384 }
385
386 string
387 Bindings::ardour_action_name (RefPtr<Action> action)
388 {
389         /* Skip "<Actions>/" */
390         return action->get_accel_path ().substr (10);
391 }
392
393 KeyboardKey
394 Bindings::get_binding_for_action (RefPtr<Action> action, Operation& op)
395 {
396         const string action_name = ardour_action_name (action);
397
398         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
399
400                 /* option one: action has already been associated with the
401                  * binding
402                  */
403
404                 if (k->second.action == action) {
405                         return k->first;
406                 }
407
408                 /* option two: action name matches, so lookup the action,
409                  * setup the association while we're here, and return the binding.
410                  */
411
412                 if (_action_map && k->second.action_name == action_name) {
413                         k->second.action = _action_map->find_action (action_name);
414                         return k->first;
415                 }
416
417         }
418
419         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
420
421                 /* option one: action has already been associated with the
422                  * binding
423                  */
424
425                 if (k->second.action == action) {
426                         return k->first;
427                 }
428
429                 /* option two: action name matches, so lookup the action,
430                  * setup the association while we're here, and return the binding.
431                  */
432
433                 if (_action_map && k->second.action_name == action_name) {
434                         k->second.action = _action_map->find_action (action_name);
435                         return k->first;
436                 }
437
438         }
439
440         return KeyboardKey::null_key();
441 }
442
443 void
444 Bindings::set_action_map (ActionMap& actions)
445 {
446         if (_action_map) {
447                 _action_map->set_bindings (0);
448         }
449
450         _action_map = &actions;
451         _action_map->set_bindings (this);
452
453         dissociate ();
454         associate ();
455 }
456
457 bool
458 Bindings::empty_keys() const
459 {
460         return press_bindings.empty() && release_bindings.empty();
461 }
462
463 bool
464 Bindings::empty_mouse () const
465 {
466         return button_press_bindings.empty() && button_release_bindings.empty();
467 }
468
469 bool
470 Bindings::empty() const
471 {
472         return empty_keys() && empty_mouse ();
473 }
474
475 bool
476 Bindings::activate (KeyboardKey kb, Operation op)
477 {
478         KeybindingMap& kbm = get_keymap (op);
479
480         /* if shift was pressed, GDK will send us (e.g) 'E' rather than 'e'.
481            Our bindings all use the lower case character/keyname, so switch
482            to the lower case before doing the lookup.
483         */
484
485         KeyboardKey unshifted (kb.state(), gdk_keyval_to_lower (kb.key()));
486
487         KeybindingMap::iterator k = kbm.find (unshifted);
488
489         if (k == kbm.end()) {
490                 /* no entry for this key in the state map */
491                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("no binding for %1\n", unshifted));
492                 return false;
493         }
494
495         RefPtr<Action> action;
496
497         if (k->second.action) {
498                 action = k->second.action;
499         } else {
500                 if (_action_map) {
501                         action = _action_map->find_action (k->second.action_name);
502                 }
503         }
504
505         if (action) {
506                 /* lets do it ... */
507                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("binding for %1: %2\n", unshifted, k->second.action_name));
508                 action->activate ();
509         }
510
511         /* return true even if the action could not be found */
512
513         return true;
514 }
515
516 void
517 Bindings::associate ()
518 {
519         KeybindingMap::iterator k;
520
521         if (!_action_map) {
522                 return;
523         }
524
525         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
526                 k->second.action = _action_map->find_action (k->second.action_name);
527                 if (k->second.action) {
528                         push_to_gtk (k->first, k->second.action);
529                 } else {
530                         cerr << _name << " didn't find " << k->second.action_name << " in " << _action_map->name() << endl;
531                 }
532         }
533
534         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
535                 k->second.action = _action_map->find_action (k->second.action_name);
536                 /* no working support in GTK for release bindings */
537         }
538
539         MouseButtonBindingMap::iterator b;
540
541         for (b = button_press_bindings.begin(); b != button_press_bindings.end(); ++b) {
542                 b->second.action = _action_map->find_action (b->second.action_name);
543         }
544
545         for (b = button_release_bindings.begin(); b != button_release_bindings.end(); ++b) {
546                 b->second.action = _action_map->find_action (b->second.action_name);
547         }
548 }
549
550 void
551 Bindings::dissociate ()
552 {
553         KeybindingMap::iterator k;
554
555         for (k = press_bindings.begin(); k != press_bindings.end(); ++k) {
556                 k->second.action.clear ();
557         }
558         for (k = release_bindings.begin(); k != release_bindings.end(); ++k) {
559                 k->second.action.clear ();
560         }
561 }
562
563 void
564 Bindings::push_to_gtk (KeyboardKey kb, RefPtr<Action> what)
565 {
566         /* GTK has the useful feature of showing key bindings for actions in
567          * menus. As of August 2015, we have no interest in trying to
568          * reimplement this functionality, so we will use it even though we no
569          * longer use GTK accelerators for handling key events. To do this, we
570          * need to make sure that there is a fully populated GTK AccelMap set
571          * up with all bindings/actions.
572          */
573
574         Gtk::AccelKey gtk_key;
575         bool entry_exists = Gtk::AccelMap::lookup_entry (what->get_accel_path(), gtk_key);
576
577         if (!entry_exists) {
578
579                 /* there is a trick happening here. It turns out that
580                  * gtk_accel_map_add_entry() performs no validation checks on
581                  * the accelerator keyval. This means we can use it to define
582                  * ANY accelerator, even if they violate GTK's rules
583                  * (e.g. about not using navigation keys). This works ONLY when
584                  * the entry in the GTK accelerator map has not already been
585                  * added. The entries will be added by the GTK UIManager when
586                  * building menus, so this code must be called before that
587                  * happens.
588                  */
589
590
591                 int mod = kb.state();
592
593                 Gtk::AccelMap::add_entry (what->get_accel_path(), kb.key(), (Gdk::ModifierType) mod);
594         }
595 }
596
597 bool
598 Bindings::replace (KeyboardKey kb, Operation op, string const & action_name, bool can_save)
599 {
600         if (!_action_map) {
601                 return false;
602         }
603
604         if (is_registered(op, action_name)) {
605                 remove (op, action_name, can_save);
606         }
607
608         /* XXX need a way to get the old group name */
609         add (kb, op, action_name, 0, can_save);
610
611         return true;
612 }
613
614 bool
615 Bindings::add (KeyboardKey kb, Operation op, string const& action_name, XMLProperty const* group, bool can_save)
616 {
617         if (is_registered (op, action_name)) {
618                 return false;
619         }
620
621         KeybindingMap& kbm = get_keymap (op);
622         if (group) {
623                 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name, group->value()));
624                 (void) kbm.insert (new_pair).first;
625         } else {
626                 KeybindingMap::value_type new_pair = make_pair (kb, ActionInfo (action_name));
627                 (void) kbm.insert (new_pair).first;
628         }
629
630         DEBUG_TRACE (DEBUG::Bindings, string_compose ("add binding between %1 and %2, group [%3]\n",
631                                                       kb, action_name, (group ? group->value() : string())));
632
633         if (can_save) {
634                 Keyboard::keybindings_changed ();
635         }
636
637         BindingsChanged (this); /* EMIT SIGNAL */
638         return true;
639 }
640
641 bool
642 Bindings::remove (Operation op, std::string const& action_name, bool can_save)
643 {
644         bool erased_action = false;
645         KeybindingMap& kbm = get_keymap (op);
646         for (KeybindingMap::iterator k = kbm.begin(); k != kbm.end(); ++k) {
647                 if (k->second.action_name == action_name) {
648                         kbm.erase (k);
649                         erased_action = true;
650                         break;
651                 }
652         }
653
654         if (!erased_action) {
655                 return erased_action;
656         }
657
658         if (can_save) {
659                 Keyboard::keybindings_changed ();
660         }
661
662         BindingsChanged (this); /* EMIT SIGNAL */
663         return erased_action;
664 }
665
666
667 bool
668 Bindings::activate (MouseButton bb, Operation op)
669 {
670         MouseButtonBindingMap& bbm = get_mousemap(op);
671
672         MouseButtonBindingMap::iterator b = bbm.find (bb);
673
674         if (b == bbm.end()) {
675                 /* no entry for this key in the state map */
676                 return false;
677         }
678
679         RefPtr<Action> action;
680
681         if (b->second.action) {
682                 action = b->second.action;
683         } else {
684                 if (_action_map) {
685                         action = _action_map->find_action (b->second.action_name);
686                 }
687         }
688
689         if (action) {
690                 /* lets do it ... */
691                 DEBUG_TRACE (DEBUG::Bindings, string_compose ("activating action %1\n", ardour_action_name (action)));
692                 action->activate ();
693         }
694
695         /* return true even if the action could not be found */
696
697         return true;
698 }
699
700 void
701 Bindings::add (MouseButton bb, Operation op, string const& action_name, XMLProperty const* /*group*/)
702 {
703         MouseButtonBindingMap& bbm = get_mousemap(op);
704
705         MouseButtonBindingMap::value_type newpair (bb, ActionInfo (action_name));
706         bbm.insert (newpair);
707 }
708
709 void
710 Bindings::remove (MouseButton bb, Operation op)
711 {
712         MouseButtonBindingMap& bbm = get_mousemap(op);
713         MouseButtonBindingMap::iterator b = bbm.find (bb);
714
715         if (b != bbm.end()) {
716                 bbm.erase (b);
717         }
718 }
719
720 void
721 Bindings::save (XMLNode& root)
722 {
723         XMLNode* presses = new XMLNode (X_("Press"));
724
725         for (KeybindingMap::iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
726                 XMLNode* child;
727
728                 if (k->first.name().empty()) {
729                         continue;
730                 }
731
732                 child = new XMLNode (X_("Binding"));
733                 child->add_property (X_("key"), k->first.name());
734                 child->add_property (X_("action"), k->second.action_name);
735                 presses->add_child_nocopy (*child);
736         }
737
738         for (MouseButtonBindingMap::iterator k = button_press_bindings.begin(); k != button_press_bindings.end(); ++k) {
739                 XMLNode* child;
740                 child = new XMLNode (X_("Binding"));
741                 child->add_property (X_("button"), k->first.name());
742                 child->add_property (X_("action"), k->second.action_name);
743                 presses->add_child_nocopy (*child);
744         }
745
746         XMLNode* releases = new XMLNode (X_("Release"));
747
748         for (KeybindingMap::iterator k = release_bindings.begin(); k != release_bindings.end(); ++k) {
749                 XMLNode* child;
750
751                 if (k->first.name().empty()) {
752                         continue;
753                 }
754
755                 child = new XMLNode (X_("Binding"));
756                 child->add_property (X_("key"), k->first.name());
757                 child->add_property (X_("action"), k->second.action_name);
758                 releases->add_child_nocopy (*child);
759         }
760
761         for (MouseButtonBindingMap::iterator k = button_release_bindings.begin(); k != button_release_bindings.end(); ++k) {
762                 XMLNode* child;
763                 child = new XMLNode (X_("Binding"));
764                 child->add_property (X_("button"), k->first.name());
765                 child->add_property (X_("action"), k->second.action_name);
766                 releases->add_child_nocopy (*child);
767         }
768
769         root.add_child_nocopy (*presses);
770         root.add_child_nocopy (*releases);
771 }
772
773 void
774 Bindings::save_all_bindings_as_html (ostream& ostr)
775 {
776         if (bindings.empty()) {
777                 return;
778         }
779
780
781         ostr << "<html>\n<head>\n<title>";
782         ostr << PROGRAM_NAME;
783         ostr << "</title>\n";
784
785
786         ostr << "<style>\n";
787         ostr << "\n\
788 .key-name-even, .key-name-odd\n\
789 {\n\
790     font-weight: bold;\n\
791 }\n\
792 \n\
793 .key-action-odd, .key-action-even\n\
794 {\n\
795     font-weight: normal;\n\
796     font-style: italic;\n\
797 }";
798         ostr << "</style>\n";
799
800         ostr << "</head>\n<body>\n";
801
802         ostr << "<div class=\"container\">\n";
803
804         for (list<Bindings*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
805                 (*b)->save_as_html (ostr);
806         }
807
808         ostr << "</div>\n";
809         ostr << "</body>\n";
810         ostr << "</html>\n";
811 }
812
813 void
814 Bindings::save_as_html (ostream& ostr) const
815 {
816
817         if (!press_bindings.empty()) {
818
819                 ostr << "<div class=\"binding-set\">\n";
820                 ostr << "<h1>";
821                 ostr << name();
822                 ostr << "</h1>\n\n";
823
824                 /* first pass: separate by group */
825
826                 typedef std::map<std::string, std::vector<KeybindingMap::const_iterator> > GroupMap;
827                 GroupMap group_map;
828
829                 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
830                         if (k->first.name().empty()) {
831                                 continue;
832                         }
833
834                         string group_name;
835                         if (!k->second.group_name.empty()) {
836                                 group_name = k->second.group_name;
837                         } else {
838                                 group_name = X_("nogroup");
839                         }
840
841                         GroupMap::iterator gm = group_map.find (group_name);
842                         if (gm == group_map.end()) {
843                                 std::vector<KeybindingMap::const_iterator> li;
844                                 li.push_back (k);
845                                 group_map.insert (make_pair (group_name,li));
846                         } else {
847                                 gm->second.push_back (k);
848                         }
849                 }
850
851                 for (GroupMap::const_iterator gm = group_map.begin(); gm != group_map.end(); ++gm) {
852
853                         ostr << "<div class=\"group\">\n";
854                         ostr << "<div class=\"group-name\">" << gm->first << "</div>\n";
855
856                         for (vector<KeybindingMap::const_iterator>::const_iterator k = gm->second.begin(); k != gm->second.end(); ++k) {
857
858                                 if ((*k)->first.name().empty()) {
859                                         continue;
860                                 }
861
862                                 RefPtr<Action> action;
863
864                                 if ((*k)->second.action) {
865                                         action = (*k)->second.action;
866                                 } else {
867                                         if (_action_map) {
868                                                 action = _action_map->find_action ((*k)->second.action_name);
869                                         }
870                                 }
871
872                                 if (!action) {
873                                         continue;
874                                 }
875
876                                 string key_name = (*k)->first.native_short_name ();
877                                 replace_all (key_name, X_("KP_"), X_("Numpad "));
878
879                                 string::size_type pos;
880
881                                 char const *targets[] = { X_("Separator"), X_("Add"), X_("Subtract"), X_("Decimal"), X_("Divide"),
882                                                           X_("grave"), X_("comma"), X_("period"), X_("asterisk"), X_("backslash"),
883                                                           X_("apostrophe"), X_("minus"), X_("plus"), X_("slash"), X_("semicolon"),
884                                                           X_("colon"), X_("equal"), X_("bracketleft"), X_("bracketright"),
885                                                           X_("ampersand"), X_("numbersign"), X_("parenleft"), X_("parenright"),
886                                                           X_("quoteright"), X_("quoteleft"), X_("exclam"), X_("quotedbl"),
887                                                           0
888                                 };
889
890                                 char const *replacements[] = { X_("-"), X_("+"), X_("-"), X_("."), X_("/"),
891                                                                X_("`"), X_(","), X_("."), X_("*"), X_("\\"),
892                                                                X_("'"), X_("-"), X_("+"), X_("/"), X_(";"),
893                                                                X_(":"), X_("="), X_("{"), X_("{"),
894                                                                X_("&"), X_("#"), X_("("), X_(")"),
895                                                                X_("`"), X_("'"), X_("!"), X_("\""),
896                                 };
897
898                                 for (size_t n = 0; targets[n]; ++n) {
899                                         if ((pos = key_name.find (targets[n])) != string::npos) {
900                                                 key_name.replace (pos, strlen (targets[n]), replacements[n]);
901                                         }
902                                 }
903
904                                 ostr << "<div class=\"key\">" << key_name << "</div>";
905                                 ostr << "<div class=\"action\">" << action->get_label() << "</div>\n";
906                         }
907                         ostr << "</div>\n\n";
908                 }
909
910                 ostr << "</div>\n";
911         }
912 }
913
914 bool
915 Bindings::load (XMLNode const& node)
916 {
917         const XMLNodeList& children (node.children());
918
919         press_bindings.clear ();
920         release_bindings.clear ();
921
922         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
923                 /* each node could be Press or Release */
924                 load_operation (**i);
925         }
926
927         return true;
928 }
929
930 void
931 Bindings::load_operation (XMLNode const& node)
932 {
933         if (node.name() == X_("Press") || node.name() == X_("Release")) {
934
935                 Operation op;
936
937                 if (node.name() == X_("Press")) {
938                         op = Press;
939                 } else {
940                         op = Release;
941                 }
942
943                 const XMLNodeList& children (node.children());
944
945                 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
946
947                         XMLProperty const * ap;
948                         XMLProperty const * kp;
949                         XMLProperty const * bp;
950                         XMLProperty const * gp;
951                         XMLNode const * child = *p;
952
953                         ap = child->property ("action");
954                         kp = child->property ("key");
955                         bp = child->property ("button");
956                         gp = child->property ("group");
957
958                         if (!ap || (!kp && !bp)) {
959                                 continue;
960                         }
961
962                         if (kp) {
963                                 KeyboardKey k;
964                                 if (!KeyboardKey::make_key (kp->value(), k)) {
965                                         continue;
966                                 }
967                                 add (k, op, ap->value(), gp);
968                         } else {
969                                 MouseButton b;
970                                 if (!MouseButton::make_button (bp->value(), b)) {
971                                         continue;
972                                 }
973                                 add (b, op, ap->value(), gp);
974                         }
975                 }
976         }
977 }
978
979 void
980 Bindings::get_all_actions (std::vector<std::string>& paths,
981                            std::vector<std::string>& labels,
982                            std::vector<std::string>& tooltips,
983                            std::vector<std::string>& keys,
984                            std::vector<RefPtr<Action> >& actions)
985 {
986         if (!_action_map) {
987                 return;
988         }
989
990         /* build a reverse map from actions to bindings */
991
992         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
993         ReverseMap rmap;
994
995         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
996                 rmap.insert (make_pair (k->second.action, k->first));
997         }
998
999         /* get a list of all actions */
1000
1001         ActionMap::Actions all_actions;
1002         _action_map->get_actions (all_actions);
1003
1004         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
1005
1006                 paths.push_back ((*act)->get_accel_path());
1007                 labels.push_back ((*act)->get_label());
1008                 tooltips.push_back ((*act)->get_tooltip());
1009
1010                 ReverseMap::iterator r = rmap.find (*act);
1011
1012                 if (r != rmap.end()) {
1013                         keys.push_back (r->second.display_label());
1014                 } else {
1015                         keys.push_back (string());
1016                 }
1017
1018                 actions.push_back (*act);
1019         }
1020 }
1021
1022 Bindings*
1023 Bindings::get_bindings (string const& name, ActionMap& map)
1024 {
1025         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1026                 if ((*b)->name() == name) {
1027                         (*b)->set_action_map (map);
1028                         return *b;
1029                 }
1030         }
1031
1032         return 0;
1033 }
1034
1035 void
1036 Bindings::associate_all ()
1037 {
1038         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1039                 (*b)->associate ();
1040         }
1041 }
1042
1043 bool
1044 Bindings::is_bound (KeyboardKey const& kb, Operation op) const
1045 {
1046         const KeybindingMap& km = get_keymap(op);
1047         return km.find(kb) != km.end();
1048 }
1049
1050 std::string
1051 Bindings::bound_name (KeyboardKey const& kb, Operation op) const
1052 {
1053         const KeybindingMap& km = get_keymap(op);
1054         KeybindingMap::const_iterator b = km.find(kb);
1055         if (b == km.end()) {
1056                 return "";
1057         }
1058         return b->second.action_name;
1059 }
1060
1061 bool
1062 Bindings::is_registered (Operation op, std::string const& action_name) const
1063 {
1064         const KeybindingMap& km = get_keymap(op);
1065         return std::find_if(km.begin(),  km.end(),  ActionNameRegistered<KeybindingMap::const_iterator::value_type>(action_name)) != km.end();
1066 }
1067
1068 Bindings::KeybindingMap&
1069 Bindings::get_keymap (Operation op)
1070 {
1071         switch (op) {
1072         case Press:
1073                 return press_bindings;
1074         case Release:
1075         default:
1076                 return release_bindings;
1077         }
1078 }
1079
1080 const Bindings::KeybindingMap&
1081 Bindings::get_keymap (Operation op) const
1082 {
1083         switch (op) {
1084         case Press:
1085                 return press_bindings;
1086         case Release:
1087         default:
1088                 return release_bindings;
1089         }
1090 }
1091
1092 Bindings::MouseButtonBindingMap&
1093 Bindings::get_mousemap (Operation op)
1094 {
1095         switch (op) {
1096         case Press:
1097                 return button_press_bindings;
1098         case Release:
1099         default:
1100                 return button_release_bindings;
1101         }
1102 }
1103
1104 /*==========================================ACTION MAP =========================================*/
1105
1106 ActionMap::ActionMap (string const & name)
1107         : _name (name)
1108         , _bindings (0)
1109 {
1110         action_maps.push_back (this);
1111 }
1112
1113 ActionMap::~ActionMap ()
1114 {
1115         action_maps.remove (this);
1116 }
1117
1118 void
1119 ActionMap::set_bindings (Bindings* b)
1120 {
1121         _bindings = b;
1122 }
1123
1124 void
1125 ActionMap::get_actions (ActionMap::Actions& acts)
1126 {
1127         for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
1128                 acts.push_back (a->second);
1129         }
1130 }
1131
1132 RefPtr<Action>
1133 ActionMap::find_action (const string& name)
1134 {
1135         _ActionMap::iterator a = _actions.find (name);
1136
1137         if (a != _actions.end()) {
1138                 return a->second;
1139         }
1140
1141         return RefPtr<Action>();
1142 }
1143
1144 RefPtr<ActionGroup>
1145 ActionMap::create_action_group (const string& name)
1146 {
1147         RefPtr<ActionGroup> g = ActionGroup::create (name);
1148
1149         /* this is one of the places where our own Action management code
1150            has to touch the GTK one, because we want the GtkUIManager to
1151            be able to create widgets (particularly Menus) from our actions.
1152
1153            This is a a necessary step for that to happen.
1154         */
1155
1156         if (g) {
1157                 ActionManager::ui_manager->insert_action_group (g);
1158         }
1159
1160         return g;
1161 }
1162
1163 RefPtr<Action>
1164 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
1165 {
1166         string fullpath;
1167
1168         RefPtr<Action> act = Action::create (name, label);
1169
1170         fullpath = group->get_name();
1171         fullpath += '/';
1172         fullpath += name;
1173
1174         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1175                 group->add (act);
1176                 return act;
1177         }
1178
1179         /* already registered */
1180         return RefPtr<Action> ();
1181 }
1182
1183 RefPtr<Action>
1184 ActionMap::register_action (RefPtr<ActionGroup> group,
1185                             const char* name, const char* label, sigc::slot<void> sl)
1186 {
1187         string fullpath;
1188
1189         RefPtr<Action> act = Action::create (name, label);
1190
1191         fullpath = group->get_name();
1192         fullpath += '/';
1193         fullpath += name;
1194
1195         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1196                 group->add (act, sl);
1197                 return act;
1198         }
1199
1200         /* already registered */
1201         return RefPtr<Action>();
1202 }
1203
1204 RefPtr<Action>
1205 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1206                                   Gtk::RadioAction::Group& rgroup,
1207                                   const char* name, const char* label,
1208                                   sigc::slot<void> sl)
1209 {
1210         string fullpath;
1211
1212         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1213         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1214
1215         fullpath = group->get_name();
1216         fullpath += '/';
1217         fullpath += name;
1218
1219         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1220                 group->add (act, sl);
1221                 return act;
1222         }
1223
1224         /* already registered */
1225         return RefPtr<Action>();
1226 }
1227
1228 RefPtr<Action>
1229 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1230                                   Gtk::RadioAction::Group& rgroup,
1231                                   const char* name, const char* label,
1232                                   sigc::slot<void,GtkAction*> sl,
1233                                   int value)
1234 {
1235         string fullpath;
1236
1237         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1238         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1239         ract->property_value() = value;
1240
1241         fullpath = group->get_name();
1242         fullpath += '/';
1243         fullpath += name;
1244
1245         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1246                 group->add (act, sigc::bind (sl, act->gobj()));
1247                 return act;
1248         }
1249
1250         /* already registered */
1251
1252         return RefPtr<Action>();
1253 }
1254
1255 RefPtr<Action>
1256 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1257                                    const char* name, const char* label, sigc::slot<void> sl)
1258 {
1259         string fullpath;
1260
1261         fullpath = group->get_name();
1262         fullpath += '/';
1263         fullpath += name;
1264
1265         RefPtr<Action> act = ToggleAction::create (name, label);
1266
1267         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1268                 group->add (act, sl);
1269                 return act;
1270         }
1271
1272         /* already registered */
1273         return RefPtr<Action>();
1274 }
1275
1276 void
1277 ActionMap::get_all_actions (std::vector<std::string>& paths,
1278                             std::vector<std::string>& labels,
1279                             std::vector<std::string>& tooltips,
1280                             std::vector<std::string>& keys,
1281                             std::vector<RefPtr<Action> >& actions)
1282 {
1283         for (list<ActionMap*>::const_iterator map = action_maps.begin(); map != action_maps.end(); ++map) {
1284
1285                 ActionMap::Actions these_actions;
1286                 (*map)->get_actions (these_actions);
1287
1288                 for (ActionMap::Actions::const_iterator act = these_actions.begin(); act != these_actions.end(); ++act) {
1289
1290                         paths.push_back ((*act)->get_accel_path());
1291                         labels.push_back ((*act)->get_label());
1292                         tooltips.push_back ((*act)->get_tooltip());
1293                         actions.push_back (*act);
1294
1295                         Bindings* bindings = (*map)->bindings();
1296
1297                         if (bindings) {
1298
1299                                 KeyboardKey key;
1300                                 Bindings::Operation op;
1301
1302                                 key = bindings->get_binding_for_action (*act, op);
1303
1304                                 if (key == KeyboardKey::null_key()) {
1305                                         keys.push_back (string());
1306                                 } else {
1307                                         keys.push_back (key.display_label());
1308                                 }
1309                         } else {
1310                                 keys.push_back (string());
1311                         }
1312                 }
1313
1314                 these_actions.clear ();
1315         }
1316 }
1317
1318 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1319         char const *gdk_name = gdk_keyval_name (k.key());
1320         return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state "
1321                    << hex << k.state() << dec << ' ' << show_gdk_event_state (k.state());
1322 }