1391 lines
39 KiB
C++
1391 lines
39 KiB
C++
|
/****************************************************************************
|
||
|
**
|
||
|
** 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 Qt Designer of the Qt Toolkit.
|
||
|
**
|
||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||
|
** Commercial Usage
|
||
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
||
|
** accordance with the Qt Commercial License Agreement provided with the
|
||
|
** Software or, alternatively, in accordance with the terms contained in
|
||
|
** a written agreement between you and Nokia.
|
||
|
**
|
||
|
** 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.
|
||
|
**
|
||
|
** 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.
|
||
|
**
|
||
|
** If you have questions regarding the use of this file, please contact
|
||
|
** Nokia at qt-info@nokia.com.
|
||
|
** $QT_END_LICENSE$
|
||
|
**
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "qdesigner_menu_p.h"
|
||
|
#include "qdesigner_menubar_p.h"
|
||
|
#include "qdesigner_toolbar_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 "qdesigner_objectinspector_p.h"
|
||
|
|
||
|
#include <QtCore/QTimer>
|
||
|
#include <QtCore/qdebug.h>
|
||
|
|
||
|
#include <QtDesigner/QDesignerFormEditorInterface>
|
||
|
#include <QtDesigner/QDesignerWidgetFactoryInterface>
|
||
|
#include <QtDesigner/QDesignerMetaDataBaseInterface>
|
||
|
#include <QtDesigner/QExtensionManager>
|
||
|
|
||
|
#include <QtGui/QAction>
|
||
|
#include <QtGui/QApplication>
|
||
|
#include <QtGui/QLineEdit>
|
||
|
#include <QtGui/QPainter>
|
||
|
#include <QtGui/QRubberBand>
|
||
|
#include <QtGui/QToolTip>
|
||
|
#include <QtGui/QToolBar>
|
||
|
#include <QtGui/qevent.h>
|
||
|
|
||
|
Q_DECLARE_METATYPE(QAction*)
|
||
|
|
||
|
QT_BEGIN_NAMESPACE
|
||
|
|
||
|
using namespace qdesigner_internal;
|
||
|
|
||
|
// give the user a little more space to click on the sub menu rectangle
|
||
|
static inline void extendClickableArea(QRect *subMenuRect, Qt::LayoutDirection dir)
|
||
|
{
|
||
|
switch (dir) {
|
||
|
case Qt::LayoutDirectionAuto: // Should never happen
|
||
|
case Qt::LeftToRight:
|
||
|
subMenuRect->setLeft(subMenuRect->left() - 20);
|
||
|
break;
|
||
|
case Qt::RightToLeft:
|
||
|
subMenuRect->setRight(subMenuRect->right() + 20);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QDesignerMenu::QDesignerMenu(QWidget *parent) :
|
||
|
QMenu(parent),
|
||
|
m_subMenuPixmap(QPixmap(QLatin1String(":/trolltech/formeditor/images/submenu.png"))),
|
||
|
m_currentIndex(0),
|
||
|
m_addItem(new SpecialMenuAction(this)),
|
||
|
m_addSeparator(new SpecialMenuAction(this)),
|
||
|
m_showSubMenuTimer(new QTimer(this)),
|
||
|
m_deactivateWindowTimer(new QTimer(this)),
|
||
|
m_adjustSizeTimer(new QTimer(this)),
|
||
|
m_editor(new QLineEdit(this)),
|
||
|
m_dragging(false),
|
||
|
m_lastSubMenuIndex(-1)
|
||
|
{
|
||
|
setContextMenuPolicy(Qt::DefaultContextMenu);
|
||
|
setAcceptDrops(true); // ### fake
|
||
|
setSeparatorsCollapsible(false);
|
||
|
|
||
|
connect(m_adjustSizeTimer, SIGNAL(timeout()), this, SLOT(slotAdjustSizeNow()));
|
||
|
m_addItem->setText(tr("Type Here"));
|
||
|
addAction(m_addItem);
|
||
|
|
||
|
m_addSeparator->setText(tr("Add Separator"));
|
||
|
addAction(m_addSeparator);
|
||
|
|
||
|
connect(m_showSubMenuTimer, SIGNAL(timeout()), this, SLOT(slotShowSubMenuNow()));
|
||
|
|
||
|
connect(m_deactivateWindowTimer, SIGNAL(timeout()), this, SLOT(slotDeactivateNow()));
|
||
|
|
||
|
m_editor->setObjectName(QLatin1String("__qt__passive_editor"));
|
||
|
m_editor->hide();
|
||
|
|
||
|
m_editor->installEventFilter(this);
|
||
|
installEventFilter(this);
|
||
|
}
|
||
|
|
||
|
QDesignerMenu::~QDesignerMenu()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::slotAdjustSizeNow()
|
||
|
{
|
||
|
// Not using a single-shot, since we want to compress the timers if many items are being
|
||
|
// adjusted
|
||
|
m_adjustSizeTimer->stop();
|
||
|
adjustSize();
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleEvent(QWidget *widget, QEvent *event)
|
||
|
{
|
||
|
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
|
||
|
update();
|
||
|
|
||
|
if (widget == m_editor)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
switch (event->type()) {
|
||
|
default: break;
|
||
|
|
||
|
case QEvent::MouseButtonPress:
|
||
|
return handleMousePressEvent(widget, static_cast<QMouseEvent*>(event));
|
||
|
case QEvent::MouseButtonRelease:
|
||
|
return handleMouseReleaseEvent(widget, static_cast<QMouseEvent*>(event));
|
||
|
case QEvent::MouseButtonDblClick:
|
||
|
return handleMouseDoubleClickEvent(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));
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers)
|
||
|
{
|
||
|
const int index = findAction(pos);
|
||
|
if (index >= realActionCount())
|
||
|
return;
|
||
|
|
||
|
QAction *action = safeActionAt(index);
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction;
|
||
|
if (dropAction == Qt::MoveAction) {
|
||
|
RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
|
||
|
cmd->init(this, action, actions().at(index + 1));
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
|
||
|
QDrag *drag = new QDrag(this);
|
||
|
drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
|
||
|
drag->setMimeData(new ActionRepositoryMimeData(action, dropAction));
|
||
|
|
||
|
const int old_index = m_currentIndex;
|
||
|
m_currentIndex = -1;
|
||
|
|
||
|
if (drag->start(dropAction) == Qt::IgnoreAction) {
|
||
|
if (dropAction == Qt::MoveAction) {
|
||
|
QAction *previous = safeActionAt(index);
|
||
|
InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
|
||
|
cmd->init(this, action, previous);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
|
||
|
m_currentIndex = old_index;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleKeyPressEvent(QWidget * /*widget*/, QKeyEvent *e)
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
|
||
|
if (m_editor->isHidden() && hasFocus()) { // In navigation mode
|
||
|
switch (e->key()) {
|
||
|
|
||
|
case Qt::Key_Delete:
|
||
|
if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
|
||
|
break;
|
||
|
hideSubMenu();
|
||
|
deleteAction();
|
||
|
break;
|
||
|
|
||
|
case Qt::Key_Left:
|
||
|
e->accept();
|
||
|
moveLeft();
|
||
|
return true;
|
||
|
|
||
|
case Qt::Key_Right:
|
||
|
e->accept();
|
||
|
moveRight();
|
||
|
return true; // no update
|
||
|
|
||
|
case Qt::Key_Up:
|
||
|
e->accept();
|
||
|
moveUp(e->modifiers() & Qt::ControlModifier);
|
||
|
return true;
|
||
|
|
||
|
case Qt::Key_Down:
|
||
|
e->accept();
|
||
|
moveDown(e->modifiers() & Qt::ControlModifier);
|
||
|
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:
|
||
|
case Qt::Key_F2:
|
||
|
e->accept();
|
||
|
enterEditMode();
|
||
|
return true; // no update
|
||
|
|
||
|
case Qt::Key_Escape:
|
||
|
e->ignore();
|
||
|
setFocus();
|
||
|
hide();
|
||
|
closeMenuChain();
|
||
|
return true;
|
||
|
|
||
|
case Qt::Key_Alt:
|
||
|
case Qt::Key_Shift:
|
||
|
case Qt::Key_Control:
|
||
|
e->ignore();
|
||
|
setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed
|
||
|
return true; // no update
|
||
|
|
||
|
default: {
|
||
|
QAction *action = currentAction();
|
||
|
if (!action || action->isSeparator() || action == m_addSeparator) {
|
||
|
e->ignore();
|
||
|
return true;
|
||
|
} else if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
|
||
|
showLineEdit();
|
||
|
QApplication::sendEvent(m_editor, e);
|
||
|
e->accept();
|
||
|
} else {
|
||
|
e->ignore();
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
} else if (m_editor->hasFocus()) { // In edit mode
|
||
|
switch (e->key()) {
|
||
|
default:
|
||
|
e->ignore();
|
||
|
return false;
|
||
|
|
||
|
case Qt::Key_Enter:
|
||
|
case Qt::Key_Return:
|
||
|
if (!m_editor->text().isEmpty()) {
|
||
|
leaveEditMode(ForceAccept);
|
||
|
m_editor->hide();
|
||
|
setFocus();
|
||
|
moveDown(false);
|
||
|
break;
|
||
|
}
|
||
|
// fall through
|
||
|
|
||
|
case Qt::Key_Escape:
|
||
|
m_editor->hide();
|
||
|
setFocus();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
e->accept();
|
||
|
update();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static void sendMouseEventTo(QWidget *target, const QPoint &targetPoint, const QMouseEvent *event)
|
||
|
{
|
||
|
QMouseEvent e(event->type(), targetPoint, event->globalPos(), event->button(), event->buttons(), event->modifiers());
|
||
|
QApplication::sendEvent(target, &e);
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
|
||
|
{
|
||
|
event->accept();
|
||
|
m_startPosition = QPoint();
|
||
|
|
||
|
if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
|
||
|
return true;
|
||
|
|
||
|
if (!rect().contains(event->pos())) {
|
||
|
// special case for menubar
|
||
|
QWidget *target = QApplication::widgetAt(event->globalPos());
|
||
|
QMenuBar *mb = qobject_cast<QMenuBar*>(target);
|
||
|
QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(target);
|
||
|
if (mb != 0 || menu != 0) {
|
||
|
const QPoint pt = target->mapFromGlobal(event->globalPos());
|
||
|
QAction *action = mb == 0 ? menu->actionAt(pt) : mb->actionAt(pt);
|
||
|
if (action)
|
||
|
sendMouseEventTo(target, pt, event);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
m_currentIndex = findAction(event->pos());
|
||
|
QAction *action = safeActionAt(m_currentIndex);
|
||
|
|
||
|
QRect pm_rect;
|
||
|
if (action->menu() || hasSubMenuPixmap(action)) {
|
||
|
pm_rect = subMenuPixmapRect(action);
|
||
|
extendClickableArea(&pm_rect, layoutDirection());
|
||
|
}
|
||
|
|
||
|
if (!pm_rect.contains(event->pos()) && m_currentIndex != -1)
|
||
|
enterEditMode();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *event)
|
||
|
{
|
||
|
if (!rect().contains(event->pos())) {
|
||
|
QWidget *clickedWidget = QApplication::widgetAt(event->globalPos());
|
||
|
if (QMenuBar *mb = qobject_cast<QMenuBar*>(clickedWidget)) {
|
||
|
const QPoint pt = mb->mapFromGlobal(event->globalPos());
|
||
|
if (QAction *action = mb->actionAt(pt)) {
|
||
|
QMenu * menu = action->menu();
|
||
|
if (menu == findRootMenu()) {
|
||
|
// propagate the mouse press event (but don't close the popup)
|
||
|
sendMouseEventTo(mb, pt, event);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (QDesignerMenu *m = qobject_cast<QDesignerMenu *>(clickedWidget)) {
|
||
|
m->hideSubMenu();
|
||
|
sendMouseEventTo(m, m->mapFromGlobal(event->globalPos()), event);
|
||
|
} else {
|
||
|
QDesignerMenu *root = findRootMenu();
|
||
|
root->hide();
|
||
|
root->hideSubMenu();
|
||
|
}
|
||
|
if (clickedWidget) {
|
||
|
if (QWidget *focusProxy = clickedWidget->focusProxy())
|
||
|
clickedWidget = focusProxy;
|
||
|
if (clickedWidget->focusPolicy() != Qt::NoFocus)
|
||
|
clickedWidget->setFocus(Qt::OtherFocusReason);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
m_showSubMenuTimer->stop();
|
||
|
m_startPosition = QPoint();
|
||
|
event->accept();
|
||
|
|
||
|
if (event->button() != Qt::LeftButton)
|
||
|
return true;
|
||
|
|
||
|
m_startPosition = mapFromGlobal(event->globalPos());
|
||
|
|
||
|
const int index = findAction(m_startPosition);
|
||
|
|
||
|
QAction *action = safeActionAt(index);
|
||
|
QRect pm_rect = subMenuPixmapRect(action);
|
||
|
extendClickableArea(&pm_rect, layoutDirection());
|
||
|
|
||
|
const int old_index = m_currentIndex;
|
||
|
m_currentIndex = index;
|
||
|
if ((hasSubMenuPixmap(action) || action->menu() != 0)
|
||
|
&& pm_rect.contains(m_startPosition)) {
|
||
|
if (m_currentIndex == m_lastSubMenuIndex) {
|
||
|
hideSubMenu();
|
||
|
} else
|
||
|
slotShowSubMenuNow();
|
||
|
} else {
|
||
|
if (index == old_index) {
|
||
|
if (m_currentIndex == m_lastSubMenuIndex)
|
||
|
hideSubMenu();
|
||
|
} else {
|
||
|
hideSubMenu();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
update();
|
||
|
if (index != old_index)
|
||
|
selectCurrentAction();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
|
||
|
{
|
||
|
event->accept();
|
||
|
m_startPosition = QPoint();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
|
||
|
{
|
||
|
if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
|
||
|
return true;
|
||
|
|
||
|
if (!rect().contains(event->pos())) {
|
||
|
|
||
|
if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::widgetAt(event->globalPos()))) {
|
||
|
const QPoint pt = mb->mapFromGlobal(event->globalPos());
|
||
|
QAction *action = mb->actionAt(pt);
|
||
|
if (action && action->menu() == findRootMenu()) {
|
||
|
// propagate the mouse press event (but don't close the popup)
|
||
|
sendMouseEventTo(mb, pt, event);
|
||
|
return true;
|
||
|
}
|
||
|
// hide the popup Qt will replay the event
|
||
|
slotDeactivateNow();
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (m_startPosition.isNull())
|
||
|
return true;
|
||
|
|
||
|
event->accept();
|
||
|
|
||
|
const QPoint pos = mapFromGlobal(event->globalPos());
|
||
|
|
||
|
if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
|
||
|
return true;
|
||
|
|
||
|
startDrag(m_startPosition, event->modifiers());
|
||
|
m_startPosition = QPoint();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
|
||
|
{
|
||
|
event->accept();
|
||
|
|
||
|
const int index = findAction(mapFromGlobal(event->globalPos()));
|
||
|
QAction *action = safeActionAt(index);
|
||
|
if (qobject_cast<SpecialMenuAction*>(action))
|
||
|
return true;
|
||
|
|
||
|
QMenu menu;
|
||
|
QVariant itemData;
|
||
|
qVariantSetValue(itemData, action);
|
||
|
|
||
|
QAction *addSeparatorAction = menu.addAction(tr("Insert separator"));
|
||
|
addSeparatorAction->setData(itemData);
|
||
|
|
||
|
QAction *removeAction = 0;
|
||
|
if (action->isSeparator())
|
||
|
removeAction = menu.addAction(tr("Remove separator"));
|
||
|
else
|
||
|
removeAction = menu.addAction(tr("Remove action '%1'").arg(action->objectName()));
|
||
|
removeAction->setData(itemData);
|
||
|
|
||
|
connect(addSeparatorAction, SIGNAL(triggered(bool)), this, SLOT(slotAddSeparator()));
|
||
|
connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(slotRemoveSelectedAction()));
|
||
|
menu.exec(event->globalPos());
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::slotAddSeparator()
|
||
|
{
|
||
|
QAction *action = qobject_cast<QAction *>(sender());
|
||
|
if (!action)
|
||
|
return;
|
||
|
|
||
|
QAction *a = qvariant_cast<QAction*>(action->data());
|
||
|
Q_ASSERT(a != 0);
|
||
|
|
||
|
const int pos = actions().indexOf(a);
|
||
|
QAction *action_before = 0;
|
||
|
if (pos != -1)
|
||
|
action_before = safeActionAt(pos);
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
fw->beginCommand(tr("Add separator"));
|
||
|
QAction *sep = createAction(QString(), true);
|
||
|
|
||
|
InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
|
||
|
cmd->init(this, sep, action_before);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
|
||
|
if (parentMenu()) {
|
||
|
QAction *parent_action = parentMenu()->currentAction();
|
||
|
if (parent_action->menu() == 0) {
|
||
|
CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
|
||
|
cmd->init(parentMenu(), parentMenu()->currentAction());
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fw->endCommand();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::slotRemoveSelectedAction()
|
||
|
{
|
||
|
if (QAction *action = qobject_cast<QAction *>(sender()))
|
||
|
if (QAction *a = qvariant_cast<QAction*>(action->data()))
|
||
|
deleteAction(a);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::deleteAction(QAction *a)
|
||
|
{
|
||
|
const int pos = actions().indexOf(a);
|
||
|
QAction *action_before = 0;
|
||
|
if (pos != -1)
|
||
|
action_before = safeActionAt(pos + 1);
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
|
||
|
cmd->init(this, a, action_before);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
|
||
|
QRect QDesignerMenu::subMenuPixmapRect(QAction *action) const
|
||
|
{
|
||
|
const QRect g = actionGeometry(action);
|
||
|
const int x = layoutDirection() == Qt::LeftToRight ? (g.right() - m_subMenuPixmap.width() - 2) : 2;
|
||
|
const int y = g.top() + (g.height() - m_subMenuPixmap.height())/2 + 1;
|
||
|
return QRect(x, y, m_subMenuPixmap.width(), m_subMenuPixmap.height());
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::hasSubMenuPixmap(QAction *action) const
|
||
|
{
|
||
|
return action != 0
|
||
|
&& qobject_cast<SpecialMenuAction*>(action) == 0
|
||
|
&& !action->isSeparator()
|
||
|
&& !action->menu()
|
||
|
&& canCreateSubMenu(action);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::showEvent ( QShowEvent * event )
|
||
|
{
|
||
|
selectCurrentAction();
|
||
|
QMenu::showEvent (event);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::paintEvent(QPaintEvent *event)
|
||
|
{
|
||
|
QMenu::paintEvent(event);
|
||
|
|
||
|
QPainter p(this);
|
||
|
|
||
|
QAction *current = currentAction();
|
||
|
|
||
|
foreach (QAction *a, actions()) {
|
||
|
const QRect g = actionGeometry(a);
|
||
|
|
||
|
if (qobject_cast<SpecialMenuAction*>(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);
|
||
|
} else if (hasSubMenuPixmap(a)) {
|
||
|
p.drawPixmap(subMenuPixmapRect(a).topLeft(), m_subMenuPixmap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!hasFocus() || !current || m_dragging)
|
||
|
return;
|
||
|
|
||
|
if (QDesignerMenu *menu = parentMenu()) {
|
||
|
if (menu->dragging())
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (QDesignerMenuBar *menubar = qobject_cast<QDesignerMenuBar*>(parentWidget())) {
|
||
|
if (menubar->dragging())
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const QRect g = actionGeometry(current);
|
||
|
drawSelection(&p, g.adjusted(1, 1, -3, -3));
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::dragging() const
|
||
|
{
|
||
|
return m_dragging;
|
||
|
}
|
||
|
|
||
|
QDesignerMenu *QDesignerMenu::findRootMenu() const
|
||
|
{
|
||
|
if (parentMenu())
|
||
|
return parentMenu()->findRootMenu();
|
||
|
|
||
|
return const_cast<QDesignerMenu*>(this);
|
||
|
}
|
||
|
|
||
|
QDesignerMenu *QDesignerMenu::findActivatedMenu() const
|
||
|
{
|
||
|
QList<QDesignerMenu*> candidates;
|
||
|
candidates.append(const_cast<QDesignerMenu*>(this));
|
||
|
candidates += qFindChildren<QDesignerMenu*>(this);
|
||
|
|
||
|
foreach (QDesignerMenu *m, candidates) {
|
||
|
if (m == qApp->activeWindow())
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::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 false;
|
||
|
}
|
||
|
|
||
|
bool dispatch = true;
|
||
|
|
||
|
switch (event->type()) {
|
||
|
default: break;
|
||
|
|
||
|
case QEvent::WindowDeactivate:
|
||
|
deactivateMenu();
|
||
|
break;
|
||
|
case QEvent::ContextMenu:
|
||
|
case QEvent::MouseButtonPress:
|
||
|
case QEvent::MouseButtonRelease:
|
||
|
case QEvent::MouseButtonDblClick:
|
||
|
|
||
|
while (QApplication::activePopupWidget() && !qobject_cast<QDesignerMenu*>(QApplication::activePopupWidget())) {
|
||
|
QApplication::activePopupWidget()->close();
|
||
|
}
|
||
|
|
||
|
// fall through
|
||
|
case QEvent::KeyPress:
|
||
|
case QEvent::KeyRelease:
|
||
|
case QEvent::MouseMove:
|
||
|
dispatch = (object != m_editor);
|
||
|
// no break
|
||
|
|
||
|
case QEvent::Enter:
|
||
|
case QEvent::Leave:
|
||
|
case QEvent::FocusIn:
|
||
|
case QEvent::FocusOut:
|
||
|
if (dispatch)
|
||
|
if (QWidget *widget = qobject_cast<QWidget*>(object))
|
||
|
if (widget == this || isAncestorOf(widget))
|
||
|
return handleEvent(widget, event);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
int QDesignerMenu::findAction(const QPoint &pos) const
|
||
|
{
|
||
|
const int index = actionIndexAt(this, pos, Qt::Vertical);
|
||
|
if (index == -1)
|
||
|
return realActionCount();
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::adjustIndicator(const QPoint &pos)
|
||
|
{
|
||
|
if (QDesignerActionProviderExtension *a = actionProvider()) {
|
||
|
a->adjustIndicator(pos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QDesignerMenu::ActionDragCheck QDesignerMenu::checkAction(QAction *action) const
|
||
|
{
|
||
|
if (!action || (action->menu() && action->menu()->parentWidget() != const_cast<QDesignerMenu*>(this)))
|
||
|
return NoActionDrag; // menu action!! nothing to do
|
||
|
|
||
|
if (!Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
|
||
|
return NoActionDrag; // the action belongs to another form window
|
||
|
|
||
|
if (actions().contains(action))
|
||
|
return ActionDragOnSubMenu; // we already have the action in the menu
|
||
|
|
||
|
return AcceptActionDrag;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::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:
|
||
|
d->accept(event);
|
||
|
m_dragging = true;
|
||
|
break;
|
||
|
case AcceptActionDrag:
|
||
|
d->accept(event);
|
||
|
m_dragging = true;
|
||
|
adjustIndicator(event->pos());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event)
|
||
|
{
|
||
|
if (actionGeometry(m_addSeparator).contains(event->pos())) {
|
||
|
event->ignore();
|
||
|
adjustIndicator(QPoint(-1, -1));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
|
||
|
if (!d || d->actionList().empty()) {
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QAction *action = d->actionList().first();
|
||
|
const ActionDragCheck dc = checkAction(action);
|
||
|
switch (dc) {
|
||
|
case NoActionDrag:
|
||
|
event->ignore();
|
||
|
break;
|
||
|
case ActionDragOnSubMenu:
|
||
|
case AcceptActionDrag: { // Do not pop up submenu of action being dragged
|
||
|
const int newIndex = findAction(event->pos());
|
||
|
if (safeActionAt(newIndex) != action) {
|
||
|
m_currentIndex = newIndex;
|
||
|
if (m_lastSubMenuIndex != m_currentIndex)
|
||
|
m_showSubMenuTimer->start(300);
|
||
|
}
|
||
|
if (dc == AcceptActionDrag) {
|
||
|
adjustIndicator(event->pos());
|
||
|
d->accept(event);
|
||
|
} else {
|
||
|
event->ignore();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::dragLeaveEvent(QDragLeaveEvent *)
|
||
|
{
|
||
|
m_dragging = false;
|
||
|
adjustIndicator(QPoint(-1, -1));
|
||
|
m_showSubMenuTimer->stop();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::dropEvent(QDropEvent *event)
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
hideSubMenu();
|
||
|
m_dragging = false;
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
const ActionRepositoryMimeData *d = qobject_cast<const ActionRepositoryMimeData*>(event->mimeData());
|
||
|
if (!d || d->actionList().empty()) {
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
QAction *action = d->actionList().first();
|
||
|
if (action && checkAction(action) == AcceptActionDrag) {
|
||
|
event->acceptProposedAction();
|
||
|
int index = findAction(event->pos());
|
||
|
index = qMin(index, actions().count() - 1);
|
||
|
|
||
|
fw->beginCommand(tr("Insert action"));
|
||
|
InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
|
||
|
cmd->init(this, action, safeActionAt(index));
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
|
||
|
m_currentIndex = index;
|
||
|
|
||
|
if (parentMenu()) {
|
||
|
QAction *parent_action = parentMenu()->currentAction();
|
||
|
if (parent_action->menu() == 0) {
|
||
|
CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
|
||
|
cmd->init(parentMenu(), parentMenu()->currentAction(), action);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
}
|
||
|
update();
|
||
|
fw->endCommand();
|
||
|
} else {
|
||
|
event->ignore();
|
||
|
}
|
||
|
adjustIndicator(QPoint(-1, -1));
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::actionEvent(QActionEvent *event)
|
||
|
{
|
||
|
QMenu::actionEvent(event);
|
||
|
m_adjustSizeTimer->start(0);
|
||
|
}
|
||
|
|
||
|
QDesignerFormWindowInterface *QDesignerMenu::formWindow() const
|
||
|
{
|
||
|
if (parentMenu())
|
||
|
return parentMenu()->formWindow();
|
||
|
|
||
|
return QDesignerFormWindowInterface::findFormWindow(parentWidget());
|
||
|
}
|
||
|
|
||
|
QDesignerActionProviderExtension *QDesignerMenu::actionProvider()
|
||
|
{
|
||
|
if (QDesignerFormWindowInterface *fw = formWindow()) {
|
||
|
QDesignerFormEditorInterface *core = fw->core();
|
||
|
return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), this);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::closeMenuChain()
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
|
||
|
QWidget *w = this;
|
||
|
while (w && qobject_cast<QMenu*>(w))
|
||
|
w = w->parentWidget();
|
||
|
|
||
|
if (w) {
|
||
|
foreach (QMenu *subMenu, qFindChildren<QMenu*>(w)) {
|
||
|
subMenu->hide();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_lastSubMenuIndex = -1;
|
||
|
}
|
||
|
|
||
|
// Close submenu using the left/right keys according to layoutDirection().
|
||
|
// Return false to indicate the event must be propagated to the menu bar.
|
||
|
bool QDesignerMenu::hideSubMenuOnCursorKey()
|
||
|
{
|
||
|
if (parentMenu()) {
|
||
|
hide();
|
||
|
return true;
|
||
|
}
|
||
|
closeMenuChain();
|
||
|
update();
|
||
|
if (parentMenuBar())
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Open a submenu using the left/right keys according to layoutDirection().
|
||
|
// Return false to indicate the event must be propagated to the menu bar.
|
||
|
bool QDesignerMenu::showSubMenuOnCursorKey()
|
||
|
{
|
||
|
const QAction *action = currentAction();
|
||
|
|
||
|
if (qobject_cast<const SpecialMenuAction*>(action) || action->isSeparator()) {
|
||
|
closeMenuChain();
|
||
|
if (parentMenuBar())
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
m_lastSubMenuIndex = -1; // force a refresh
|
||
|
slotShowSubMenuNow();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::moveLeft()
|
||
|
{
|
||
|
const bool handled = layoutDirection() == Qt::LeftToRight ?
|
||
|
hideSubMenuOnCursorKey() : showSubMenuOnCursorKey();
|
||
|
if (!handled)
|
||
|
parentMenuBar()->moveLeft();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::moveRight()
|
||
|
{
|
||
|
const bool handled = layoutDirection() == Qt::LeftToRight ?
|
||
|
showSubMenuOnCursorKey() : hideSubMenuOnCursorKey();
|
||
|
if (!handled)
|
||
|
parentMenuBar()->moveRight();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::moveUp(bool ctrl)
|
||
|
{
|
||
|
if (m_currentIndex == 0) {
|
||
|
hide();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ctrl)
|
||
|
(void) swap(m_currentIndex, m_currentIndex - 1);
|
||
|
--m_currentIndex;
|
||
|
m_currentIndex = qMax(0, m_currentIndex);
|
||
|
// Always re-select, swapping destroys order
|
||
|
update();
|
||
|
selectCurrentAction();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::moveDown(bool ctrl)
|
||
|
{
|
||
|
if (m_currentIndex == actions().count() - 1) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (ctrl)
|
||
|
(void) swap(m_currentIndex + 1, m_currentIndex);
|
||
|
|
||
|
++m_currentIndex;
|
||
|
m_currentIndex = qMin(actions().count() - 1, m_currentIndex);
|
||
|
update();
|
||
|
if (!ctrl)
|
||
|
selectCurrentAction();
|
||
|
}
|
||
|
|
||
|
QAction *QDesignerMenu::currentAction() const
|
||
|
{
|
||
|
if (m_currentIndex < 0 || m_currentIndex >= actions().count())
|
||
|
return 0;
|
||
|
|
||
|
return safeActionAt(m_currentIndex);
|
||
|
}
|
||
|
|
||
|
int QDesignerMenu::realActionCount() const
|
||
|
{
|
||
|
return actions().count() - 2; // 2 fake actions
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::selectCurrentAction()
|
||
|
{
|
||
|
QAction *action = currentAction();
|
||
|
if (!action || action == m_addSeparator || action == m_addItem)
|
||
|
return;
|
||
|
|
||
|
QDesignerObjectInspector *oi = 0;
|
||
|
if (QDesignerFormWindowInterface *fw = formWindow())
|
||
|
oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
|
||
|
|
||
|
if (!oi)
|
||
|
return;
|
||
|
|
||
|
oi->clearSelection();
|
||
|
if (QMenu *menu = action->menu())
|
||
|
oi->selectObject(menu);
|
||
|
else
|
||
|
oi->selectObject(action);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::createRealMenuAction(QAction *action)
|
||
|
{
|
||
|
if (action->menu())
|
||
|
return; // nothing to do
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
QDesignerFormEditorInterface *core = formWindow()->core();
|
||
|
|
||
|
QDesignerMenu *menu = findOrCreateSubMenu(action);
|
||
|
m_subMenus.remove(action);
|
||
|
|
||
|
action->setMenu(menu);
|
||
|
menu->setTitle(action->text());
|
||
|
|
||
|
Q_ASSERT(fw);
|
||
|
|
||
|
core->widgetFactory()->initialize(menu);
|
||
|
|
||
|
const QString niceObjectName = ActionEditor::actionTextToName(menu->title(), QLatin1String("menu"));
|
||
|
menu->setObjectName(niceObjectName);
|
||
|
|
||
|
core->metaDataBase()->add(menu);
|
||
|
fw->ensureUniqueObjectName(menu);
|
||
|
|
||
|
QAction *menuAction = menu->menuAction();
|
||
|
core->metaDataBase()->add(menuAction);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::removeRealMenu(QAction *action)
|
||
|
{
|
||
|
QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu());
|
||
|
if (menu == 0)
|
||
|
return;
|
||
|
action->setMenu(0);
|
||
|
m_subMenus.insert(action, menu);
|
||
|
QDesignerFormEditorInterface *core = formWindow()->core();
|
||
|
core->metaDataBase()->remove(menu);
|
||
|
}
|
||
|
|
||
|
QDesignerMenu *QDesignerMenu::findOrCreateSubMenu(QAction *action)
|
||
|
{
|
||
|
if (action->menu())
|
||
|
return qobject_cast<QDesignerMenu*>(action->menu());
|
||
|
|
||
|
QDesignerMenu *menu = m_subMenus.value(action);
|
||
|
if (!menu) {
|
||
|
menu = new QDesignerMenu(this);
|
||
|
m_subMenus.insert(action, menu);
|
||
|
}
|
||
|
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::canCreateSubMenu(QAction *action) const // ### improve it's a bit too slow
|
||
|
{
|
||
|
foreach (const QWidget *aw, action->associatedWidgets())
|
||
|
if (aw != this) {
|
||
|
if (const QMenu *m = qobject_cast<const QMenu *>(aw)) {
|
||
|
if (m->actions().contains(action))
|
||
|
return false; // sorry
|
||
|
} else {
|
||
|
if (const QToolBar *tb = qobject_cast<const QToolBar *>(aw))
|
||
|
if (tb->actions().contains(action))
|
||
|
return false; // sorry
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::slotShowSubMenuNow()
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
|
||
|
if (m_lastSubMenuIndex == m_currentIndex)
|
||
|
return;
|
||
|
|
||
|
if (m_lastSubMenuIndex != -1)
|
||
|
hideSubMenu();
|
||
|
|
||
|
if (m_currentIndex >= realActionCount())
|
||
|
return;
|
||
|
|
||
|
QAction *action = currentAction();
|
||
|
|
||
|
if (action->isSeparator() || !canCreateSubMenu(action))
|
||
|
return;
|
||
|
|
||
|
if (QMenu *menu = findOrCreateSubMenu(action)) {
|
||
|
if (!menu->isVisible()) {
|
||
|
if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
|
||
|
menu->setWindowFlags(Qt::Popup);
|
||
|
const QRect g = actionGeometry(action);
|
||
|
if (layoutDirection() == Qt::LeftToRight) {
|
||
|
menu->move(mapToGlobal(g.topRight()));
|
||
|
} 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.topLeft() - QPoint(menu->width() + 10, 0);
|
||
|
menu->move(mapToGlobal(point));
|
||
|
}
|
||
|
menu->show();
|
||
|
menu->setFocus();
|
||
|
} else {
|
||
|
menu->raise();
|
||
|
}
|
||
|
menu->setFocus();
|
||
|
|
||
|
m_lastSubMenuIndex = m_currentIndex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::showSubMenu(QAction *action)
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
|
||
|
if (m_editor->isVisible() || !action || qobject_cast<SpecialMenuAction*>(action)
|
||
|
|| action->isSeparator() || !isVisible())
|
||
|
return;
|
||
|
|
||
|
m_showSubMenuTimer->start(300);
|
||
|
}
|
||
|
|
||
|
QDesignerMenu *QDesignerMenu::parentMenu() const
|
||
|
{
|
||
|
return qobject_cast<QDesignerMenu*>(parentWidget());
|
||
|
}
|
||
|
|
||
|
QDesignerMenuBar *QDesignerMenu::parentMenuBar() const
|
||
|
{
|
||
|
if (QDesignerMenuBar *mb = qobject_cast<QDesignerMenuBar*>(parentWidget())) {
|
||
|
return mb;
|
||
|
} else if (QDesignerMenu *m = parentMenu()) {
|
||
|
return m->parentMenuBar();
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::setVisible(bool visible)
|
||
|
{
|
||
|
if (visible)
|
||
|
m_currentIndex = 0;
|
||
|
else
|
||
|
m_lastSubMenuIndex = -1;
|
||
|
|
||
|
QMenu::setVisible(visible);
|
||
|
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::adjustSpecialActions()
|
||
|
{
|
||
|
removeAction(m_addItem);
|
||
|
removeAction(m_addSeparator);
|
||
|
addAction(m_addItem);
|
||
|
addAction(m_addSeparator);
|
||
|
}
|
||
|
|
||
|
bool QDesignerMenu::interactive(bool i)
|
||
|
{
|
||
|
const bool old = m_interactive;
|
||
|
m_interactive = i;
|
||
|
return old;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::enterEditMode()
|
||
|
{
|
||
|
if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
|
||
|
showLineEdit();
|
||
|
} else {
|
||
|
hideSubMenu();
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
fw->beginCommand(tr("Add separator"));
|
||
|
QAction *sep = createAction(QString(), true);
|
||
|
|
||
|
InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
|
||
|
cmd->init(this, sep, safeActionAt(realActionCount()));
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
|
||
|
if (parentMenu()) {
|
||
|
QAction *parent_action = parentMenu()->currentAction();
|
||
|
if (parent_action->menu() == 0) {
|
||
|
CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
|
||
|
cmd->init(parentMenu(), parentMenu()->currentAction());
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fw->endCommand();
|
||
|
|
||
|
m_currentIndex = actions().indexOf(m_addItem);
|
||
|
update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::leaveEditMode(LeaveEditMode mode)
|
||
|
{
|
||
|
if (mode == Default)
|
||
|
return;
|
||
|
|
||
|
QAction *action = 0;
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
if (m_currentIndex < realActionCount()) {
|
||
|
action = safeActionAt(m_currentIndex);
|
||
|
fw->beginCommand(QApplication::translate("Command", "Set action text"));
|
||
|
} else {
|
||
|
Q_ASSERT(fw != 0);
|
||
|
fw->beginCommand(QApplication::translate("Command", "Insert action"));
|
||
|
action = createAction(ActionEditor::actionTextToName(m_editor->text()));
|
||
|
InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw);
|
||
|
cmd->init(this, action, currentAction());
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
|
||
|
SetPropertyCommand *cmd = new SetPropertyCommand(fw);
|
||
|
cmd->init(action, QLatin1String("text"), m_editor->text());
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
|
||
|
if (parentMenu()) {
|
||
|
QAction *parent_action = parentMenu()->currentAction();
|
||
|
if (parent_action->menu() == 0) {
|
||
|
CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw);
|
||
|
cmd->init(parentMenu(), parentMenu()->currentAction(), action);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
update();
|
||
|
fw->endCommand();
|
||
|
}
|
||
|
|
||
|
QAction *QDesignerMenu::safeMenuAction(QDesignerMenu *menu) const
|
||
|
{
|
||
|
QAction *action = menu->menuAction();
|
||
|
|
||
|
if (!action)
|
||
|
action = m_subMenus.key(menu);
|
||
|
|
||
|
return action;
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::showLineEdit()
|
||
|
{
|
||
|
m_showSubMenuTimer->stop();
|
||
|
|
||
|
QAction *action = 0;
|
||
|
|
||
|
if (m_currentIndex < realActionCount())
|
||
|
action = safeActionAt(m_currentIndex);
|
||
|
else
|
||
|
action = m_addItem;
|
||
|
|
||
|
if (action->isSeparator())
|
||
|
return;
|
||
|
|
||
|
hideSubMenu();
|
||
|
|
||
|
// open edit field for item name
|
||
|
setFocus();
|
||
|
|
||
|
const QString text = action != m_addItem ? action->text() : QString();
|
||
|
m_editor->setText(text);
|
||
|
m_editor->selectAll();
|
||
|
m_editor->setGeometry(actionGeometry(action).adjusted(1, 1, -2, -2));
|
||
|
m_editor->show();
|
||
|
m_editor->setFocus();
|
||
|
}
|
||
|
|
||
|
QAction *QDesignerMenu::createAction(const QString &objectName, bool separator)
|
||
|
{
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
Q_ASSERT(fw);
|
||
|
return ToolBarEventFilter::createAction(fw, objectName, separator);
|
||
|
}
|
||
|
|
||
|
// ### share with QDesignerMenu::swap
|
||
|
bool QDesignerMenu::swap(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
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
fw->beginCommand(QApplication::translate("Command", "Move action"));
|
||
|
|
||
|
QAction *action_b_before = safeActionAt(right + 1);
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
QAction *QDesignerMenu::safeActionAt(int index) const
|
||
|
{
|
||
|
if (index < 0 || index >= actions().count())
|
||
|
return 0;
|
||
|
|
||
|
return actions().at(index);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::hideSubMenu()
|
||
|
{
|
||
|
m_lastSubMenuIndex = -1;
|
||
|
foreach (QMenu *subMenu, qFindChildren<QMenu*>(this)) {
|
||
|
subMenu->hide();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::deleteAction()
|
||
|
{
|
||
|
QAction *action = currentAction();
|
||
|
const int pos = actions().indexOf(action);
|
||
|
QAction *action_before = 0;
|
||
|
if (pos != -1)
|
||
|
action_before = safeActionAt(pos + 1);
|
||
|
|
||
|
QDesignerFormWindowInterface *fw = formWindow();
|
||
|
RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw);
|
||
|
cmd->init(this, action, action_before);
|
||
|
fw->commandHistory()->push(cmd);
|
||
|
|
||
|
update();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::deactivateMenu()
|
||
|
{
|
||
|
m_deactivateWindowTimer->start(10);
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::slotDeactivateNow()
|
||
|
{
|
||
|
m_deactivateWindowTimer->stop();
|
||
|
|
||
|
if (m_dragging)
|
||
|
return;
|
||
|
|
||
|
QDesignerMenu *root = findRootMenu();
|
||
|
|
||
|
if (! root->findActivatedMenu()) {
|
||
|
root->hide();
|
||
|
root->hideSubMenu();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::drawSelection(QPainter *p, const QRect &r)
|
||
|
{
|
||
|
p->save();
|
||
|
|
||
|
QColor c = Qt::blue;
|
||
|
p->setPen(QPen(c, 1));
|
||
|
c.setAlpha(32);
|
||
|
p->setBrush(c);
|
||
|
p->drawRect(r);
|
||
|
|
||
|
p->restore();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::keyPressEvent(QKeyEvent *event)
|
||
|
{
|
||
|
event->ignore();
|
||
|
}
|
||
|
|
||
|
void QDesignerMenu::keyReleaseEvent(QKeyEvent *event)
|
||
|
{
|
||
|
event->ignore();
|
||
|
}
|
||
|
|
||
|
QT_END_NAMESPACE
|