source: trunk/src/widgets/qmenubar.cpp@ 174

Last change on this file since 174 was 174, checked in by dmik, 18 years ago

Styles: Implemented the first version of the Warp4 style (contributed by Cornelis Bockemuehl).

  • Property svn:keywords set to Id
File size: 44.7 KB
Line 
1/****************************************************************************
2** $Id: qmenubar.cpp 174 2007-11-06 22:27:57Z dmik $
3**
4** Implementation of QMenuBar class
5**
6** Created : 941209
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
141** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38// qmainwindow.h before qmenubar.h because of GCC-2.7.* compatibility
39// ### could be reorganised by discarding INCLUDE_MENUITEM_DEF and put
40// the relevant declarations in a private header?
41#include "qmainwindow.h"
42#ifndef QT_NO_MENUBAR
43#include "qmenubar.h"
44#include "qpopupmenu.h"
45#include "qaccel.h"
46#include "qpainter.h"
47#include "qdrawutil.h"
48#include "qapplication.h"
49#include "qguardedptr.h"
50#include "qlayout.h"
51#include "qcleanuphandler.h"
52#include "../kernel/qinternal_p.h"
53#include "qstyle.h"
54#include "qtimer.h"
55#if defined(QT_ACCESSIBILITY_SUPPORT)
56#include "qaccessible.h"
57#endif
58
59class QMenuDataData {
60 // attention: also defined in qmenudata.cpp
61public:
62 QMenuDataData();
63 QGuardedPtr<QWidget> aWidget;
64 int aInt;
65};
66
67#if defined(QT_ACCESSIBILITY_SUPPORT)
68static bool inMenu = FALSE;
69#endif
70
71#if defined(Q_WS_X11)
72extern int qt_xfocusout_grab_counter; // defined in qapplication_x11.cpp
73#endif
74
75/*!
76 \class QMenuBar qmenubar.h
77 \brief The QMenuBar class provides a horizontal menu bar.
78
79 \ingroup application
80 \mainclass
81
82 A menu bar consists of a list of pull-down menu items. You add
83 menu items with \link QMenuData::insertItem()
84 insertItem()\endlink. For example, asuming that \c menubar is a
85 pointer to a QMenuBar and \c filemenu is a pointer to a
86 QPopupMenu, the following statement inserts the menu into the menu
87 bar:
88 \code
89 menubar->insertItem( "&File", filemenu );
90 \endcode
91 The ampersand in the menu item's text sets Alt+F as a shortcut for
92 this menu. (You can use "\&\&" to get a real ampersand in the menu
93 bar.)
94
95 Items are either enabled or disabled. You toggle their state with
96 setItemEnabled().
97
98 There is no need to lay out a menu bar. It automatically sets its
99 own geometry to the top of the parent widget and changes it
100 appropriately whenever the parent is resized.
101
102 \important insertItem removeItem clear insertSeparator setItemEnabled isItemEnabled setItemVisible isItemVisible
103
104 Example of creating a menu bar with menu items (from \l menu/menu.cpp):
105 \quotefile menu/menu.cpp
106 \skipto file = new QPopupMenu
107 \printline
108 \skipto Key_O
109 \printline
110 \printline
111 \skipto new QMenuBar
112 \printline
113 \skipto insertItem
114 \printline
115
116 In most main window style applications you would use the menuBar()
117 provided in QMainWindow, adding \l{QPopupMenu}s to the menu bar
118 and adding \l{QAction}s to the popup menus.
119
120 Example (from \l action/application.cpp):
121 \quotefile action/application.cpp
122 \skipto file = new QPopupMenu
123 \printuntil fileNewAction
124
125 Menu items can have text and pixmaps (or iconsets), see the
126 various \link QMenuData::insertItem() insertItem()\endlink
127 overloads, as well as separators, see \link
128 QMenuData::insertSeparator() insertSeparator()\endlink. You can
129 also add custom menu items that are derived from
130 \l{QCustomMenuItem}.
131
132 Menu items may be removed with removeItem() and enabled or
133 disabled with \link QMenuData::setItemEnabled()
134 setItemEnabled()\endlink.
135
136 <img src=qmenubar-m.png> <img src=qmenubar-w.png>
137
138 \section1 QMenuBar on Qt/Mac
139
140 QMenuBar on Qt/Mac is a wrapper for using the system-wide menubar.
141 If you have multiple menubars in one dialog the outermost menubar
142 (normally inside a widget with widget flag \c WType_TopLevel) will
143 be used for the system-wide menubar.
144
145 Note that arbitrary Qt widgets \e cannot be inserted into a
146 QMenuBar on the Mac because Qt uses Mac's native menus which don't
147 support this functionality. This limitation does not apply to
148 stand-alone QPopupMenus.
149
150 Qt/Mac also provides a menubar merging feature to make QMenuBar
151 conform more closely to accepted Mac OS X menubar layout. The
152 merging functionality is based on string matching the title of a
153 QPopupMenu entry. These strings are translated (using
154 QObject::tr()) in the "QMenuBar" context. If an entry is moved its
155 slots will still fire as if it was in the original place. The
156 table below outlines the strings looked for and where the entry is
157 placed if matched:
158
159 \table
160 \header \i String matches \i Placement \i Notes
161 \row \i about.*
162 \i Application Menu | About <application name>
163 \i If this entry is not found no About item will appear in
164 the Application Menu
165 \row \i config, options, setup, settings or preferences
166 \i Application Menu | Preferences
167 \i If this entry is not found the Settings item will be disabled
168 \row \i quit or exit
169 \i Application Menu | Quit <application name>
170 \i If this entry is not found a default Quit item will be
171 created to call QApplication::quit()
172 \endtable
173
174 \link menu-example.html menu/menu.cpp\endlink is an example of
175 QMenuBar and QPopupMenu use.
176
177 \sa QPopupMenu QAccel QAction \link http://developer.apple.com/techpubs/macosx/Carbon/HumanInterfaceToolbox/Aqua/aqua.html Aqua Style Guidelines \endlink \link guibooks.html#fowler GUI Design Handbook: Menu Bar \endlink
178*/
179
180
181/*!
182 \enum QMenuBar::Separator
183
184 This enum type is used to decide whether QMenuBar should draw a
185 separator line at its bottom.
186
187 \value Never In many applications there is already a separator,
188 and having two looks wrong.
189
190 \value InWindowsStyle In some other applications a separator looks
191 good in Windows style, but nowhere else.
192*/
193
194/*!
195 \fn void QMenuBar::activated( int id )
196
197 This signal is emitted when a menu item is selected; \a id is the
198 id of the selected item.
199
200 Normally you will connect each menu item to a single slot using
201 QMenuData::insertItem(), but sometimes you will want to connect
202 several items to a single slot (most often if the user selects
203 from an array). This signal is useful in such cases.
204
205 \sa highlighted(), QMenuData::insertItem()
206*/
207
208/*!
209 \fn void QMenuBar::highlighted( int id )
210
211 This signal is emitted when a menu item is highlighted; \a id is
212 the id of the highlighted item.
213
214 Normally, you will connect each menu item to a single slot using
215 QMenuData::insertItem(), but sometimes you will want to connect
216 several items to a single slot (most often if the user selects
217 from an array). This signal is useful in such cases.
218
219 \sa activated(), QMenuData::insertItem()
220*/
221
222
223// Motif style parameters
224
225static const int motifBarHMargin = 2; // menu bar hor margin to item
226static const int motifBarVMargin = 1; // menu bar ver margin to item
227static const int motifItemFrame = 2; // menu item frame width
228static const int motifItemHMargin = 5; // menu item hor text margin
229static const int motifItemVMargin = 4; // menu item ver text margin
230
231/*
232
233+-----------------------------
234| BarFrame
235| +-------------------------
236| | V BarMargin
237| | +---------------------
238| | H | ItemFrame
239| | | +-----------------
240| | | | \
241| | | | ^ T E X T ^ | ItemVMargin
242| | | | | | /
243| | | ItemHMargin
244| |
245|
246
247*/
248
249
250/*****************************************************************************
251 QMenuBar member functions
252 *****************************************************************************/
253
254
255/*!
256 Constructs a menu bar called \a name with parent \a parent.
257*/
258QMenuBar::QMenuBar( QWidget *parent, const char *name )
259 : QFrame( parent, name, WNoAutoErase )
260{
261#if defined( Q_WS_MAC ) && !defined(QMAC_QMENUBAR_NO_NATIVE)
262 mac_eaten_menubar = FALSE;
263 mac_d = 0;
264 macCreateNativeMenubar();
265#endif
266 isMenuBar = TRUE;
267#ifndef QT_NO_ACCEL
268 autoaccel = 0;
269#endif
270 irects = 0;
271 rightSide = 0; // Right of here is rigth-aligned content
272 mseparator = 0;
273 waitforalt = 0;
274 popupvisible = 0;
275 hasmouse = 0;
276 defaultup = 0;
277 toggleclose = 0;
278 pendingDelayedContentsChanges = 0;
279 pendingDelayedStateChanges = 0;
280 if ( parent ) {
281 // filter parent events for resizing
282 parent->installEventFilter( this );
283
284 // filter top-level-widget events for accelerators
285 QWidget *tlw = topLevelWidget();
286 if ( tlw != parent )
287 tlw->installEventFilter( this );
288 }
289 installEventFilter( this );
290
291 setBackgroundMode( PaletteButton );
292 setFrameStyle( QFrame::MenuBarPanel | QFrame::Raised );
293
294 QFontMetrics fm = fontMetrics();
295 int h = 2*motifBarVMargin + fm.height() + motifItemVMargin + 2*frameWidth() + 2*motifItemFrame;
296
297 if ( style().styleHint( QStyle::SH_GUIStyle ) == QStyle::PMStyle )
298 h++;
299
300 setGeometry( 0, 0, width(), h );
301
302 setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
303}
304
305
306
307/*! \reimp */
308
309void QMenuBar::styleChange( QStyle& old )
310{
311 setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
312 QFrame::styleChange( old );
313}
314
315
316
317/*!
318 Destroys the menu bar.
319*/
320
321QMenuBar::~QMenuBar()
322{
323#ifndef QT_NO_ACCEL
324 delete autoaccel;
325#endif
326#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
327 macRemoveNativeMenubar();
328#endif
329 if ( irects ) // Avoid purify complaint.
330 delete [] irects;
331}
332
333/*!
334 \internal
335
336 Repaints the menu item with id \a id; does nothing if there is no
337 such menu item.
338*/
339void QMenuBar::updateItem( int id )
340{
341 int i = indexOf( id );
342 if ( i >= 0 && irects )
343 repaint( irects[i], FALSE );
344}
345
346#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
347static bool fromFrameChange = FALSE;
348#endif
349
350/*!
351 Recomputes the menu bar's display data according to the new
352 contents.
353
354 You should never need to call this; it is called automatically by
355 QMenuData whenever it needs to be called.
356*/
357
358void QMenuBar::menuContentsChanged()
359{
360 // here the part that can't be delayed
361 QMenuData::menuContentsChanged();
362 badSize = TRUE; // might change the size
363 if( pendingDelayedContentsChanges )
364 return;
365 pendingDelayedContentsChanges = 1;
366 if( !pendingDelayedStateChanges )// if the timer hasn't been started yet
367 QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
368}
369
370void QMenuBar::performDelayedContentsChanged()
371{
372 pendingDelayedContentsChanges = 0;
373 // here the part the can be delayed
374#ifndef QT_NO_ACCEL
375 // if performDelayedStateChanged() will be called too,
376 // it will call setupAccelerators() too, no need to do it twice
377 if( !pendingDelayedStateChanges )
378 setupAccelerators();
379#endif
380 calculateRects();
381 if ( isVisible() ) {
382 update();
383#ifndef QT_NO_MAINWINDOW
384 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
385 if ( mw ) {
386 mw->triggerLayout();
387 mw->update();
388 }
389#endif
390#ifndef QT_NO_LAYOUT
391 if ( parentWidget() && parentWidget()->layout() )
392 parentWidget()->layout()->activate();
393#endif
394 }
395}
396
397/*!
398 Recomputes the menu bar's display data according to the new state.
399
400 You should never need to call this; it is called automatically by
401 QMenuData whenever it needs to be called.
402*/
403
404void QMenuBar::menuStateChanged()
405{
406 if( pendingDelayedStateChanges )
407 return;
408 pendingDelayedStateChanges = 1;
409 if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
410 QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
411}
412
413void QMenuBar::performDelayedStateChanged()
414{
415 pendingDelayedStateChanges = 0;
416 // here the part that can be delayed
417#ifndef QT_NO_ACCEL
418 setupAccelerators(); // ### when we have a good solution for the accel vs. focus
419 // widget problem, remove that. That is only a workaround
420 // if you remove this, see performDelayedContentsChanged()
421#endif
422 update();
423}
424
425
426void QMenuBar::performDelayedChanges()
427{
428#if defined(Q_WS_MAC) && !defined(QMAC_MENUBAR_NO_NATIVE)
429 // I must do this here as the values change in the function below.
430 bool needMacUpdate = (pendingDelayedContentsChanges || pendingDelayedStateChanges);
431#endif
432 if( pendingDelayedContentsChanges )
433 performDelayedContentsChanged();
434 if( pendingDelayedStateChanges )
435 performDelayedStateChanged();
436#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
437 if(mac_eaten_menubar && needMacUpdate) {
438 macDirtyNativeMenubar();
439
440 bool all_hidden = TRUE;
441 if(irects) {
442 for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
443 all_hidden = irects[i].isEmpty();
444 }
445 if( all_hidden ) {
446 if( !isHidden())
447 hide();
448 } else {
449 if( !isShown() && !fromFrameChange )
450 show();
451 }
452 }
453#endif
454}
455
456
457void QMenuBar::menuInsPopup( QPopupMenu *popup )
458{
459 connect( popup, SIGNAL(activatedRedirect(int)),
460 SLOT(subActivated(int)) );
461 connect( popup, SIGNAL(highlightedRedirect(int)),
462 SLOT(subHighlighted(int)) );
463 connect( popup, SIGNAL(destroyed(QObject*)),
464 this, SLOT(popupDestroyed(QObject*)) );
465}
466
467void QMenuBar::menuDelPopup( QPopupMenu *popup )
468{
469 popup->disconnect( SIGNAL(activatedRedirect(int)) );
470 popup->disconnect( SIGNAL(highlightedRedirect(int)) );
471 disconnect( popup, SIGNAL(destroyed(QObject*)),
472 this, SLOT(popupDestroyed(QObject*)) );
473}
474
475void QMenuBar::frameChanged()
476{
477#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
478 fromFrameChange = TRUE;
479#endif
480 menuContentsChanged();
481#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
482 fromFrameChange = FALSE;
483#endif
484}
485
486void QMenuBar::languageChange()
487{
488 menuContentsChanged();
489}
490
491/*!
492 \internal
493
494 This function is used to adjust the menu bar's geometry to the
495 parent widget's geometry. Note that this is \e not part of the
496 public interface - the function is \c public only because
497 QObject::eventFilter() is.
498
499 Resizes the menu bar to fit in the parent widget when the parent
500 receives a resize event.
501*/
502
503bool QMenuBar::eventFilter( QObject *object, QEvent *event )
504{
505 if ( object == parent() && object
506#ifndef QT_NO_TOOLBAR
507 && !::qt_cast<QToolBar*>(object)
508#endif
509 && event->type() == QEvent::Resize ) {
510 QResizeEvent *e = (QResizeEvent *)event;
511 int w = e->size().width();
512 setGeometry( 0, y(), w, heightForWidth(w) );
513 return FALSE;
514 }
515
516 if ( !isVisible() || !object->isWidgetType() )
517 return FALSE;
518
519 if ( object == this && event->type() == QEvent::LanguageChange ) {
520 badSize = TRUE;
521 calculateRects();
522 return FALSE;
523 } else if ( event->type() == QEvent::MouseButtonPress ||
524 event->type() == QEvent::MouseButtonRelease ) {
525 waitforalt = 0;
526 return FALSE;
527 } else if ( waitforalt && event->type() == QEvent::FocusOut ) {
528 // some window systems/managers use alt/meta as accelerator keys
529 // for switching between windows/desktops/etc. If the focus
530 // widget gets unfocused, then we need to stop waiting for alt
531 // NOTE: this event came from the real focus widget, so we don't
532 // need to touch the event filters
533 waitforalt = 0;
534 // although the comment above said not to remove the event filter, it is
535 // incorrect. We need to remove our self fom the focused widget as normally
536 // this happens in the key release but it does not happen in this case
537 QWidget * f = ((QWidget *)object)->focusWidget();
538 if (f)
539 f->removeEventFilter( this );
540 return FALSE;
541 } else if ( !( event->type() == QEvent::Accel ||
542 event->type() == QEvent::AccelOverride ||
543 event->type() == QEvent::KeyPress ||
544 event->type() == QEvent::KeyRelease ) ||
545 !style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) ) {
546 return FALSE;
547 }
548
549 QKeyEvent * ke = (QKeyEvent *) event;
550#ifndef QT_NO_ACCEL
551 // look for Alt press and Alt-anything press
552 if ( event->type() == QEvent::Accel ) {
553 QWidget * f = ((QWidget *)object)->focusWidget();
554 // ### this thinks alt and meta are the same
555 if ( ke->key() == Key_Alt || ke->key() == Key_Meta ) {
556 // A new Alt press and we wait for release, eat
557 // this key and don't wait for Alt on this widget
558 if ( waitforalt ) {
559 waitforalt = 0;
560 if ( object->parent() )
561 object->removeEventFilter( this );
562 ke->accept();
563 return TRUE;
564 // Menu has focus, send focus back
565 } else if ( hasFocus() ) {
566 setAltMode( FALSE );
567 ke->accept();
568 return TRUE;
569 // Start waiting for Alt release on focus widget
570 } else if ( ke->stateAfter() == AltButton ) {
571 waitforalt = 1;
572#if defined(Q_WS_X11)
573 QMenuData::d->aInt = qt_xfocusout_grab_counter;
574#endif
575 if ( f && f != object )
576 f->installEventFilter( this );
577 }
578 // Other modifiers kills focus on menubar
579 } else if ( ke->key() == Key_Control || ke->key() == Key_Shift) {
580 setAltMode( FALSE );
581 // Got other key, no need to wait for Alt release
582 } else {
583 waitforalt = 0;
584 }
585 // ### ! block all accelerator events when the menu bar is active
586 if ( qApp && qApp->focusWidget() == this ) {
587 return TRUE;
588 }
589
590 return FALSE;
591 }
592#endif
593 // look for Alt release
594 if ( ((QWidget*)object)->focusWidget() == object ||
595 (object->parent() == 0 && ((QWidget*)object)->focusWidget() == 0) ) {
596 if ( waitforalt && event->type() == QEvent::KeyRelease &&
597 ( ke->key() == Key_Alt || ke->key() == Key_Meta )
598#if defined(Q_WS_X11)
599 && QMenuData::d->aInt == qt_xfocusout_grab_counter
600#endif
601 ) {
602 setAltMode( TRUE );
603 if ( object->parent() )
604 object->removeEventFilter( this );
605 QWidget * tlw = ((QWidget *)object)->topLevelWidget();
606 if ( tlw ) {
607 // ### !
608 // make sure to be the first event filter, so we can kill
609 // accelerator events before the accelerators get to them.
610 tlw->removeEventFilter( this );
611 tlw->installEventFilter( this );
612 }
613 return TRUE;
614 // Cancel if next keypress is NOT Alt/Meta,
615 } else if ( !hasFocus() && (event->type() == QEvent::AccelOverride ) &&
616 !(((QKeyEvent *)event)->key() == Key_Alt ||
617 ((QKeyEvent *)event)->key() == Key_Meta) ) {
618 if ( object->parent() )
619 object->removeEventFilter( this );
620 setAltMode( FALSE );
621 }
622 }
623
624 return FALSE; // don't stop event
625}
626
627
628
629/*!
630 \internal
631 Receives signals from menu items.
632*/
633
634void QMenuBar::subActivated( int id )
635{
636 emit activated( id );
637}
638
639/*!
640 \internal
641 Receives signals from menu items.
642*/
643
644void QMenuBar::subHighlighted( int id )
645{
646 emit highlighted( id );
647}
648
649/*!
650 \internal
651 Receives signals from menu accelerator.
652*/
653#ifndef QT_NO_ACCEL
654void QMenuBar::accelActivated( int id )
655{
656#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
657 if(mac_eaten_menubar)
658 return;
659#endif
660 if ( !isEnabled() ) // the menu bar is disabled
661 return;
662 setAltMode( TRUE );
663 setActiveItem( indexOf( id ) );
664}
665#endif
666
667/*!
668 \internal
669 This slot receives signals from menu accelerator when it is about to be
670 destroyed.
671*/
672#ifndef QT_NO_ACCEL
673void QMenuBar::accelDestroyed()
674{
675 autoaccel = 0; // don't delete it twice!
676}
677#endif
678
679void QMenuBar::popupDestroyed( QObject *o )
680{
681 removePopup( (QPopupMenu*)o );
682}
683
684bool QMenuBar::tryMouseEvent( QPopupMenu *, QMouseEvent *e )
685{
686 QPoint pos = mapFromGlobal( e->globalPos() );
687 if ( !rect().contains( pos ) ) // outside
688 return FALSE;
689 int item = itemAtPos( pos );
690 if ( item == -1 && (e->type() == QEvent::MouseButtonPress ||
691 e->type() == QEvent::MouseButtonRelease) ) {
692 hidePopups();
693 goodbye();
694 return FALSE;
695 }
696 QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
697 event( &ee );
698 return TRUE;
699}
700
701
702void QMenuBar::tryKeyEvent( QPopupMenu *, QKeyEvent *e )
703{
704 event( e );
705}
706
707
708void QMenuBar::goodbye( bool cancelled )
709{
710 mouseBtDn = FALSE;
711 popupvisible = 0;
712 setAltMode( cancelled && style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) );
713}
714
715
716void QMenuBar::openActPopup()
717{
718#if defined(QT_ACCESSIBILITY_SUPPORT)
719 if ( !inMenu ) {
720 QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
721 inMenu = TRUE;
722 }
723#endif
724
725 if ( actItem < 0 )
726 return;
727 QPopupMenu *popup = mitems->at(actItem)->popup();
728 if ( !popup || !popup->isEnabled() )
729 return;
730
731 QRect r = itemRect( actItem );
732 bool reverse = QApplication::reverseLayout();
733 const int yoffset = 1; //(style().styleHint( QStyle::SH_GUIStyle ) == QStyle::WindowsStyle) ? 4 : 1; ### this breaks designer mainwindow editing
734 // Warp4style: popup menus are displaced by 4
735 const int xoffset = ( style().styleHint( QStyle::SH_GUIStyle ) == QStyle::PMStyle ) ? -4 : 0;
736 QPoint pos = r.bottomLeft() + QPoint( xoffset, yoffset );
737 if( reverse ) {
738 pos = r.bottomRight() + QPoint( -xoffset, yoffset );
739 pos.rx() -= popup->sizeHint().width();
740 }
741
742 int ph = popup->sizeHint().height();
743 pos = mapToGlobal(pos);
744 int sh = QApplication::desktop()->height();
745 if ( defaultup || (pos.y() + ph > sh) ) {
746 QPoint t = mapToGlobal( r.topLeft() );
747 if( reverse ) {
748 t = mapToGlobal( r.topRight() );
749 t.rx() -= popup->sizeHint().width();
750 }
751 t.ry() -= (QCOORD)ph;
752 if ( !defaultup || t.y() >= 0 )
753 pos = t;
754 }
755
756 //avoid circularity
757 if ( popup->isVisible() )
758 return;
759
760 Q_ASSERT( popup->parentMenu == 0 );
761 popup->parentMenu = this; // set parent menu
762
763 popup->snapToMouse = FALSE;
764 popup->popup( pos );
765 popup->snapToMouse = TRUE;
766}
767
768/*!
769 \internal
770 Hides all popup menu items.
771*/
772
773void QMenuBar::hidePopups()
774{
775#if defined(QT_ACCESSIBILITY_SUPPORT)
776 bool anyVisible = FALSE;
777#endif
778 QMenuItemListIt it(*mitems);
779 register QMenuItem *mi;
780 while ( (mi=it.current()) ) {
781 ++it;
782 if ( mi->popup() && mi->popup()->isVisible() ) {
783#if defined(QT_ACCESSIBILITY_SUPPORT)
784 anyVisible = TRUE;
785#endif
786 mi->popup()->hide();
787 }
788 }
789#if defined(QT_ACCESSIBILITY_SUPPORT)
790 if ( !popupvisible && anyVisible && inMenu ) {
791 QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
792 inMenu = FALSE;
793 }
794#endif
795}
796
797
798/*!
799 Reimplements QWidget::show() in order to set up the correct
800 keyboard accelerators and to raise itself to the top of the widget
801 stack.
802*/
803
804void QMenuBar::show()
805{
806#ifndef QT_NO_ACCEL
807 setupAccelerators();
808#endif
809
810 if ( parentWidget() )
811 resize( parentWidget()->width(), height() );
812
813 QApplication::sendPostedEvents( this, QEvent::Resize );
814 performDelayedChanges();
815 calculateRects();
816
817#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
818 if(mac_eaten_menubar) {
819 //If all elements are invisible no reason for me to be visible either
820 bool all_hidden = TRUE;
821 if(irects) {
822 for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
823 all_hidden = irects[i].isEmpty();
824 }
825 if(all_hidden)
826 QWidget::hide();
827 else
828 QWidget::show();
829 } else {
830 QWidget::show();
831 }
832#else
833 QWidget::show();
834#endif
835
836#ifndef QT_NO_MAINWINDOW
837 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
838 if ( mw ) //### ugly workaround
839 mw->triggerLayout();
840#endif
841 raise();
842}
843
844/*!
845 Reimplements QWidget::hide() in order to deselect any selected
846 item, and calls setUpLayout() for the main window.
847*/
848
849void QMenuBar::hide()
850{
851 QWidget::hide();
852 setAltMode( FALSE );
853 hidePopups();
854#ifndef QT_NO_MAINWINDOW
855 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
856 if ( mw ) //### ugly workaround
857 mw->triggerLayout();
858#endif
859}
860
861/*!
862 \internal
863 Needs to change the size of the menu bar when a new font is set.
864*/
865
866void QMenuBar::fontChange( const QFont & f )
867{
868 badSize = TRUE;
869 updateGeometry();
870 if ( isVisible() )
871 calculateRects();
872 QWidget::fontChange( f );
873}
874
875
876/*****************************************************************************
877 Item geometry functions
878 *****************************************************************************/
879
880/*
881 This function serves two different purposes. If the parameter is
882 negative, it updates the irects member for the current width and
883 resizes. Otherwise, it does the same calculations for the GIVEN
884 width and returns the height to which it WOULD have resized. A bit
885 tricky, but both operations require almost identical steps.
886*/
887int QMenuBar::calculateRects( int max_width )
888{
889 polish();
890 bool update = ( max_width < 0 );
891
892 if ( update ) {
893 rightSide = 0;
894 if ( !badSize ) // size was not changed
895 return 0;
896 delete [] irects;
897 int i = mitems->count();
898 if ( i == 0 ) {
899 irects = 0;
900 } else {
901 irects = new QRect[ i ];
902 Q_CHECK_PTR( irects );
903 }
904 max_width = width();
905 }
906 QFontMetrics fm = fontMetrics();
907 int max_height = 0;
908 int max_item_height = 0;
909 int nlitems = 0; // number on items on cur line
910 int gs = style().styleHint(QStyle::SH_GUIStyle);
911 bool reverse = QApplication::reverseLayout();
912 int x = frameWidth();
913 int y = frameWidth();
914 if ( gs == MotifStyle ) {
915 x += motifBarHMargin;
916 y += motifBarVMargin;
917 } else if ( gs == WindowsStyle ) {
918 x += 2;
919 y += 2;
920 } else if ( gs == PMStyle ) {
921 x += 4;
922 }
923 if ( reverse )
924 x = max_width - x;
925
926 int i = 0;
927 int separator = -1;
928 const int itemSpacing = style().pixelMetric(QStyle::PM_MenuBarItemSpacing);
929 const int lastItem = reverse ? 0 : mitems->count() - 1;
930
931 while ( i < (int)mitems->count() ) { // for each menu item...
932 QMenuItem *mi = mitems->at(i);
933
934 int w=0, h=0;
935 if ( !mi->isVisible()
936#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
937 || (mac_eaten_menubar && !mi->custom() && !mi->widget() )
938#endif
939 ) {
940 ; // empty rectangle
941 } else if ( mi->widget() ) {
942 if ( mi->widget()->parentWidget() != this ) {
943 mi->widget()->reparent( this, QPoint(0,0) );
944 }
945 w = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).width()+2;
946 h = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).height()+2;
947 if ( i && separator < 0 )
948 separator = i;
949 } else if ( mi->pixmap() ) { // pixmap item
950 w = QMAX( mi->pixmap()->width() + 4, QApplication::globalStrut().width() );
951 h = QMAX( mi->pixmap()->height() + 4, QApplication::globalStrut().height() );
952 } else if ( !mi->text().isNull() ) { // text item
953 QString s = mi->text();
954 w = fm.boundingRect( s ).width()
955 + 2*motifItemHMargin;
956 w -= s.contains('&')*fm.width('&');
957 w += s.contains("&&")*fm.width('&');
958 w = QMAX( w, QApplication::globalStrut().width() );
959 h = QMAX( fm.height() + motifItemVMargin, QApplication::globalStrut().height() );
960 } else if ( mi->isSeparator() ) { // separator item
961 if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
962 separator = i; //### only motif?
963 }
964 if ( !mi->isSeparator() || mi->widget() ) {
965#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
966 if ( !mac_eaten_menubar ) {
967#endif
968 if ( gs == MotifStyle ) {
969 w += 2*motifItemFrame;
970 h += 2*motifItemFrame;
971 }
972#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
973 }
974#endif
975
976 if ( ( ( !reverse && x + w + frameWidth() - max_width > 0 ) ||
977 ( reverse && x - w - itemSpacing - frameWidth() < 0 ) )
978 && nlitems > 0 ) {
979 nlitems = 0;
980 x = frameWidth();
981 y += h;
982 if ( gs == MotifStyle ) {
983 x += motifBarHMargin;
984 y += motifBarVMargin;
985 } else if ( gs == PMStyle ) {
986 x += 5;
987 }
988 if ( reverse )
989 x = max_width - x + itemSpacing;
990 if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
991 separator = -1;
992 }
993 if ( y + h + 2*frameWidth() > max_height )
994 max_height = y + h + 2*frameWidth();
995 if ( h > max_item_height )
996 max_item_height = h;
997 }
998
999 const bool isLast = (i == lastItem);
1000
1001 if( reverse ) {
1002 x -= w;
1003 if (!isLast && !mi->isSeparator())
1004 x -= itemSpacing;
1005 }
1006 if ( update ) {
1007 irects[i].setRect( x, y, w, h );
1008 }
1009 if ( !reverse ) {
1010 x += w;
1011 if (!isLast && !mi->isSeparator())
1012 x += itemSpacing;
1013 }
1014 nlitems++;
1015 i++;
1016 }
1017 if ( gs == WindowsStyle ) {
1018 max_height += 2;
1019 max_width += 2;
1020 }
1021
1022 if ( update ) {
1023 if ( separator >= 0 ) {
1024 int moveBy = reverse ? - x - frameWidth() : max_width - x - frameWidth();
1025 rightSide = x;
1026 while( --i >= separator ) {
1027 irects[i].moveBy( moveBy, 0 );
1028 }
1029 } else {
1030 rightSide = width()-frameWidth();
1031 }
1032 if ( max_height != height() )
1033 resize( width(), max_height );
1034 for ( i = 0; i < (int)mitems->count(); i++ ) {
1035 irects[i].setHeight( max_item_height );
1036 QMenuItem *mi = mitems->at(i);
1037 if ( mi->widget() ) {
1038 QRect r ( QPoint(0,0), mi->widget()->sizeHint() );
1039 r.moveCenter( irects[i].center() );
1040 mi->widget()->setGeometry( r );
1041 if( mi->widget()->isHidden() )
1042 mi->widget()->show();
1043 }
1044 }
1045 badSize = FALSE;
1046 }
1047
1048 return max_height;
1049}
1050
1051/*!
1052 Returns the height that the menu would resize itself to if its
1053 parent (and hence itself) resized to the given \a max_width. This
1054 can be useful for simple layout tasks in which the height of the
1055 menu bar is needed after items have been inserted. See \l
1056 showimg/showimg.cpp for an example of the usage.
1057*/
1058int QMenuBar::heightForWidth(int max_width) const
1059{
1060 // Okay to cast away const, as we are not updating.
1061 if ( max_width < 0 ) max_width = 0;
1062 return ((QMenuBar*)this)->calculateRects( max_width );
1063}
1064
1065/*!
1066 \internal
1067 Return the bounding rectangle for the menu item at position \a index.
1068*/
1069
1070QRect QMenuBar::itemRect( int index )
1071{
1072 calculateRects();
1073 return irects ? irects[index] : QRect(0,0,0,0);
1074}
1075
1076/*!
1077 \internal
1078 Return the item at \a pos, or -1 if there is no item there or if
1079 it is a separator item.
1080*/
1081
1082int QMenuBar::itemAtPos( const QPoint &pos_ )
1083{
1084 calculateRects();
1085 if ( !irects )
1086 return -1;
1087 int i = 0;
1088 QPoint pos = pos_;
1089 // Fitts' Law for edges - compensate for the extra margin
1090 // added in calculateRects()
1091 const int margin = 2;
1092 pos.setX( QMAX( margin, QMIN( width() - margin, pos.x())));
1093 pos.setY( QMAX( margin, QMIN( height() - margin, pos.y())));
1094 while ( i < (int)mitems->count() ) {
1095 if ( !irects[i].isEmpty() && irects[i].contains( pos ) ) {
1096 QMenuItem *mi = mitems->at(i);
1097 return mi->isSeparator() ? -1 : i;
1098 }
1099 ++i;
1100 }
1101 return -1; // no match
1102}
1103
1104
1105/*!
1106 \property QMenuBar::separator
1107 \brief in which cases a menubar sparator is drawn
1108
1109 \obsolete
1110*/
1111void QMenuBar::setSeparator( Separator when )
1112{
1113 mseparator = when;
1114}
1115
1116QMenuBar::Separator QMenuBar::separator() const
1117{
1118 return mseparator ? InWindowsStyle : Never;
1119}
1120
1121/*****************************************************************************
1122 Event handlers
1123 *****************************************************************************/
1124
1125/*!
1126 Called from QFrame::paintEvent(). Draws the menu bar contents
1127 using painter \a p.
1128*/
1129
1130void QMenuBar::drawContents( QPainter *p )
1131{
1132 performDelayedChanges();
1133 QRegion reg( contentsRect() );
1134 QColorGroup g = colorGroup();
1135 bool e;
1136
1137 // this shouldn't happen
1138 if ( !irects )
1139 return;
1140
1141 for ( int i=0; i<(int)mitems->count(); i++ ) {
1142 QMenuItem *mi = mitems->at( i );
1143 if ( !mi->text().isNull() || mi->pixmap() ) {
1144 QRect r = irects[i];
1145 if(r.isEmpty() || !mi->isVisible())
1146 continue;
1147 e = mi->isEnabledAndVisible();
1148 if ( e )
1149 g = isEnabled() ? ( isActiveWindow() ? palette().active() :
1150 palette().inactive() ) : palette().disabled();
1151 else
1152 g = palette().disabled();
1153 reg = reg.subtract( r );
1154 QSharedDoubleBuffer buffer( p, r );
1155 buffer.painter()->setFont( p->font() );
1156 buffer.painter()->setPen( p->pen() );
1157 buffer.painter()->setBrush( p->brush() );
1158
1159 QStyle::SFlags flags = QStyle::Style_Default;
1160 if (isEnabled() && e)
1161 flags |= QStyle::Style_Enabled;
1162 if ( i == actItem )
1163 flags |= QStyle::Style_Active;
1164 if ( actItemDown )
1165 flags |= QStyle::Style_Down;
1166 if (hasFocus() || hasmouse || popupvisible)
1167 flags |= QStyle::Style_HasFocus;
1168 style().drawControl(QStyle::CE_MenuBarItem, buffer.painter(), this,
1169 r, g, flags, QStyleOption(mi));
1170 }
1171 }
1172
1173 p->save();
1174 p->setClipRegion(reg);
1175 style().drawControl(QStyle::CE_MenuBarEmptyArea, p, this, contentsRect(), g);
1176 p->restore();
1177
1178#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
1179 if ( !mac_eaten_menubar )
1180#endif
1181 {
1182 Qt::GUIStyle gs = (Qt::GUIStyle) style().styleHint(QStyle::SH_GUIStyle);
1183 if ( mseparator == InWindowsStyle && gs == WindowsStyle ) {
1184 p->setPen( g.light() );
1185 p->drawLine( 0, height()-1, width()-1, height()-1 );
1186 p->setPen( g.dark() );
1187 p->drawLine( 0, height()-2, width()-1, height()-2 );
1188 }
1189 }
1190}
1191
1192
1193/*!
1194 \reimp
1195*/
1196void QMenuBar::mousePressEvent( QMouseEvent *e )
1197{
1198 if ( e->button() != LeftButton )
1199 return;
1200 mouseBtDn = TRUE; // mouse button down
1201 int item = itemAtPos( e->pos() );
1202 if ( item == actItem && popupvisible )
1203 toggleclose = 1;
1204 if ( item >= 0 ) {
1205 QFocusEvent::Reason oldReason = QFocusEvent::reason();
1206 QMenuItem *mi = findItem( idAt( item ) );
1207 // we know that a popup will open, so set the reason to avoid
1208 // itemviews to redraw their selections
1209 if ( mi && mi->popup() )
1210 QFocusEvent::setReason( QFocusEvent::Popup );
1211 setAltMode( TRUE );
1212 QFocusEvent::setReason( oldReason );
1213 }
1214 setActiveItem( item, TRUE, FALSE );
1215}
1216
1217
1218/*!
1219 \reimp
1220*/
1221void QMenuBar::mouseReleaseEvent( QMouseEvent *e )
1222{
1223 if ( e->button() != LeftButton )
1224 return;
1225 if ( !mouseBtDn )
1226 return;
1227 mouseBtDn = FALSE; // mouse button up
1228 int item = itemAtPos( e->pos() );
1229 if ( item >= 0 && !mitems->at(item)->isEnabledAndVisible() ||
1230 actItem >= 0 && !mitems->at(actItem)->isEnabledAndVisible() ) {
1231 hidePopups();
1232 setActiveItem( -1 );
1233 return;
1234 }
1235 bool showMenu = TRUE;
1236 if ( toggleclose &&
1237 // pressing an item twice closes in windows, but not in motif :/
1238 style().styleHint(QStyle::SH_GUIStyle) == WindowsStyle &&
1239 actItem == item ) {
1240 showMenu = FALSE;
1241 setAltMode( FALSE );
1242 }
1243 setActiveItem( item, showMenu, !hasMouseTracking() );
1244 toggleclose = 0;
1245}
1246
1247
1248/*!
1249 \reimp
1250*/
1251void QMenuBar::mouseMoveEvent( QMouseEvent *e )
1252{
1253 int item = itemAtPos( e->pos() );
1254 if ( !mouseBtDn && !popupvisible) {
1255 if ( item >= 0 ) {
1256 if ( !hasmouse ) {
1257 hasmouse = 1;
1258 if ( actItem == item )
1259 actItem = -1; // trigger update
1260 }
1261 }
1262 setActiveItem( item, FALSE, FALSE );
1263 return;
1264 }
1265 if ( item != actItem && item >= 0 && ( popupvisible || mouseBtDn ) )
1266 setActiveItem( item, TRUE, FALSE );
1267}
1268
1269
1270/*!
1271 \reimp
1272*/
1273void QMenuBar::leaveEvent( QEvent * e )
1274{
1275 hasmouse = 0;
1276 int actId = idAt( actItem );
1277 if ( !hasFocus() && !popupvisible )
1278 actItem = -1;
1279 updateItem( actId );
1280 QFrame::leaveEvent( e );
1281}
1282
1283
1284/*!
1285 \reimp
1286*/
1287void QMenuBar::keyPressEvent( QKeyEvent *e )
1288{
1289 if ( actItem < 0 )
1290 return;
1291
1292 QMenuItem *mi = 0;
1293 int dx = 0;
1294
1295 if ( e->state() & Qt::ControlButton &&
1296 ( e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab ) )
1297 {
1298 e->ignore();
1299 return;
1300 }
1301
1302 switch ( e->key() ) {
1303 case Key_Left:
1304 dx = QApplication::reverseLayout() ? 1 : -1;
1305 break;
1306
1307 case Key_Right:
1308 case Key_Tab:
1309 dx = QApplication::reverseLayout() ? -1 : 1;
1310 break;
1311
1312 case Key_Up:
1313 case Key_Down:
1314 case Key_Enter:
1315 case Key_Return:
1316 if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation) )
1317 setActiveItem( actItem );
1318 break;
1319
1320 case Key_Escape:
1321 setAltMode( FALSE );
1322 break;
1323 }
1324
1325 if ( dx ) { // highlight next/prev
1326 register int i = actItem;
1327 int c = mitems->count();
1328 int n = c;
1329 while ( n-- ) {
1330 i = i + dx;
1331 if ( i == c )
1332 i = 0;
1333 else if ( i < 0 )
1334 i = c - 1;
1335 mi = mitems->at( i );
1336 // ### fix windows-style traversal - currently broken due to
1337 // QMenuBar's reliance on QPopupMenu
1338 if ( /* (style() == WindowsStyle || */ mi->isEnabledAndVisible() /* ) */
1339 && !mi->isSeparator() )
1340 break;
1341 }
1342 setActiveItem( i, popupvisible );
1343 } else if ( ( !e->state() || (e->state()&(MetaButton|AltButton)) ) && e->text().length()==1 && !popupvisible ) {
1344 QChar c = e->text()[0].upper();
1345
1346 QMenuItemListIt it(*mitems);
1347 QMenuItem* first = 0;
1348 QMenuItem* currentSelected = 0;
1349 QMenuItem* firstAfterCurrent = 0;
1350
1351 register QMenuItem *m;
1352 int indx = 0;
1353 int clashCount = 0;
1354 while ( (m=it.current()) ) {
1355 ++it;
1356 QString s = m->text();
1357 if ( !s.isEmpty() ) {
1358 int i = s.find( '&' );
1359 if ( i >= 0 )
1360 {
1361 if ( s[i+1].upper() == c ) {
1362 clashCount++;
1363 if ( !first )
1364 first = m;
1365 if ( indx == actItem )
1366 currentSelected = m;
1367 else if ( !firstAfterCurrent && currentSelected )
1368 firstAfterCurrent = m;
1369 }
1370 }
1371 }
1372 indx++;
1373 }
1374 if ( 0 == clashCount ) {
1375 return;
1376 } else if ( 1 == clashCount ) {
1377 indx = indexOf( first->id() );
1378 } else {
1379 // If there's clashes and no one is selected, use first one
1380 // or if there is no clashes _after_ current, use first one
1381 if ( !currentSelected || (currentSelected && !firstAfterCurrent))
1382 indx = indexOf( first->id() );
1383 else
1384 indx = indexOf( firstAfterCurrent->id() );
1385 }
1386
1387 setActiveItem( indx );
1388 }
1389}
1390
1391
1392/*!
1393 \reimp
1394*/
1395void QMenuBar::resizeEvent( QResizeEvent *e )
1396{
1397 QFrame::resizeEvent( e );
1398 if ( badSize )
1399 return;
1400 badSize = TRUE;
1401 calculateRects();
1402}
1403
1404/*
1405 Sets actItem to \a i and calls repaint for the changed things.
1406
1407 Takes care to optimize the repainting. Assumes that
1408 calculateRects() has been called as appropriate.
1409*/
1410
1411void QMenuBar::setActiveItem( int i, bool show, bool activate_first_item )
1412{
1413 if ( i == actItem && (uint)show == popupvisible )
1414 return;
1415
1416 QMenuItem* mi = 0;
1417 if ( i >= 0 )
1418 mi = mitems->at( i );
1419 if ( mi && !mi->isEnabledAndVisible() )
1420 return;
1421
1422 popupvisible = i >= 0 ? (show) : 0;
1423 actItemDown = popupvisible;
1424
1425 if ( i < 0 || actItem < 0 ) {
1426 // just one item needs repainting
1427 int n = QMAX( actItem, i );
1428 actItem = i;
1429 if ( irects && n >= 0 )
1430 repaint( irects[n], FALSE );
1431 } else if ( QABS(i-actItem) == 1 ) {
1432 // two neighbouring items need repainting
1433 int o = actItem;
1434 actItem = i;
1435 if ( irects )
1436 repaint( irects[i].unite( irects[o] ), FALSE );
1437 } else {
1438 // two non-neighbouring items need repainting
1439 int o = actItem;
1440 actItem = i;
1441 if ( irects ) {
1442 repaint( irects[o], FALSE );
1443 repaint( irects[i], FALSE );
1444 }
1445 }
1446
1447 hidePopups();
1448
1449 if ( !popupvisible && actItem >= 0 && irects ) {
1450 QRect mfrect = irects[actItem];
1451 setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
1452 }
1453
1454#if defined(QT_ACCESSIBILITY_SUPPORT)
1455 if ( mi )
1456 QAccessible::updateAccessibility( this, indexOf( mi->id() )+1, QAccessible::Focus );
1457#endif
1458
1459 if ( actItem < 0 || !popupvisible || !mi )
1460 return;
1461
1462 QPopupMenu *popup = mi->popup();
1463 if ( popup ) {
1464 emit highlighted( mi->id() );
1465 openActPopup();
1466 if ( activate_first_item )
1467 popup->setFirstItemActive();
1468 } else { // not a popup
1469 goodbye( FALSE );
1470 if ( mi->signal() ) // activate signal
1471 mi->signal()->activate();
1472 emit activated( mi->id() );
1473 }
1474}
1475
1476
1477void QMenuBar::setAltMode( bool enable )
1478{
1479#if defined(QT_ACCESSIBILITY_SUPPORT)
1480 if ( inMenu && !enable ) {
1481 QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
1482 inMenu = FALSE;
1483 } else if ( !inMenu && enable ) {
1484 QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
1485 inMenu = TRUE;
1486 }
1487#endif
1488
1489 waitforalt = 0;
1490 actItemDown = FALSE;
1491 if ( enable ) {
1492 if ( !QMenuData::d->aWidget )
1493 QMenuData::d->aWidget = qApp->focusWidget();
1494 setFocus();
1495 updateItem( idAt( actItem ) );
1496 } else {
1497 // set the focus back to the previous widget if
1498 // we still have the focus.
1499 if ( qApp->focusWidget() == this ) {
1500 if ( QMenuData::d->aWidget )
1501 QMenuData::d->aWidget->setFocus();
1502 else
1503 clearFocus();
1504 }
1505 int actId = idAt( actItem );
1506 actItem = -1;
1507 updateItem( actId );
1508 QMenuData::d->aWidget = 0;
1509 }
1510}
1511
1512/*!
1513 Sets up keyboard accelerators for the menu bar.
1514*/
1515#ifndef QT_NO_ACCEL
1516
1517void QMenuBar::setupAccelerators()
1518{
1519 delete autoaccel;
1520 autoaccel = 0;
1521
1522 QMenuItemListIt it(*mitems);
1523 register QMenuItem *mi;
1524 while ( (mi=it.current()) ) {
1525 ++it;
1526 if ( !mi->isEnabledAndVisible() ) // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
1527 continue;
1528 QString s = mi->text();
1529 if ( !s.isEmpty() ) {
1530 int i = QAccel::shortcutKey( s );
1531 if ( i ) {
1532 if ( !autoaccel ) {
1533 autoaccel = new QAccel( this );
1534 Q_CHECK_PTR( autoaccel );
1535 autoaccel->setIgnoreWhatsThis( TRUE );
1536 connect( autoaccel, SIGNAL(activated(int)),
1537 SLOT(accelActivated(int)) );
1538 connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
1539 SLOT(accelActivated(int)) );
1540 connect( autoaccel, SIGNAL(destroyed()),
1541 SLOT(accelDestroyed()) );
1542 }
1543 autoaccel->insertItem( i, mi->id() );
1544 }
1545 }
1546 if ( mi->popup() ) {
1547 QPopupMenu* popup = mi->popup();
1548 popup->updateAccel( this );
1549 if ( !popup->isEnabled() )
1550 popup->enableAccel( FALSE );
1551 }
1552 }
1553}
1554#endif
1555
1556/*!
1557 \reimp
1558 */
1559bool QMenuBar::customWhatsThis() const
1560{
1561 return TRUE;
1562}
1563
1564
1565
1566/*!
1567 \reimp
1568 */
1569void QMenuBar::focusInEvent( QFocusEvent * )
1570{
1571 if ( actItem < 0 ) {
1572 int i = -1;
1573 while ( actItem < 0 && ++i < (int) mitems->count() ) {
1574 QMenuItem* mi = mitems->at( i );
1575 if ( mi && mi->isEnabledAndVisible() && !mi->isSeparator() )
1576 setActiveItem( i, FALSE );
1577 }
1578 } else if ( !popupvisible ) {
1579 updateItem( idAt( actItem ) );
1580 }
1581}
1582
1583/*!
1584 \reimp
1585 */
1586void QMenuBar::focusOutEvent( QFocusEvent * )
1587{
1588 updateItem( idAt( actItem ) );
1589 if ( !popupvisible )
1590 setAltMode( FALSE );
1591}
1592
1593/*!
1594 \reimp
1595*/
1596
1597QSize QMenuBar::sizeHint() const
1598{
1599 int h = height();
1600 if ( badSize )
1601 h = ( (QMenuBar*)this )->calculateRects();
1602 QSize s( 2*frameWidth(),0);
1603 if ( irects ) {
1604 for ( int i = 0; i < (int)mitems->count(); ++i )
1605 s.setWidth( s.width() + irects[ i ].width() + 2 );
1606 }
1607 s.setHeight( h );
1608 return (style().sizeFromContents(QStyle::CT_MenuBar, this, s.
1609 expandedTo(QApplication::globalStrut())));
1610}
1611
1612/*!
1613 \reimp
1614*/
1615
1616QSize QMenuBar::minimumSize() const
1617{
1618#ifndef QT_NO_TOOLBAR
1619 QToolBar *tb = ::qt_cast<QToolBar*>(parent());
1620 if ( tb )
1621 return sizeHint();
1622#endif
1623 return QFrame::minimumSize();
1624}
1625
1626/*!
1627 \reimp
1628*/
1629
1630QSize QMenuBar::minimumSizeHint() const
1631{
1632 return minimumSize();
1633}
1634
1635/*!
1636 \property QMenuBar::defaultUp
1637 \brief the popup orientation
1638
1639 The default popup orientation. By default, menus pop "down" the
1640 screen. By setting the property to TRUE, the menu will pop "up".
1641 You might call this for menus that are \e below the document to
1642 which they refer.
1643
1644 If the menu would not fit on the screen, the other direction is
1645 used automatically.
1646*/
1647void QMenuBar::setDefaultUp( bool on )
1648{
1649 defaultup = on;
1650}
1651
1652bool QMenuBar::isDefaultUp() const
1653{
1654 return defaultup;
1655}
1656
1657
1658/*!
1659 \reimp
1660 */
1661void QMenuBar::activateItemAt( int index )
1662{
1663 if ( index >= 0 && index < (int) mitems->count() )
1664 setActiveItem( index );
1665 else
1666 goodbye( FALSE );
1667}
1668
1669#endif // QT_NO_MENUBAR
Note: See TracBrowser for help on using the repository browser.