|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 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 QWidget* actionMenu = NULL; |
|
85 static int contexMenuCommand=0; |
|
86 |
|
87 bool menuExists() |
|
88 { |
|
89 QWidget *w = qApp->activeWindow(); |
|
90 QMenuBarPrivate *mb = menubars()->value(w); |
|
91 if ((!mb) && !menubars()->count()) |
|
92 return false; |
|
93 return true; |
|
94 } |
|
95 |
|
96 static bool hasContextMenu(QWidget* widget) |
|
97 { |
|
98 if (!widget) |
|
99 return false; |
|
100 const Qt::ContextMenuPolicy policy = widget->contextMenuPolicy(); |
|
101 if (policy != Qt::NoContextMenu && policy != Qt::PreventContextMenu ) { |
|
102 return true; |
|
103 } |
|
104 return false; |
|
105 } |
|
106 |
|
107 static SymbianMenuItem* qt_symbian_find_menu(int id, const QList<SymbianMenuItem*> &parent) |
|
108 { |
|
109 int index=0; |
|
110 while (index < parent.count()) { |
|
111 SymbianMenuItem* temp = parent[index]; |
|
112 if (temp->menuItemData.iCascadeId == id) |
|
113 return temp; |
|
114 else if (temp->menuItemData.iCascadeId != 0) { |
|
115 SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children); |
|
116 if (result) |
|
117 return result; |
|
118 } |
|
119 index++; |
|
120 } |
|
121 return 0; |
|
122 } |
|
123 |
|
124 static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList<SymbianMenuItem*> &parent) |
|
125 { |
|
126 int index=0; |
|
127 while (index < parent.count()) { |
|
128 SymbianMenuItem* temp = parent[index]; |
|
129 if (temp->menuItemData.iCascadeId != 0) { |
|
130 SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children); |
|
131 if (result) |
|
132 return result; |
|
133 } |
|
134 else if (temp->menuItemData.iCommandId == id) |
|
135 return temp; |
|
136 index++; |
|
137 |
|
138 } |
|
139 return 0; |
|
140 } |
|
141 |
|
142 static void qt_symbian_insert_action(QSymbianMenuAction* action, QList<SymbianMenuItem*>* parent) |
|
143 { |
|
144 if (action->action->isVisible()) { |
|
145 if (action->action->isSeparator()) |
|
146 return; |
|
147 |
|
148 Q_ASSERT_X(action->command <= QT_SYMBIAN_LAST_MENU_ITEM, "qt_symbian_insert_action", |
|
149 "Too many menu actions"); |
|
150 |
|
151 const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut); |
|
152 QString iconText = action->action->iconText(); |
|
153 TPtrC menuItemText = qt_QString2TPtrC( underlineShortCut ? action->action->text() : iconText); |
|
154 if (action->action->menu()) { |
|
155 SymbianMenuItem* menuItem = new SymbianMenuItem(); |
|
156 menuItem->menuItemData.iCascadeId = action->command; |
|
157 menuItem->menuItemData.iCommandId = action->command; |
|
158 menuItem->menuItemData.iFlags = 0; |
|
159 menuItem->menuItemData.iText = menuItemText; |
|
160 menuItem->action = action->action; |
|
161 if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() ) |
|
162 menuItem->menuItemData.iFlags |= EEikMenuItemDimmed; |
|
163 parent->append(menuItem); |
|
164 |
|
165 if (action->action->menu()->actions().size() > 0) { |
|
166 for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) { |
|
167 QSymbianMenuAction *symbianAction2 = new QSymbianMenuAction; |
|
168 symbianAction2->action = action->action->menu()->actions().at(c2); |
|
169 QMenu * menu = symbianAction2->action->menu(); |
|
170 symbianAction2->command = qt_symbian_menu_static_cmd_id++; |
|
171 qt_symbian_insert_action(symbianAction2, &(menuItem->children)); |
|
172 } |
|
173 } |
|
174 |
|
175 } else { |
|
176 SymbianMenuItem* menuItem = new SymbianMenuItem(); |
|
177 menuItem->menuItemData.iCascadeId = 0; |
|
178 menuItem->menuItemData.iCommandId = action->command; |
|
179 menuItem->menuItemData.iFlags = 0; |
|
180 menuItem->menuItemData.iText = menuItemText; |
|
181 menuItem->action = action->action; |
|
182 if (!action->action->isEnabled()){ |
|
183 menuItem->menuItemData.iFlags += EEikMenuItemDimmed; |
|
184 } |
|
185 |
|
186 if (action->action->isCheckable()) { |
|
187 if (action->action->isChecked()) |
|
188 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn; |
|
189 else |
|
190 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox; |
|
191 } |
|
192 parent->append(menuItem); |
|
193 } |
|
194 } |
|
195 } |
|
196 |
|
197 void deleteAll(QList<SymbianMenuItem*> *items) |
|
198 { |
|
199 while (!items->isEmpty()) { |
|
200 SymbianMenuItem* temp = items->takeFirst(); |
|
201 deleteAll(&temp->children); |
|
202 delete temp; |
|
203 } |
|
204 } |
|
205 |
|
206 static void rebuildMenu() |
|
207 { |
|
208 widgetWithContextMenu = 0; |
|
209 QMenuBarPrivate *mb = 0; |
|
210 QWidget *w = qApp->activeWindow(); |
|
211 QWidget* focusWidget = QApplication::focusWidget(); |
|
212 if (focusWidget) { |
|
213 if (hasContextMenu(focusWidget)) |
|
214 widgetWithContextMenu = focusWidget; |
|
215 } |
|
216 |
|
217 if (w) { |
|
218 mb = menubars()->value(w); |
|
219 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
220 deleteAll( &symbianMenus ); |
|
221 if (!mb) |
|
222 return; |
|
223 mb->symbian_menubar->rebuild(); |
|
224 } |
|
225 } |
|
226 |
|
227 #ifdef Q_WS_S60 |
|
228 void qt_symbian_next_menu_from_action(QWidget *actionContainer) |
|
229 { |
|
230 actionMenu = actionContainer; |
|
231 } |
|
232 |
|
233 void qt_symbian_show_toplevel( CEikMenuPane* menuPane) |
|
234 { |
|
235 if (actionMenu) { |
|
236 QMenuBarPrivate *mb = 0; |
|
237 mb = menubars()->value(actionMenu); |
|
238 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
239 deleteAll( &symbianMenus ); |
|
240 Q_ASSERT(mb); |
|
241 mb->symbian_menubar->rebuild(); |
|
242 for (int i = 0; i < symbianMenus.count(); ++i) |
|
243 QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData)); |
|
244 actionMenu = NULL; |
|
245 return; |
|
246 } |
|
247 |
|
248 if (!menuExists()) |
|
249 return; |
|
250 rebuildMenu(); |
|
251 for (int i = 0; i < symbianMenus.count(); ++i) |
|
252 QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData)); |
|
253 } |
|
254 |
|
255 void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id) |
|
256 { |
|
257 SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus); |
|
258 if (menu) { |
|
259 // Normally first AddMenuItemL call for menuPane will create the item array. |
|
260 // However if we don't have any items, we still need the item array. Otherwise |
|
261 // menupane will crash. That's why we create item array here manually, and |
|
262 // AddMenuItemL will then use the existing array. |
|
263 CEikMenuPane::CItemArray* itemArray = q_check_ptr(new CEikMenuPane::CItemArray); |
|
264 menuPane->SetItemArray(itemArray); |
|
265 menuPane->SetItemArrayOwnedExternally(EFalse); |
|
266 |
|
267 for (int i = 0; i < menu->children.count(); ++i) |
|
268 QT_TRAP_THROWING(menuPane->AddMenuItemL(menu->children.at(i)->menuItemData)); |
|
269 } |
|
270 } |
|
271 #endif // Q_WS_S60 |
|
272 |
|
273 int QMenuBarPrivate::symbianCommands(int command) |
|
274 { |
|
275 int ret = 0; |
|
276 |
|
277 if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) { |
|
278 QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0)); |
|
279 QCoreApplication::postEvent(widgetWithContextMenu, event); |
|
280 ret = 1; |
|
281 } |
|
282 |
|
283 int size = nativeMenuBars.size(); |
|
284 for (int i = 0; i < nativeMenuBars.size(); ++i) { |
|
285 SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); |
|
286 if (!menu) |
|
287 continue; |
|
288 |
|
289 emit nativeMenuBars.at(i)->triggered(menu->action); |
|
290 menu->action->activate(QAction::Trigger); |
|
291 ret = 1; |
|
292 break; |
|
293 } |
|
294 |
|
295 return ret; |
|
296 } |
|
297 |
|
298 void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) |
|
299 { |
|
300 Q_Q(QMenuBar); |
|
301 if (parent) { |
|
302 if(parent->isWindow()) { |
|
303 menubars()->insert(q->window(), this); |
|
304 symbian_menubar = new QSymbianMenuBarPrivate(this); |
|
305 nativeMenuBars.append(q); |
|
306 } else { |
|
307 menubars()->insert(q->parentWidget(), this); |
|
308 symbian_menubar = new QSymbianMenuBarPrivate(this); |
|
309 nativeMenuBars.append(q); |
|
310 } |
|
311 } |
|
312 } |
|
313 |
|
314 void QMenuBarPrivate::symbianDestroyMenuBar() |
|
315 { |
|
316 Q_Q(QMenuBar); |
|
317 int index = nativeMenuBars.indexOf(q); |
|
318 nativeMenuBars.removeAt(index); |
|
319 menubars()->remove(q->window(), this); |
|
320 menubars()->remove(q->parentWidget(), this); |
|
321 rebuildMenu(); |
|
322 if (symbian_menubar) |
|
323 delete symbian_menubar; |
|
324 symbian_menubar = 0; |
|
325 } |
|
326 |
|
327 void QMenuBarPrivate::reparentMenuBar(QWidget *oldParent, QWidget *newParent) |
|
328 { |
|
329 if (menubars()->contains(oldParent)) { |
|
330 QMenuBarPrivate *object = menubars()->take(oldParent); |
|
331 menubars()->insert(newParent, object); |
|
332 } |
|
333 } |
|
334 |
|
335 QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) |
|
336 { |
|
337 d = menubar; |
|
338 } |
|
339 |
|
340 QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() |
|
341 { |
|
342 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
343 deleteAll( &symbianMenus ); |
|
344 symbianMenus.clear(); |
|
345 d = 0; |
|
346 rebuild(); |
|
347 } |
|
348 |
|
349 QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate() |
|
350 { |
|
351 } |
|
352 |
|
353 QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate() |
|
354 { |
|
355 |
|
356 } |
|
357 |
|
358 void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before) |
|
359 { |
|
360 QSymbianMenuAction *action = new QSymbianMenuAction; |
|
361 action->action = a; |
|
362 action->command = qt_symbian_menu_static_cmd_id++; |
|
363 addAction(action, before); |
|
364 } |
|
365 |
|
366 void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) |
|
367 { |
|
368 if (!action) |
|
369 return; |
|
370 int before_index = actionItems.indexOf(before); |
|
371 if (before_index < 0) { |
|
372 before = 0; |
|
373 before_index = actionItems.size(); |
|
374 } |
|
375 actionItems.insert(before_index, action); |
|
376 } |
|
377 |
|
378 |
|
379 void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *) |
|
380 { |
|
381 rebuild(); |
|
382 } |
|
383 |
|
384 void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action) |
|
385 { |
|
386 actionItems.removeAll(action); |
|
387 delete action; |
|
388 action = 0; |
|
389 rebuild(); |
|
390 } |
|
391 |
|
392 void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) |
|
393 { |
|
394 } |
|
395 |
|
396 void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) |
|
397 { |
|
398 QSymbianMenuAction *action = new QSymbianMenuAction; |
|
399 action->action = a; |
|
400 action->command = qt_symbian_menu_static_cmd_id++; |
|
401 addAction(action, before); |
|
402 } |
|
403 |
|
404 void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) |
|
405 { |
|
406 if (!action) |
|
407 return; |
|
408 int before_index = actionItems.indexOf(before); |
|
409 if (before_index < 0) { |
|
410 before = 0; |
|
411 before_index = actionItems.size(); |
|
412 } |
|
413 actionItems.insert(before_index, action); |
|
414 } |
|
415 |
|
416 void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*) |
|
417 { |
|
418 rebuild(); |
|
419 } |
|
420 |
|
421 void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action) |
|
422 { |
|
423 actionItems.removeAll(action); |
|
424 delete action; |
|
425 rebuild(); |
|
426 } |
|
427 |
|
428 void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList<QAction*> &actions) |
|
429 { |
|
430 for (int i = 0; i <actions.size(); ++i) { |
|
431 QSymbianMenuAction *symbianActionTopLevel = new QSymbianMenuAction; |
|
432 symbianActionTopLevel->action = actions.at(i); |
|
433 symbianActionTopLevel->parent = 0; |
|
434 symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; |
|
435 qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); |
|
436 } |
|
437 } |
|
438 |
|
439 |
|
440 |
|
441 void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() |
|
442 { |
|
443 contexMenuCommand = 0; |
|
444 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; |
|
445 deleteAll( &symbianMenus ); |
|
446 if (d) |
|
447 insertNativeMenuItems(d->actions); |
|
448 |
|
449 contextMenuActionList.clear(); |
|
450 if (widgetWithContextMenu) { |
|
451 contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems |
|
452 contextAction()->setText(QMenuBar::tr("Actions")); |
|
453 contextMenuActionList.append(contextAction()); |
|
454 insertNativeMenuItems(contextMenuActionList); |
|
455 } |
|
456 } |
|
457 QT_END_NAMESPACE |
|
458 |
|
459 #endif //QT_NO_MENUBAR |