Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdesigner_menubar.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
11#include "actioneditor_p.h"
16
17#include <QtDesigner/abstractformwindow.h>
18#include <QtDesigner/abstractformeditor.h>
19#include <QtDesigner/abstractwidgetfactory.h>
20#include <QtDesigner/qextensionmanager.h>
21
22#include <QtCore/qmimedata.h>
23
24#include <QtCore/qdebug.h>
25
26#include <QtWidgets/qapplication.h>
27#include <QtGui/qdrag.h>
28#include <QtWidgets/qlineedit.h>
29#include <QtGui/qpainter.h>
30#include <QtGui/qevent.h>
31
33
34using namespace Qt::StringLiterals;
35
36using ActionList = QList<QAction *>;
37
38namespace qdesigner_internal
39{
40
41/////////////////////////////////////////////////////////////////////////////////////////////////////////
42SpecialMenuAction::SpecialMenuAction(QObject *parent)
43 : QAction(parent)
44{
45}
46
48
50{
51public:
52 using QObject::QObject;
53
54 bool eventFilter(QObject *object, QEvent *event) override;
55};
56
57} // namespace qdesigner_internal
58
59/////////////////////////////////////////////////////////////////////////////////////////////////////////
60QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) :
61 QMenuBar(parent),
62 m_addMenu(new qdesigner_internal::SpecialMenuAction(this)),
63 m_editor(new qdesigner_internal::MenuActionLineEdit(this)),
64 m_promotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(this, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
65{
66 setContextMenuPolicy(Qt::DefaultContextMenu);
67
68 setAcceptDrops(true); // ### fake
69 // Fake property: Keep the menu bar editable in the form even if a native menu bar is used.
70 setNativeMenuBar(false);
71
72 m_addMenu->setText(tr("Type Here"));
73 addAction(m_addMenu);
74
75 QFont italic;
76 italic.setItalic(true);
77 m_addMenu->setFont(italic);
78
79 m_editor->setObjectName(u"__qt__passive_editor"_s);
80 m_editor->hide();
81 connect(m_editor, &qdesigner_internal::MenuActionLineEdit::focusOut,
82 this, &QDesignerMenuBar::stopInlineEditing);
83 installEventFilter(new qdesigner_internal::MenuBarEventFilter(this));
84}
85
86QDesignerMenuBar::~QDesignerMenuBar() = default;
87
88void QDesignerMenuBar::paintEvent(QPaintEvent *event)
89{
90 QMenuBar::paintEvent(event);
91
92 QPainter p(this);
93
94 const auto &actionList = actions();
95 for (QAction *a : actionList) {
96 if (qobject_cast<qdesigner_internal::SpecialMenuAction*>(a)) {
97 const QRect g = actionGeometry(a);
98 QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom());
99 lg.setColorAt(0.0, Qt::transparent);
100 lg.setColorAt(0.7, QColor(0, 0, 0, 32));
101 lg.setColorAt(1.0, Qt::transparent);
102
103 p.fillRect(g, lg);
104 }
105 }
106
107 QAction *action = currentAction();
108
109 if (m_dragging || !action)
110 return;
111
112 if (hasFocus()) {
113 const QRect g = actionGeometry(action);
114 QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1));
115 } else if (action->menu() && action->menu()->isVisible()) {
116 const QRect g = actionGeometry(action);
117 p.drawRect(g.adjusted(1, 1, -1, -1));
118 }
119}
120
121bool QDesignerMenuBar::handleEvent(QEvent *event)
122{
123 if (!formWindow())
124 return false;
125
126 switch (event->type()) {
127 case QEvent::MouseButtonDblClick:
128 return handleMouseDoubleClickEvent(static_cast<QMouseEvent*>(event));
129 case QEvent::MouseButtonPress:
130 return handleMousePressEvent(static_cast<QMouseEvent*>(event));
131 case QEvent::MouseButtonRelease:
132 return handleMouseReleaseEvent(static_cast<QMouseEvent*>(event));
133 case QEvent::MouseMove:
134 return handleMouseMoveEvent(static_cast<QMouseEvent*>(event));
135 case QEvent::ContextMenu:
136 return handleContextMenuEvent(static_cast<QContextMenuEvent*>(event));
137 case QEvent::KeyPress:
138 return handleKeyPressEvent(static_cast<QKeyEvent*>(event));
139 case QEvent::FocusIn:
140 case QEvent::FocusOut:
141 update();
142 break;
143 default:
144 break;
145 }
146
147 return true;
148}
149
150bool QDesignerMenuBar::handleMouseDoubleClickEvent(QMouseEvent *event)
151{
152 if (!rect().contains(event->position().toPoint()))
153 return true;
154
155 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
156 return true;
157
158 event->accept();
159
160 m_startPosition = QPoint();
161
162 m_currentIndex = actionIndexAt(this, event->position().toPoint(), Qt::Horizontal);
163 if (m_currentIndex != -1) {
164 showLineEdit();
165 }
166
167 return true;
168}
169
170bool QDesignerMenuBar::handleKeyPressEvent(QKeyEvent *e)
171{
172 if (m_editor->isHidden()) { // In navigation mode
173 switch (e->key()) {
174
175 case Qt::Key_Delete:
176 if (m_currentIndex == -1 || m_currentIndex >= realActionCount())
177 break;
178 hideMenu();
179 deleteMenu();
180 break;
181
182 case Qt::Key_Left:
183 e->accept();
184 moveLeft(e->modifiers() & Qt::ControlModifier);
185 return true;
186
187 case Qt::Key_Right:
188 e->accept();
189 moveRight(e->modifiers() & Qt::ControlModifier);
190 return true; // no update
191
192 case Qt::Key_Up:
193 e->accept();
194 moveUp();
195 return true;
196
197 case Qt::Key_Down:
198 e->accept();
199 moveDown();
200 return true;
201
202 case Qt::Key_PageUp:
203 m_currentIndex = 0;
204 break;
205
206 case Qt::Key_PageDown:
207 m_currentIndex = actions().size() - 1;
208 break;
209
210 case Qt::Key_Enter:
211 case Qt::Key_Return:
212 e->accept();
213 enterEditMode();
214 return true; // no update
215
216 case Qt::Key_Alt:
217 case Qt::Key_Shift:
218 case Qt::Key_Control:
219 case Qt::Key_Escape:
220 e->ignore();
221 setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed
222 return true; // no update
223
224 default:
225 if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) {
226 showLineEdit();
227 QApplication::sendEvent(m_editor, e);
228 e->accept();
229 } else {
230 e->ignore();
231 }
232 return true;
233 }
234 } else { // In edit mode
235 switch (e->key()) {
236 default:
237 return false;
238
239 case Qt::Key_Control:
240 e->ignore();
241 return true;
242
243 case Qt::Key_Enter:
244 case Qt::Key_Return:
245 if (!m_editor->text().isEmpty()) {
246 leaveEditMode(ForceAccept);
247 if (m_lastFocusWidget)
248 m_lastFocusWidget->setFocus();
249
250 m_editor->hide();
251 showMenu();
252 break;
253 }
254 Q_FALLTHROUGH();
255
256 case Qt::Key_Escape:
257 update();
258 setFocus();
259 break;
260 }
261 }
262
263 e->accept();
264 update();
265
266 return true;
267}
268
269void QDesignerMenuBar::startDrag(const QPoint &pos)
270{
271 using namespace qdesigner_internal;
272
273 const int index = findAction(pos);
274 if (m_currentIndex == -1 || index >= realActionCount())
275 return;
276
277 QAction *action = safeActionAt(index);
278
279 QDesignerFormWindowInterface *fw = formWindow();
280 auto *cmd = new qdesigner_internal::RemoveActionFromCommand(fw);
281 cmd->init(this, action, actions().at(index + 1));
282 fw->commandHistory()->push(cmd);
283
284 adjustSize();
285
286 hideMenu(index);
287
288 QDrag *drag = new QDrag(this);
289 drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action));
290 drag->setMimeData(new ActionRepositoryMimeData(action, Qt::MoveAction));
291
292 const int old_index = m_currentIndex;
293 m_currentIndex = -1;
294
295 if (drag->exec(Qt::MoveAction) == Qt::IgnoreAction) {
296 auto *cmd = new qdesigner_internal::InsertActionIntoCommand(fw);
297 cmd->init(this, action, safeActionAt(index));
298 fw->commandHistory()->push(cmd);
299
300 m_currentIndex = old_index;
301 adjustSize();
302 }
303}
304
305bool QDesignerMenuBar::handleMousePressEvent(QMouseEvent *event)
306{
307 m_startPosition = QPoint();
308 event->accept();
309
310 if (event->button() != Qt::LeftButton)
311 return true;
312
313 m_startPosition = event->position().toPoint();
314 const int newIndex = actionIndexAt(this, m_startPosition, Qt::Horizontal);
315 const bool changed = newIndex != m_currentIndex;
316 m_currentIndex = newIndex;
317 updateCurrentAction(changed);
318
319 return true;
320}
321
322bool QDesignerMenuBar::handleMouseReleaseEvent(QMouseEvent *event)
323{
324 m_startPosition = QPoint();
325
326 if (event->button() != Qt::LeftButton)
327 return true;
328
329 event->accept();
330 m_currentIndex = actionIndexAt(this, event->position().toPoint(), Qt::Horizontal);
331 if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount())
332 showMenu();
333
334 return true;
335}
336
337bool QDesignerMenuBar::handleMouseMoveEvent(QMouseEvent *event)
338{
339 if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton)
340 return true;
341
342 if (m_startPosition.isNull())
343 return true;
344
345 const QPoint pos = mapFromGlobal(event->globalPosition().toPoint());
346
347 if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance())
348 return true;
349
350 const int index = actionIndexAt(this, m_startPosition, Qt::Horizontal);
351 if (index < actions().size()) {
352 hideMenu(index);
353 update();
354 }
355
356 startDrag(m_startPosition);
357 m_startPosition = QPoint();
358
359 return true;
360}
361
362ActionList QDesignerMenuBar::contextMenuActions()
363{
364 using namespace qdesigner_internal;
365
366 ActionList rc;
367 if (QAction *action = safeActionAt(m_currentIndex)) {
368 if (!qobject_cast<SpecialMenuAction*>(action)) {
369 QVariant itemData;
370 itemData.setValue(action);
371
372 QAction *remove_action = new QAction(tr("Remove Menu '%1'").arg(action->menu()->objectName()), nullptr);
373 remove_action->setData(itemData);
374 connect(remove_action, &QAction::triggered, this, &QDesignerMenuBar::deleteMenu);
375 rc.push_back(remove_action);
376 QAction *sep = new QAction(nullptr);
377 sep->setSeparator(true);
378 rc.push_back(sep);
379 }
380 }
381
382 m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc);
383
384 QAction *remove_menubar = new QAction(tr("Remove Menu Bar"), nullptr);
385 connect(remove_menubar, &QAction::triggered, this, &QDesignerMenuBar::slotRemoveMenuBar);
386 rc.push_back(remove_menubar);
387 return rc;
388}
389
390bool QDesignerMenuBar::handleContextMenuEvent(QContextMenuEvent *event)
391{
392 event->accept();
393
394 m_currentIndex = actionIndexAt(this, mapFromGlobal(event->globalPos()), Qt::Horizontal);
395
396 update();
397
398 QMenu menu;
399 const ActionList al = contextMenuActions();
400 for (auto *a : al)
401 menu.addAction(a);
402 menu.exec(event->globalPos());
403 return true;
404}
405
406void QDesignerMenuBar::slotRemoveMenuBar()
407{
408 Q_ASSERT(formWindow() != nullptr);
409
410 QDesignerFormWindowInterface *fw = formWindow();
411
412 auto *cmd = new qdesigner_internal::DeleteMenuBarCommand(fw);
413 cmd->init(this);
414 fw->commandHistory()->push(cmd);
415}
416
417void QDesignerMenuBar::stopInlineEditing()
418{
419 if (!m_editor->isHidden()) {
420 leaveEditMode(Default);
421 m_editor->hide();
422 update();
423 }
424}
425
426void QDesignerMenuBar::focusOutEvent(QFocusEvent *event)
427{
428 QMenuBar::focusOutEvent(event);
429}
430
431void QDesignerMenuBar::enterEditMode()
432{
433 if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) {
434 showLineEdit();
435 }
436}
437
438void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode)
439{
440 using namespace qdesigner_internal;
441
442 m_editor->releaseKeyboard();
443
444 if (mode == Default)
445 return;
446
447 if (m_editor->text().isEmpty())
448 return;
449
450 QAction *action = nullptr;
451
452 QDesignerFormWindowInterface *fw = formWindow();
453 Q_ASSERT(fw);
454
455 if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) {
456 action = safeActionAt(m_currentIndex);
457 fw->beginCommand(QApplication::translate("Command", "Change Title"));
458 } else {
459 fw->beginCommand(QApplication::translate("Command", "Insert Menu"));
460 const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), u"menu"_s);
461 QMenu *menu = qobject_cast<QMenu*>(fw->core()->widgetFactory()->createWidget(u"QMenu"_s, this));
462 fw->core()->widgetFactory()->initialize(menu);
463 menu->setObjectName(niceObjectName);
464 menu->setTitle(tr("Menu"));
465 fw->ensureUniqueObjectName(menu);
466 action = menu->menuAction();
467 auto *cmd = new qdesigner_internal::AddMenuActionCommand(fw);
468 cmd->init(action, m_addMenu, this, this);
469 fw->commandHistory()->push(cmd);
470 }
471
472 auto *cmd = new qdesigner_internal::SetPropertyCommand(fw);
473 cmd->init(action, u"text"_s, m_editor->text());
474 fw->commandHistory()->push(cmd);
475 fw->endCommand();
476}
477
478void QDesignerMenuBar::showLineEdit()
479{
480 QAction *action = nullptr;
481
482 if (m_currentIndex >= 0 && m_currentIndex < realActionCount())
483 action = safeActionAt(m_currentIndex);
484 else
485 action = m_addMenu;
486
487 if (action->isSeparator())
488 return;
489
490 // hideMenu();
491
492 m_lastFocusWidget = qApp->focusWidget();
493
494 // open edit field for item name
495 const QString text = action != m_addMenu ? action->text() : QString();
496
497 m_editor->setText(text);
498 m_editor->selectAll();
499 m_editor->setGeometry(actionGeometry(action));
500 m_editor->show();
501 m_editor->activateWindow();
502 m_editor->setFocus();
503 m_editor->grabKeyboard();
504}
505
506bool qdesigner_internal::MenuBarEventFilter::eventFilter(QObject *object, QEvent *event)
507{
508 switch (event->type()) {
509 case QEvent::KeyPress:
510 case QEvent::KeyRelease:
511 case QEvent::ContextMenu:
512 case QEvent::MouseMove:
513 case QEvent::MouseButtonPress:
514 case QEvent::MouseButtonRelease:
515 case QEvent::MouseButtonDblClick:
516 case QEvent::Enter:
517 case QEvent::Leave:
518 case QEvent::FocusIn:
519 case QEvent::FocusOut:
520 if (auto *mb = qobject_cast<QDesignerMenuBar *>(object))
521 return mb->handleEvent(event);
522 break;
523 case QEvent::Shortcut:
524 event->accept();
525 return true;
526 default:
527 break;
528
529 }
530 return QObject::eventFilter(object, event);
531};
532
533int QDesignerMenuBar::findAction(const QPoint &pos) const
534{
535 const int index = actionIndexAt(this, pos, Qt::Horizontal);
536 if (index == -1)
537 return realActionCount();
538
539 return index;
540}
541
542void QDesignerMenuBar::adjustIndicator(const QPoint &pos)
543{
544 const int index = findAction(pos);
545 QAction *action = safeActionAt(index);
546 Q_ASSERT(action != nullptr);
547
548 if (pos != QPoint(-1, -1)) {
549 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
550 if (!m || m->parentMenu()) {
551 m_currentIndex = index;
552 showMenu(index);
553 }
554 }
555
556 if (QDesignerActionProviderExtension *a = actionProvider()) {
557 a->adjustIndicator(pos);
558 }
559}
560
561QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action) const
562{
563 // action belongs to another form
564 if (!action || !qdesigner_internal::Utils::isObjectAncestorOf(formWindow()->mainContainer(), action))
565 return NoActionDrag;
566
567 if (!action->menu())
568 return ActionDragOnSubMenu; // simple action only on sub menus
569
570 QDesignerMenu *m = qobject_cast<QDesignerMenu*>(action->menu());
571 if (m && m->parentMenu())
572 return ActionDragOnSubMenu; // it looks like a submenu
573
574 if (actions().contains(action))
575 return ActionDragOnSubMenu; // we already have the action in the menubar
576
577 return AcceptActionDrag;
578}
579
580void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event)
581{
582 auto *d = qobject_cast<const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
583 if (!d || d->actionList().isEmpty()) {
584 event->ignore();
585 return;
586 }
587
588 QAction *action = d->actionList().first();
589 switch (checkAction(action)) {
590 case NoActionDrag:
591 event->ignore();
592 break;
593 case ActionDragOnSubMenu:
594 m_dragging = true;
595 d->accept(event);
596 break;
597 case AcceptActionDrag:
598 m_dragging = true;
599 d->accept(event);
600 adjustIndicator(event->position().toPoint());
601 break;
602 }
603}
604
605void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event)
606{
607 auto *d = qobject_cast<const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData());
608 if (!d || d->actionList().isEmpty()) {
609 event->ignore();
610 return;
611 }
612 QAction *action = d->actionList().first();
613
614 switch (checkAction(action)) {
615 case NoActionDrag:
616 event->ignore();
617 break;
618 case ActionDragOnSubMenu:
619 event->ignore();
620 showMenu(findAction(event->position().toPoint()));
621 break;
622 case AcceptActionDrag:
623 d->accept(event);
624 adjustIndicator(event->position().toPoint());
625 break;
626 }
627}
628
629void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *)
630{
631 m_dragging = false;
632
633 adjustIndicator(QPoint(-1, -1));
634}
635
636void QDesignerMenuBar::dropEvent(QDropEvent *event)
637{
638 m_dragging = false;
639
640 if (auto *d = qobject_cast<const qdesigner_internal::ActionRepositoryMimeData*>(event->mimeData())) {
641
642 QAction *action = d->actionList().first();
643 if (checkAction(action) == AcceptActionDrag) {
644 event->acceptProposedAction();
645 int index = findAction(event->position().toPoint());
646 index = qMin(index, actions().size() - 1);
647
648 QDesignerFormWindowInterface *fw = formWindow();
649 auto *cmd = new qdesigner_internal::InsertActionIntoCommand(fw);
650 cmd->init(this, action, safeActionAt(index));
651 fw->commandHistory()->push(cmd);
652
653 m_currentIndex = index;
654 update();
655 adjustIndicator(QPoint(-1, -1));
656 return;
657 }
658 }
659 event->ignore();
660}
661
662void QDesignerMenuBar::actionEvent(QActionEvent *event)
663{
664 QMenuBar::actionEvent(event);
665}
666
667QDesignerFormWindowInterface *QDesignerMenuBar::formWindow() const
668{
669 return QDesignerFormWindowInterface::findFormWindow(const_cast<QDesignerMenuBar*>(this));
670}
671
672QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider()
673{
674 if (QDesignerFormWindowInterface *fw = formWindow()) {
675 QDesignerFormEditorInterface *core = fw->core();
676 return qt_extension<QDesignerActionProviderExtension*>(core->extensionManager(), this);
677 }
678
679 return nullptr;
680}
681
682QAction *QDesignerMenuBar::currentAction() const
683{
684 if (m_currentIndex < 0 || m_currentIndex >= actions().size())
685 return nullptr;
686
687 return safeActionAt(m_currentIndex);
688}
689
690int QDesignerMenuBar::realActionCount() const
691{
692 return actions().size() - 1; // 1 fake actions
693}
694
695bool QDesignerMenuBar::dragging() const
696{
697 return m_dragging;
698}
699
700void QDesignerMenuBar::moveLeft(bool ctrl)
701{
702 if (layoutDirection() == Qt::LeftToRight) {
703 movePrevious(ctrl);
704 } else {
705 moveNext(ctrl);
706 }
707}
708
709void QDesignerMenuBar::moveRight(bool ctrl)
710{
711 if (layoutDirection() == Qt::LeftToRight) {
712 moveNext(ctrl);
713 } else {
714 movePrevious(ctrl);
715 }
716}
717
718void QDesignerMenuBar::movePrevious(bool ctrl)
719{
720 const bool swapped = ctrl && swapActions(m_currentIndex, m_currentIndex - 1);
721 const int newIndex = qMax(0, m_currentIndex - 1);
722 // Always re-select, swapping destroys order
723 if (swapped || newIndex != m_currentIndex) {
724 m_currentIndex = newIndex;
725 updateCurrentAction(true);
726 }
727}
728
729void QDesignerMenuBar::moveNext(bool ctrl)
730{
731 const bool swapped = ctrl && swapActions(m_currentIndex + 1, m_currentIndex);
732 const int newIndex = qMin(actions().size() - 1, m_currentIndex + 1);
733 if (swapped || newIndex != m_currentIndex) {
734 m_currentIndex = newIndex;
735 updateCurrentAction(!ctrl);
736 }
737}
738
739void QDesignerMenuBar::moveUp()
740{
741 update();
742}
743
744void QDesignerMenuBar::moveDown()
745{
746 showMenu();
747}
748
749void QDesignerMenuBar::adjustSpecialActions()
750{
751 removeAction(m_addMenu);
752 addAction(m_addMenu);
753}
754
755void QDesignerMenuBar::hideMenu(int index)
756{
757 if (index < 0 && m_currentIndex >= 0)
758 index = m_currentIndex;
759
760 if (index < 0 || index >= realActionCount())
761 return;
762
763 QAction *action = safeActionAt(index);
764
765 if (action && action->menu()) {
766 action->menu()->hide();
767
768 if (QDesignerMenu *menu = qobject_cast<QDesignerMenu*>(action->menu())) {
769 menu->closeMenuChain();
770 }
771 }
772}
773
774void QDesignerMenuBar::deleteMenu()
775{
776 deleteMenuAction(currentAction());
777}
778
779void QDesignerMenuBar::deleteMenuAction(QAction *action)
780{
781 if (action && !qobject_cast<qdesigner_internal::SpecialMenuAction*>(action)) {
782 const int pos = actions().indexOf(action);
783 QAction *action_before = nullptr;
784 if (pos != -1)
785 action_before = safeActionAt(pos + 1);
786
787 QDesignerFormWindowInterface *fw = formWindow();
788 auto *cmd = new qdesigner_internal::RemoveMenuActionCommand(fw);
789 cmd->init(action, action_before, this, this);
790 fw->commandHistory()->push(cmd);
791 }
792}
793
794void QDesignerMenuBar::showMenu(int index)
795{
796 if (index < 0 && m_currentIndex >= 0)
797 index = m_currentIndex;
798
799 if (index < 0 || index >= realActionCount())
800 return;
801
802 m_currentIndex = index;
803 QAction *action = currentAction();
804
805 if (action && action->menu()) {
806 if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) {
807 hideMenu(m_lastMenuActionIndex);
808 }
809
810 m_lastMenuActionIndex = index;
811 QMenu *menu = action->menu();
812 const QRect g = actionGeometry(action);
813
814 if (!menu->isVisible()) {
815 if ((menu->windowFlags() & Qt::Popup) != Qt::Popup)
816 menu->setWindowFlags(Qt::Popup);
817 menu->adjustSize();
818 if (layoutDirection() == Qt::LeftToRight) {
819 menu->move(mapToGlobal(g.bottomLeft()));
820 } else {
821 // The position is not initially correct due to the unknown width,
822 // causing it to overlap a bit the first time it is invoked.
823 QPoint point = g.bottomRight() - QPoint(menu->width(), 0);
824 menu->move(mapToGlobal(point));
825 }
826 menu->setFocus(Qt::MouseFocusReason);
827 menu->raise();
828 menu->show();
829 } else {
830 menu->raise();
831 }
832 }
833}
834
835QAction *QDesignerMenuBar::safeActionAt(int index) const
836{
837 if (index < 0 || index >= actions().size())
838 return nullptr;
839
840 return actions().at(index);
841}
842
843bool QDesignerMenuBar::swapActions(int a, int b)
844{
845 using namespace qdesigner_internal;
846
847 const int left = qMin(a, b);
848 int right = qMax(a, b);
849
850 QAction *action_a = safeActionAt(left);
851 QAction *action_b = safeActionAt(right);
852
853 if (action_a == action_b
854 || !action_a
855 || !action_b
856 || qobject_cast<SpecialMenuAction*>(action_a)
857 || qobject_cast<SpecialMenuAction*>(action_b))
858 return false; // nothing to do
859
860 right = qMin(right, realActionCount());
861 if (right < 0)
862 return false; // nothing to do
863
864 formWindow()->beginCommand(QApplication::translate("Command", "Move action"));
865
866 QAction *action_b_before = safeActionAt(right + 1);
867
868 QDesignerFormWindowInterface *fw = formWindow();
869 auto *cmd1 = new qdesigner_internal::RemoveActionFromCommand(fw);
870 cmd1->init(this, action_b, action_b_before, false);
871 fw->commandHistory()->push(cmd1);
872
873 QAction *action_a_before = safeActionAt(left + 1);
874
875 auto *cmd2 = new qdesigner_internal::InsertActionIntoCommand(fw);
876 cmd2->init(this, action_b, action_a_before, false);
877 fw->commandHistory()->push(cmd2);
878
879 auto *cmd3 = new qdesigner_internal::RemoveActionFromCommand(fw);
880 cmd3->init(this, action_a, action_b, false);
881 fw->commandHistory()->push(cmd3);
882
883 auto *cmd4 = new qdesigner_internal::InsertActionIntoCommand(fw);
884 cmd4->init(this, action_a, action_b_before, true);
885 fw->commandHistory()->push(cmd4);
886
887 fw->endCommand();
888
889 return true;
890}
891
892void QDesignerMenuBar::keyPressEvent(QKeyEvent *event)
893{
894 event->ignore();
895}
896
897void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event)
898{
899 event->ignore();
900}
901
902void QDesignerMenuBar::updateCurrentAction(bool selectAction)
903{
904 using namespace qdesigner_internal;
905
906 update();
907
908 if (!selectAction)
909 return;
910
911 QAction *action = currentAction();
912 if (!action || action == m_addMenu)
913 return;
914
915 QMenu *menu = action->menu();
916 if (!menu)
917 return;
918
919 QDesignerObjectInspector *oi = nullptr;
920 if (QDesignerFormWindowInterface *fw = formWindow())
921 oi = qobject_cast<QDesignerObjectInspector *>(fw->core()->objectInspector());
922
923 if (!oi)
924 return;
925
926 oi->clearSelection();
927 oi->selectObject(menu);
928}
929
930QT_END_NAMESPACE
bool eventFilter(QObject *object, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.