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