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