]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QLPopupMenu.C
Fix memory leaks with multiple windows and crash when deleteOnClose is set.
[lyx.git] / src / frontends / qt4 / 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  * \author Abdelrazak Younes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include <boost/current_function.hpp>
15
16 // Qt defines a macro 'signals' that clashes with a boost namespace.
17 // All is well if the namespace is visible first.
18 #include "GuiView.h"
19
20 #include "Action.h"
21 #include "QLPopupMenu.h"
22 #include "QLMenubar.h"
23 #include "qt_helpers.h"
24 #include "MenuBackend.h"
25
26 #include "support/lstrings.h"
27 #include "debug.h"
28
29
30 #ifdef Q_WS_MACX
31 #include "kbmap.h"
32 #include "QLyXKeySym.h"
33 #endif
34
35 using std::make_pair;
36 using std::string;
37 using std::pair;
38 using std::endl;
39
40 namespace {
41
42 } // namespace anon
43
44 namespace lyx {
45
46 namespace frontend {
47
48
49 // MacOSX specific stuff is at the end.
50
51 QLPopupMenu::QLPopupMenu(QLMenubar * owner,
52                                                  MenuItem const & mi, bool topLevelMenu)
53         : owner_(owner)
54 {
55         name_ = mi.submenuname();
56
57         setTitle(toqstr(getLabel(mi)));
58
59         if (topLevelMenu)
60                 connect(this, SIGNAL(aboutToShow()), this, SLOT(update()));
61 }
62
63
64
65 void QLPopupMenu::update()
66 {
67         lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION << endl;
68         lyxerr[Debug::GUI] << "\tTriggered menu: " << lyx::to_utf8(name_) << endl;
69
70         clear();
71
72         if (name_.empty())
73                 return;
74
75         // Here, We make sure that theLyXFunc points to the correct LyXView.
76         theLyXFunc().setLyXView(owner_->view());
77
78         Menu const & fromLyxMenu = owner_->backend().getMenu(name_);
79         owner_->backend().expand(fromLyxMenu, topLevelMenu_, owner_->view()->buffer());
80
81         if (!owner_->backend().hasMenu(topLevelMenu_.name())) {
82                 lyxerr[Debug::GUI] << "\tWARNING: menu seems empty" << lyx::to_utf8(topLevelMenu_.name()) << endl;
83         }
84         populate(this, &topLevelMenu_);
85
86         specialMacXmenuHack();
87 }
88
89 void QLPopupMenu::populate(QMenu* qMenu, Menu * menu)
90 {
91         lyxerr[Debug::GUI] << "populating menu " << lyx::to_utf8(menu->name()) ;
92         if (menu->size() == 0) {
93                 lyxerr[Debug::GUI] << "\tERROR: empty menu " << lyx::to_utf8(menu->name()) << endl;
94                 return;
95         }
96         else {
97                 lyxerr[Debug::GUI] << " *****  menu entries " << menu->size() << endl;
98         }
99
100         Menu::const_iterator m = menu->begin();
101         Menu::const_iterator end = menu->end();
102
103         for (; m != end; ++m) {
104
105                 if (m->kind() == MenuItem::Separator) {
106
107                         qMenu->addSeparator();
108                         lyxerr[Debug::GUI] << "adding Menubar Separator" << endl;
109
110                 } else if (m->kind() == MenuItem::Submenu) {
111
112                         lyxerr[Debug::GUI] << "** creating New Sub-Menu " << lyx::to_utf8(getLabel(*m)) << endl;
113                         QMenu * subMenu = qMenu->addMenu(toqstr(getLabel(*m)));
114                         populate(subMenu, m->submenu());
115
116                 } else { // we have a MenuItem::Command
117
118                         lyxerr[Debug::GUI] << "creating Menu Item " << lyx::to_utf8(m->label()) << endl;
119
120                         docstring label = getLabel(*m);
121                         addBinding(label, *m);
122
123                         Action * action = new Action(*(owner_->view()),
124                                                      label, m->func());
125                         qMenu->addAction(action);
126                 }
127         }
128 }
129
130 docstring const QLPopupMenu::getLabel(MenuItem const & mi)
131 {
132         docstring const shortcut = mi.shortcut();
133         docstring label = support::subst(mi.label(),
134                                       lyx::from_ascii("&"),
135                                       lyx::from_ascii("&&"));
136
137         if (!shortcut.empty()) {
138                 docstring::size_type pos = label.find(shortcut);
139                 if (pos != docstring::npos)
140                         label.insert(pos, 1, char_type('&'));
141         }
142
143         return label;
144 }
145
146 /// \todo Mac specific binding handling.
147 void QLPopupMenu::addBinding(docstring & label, MenuItem const & mi)
148 {
149 #ifndef Q_WS_MACX
150
151                 docstring const binding(mi.binding());
152                 if (!binding.empty()) {
153                         label += char_type('\t') + binding;
154                 }
155
156 #else
157                         /* There are two constraints on Qt/Mac: (1)
158                            the bindings require a unicode string to be
159                            represented meaningfully and std::string
160                            does not work (2) only 1-key bindings can
161                            be represented in menus.
162
163                            This is why the unpleasant hack bellow is
164                            needed (JMarc)
165                         */
166 /*                      pair<LyXKeySym const *, key_modifier::state>
167                                 binding = toplevel_keymap->find1keybinding(mi.func());
168                         if (binding.first) {
169                                 QLyXKeySym const *key = static_cast<QLyXKeySym const *>(binding.first);
170                                 label += '\t' + key->qprint(binding.second);
171                         }
172 */
173 #endif
174 }
175
176 /// \todo Fix Mac specific menu hack
177 void QLPopupMenu::specialMacXmenuHack()
178 {
179 #ifdef Q_WS_MACX
180         /* The qt/mac menu code has a very silly hack that
181            moves some menu entries that it recognizes by name
182            (e.g. "Preferences...") to the "LyX" menu. This
183            feature can only work if the menu entries are
184            always available. Since we build menus on demand,
185            we add some dummy contents to one of the menus (JMarc)
186         */
187 /*
188         static QLPopupMenu * themenu = this;
189         if (themenu == this && owner_->backend().hasMenu("LyX")) {
190                 Menu special = owner_->backend().getMenu("LyX");
191                 Menu::const_iterator end = special.end();
192                 Menu::size_type i = 0;
193                 for (Menu::const_iterator cit = special.begin();
194                      cit != end ; ++cit, ++i)
195                         insertItem(toqstr(cit->label()), indexOffset + i);
196         }
197 */
198 #endif
199 }
200
201 } // namespace frontend
202 } // namespace lyx
203
204 #include "QLPopupMenu_moc.cpp"