source: trunk/src/gui/widgets/qmenubar.cpp@ 938

Last change on this file since 938 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: 71.1 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 QtGui module 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 <qmenubar.h>
43
44#include <qstyle.h>
45#include <qlayout.h>
46#include <qapplication.h>
47#include <qdesktopwidget.h>
48#ifndef QT_NO_ACCESSIBILITY
49# include <qaccessible.h>
50#endif
51#include <qpainter.h>
52#include <qstylepainter.h>
53#include <qevent.h>
54#include <qmainwindow.h>
55#include <qtoolbar.h>
56#include <qtoolbutton.h>
57#include <qwhatsthis.h>
58
59#ifndef QT_NO_MENUBAR
60
61#ifdef QT3_SUPPORT
62#include <private/qaction_p.h>
63#include <qmenudata.h>
64#endif
65
66#include "qmenu_p.h"
67#include "qmenubar_p.h"
68#include "qdebug.h"
69
70#ifdef Q_WS_WINCE
71extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp
72#endif
73
74#ifdef QT_SOFTKEYS_ENABLED
75#include <private/qsoftkeymanager_p.h>
76#endif
77
78QT_BEGIN_NAMESPACE
79
80class QMenuBarExtension : public QToolButton
81{
82public:
83 explicit QMenuBarExtension(QWidget *parent);
84
85 QSize sizeHint() const;
86 void paintEvent(QPaintEvent *);
87};
88
89QMenuBarExtension::QMenuBarExtension(QWidget *parent)
90 : QToolButton(parent)
91{
92 setObjectName(QLatin1String("qt_menubar_ext_button"));
93 setAutoRaise(true);
94#ifndef QT_NO_MENU
95 setPopupMode(QToolButton::InstantPopup);
96#endif
97 setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, 0, parentWidget()));
98}
99
100void QMenuBarExtension::paintEvent(QPaintEvent *)
101{
102 QStylePainter p(this);
103 QStyleOptionToolButton opt;
104 initStyleOption(&opt);
105 // We do not need to draw both extension arrows
106 opt.features &= ~QStyleOptionToolButton::HasMenu;
107 p.drawComplexControl(QStyle::CC_ToolButton, opt);
108}
109
110
111QSize QMenuBarExtension::sizeHint() const
112{
113 int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, 0, parentWidget());
114 return QSize(ext, ext);
115}
116
117
118/*!
119 \internal
120*/
121QAction *QMenuBarPrivate::actionAt(QPoint p) const
122{
123 for(int i = 0; i < actions.size(); ++i) {
124 if(actionRect(actions.at(i)).contains(p))
125 return actions.at(i);
126 }
127 return 0;
128}
129
130QRect QMenuBarPrivate::menuRect(bool extVisible) const
131{
132 Q_Q(const QMenuBar);
133
134 int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
135 QRect result = q->rect();
136 result.adjust(hmargin, 0, -hmargin, 0);
137
138 if (extVisible) {
139 if (q->isRightToLeft())
140 result.setLeft(result.left() + extension->sizeHint().width());
141 else
142 result.setWidth(result.width() - extension->sizeHint().width());
143 }
144
145 if (leftWidget && leftWidget->isVisible()) {
146 QSize sz = leftWidget->sizeHint();
147 if (q->isRightToLeft())
148 result.setRight(result.right() - sz.width());
149 else
150 result.setLeft(result.left() + sz.width());
151 }
152
153 if (rightWidget && rightWidget->isVisible()) {
154 QSize sz = rightWidget->sizeHint();
155 if (q->isRightToLeft())
156 result.setLeft(result.left() + sz.width());
157 else
158 result.setRight(result.right() - sz.width());
159 }
160
161 return result;
162}
163
164bool QMenuBarPrivate::isVisible(QAction *action)
165{
166 return !hiddenActions.contains(action);
167}
168
169void QMenuBarPrivate::updateGeometries()
170{
171 Q_Q(QMenuBar);
172 if(!itemsDirty)
173 return;
174 int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2);
175 int q_start = -1;
176 if(leftWidget || rightWidget) {
177 int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q)
178 + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
179 int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q)
180 + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
181 if (leftWidget && leftWidget->isVisible()) {
182 QSize sz = leftWidget->sizeHint();
183 q_width -= sz.width();
184 q_start = sz.width();
185 QPoint pos(hmargin, (q->height() - leftWidget->height()) / 2);
186 QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
187 leftWidget->setGeometry(vRect);
188 }
189 if (rightWidget && rightWidget->isVisible()) {
190 QSize sz = rightWidget->sizeHint();
191 q_width -= sz.width();
192 QPoint pos(q->width() - sz.width() - hmargin, vmargin);
193 QRect vRect = QStyle::visualRect(q->layoutDirection(), q->rect(), QRect(pos, sz));
194 rightWidget->setGeometry(vRect);
195 }
196 }
197
198#ifdef Q_WS_MAC
199 if(q->isNativeMenuBar()) {//nothing to see here folks, move along..
200 itemsDirty = false;
201 return;
202 }
203#endif
204 calcActionRects(q_width, q_start);
205 currentAction = 0;
206#ifndef QT_NO_SHORTCUT
207 if(itemsDirty) {
208 for(int j = 0; j < shortcutIndexMap.size(); ++j)
209 q->releaseShortcut(shortcutIndexMap.value(j));
210 shortcutIndexMap.resize(0); // faster than clear
211 for(int i = 0; i < actions.count(); i++)
212 shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text())));
213 }
214#endif
215 itemsDirty = false;
216
217 hiddenActions.clear();
218 //this is the menu rectangle without any extension
219 QRect menuRect = this->menuRect(false);
220
221 //we try to see if the actions will fit there
222 bool hasHiddenActions = false;
223 for (int i = 0; i < actions.count(); ++i) {
224 const QRect &rect = actionRects.at(i);
225 if (rect.isValid() && !menuRect.contains(rect)) {
226 hasHiddenActions = true;
227 break;
228 }
229 }
230
231 //...and if not, determine the ones that fit on the menu with the extension visible
232 if (hasHiddenActions) {
233 menuRect = this->menuRect(true);
234 for (int i = 0; i < actions.count(); ++i) {
235 const QRect &rect = actionRects.at(i);
236 if (rect.isValid() && !menuRect.contains(rect)) {
237 hiddenActions.append(actions.at(i));
238 }
239 }
240 }
241
242 if (hiddenActions.count() > 0) {
243 QMenu *pop = extension->menu();
244 if (!pop) {
245 pop = new QMenu(q);
246 extension->setMenu(pop);
247 }
248 pop->clear();
249 pop->addActions(hiddenActions);
250
251 int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q);
252 int x = q->isRightToLeft()
253 ? menuRect.left() - extension->sizeHint().width() + 1
254 : menuRect.right();
255 extension->setGeometry(x, vmargin, extension->sizeHint().width(), menuRect.height() - vmargin*2);
256 extension->show();
257 } else {
258 extension->hide();
259 }
260 q->updateGeometry();
261#ifdef QT3_SUPPORT
262 if (parent) {
263 QMenubarUpdatedEvent menubarUpdated(q);
264 QApplication::sendEvent(parent, &menubarUpdated);
265 }
266#endif
267}
268
269QRect QMenuBarPrivate::actionRect(QAction *act) const
270{
271 const int index = actions.indexOf(act);
272
273 //makes sure the geometries are up-to-date
274 const_cast<QMenuBarPrivate*>(this)->updateGeometries();
275
276 if (index < 0 || index >= actionRects.count())
277 return QRect(); // that can happen in case of native menubar
278
279 return actionRects.at(index);
280}
281
282void QMenuBarPrivate::focusFirstAction()
283{
284 if(!currentAction) {
285 updateGeometries();
286 int index = 0;
287 while (index < actions.count() && actionRects.at(index).isNull()) ++index;
288 if (index < actions.count())
289 setCurrentAction(actions.at(index));
290 }
291}
292
293void QMenuBarPrivate::setKeyboardMode(bool b)
294{
295 Q_Q(QMenuBar);
296 if (b && !q->style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, q)) {
297 setCurrentAction(0);
298 return;
299 }
300 keyboardState = b;
301 if(b) {
302 QWidget *fw = QApplication::focusWidget();
303 if (fw != q)
304 keyboardFocusWidget = fw;
305 focusFirstAction();
306 q->setFocus(Qt::MenuBarFocusReason);
307 } else {
308 if(!popupState)
309 setCurrentAction(0);
310 if(keyboardFocusWidget) {
311 if (QApplication::focusWidget() == q)
312 keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason);
313 keyboardFocusWidget = 0;
314 }
315 }
316 q->update();
317}
318
319void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
320{
321 Q_Q(QMenuBar);
322 if(!action || !action->menu() || closePopupMode)
323 return;
324 popupState = true;
325 if (action->isEnabled() && action->menu()->isEnabled()) {
326 closePopupMode = 0;
327 activeMenu = action->menu();
328 activeMenu->d_func()->causedPopup.widget = q;
329 activeMenu->d_func()->causedPopup.action = action;
330
331 QRect adjustedActionRect = actionRect(action);
332 QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1)));
333 QSize popup_size = activeMenu->sizeHint();
334
335 //we put the popup menu on the screen containing the bottom-center of the action rect
336 QRect screenRect = QApplication::desktop()->screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0));
337 pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
338
339 const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height());
340 const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom());
341 const bool rtl = q->isRightToLeft();
342 const int actionWidth = adjustedActionRect.width();
343
344 if (!fitUp && !fitDown) { //we should shift the menu
345 bool shouldShiftToRight = !rtl;
346 if (rtl && popup_size.width() > pos.x())
347 shouldShiftToRight = true;
348 else if (actionWidth + popup_size.width() + pos.x() > screenRect.right())
349 shouldShiftToRight = false;
350
351 if (shouldShiftToRight) {
352 pos.rx() += actionWidth + (rtl ? popup_size.width() : 0);
353 } else {
354 //shift to left
355 if (!rtl)
356 pos.rx() -= popup_size.width();
357 }
358 } else if (rtl) {
359 pos.rx() += actionWidth;
360 }
361
362 if(!defaultPopDown || (fitUp && !fitDown))
363 pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y()));
364 activeMenu->popup(pos);
365 if(activateFirst)
366 activeMenu->d_func()->setFirstActionActive();
367 }
368 q->update(actionRect(action));
369}
370
371void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst)
372{
373 if(currentAction == action && popup == popupState)
374 return;
375
376 autoReleaseTimer.stop();
377
378 doChildEffects = (popup && !activeMenu);
379 Q_Q(QMenuBar);
380 QWidget *fw = 0;
381 if(QMenu *menu = activeMenu) {
382 activeMenu = 0;
383 if (popup) {
384 fw = q->window()->focusWidget();
385 q->setFocus(Qt::NoFocusReason);
386 }
387 menu->hide();
388 }
389
390 if(currentAction)
391 q->update(actionRect(currentAction));
392
393 popupState = popup;
394#ifndef QT_NO_STATUSTIP
395 QAction *previousAction = currentAction;
396#endif
397 currentAction = action;
398 if (action) {
399 activateAction(action, QAction::Hover);
400 if(popup)
401 popupAction(action, activateFirst);
402 q->update(actionRect(action));
403#ifndef QT_NO_STATUSTIP
404 } else if (previousAction) {
405 QString empty;
406 QStatusTipEvent tip(empty);
407 QApplication::sendEvent(q, &tip);
408#endif
409 }
410 if (fw)
411 fw->setFocus(Qt::NoFocusReason);
412}
413
414void QMenuBarPrivate::calcActionRects(int max_width, int start) const
415{
416 Q_Q(const QMenuBar);
417
418 if(!itemsDirty)
419 return;
420
421 //let's reinitialize the buffer
422 actionRects.resize(actions.count());
423 actionRects.fill(QRect());
424
425 const QStyle *style = q->style();
426
427 const int itemSpacing = style->pixelMetric(QStyle::PM_MenuBarItemSpacing, 0, q);
428 int max_item_height = 0, separator = -1, separator_start = 0, separator_len = 0;
429
430 //calculate size
431 const QFontMetrics fm = q->fontMetrics();
432 const int hmargin = style->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q),
433 vmargin = style->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q),
434 icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q);
435 for(int i = 0; i < actions.count(); i++) {
436 QAction *action = actions.at(i);
437 if(!action->isVisible())
438 continue;
439
440 QSize sz;
441
442 //calc what I think the size is..
443 if(action->isSeparator()) {
444 if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q))
445 separator = i;
446 continue; //we don't really position these!
447 } else {
448 const QString s = action->text();
449 QIcon is = action->icon();
450 // If an icon is set, only the icon is visible
451 if (!is.isNull())
452 sz = sz.expandedTo(QSize(icone, icone));
453 else if (!s.isEmpty())
454 sz = fm.size(Qt::TextShowMnemonic, s);
455 }
456
457 //let the style modify the above size..
458 QStyleOptionMenuItem opt;
459 q->initStyleOption(&opt, action);
460 sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q);
461
462 if(!sz.isEmpty()) {
463 { //update the separator state
464 int iWidth = sz.width() + itemSpacing;
465 if(separator == -1)
466 separator_start += iWidth;
467 else
468 separator_len += iWidth;
469 }
470 //maximum height
471 max_item_height = qMax(max_item_height, sz.height());
472 //append
473 actionRects[i] = QRect(0, 0, sz.width(), sz.height());
474 }
475 }
476
477 //calculate position
478 const int fw = q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q);
479 int x = fw + ((start == -1) ? hmargin : start) + itemSpacing;
480 int y = fw + vmargin;
481 for(int i = 0; i < actions.count(); i++) {
482 QRect &rect = actionRects[i];
483 if (rect.isNull())
484 continue;
485
486 //resize
487 rect.setHeight(max_item_height);
488
489 //move
490 if(separator != -1 && i >= separator) { //after the separator
491 int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin);
492 if(left < separator_start) { //wrap
493 separator_start = x = hmargin;
494 y += max_item_height;
495 }
496 rect.moveLeft(left);
497 } else {
498 rect.moveLeft(x);
499 }
500 rect.moveTop(y);
501
502 //keep moving along..
503 x += rect.width() + itemSpacing;
504
505 //make sure we follow the layout direction
506 rect = QStyle::visualRect(q->layoutDirection(), q->rect(), rect);
507 }
508}
509
510void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent action_e)
511{
512 Q_Q(QMenuBar);
513 if (!action || !action->isEnabled())
514 return;
515 action->activate(action_e);
516 if (action_e == QAction::Hover)
517 action->showStatusText(q);
518
519// if(action_e == QAction::Trigger)
520// emit q->activated(action);
521// else if(action_e == QAction::Hover)
522// emit q->highlighted(action);
523}
524
525
526void QMenuBarPrivate::_q_actionTriggered()
527{
528 Q_Q(QMenuBar);
529 if (QAction *action = qobject_cast<QAction *>(q->sender())) {
530 emit q->triggered(action);
531#ifdef QT3_SUPPORT
532 emit q->activated(q->findIdForAction(action));
533#endif
534 }
535}
536
537void QMenuBarPrivate::_q_actionHovered()
538{
539 Q_Q(QMenuBar);
540 if (QAction *action = qobject_cast<QAction *>(q->sender())) {
541 emit q->hovered(action);
542#ifndef QT_NO_ACCESSIBILITY
543 if (QAccessible::isActive()) {
544 int actionIndex = actions.indexOf(action);
545 ++actionIndex;
546 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus);
547 QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection);
548 }
549#endif //QT_NO_ACCESSIBILITY
550#ifdef QT3_SUPPORT
551 emit q->highlighted(q->findIdForAction(action));
552#endif
553 }
554}
555
556/*!
557 Initialize \a option with the values from the menu bar and information from \a action. This method
558 is useful for subclasses when they need a QStyleOptionMenuItem, but don't want
559 to fill in all the information themselves.
560
561 \sa QStyleOption::initFrom() QMenu::initStyleOption()
562*/
563void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
564{
565 if (!option || !action)
566 return;
567 Q_D(const QMenuBar);
568 option->palette = palette();
569 option->state = QStyle::State_None;
570 if (isEnabled() && action->isEnabled())
571 option->state |= QStyle::State_Enabled;
572 else
573 option->palette.setCurrentColorGroup(QPalette::Disabled);
574 option->fontMetrics = fontMetrics();
575 if (d->currentAction && d->currentAction == action) {
576 option->state |= QStyle::State_Selected;
577 if (d->popupState && !d->closePopupMode)
578 option->state |= QStyle::State_Sunken;
579 }
580 if (hasFocus() || d->currentAction)
581 option->state |= QStyle::State_HasFocus;
582 option->menuRect = rect();
583 option->menuItemType = QStyleOptionMenuItem::Normal;
584 option->checkType = QStyleOptionMenuItem::NotCheckable;
585 option->text = action->text();
586 option->icon = action->icon();
587}
588
589/*!
590 \class QMenuBar
591 \brief The QMenuBar class provides a horizontal menu bar.
592
593 \ingroup mainwindow-classes
594
595 A menu bar consists of a list of pull-down menu items. You add
596 menu items with addMenu(). For example, asuming that \c menubar
597 is a pointer to a QMenuBar and \c fileMenu is a pointer to a
598 QMenu, the following statement inserts the menu into the menu bar:
599 \snippet doc/src/snippets/code/src_gui_widgets_qmenubar.cpp 0
600
601 The ampersand in the menu item's text sets Alt+F as a shortcut for
602 this menu. (You can use "\&\&" to get a real ampersand in the menu
603 bar.)
604
605 There is no need to lay out a menu bar. It automatically sets its
606 own geometry to the top of the parent widget and changes it
607 appropriately whenever the parent is resized.
608
609 \section1 Usage
610
611 In most main window style applications you would use the
612 \l{QMainWindow::}{menuBar()} function provided in QMainWindow,
613 adding \l{QMenu}s to the menu bar and adding \l{QAction}s to the
614 pop-up menus.
615
616 Example (from the \l{mainwindows/menus}{Menus} example):
617
618 \snippet examples/mainwindows/menus/mainwindow.cpp 9
619
620 Menu items may be removed with removeAction().
621
622 Widgets can be added to menus by using instances of the QWidgetAction
623 class to hold them. These actions can then be inserted into menus
624 in the usual way; see the QMenu documentation for more details.
625
626 \section1 Platform Dependent Look and Feel
627
628 Different platforms have different requirements for the appearance
629 of menu bars and their behavior when the user interacts with them.
630 For example, Windows systems are often configured so that the
631 underlined character mnemonics that indicate keyboard shortcuts
632 for items in the menu bar are only shown when the \gui{Alt} key is
633 pressed.
634
635 \table
636
637 \row \o \inlineimage plastique-menubar.png A menu bar shown in the
638 Plastique widget style.
639
640 \o The \l{QPlastiqueStyle}{Plastique widget style}, like most
641 other styles, handles the \gui{Help} menu in the same way as it
642 handles any other menu.
643
644 \row \o \inlineimage motif-menubar.png A menu bar shown in the
645 Motif widget style.
646
647 \o The \l{QMotifStyle}{Motif widget style} treats \gui{Help} menus
648 in a special way, placing them at right-hand end of the menu bar.
649
650 \endtable
651
652 \section1 QMenuBar on Mac OS X
653
654 QMenuBar on Mac OS X is a wrapper for using the system-wide menu bar.
655 If you have multiple menu bars in one dialog the outermost menu bar
656 (normally inside a widget with widget flag Qt::Window) will
657 be used for the system-wide menu bar.
658
659 Qt for Mac OS X also provides a menu bar merging feature to make
660 QMenuBar conform more closely to accepted Mac OS X menu bar layout.
661 The merging functionality is based on string matching the title of
662 a QMenu entry. These strings are translated (using QObject::tr())
663 in the "QMenuBar" context. If an entry is moved its slots will still
664 fire as if it was in the original place. The table below outlines
665 the strings looked for and where the entry is placed if matched:
666
667 \table
668 \header \i String matches \i Placement \i Notes
669 \row \i about.*
670 \i Application Menu | About <application name>
671 \i The application name is fetched from the \c {Info.plist} file
672 (see note below). If this entry is not found no About item
673 will appear in the Application Menu.
674 \row \i config, options, setup, settings or preferences
675 \i Application Menu | Preferences
676 \i If this entry is not found the Settings item will be disabled
677 \row \i quit or exit
678 \i Application Menu | Quit <application name>
679 \i If this entry is not found a default Quit item will be
680 created to call QApplication::quit()
681 \endtable
682
683 You can override this behavior by using the QAction::menuRole()
684 property.
685
686 If you want all windows in a Mac application to share one menu
687 bar, you must create a menu bar that does not have a parent.
688 Create a parent-less menu bar this way:
689
690 \snippet doc/src/snippets/code/src_gui_widgets_qmenubar.cpp 1
691
692 \bold{Note:} Do \e{not} call QMainWindow::menuBar() to create the
693 shared menu bar, because that menu bar will have the QMainWindow
694 as its parent. That menu bar would only be displayed for the
695 parent QMainWindow.
696
697 \bold{Note:} The text used for the application name in the menu
698 bar is obtained from the value set in the \c{Info.plist} file in
699 the application's bundle. See \l{Deploying an Application on
700 Mac OS X} for more information.
701
702 \section1 QMenuBar on Windows CE
703
704 QMenuBar on Windows CE is a wrapper for using the system-wide menu bar,
705 similar to the Mac. This feature is activated for Windows Mobile
706 and integrates QMenuBar with the native soft keys. The left soft
707 key can be controlled with QMenuBar::setDefaultAction() and the
708 right soft key can be used to access the menu bar.
709
710 The hovered() signal is not supported for the native menu
711 integration. Also, it is not possible to display an icon in a
712 native menu on Windows Mobile.
713
714 \section1 Examples
715
716 The \l{mainwindows/menus}{Menus} example shows how to use QMenuBar
717 and QMenu. The other \l{Main Window Examples}{main window
718 application examples} also provide menus using these classes.
719
720 \sa QMenu, QShortcut, QAction,
721 {http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGIntro/XHIGIntro.html}{Introduction to Apple Human Interface Guidelines},
722 {fowler}{GUI Design Handbook: Menu Bar}, {Menus Example}
723*/
724
725
726void QMenuBarPrivate::init()
727{
728 Q_Q(QMenuBar);
729 q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
730 q->setAttribute(Qt::WA_CustomWhatsThis);
731#ifdef Q_WS_MAC
732 macCreateMenuBar(q->parentWidget());
733 if(mac_menubar)
734 q->hide();
735#endif
736#ifdef Q_WS_WINCE
737 if (qt_wince_is_mobile()) {
738 wceCreateMenuBar(q->parentWidget());
739 if(wce_menubar)
740 q->hide();
741 }
742 else {
743 QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
744 }
745#endif
746 q->setBackgroundRole(QPalette::Button);
747 oldWindow = oldParent = 0;
748#ifdef QT3_SUPPORT
749 doAutoResize = false;
750#endif
751#ifdef QT_SOFTKEYS_ENABLED
752 menuBarAction = 0;
753#endif
754 handleReparent();
755 q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, q));
756
757 extension = new QMenuBarExtension(q);
758 extension->setFocusPolicy(Qt::NoFocus);
759 extension->hide();
760}
761
762//Gets the next action for keyboard navigation
763QAction *QMenuBarPrivate::getNextAction(const int _start, const int increment) const
764{
765 Q_Q(const QMenuBar);
766 const_cast<QMenuBarPrivate*>(this)->updateGeometries();
767 bool allowActiveAndDisabled = q->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled, 0, q);
768 const int start = (_start == -1 && increment == -1) ? actions.count() : _start;
769 const int end = increment == -1 ? 0 : actions.count() - 1;
770
771 for (int i = start; i != end;) {
772 i += increment;
773 QAction *current = actions.at(i);
774 if (!actionRects.at(i).isNull() && (allowActiveAndDisabled || current->isEnabled()))
775 return current;
776 }
777
778 if (_start != -1) //let's try from the beginning or the end
779 return getNextAction(-1, increment);
780
781 return 0;
782}
783
784/*!
785 Constructs a menu bar with parent \a parent.
786*/
787QMenuBar::QMenuBar(QWidget *parent) : QWidget(*new QMenuBarPrivate, parent, 0)
788{
789 Q_D(QMenuBar);
790 d->init();
791}
792
793#ifdef QT3_SUPPORT
794/*!
795 Use one of the constructors that doesn't take the \a name
796 argument and then use setObjectName() instead.
797*/
798QMenuBar::QMenuBar(QWidget *parent, const char *name) : QWidget(*new QMenuBarPrivate, parent, 0)
799{
800 Q_D(QMenuBar);
801 d->init();
802 setObjectName(QString::fromAscii(name));
803}
804#endif
805
806/*!
807 Destroys the menu bar.
808*/
809QMenuBar::~QMenuBar()
810{
811#ifdef Q_WS_MAC
812 Q_D(QMenuBar);