ptformat: Update lib to upstream 3b60276
[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         ostr << "</head>\n<body>\n";
786
787         ostr << "<table border=\"2\" cellpadding=\"6\"><tbody>\n\n";
788         ostr << "<tr>\n\n";
789         
790         /* first column: separate by group */
791         ostr << "<td>\n\n";
792         for (list<Bindings*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
793                 (*b)->save_as_html (ostr, true);
794         }
795         ostr << "</td>\n\n";
796
797         //second column
798         ostr << "<td style=\"vertical-align:top\">\n\n";
799         for (list<Bindings*>::const_iterator b = bindings.begin(); b != bindings.end(); ++b) {
800                 (*b)->save_as_html (ostr, false);
801         }
802         ostr << "</td>\n\n";
803
804
805         ostr << "</tr>\n\n";
806         ostr << "</tbody></table>\n\n";
807
808         ostr << "</body>\n";
809         ostr << "</html>\n";
810 }
811
812 void
813 Bindings::save_as_html (ostream& ostr, bool categorize) const
814 {
815
816         if (!press_bindings.empty()) {
817
818                 ostr << "<h2><u>";
819                 if (categorize)
820                         ostr << _("Window") << ": " << name() << _(" (Categorized)");
821                 else
822                         ostr << _("Window") << ": " << name() << _(" (Alphabetical)");
823                 ostr << "</u></h2>\n\n";
824
825                 typedef std::map<std::string, std::vector<KeybindingMap::const_iterator> > GroupMap;
826                 GroupMap group_map;
827
828                 for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
829                         
830                         if (k->first.name().empty()) {
831                                 continue;
832                         }
833
834                         string group_name;
835                         if (categorize && !k->second.group_name.empty()) {
836                                 group_name = k->second.group_name;
837                         } else {
838                                 group_name = _("Uncategorized");
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                 
852                 for (GroupMap::const_iterator gm = group_map.begin(); gm != group_map.end(); ++gm) {
853
854                         if (categorize) {
855                                 ostr << "<h3>" << gm->first << "</h3>\n";
856                         }
857                         
858                         for (vector<KeybindingMap::const_iterator>::const_iterator k = gm->second.begin(); k != gm->second.end(); ++k) {
859
860                                 if ((*k)->first.name().empty()) {
861                                         continue;
862                                 }
863
864                                 RefPtr<Action> action;
865
866                                 if ((*k)->second.action) {
867                                         action = (*k)->second.action;
868                                 } else {
869                                         if (_action_map) {
870                                                 action = _action_map->find_action ((*k)->second.action_name);
871                                         }
872                                 }
873
874                                 if (!action) {
875                                         continue;
876                                 }
877
878                                 string key_name = (*k)->first.native_short_name ();
879                                 replace_all (key_name, X_("KP_"), X_("Numpad "));
880                                 replace_all (key_name, X_("nabla"), X_("Tab"));
881
882                                 string::size_type pos;
883
884                                 char const *targets[] = { X_("Separator"), X_("Add"), X_("Subtract"), X_("Decimal"), X_("Divide"),
885                                                           X_("grave"), X_("comma"), X_("period"), X_("asterisk"), X_("backslash"),
886                                                           X_("apostrophe"), X_("minus"), X_("plus"), X_("slash"), X_("semicolon"),
887                                                           X_("colon"), X_("equal"), X_("bracketleft"), X_("bracketright"),
888                                                           X_("ampersand"), X_("numbersign"), X_("parenleft"), X_("parenright"),
889                                                           X_("quoteright"), X_("quoteleft"), X_("exclam"), X_("quotedbl"),
890                                                           0
891                                 };
892
893                                 char const *replacements[] = { X_("-"), X_("+"), X_("-"), X_("."), X_("/"),
894                                                                X_("`"), X_(","), X_("."), X_("*"), X_("\\"),
895                                                                X_("'"), X_("-"), X_("+"), X_("/"), X_(";"),
896                                                                X_(":"), X_("="), X_("{"), X_("{"),
897                                                                X_("&"), X_("#"), X_("("), X_(")"),
898                                                                X_("`"), X_("'"), X_("!"), X_("\""),
899                                 };
900
901                                 for (size_t n = 0; targets[n]; ++n) {
902                                         if ((pos = key_name.find (targets[n])) != string::npos) {
903                                                 key_name.replace (pos, strlen (targets[n]), replacements[n]);
904                                         }
905                                 }
906                                 
907                                 key_name.append(" ");
908
909                                 while (key_name.length()<28)
910                                         key_name.append("-");
911
912                                 ostr << "<span style=\"font-family:monospace;\">" << key_name;
913                                 ostr << "<i>" << action->get_label() << "</i></span></br>\n";
914                         }
915                         ostr << "\n\n";
916
917                 }
918                 
919                 ostr << "\n";
920         }
921 }
922
923 bool
924 Bindings::load (XMLNode const& node)
925 {
926         const XMLNodeList& children (node.children());
927
928         press_bindings.clear ();
929         release_bindings.clear ();
930
931         for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
932                 /* each node could be Press or Release */
933                 load_operation (**i);
934         }
935
936         return true;
937 }
938
939 void
940 Bindings::load_operation (XMLNode const& node)
941 {
942         if (node.name() == X_("Press") || node.name() == X_("Release")) {
943
944                 Operation op;
945
946                 if (node.name() == X_("Press")) {
947                         op = Press;
948                 } else {
949                         op = Release;
950                 }
951
952                 const XMLNodeList& children (node.children());
953
954                 for (XMLNodeList::const_iterator p = children.begin(); p != children.end(); ++p) {
955
956                         XMLProperty const * ap;
957                         XMLProperty const * kp;
958                         XMLProperty const * bp;
959                         XMLProperty const * gp;
960                         XMLNode const * child = *p;
961
962                         ap = child->property ("action");
963                         kp = child->property ("key");
964                         bp = child->property ("button");
965                         gp = child->property ("group");
966
967                         if (!ap || (!kp && !bp)) {
968                                 continue;
969                         }
970
971                         if (kp) {
972                                 KeyboardKey k;
973                                 if (!KeyboardKey::make_key (kp->value(), k)) {
974                                         continue;
975                                 }
976                                 add (k, op, ap->value(), gp);
977                         } else {
978                                 MouseButton b;
979                                 if (!MouseButton::make_button (bp->value(), b)) {
980                                         continue;
981                                 }
982                                 add (b, op, ap->value(), gp);
983                         }
984                 }
985         }
986 }
987
988 void
989 Bindings::get_all_actions (std::vector<std::string>& paths,
990                            std::vector<std::string>& labels,
991                            std::vector<std::string>& tooltips,
992                            std::vector<std::string>& keys,
993                            std::vector<RefPtr<Action> >& actions)
994 {
995         if (!_action_map) {
996                 return;
997         }
998
999         /* build a reverse map from actions to bindings */
1000
1001         typedef map<Glib::RefPtr<Gtk::Action>,KeyboardKey> ReverseMap;
1002         ReverseMap rmap;
1003
1004         for (KeybindingMap::const_iterator k = press_bindings.begin(); k != press_bindings.end(); ++k) {
1005                 rmap.insert (make_pair (k->second.action, k->first));
1006         }
1007
1008         /* get a list of all actions */
1009
1010         ActionMap::Actions all_actions;
1011         _action_map->get_actions (all_actions);
1012
1013         for (ActionMap::Actions::const_iterator act = all_actions.begin(); act != all_actions.end(); ++act) {
1014
1015                 paths.push_back ((*act)->get_accel_path());
1016                 labels.push_back ((*act)->get_label());
1017                 tooltips.push_back ((*act)->get_tooltip());
1018
1019                 ReverseMap::iterator r = rmap.find (*act);
1020
1021                 if (r != rmap.end()) {
1022                         keys.push_back (r->second.display_label());
1023                 } else {
1024                         keys.push_back (string());
1025                 }
1026
1027                 actions.push_back (*act);
1028         }
1029 }
1030
1031 Bindings*
1032 Bindings::get_bindings (string const& name, ActionMap& map)
1033 {
1034         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1035                 if ((*b)->name() == name) {
1036                         (*b)->set_action_map (map);
1037                         return *b;
1038                 }
1039         }
1040
1041         return 0;
1042 }
1043
1044 void
1045 Bindings::associate_all ()
1046 {
1047         for (list<Bindings*>::iterator b = bindings.begin(); b != bindings.end(); b++) {
1048                 (*b)->associate ();
1049         }
1050 }
1051
1052 bool
1053 Bindings::is_bound (KeyboardKey const& kb, Operation op) const
1054 {
1055         const KeybindingMap& km = get_keymap(op);
1056         return km.find(kb) != km.end();
1057 }
1058
1059 std::string
1060 Bindings::bound_name (KeyboardKey const& kb, Operation op) const
1061 {
1062         const KeybindingMap& km = get_keymap(op);
1063         KeybindingMap::const_iterator b = km.find(kb);
1064         if (b == km.end()) {
1065                 return "";
1066         }
1067         return b->second.action_name;
1068 }
1069
1070 bool
1071 Bindings::is_registered (Operation op, std::string const& action_name) const
1072 {
1073         const KeybindingMap& km = get_keymap(op);
1074         return std::find_if(km.begin(),  km.end(),  ActionNameRegistered<KeybindingMap::const_iterator::value_type>(action_name)) != km.end();
1075 }
1076
1077 Bindings::KeybindingMap&
1078 Bindings::get_keymap (Operation op)
1079 {
1080         switch (op) {
1081         case Press:
1082                 return press_bindings;
1083         case Release:
1084         default:
1085                 return release_bindings;
1086         }
1087 }
1088
1089 const Bindings::KeybindingMap&
1090 Bindings::get_keymap (Operation op) const
1091 {
1092         switch (op) {
1093         case Press:
1094                 return press_bindings;
1095         case Release:
1096         default:
1097                 return release_bindings;
1098         }
1099 }
1100
1101 Bindings::MouseButtonBindingMap&
1102 Bindings::get_mousemap (Operation op)
1103 {
1104         switch (op) {
1105         case Press:
1106                 return button_press_bindings;
1107         case Release:
1108         default:
1109                 return button_release_bindings;
1110         }
1111 }
1112
1113 /*==========================================ACTION MAP =========================================*/
1114
1115 ActionMap::ActionMap (string const & name)
1116         : _name (name)
1117         , _bindings (0)
1118 {
1119         action_maps.push_back (this);
1120 }
1121
1122 ActionMap::~ActionMap ()
1123 {
1124         action_maps.remove (this);
1125 }
1126
1127 void
1128 ActionMap::set_bindings (Bindings* b)
1129 {
1130         _bindings = b;
1131 }
1132
1133 void
1134 ActionMap::get_actions (ActionMap::Actions& acts)
1135 {
1136         for (_ActionMap::iterator a = _actions.begin(); a != _actions.end(); ++a) {
1137                 acts.push_back (a->second);
1138         }
1139 }
1140
1141 RefPtr<Action>
1142 ActionMap::find_action (const string& name)
1143 {
1144         _ActionMap::iterator a = _actions.find (name);
1145
1146         if (a != _actions.end()) {
1147                 return a->second;
1148         }
1149
1150         return RefPtr<Action>();
1151 }
1152
1153 RefPtr<ActionGroup>
1154 ActionMap::create_action_group (const string& name)
1155 {
1156         RefPtr<ActionGroup> g = ActionGroup::create (name);
1157
1158         /* this is one of the places where our own Action management code
1159            has to touch the GTK one, because we want the GtkUIManager to
1160            be able to create widgets (particularly Menus) from our actions.
1161
1162            This is a a necessary step for that to happen.
1163         */
1164
1165         if (g) {
1166                 ActionManager::ui_manager->insert_action_group (g);
1167         }
1168
1169         return g;
1170 }
1171
1172 RefPtr<Action>
1173 ActionMap::register_action (RefPtr<ActionGroup> group, const char* name, const char* label)
1174 {
1175         string fullpath;
1176
1177         RefPtr<Action> act = Action::create (name, label);
1178
1179         fullpath = group->get_name();
1180         fullpath += '/';
1181         fullpath += name;
1182
1183         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1184                 group->add (act);
1185                 return act;
1186         }
1187
1188         /* already registered */
1189         return RefPtr<Action> ();
1190 }
1191
1192 RefPtr<Action>
1193 ActionMap::register_action (RefPtr<ActionGroup> group,
1194                             const char* name, const char* label, sigc::slot<void> sl)
1195 {
1196         string fullpath;
1197
1198         RefPtr<Action> act = Action::create (name, label);
1199
1200         fullpath = group->get_name();
1201         fullpath += '/';
1202         fullpath += name;
1203
1204         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1205                 group->add (act, sl);
1206                 return act;
1207         }
1208
1209         /* already registered */
1210         return RefPtr<Action>();
1211 }
1212
1213 RefPtr<Action>
1214 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1215                                   Gtk::RadioAction::Group& rgroup,
1216                                   const char* name, const char* label,
1217                                   sigc::slot<void> sl)
1218 {
1219         string fullpath;
1220
1221         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1222         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1223
1224         fullpath = group->get_name();
1225         fullpath += '/';
1226         fullpath += name;
1227
1228         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1229                 group->add (act, sl);
1230                 return act;
1231         }
1232
1233         /* already registered */
1234         return RefPtr<Action>();
1235 }
1236
1237 RefPtr<Action>
1238 ActionMap::register_radio_action (RefPtr<ActionGroup> group,
1239                                   Gtk::RadioAction::Group& rgroup,
1240                                   const char* name, const char* label,
1241                                   sigc::slot<void,GtkAction*> sl,
1242                                   int value)
1243 {
1244         string fullpath;
1245
1246         RefPtr<Action> act = RadioAction::create (rgroup, name, label);
1247         RefPtr<RadioAction> ract = RefPtr<RadioAction>::cast_dynamic(act);
1248         ract->property_value() = value;
1249
1250         fullpath = group->get_name();
1251         fullpath += '/';
1252         fullpath += name;
1253
1254         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1255                 group->add (act, sigc::bind (sl, act->gobj()));
1256                 return act;
1257         }
1258
1259         /* already registered */
1260
1261         return RefPtr<Action>();
1262 }
1263
1264 RefPtr<Action>
1265 ActionMap::register_toggle_action (RefPtr<ActionGroup> group,
1266                                    const char* name, const char* label, sigc::slot<void> sl)
1267 {
1268         string fullpath;
1269
1270         fullpath = group->get_name();
1271         fullpath += '/';
1272         fullpath += name;
1273
1274         RefPtr<Action> act = ToggleAction::create (name, label);
1275
1276         if (_actions.insert (_ActionMap::value_type (fullpath, act)).second) {
1277                 group->add (act, sl);
1278                 return act;
1279         }
1280
1281         /* already registered */
1282         return RefPtr<Action>();
1283 }
1284
1285 void
1286 ActionMap::get_all_actions (std::vector<std::string>& paths,
1287                             std::vector<std::string>& labels,
1288                             std::vector<std::string>& tooltips,
1289                             std::vector<std::string>& keys,
1290                             std::vector<RefPtr<Action> >& actions)
1291 {
1292         for (list<ActionMap*>::const_iterator map = action_maps.begin(); map != action_maps.end(); ++map) {
1293
1294                 ActionMap::Actions these_actions;
1295                 (*map)->get_actions (these_actions);
1296
1297                 for (ActionMap::Actions::const_iterator act = these_actions.begin(); act != these_actions.end(); ++act) {
1298
1299                         paths.push_back ((*act)->get_accel_path());
1300                         labels.push_back ((*act)->get_label());
1301                         tooltips.push_back ((*act)->get_tooltip());
1302                         actions.push_back (*act);
1303
1304                         Bindings* bindings = (*map)->bindings();
1305
1306                         if (bindings) {
1307
1308                                 KeyboardKey key;
1309                                 Bindings::Operation op;
1310
1311                                 key = bindings->get_binding_for_action (*act, op);
1312
1313                                 if (key == KeyboardKey::null_key()) {
1314                                         keys.push_back (string());
1315                                 } else {
1316                                         keys.push_back (key.display_label());
1317                                 }
1318                         } else {
1319                                 keys.push_back (string());
1320                         }
1321                 }
1322
1323                 these_actions.clear ();
1324         }
1325 }
1326
1327 std::ostream& operator<<(std::ostream& out, Gtkmm2ext::KeyboardKey const & k) {
1328         char const *gdk_name = gdk_keyval_name (k.key());
1329         return out << "Key " << k.key() << " (" << (gdk_name ? gdk_name : "no-key") << ") state "
1330                    << hex << k.state() << dec << ' ' << show_gdk_event_state (k.state());
1331 }