/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the S60 port of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmenu.h" #include "qapplication.h" #include "qevent.h" #include "qstyle.h" #include "qdebug.h" #include "qwidgetaction.h" #include #include #include #include #include #ifdef Q_WS_S60 #include #include #include #include #include #endif #if !defined(QT_NO_MENUBAR) && defined(Q_WS_S60) QT_BEGIN_NAMESPACE typedef QMultiHash MenuBarHash; Q_GLOBAL_STATIC(MenuBarHash, menubars) struct SymbianMenuItem { int id; CEikMenuPaneItem::SData menuItemData; QList children; QAction* action; }; Q_GLOBAL_STATIC_WITH_ARGS(QAction, contextAction, (0)) static QList symbianMenus; static QList nativeMenuBars; static uint qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; static QPointer widgetWithContextMenu; static QList contextMenuActionList; static QWidget* actionMenu = NULL; static int contexMenuCommand=0; bool menuExists() { QWidget *w = qApp->activeWindow(); QMenuBarPrivate *mb = menubars()->value(w); if ((!mb) && !menubars()->count()) return false; return true; } static bool hasContextMenu(QWidget* widget) { if (!widget) return false; const Qt::ContextMenuPolicy policy = widget->contextMenuPolicy(); if (policy != Qt::NoContextMenu && policy != Qt::PreventContextMenu ) { return true; } return false; } static SymbianMenuItem* qt_symbian_find_menu(int id, const QList &parent) { int index=0; while (index < parent.count()) { SymbianMenuItem* temp = parent[index]; if (temp->menuItemData.iCascadeId == id) return temp; else if (temp->menuItemData.iCascadeId != 0) { SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children); if (result) return result; } index++; } return 0; } static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList &parent) { int index=0; while (index < parent.count()) { SymbianMenuItem* temp = parent[index]; if (temp->menuItemData.iCascadeId != 0) { SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children); if (result) return result; } else if (temp->menuItemData.iCommandId == id) return temp; index++; } return 0; } static void qt_symbian_insert_action(QSymbianMenuAction* action, QList* parent) { if (action->action->isVisible()) { if (action->action->isSeparator()) return; Q_ASSERT_X(action->command <= QT_SYMBIAN_LAST_MENU_ITEM, "qt_symbian_insert_action", "Too many menu actions"); const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut); QString actionText; if (underlineShortCut) actionText = action->action->text().left(CEikMenuPaneItem::SData::ENominalTextLength); else actionText = action->action->iconText().left(CEikMenuPaneItem::SData::ENominalTextLength); TPtrC menuItemText = qt_QString2TPtrC(actionText); if (action->action->menu()) { SymbianMenuItem* menuItem = new SymbianMenuItem(); menuItem->menuItemData.iCascadeId = action->command; menuItem->menuItemData.iCommandId = action->command; menuItem->menuItemData.iFlags = 0; menuItem->menuItemData.iText = menuItemText; menuItem->action = action->action; if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() ) menuItem->menuItemData.iFlags |= EEikMenuItemDimmed; parent->append(menuItem); if (action->action->menu()->actions().size() > 0) { for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) { QSymbianMenuAction *symbianAction2 = new QSymbianMenuAction; symbianAction2->action = action->action->menu()->actions().at(c2); QMenu * menu = symbianAction2->action->menu(); symbianAction2->command = qt_symbian_menu_static_cmd_id++; qt_symbian_insert_action(symbianAction2, &(menuItem->children)); } } } else { SymbianMenuItem* menuItem = new SymbianMenuItem(); menuItem->menuItemData.iCascadeId = 0; menuItem->menuItemData.iCommandId = action->command; menuItem->menuItemData.iFlags = 0; menuItem->menuItemData.iText = menuItemText; menuItem->action = action->action; if (!action->action->isEnabled()){ menuItem->menuItemData.iFlags += EEikMenuItemDimmed; } if (action->action->isCheckable()) { if (action->action->isChecked()) menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn; else menuItem->menuItemData.iFlags += EEikMenuItemCheckBox; } parent->append(menuItem); } } } void deleteAll(QList *items) { while (!items->isEmpty()) { SymbianMenuItem* temp = items->takeFirst(); deleteAll(&temp->children); delete temp; } } static void rebuildMenu() { widgetWithContextMenu = 0; QMenuBarPrivate *mb = 0; QWidget *w = qApp->activeWindow(); QWidget* focusWidget = QApplication::focusWidget(); if (focusWidget) { if (hasContextMenu(focusWidget)) widgetWithContextMenu = focusWidget; } if (w) { mb = menubars()->value(w); qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; deleteAll( &symbianMenus ); if (!mb) return; mb->symbian_menubar->rebuild(); } } #ifdef Q_WS_S60 void qt_symbian_next_menu_from_action(QWidget *actionContainer) { actionMenu = actionContainer; } void qt_symbian_show_toplevel( CEikMenuPane* menuPane) { if (actionMenu) { QMenuBarPrivate *mb = 0; mb = menubars()->value(actionMenu); qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; deleteAll( &symbianMenus ); Q_ASSERT(mb); mb->symbian_menubar->rebuild(); for (int i = 0; i < symbianMenus.count(); ++i) QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData)); actionMenu = NULL; return; } if (!menuExists()) return; rebuildMenu(); for (int i = 0; i < symbianMenus.count(); ++i) QT_TRAP_THROWING(menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData)); } void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id) { SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus); if (menu) { // Normally first AddMenuItemL call for menuPane will create the item array. // However if we don't have any items, we still need the item array. Otherwise // menupane will crash. That's why we create item array here manually, and // AddMenuItemL will then use the existing array. CEikMenuPane::CItemArray* itemArray = new CEikMenuPane::CItemArray; Q_CHECK_PTR(itemArray); menuPane->SetItemArray(itemArray); menuPane->SetItemArrayOwnedExternally(EFalse); for (int i = 0; i < menu->children.count(); ++i) QT_TRAP_THROWING(menuPane->AddMenuItemL(menu->children.at(i)->menuItemData)); } } #endif // Q_WS_S60 int QMenuBarPrivate::symbianCommands(int command) { int ret = 0; if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) { QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0)); QCoreApplication::postEvent(widgetWithContextMenu, event); ret = 1; } int size = nativeMenuBars.size(); for (int i = 0; i < nativeMenuBars.size(); ++i) { SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); if (!menu) continue; emit nativeMenuBars.at(i)->triggered(menu->action); menu->action->activate(QAction::Trigger); ret = 1; break; } return ret; } void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) { Q_Q(QMenuBar); if (parent) { if(parent->isWindow()) { menubars()->insert(q->window(), this); symbian_menubar = new QSymbianMenuBarPrivate(this); nativeMenuBars.append(q); } else { menubars()->insert(q->parentWidget(), this); symbian_menubar = new QSymbianMenuBarPrivate(this); nativeMenuBars.append(q); } } } void QMenuBarPrivate::symbianDestroyMenuBar() { Q_Q(QMenuBar); int index = nativeMenuBars.indexOf(q); nativeMenuBars.removeAt(index); menubars()->remove(q->window(), this); menubars()->remove(q->parentWidget(), this); rebuildMenu(); if (symbian_menubar) delete symbian_menubar; symbian_menubar = 0; } void QMenuBarPrivate::reparentMenuBar(QWidget *oldParent, QWidget *newParent) { if (menubars()->contains(oldParent)) { QMenuBarPrivate *object = menubars()->take(oldParent); menubars()->insert(newParent, object); } } QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) { d = menubar; } QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() { qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; deleteAll( &symbianMenus ); symbianMenus.clear(); d = 0; rebuild(); } QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate() { } QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate() { } void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before) { QSymbianMenuAction *action = new QSymbianMenuAction; action->action = a; action->command = qt_symbian_menu_static_cmd_id++; addAction(action, before); } void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) { if (!action) return; int before_index = actionItems.indexOf(before); if (before_index < 0) { before = 0; before_index = actionItems.size(); } actionItems.insert(before_index, action); } void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *) { rebuild(); } void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action) { actionItems.removeAll(action); delete action; action = 0; rebuild(); } void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) { } void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) { QSymbianMenuAction *action = new QSymbianMenuAction; action->action = a; action->command = qt_symbian_menu_static_cmd_id++; addAction(action, before); } void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) { if (!action) return; int before_index = actionItems.indexOf(before); if (before_index < 0) { before = 0; before_index = actionItems.size(); } actionItems.insert(before_index, action); } void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*) { rebuild(); } void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action) { actionItems.removeAll(action); delete action; rebuild(); } void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList &actions) { for (int i = 0; i action = actions.at(i); symbianActionTopLevel->parent = 0; symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); } } void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() { contexMenuCommand = 0; qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; deleteAll( &symbianMenus ); if (d) insertNativeMenuItems(d->actions); contextMenuActionList.clear(); if (widgetWithContextMenu) { contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems contextAction()->setText(QMenuBar::tr("Actions")); contextMenuActionList.append(contextAction()); insertNativeMenuItems(contextMenuActionList); } } QT_END_NAMESPACE #endif //QT_NO_MENUBAR