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