15#include <QtDesigner/abstractformeditor.h>
16#include <QtDesigner/abstractwidgetfactory.h>
17#include <QtDesigner/abstractmetadatabase.h>
18#include <QtDesigner/qextensionmanager.h>
20#include <QtWidgets/qapplication.h>
21#include <QtWidgets/qlineedit.h>
22#include <QtWidgets/qrubberband.h>
23#include <QtWidgets/qtooltip.h>
24#include <QtWidgets/qtoolbar.h>
26#include <QtGui/qaction.h>
27#include <QtGui/qdrag.h>
28#include <QtGui/qevent.h>
29#include <QtGui/qpainter.h>
31#include <QtCore/qtimer.h>
32#include <QtCore/qdebug.h>
36using namespace Qt::StringLiterals;
42 case Qt::LayoutDirectionAuto:
44 subMenuRect->setLeft(subMenuRect->left() - 20);
47 subMenuRect->setRight(subMenuRect->right() + 20);
52QDesignerMenu::QDesignerMenu(QWidget *parent) :
54 m_subMenuPixmap(QPixmap(u":/qt-project.org/formeditor/images/submenu.png"_s)),
56 m_addItem(
new qdesigner_internal::SpecialMenuAction(
this)),
57 m_addSeparator(
new qdesigner_internal::SpecialMenuAction(
this)),
58 m_showSubMenuTimer(
new QTimer(
this)),
59 m_deactivateWindowTimer(
new QTimer(
this)),
60 m_adjustSizeTimer(
new QTimer(
this)),
61 m_editor(
new QLineEdit(
this)),
63 m_lastSubMenuIndex(-1)
65 setContextMenuPolicy(Qt::DefaultContextMenu);
67 setSeparatorsCollapsible(
false);
69 connect(m_adjustSizeTimer, &QTimer::timeout,
this, &QDesignerMenu::slotAdjustSizeNow);
70 m_addItem->setText(tr(
"Type Here"));
73 m_addSeparator->setText(tr(
"Add Separator"));
74 addAction(m_addSeparator);
76 connect(m_showSubMenuTimer, &QTimer::timeout,
this, &QDesignerMenu::slotShowSubMenuNow);
78 connect(m_deactivateWindowTimer, &QTimer::timeout,
this, &QDesignerMenu::slotDeactivateNow);
80 m_editor->setObjectName(u"__qt__passive_editor"_s);
83 m_editor->installEventFilter(
this);
84 installEventFilter(
this);
87QDesignerMenu::~QDesignerMenu() =
default;
89void QDesignerMenu::slotAdjustSizeNow()
93 m_adjustSizeTimer->stop();
97bool QDesignerMenu::handleEvent(QWidget *widget, QEvent *event)
99 if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
102 if (widget == m_editor)
106 switch (event->type()) {
109 case QEvent::MouseButtonPress:
110 return handleMousePressEvent(widget,
static_cast<QMouseEvent*>(event));
111 case QEvent::MouseButtonRelease:
112 return handleMouseReleaseEvent(widget,
static_cast<QMouseEvent*>(event));
113 case QEvent::MouseButtonDblClick:
114 return handleMouseDoubleClickEvent(widget,
static_cast<QMouseEvent*>(event));
115 case QEvent::MouseMove:
116 return handleMouseMoveEvent(widget,
static_cast<QMouseEvent*>(event));
117 case QEvent::ContextMenu:
118 return handleContextMenuEvent(widget,
static_cast<QContextMenuEvent*>(event));
119 case QEvent::KeyPress:
120 return handleKeyPressEvent(widget,
static_cast<QKeyEvent*>(event));
126void QDesignerMenu::startDrag(
const QPoint &pos, Qt::KeyboardModifiers modifiers)
128 using namespace qdesigner_internal;
130 const int index = findAction(pos);
131 if (index >= realActionCount())
134 QAction *action = safeActionAt(index);
136 QDesignerFormWindowInterface *fw = formWindow();
137 const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction;
138 if (dropAction == Qt::MoveAction) {
139 auto *cmd =
new RemoveActionFromCommand(fw);
140 cmd->init(
this, action, actions().at(index + 1));
141 fw->commandHistory()->push(cmd);
144 QDrag *drag =
new QDrag(
this);
145 drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
146 drag->setMimeData(
new ActionRepositoryMimeData(action, dropAction));
148 const int old_index = m_currentIndex;
151 if (drag->exec(dropAction) == Qt::IgnoreAction) {
152 if (dropAction == Qt::MoveAction) {
153 QAction *previous = safeActionAt(index);
154 auto *cmd =
new InsertActionIntoCommand(fw);
155 cmd->init(
this, action, previous);
156 fw->commandHistory()->push(cmd);
159 m_currentIndex = old_index;
163bool QDesignerMenu::handleKeyPressEvent(QWidget * , QKeyEvent *e)
165 m_showSubMenuTimer->stop();
167 if (m_editor->isHidden() && hasFocus()) {
171 if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
189 moveUp(e->modifiers() & Qt::ControlModifier);
194 moveDown(e->modifiers() & Qt::ControlModifier);
201 case Qt::Key_PageDown:
202 m_currentIndex = actions().size() - 1;
221 case Qt::Key_Control:
227 QAction *action = currentAction();
228 if (!action || action->isSeparator() || action == m_addSeparator) {
232 if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
234 QApplication::sendEvent(m_editor, e);
242 }
else if (m_editor->hasFocus()) {
250 if (!m_editor->text().isEmpty()) {
251 leaveEditMode(ForceAccept);
274 QMouseEvent e(event->type(), targetPoint, event->globalPosition().toPoint(), event->button(), event->buttons(), event->modifiers());
275 QApplication::sendEvent(target, &e);
278bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
281 m_startPosition = QPoint();
283 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
286 if (!rect().contains(event->position().toPoint())) {
288 QWidget *target = QApplication::widgetAt(event->globalPosition().toPoint());
289 QMenuBar *mb = qobject_cast<QMenuBar*>(target);
290 QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(target);
291 if (mb !=
nullptr || menu !=
nullptr) {
292 const QPoint pt = target->mapFromGlobal(event->globalPosition().toPoint());
293 QAction *action = mb ==
nullptr ? menu->actionAt(pt) : mb->actionAt(pt);
295 sendMouseEventTo(target, pt, event);
300 m_currentIndex = findAction(event->position().toPoint());
301 QAction *action = safeActionAt(m_currentIndex);
304 if (action->menu() || hasSubMenuPixmap(action)) {
305 pm_rect = subMenuPixmapRect(action);
306 extendClickableArea(&pm_rect, layoutDirection());
309 if (!pm_rect.contains(event->position().toPoint()) && m_currentIndex != -1)
315bool QDesignerMenu::handleMousePressEvent(QWidget * , QMouseEvent *event)
317 if (!rect().contains(event->position().toPoint())) {
318 QWidget *clickedWidget = QApplication::widgetAt(event->globalPosition().toPoint());
319 if (QMenuBar *mb = qobject_cast<QMenuBar*>(clickedWidget)) {
320 const QPoint pt = mb->mapFromGlobal(event->globalPosition().toPoint());
321 if (QAction *action = mb->actionAt(pt)) {
322 QMenu * menu = action->menu();
323 if (menu == findRootMenu()) {
325 sendMouseEventTo(mb, pt, event);
331 if (QDesignerMenu *m = qobject_cast<QDesignerMenu *>(clickedWidget)) {
333 sendMouseEventTo(m, m->mapFromGlobal(event->globalPosition().toPoint()), event);
335 QDesignerMenu *root = findRootMenu();
340 if (QWidget *focusProxy = clickedWidget->focusProxy())
341 clickedWidget = focusProxy;
342 if (clickedWidget->focusPolicy() != Qt::NoFocus)
343 clickedWidget->setFocus(Qt::OtherFocusReason);
348 m_showSubMenuTimer->stop();
349 m_startPosition = QPoint();
352 if (event->button() != Qt::LeftButton)
355 m_startPosition = mapFromGlobal(event->globalPosition().toPoint());
357 const int index = findAction(m_startPosition);
359 QAction *action = safeActionAt(index);
360 QRect pm_rect = subMenuPixmapRect(action);
361 extendClickableArea(&pm_rect, layoutDirection());
363 const int old_index = m_currentIndex;
364 m_currentIndex = index;
365 if ((hasSubMenuPixmap(action) || action->menu() !=
nullptr)
366 && pm_rect.contains(m_startPosition)) {
367 if (m_currentIndex == m_lastSubMenuIndex) {
370 slotShowSubMenuNow();
372 if (index == old_index) {
373 if (m_currentIndex == m_lastSubMenuIndex)
381 if (index != old_index)
382 selectCurrentAction();
387bool QDesignerMenu::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
390 m_startPosition = QPoint();
395bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
397 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
400 if (!rect().contains(event->position().toPoint())) {
402 if (QMenuBar *mb = qobject_cast<QMenuBar*>(QApplication::widgetAt(event->globalPosition().toPoint()))) {
403 const QPoint pt = mb->mapFromGlobal(event->globalPosition().toPoint());
404 QAction *action = mb->actionAt(pt);
405 if (action && action->menu() == findRootMenu()) {
407 sendMouseEventTo(mb, pt, event);
416 if (m_startPosition.isNull())
421 const QPoint pos = mapFromGlobal(event->globalPosition().toPoint());
423 if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
426 startDrag(m_startPosition, event->modifiers());
427 m_startPosition = QPoint();
432bool QDesignerMenu::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
436 const int index = findAction(mapFromGlobal(event->globalPos()));
437 QAction *action = safeActionAt(index);
438 if (qobject_cast<qdesigner_internal::SpecialMenuAction*>(action))
443 itemData.setValue(action);
445 QAction *addSeparatorAction = menu.addAction(tr(
"Insert separator"));
446 addSeparatorAction->setData(itemData);
448 QAction *removeAction =
nullptr;
449 if (action->isSeparator())
450 removeAction = menu.addAction(tr(
"Remove separator"));
452 removeAction = menu.addAction(tr(
"Remove action '%1'").arg(action->objectName()));
453 removeAction->setData(itemData);
455 connect(addSeparatorAction, &QAction::triggered,
this, &QDesignerMenu::slotAddSeparator);
456 connect(removeAction, &QAction::triggered,
this, &QDesignerMenu::slotRemoveSelectedAction);
457 menu.exec(event->globalPos());
462void QDesignerMenu::slotAddSeparator()
464 QAction *action = qobject_cast<QAction *>(sender());
468 QAction *a = qvariant_cast<QAction*>(action->data());
469 Q_ASSERT(a !=
nullptr);
471 const int pos = actions().indexOf(a);
472 QAction *action_before =
nullptr;
474 action_before = safeActionAt(pos);
476 QDesignerFormWindowInterface *fw = formWindow();
477 fw->beginCommand(tr(
"Add separator"));
478 QAction *sep = createAction(QString(),
true);
480 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
481 cmd->init(
this, sep, action_before);
482 fw->commandHistory()->push(cmd);
485 QAction *parent_action = parentMenu()->currentAction();
486 if (parent_action->menu() ==
nullptr) {
487 auto *cmd =
new qdesigner_internal::CreateSubmenuCommand(fw);
488 cmd->init(parentMenu(), parentMenu()->currentAction());
489 fw->commandHistory()->push(cmd);
496void QDesignerMenu::slotRemoveSelectedAction()
498 if (QAction *action = qobject_cast<QAction *>(sender()))
499 if (QAction *a = qvariant_cast<QAction*>(action->data()))
503void QDesignerMenu::deleteAction(QAction *a)
505 const int pos = actions().indexOf(a);
506 QAction *action_before =
nullptr;
508 action_before = safeActionAt(pos + 1);
510 QDesignerFormWindowInterface *fw = formWindow();
511 auto *cmd =
new qdesigner_internal::RemoveActionFromCommand(fw);
512 cmd->init(
this, a, action_before);
513 fw->commandHistory()->push(cmd);
516QRect QDesignerMenu::subMenuPixmapRect(QAction *action)
const
518 const QRect g = actionGeometry(action);
519 const int x = layoutDirection() == Qt::LeftToRight ? (g.right() - m_subMenuPixmap.width() - 2) : 2;
520 const int y = g.top() + (g.height() - m_subMenuPixmap.height())/2 + 1;
521 return QRect(x, y, m_subMenuPixmap.width(), m_subMenuPixmap.height());
524bool QDesignerMenu::hasSubMenuPixmap(QAction *action)
const
526 return action !=
nullptr
527 && qobject_cast<qdesigner_internal::SpecialMenuAction*>(action) ==
nullptr
528 && !action->isSeparator()
530 && canCreateSubMenu(action);
533void QDesignerMenu::showEvent ( QShowEvent * event )
535 selectCurrentAction();
536 QMenu::showEvent (event);
539void QDesignerMenu::paintEvent(QPaintEvent *event)
541 using namespace qdesigner_internal;
543 QMenu::paintEvent(event);
547 QAction *current = currentAction();
549 const auto &actionList = actions();
550 for (QAction *a : actionList) {
551 const QRect g = actionGeometry(a);
553 if (qobject_cast<SpecialMenuAction*>(a)) {
554 QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
555 lg.setColorAt(0.0, Qt::transparent);
556 lg.setColorAt(0.7, QColor(0, 0, 0, 32));
557 lg.setColorAt(1.0, Qt::transparent);
560 }
else if (hasSubMenuPixmap(a)) {
561 p.drawPixmap(subMenuPixmapRect(a).topLeft(), m_subMenuPixmap);
565 if (!hasFocus() || !current || m_dragging)
568 if (QDesignerMenu *menu = parentMenu()) {
569 if (menu->dragging())
573 if (QDesignerMenuBar *menubar = qobject_cast<QDesignerMenuBar*>(parentWidget())) {
574 if (menubar->dragging())
578 const QRect g = actionGeometry(current);
579 drawSelection(&p, g.adjusted(1, 1, -3, -3));
582bool QDesignerMenu::dragging()
const
587QDesignerMenu *QDesignerMenu::findRootMenu()
const
590 return parentMenu()->findRootMenu();
592 return const_cast<QDesignerMenu*>(
this);
595QDesignerMenu *QDesignerMenu::findActivatedMenu()
const
597 if (QDesignerMenu *activeDesignerMenu = qobject_cast<QDesignerMenu *>(QApplication::activeWindow())) {
598 if (activeDesignerMenu ==
this || findChildren<QDesignerMenu *>().contains(activeDesignerMenu))
599 return activeDesignerMenu;
605bool QDesignerMenu::eventFilter(QObject *object, QEvent *event)
607 if (object !=
this && object != m_editor) {
611 if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) {
612 leaveEditMode(Default);
618 bool dispatch =
true;
620 switch (event->type()) {
623 case QEvent::WindowDeactivate:
626 case QEvent::ContextMenu:
627 case QEvent::MouseButtonPress:
628 case QEvent::MouseButtonRelease:
629 case QEvent::MouseButtonDblClick:
631 while (QApplication::activePopupWidget() && !qobject_cast<QDesignerMenu*>(QApplication::activePopupWidget())) {
632 QApplication::activePopupWidget()->close();
636 case QEvent::KeyPress:
637 case QEvent::KeyRelease:
638 case QEvent::MouseMove:
639 dispatch = (object != m_editor);
644 case QEvent::FocusIn:
645 case QEvent::FocusOut:
647 if (QWidget *widget = qobject_cast<QWidget*>(object))
648 if (widget ==
this || isAncestorOf(widget))
649 return handleEvent(widget, event);
656int QDesignerMenu::findAction(
const QPoint &pos)
const
658 const int index = actionIndexAt(
this, pos, Qt::Vertical);
660 return realActionCount();
665void QDesignerMenu::adjustIndicator(
const QPoint &pos)
667 if (QDesignerActionProviderExtension *a = actionProvider()) {
668 a->adjustIndicator(pos);
672QDesignerMenu::ActionDragCheck QDesignerMenu::checkAction(QAction *action)
const
674 if (!action || (action->menu() && action->menu()->parentWidget() !=
const_cast<QDesignerMenu*>(
this)))
677 if (!qdesigner_internal::Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
680 if (actions().contains(action))
681 return ActionDragOnSubMenu;
683 return AcceptActionDrag;
686void QDesignerMenu::dragEnterEvent(QDragEnterEvent *event)
688 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
689 if (!d || d->actionList().isEmpty()) {
694 QAction *action = d->actionList().first();
696 switch (checkAction(action)) {
700 case ActionDragOnSubMenu:
704 case AcceptActionDrag:
707 adjustIndicator(event->position().toPoint());
712void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event)
714 if (actionGeometry(m_addSeparator).contains(event->position().toPoint())) {
716 adjustIndicator(QPoint(-1, -1));
720 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
721 if (!d || d->actionList().isEmpty()) {
726 QAction *action = d->actionList().first();
727 const ActionDragCheck dc = checkAction(action);
732 case ActionDragOnSubMenu:
733 case AcceptActionDrag: {
734 const int newIndex = findAction(event->position().toPoint());
735 if (safeActionAt(newIndex) != action) {
736 m_currentIndex = newIndex;
737 if (m_lastSubMenuIndex != m_currentIndex)
738 m_showSubMenuTimer->start(300);
740 if (dc == AcceptActionDrag) {
741 adjustIndicator(event->position().toPoint());
751void QDesignerMenu::dragLeaveEvent(QDragLeaveEvent *)
754 adjustIndicator(QPoint(-1, -1));
755 m_showSubMenuTimer->stop();
758void QDesignerMenu::dropEvent(QDropEvent *event)
760 m_showSubMenuTimer->stop();
764 QDesignerFormWindowInterface *fw = formWindow();
765 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
766 if (!d || d->actionList().isEmpty()) {
770 QAction *action = d->actionList().first();
771 if (action && checkAction(action) == AcceptActionDrag) {
772 event->acceptProposedAction();
773 int index = findAction(event->position().toPoint());
774 index = qMin(index, actions().size() - 1);
776 fw->beginCommand(tr(
"Insert action"));
777 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
778 cmd->init(
this, action, safeActionAt(index));
779 fw->commandHistory()->push(cmd);
781 m_currentIndex = index;
784 QAction *parent_action = parentMenu()->currentAction();
785 if (parent_action->menu() ==
nullptr) {
786 auto *cmd =
new qdesigner_internal::CreateSubmenuCommand(fw);
787 cmd->init(parentMenu(), parentMenu()->currentAction(), action);
788 fw->commandHistory()->push(cmd);
796 adjustIndicator(QPoint(-1, -1));
799void QDesignerMenu::actionEvent(QActionEvent *event)
801 QMenu::actionEvent(event);
802 m_adjustSizeTimer->start(0);
805QDesignerFormWindowInterface *QDesignerMenu::formWindow()
const
808 return parentMenu()->formWindow();
810 return QDesignerFormWindowInterface::findFormWindow(parentWidget());
813QDesignerActionProviderExtension *QDesignerMenu::actionProvider()
815 if (QDesignerFormWindowInterface *fw = formWindow()) {
816 QDesignerFormEditorInterface *core = fw->core();
817 return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(),
this);
823void QDesignerMenu::closeMenuChain()
825 m_showSubMenuTimer->stop();
828 while (w && qobject_cast<QMenu*>(w))
829 w = w->parentWidget();
832 const auto &menus = w->findChildren<QMenu *>();
833 for (QMenu *subMenu : menus)
837 m_lastSubMenuIndex = -1;
842bool QDesignerMenu::hideSubMenuOnCursorKey()
850 return parentMenuBar() ==
nullptr;
855bool QDesignerMenu::showSubMenuOnCursorKey()
857 using namespace qdesigner_internal;
859 const QAction *action = currentAction();
861 if (qobject_cast<
const SpecialMenuAction*>(action) || action->isSeparator()) {
867 m_lastSubMenuIndex = -1;
868 slotShowSubMenuNow();
872void QDesignerMenu::moveLeft()
874 const bool handled = layoutDirection() == Qt::LeftToRight ?
875 hideSubMenuOnCursorKey() : showSubMenuOnCursorKey();
877 parentMenuBar()->moveLeft();
880void QDesignerMenu::moveRight()
882 const bool handled = layoutDirection() == Qt::LeftToRight ?
883 showSubMenuOnCursorKey() : hideSubMenuOnCursorKey();
885 parentMenuBar()->moveRight();
888void QDesignerMenu::moveUp(
bool ctrl)
890 if (m_currentIndex == 0) {
896 (
void) swap(m_currentIndex, m_currentIndex - 1);
898 m_currentIndex = qMax(0, m_currentIndex);
901 selectCurrentAction();
904void QDesignerMenu::moveDown(
bool ctrl)
906 if (m_currentIndex == actions().size() - 1) {
911 (
void) swap(m_currentIndex + 1, m_currentIndex);
914 m_currentIndex = qMin(actions().size() - 1, m_currentIndex);
917 selectCurrentAction();
920QAction *QDesignerMenu::currentAction()
const
922 if (m_currentIndex < 0 || m_currentIndex >= actions().size())
925 return safeActionAt(m_currentIndex);
928int QDesignerMenu::realActionCount()
const
930 return actions().size() - 2;
933void QDesignerMenu::selectCurrentAction()
935 using namespace qdesigner_internal;
937 QAction *action = currentAction();
938 if (!action || action == m_addSeparator || action == m_addItem)
941 QDesignerObjectInspector *oi =
nullptr;
942 ActionEditor *ae =
nullptr;
943 if (QDesignerFormWindowInterface *fw = formWindow()) {
944 auto core = fw->core();
945 oi = qobject_cast<QDesignerObjectInspector *>(core->objectInspector());
946 ae = qobject_cast<ActionEditor *>(core->actionEditor());
952 oi->clearSelection();
953 if (QMenu *menu = action->menu()) {
954 oi->selectObject(menu);
956 ae->clearSelection();
958 oi->selectObject(action);
960 ae->selectAction(action);
964void QDesignerMenu::createRealMenuAction(QAction *action)
966 using namespace qdesigner_internal;
971 QDesignerFormWindowInterface *fw = formWindow();
972 QDesignerFormEditorInterface *core = formWindow()->core();
974 QDesignerMenu *menu = findOrCreateSubMenu(action);
975 m_subMenus.remove(action);
977 action->setMenu(menu);
978 menu->setTitle(action->text());
982 core->widgetFactory()->initialize(menu);
984 const QString niceObjectName = ActionEditor::actionTextToName(menu->title(), u"menu"_s);
985 menu->setObjectName(niceObjectName);
987 core->metaDataBase()->add(menu);
988 fw->ensureUniqueObjectName(menu);
990 QAction *menuAction = menu->menuAction();
991 core->metaDataBase()->add(menuAction);
994void QDesignerMenu::removeRealMenu(QAction *action)
996 QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu());
999 action->setMenu(
nullptr);
1000 m_subMenus.insert(action, menu);
1001 QDesignerFormEditorInterface *core = formWindow()->core();
1002 core->metaDataBase()->remove(menu);
1005QDesignerMenu *QDesignerMenu::findOrCreateSubMenu(QAction *action)
1008 return qobject_cast<QDesignerMenu*>(action->menu());
1010 QDesignerMenu *menu = m_subMenus.value(action);
1012 menu =
new QDesignerMenu(
this);
1013 m_subMenus.insert(action, menu);
1019bool QDesignerMenu::canCreateSubMenu(QAction *action)
const
1021 const QObjectList associatedObjects = action->associatedObjects();
1022 for (
const QObject *ao : associatedObjects) {
1024 if (
const QMenu *m = qobject_cast<
const QMenu *>(ao)) {
1025 if (m->actions().contains(action))
1027 }
else if (
const QToolBar *tb = qobject_cast<
const QToolBar *>(ao)) {
1028 if (tb->actions().contains(action))
1036void QDesignerMenu::slotShowSubMenuNow()
1038 m_showSubMenuTimer->stop();
1040 if (m_lastSubMenuIndex == m_currentIndex)
1043 if (m_lastSubMenuIndex != -1)
1046 if (m_currentIndex >= realActionCount())
1049 QAction *action = currentAction();
1051 if (action->isSeparator() || !canCreateSubMenu(action))
1054 if (QMenu *menu = findOrCreateSubMenu(action)) {
1055 if (!menu->isVisible()) {
1056 if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
1057 menu->setWindowFlags(Qt::Popup);
1058 const QRect g = actionGeometry(action);
1059 if (layoutDirection() == Qt::LeftToRight) {
1060 menu->move(mapToGlobal(g.topRight()));
1064 QPoint point = g.topLeft() - QPoint(menu->width() + 10, 0);
1065 menu->move(mapToGlobal(point));
1074 m_lastSubMenuIndex = m_currentIndex;
1078void QDesignerMenu::showSubMenu(QAction *action)
1080 using namespace qdesigner_internal;
1082 m_showSubMenuTimer->stop();
1084 if (m_editor->isVisible() || !action || qobject_cast<SpecialMenuAction*>(action)
1085 || action->isSeparator() || !isVisible())
1088 m_showSubMenuTimer->start(300);
1091QDesignerMenu *QDesignerMenu::parentMenu()
const
1093 return qobject_cast<QDesignerMenu*>(parentWidget());
1096QDesignerMenuBar *QDesignerMenu::parentMenuBar()
const
1098 if (QDesignerMenuBar *mb = qobject_cast<QDesignerMenuBar*>(parentWidget()))
1100 if (QDesignerMenu *m = parentMenu())
1101 return m->parentMenuBar();
1106void QDesignerMenu::setVisible(
bool visible)
1111 m_lastSubMenuIndex = -1;
1113 QMenu::setVisible(visible);
1117void QDesignerMenu::adjustSpecialActions()
1119 removeAction(m_addItem);
1120 removeAction(m_addSeparator);
1121 addAction(m_addItem);
1122 addAction(m_addSeparator);
1125void QDesignerMenu::enterEditMode()
1127 if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
1131 QDesignerFormWindowInterface *fw = formWindow();
1132 fw->beginCommand(tr(
"Add separator"));
1133 QAction *sep = createAction(QString(),
true);
1135 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
1136 cmd->init(
this, sep, safeActionAt(realActionCount()));
1137 fw->commandHistory()->push(cmd);
1140 QAction *parent_action = parentMenu()->currentAction();
1141 if (parent_action->menu() ==
nullptr) {
1142 auto *cmd =
new qdesigner_internal::CreateSubmenuCommand(fw);
1143 cmd->init(parentMenu(), parentMenu()->currentAction());
1144 fw->commandHistory()->push(cmd);
1150 m_currentIndex = actions().indexOf(m_addItem);
1155void QDesignerMenu::leaveEditMode(LeaveEditMode mode)
1157 using namespace qdesigner_internal;
1159 if (mode == Default)
1162 QAction *action =
nullptr;
1164 QDesignerFormWindowInterface *fw = formWindow();
1165 if (m_currentIndex < realActionCount()) {
1166 action = safeActionAt(m_currentIndex);
1167 fw->beginCommand(QApplication::translate(
"Command",
"Set action text"));
1169 Q_ASSERT(fw !=
nullptr);
1170 fw->beginCommand(QApplication::translate(
"Command",
"Insert action"));
1171 action = createAction(ActionEditor::actionTextToName(m_editor->text()));
1172 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
1173 cmd->init(
this, action, currentAction());
1174 fw->commandHistory()->push(cmd);
1177 auto *cmd =
new qdesigner_internal::SetPropertyCommand(fw);
1178 cmd->init(action, u"text"_s, m_editor->text());
1179 fw->commandHistory()->push(cmd);
1182 QAction *parent_action = parentMenu()->currentAction();
1183 if (parent_action->menu() ==
nullptr) {
1184 auto *cmd =
new qdesigner_internal::CreateSubmenuCommand(fw);
1185 cmd->init(parentMenu(), parentMenu()->currentAction(), action);
1186 fw->commandHistory()->push(cmd);
1194QAction *QDesignerMenu::safeMenuAction(QDesignerMenu *menu)
const
1196 QAction *action = menu->menuAction();
1199 action = m_subMenus.key(menu);
1204void QDesignerMenu::showLineEdit()
1206 m_showSubMenuTimer->stop();
1208 QAction *action =
nullptr;
1210 if (m_currentIndex < realActionCount())
1211 action = safeActionAt(m_currentIndex);
1215 if (action->isSeparator())
1223 const QString text = action != m_addItem ? action->text() : QString();
1224 m_editor->setText(text);
1225 m_editor->selectAll();
1226 m_editor->setGeometry(actionGeometry(action).adjusted(1, 1, -2, -2));
1228 m_editor->setFocus();
1231QAction *QDesignerMenu::createAction(
const QString &objectName,
bool separator)
1233 QDesignerFormWindowInterface *fw = formWindow();
1235 return qdesigner_internal::ToolBarEventFilter::createAction(fw, objectName, separator);
1239bool QDesignerMenu::swap(
int a,
int b)
1241 using namespace qdesigner_internal;
1243 const int left = qMin(a, b);
1244 int right = qMax(a, b);
1246 QAction *action_a = safeActionAt(left);
1247 QAction *action_b = safeActionAt(right);
1249 if (action_a == action_b
1252 || qobject_cast<SpecialMenuAction*>(action_a)
1253 || qobject_cast<SpecialMenuAction*>(action_b))
1256 right = qMin(right, realActionCount());
1260 QDesignerFormWindowInterface *fw = formWindow();
1261 fw->beginCommand(QApplication::translate(
"Command",
"Move action"));
1263 QAction *action_b_before = safeActionAt(right + 1);
1265 auto *cmd1 =
new qdesigner_internal::RemoveActionFromCommand(fw);
1266 cmd1->init(
this, action_b, action_b_before,
false);
1267 fw->commandHistory()->push(cmd1);
1269 QAction *action_a_before = safeActionAt(left + 1);
1271 auto *cmd2 =
new qdesigner_internal::InsertActionIntoCommand(fw);
1272 cmd2->init(
this, action_b, action_a_before,
false);
1273 fw->commandHistory()->push(cmd2);
1275 auto *cmd3 =
new qdesigner_internal::RemoveActionFromCommand(fw);
1276 cmd3->init(
this, action_a, action_b,
false);
1277 fw->commandHistory()->push(cmd3);
1279 auto *cmd4 =
new qdesigner_internal::InsertActionIntoCommand(fw);
1280 cmd4->init(
this, action_a, action_b_before,
true);
1281 fw->commandHistory()->push(cmd4);
1288QAction *QDesignerMenu::safeActionAt(
int index)
const
1290 if (index < 0 || index >= actions().size())
1293 return actions().at(index);
1296void QDesignerMenu::hideSubMenu()
1298 m_lastSubMenuIndex = -1;
1299 const auto &menus = findChildren<QMenu *>();
1300 for (QMenu *subMenu : menus)
1304void QDesignerMenu::deleteAction()
1306 QAction *action = currentAction();
1307 const int pos = actions().indexOf(action);
1308 QAction *action_before =
nullptr;
1310 action_before = safeActionAt(pos + 1);
1312 QDesignerFormWindowInterface *fw = formWindow();
1313 auto *cmd =
new qdesigner_internal::RemoveActionFromCommand(fw);
1314 cmd->init(
this, action, action_before);
1315 fw->commandHistory()->push(cmd);
1320void QDesignerMenu::deactivateMenu()
1322 m_deactivateWindowTimer->start(10);
1325void QDesignerMenu::slotDeactivateNow()
1327 m_deactivateWindowTimer->stop();
1332 QDesignerMenu *root = findRootMenu();
1334 if (! root->findActivatedMenu()) {
1336 root->hideSubMenu();
1340void QDesignerMenu::drawSelection(QPainter *p,
const QRect &r)
1344 QColor c = Qt::blue;
1345 p->setPen(QPen(c, 1));
1353void QDesignerMenu::keyPressEvent(QKeyEvent *event)
1358void QDesignerMenu::keyReleaseEvent(QKeyEvent *event)
Combined button and popup list for selecting options.