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