]> git.lyx.org Git - lyx.git/blob - src/frontends/qt2/QLPopupMenu.C
1f1ba57aa6726c268e93b5a22a1a5ee82e99f3f9
[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         qApp->processEvents();
92 #ifdef Q_WS_MACX
93         if (index >= indexOffset) {
94                 MenuItem mi = owner_->backend().getMenu("LyX")[index - indexOffset];
95                 owner_->view()->activated(mi.func());
96         } else
97 #endif
98                 owner_->view()->activated(funcs_[index]);
99 }
100
101
102 void QLPopupMenu::populate(Menu * menu)
103 {
104         funcs_.clear();
105
106         Menu::const_iterator m = menu->begin();
107         Menu::const_iterator end = menu->end();
108         for (; m != end; ++m) {
109                 if (m->kind() == MenuItem::Separator) {
110                         insertSeparator();
111                 } else if (m->kind() == MenuItem::Submenu) {
112                         pair<int, QLPopupMenu *> res = createMenu(this, &(*m), owner_);
113                         setItemEnabled(res.first, m->status().enabled());
114                         res.second->populate(m->submenu());
115                 } else { // we have a MenuItem::Command
116                         FuncStatus status = m->status();
117
118                         Funcs::iterator fit =
119                                 funcs_.insert(funcs_.end(), m->func());
120                         int const index = distance(funcs_.begin(), fit);
121
122                         QString label = toqstr(getLabel(*m));
123 #ifdef Q_WS_MACX
124                         /* There are two constraints on Qt/Mac: (1)
125                            the bindings require a unicode string to be
126                            represented meaningfully and std::string
127                            does not work (2) only 1-key bindings can
128                            be represented in menus.
129
130                            This is why the unpleasant hack bellow is
131                            needed (JMarc)
132                         */
133                         pair<LyXKeySym const *, key_modifier::state>
134                                 binding = toplevel_keymap->find1keybinding(m->func());
135                         if (binding.first) {
136                                 QLyXKeySym const *key = static_cast<QLyXKeySym const *>(binding.first);
137                                 label += '\t' + key->qprint(binding.second);
138                         }
139 #else
140                         string const binding(m->binding());
141                         if (!binding.empty()) {
142                                 label += '\t' + toqstr(binding);
143                         }
144 #endif
145
146                         // Actually insert the menu item
147                         insertItem(label, index);
148                         setItemEnabled(index, status.enabled());
149                         setItemChecked(index, status.onoff(true));
150                 }
151         }
152 }
153
154
155 void QLPopupMenu::showing()
156 {
157         clear();
158         Menu tomenu;
159         Menu const frommenu = owner_->backend().getMenu(name_);
160         owner_->backend().expand(frommenu, tomenu, owner_->view());
161         populate(&tomenu);
162 #ifdef Q_WS_MACX
163         /* The qt/mac menu code has a very silly hack that
164            moves some menu entries that it recognizes by name
165            (e.g. "Preferences...") to the "LyX" menu. This
166            feature can only work if the menu entries are
167            always available. Since we build menus on demand,
168            we add some dummy contents to one of the menus (JMarc)
169         */
170         static QLPopupMenu * themenu = this;
171         if (themenu == this && owner_->backend().hasMenu("LyX")) {
172                 Menu special = owner_->backend().getMenu("LyX");
173                 Menu::const_iterator end = special.end();
174                 Menu::size_type i = 0;
175                 for (Menu::const_iterator cit = special.begin();
176                      cit != end ; ++cit, ++i)
177                         insertItem(toqstr(cit->label()), indexOffset + i);
178         }
179 #endif
180 }
181
182 } // namespace frontend
183 } // namespace lyx