]> git.lyx.org Git - lyx.git/blob - src/frontends/qt2/QLPopupMenu.C
677a4fa6a3233a7643f71dd49fefe9057b7845ee
[lyx.git] / src / frontends / qt2 / QLPopupMenu.C
1 /**
2  * \file QLPopupMenu.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 // Qt defines a macro 'signals' that clashes with a boost namespace.
14 // All is well if the namespace is visible first.
15 #include "QtView.h"
16
17 #include "QLPopupMenu.h"
18 #include "QLMenubar.h"
19 #include "qt_helpers.h"
20
21 #include "MenuBackend.h"
22
23 #include "support/lstrings.h"
24
25 #ifdef Q_WS_MACX
26 #include "kbmap.h"
27 #include "QLyXKeySym.h"
28 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
29 #endif
30
31 #include <qapplication.h>
32
33 using std::distance;
34 using std::make_pair;
35 using std::string;
36 using std::pair;
37
38 namespace lyx {
39
40 using support::subst;
41
42 namespace frontend {
43
44 namespace {
45
46 string const getLabel(MenuItem const & mi)
47 {
48         string const shortcut = mi.shortcut();
49         string label = subst(mi.label(), "&", "&&");
50
51         if (!shortcut.empty()) {
52                 string::size_type pos = label.find(shortcut);
53                 if (pos != string::npos)
54                         label.insert(pos, 1, '&');
55         }
56
57         return label;
58 }
59
60 #ifdef Q_WS_MACX
61 // The offset added to the special Mac menu entries
62 const int indexOffset = 5000;
63 #endif
64
65 } // namespace anon
66
67
68 pair<int, QLPopupMenu *>
69 createMenu(QMenuData * parent, MenuItem const * item, QLMenubar * owner,
70            bool is_toplevel)
71 {
72         QLPopupMenu * pm = new QLPopupMenu(owner, item->submenuname(), is_toplevel);
73         int const id = parent->insertItem(toqstr(getLabel(*item)), pm);
74         return make_pair(id, pm);
75 }
76
77
78 QLPopupMenu::QLPopupMenu(QLMenubar * owner,
79                          string const & name, bool toplevel)
80         : owner_(owner), name_(name)
81 {
82         if (toplevel)
83                 connect(this, SIGNAL(aboutToShow()), this, SLOT(showing()));
84         connect(this, SIGNAL(activated(int)),
85                 this, SLOT(fire(int)));
86 }
87
88
89 void QLPopupMenu::fire(int index)
90 {
91 #ifdef Q_WS_MACX
92         if (index >= indexOffset) {
93                 MenuItem mi = owner_->backend().getMenu("LyX")[index - indexOffset];
94                 owner_->view()->activated(mi.func());
95         } else
96 #endif
97                 owner_->view()->activated(funcs_[index]);
98 }
99
100
101 void QLPopupMenu::populate(Menu * menu)
102 {
103         funcs_.clear();
104
105         Menu::const_iterator m = menu->begin();
106         Menu::const_iterator end = menu->end();
107         for (; m != end; ++m) {
108                 if (m->kind() == MenuItem::Separator) {
109                         insertSeparator();
110                 } else if (m->kind() == MenuItem::Submenu) {
111                         pair<int, QLPopupMenu *> res = createMenu(this, &(*m), owner_);
112                         setItemEnabled(res.first, m->status().enabled());
113                         res.second->populate(m->submenu());
114                 } else { // we have a MenuItem::Command
115                         FuncStatus status = m->status();
116
117                         Funcs::iterator fit =
118                                 funcs_.insert(funcs_.end(), m->func());
119                         int const index = distance(funcs_.begin(), fit);
120
121                         QString label = toqstr(getLabel(*m));
122 #ifdef Q_WS_MACX
123                         /* There are two constraints on Qt/Mac: (1)
124                            the bindings require a unicode string to be
125                            represented meaningfully and std::string
126                            does not work (2) only 1-key bindings can
127                            be represented in menus.
128
129                            This is why the unpleasant hack bellow is
130                            needed (JMarc)
131                         */
132                         pair<LyXKeySym const *, key_modifier::state>
133                                 binding = toplevel_keymap->find1keybinding(m->func());
134                         if (binding.first) {
135                                 QLyXKeySym const *key = static_cast<QLyXKeySym const *>(binding.first);
136                                 label += '\t' + key->qprint(binding.second);
137                         }
138 #else
139                         string const binding(m->binding());
140                         if (!binding.empty()) {
141                                 label += '\t' + toqstr(binding);
142                         }
143 #endif
144
145                         // Actually insert the menu item
146                         insertItem(label, index);
147                         setItemEnabled(index, status.enabled());
148                         setItemChecked(index, status.onoff(true));
149                 }
150         }
151 }
152
153
154 void QLPopupMenu::showing()
155 {
156         clear();
157         Menu tomenu;
158         Menu const frommenu = owner_->backend().getMenu(name_);
159         owner_->backend().expand(frommenu, tomenu, owner_->view());
160         populate(&tomenu);
161 #ifdef Q_WS_MACX
162         /* The qt/mac menu code has a very silly hack that
163            moves some menu entries that it recognizes by name
164            (e.g. "Preferences...") to the "LyX" menu. This
165            feature can only work if the menu entries are
166            always available. Since we build menus on demand,
167            we add some dummy contents to one of the menus (JMarc)
168         */
169         static QLPopupMenu * themenu = this;
170         if (themenu == this && owner_->backend().hasMenu("LyX")) {
171                 Menu special = owner_->backend().getMenu("LyX");
172                 Menu::const_iterator end = special.end();
173                 Menu::size_type i = 0;
174                 for (Menu::const_iterator cit = special.begin();
175                      cit != end ; ++cit, ++i)
176                         insertItem(toqstr(cit->label()), indexOffset + i);
177         }
178 #endif
179 }
180
181 } // namespace frontend
182 } // namespace lyx