source: trunk/tools/designer/src/lib/shared/qdesigner_menubar.cpp@ 944

Last change on this file since 944 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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