16#include <QtDesigner/abstractformwindow.h>
17#include <QtDesigner/abstractformeditor.h>
18#include <QtDesigner/abstractwidgetfactory.h>
19#include <QtDesigner/qextensionmanager.h>
21#include <QtCore/qmimedata.h>
23#include <QtCore/qdebug.h>
25#include <QtWidgets/qapplication.h>
26#include <QtGui/qdrag.h>
27#include <QtWidgets/qlineedit.h>
28#include <QtGui/qpainter.h>
29#include <QtGui/qevent.h>
33using namespace Qt::StringLiterals;
35using ActionList = QList<QAction *>;
59QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) :
61 m_addMenu(
new qdesigner_internal::SpecialMenuAction(
this)),
62 m_editor(
new qdesigner_internal::MenuActionLineEdit(
this)),
63 m_promotionTaskMenu(
new qdesigner_internal::PromotionTaskMenu(
this, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget,
this))
65 setContextMenuPolicy(Qt::DefaultContextMenu);
69 setNativeMenuBar(
false);
71 m_addMenu->setText(tr(
"Type Here"));
75 italic.setItalic(
true);
76 m_addMenu->setFont(italic);
78 m_editor->setObjectName(u"__qt__passive_editor"_s);
80 connect(m_editor, &qdesigner_internal::MenuActionLineEdit::focusOut,
81 this, &QDesignerMenuBar::stopInlineEditing);
82 installEventFilter(
new qdesigner_internal::MenuBarEventFilter(
this));
85QDesignerMenuBar::~QDesignerMenuBar() =
default;
87void QDesignerMenuBar::paintEvent(QPaintEvent *event)
89 QMenuBar::paintEvent(event);
93 const auto &actionList = actions();
94 for (QAction *a : actionList) {
95 if (qobject_cast<qdesigner_internal::SpecialMenuAction*>(a)) {
96 const QRect g = actionGeometry(a);
97 QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
98 lg.setColorAt(0.0, Qt::transparent);
99 lg.setColorAt(0.7, QColor(0, 0, 0, 32));
100 lg.setColorAt(1.0, Qt::transparent);
106 QAction *action = currentAction();
108 if (m_dragging || !action)
112 const QRect g = actionGeometry(action);
113 QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1));
114 }
else if (action->menu() && action->menu()->isVisible()) {
115 const QRect g = actionGeometry(action);
116 p.drawRect(g.adjusted(1, 1, -1, -1));
120bool QDesignerMenuBar::handleEvent(QEvent *event)
125 switch (event->type()) {
126 case QEvent::MouseButtonDblClick:
127 return handleMouseDoubleClickEvent(
static_cast<QMouseEvent*>(event));
128 case QEvent::MouseButtonPress:
129 return handleMousePressEvent(
static_cast<QMouseEvent*>(event));
130 case QEvent::MouseButtonRelease:
131 return handleMouseReleaseEvent(
static_cast<QMouseEvent*>(event));
132 case QEvent::MouseMove:
133 return handleMouseMoveEvent(
static_cast<QMouseEvent*>(event));
134 case QEvent::ContextMenu:
135 return handleContextMenuEvent(
static_cast<QContextMenuEvent*>(event));
136 case QEvent::KeyPress:
137 return handleKeyPressEvent(
static_cast<QKeyEvent*>(event));
138 case QEvent::FocusIn:
139 case QEvent::FocusOut:
149bool QDesignerMenuBar::handleMouseDoubleClickEvent(QMouseEvent *event)
151 if (!rect().contains(event->position().toPoint()))
154 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
159 m_startPosition = QPoint();
161 m_currentIndex = actionIndexAt(
this, event->position().toPoint(), Qt::Horizontal);
162 if (m_currentIndex != -1) {
169bool QDesignerMenuBar::handleKeyPressEvent(QKeyEvent *e)
171 if (m_editor->isHidden()) {
175 if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
183 moveLeft(e->modifiers() & Qt::ControlModifier);
188 moveRight(e->modifiers() & Qt::ControlModifier);
205 case Qt::Key_PageDown:
206 m_currentIndex = actions().size() - 1;
217 case Qt::Key_Control:
224 if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
226 QApplication::sendEvent(m_editor, e);
238 case Qt::Key_Control:
244 if (!m_editor->text().isEmpty()) {
245 leaveEditMode(ForceAccept);
246 if (m_lastFocusWidget)
247 m_lastFocusWidget->setFocus();
268void QDesignerMenuBar::startDrag(
const QPoint &pos)
270 using namespace qdesigner_internal;
272 const int index = findAction(pos);
273 if (m_currentIndex == -1 || index >= realActionCount())
276 QAction *action = safeActionAt(index);
278 QDesignerFormWindowInterface *fw = formWindow();
279 auto *cmd =
new qdesigner_internal::RemoveActionFromCommand(fw);
280 cmd->init(
this, action, actions().at(index + 1));
281 fw->commandHistory()->push(cmd);
287 QDrag *drag =
new QDrag(
this);
288 drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
289 drag->setMimeData(
new ActionRepositoryMimeData(action, Qt::MoveAction));
291 const int old_index = m_currentIndex;
294 if (drag->exec(Qt::MoveAction) == Qt::IgnoreAction) {
295 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
296 cmd->init(
this, action, safeActionAt(index));
297 fw->commandHistory()->push(cmd);
299 m_currentIndex = old_index;
304bool QDesignerMenuBar::handleMousePressEvent(QMouseEvent *event)
306 m_startPosition = QPoint();
309 if (event->button() != Qt::LeftButton)
312 m_startPosition = event->position().toPoint();
313 const int newIndex = actionIndexAt(
this, m_startPosition, Qt::Horizontal);
314 const bool changed = newIndex != m_currentIndex;
315 m_currentIndex = newIndex;
316 updateCurrentAction(changed);
321bool QDesignerMenuBar::handleMouseReleaseEvent(QMouseEvent *event)
323 m_startPosition = QPoint();
325 if (event->button() != Qt::LeftButton)
329 m_currentIndex = actionIndexAt(
this, event->position().toPoint(), Qt::Horizontal);
330 if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount())
336bool QDesignerMenuBar::handleMouseMoveEvent(QMouseEvent *event)
338 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
341 if (m_startPosition.isNull())
344 const QPoint pos = mapFromGlobal(event->globalPosition().toPoint());
346 if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
349 const int index = actionIndexAt(
this, m_startPosition, Qt::Horizontal);
350 if (index < actions().size()) {
355 startDrag(m_startPosition);
356 m_startPosition = QPoint();
361ActionList QDesignerMenuBar::contextMenuActions()
363 using namespace qdesigner_internal;
366 if (QAction *action = safeActionAt(m_currentIndex)) {
367 if (!qobject_cast<SpecialMenuAction*>(action)) {
369 itemData.setValue(action);
371 QAction *remove_action =
new QAction(tr(
"Remove Menu '%1'").arg(action->menu()->objectName()),
nullptr);
372 remove_action->setData(itemData);
373 connect(remove_action, &QAction::triggered,
this, &QDesignerMenuBar::deleteMenu);
374 rc.push_back(remove_action);
375 QAction *sep =
new QAction(
nullptr);
376 sep->setSeparator(
true);
381 m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc);
383 QAction *remove_menubar =
new QAction(tr(
"Remove Menu Bar"),
nullptr);
384 connect(remove_menubar, &QAction::triggered,
this, &QDesignerMenuBar::slotRemoveMenuBar);
385 rc.push_back(remove_menubar);
389bool QDesignerMenuBar::handleContextMenuEvent(QContextMenuEvent *event)
393 m_currentIndex = actionIndexAt(
this, mapFromGlobal(event->globalPos()), Qt::Horizontal);
398 const ActionList al = contextMenuActions();
401 menu.exec(event->globalPos());
405void QDesignerMenuBar::slotRemoveMenuBar()
407 Q_ASSERT(formWindow() !=
nullptr);
409 QDesignerFormWindowInterface *fw = formWindow();
411 auto *cmd =
new qdesigner_internal::DeleteMenuBarCommand(fw);
413 fw->commandHistory()->push(cmd);
416void QDesignerMenuBar::stopInlineEditing()
418 if (!m_editor->isHidden()) {
419 leaveEditMode(Default);
425void QDesignerMenuBar::focusOutEvent(QFocusEvent *event)
427 QMenuBar::focusOutEvent(event);
430void QDesignerMenuBar::enterEditMode()
432 if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
437void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode)
439 using namespace qdesigner_internal;
441 m_editor->releaseKeyboard();
446 if (m_editor->text().isEmpty())
449 QAction *action =
nullptr;
451 QDesignerFormWindowInterface *fw = formWindow();
454 if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) {
455 action = safeActionAt(m_currentIndex);
456 fw->beginCommand(QApplication::translate(
"Command",
"Change Title"));
458 fw->beginCommand(QApplication::translate(
"Command",
"Insert Menu"));
459 const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), u"menu"_s);
460 QMenu *menu = qobject_cast<QMenu*>(fw->core()->widgetFactory()->createWidget(u"QMenu"_s,
this));
461 fw->core()->widgetFactory()->initialize(menu);
462 menu->setObjectName(niceObjectName);
463 menu->setTitle(tr(
"Menu"));
464 fw->ensureUniqueObjectName(menu);
465 action = menu->menuAction();
466 auto *cmd =
new qdesigner_internal::AddMenuActionCommand(fw);
467 cmd->init(action, m_addMenu,
this,
this);
468 fw->commandHistory()->push(cmd);
471 auto *cmd =
new qdesigner_internal::SetPropertyCommand(fw);
472 cmd->init(action, u"text"_s, m_editor->text());
473 fw->commandHistory()->push(cmd);
477void QDesignerMenuBar::showLineEdit()
479 QAction *action =
nullptr;
481 if (m_currentIndex >= 0 && m_currentIndex < realActionCount())
482 action = safeActionAt(m_currentIndex);
486 if (action->isSeparator())
491 m_lastFocusWidget = qApp->focusWidget();
494 const QString text = action != m_addMenu ? action->text() : QString();
496 m_editor->setText(text);
497 m_editor->selectAll();
498 m_editor->setGeometry(actionGeometry(action));
500 m_editor->activateWindow();
501 m_editor->setFocus();
502 m_editor->grabKeyboard();
507 switch (event->type()) {
508 case QEvent::KeyPress:
509 case QEvent::KeyRelease:
510 case QEvent::ContextMenu:
511 case QEvent::MouseMove:
512 case QEvent::MouseButtonPress:
513 case QEvent::MouseButtonRelease:
514 case QEvent::MouseButtonDblClick:
517 case QEvent::FocusIn:
518 case QEvent::FocusOut:
519 if (
auto *mb = qobject_cast<QDesignerMenuBar *>(object))
520 return mb->handleEvent(event);
522 case QEvent::Shortcut:
529 return QObject::eventFilter(object, event);
532int QDesignerMenuBar::findAction(
const QPoint &pos)
const
534 const int index = actionIndexAt(
this, pos, Qt::Horizontal);
536 return realActionCount();
541void QDesignerMenuBar::adjustIndicator(
const QPoint &pos)
543 const int index = findAction(pos);
544 QAction *action = safeActionAt(index);
545 Q_ASSERT(action !=
nullptr);
547 if (pos != QPoint(-1, -1)) {
548 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
549 if (!m || m->parentMenu()) {
550 m_currentIndex = index;
555 if (QDesignerActionProviderExtension *a = actionProvider()) {
556 a->adjustIndicator(pos);
560QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action)
const
563 if (!action || !qdesigner_internal::Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
567 return ActionDragOnSubMenu;
569 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
570 if (m && m->parentMenu())
571 return ActionDragOnSubMenu;
573 if (actions().contains(action))
574 return ActionDragOnSubMenu;
576 return AcceptActionDrag;
579void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event)
581 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
582 if (!d || d->actionList().isEmpty()) {
587 QAction *action = d->actionList().first();
588 switch (checkAction(action)) {
592 case ActionDragOnSubMenu:
596 case AcceptActionDrag:
599 adjustIndicator(event->position().toPoint());
604void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event)
606 auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
607 if (!d || d->actionList().isEmpty()) {
611 QAction *action = d->actionList().first();
613 switch (checkAction(action)) {
617 case ActionDragOnSubMenu:
619 showMenu(findAction(event->position().toPoint()));
621 case AcceptActionDrag:
623 adjustIndicator(event->position().toPoint());
628void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *)
632 adjustIndicator(QPoint(-1, -1));
635void QDesignerMenuBar::dropEvent(QDropEvent *event)
639 if (
auto *d = qobject_cast<
const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData())) {
641 QAction *action = d->actionList().first();
642 if (checkAction(action) == AcceptActionDrag) {
643 event->acceptProposedAction();
644 int index = findAction(event->position().toPoint());
645 index = qMin(index, actions().size() - 1);
647 QDesignerFormWindowInterface *fw = formWindow();
648 auto *cmd =
new qdesigner_internal::InsertActionIntoCommand(fw);
649 cmd->init(
this, action, safeActionAt(index));
650 fw->commandHistory()->push(cmd);
652 m_currentIndex = index;
654 adjustIndicator(QPoint(-1, -1));
661void QDesignerMenuBar::actionEvent(QActionEvent *event)
663 QMenuBar::actionEvent(event);
666QDesignerFormWindowInterface *QDesignerMenuBar::formWindow()
const
668 return QDesignerFormWindowInterface::findFormWindow(
const_cast<QDesignerMenuBar*>(
this));
671QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider()
673 if (QDesignerFormWindowInterface *fw = formWindow()) {
674 QDesignerFormEditorInterface *core = fw->core();
675 return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(),
this);
681QAction *QDesignerMenuBar::currentAction()
const
683 if (m_currentIndex < 0 || m_currentIndex >= actions().size())
686 return safeActionAt(m_currentIndex);
689int QDesignerMenuBar::realActionCount()
const
691 return actions().size() - 1;
694bool QDesignerMenuBar::dragging()
const
699void QDesignerMenuBar::moveLeft(
bool ctrl)
701 if (layoutDirection() == Qt::LeftToRight) {
708void QDesignerMenuBar::moveRight(
bool ctrl)
710 if (layoutDirection() == Qt::LeftToRight) {
717void QDesignerMenuBar::movePrevious(
bool ctrl)
719 const bool swapped = ctrl && swapActions(m_currentIndex, m_currentIndex - 1);
720 const int newIndex = qMax(0, m_currentIndex - 1);
722 if (swapped || newIndex != m_currentIndex) {
723 m_currentIndex = newIndex;
724 updateCurrentAction(
true);
728void QDesignerMenuBar::moveNext(
bool ctrl)
730 const bool swapped = ctrl && swapActions(m_currentIndex + 1, m_currentIndex);
731 const int newIndex = qMin(actions().size() - 1, m_currentIndex + 1);
732 if (swapped || newIndex != m_currentIndex) {
733 m_currentIndex = newIndex;
734 updateCurrentAction(!ctrl);
738void QDesignerMenuBar::moveUp()
743void QDesignerMenuBar::moveDown()
748void QDesignerMenuBar::adjustSpecialActions()
750 removeAction(m_addMenu);
751 addAction(m_addMenu);
754void QDesignerMenuBar::hideMenu(
int index)
756 if (index < 0 && m_currentIndex >= 0)
757 index = m_currentIndex;
759 if (index < 0 || index >= realActionCount())
762 QAction *action = safeActionAt(index);
764 if (action && action->menu()) {
765 action->menu()->hide();
767 if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu())) {
768 menu->closeMenuChain();
773void QDesignerMenuBar::deleteMenu()
775 deleteMenuAction(currentAction());
778void QDesignerMenuBar::deleteMenuAction(QAction *action)
780 if (action && !qobject_cast<qdesigner_internal::SpecialMenuAction*>(action)) {
781 const int pos = actions().indexOf(action);
782 QAction *action_before =
nullptr;
784 action_before = safeActionAt(pos + 1);
786 QDesignerFormWindowInterface *fw = formWindow();
787 auto *cmd =
new qdesigner_internal::RemoveMenuActionCommand(fw);
788 cmd->init(action, action_before,
this,
this);
789 fw->commandHistory()->push(cmd);
793void QDesignerMenuBar::showMenu(
int index)
795 if (index < 0 && m_currentIndex >= 0)
796 index = m_currentIndex;
798 if (index < 0 || index >= realActionCount())
801 m_currentIndex = index;
802 QAction *action = currentAction();
804 if (action && action->menu()) {
805 if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) {
806 hideMenu(m_lastMenuActionIndex);
809 m_lastMenuActionIndex = index;
810 QMenu *menu = action->menu();
811 const QRect g = actionGeometry(action);
813 if (!menu->isVisible()) {
814 if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
815 menu->setWindowFlags(Qt::Popup);
817 if (layoutDirection() == Qt::LeftToRight) {
818 menu->move(mapToGlobal(g.bottomLeft()));
822 QPoint point = g.bottomRight() - QPoint(menu->width(), 0);
823 menu->move(mapToGlobal(point));
825 menu->setFocus(Qt::MouseFocusReason);
834QAction *QDesignerMenuBar::safeActionAt(
int index)
const
836 if (index < 0 || index >= actions().size())
839 return actions().at(index);
842bool QDesignerMenuBar::swapActions(
int a,
int b)
844 using namespace qdesigner_internal;
846 const int left = qMin(a, b);
847 int right = qMax(a, b);
849 QAction *action_a = safeActionAt(left);
850 QAction *action_b = safeActionAt(right);
852 if (action_a == action_b
855 || qobject_cast<SpecialMenuAction*>(action_a)
856 || qobject_cast<SpecialMenuAction*>(action_b))
859 right = qMin(right, realActionCount());
863 formWindow()->beginCommand(QApplication::translate(
"Command",
"Move action"));
865 QAction *action_b_before = safeActionAt(right + 1);
867 QDesignerFormWindowInterface *fw = formWindow();
868 auto *cmd1 =
new qdesigner_internal::RemoveActionFromCommand(fw);
869 cmd1->init(
this, action_b, action_b_before,
false);
870 fw->commandHistory()->push(cmd1);
872 QAction *action_a_before = safeActionAt(left + 1);
874 auto *cmd2 =
new qdesigner_internal::InsertActionIntoCommand(fw);
875 cmd2->init(
this, action_b, action_a_before,
false);
876 fw->commandHistory()->push(cmd2);
878 auto *cmd3 =
new qdesigner_internal::RemoveActionFromCommand(fw);
879 cmd3->init(
this, action_a, action_b,
false);
880 fw->commandHistory()->push(cmd3);
882 auto *cmd4 =
new qdesigner_internal::InsertActionIntoCommand(fw);
883 cmd4->init(
this, action_a, action_b_before,
true);
884 fw->commandHistory()->push(cmd4);
891void QDesignerMenuBar::keyPressEvent(QKeyEvent *event)
896void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event)
901void QDesignerMenuBar::updateCurrentAction(
bool selectAction)
903 using namespace qdesigner_internal;
910 QAction *action = currentAction();
911 if (!action || action == m_addMenu)
914 QMenu *menu = action->menu();
918 QDesignerObjectInspector *oi =
nullptr;
919 if (QDesignerFormWindowInterface *fw = formWindow())
920 oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
925 oi->clearSelection();
926 oi->selectObject(menu);
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.