tools/designer/src/lib/shared/qdesigner_menubar.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/designer/src/lib/shared/qdesigner_menubar.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,971 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Designer 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 "qdesigner_menubar_p.h"
+#include "qdesigner_menu_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "actionrepository_p.h"
+#include "actionprovider_p.h"
+#include "actioneditor_p.h"
+#include "qdesigner_utils_p.h"
+#include "promotiontaskmenu_p.h"
+#include "qdesigner_objectinspector_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+#include <QtDesigner/QDesignerFormEditorInterface>
+#include <QtDesigner/QDesignerWidgetFactoryInterface>
+#include <QtDesigner/QExtensionManager>
+
+#include <QtCore/QMimeData>
+
+#include <QtCore/qdebug.h>
+
+#include <QtGui/QApplication>
+#include <QtGui/QDrag>
+#include <QtGui/QLineEdit>
+#include <QtGui/QPainter>
+#include <QtGui/qevent.h>
+
+Q_DECLARE_METATYPE(QAction*)
+
+QT_BEGIN_NAMESPACE
+
+typedef QList<QAction *> ActionList;
+
+using namespace qdesigner_internal;
+
+namespace qdesigner_internal
+{
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+SpecialMenuAction::SpecialMenuAction(QObject *parent)
+    : QAction(parent)
+{
+}
+
+SpecialMenuAction::~SpecialMenuAction()
+{
+}
+
+
+} // namespace qdesigner_internal
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+QDesignerMenuBar::QDesignerMenuBar(QWidget *parent)  :
+    QMenuBar(parent),
+    m_addMenu(new SpecialMenuAction(this)),
+    m_currentIndex(0),
+    m_interactive(true),
+    m_editor(new QLineEdit(this)),
+    m_dragging(false),
+    m_lastMenuActionIndex( -1),
+    m_promotionTaskMenu(new PromotionTaskMenu(this, PromotionTaskMenu::ModeSingleWidget, this))
+{
+    setContextMenuPolicy(Qt::DefaultContextMenu);
+
+    setAcceptDrops(true); // ### fake
+    // Fake property: Keep the menu bar editable in the form even if a native menu bar is used.
+    setNativeMenuBar(false);
+
+    m_addMenu->setText(tr("Type Here"));
+    addAction(m_addMenu);
+
+    QFont italic;
+    italic.setItalic(true);
+    m_addMenu->setFont(italic);
+
+    m_editor->setObjectName(QLatin1String("__qt__passive_editor"));
+    m_editor->hide();
+    m_editor->installEventFilter(this);
+    installEventFilter(this);
+}
+
+QDesignerMenuBar::~QDesignerMenuBar()
+{
+}
+
+void QDesignerMenuBar::paintEvent(QPaintEvent *event)
+{
+    QMenuBar::paintEvent(event);
+
+    QPainter p(this);
+
+    foreach (QAction *a, actions()) {
+        if (qobject_cast<SpecialMenuAction*>(a)) {
+            const QRect g = actionGeometry(a);
+            QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
+            lg.setColorAt(0.0, Qt::transparent);
+            lg.setColorAt(0.7, QColor(0, 0, 0, 32));
+            lg.setColorAt(1.0, Qt::transparent);
+
+            p.fillRect(g, lg);
+        }
+    }
+
+    QAction *action = currentAction();
+
+    if (m_dragging || !action)
+        return;
+
+    if (hasFocus()) {
+        const QRect g = actionGeometry(action);
+        QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1));
+    } else if (action->menu() && action->menu()->isVisible()) {
+        const QRect g = actionGeometry(action);
+        p.drawRect(g.adjusted(1, 1, -1, -1));
+    }
+}
+
+bool QDesignerMenuBar::handleEvent(QWidget *widget, QEvent *event)
+{
+    if (!formWindow())
+        return false;
+
+    if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
+        update();
+
+    switch (event->type()) {
+        default: break;
+
+        case QEvent::MouseButtonDblClick:
+            return handleMouseDoubleClickEvent(widget, static_cast<QMouseEvent*>(event));
+        case QEvent::MouseButtonPress:
+            return handleMousePressEvent(widget, static_cast<QMouseEvent*>(event));
+        case QEvent::MouseButtonRelease:
+            return handleMouseReleaseEvent(widget, static_cast<QMouseEvent*>(event));
+        case QEvent::MouseMove:
+            return handleMouseMoveEvent(widget, static_cast<QMouseEvent*>(event));
+        case QEvent::ContextMenu:
+            return handleContextMenuEvent(widget, static_cast<QContextMenuEvent*>(event));
+        case QEvent::KeyPress:
+            return handleKeyPressEvent(widget, static_cast<QKeyEvent*>(event));
+        case QEvent::FocusIn:
+        case QEvent::FocusOut:
+            return widget != m_editor;
+    }
+
+    return true;
+}
+
+bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
+{
+    if (!rect().contains(event->pos()))
+        return true;
+
+    if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+        return true;
+
+    event->accept();
+
+    m_startPosition = QPoint();
+
+    m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal);
+    if (m_currentIndex != -1) {
+        showLineEdit();
+    }
+
+    return true;
+}
+
+bool QDesignerMenuBar::handleKeyPressEvent(QWidget *, QKeyEvent *e)
+{
+    if (m_editor->isHidden()) { // In navigation mode
+        switch (e->key()) {
+
+        case Qt::Key_Delete:
+            if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
+                break;
+            hideMenu();
+            deleteMenu();
+            break;
+
+        case Qt::Key_Left:
+            e->accept();
+            moveLeft(e->modifiers() & Qt::ControlModifier);
+            return true;
+
+        case Qt::Key_Right:
+            e->accept();
+            moveRight(e->modifiers() & Qt::ControlModifier);
+            return true; // no update
+
+        case Qt::Key_Up:
+            e->accept();
+            moveUp();
+            return true;
+
+        case Qt::Key_Down:
+            e->accept();
+            moveDown();
+            return true;
+
+        case Qt::Key_PageUp:
+            m_currentIndex = 0;
+            break;
+
+        case Qt::Key_PageDown:
+            m_currentIndex = actions().count() - 1;
+            break;
+
+        case Qt::Key_Enter:
+        case Qt::Key_Return:
+            e->accept();
+            enterEditMode();
+            return true; // no update
+
+        case Qt::Key_Alt:
+        case Qt::Key_Shift:
+        case Qt::Key_Control:
+        case Qt::Key_Escape:
+            e->ignore();
+            setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed
+            return true; // no update
+
+        default:
+            if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
+                showLineEdit();
+                QApplication::sendEvent(m_editor, e);
+                e->accept();
+            } else {
+                e->ignore();
+            }
+            return true;
+        }
+    } else { // In edit mode
+        switch (e->key()) {
+        default:
+            return false;
+
+        case Qt::Key_Control:
+            e->ignore();
+            return true;
+
+        case Qt::Key_Enter:
+        case Qt::Key_Return:
+            if (!m_editor->text().isEmpty()) {
+                leaveEditMode(ForceAccept);
+                if (m_lastFocusWidget)
+                    m_lastFocusWidget->setFocus();
+
+                m_editor->hide();
+                showMenu();
+                break;
+            }
+            // fall through
+
+        case Qt::Key_Escape:
+            update();
+            setFocus();
+            break;
+        }
+    }
+
+    e->accept();
+    update();
+
+    return true;
+}
+
+void QDesignerMenuBar::startDrag(const QPoint &pos)
+{
+    const int index = findAction(pos);
+    if (m_currentIndex == -1 || index >= realActionCount())
+        return;
+
+    QAction *action = safeActionAt(index);
+
+    QDesignerFormWindowInterface *fw = formWindow();
+    RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
+    cmd->init(this, action, actions().at(index + 1));
+    fw->commandHistory()->push(cmd);
+
+    adjustSize();
+
+    hideMenu(index);
+
+    QDrag *drag = new QDrag(this);
+    drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
+    drag->setMimeData(new ActionRepositoryMimeData(action, Qt::MoveAction));
+
+    const int old_index = m_currentIndex;
+    m_currentIndex = -1;
+
+    if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) {
+        InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+        cmd->init(this, action, safeActionAt(index));
+        fw->commandHistory()->push(cmd);
+
+        m_currentIndex = old_index;
+        adjustSize();
+    }
+}
+
+bool QDesignerMenuBar::handleMousePressEvent(QWidget *, QMouseEvent *event)
+{
+    m_startPosition = QPoint();
+    event->accept();
+
+    if (event->button() != Qt::LeftButton)
+        return true;
+
+    m_startPosition = event->pos();
+    const int newIndex = actionIndexAt(this, m_startPosition, Qt::Horizontal);
+    const bool changed = newIndex != m_currentIndex;
+    m_currentIndex =  newIndex;
+    updateCurrentAction(changed);
+
+    return true;
+}
+
+bool QDesignerMenuBar::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
+{
+    m_startPosition = QPoint();
+
+    if (event->button() != Qt::LeftButton)
+        return true;
+
+    event->accept();
+    m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal);
+    if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount())
+        showMenu();
+
+    return true;
+}
+
+bool QDesignerMenuBar::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
+{
+    if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
+        return true;
+
+    if (m_startPosition.isNull())
+        return true;
+
+    const QPoint pos = mapFromGlobal(event->globalPos());
+
+    if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
+        return true;
+
+    const int index =  actionIndexAt(this, m_startPosition, Qt::Horizontal);
+    if (index < actions().count()) {
+        hideMenu(index);
+        update();
+    }
+
+    startDrag(m_startPosition);
+    m_startPosition = QPoint();
+
+    return true;
+}
+
+ActionList QDesignerMenuBar::contextMenuActions()
+{
+    ActionList rc;
+    if (QAction *action = safeActionAt(m_currentIndex)) {
+        if (!qobject_cast<SpecialMenuAction*>(action)) {
+            QVariant itemData;
+            qVariantSetValue(itemData, action);
+
+            QAction *remove_action = new QAction(tr("Remove Menu '%1'").arg(action->menu()->objectName()), 0);
+            remove_action->setData(itemData);
+            connect(remove_action, SIGNAL(triggered()), this, SLOT(deleteMenu()));
+            rc.push_back(remove_action);
+            QAction *sep = new QAction(0);
+            sep->setSeparator(true);
+            rc.push_back(sep);
+        }
+    }
+
+    m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc);
+
+    QAction *remove_menubar = new QAction(tr("Remove Menu Bar"), 0);
+    connect(remove_menubar, SIGNAL(triggered()), this, SLOT(slotRemoveMenuBar()));
+    rc.push_back(remove_menubar);
+    return rc;
+}
+
+bool QDesignerMenuBar::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
+{
+    event->accept();
+
+    m_currentIndex = actionIndexAt(this, mapFromGlobal(event->globalPos()), Qt::Horizontal);
+
+    update();
+
+    QMenu menu;
+    const ActionList al = contextMenuActions();
+    const ActionList::const_iterator acend = al.constEnd();
+    for (ActionList::const_iterator it =  al.constBegin(); it != acend; ++it)
+        menu.addAction(*it);
+    menu.exec(event->globalPos());
+    return true;
+}
+
+void QDesignerMenuBar::slotRemoveMenuBar()
+{
+    Q_ASSERT(formWindow() != 0);
+
+    QDesignerFormWindowInterface *fw = formWindow();
+
+    DeleteMenuBarCommand *cmd = new DeleteMenuBarCommand(fw);
+    cmd->init(this);
+    fw->commandHistory()->push(cmd);
+}
+
+void QDesignerMenuBar::focusOutEvent(QFocusEvent *event)
+{
+    QMenuBar::focusOutEvent(event);
+}
+
+void QDesignerMenuBar::enterEditMode()
+{
+    if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
+        showLineEdit();
+    }
+}
+
+void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode)
+{
+    m_editor->releaseKeyboard();
+
+    if (mode == Default)
+        return;
+
+    if (m_editor->text().isEmpty())
+        return;
+
+    QAction *action = 0;
+
+    QDesignerFormWindowInterface *fw = formWindow();
+    Q_ASSERT(fw);
+
+    if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) {
+        action = safeActionAt(m_currentIndex);
+        fw->beginCommand(QApplication::translate("Command", "Change Title"));
+    } else {
+        fw->beginCommand(QApplication::translate("Command", "Insert Menu"));
+        const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), QLatin1String("menu"));
+        QMenu *menu = qobject_cast<QMenu*>(fw->core()->widgetFactory()->createWidget(QLatin1String("QMenu"), this));
+        fw->core()->widgetFactory()->initialize(menu);
+        menu->setObjectName(niceObjectName);
+        menu->setTitle(tr("Menu"));
+        fw->ensureUniqueObjectName(menu);
+        action = menu->menuAction();
+        AddMenuActionCommand *cmd = new AddMenuActionCommand(fw);
+        cmd->init(action, m_addMenu, this, this);
+        fw->commandHistory()->push(cmd);
+    }
+
+    SetPropertyCommand *cmd = new SetPropertyCommand(fw);
+    cmd->init(action, QLatin1String("text"), m_editor->text());
+    fw->commandHistory()->push(cmd);
+    fw->endCommand();
+}
+
+void QDesignerMenuBar::showLineEdit()
+{
+    QAction *action = 0;
+
+    if (m_currentIndex >= 0 && m_currentIndex < realActionCount())
+        action = safeActionAt(m_currentIndex);
+    else
+        action = m_addMenu;
+
+    if (action->isSeparator())
+        return;
+
+    // hideMenu();
+
+    m_lastFocusWidget = qApp->focusWidget();
+
+    // open edit field for item name
+    const QString text = action != m_addMenu ? action->text() : QString();
+
+    m_editor->setText(text);
+    m_editor->selectAll();
+    m_editor->setGeometry(actionGeometry(action));
+    m_editor->show();
+    qApp->setActiveWindow(m_editor);
+    m_editor->setFocus();
+    m_editor->grabKeyboard();
+}
+
+bool QDesignerMenuBar::eventFilter(QObject *object, QEvent *event)
+{
+    if (object != this && object != m_editor)
+        return false;
+
+    if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) {
+        leaveEditMode(Default);
+        m_editor->hide();
+        update();
+        return true;
+    }
+
+    bool dispatch = true;
+
+    switch (event->type()) {
+        default: break;
+
+        case QEvent::KeyPress:
+        case QEvent::KeyRelease:
+        case QEvent::ContextMenu:
+        case QEvent::MouseMove:
+        case QEvent::MouseButtonPress:
+        case QEvent::MouseButtonRelease:
+        case QEvent::MouseButtonDblClick:
+            dispatch = (object != m_editor);
+            // no break
+
+        case QEvent::Enter:
+        case QEvent::Leave:
+        case QEvent::FocusIn:
+        case QEvent::FocusOut:
+        {
+            QWidget *widget = qobject_cast<QWidget*>(object);
+
+            if (dispatch && widget && (widget == this || isAncestorOf(widget)))
+                return handleEvent(widget, event);
+        } break;
+
+        case QEvent::Shortcut:
+            event->accept();
+            return true;
+    }
+
+    return false;
+};
+
+int QDesignerMenuBar::findAction(const QPoint &pos) const
+{
+    const int index = actionIndexAt(this, pos, Qt::Horizontal);
+    if (index == -1)
+        return realActionCount();
+
+    return index;
+}
+
+void QDesignerMenuBar::adjustIndicator(const QPoint &pos)
+{
+    const int index = findAction(pos);
+    QAction *action = safeActionAt(index);
+    Q_ASSERT(action != 0);
+
+    if (pos != QPoint(-1, -1)) {
+        QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
+        if (!m || m->parentMenu()) {
+            m_currentIndex = index;
+            showMenu(index);
+        }
+    }
+
+    if (QDesignerActionProviderExtension *a = actionProvider()) {
+        a->adjustIndicator(pos);
+    }
+}
+
+QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action) const
+{
+    // action belongs to another form
+    if (!action || !Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
+        return NoActionDrag;
+
+    if (!action->menu())
+        return ActionDragOnSubMenu; // simple action only on sub menus
+
+    QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
+    if (m && m->parentMenu())
+        return ActionDragOnSubMenu; // it looks like a submenu
+
+    if (actions().contains(action))
+        return ActionDragOnSubMenu; // we already have the action in the menubar
+
+    return AcceptActionDrag;
+}
+
+void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event)
+{
+    const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+    if (!d || d->actionList().empty()) {
+        event->ignore();
+        return;
+    }
+
+    QAction *action = d->actionList().first();
+    switch (checkAction(action)) {
+    case NoActionDrag:
+        event->ignore();
+        break;
+    case ActionDragOnSubMenu:
+        m_dragging = true;
+        d->accept(event);
+        break;
+    case AcceptActionDrag:
+        m_dragging = true;
+        d->accept(event);
+        adjustIndicator(event->pos());
+        break;
+    }
+}
+
+void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event)
+{
+    const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
+    if (!d || d->actionList().empty()) {
+        event->ignore();
+        return;
+    }
+    QAction *action = d->actionList().first();
+
+    switch (checkAction(action)) {
+    case NoActionDrag:
+        event->ignore();
+        break;
+    case ActionDragOnSubMenu:
+        event->ignore();
+        showMenu(findAction(event->pos()));
+        break;
+    case AcceptActionDrag:
+        d->accept(event);
+        adjustIndicator(event->pos());
+        break;
+    }
+}
+
+void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *)
+{
+    m_dragging = false;
+
+    adjustIndicator(QPoint(-1, -1));
+}
+
+void QDesignerMenuBar::dropEvent(QDropEvent *event)
+{
+    m_dragging = false;
+
+    if (const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData())) {
+
+        QAction *action = d->actionList().first();
+        if (checkAction(action) == AcceptActionDrag) {
+            event->acceptProposedAction();
+            int index = findAction(event->pos());
+            index = qMin(index, actions().count() - 1);
+
+            QDesignerFormWindowInterface *fw = formWindow();
+            InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
+            cmd->init(this, action, safeActionAt(index));
+            fw->commandHistory()->push(cmd);
+
+            m_currentIndex = index;
+            update();
+            adjustIndicator(QPoint(-1, -1));
+            return;
+        }
+    }
+    event->ignore();
+}
+
+void QDesignerMenuBar::actionEvent(QActionEvent *event)
+{
+    QMenuBar::actionEvent(event);
+}
+
+QDesignerFormWindowInterface *QDesignerMenuBar::formWindow() const
+{
+    return QDesignerFormWindowInterface::findFormWindow(const_cast<QDesignerMenuBar*>(this));
+}
+
+QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider()
+{
+    if (QDesignerFormWindowInterface *fw = formWindow()) {
+        QDesignerFormEditorInterface *core = fw->core();
+        return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), this);
+    }
+
+    return 0;
+}
+
+QAction *QDesignerMenuBar::currentAction() const
+{
+    if (m_currentIndex < 0 || m_currentIndex >= actions().count())
+        return 0;
+
+    return safeActionAt(m_currentIndex);
+}
+
+int QDesignerMenuBar::realActionCount() const
+{
+    return actions().count() - 1; // 1 fake actions
+}
+
+bool QDesignerMenuBar::dragging() const
+{
+    return m_dragging;
+}
+
+void QDesignerMenuBar::moveLeft(bool ctrl)
+{
+    if (layoutDirection() == Qt::LeftToRight) {
+        movePrevious(ctrl);
+    } else {
+        moveNext(ctrl);
+    }
+}
+
+void QDesignerMenuBar::moveRight(bool ctrl)
+{
+    if (layoutDirection() == Qt::LeftToRight) {
+        moveNext(ctrl);
+    } else {
+        movePrevious(ctrl);
+    }
+}
+
+void QDesignerMenuBar::movePrevious(bool ctrl)
+{
+    const bool swapped = ctrl && swapActions(m_currentIndex, m_currentIndex - 1);
+    const int newIndex = qMax(0, m_currentIndex - 1);
+    // Always re-select, swapping destroys order
+    if (swapped || newIndex != m_currentIndex) {
+        m_currentIndex = newIndex;
+        updateCurrentAction(true);
+    }
+}
+
+void QDesignerMenuBar::moveNext(bool ctrl)
+{
+    const bool swapped = ctrl && swapActions(m_currentIndex + 1, m_currentIndex);
+    const int newIndex = qMin(actions().count() - 1, m_currentIndex + 1);
+    if (swapped || newIndex != m_currentIndex) {
+        m_currentIndex = newIndex;
+        updateCurrentAction(!ctrl);
+    }
+}
+
+void QDesignerMenuBar::moveUp()
+{
+    update();
+}
+
+void QDesignerMenuBar::moveDown()
+{
+    showMenu();
+}
+
+void QDesignerMenuBar::adjustSpecialActions()
+{
+    removeAction(m_addMenu);
+    addAction(m_addMenu);
+}
+
+bool QDesignerMenuBar::interactive(bool i)
+{
+    const bool old = m_interactive;
+    m_interactive = i;
+    return old;
+}
+
+void QDesignerMenuBar::hideMenu(int index)
+{
+    if (index < 0 && m_currentIndex >= 0)
+        index = m_currentIndex;
+
+    if (index < 0 || index >= realActionCount())
+        return;
+
+    QAction *action = safeActionAt(index);
+
+    if (action && action->menu()) {
+        action->menu()->hide();
+
+        if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu())) {
+            menu->closeMenuChain();
+        }
+    }
+}
+
+void QDesignerMenuBar::deleteMenu()
+{
+    deleteMenuAction(currentAction());
+}
+
+void QDesignerMenuBar::deleteMenuAction(QAction *action)
+{
+    if (action && !qobject_cast<SpecialMenuAction*>(action)) {
+        const int pos = actions().indexOf(action);
+        QAction *action_before = 0;
+        if (pos != -1)
+            action_before = safeActionAt(pos + 1);
+
+        QDesignerFormWindowInterface *fw = formWindow();
+        RemoveMenuActionCommand *cmd = new RemoveMenuActionCommand(fw);
+        cmd->init(action, action_before, this, this);
+        fw->commandHistory()->push(cmd);
+    }
+}
+
+void QDesignerMenuBar::showMenu(int index)
+{
+    if (index < 0 && m_currentIndex >= 0)
+        index = m_currentIndex;
+
+    if (index < 0 || index >= realActionCount())
+        return;
+
+    m_currentIndex = index;
+    QAction *action = currentAction();
+
+    if (action && action->menu()) {
+        if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) {
+            hideMenu(m_lastMenuActionIndex);
+        }
+
+        m_lastMenuActionIndex = index;
+        QMenu *menu = action->menu();
+        const QRect g = actionGeometry(action);
+
+        if (!menu->isVisible()) {
+            if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
+                menu->setWindowFlags(Qt::Popup);
+            menu->adjustSize();
+            menu->move(mapToGlobal(g.bottomLeft()));
+            menu->setFocus(Qt::MouseFocusReason);
+            menu->raise();
+            menu->show();
+        } else {
+            menu->raise();
+        }
+    }
+}
+
+QAction *QDesignerMenuBar::safeActionAt(int index) const
+{
+    if (index < 0 || index >= actions().count())
+        return 0;
+
+    return actions().at(index);
+}
+
+bool QDesignerMenuBar::swapActions(int a, int b)
+{
+    const int left = qMin(a, b);
+    int right = qMax(a, b);
+
+    QAction *action_a = safeActionAt(left);
+    QAction *action_b = safeActionAt(right);
+
+    if (action_a == action_b
+            || !action_a
+            || !action_b
+            || qobject_cast<SpecialMenuAction*>(action_a)
+            || qobject_cast<SpecialMenuAction*>(action_b))
+        return false; // nothing to do
+
+    right = qMin(right, realActionCount());
+    if (right < 0)
+        return false; // nothing to do
+
+    formWindow()->beginCommand(QApplication::translate("Command", "Move action"));
+
+    QAction *action_b_before = safeActionAt(right + 1);
+
+    QDesignerFormWindowInterface *fw = formWindow();
+    RemoveActionFromCommand *cmd1 = new RemoveActionFromCommand(fw);
+    cmd1->init(this, action_b, action_b_before, false);
+    fw->commandHistory()->push(cmd1);
+
+    QAction *action_a_before = safeActionAt(left + 1);
+
+    InsertActionIntoCommand *cmd2 = new InsertActionIntoCommand(fw);
+    cmd2->init(this, action_b, action_a_before, false);
+    fw->commandHistory()->push(cmd2);
+
+    RemoveActionFromCommand *cmd3 = new RemoveActionFromCommand(fw);
+    cmd3->init(this, action_a, action_b, false);
+    fw->commandHistory()->push(cmd3);
+
+    InsertActionIntoCommand *cmd4 = new InsertActionIntoCommand(fw);
+    cmd4->init(this, action_a, action_b_before, true);
+    fw->commandHistory()->push(cmd4);
+
+    fw->endCommand();
+
+    return true;
+}
+
+void QDesignerMenuBar::keyPressEvent(QKeyEvent *event)
+{
+    event->ignore();
+}
+
+void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event)
+{
+    event->ignore();
+}
+
+void QDesignerMenuBar::updateCurrentAction(bool selectAction)
+{
+    update();
+
+    if (!selectAction)
+        return;
+
+    QAction *action = currentAction();
+    if (!action || action == m_addMenu)
+        return;
+
+    QMenu *menu = action->menu();
+    if (!menu)
+        return;
+
+    QDesignerObjectInspector *oi = 0;
+    if (QDesignerFormWindowInterface *fw = formWindow())
+        oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
+
+    if (!oi)
+        return;
+
+    oi->clearSelection();
+    oi->selectObject(menu);
+}
+
+QT_END_NAMESPACE