| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $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(); |
| if (layoutDirection() == Qt::LeftToRight) { |
| menu->move(mapToGlobal(g.bottomLeft())); |
| } else { |
| // The position is not initially correct due to the unknown width, |
| // causing it to overlap a bit the first time it is invoked. |
| const QSize menuSize = menu->size(); |
| QPoint point = g.bottomRight() - QPoint(menu->width(), 0); |
| menu->move(mapToGlobal(point)); |
| } |
| 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 |