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