15#include <QtDesigner/abstractformwindow.h>
16#include <QtDesigner/abstractformeditor.h>
17#include <QtDesigner/abstractwidgetfactory.h>
18#include <QtDesigner/qextensionmanager.h>
20#include <QtCore/qmimedata.h>
22#include <QtCore/qdebug.h>
24#include <QtWidgets/qapplication.h>
25#include <QtGui/qdrag.h>
26#include <QtWidgets/qlineedit.h>
27#include <QtGui/qpainter.h>
28#include <QtGui/qevent.h>
32using namespace Qt::StringLiterals;
34using ActionList = QList<QAction *>;
51QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) :
53 m_addMenu(
new qdesigner_internal::SpecialMenuAction(
this)),
54 m_editor(
new QLineEdit(
this)),
55 m_promotionTaskMenu(
new qdesigner_internal::PromotionTaskMenu(
this, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget,
this))
57 setContextMenuPolicy(Qt::DefaultContextMenu);
61 setNativeMenuBar(
false);
63 m_addMenu->setText(tr(
"Type Here"));
67 italic.setItalic(
true);
68 m_addMenu->setFont(italic);
70 m_editor->setObjectName(u"__qt__passive_editor"_s);
72 m_editor->installEventFilter(
this);
73 installEventFilter(
this);
76QDesignerMenuBar::~QDesignerMenuBar() =
default;
78void QDesignerMenuBar::paintEvent(QPaintEvent *event)
80 QMenuBar::paintEvent(event);
84 const auto &actionList = actions();
85 for (QAction *a : actionList) {
86 if (qobject_cast<qdesigner_internal::SpecialMenuAction*>(a)) {
87 const QRect g = actionGeometry(a);
88 QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
89 lg.setColorAt(0.0, Qt::transparent);
90 lg.setColorAt(0.7, QColor(0, 0, 0, 32));
91 lg.setColorAt(1.0, Qt::transparent);
97 QAction *action = currentAction();
99 if (m_dragging || !action)
103 const QRect g = actionGeometry(action);
104 QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1));
105 }
else if (action->menu() && action->menu()->isVisible()) {
106 const QRect g = actionGeometry(action);
107 p.drawRect(g.adjusted(1, 1, -1, -1));
111bool QDesignerMenuBar::handleEvent(QWidget *widget, QEvent *event)
116 if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
119 switch (event->type()) {
122 case QEvent::MouseButtonDblClick:
123 return handleMouseDoubleClickEvent(widget,
static_cast<QMouseEvent*>(event));
124 case QEvent::MouseButtonPress:
125 return handleMousePressEvent(widget,
static_cast<QMouseEvent*>(event));
126 case QEvent::MouseButtonRelease:
127 return handleMouseReleaseEvent(widget,
static_cast<QMouseEvent*>(event));
128 case QEvent::MouseMove:
129 return handleMouseMoveEvent(widget,
static_cast<QMouseEvent*>(event));
130 case QEvent::ContextMenu:
131 return handleContextMenuEvent(widget,
static_cast<QContextMenuEvent*>(event));
132 case QEvent::KeyPress:
133 return handleKeyPressEvent(widget,
static_cast<QKeyEvent*>(event));
134 case QEvent::FocusIn:
135 case QEvent::FocusOut:
136 return widget != m_editor;
142bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event)
144 if (!rect().contains(event->position().toPoint()))
147 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
152 m_startPosition = QPoint();
154 m_currentIndex = actionIndexAt(
this, event->position().toPoint(), Qt::Horizontal);
155 if (m_currentIndex != -1) {
162bool QDesignerMenuBar::handleKeyPressEvent(QWidget *, QKeyEvent *e)
164 if (m_editor->isHidden()) {
168 if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
176 moveLeft(e->modifiers() & Qt::ControlModifier);
181 moveRight(e->modifiers() & Qt::ControlModifier);
198 case Qt::Key_PageDown:
199 m_currentIndex = actions().size() - 1;
210 case Qt::Key_Control:
217 if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
219 QApplication::sendEvent(m_editor, e);
231 case Qt::Key_Control:
237 if (!m_editor->text().isEmpty()) {
238 leaveEditMode(ForceAccept);
239 if (m_lastFocusWidget)
240 m_lastFocusWidget->setFocus();
261void QDesignerMenuBar::startDrag(
const QPoint &pos)
263 using namespace qdesigner_internal;
265 const int index = findAction(pos);
266 if (m_currentIndex == -1 || index >= realActionCount())
269 QAction *action = safeActionAt(index);
271 QDesignerFormWindowInterface *fw = formWindow();
272 auto *cmd =
new qdesigner_internal::RemoveActionFromCommand(fw);
273 cmd->init(
this, action, actions().at(index + 1));
274 fw->commandHistory()->push(cmd);
280 QDrag *drag =
new QDrag(
this);
281 drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
282 drag->setMimeData(
new ActionRepositoryMimeData(action, Qt::MoveAction));
284 const int old_index = m_currentIndex;
287 if (drag->exec(Qt::MoveAction) == Qt::IgnoreAction) {
288 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
289 cmd->init(
this, action, safeActionAt(index));
290 fw->commandHistory()->push(cmd);
292 m_currentIndex = old_index;
297bool QDesignerMenuBar::handleMousePressEvent(QWidget *, QMouseEvent *event)
299 m_startPosition = QPoint();
302 if (event->button() != Qt::LeftButton)
305 m_startPosition = event->position().toPoint();
306 const int newIndex = actionIndexAt(
this, m_startPosition, Qt::Horizontal);
307 const bool changed = newIndex != m_currentIndex;
308 m_currentIndex = newIndex;
309 updateCurrentAction(changed);
314bool QDesignerMenuBar::handleMouseReleaseEvent(QWidget *, QMouseEvent *event)
316 m_startPosition = QPoint();
318 if (event->button() != Qt::LeftButton)
322 m_currentIndex = actionIndexAt(
this, event->position().toPoint(), Qt::Horizontal);
323 if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount())
329bool QDesignerMenuBar::handleMouseMoveEvent(QWidget *, QMouseEvent *event)
331 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
334 if (m_startPosition.isNull())
337 const QPoint pos = mapFromGlobal(event->globalPosition().toPoint());
339 if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
342 const int index = actionIndexAt(
this, m_startPosition, Qt::Horizontal);
343 if (index < actions().size()) {
348 startDrag(m_startPosition);
349 m_startPosition = QPoint();
354ActionList QDesignerMenuBar::contextMenuActions()
356 using namespace qdesigner_internal;
359 if (QAction *action = safeActionAt(m_currentIndex)) {
360 if (!qobject_cast<SpecialMenuAction*>(action)) {
362 itemData.setValue(action);
364 QAction *remove_action =
new QAction(tr(
"Remove Menu '%1'").arg(action->menu()->objectName()),
nullptr);
365 remove_action->setData(itemData);
366 connect(remove_action, &QAction::triggered,
this, &QDesignerMenuBar::deleteMenu);
367 rc.push_back(remove_action);
368 QAction *sep =
new QAction(
nullptr);
369 sep->setSeparator(
true);
374 m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc);
376 QAction *remove_menubar =
new QAction(tr(
"Remove Menu Bar"),
nullptr);
377 connect(remove_menubar, &QAction::triggered,
this, &QDesignerMenuBar::slotRemoveMenuBar);
378 rc.push_back(remove_menubar);
382bool QDesignerMenuBar::handleContextMenuEvent(QWidget *, QContextMenuEvent *event)
386 m_currentIndex = actionIndexAt(
this, mapFromGlobal(event->globalPos()), Qt::Horizontal);
391 const ActionList al = contextMenuActions();
394 menu.exec(event->globalPos());
398void QDesignerMenuBar::slotRemoveMenuBar()
400 Q_ASSERT(formWindow() !=
nullptr);
402 QDesignerFormWindowInterface *fw = formWindow();
404 auto *cmd =
new qdesigner_internal::DeleteMenuBarCommand(fw);
406 fw->commandHistory()->push(cmd);
409void QDesignerMenuBar::focusOutEvent(QFocusEvent *event)
411 QMenuBar::focusOutEvent(event);
414void QDesignerMenuBar::enterEditMode()
416 if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
421void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode)
423 using namespace qdesigner_internal;
425 m_editor->releaseKeyboard();
430 if (m_editor->text().isEmpty())
433 QAction *action =
nullptr;
435 QDesignerFormWindowInterface *fw = formWindow();
438 if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) {
439 action = safeActionAt(m_currentIndex);
440 fw->beginCommand(QApplication::translate(
"Command",
"Change Title"));
442 fw->beginCommand(QApplication::translate(
"Command",
"Insert Menu"));
443 const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), u"menu"_s);
444 QMenu *menu = qobject_cast<QMenu*>(fw->core()->widgetFactory()->createWidget(u"QMenu"_s,
this));
445 fw->core()->widgetFactory()->initialize(menu);
446 menu->setObjectName(niceObjectName);
447 menu->setTitle(tr(
"Menu"));
448 fw->ensureUniqueObjectName(menu);
449 action = menu->menuAction();
450 auto *cmd =
new qdesigner_internal::AddMenuActionCommand(fw);
451 cmd->init(action, m_addMenu,
this,
this);
452 fw->commandHistory()->push(cmd);
455 auto *cmd =
new qdesigner_internal::SetPropertyCommand(fw);
456 cmd->init(action, u"text"_s, m_editor->text());
457 fw->commandHistory()->push(cmd);
461void QDesignerMenuBar::showLineEdit()
463 QAction *action =
nullptr;
465 if (m_currentIndex >= 0 && m_currentIndex < realActionCount())
466 action = safeActionAt(m_currentIndex);
470 if (action->isSeparator())
475 m_lastFocusWidget = qApp->focusWidget();
478 const QString text = action != m_addMenu ? action->text() : QString();
480 m_editor->setText(text);
481 m_editor->selectAll();
482 m_editor->setGeometry(actionGeometry(action));
484 m_editor->activateWindow();
485 m_editor->setFocus();
486 m_editor->grabKeyboard();
489bool QDesignerMenuBar::eventFilter(QObject *object, QEvent *event)
491 if (object !=
this && object != m_editor)
494 if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) {
495 leaveEditMode(Default);
501 bool dispatch =
true;
503 switch (event->type()) {
506 case QEvent::KeyPress:
507 case QEvent::KeyRelease:
508 case QEvent::ContextMenu:
509 case QEvent::MouseMove:
510 case QEvent::MouseButtonPress:
511 case QEvent::MouseButtonRelease:
512 case QEvent::MouseButtonDblClick:
513 dispatch = (object != m_editor);
518 case QEvent::FocusIn:
519 case QEvent::FocusOut:
521 QWidget *widget = qobject_cast<QWidget*>(object);
523 if (dispatch && widget && (widget ==
this || isAncestorOf(widget)))
524 return handleEvent(widget, event);
527 case QEvent::Shortcut:
535int QDesignerMenuBar::findAction(
const QPoint &pos)
const
537 const int index = actionIndexAt(
this, pos, Qt::Horizontal);
539 return realActionCount();
544void QDesignerMenuBar::adjustIndicator(
const QPoint &pos)
546 const int index = findAction(pos);
547 QAction *action = safeActionAt(index);
548 Q_ASSERT(action !=
nullptr);
550 if (pos != QPoint(-1, -1)) {
551 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
552 if (!m || m->parentMenu()) {
553 m_currentIndex = index;
558 if (QDesignerActionProviderExtension *a = actionProvider()) {
559 a->adjustIndicator(pos);
563QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action)
const
566 if (!action || !qdesigner_internal::Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
570 return ActionDragOnSubMenu;
572 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
573 if (m && m->parentMenu())
574 return ActionDragOnSubMenu;
576 if (actions().contains(action))
577 return ActionDragOnSubMenu;
579 return AcceptActionDrag;
582void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event)
584 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
585 if (!d || d->actionList().isEmpty()) {
590 QAction *action = d->actionList().first();
591 switch (checkAction(action)) {
595 case ActionDragOnSubMenu:
599 case AcceptActionDrag:
602 adjustIndicator(event->position().toPoint());
607void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event)
609 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
610 if (!d || d->actionList().isEmpty()) {
614 QAction *action = d->actionList().first();
616 switch (checkAction(action)) {
620 case ActionDragOnSubMenu:
622 showMenu(findAction(event->position().toPoint()));
624 case AcceptActionDrag:
626 adjustIndicator(event->position().toPoint());
631void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *)
635 adjustIndicator(QPoint(-1, -1));
638void QDesignerMenuBar::dropEvent(QDropEvent *event)
642 if (
auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData())) {
644 QAction *action = d->actionList().first();
645 if (checkAction(action) == AcceptActionDrag) {
646 event->acceptProposedAction();
647 int index = findAction(event->position().toPoint());
648 index = qMin(index, actions().size() - 1);
650 QDesignerFormWindowInterface *fw = formWindow();
651 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
652 cmd->init(
this, action, safeActionAt(index));
653 fw->commandHistory()->push(cmd);
655 m_currentIndex = index;
657 adjustIndicator(QPoint(-1, -1));
664void QDesignerMenuBar::actionEvent(QActionEvent *event)
666 QMenuBar::actionEvent(event);
669QDesignerFormWindowInterface *QDesignerMenuBar::formWindow()
const
671 return QDesignerFormWindowInterface::findFormWindow(
const_cast<QDesignerMenuBar*>(
this));
674QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider()
676 if (QDesignerFormWindowInterface *fw = formWindow()) {
677 QDesignerFormEditorInterface *core = fw->core();
678 return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(),
this);
684QAction *QDesignerMenuBar::currentAction()
const
686 if (m_currentIndex < 0 || m_currentIndex >= actions().size())
689 return safeActionAt(m_currentIndex);
692int QDesignerMenuBar::realActionCount()
const
694 return actions().size() - 1;
697bool QDesignerMenuBar::dragging()
const
702void QDesignerMenuBar::moveLeft(
bool ctrl)
704 if (layoutDirection() == Qt::LeftToRight) {
711void QDesignerMenuBar::moveRight(
bool ctrl)
713 if (layoutDirection() == Qt::LeftToRight) {
720void QDesignerMenuBar::movePrevious(
bool ctrl)
722 const bool swapped = ctrl && swapActions(m_currentIndex, m_currentIndex - 1);
723 const int newIndex = qMax(0, m_currentIndex - 1);
725 if (swapped || newIndex != m_currentIndex) {
726 m_currentIndex = newIndex;
727 updateCurrentAction(
true);
731void QDesignerMenuBar::moveNext(
bool ctrl)
733 const bool swapped = ctrl && swapActions(m_currentIndex + 1, m_currentIndex);
734 const int newIndex = qMin(actions().size() - 1, m_currentIndex + 1);
735 if (swapped || newIndex != m_currentIndex) {
736 m_currentIndex = newIndex;
737 updateCurrentAction(!ctrl);
741void QDesignerMenuBar::moveUp()
746void QDesignerMenuBar::moveDown()
751void QDesignerMenuBar::adjustSpecialActions()
753 removeAction(m_addMenu);
754 addAction(m_addMenu);
757void QDesignerMenuBar::hideMenu(
int index)
759 if (index < 0 && m_currentIndex >= 0)
760 index = m_currentIndex;
762 if (index < 0 || index >= realActionCount())
765 QAction *action = safeActionAt(index);
767 if (action && action->menu()) {
768 action->menu()->hide();
770 if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu())) {
771 menu->closeMenuChain();
776void QDesignerMenuBar::deleteMenu()
778 deleteMenuAction(currentAction());
781void QDesignerMenuBar::deleteMenuAction(QAction *action)
783 if (action && !qobject_cast<qdesigner_internal::SpecialMenuAction*>(action)) {
784 const int pos = actions().indexOf(action);
785 QAction *action_before =
nullptr;
787 action_before = safeActionAt(pos + 1);
789 QDesignerFormWindowInterface *fw = formWindow();
790 auto *cmd =
new qdesigner_internal::RemoveMenuActionCommand(fw);
791 cmd->init(action, action_before,
this,
this);
792 fw->commandHistory()->push(cmd);
796void QDesignerMenuBar::showMenu(
int index)
798 if (index < 0 && m_currentIndex >= 0)
799 index = m_currentIndex;
801 if (index < 0 || index >= realActionCount())
804 m_currentIndex = index;
805 QAction *action = currentAction();
807 if (action && action->menu()) {
808 if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) {
809 hideMenu(m_lastMenuActionIndex);
812 m_lastMenuActionIndex = index;
813 QMenu *menu = action->menu();
814 const QRect g = actionGeometry(action);
816 if (!menu->isVisible()) {
817 if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
818 menu->setWindowFlags(Qt::Popup);
820 if (layoutDirection() == Qt::LeftToRight) {
821 menu->move(mapToGlobal(g.bottomLeft()));
825 QPoint point = g.bottomRight() - QPoint(menu->width(), 0);
826 menu->move(mapToGlobal(point));
828 menu->setFocus(Qt::MouseFocusReason);
837QAction *QDesignerMenuBar::safeActionAt(
int index)
const
839 if (index < 0 || index >= actions().size())
842 return actions().at(index);
845bool QDesignerMenuBar::swapActions(
int a,
int b)
847 using namespace qdesigner_internal;
849 const int left = qMin(a, b);
850 int right = qMax(a, b);
852 QAction *action_a = safeActionAt(left);
853 QAction *action_b = safeActionAt(right);
855 if (action_a == action_b
858 || qobject_cast<SpecialMenuAction*>(action_a)
859 || qobject_cast<SpecialMenuAction*>(action_b))
862 right = qMin(right, realActionCount());
866 formWindow()->beginCommand(QApplication::translate(
"Command",
"Move action"));
868 QAction *action_b_before = safeActionAt(right + 1);
870 QDesignerFormWindowInterface *fw = formWindow();
871 auto *cmd1 =
new qdesigner_internal::RemoveActionFromCommand(fw);
872 cmd1->init(
this, action_b, action_b_before,
false);
873 fw->commandHistory()->push(cmd1);
875 QAction *action_a_before = safeActionAt(left + 1);
877 auto *cmd2 =
new qdesigner_internal::InsertActionIntoCommand(fw);
878 cmd2->init(
this, action_b, action_a_before,
false);
879 fw->commandHistory()->push(cmd2);
881 auto *cmd3 =
new qdesigner_internal::RemoveActionFromCommand(fw);
882 cmd3->init(
this, action_a, action_b,
false);
883 fw->commandHistory()->push(cmd3);
885 auto *cmd4 =
new qdesigner_internal::InsertActionIntoCommand(fw);
886 cmd4->init(
this, action_a, action_b_before,
true);
887 fw->commandHistory()->push(cmd4);
894void QDesignerMenuBar::keyPressEvent(QKeyEvent *event)
899void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event)
904void QDesignerMenuBar::updateCurrentAction(
bool selectAction)
906 using namespace qdesigner_internal;
913 QAction *action = currentAction();
914 if (!action || action == m_addMenu)
917 QMenu *menu = action->menu();
921 QDesignerObjectInspector *oi =
nullptr;
922 if (QDesignerFormWindowInterface *fw = formWindow())
923 oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
928 oi->clearSelection();
929 oi->selectObject(menu);
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.