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