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