|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the S60 port of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qmenu.h" |
|
43 #include "qapplication.h" |
|
44 #include "qevent.h" |
|
45 #include "qstyle.h" |
|
46 #include "qdebug.h" |
|
47 #include "qwidgetaction.h" |
|
48 #include <private/qapplication_p.h> |
|
49 #include <private/qmenu_p.h> |
|
50 #include <private/qmenubar_p.h> |
|
51 #include <qt_s60_p.h> |
|
52 #include <QtCore/qlibrary.h> |
|
53 |
|
54 #ifdef Q_WS_S60 |
|
55 #include <eikmenub.h> |
|
56 #include <eikmenup.h> |
|
57 #include <eikaufty.h> |
|
58 #include <eikbtgpc.h> |
|
59 #include <avkon.rsg> |
|
60 #endif |
|
61 |
|
62 #if !defined(QT_NO_MENUBAR) && defined(Q_WS_S60) |
|
63 |
|
64 QT_BEGIN_NAMESPACE |
|
65 |
|
66 typedef QMultiHash<QWidget *, QMenuBarPrivate *> MenuBarHash; |
|
67 Q_GLOBAL_STATIC(MenuBarHash, menubars) |
|
68 |
|
69 struct SymbianMenuItem |
|
70 { |
|
71 int id; |
|
72 CEikMenuPaneItem::SData menuItemData; |
|
73 QList<SymbianMenuItem*> children; |
|
74 QAction* action; |
|
75 }; |
|
76 |
|
77 Q_GLOBAL_STATIC_WITH_ARGS(QAction, contextAction, (0)) |
|
78 |
|
79 static QList<SymbianMenuItem*> symbianMenus; |
|
80 static QList<QMenuBar*> nativeMenuBars; |
|
81 static uint qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
82 static QPointer<QWidget> widgetWithContextMenu; |
|
83 static QList<QAction*> contextMenuActionList; |
|
84 static int contexMenuCommand=0; |
|
85 |
|
86 bool menuExists() |
|
87 { |
|
88 QWidget *w = qApp->activeWindow(); |
|
89 QMenuBarPrivate *mb = menubars()->value(w); |
|
90 if ((!mb) && !menubars()->count()) |
|
91 return false; |
|
92 return true; |
|
93 } |
|
94 |
|
95 static bool hasContextMenu(QWidget* widget) |
|
96 { |
|
97 if (!widget) |
|
98 return false; |
|
99 const Qt::ContextMenuPolicy policy = widget->contextMenuPolicy(); |
|
100 if (policy != Qt::NoContextMenu && policy != Qt::PreventContextMenu ) { |
|
101 return true; |
|
102 } |
|
103 return false; |
|
104 } |
|
105 |
|
106 static SymbianMenuItem* qt_symbian_find_menu(int id, const QList<SymbianMenuItem*> &parent) |
|
107 { |
|
108 int index=0; |
|
109 while (index < parent.count()) { |
|
110 SymbianMenuItem* temp = parent[index]; |
|
111 if (temp->menuItemData.iCascadeId == id) |
|
112 return temp; |
|
113 else if (temp->menuItemData.iCascadeId != 0) { |
|
114 SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children); |
|
115 if (result) |
|
116 return result; |
|
117 } |
|
118 index++; |
|
119 } |
|
120 return 0; |
|
121 } |
|
122 |
|
123 static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList<SymbianMenuItem*> &parent) |
|
124 { |
|
125 int index=0; |
|
126 while (index < parent.count()) { |
|
127 SymbianMenuItem* temp = parent[index]; |
|
128 if (temp->menuItemData.iCascadeId != 0) { |
|
129 SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children); |
|
130 if (result) |
|
131 return result; |
|
132 } |
|
133 else if (temp->menuItemData.iCommandId == id) |
|
134 return temp; |
|
135 index++; |
|
136 |
|
137 } |
|
138 return 0; |
|
139 } |
|
140 |
|
141 static void qt_symbian_insert_action(QSymbianMenuAction* action, QList<SymbianMenuItem*>* parent) |
|
142 { |
|
143 if (action->action->isVisible()) { |
|
144 if (action->action->isSeparator()) |
|
145 return; |
|
146 |
|
147 Q_ASSERT_X(action->command <= QT_SYMBIAN_LAST_MENU_ITEM, "qt_symbian_insert_action", |
|
148 "Too many menu actions"); |
|
149 |
|
150 const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut); |
|
151 QString iconText = action->action->iconText(); |
|
152 TPtrC menuItemText = qt_QString2TPtrC( underlineShortCut ? action->action->text() : iconText); |
|
153 if (action->action->menu()) { |
|
154 SymbianMenuItem* menuItem = new SymbianMenuItem(); |
|
155 menuItem->menuItemData.iCascadeId = action->command; |
|
156 menuItem->menuItemData.iCommandId = action->command; |
|
157 menuItem->menuItemData.iFlags = 0; |
|
158 menuItem->menuItemData.iText = menuItemText; |
|
159 menuItem->action = action->action; |
|
160 if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() ) |
|
161 menuItem->menuItemData.iFlags |= EEikMenuItemDimmed; |
|
162 parent->append(menuItem); |
|
163 |
|
164 if (action->action->menu()->actions().size() > 0) { |
|
165 for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) { |
|
166 QSymbianMenuAction *symbianAction2 = new QSymbianMenuAction; |
|
167 symbianAction2->action = action->action->menu()->actions().at(c2); |
|
168 QMenu * menu = symbianAction2->action->menu(); |
|
169 symbianAction2->command = qt_symbian_menu_static_cmd_id++; |
|
170 qt_symbian_insert_action(symbianAction2, &(menuItem->children)); |
|
171 } |
|
172 } |
|
173 |
|
174 } else { |
|
175 SymbianMenuItem* menuItem = new SymbianMenuItem(); |
|
176 menuItem->menuItemData.iCascadeId = 0; |
|
177 menuItem->menuItemData.iCommandId = action->command; |
|
178 menuItem->menuItemData.iFlags = 0; |
|
179 menuItem->menuItemData.iText = menuItemText; |
|
180 menuItem->action = action->action; |
|
181 if (!action->action->isEnabled()){ |
|
182 menuItem->menuItemData.iFlags += EEikMenuItemDimmed; |
|
183 } |
|
184 |
|
185 if (action->action->isCheckable()) { |
|
186 if (action->action->isChecked()) |
|
187 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn; |
|
188 else |
|
189 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox; |
|
190 } |
|
191 parent->append(menuItem); |
|
192 } |
|
193 } |
|
194 } |
|
195 |
|
196 void deleteAll(QList<SymbianMenuItem*> *items) |
|
197 { |
|
198 while (!items->isEmpty()) { |
|
199 SymbianMenuItem* temp = items->takeFirst(); |
|
200 deleteAll(&temp->children); |
|
201 delete temp; |
|
202 } |
|
203 } |
|
204 |
|
205 static void rebuildMenu() |
|
206 { |
|
207 widgetWithContextMenu = 0; |
|
208 QMenuBarPrivate *mb = 0; |
|
209 QWidget *w = qApp->activeWindow(); |
|
210 QWidget* focusWidget = QApplication::focusWidget(); |
|
211 if (focusWidget) { |
|
212 if (hasContextMenu(focusWidget)) |
|
213 widgetWithContextMenu = focusWidget; |
|
214 } |
|
215 |
|
216 if (w) { |
|
217 mb = menubars()->value(w); |
|
218 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
219 deleteAll( &symbianMenus ); |
|
220 if (!mb) |
|
221 return; |
|
222 mb->symbian_menubar->rebuild(); |
|
223 } |
|
224 } |
|
225 |
|
226 #ifdef Q_WS_S60 |
|
227 void qt_symbian_show_toplevel( CEikMenuPane* menuPane) |
|
228 { |
|
229 if (!menuExists()) |
|
230 return; |
|
231 rebuildMenu(); |
|
232 for (int i = 0; i < symbianMenus.count(); ++i) |
|
233 QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData)); |
|
234 } |
|
235 |
|
236 void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id) |
|
237 { |
|
238 SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus); |
|
239 if (menu) { |
|
240 for (int i = 0; i < menu->children.count(); ++i) |
|
241 QT_TRAP_THROWING(menuPane->AddMenuItemL(menu->children.at(i)->menuItemData)); |
|
242 } |
|
243 } |
|
244 #endif // Q_WS_S60 |
|
245 |
|
246 int QMenuBarPrivate::symbianCommands(int command) |
|
247 { |
|
248 int ret = 0; |
|
249 |
|
250 if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) { |
|
251 QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0)); |
|
252 QCoreApplication::postEvent(widgetWithContextMenu, event); |
|
253 ret = 1; |
|
254 } |
|
255 |
|
256 int size = nativeMenuBars.size(); |
|
257 for (int i = 0; i < nativeMenuBars.size(); ++i) { |
|
258 SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); |
|
259 if (!menu) |
|
260 continue; |
|
261 |
|
262 emit nativeMenuBars.at(i)->triggered(menu->action); |
|
263 menu->action->activate(QAction::Trigger); |
|
264 ret = 1; |
|
265 break; |
|
266 } |
|
267 |
|
268 return ret; |
|
269 } |
|
270 |
|
271 void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) |
|
272 { |
|
273 Q_Q(QMenuBar); |
|
274 if (parent && parent->isWindow()){ |
|
275 menubars()->insert(q->window(), this); |
|
276 symbian_menubar = new QSymbianMenuBarPrivate(this); |
|
277 nativeMenuBars.append(q); |
|
278 } |
|
279 } |
|
280 |
|
281 void QMenuBarPrivate::symbianDestroyMenuBar() |
|
282 { |
|
283 Q_Q(QMenuBar); |
|
284 int index = nativeMenuBars.indexOf(q); |
|
285 nativeMenuBars.removeAt(index); |
|
286 menubars()->remove(q->window(), this); |
|
287 rebuildMenu(); |
|
288 if (symbian_menubar) |
|
289 delete symbian_menubar; |
|
290 symbian_menubar = 0; |
|
291 } |
|
292 |
|
293 QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) |
|
294 { |
|
295 d = menubar; |
|
296 } |
|
297 |
|
298 QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() |
|
299 { |
|
300 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
301 deleteAll( &symbianMenus ); |
|
302 symbianMenus.clear(); |
|
303 d = 0; |
|
304 rebuild(); |
|
305 } |
|
306 |
|
307 QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate() |
|
308 { |
|
309 } |
|
310 |
|
311 QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate() |
|
312 { |
|
313 |
|
314 } |
|
315 |
|
316 void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before) |
|
317 { |
|
318 QSymbianMenuAction *action = new QSymbianMenuAction; |
|
319 action->action = a; |
|
320 action->command = qt_symbian_menu_static_cmd_id++; |
|
321 addAction(action, before); |
|
322 } |
|
323 |
|
324 void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) |
|
325 { |
|
326 if (!action) |
|
327 return; |
|
328 int before_index = actionItems.indexOf(before); |
|
329 if (before_index < 0) { |
|
330 before = 0; |
|
331 before_index = actionItems.size(); |
|
332 } |
|
333 actionItems.insert(before_index, action); |
|
334 } |
|
335 |
|
336 |
|
337 void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *) |
|
338 { |
|
339 rebuild(); |
|
340 } |
|
341 |
|
342 void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action) |
|
343 { |
|
344 actionItems.removeAll(action); |
|
345 delete action; |
|
346 action = 0; |
|
347 rebuild(); |
|
348 } |
|
349 |
|
350 void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) |
|
351 { |
|
352 } |
|
353 |
|
354 void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) |
|
355 { |
|
356 QSymbianMenuAction *action = new QSymbianMenuAction; |
|
357 action->action = a; |
|
358 action->command = qt_symbian_menu_static_cmd_id++; |
|
359 addAction(action, before); |
|
360 } |
|
361 |
|
362 void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) |
|
363 { |
|
364 if (!action) |
|
365 return; |
|
366 int before_index = actionItems.indexOf(before); |
|
367 if (before_index < 0) { |
|
368 before = 0; |
|
369 before_index = actionItems.size(); |
|
370 } |
|
371 actionItems.insert(before_index, action); |
|
372 } |
|
373 |
|
374 void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*) |
|
375 { |
|
376 rebuild(); |
|
377 } |
|
378 |
|
379 void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action) |
|
380 { |
|
381 actionItems.removeAll(action); |
|
382 delete action; |
|
383 rebuild(); |
|
384 } |
|
385 |
|
386 void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList<QAction*> &actions) |
|
387 { |
|
388 for (int i = 0; i <actions.size(); ++i) { |
|
389 QSymbianMenuAction *symbianActionTopLevel = new QSymbianMenuAction; |
|
390 symbianActionTopLevel->action = actions.at(i); |
|
391 symbianActionTopLevel->parent = 0; |
|
392 symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; |
|
393 qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); |
|
394 } |
|
395 } |
|
396 |
|
397 |
|
398 |
|
399 void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() |
|
400 { |
|
401 contexMenuCommand = 0; |
|
402 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
403 deleteAll( &symbianMenus ); |
|
404 if (d) |
|
405 insertNativeMenuItems(d->actions); |
|
406 |
|
407 contextMenuActionList.clear(); |
|
408 if (widgetWithContextMenu) { |
|
409 contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems |
|
410 contextAction()->setText(QMenuBar::tr("Actions")); |
|
411 contextMenuActionList.append(contextAction()); |
|
412 insertNativeMenuItems(contextMenuActionList); |
|
413 } |
|
414 } |
|
415 QT_END_NAMESPACE |
|
416 |
|
417 #endif //QT_NO_MENUBAR |