source: trunk/src/gui/widgets/qmenu_symbian.cpp@ 966

Last change on this file since 966 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the S60 port of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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 <private/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
64QT_BEGIN_NAMESPACE
65
66typedef QMultiHash<QWidget *, QMenuBarPrivate *> MenuBarHash;
67Q_GLOBAL_STATIC(MenuBarHash, menubars)
68
69struct SymbianMenuItem
70{
71 int id;
72 CEikMenuPaneItem::SData menuItemData;
73 QList<SymbianMenuItem*> children;
74 QAction* action;
75};
76
77Q_GLOBAL_STATIC_WITH_ARGS(QAction, contextAction, (0))
78
79static QList<SymbianMenuItem*> symbianMenus;
80static QList<QMenuBar*> nativeMenuBars;
81static uint qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
82static QPointer<QWidget> widgetWithContextMenu;
83static QList<QAction*> contextMenuActionList;
84static QWidget* actionMenu = NULL;
85static int contexMenuCommand=0;
86
87bool 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
96static 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
107static 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
124static 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
142static 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 actionText;
153 if (underlineShortCut)
154 actionText = action->action->text().left(CEikMenuPaneItem::SData::ENominalTextLength);
155 else
156 actionText = action->action->iconText().left(CEikMenuPaneItem::SData::ENominalTextLength);
157 TPtrC menuItemText = qt_QString2TPtrC(actionText);
158 if (action->action->menu()) {
159 SymbianMenuItem* menuItem = new SymbianMenuItem();
160 menuItem->menuItemData.iCascadeId = action->command;
161 menuItem->menuItemData.iCommandId = action->command;
162 menuItem->menuItemData.iFlags = 0;
163 menuItem->menuItemData.iText = menuItemText;
164 menuItem->action = action->action;
165 if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() )
166 menuItem->menuItemData.iFlags |= EEikMenuItemDimmed;
167 parent->append(menuItem);
168
169 if (action->action->menu()->actions().size() > 0) {
170 for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) {
171 QScopedPointer<QSymbianMenuAction> symbianAction2(new QSymbianMenuAction);
172 symbianAction2->action = action->action->menu()->actions().at(c2);
173 QMenu * menu = symbianAction2->action->menu();
174 symbianAction2->command = qt_symbian_menu_static_cmd_id++;
175 qt_symbian_insert_action(symbianAction2.data(), &(menuItem->children));
176 }
177 }
178
179 } else {
180 SymbianMenuItem* menuItem = new SymbianMenuItem();
181 menuItem->menuItemData.iCascadeId = 0;
182 menuItem->menuItemData.iCommandId = action->command;
183 menuItem->menuItemData.iFlags = 0;
184 menuItem->menuItemData.iText = menuItemText;
185 menuItem->action = action->action;
186 if (!action->action->isEnabled()){
187 menuItem->menuItemData.iFlags += EEikMenuItemDimmed;
188 }
189
190 if (action->action->isCheckable()) {
191 if (action->action->isChecked())
192 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn;
193 else
194 menuItem->menuItemData.iFlags += EEikMenuItemCheckBox;
195 }
196 parent->append(menuItem);
197 }
198 }
199}
200
201void deleteAll(QList<SymbianMenuItem*> *items)
202{
203 while (!items->isEmpty()) {
204 SymbianMenuItem* temp = items->takeFirst();
205 deleteAll(&temp->children);
206 delete temp;
207 }
208}
209
210static void rebuildMenu()
211{
212 widgetWithContextMenu = 0;
213 QMenuBarPrivate *mb = 0;
214 QWidget *w = qApp->activeWindow();
215 QWidget* focusWidget = QApplication::focusWidget();
216 if (focusWidget) {
217 if (hasContextMenu(focusWidget))
218 widgetWithContextMenu = focusWidget;
219 }
220
221 if (w) {
222 mb = menubars()->value(w);
223 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
224 deleteAll( &symbianMenus );
225 if (!mb)
226 return;
227 mb->symbian_menubar->rebuild();
228 }
229}
230
231#ifdef Q_WS_S60
232void qt_symbian_next_menu_from_action(QWidget *actionContainer)
233{
234 actionMenu = actionContainer;
235}
236
237void qt_symbian_show_toplevel( CEikMenuPane* menuPane)
238{
239 if (actionMenu) {
240 QMenuBarPrivate *mb = 0;
241 mb = menubars()->value(actionMenu);
242 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
243 deleteAll( &symbianMenus );
244 Q_ASSERT(mb);
245 mb->symbian_menubar->rebuild();
246 for (int i = 0; i < symbianMenus.count(); ++i)
247 QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData));
248 actionMenu = NULL;
249 return;
250 }
251
252 if (!menuExists())
253 return;
254 rebuildMenu();
255 for (int i = 0; i < symbianMenus.count(); ++i)
256 QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData));
257}
258
259void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id)
260{
261 SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus);
262 if (menu) {
263 // Normally first AddMenuItemL call for menuPane will create the item array.
264 // However if we don't have any items, we still need the item array. Otherwise
265 // menupane will crash. That's why we create item array here manually, and
266 // AddMenuItemL will then use the existing array.
267 CEikMenuPane::CItemArray* itemArray = q_check_ptr(new CEikMenuPane::CItemArray);
268 menuPane->SetItemArray(itemArray);
269 menuPane->SetItemArrayOwnedExternally(EFalse);
270
271 for (int i = 0; i < menu->children.count(); ++i)
272 QT_TRAP_THROWING(menuPane->AddMenuItemL(menu->children.at(i)->menuItemData));
273 }
274}
275#endif // Q_WS_S60
276
277int QMenuBarPrivate::symbianCommands(int command)
278{
279 int ret = 0;
280
281 if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) {
282 QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0));
283 QCoreApplication::postEvent(widgetWithContextMenu, event);
284 ret = 1;
285 }
286
287 int size = nativeMenuBars.size();
288 for (int i = 0; i < nativeMenuBars.size(); ++i) {
289 SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus);
290 if (!menu)
291 continue;
292
293 emit nativeMenuBars.at(i)->triggered(menu->action);
294 menu->action->activate(QAction::Trigger);
295 ret = 1;
296 break;
297 }
298
299 return ret;
300}
301
302void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent)
303{
304 Q_Q(QMenuBar);
305 if (parent) {
306 if(parent->isWindow()) {
307 menubars()->insert(q->window(), this);
308 symbian_menubar = new QSymbianMenuBarPrivate(this);
309 nativeMenuBars.append(q);
310 } else {
311 menubars()->insert(q->parentWidget(), this);
312 symbian_menubar = new QSymbianMenuBarPrivate(this);
313 nativeMenuBars.append(q);
314 }
315 }
316}
317
318void QMenuBarPrivate::symbianDestroyMenuBar()
319{
320 Q_Q(QMenuBar);
321 int index = nativeMenuBars.indexOf(q);
322 nativeMenuBars.removeAt(index);
323 menubars()->remove(q->window(), this);
324 menubars()->remove(q->parentWidget(), this);
325 rebuildMenu();
326 if (symbian_menubar)
327 delete symbian_menubar;
328 symbian_menubar = 0;
329}
330
331void QMenuBarPrivate::reparentMenuBar(QWidget *oldParent, QWidget *newParent)
332{
333 if (menubars()->contains(oldParent)) {
334 QMenuBarPrivate *object = menubars()->take(oldParent);
335 menubars()->insert(newParent, object);
336 }
337}
338
339QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar)
340{
341 d = menubar;
342}
343
344QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate()
345{
346 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
347 deleteAll( &symbianMenus );
348 symbianMenus.clear();
349 d = 0;
350 rebuild();
351}
352
353QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate()
354{
355}
356
357QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate()
358{
359
360}
361
362void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before)
363{
364 QSymbianMenuAction *action = new QSymbianMenuAction;
365 action->action = a;
366 action->command = qt_symbian_menu_static_cmd_id++;
367 addAction(action, before);
368}
369
370void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before)
371{
372 if (!action)
373 return;
374 int before_index = actionItems.indexOf(before);
375 if (before_index < 0) {
376 before = 0;
377 before_index = actionItems.size();
378 }
379 actionItems.insert(before_index, action);
380}
381
382
383void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *)
384{
385 rebuild();
386}
387
388void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action)
389{
390 actionItems.removeAll(action);
391 delete action;
392 action = 0;
393 rebuild();
394}
395
396void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool)
397{
398}
399
400void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before)
401{
402 QSymbianMenuAction *action = new QSymbianMenuAction;
403 action->action = a;
404 action->command = qt_symbian_menu_static_cmd_id++;
405 addAction(action, before);
406}
407
408void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before)
409{
410 if (!action)
411 return;
412 int before_index = actionItems.indexOf(before);
413 if (before_index < 0) {
414 before = 0;
415 before_index = actionItems.size();
416 }
417 actionItems.insert(before_index, action);
418}
419
420void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*)
421{
422 rebuild();
423}
424
425void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action)
426{
427 actionItems.removeAll(action);
428 delete action;
429 rebuild();
430}
431
432void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList<QAction*> &actions)
433{
434 for (int i = 0; i <actions.size(); ++i) {
435 QScopedPointer<QSymbianMenuAction> symbianActionTopLevel(new QSymbianMenuAction);
436 symbianActionTopLevel->action = actions.at(i);
437 symbianActionTopLevel->parent = 0;
438 symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++;
439 qt_symbian_insert_action(symbianActionTopLevel.data(), &symbianMenus);
440 }
441}
442
443
444
445void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild()
446{
447 contexMenuCommand = 0;
448 qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM;
449 deleteAll( &symbianMenus );
450 if (d)
451 insertNativeMenuItems(d->actions);
452
453 contextMenuActionList.clear();
454 if (widgetWithContextMenu) {
455 contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems
456 contextAction()->setText(QMenuBar::tr("Actions"));
457 contextMenuActionList.append(contextAction());
458 insertNativeMenuItems(contextMenuActionList);
459 }
460}
461QT_END_NAMESPACE
462
463#endif //QT_NO_MENUBAR
Note: See TracBrowser for help on using the repository browser.