source: vendor/trolltech/current/src/widgets/qmenubar.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 44.4 KB
Line 
1/****************************************************************************
2** $Id: qmenubar.cpp 2 2005-11-16 15:49:26Z 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 setGeometry( 0, 0, width(), h );
298
299 setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
300}
301
302
303
304/*! \reimp */
305
306void QMenuBar::styleChange( QStyle& old )
307{
308 setMouseTracking( style().styleHint(QStyle::SH_MenuBar_MouseTracking) );
309 QFrame::styleChange( old );
310}
311
312
313
314/*!
315 Destroys the menu bar.
316*/
317
318QMenuBar::~QMenuBar()
319{
320#ifndef QT_NO_ACCEL
321 delete autoaccel;
322#endif
323#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
324 macRemoveNativeMenubar();
325#endif
326 if ( irects ) // Avoid purify complaint.
327 delete [] irects;
328}
329
330/*!
331 \internal
332
333 Repaints the menu item with id \a id; does nothing if there is no
334 such menu item.
335*/
336void QMenuBar::updateItem( int id )
337{
338 int i = indexOf( id );
339 if ( i >= 0 && irects )
340 repaint( irects[i], FALSE );
341}
342
343#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
344static bool fromFrameChange = FALSE;
345#endif
346
347/*!
348 Recomputes the menu bar's display data according to the new
349 contents.
350
351 You should never need to call this; it is called automatically by
352 QMenuData whenever it needs to be called.
353*/
354
355void QMenuBar::menuContentsChanged()
356{
357 // here the part that can't be delayed
358 QMenuData::menuContentsChanged();
359 badSize = TRUE; // might change the size
360 if( pendingDelayedContentsChanges )
361 return;
362 pendingDelayedContentsChanges = 1;
363 if( !pendingDelayedStateChanges )// if the timer hasn't been started yet
364 QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
365}
366
367void QMenuBar::performDelayedContentsChanged()
368{
369 pendingDelayedContentsChanges = 0;
370 // here the part the can be delayed
371#ifndef QT_NO_ACCEL
372 // if performDelayedStateChanged() will be called too,
373 // it will call setupAccelerators() too, no need to do it twice
374 if( !pendingDelayedStateChanges )
375 setupAccelerators();
376#endif
377 calculateRects();
378 if ( isVisible() ) {
379 update();
380#ifndef QT_NO_MAINWINDOW
381 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
382 if ( mw ) {
383 mw->triggerLayout();
384 mw->update();
385 }
386#endif
387#ifndef QT_NO_LAYOUT
388 if ( parentWidget() && parentWidget()->layout() )
389 parentWidget()->layout()->activate();
390#endif
391 }
392}
393
394/*!
395 Recomputes the menu bar's display data according to the new state.
396
397 You should never need to call this; it is called automatically by
398 QMenuData whenever it needs to be called.
399*/
400
401void QMenuBar::menuStateChanged()
402{
403 if( pendingDelayedStateChanges )
404 return;
405 pendingDelayedStateChanges = 1;
406 if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
407 QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
408}
409
410void QMenuBar::performDelayedStateChanged()
411{
412 pendingDelayedStateChanges = 0;
413 // here the part that can be delayed
414#ifndef QT_NO_ACCEL
415 setupAccelerators(); // ### when we have a good solution for the accel vs. focus
416 // widget problem, remove that. That is only a workaround
417 // if you remove this, see performDelayedContentsChanged()
418#endif
419 update();
420}
421
422
423void QMenuBar::performDelayedChanges()
424{
425#if defined(Q_WS_MAC) && !defined(QMAC_MENUBAR_NO_NATIVE)
426 // I must do this here as the values change in the function below.
427 bool needMacUpdate = (pendingDelayedContentsChanges || pendingDelayedStateChanges);
428#endif
429 if( pendingDelayedContentsChanges )
430 performDelayedContentsChanged();
431 if( pendingDelayedStateChanges )
432 performDelayedStateChanged();
433#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
434 if(mac_eaten_menubar && needMacUpdate) {
435 macDirtyNativeMenubar();
436
437 bool all_hidden = TRUE;
438 if(irects) {
439 for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
440 all_hidden = irects[i].isEmpty();
441 }
442 if( all_hidden ) {
443 if( !isHidden())
444 hide();
445 } else {
446 if( !isShown() && !fromFrameChange )
447 show();
448 }
449 }
450#endif
451}
452
453
454void QMenuBar::menuInsPopup( QPopupMenu *popup )
455{
456 connect( popup, SIGNAL(activatedRedirect(int)),
457 SLOT(subActivated(int)) );
458 connect( popup, SIGNAL(highlightedRedirect(int)),
459 SLOT(subHighlighted(int)) );
460 connect( popup, SIGNAL(destroyed(QObject*)),
461 this, SLOT(popupDestroyed(QObject*)) );
462}
463
464void QMenuBar::menuDelPopup( QPopupMenu *popup )
465{
466 popup->disconnect( SIGNAL(activatedRedirect(int)) );
467 popup->disconnect( SIGNAL(highlightedRedirect(int)) );
468 disconnect( popup, SIGNAL(destroyed(QObject*)),
469 this, SLOT(popupDestroyed(QObject*)) );
470}
471
472void QMenuBar::frameChanged()
473{
474#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
475 fromFrameChange = TRUE;
476#endif
477 menuContentsChanged();
478#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
479 fromFrameChange = FALSE;
480#endif
481}
482
483void QMenuBar::languageChange()
484{
485 menuContentsChanged();
486}
487
488/*!
489 \internal
490
491 This function is used to adjust the menu bar's geometry to the
492 parent widget's geometry. Note that this is \e not part of the
493 public interface - the function is \c public only because
494 QObject::eventFilter() is.
495
496 Resizes the menu bar to fit in the parent widget when the parent
497 receives a resize event.
498*/
499
500bool QMenuBar::eventFilter( QObject *object, QEvent *event )
501{
502 if ( object == parent() && object
503#ifndef QT_NO_TOOLBAR
504 && !::qt_cast<QToolBar*>(object)
505#endif
506 && event->type() == QEvent::Resize ) {
507 QResizeEvent *e = (QResizeEvent *)event;
508 int w = e->size().width();
509 setGeometry( 0, y(), w, heightForWidth(w) );
510 return FALSE;
511 }
512
513 if ( !isVisible() || !object->isWidgetType() )
514 return FALSE;
515
516 if ( object == this && event->type() == QEvent::LanguageChange ) {
517 badSize = TRUE;
518 calculateRects();
519 return FALSE;
520 } else if ( event->type() == QEvent::MouseButtonPress ||
521 event->type() == QEvent::MouseButtonRelease ) {
522 waitforalt = 0;
523 return FALSE;
524 } else if ( waitforalt && event->type() == QEvent::FocusOut ) {
525 // some window systems/managers use alt/meta as accelerator keys
526 // for switching between windows/desktops/etc. If the focus
527 // widget gets unfocused, then we need to stop waiting for alt
528 // NOTE: this event came from the real focus widget, so we don't
529 // need to touch the event filters
530 waitforalt = 0;
531 // although the comment above said not to remove the event filter, it is
532 // incorrect. We need to remove our self fom the focused widget as normally
533 // this happens in the key release but it does not happen in this case
534 QWidget * f = ((QWidget *)object)->focusWidget();
535 if (f)
536 f->removeEventFilter( this );
537 return FALSE;
538 } else if ( !( event->type() == QEvent::Accel ||
539 event->type() == QEvent::AccelOverride ||
540 event->type() == QEvent::KeyPress ||
541 event->type() == QEvent::KeyRelease ) ||
542 !style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) ) {
543 return FALSE;
544 }
545
546 QKeyEvent * ke = (QKeyEvent *) event;
547#ifndef QT_NO_ACCEL
548 // look for Alt press and Alt-anything press
549 if ( event->type() == QEvent::Accel ) {
550 QWidget * f = ((QWidget *)object)->focusWidget();
551 // ### this thinks alt and meta are the same
552 if ( ke->key() == Key_Alt || ke->key() == Key_Meta ) {
553 // A new Alt press and we wait for release, eat
554 // this key and don't wait for Alt on this widget
555 if ( waitforalt ) {
556 waitforalt = 0;
557 if ( object->parent() )
558 object->removeEventFilter( this );
559 ke->accept();
560 return TRUE;
561 // Menu has focus, send focus back
562 } else if ( hasFocus() ) {
563 setAltMode( FALSE );
564 ke->accept();
565 return TRUE;
566 // Start waiting for Alt release on focus widget
567 } else if ( ke->stateAfter() == AltButton ) {
568 waitforalt = 1;
569#if defined(Q_WS_X11)
570 QMenuData::d->aInt = qt_xfocusout_grab_counter;
571#endif
572 if ( f && f != object )
573 f->installEventFilter( this );
574 }
575 // Other modifiers kills focus on menubar
576 } else if ( ke->key() == Key_Control || ke->key() == Key_Shift) {
577 setAltMode( FALSE );
578 // Got other key, no need to wait for Alt release
579 } else {
580 waitforalt = 0;
581 }
582 // ### ! block all accelerator events when the menu bar is active
583 if ( qApp && qApp->focusWidget() == this ) {
584 return TRUE;
585 }
586
587 return FALSE;
588 }
589#endif
590 // look for Alt release
591 if ( ((QWidget*)object)->focusWidget() == object ||
592 (object->parent() == 0 && ((QWidget*)object)->focusWidget() == 0) ) {
593 if ( waitforalt && event->type() == QEvent::KeyRelease &&
594 ( ke->key() == Key_Alt || ke->key() == Key_Meta )
595#if defined(Q_WS_X11)
596 && QMenuData::d->aInt == qt_xfocusout_grab_counter
597#endif
598 ) {
599 setAltMode( TRUE );
600 if ( object->parent() )
601 object->removeEventFilter( this );
602 QWidget * tlw = ((QWidget *)object)->topLevelWidget();
603 if ( tlw ) {
604 // ### !
605 // make sure to be the first event filter, so we can kill
606 // accelerator events before the accelerators get to them.
607 tlw->removeEventFilter( this );
608 tlw->installEventFilter( this );
609 }
610 return TRUE;
611 // Cancel if next keypress is NOT Alt/Meta,
612 } else if ( !hasFocus() && (event->type() == QEvent::AccelOverride ) &&
613 !(((QKeyEvent *)event)->key() == Key_Alt ||
614 ((QKeyEvent *)event)->key() == Key_Meta) ) {
615 if ( object->parent() )
616 object->removeEventFilter( this );
617 setAltMode( FALSE );
618 }
619 }
620
621 return FALSE; // don't stop event
622}
623
624
625
626/*!
627 \internal
628 Receives signals from menu items.
629*/
630
631void QMenuBar::subActivated( int id )
632{
633 emit activated( id );
634}
635
636/*!
637 \internal
638 Receives signals from menu items.
639*/
640
641void QMenuBar::subHighlighted( int id )
642{
643 emit highlighted( id );
644}
645
646/*!
647 \internal
648 Receives signals from menu accelerator.
649*/
650#ifndef QT_NO_ACCEL
651void QMenuBar::accelActivated( int id )
652{
653#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
654 if(mac_eaten_menubar)
655 return;
656#endif
657 if ( !isEnabled() ) // the menu bar is disabled
658 return;
659 setAltMode( TRUE );
660 setActiveItem( indexOf( id ) );
661}
662#endif
663
664/*!
665 \internal
666 This slot receives signals from menu accelerator when it is about to be
667 destroyed.
668*/
669#ifndef QT_NO_ACCEL
670void QMenuBar::accelDestroyed()
671{
672 autoaccel = 0; // don't delete it twice!
673}
674#endif
675
676void QMenuBar::popupDestroyed( QObject *o )
677{
678 removePopup( (QPopupMenu*)o );
679}
680
681bool QMenuBar::tryMouseEvent( QPopupMenu *, QMouseEvent *e )
682{
683 QPoint pos = mapFromGlobal( e->globalPos() );
684 if ( !rect().contains( pos ) ) // outside
685 return FALSE;
686 int item = itemAtPos( pos );
687 if ( item == -1 && (e->type() == QEvent::MouseButtonPress ||
688 e->type() == QEvent::MouseButtonRelease) ) {
689 hidePopups();
690 goodbye();
691 return FALSE;
692 }
693 QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
694 event( &ee );
695 return TRUE;
696}
697
698
699void QMenuBar::tryKeyEvent( QPopupMenu *, QKeyEvent *e )
700{
701 event( e );
702}
703
704
705void QMenuBar::goodbye( bool cancelled )
706{
707 mouseBtDn = FALSE;
708 popupvisible = 0;
709 setAltMode( cancelled && style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) );
710}
711
712
713void QMenuBar::openActPopup()
714{
715#if defined(QT_ACCESSIBILITY_SUPPORT)
716 if ( !inMenu ) {
717 QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
718 inMenu = TRUE;
719 }
720#endif
721
722 if ( actItem < 0 )
723 return;
724 QPopupMenu *popup = mitems->at(actItem)->popup();
725 if ( !popup || !popup->isEnabled() )
726 return;
727
728 QRect r = itemRect( actItem );
729 bool reverse = QApplication::reverseLayout();
730 const int yoffset = 1; //(style().styleHint( QStyle::SH_GUIStyle ) == QStyle::WindowsStyle) ? 4 : 1; ### this breaks designer mainwindow editing
731 QPoint pos = r.bottomLeft() + QPoint(0,yoffset);
732 if( reverse ) {
733 pos = r.bottomRight() + QPoint(0,yoffset);
734 pos.rx() -= popup->sizeHint().width();
735 }
736
737 int ph = popup->sizeHint().height();
738 pos = mapToGlobal(pos);
739 int sh = QApplication::desktop()->height();
740 if ( defaultup || (pos.y() + ph > sh) ) {
741 QPoint t = mapToGlobal( r.topLeft() );
742 if( reverse ) {
743 t = mapToGlobal( r.topRight() );
744 t.rx() -= popup->sizeHint().width();
745 }
746 t.ry() -= (QCOORD)ph;
747 if ( !defaultup || t.y() >= 0 )
748 pos = t;
749 }
750
751 //avoid circularity
752 if ( popup->isVisible() )
753 return;
754
755 Q_ASSERT( popup->parentMenu == 0 );
756 popup->parentMenu = this; // set parent menu
757
758 popup->snapToMouse = FALSE;
759 popup->popup( pos );
760 popup->snapToMouse = TRUE;
761}
762
763/*!
764 \internal
765 Hides all popup menu items.
766*/
767
768void QMenuBar::hidePopups()
769{
770#if defined(QT_ACCESSIBILITY_SUPPORT)
771 bool anyVisible = FALSE;
772#endif
773 QMenuItemListIt it(*mitems);
774 register QMenuItem *mi;
775 while ( (mi=it.current()) ) {
776 ++it;
777 if ( mi->popup() && mi->popup()->isVisible() ) {
778#if defined(QT_ACCESSIBILITY_SUPPORT)
779 anyVisible = TRUE;
780#endif
781 mi->popup()->hide();
782 }
783 }
784#if defined(QT_ACCESSIBILITY_SUPPORT)
785 if ( !popupvisible && anyVisible && inMenu ) {
786 QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
787 inMenu = FALSE;
788 }
789#endif
790}
791
792
793/*!
794 Reimplements QWidget::show() in order to set up the correct
795 keyboard accelerators and to raise itself to the top of the widget
796 stack.
797*/
798
799void QMenuBar::show()
800{
801#ifndef QT_NO_ACCEL
802 setupAccelerators();
803#endif
804
805 if ( parentWidget() )
806 resize( parentWidget()->width(), height() );
807
808 QApplication::sendPostedEvents( this, QEvent::Resize );
809 performDelayedChanges();
810 calculateRects();
811
812#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
813 if(mac_eaten_menubar) {
814 //If all elements are invisible no reason for me to be visible either
815 bool all_hidden = TRUE;
816 if(irects) {
817 for(int i = 0; all_hidden && i < (int)mitems->count(); i++)
818 all_hidden = irects[i].isEmpty();
819 }
820 if(all_hidden)
821 QWidget::hide();
822 else
823 QWidget::show();
824 } else {
825 QWidget::show();
826 }
827#else
828 QWidget::show();
829#endif
830
831#ifndef QT_NO_MAINWINDOW
832 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
833 if ( mw ) //### ugly workaround
834 mw->triggerLayout();
835#endif
836 raise();
837}
838
839/*!
840 Reimplements QWidget::hide() in order to deselect any selected
841 item, and calls setUpLayout() for the main window.
842*/
843
844void QMenuBar::hide()
845{
846 QWidget::hide();
847 setAltMode( FALSE );
848 hidePopups();
849#ifndef QT_NO_MAINWINDOW
850 QMainWindow *mw = ::qt_cast<QMainWindow*>(parent());
851 if ( mw ) //### ugly workaround
852 mw->triggerLayout();
853#endif
854}
855
856/*!
857 \internal
858 Needs to change the size of the menu bar when a new font is set.
859*/
860
861void QMenuBar::fontChange( const QFont & f )
862{
863 badSize = TRUE;
864 updateGeometry();
865 if ( isVisible() )
866 calculateRects();
867 QWidget::fontChange( f );
868}
869
870
871/*****************************************************************************
872 Item geometry functions
873 *****************************************************************************/
874
875/*
876 This function serves two different purposes. If the parameter is
877 negative, it updates the irects member for the current width and
878 resizes. Otherwise, it does the same calculations for the GIVEN
879 width and returns the height to which it WOULD have resized. A bit
880 tricky, but both operations require almost identical steps.
881*/
882int QMenuBar::calculateRects( int max_width )
883{
884 polish();
885 bool update = ( max_width < 0 );
886
887 if ( update ) {
888 rightSide = 0;
889 if ( !badSize ) // size was not changed
890 return 0;
891 delete [] irects;
892 int i = mitems->count();
893 if ( i == 0 ) {
894 irects = 0;
895 } else {
896 irects = new QRect[ i ];
897 Q_CHECK_PTR( irects );
898 }
899 max_width = width();
900 }
901 QFontMetrics fm = fontMetrics();
902 int max_height = 0;
903 int max_item_height = 0;
904 int nlitems = 0; // number on items on cur line
905 int gs = style().styleHint(QStyle::SH_GUIStyle);
906 bool reverse = QApplication::reverseLayout();
907 int x = frameWidth();
908 int y = frameWidth();
909 if ( gs == MotifStyle ) {
910 x += motifBarHMargin;
911 y += motifBarVMargin;
912 } else if ( gs == WindowsStyle ) {
913 x += 2;
914 y += 2;
915 }
916 if ( reverse )
917 x = max_width - x;
918
919 int i = 0;
920 int separator = -1;
921 const int itemSpacing = style().pixelMetric(QStyle::PM_MenuBarItemSpacing);
922 const int lastItem = reverse ? 0 : mitems->count() - 1;
923
924 while ( i < (int)mitems->count() ) { // for each menu item...
925 QMenuItem *mi = mitems->at(i);
926
927 int w=0, h=0;
928 if ( !mi->isVisible()
929#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
930 || (mac_eaten_menubar && !mi->custom() && !mi->widget() )
931#endif
932 ) {
933 ; // empty rectangle
934 } else if ( mi->widget() ) {
935 if ( mi->widget()->parentWidget() != this ) {
936 mi->widget()->reparent( this, QPoint(0,0) );
937 }
938 w = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).width()+2;
939 h = mi->widget()->sizeHint().expandedTo( QApplication::globalStrut() ).height()+2;
940 if ( i && separator < 0 )
941 separator = i;
942 } else if ( mi->pixmap() ) { // pixmap item
943 w = QMAX( mi->pixmap()->width() + 4, QApplication::globalStrut().width() );
944 h = QMAX( mi->pixmap()->height() + 4, QApplication::globalStrut().height() );
945 } else if ( !mi->text().isNull() ) { // text item
946 QString s = mi->text();
947 w = fm.boundingRect( s ).width()
948 + 2*motifItemHMargin;
949 w -= s.contains('&')*fm.width('&');
950 w += s.contains("&&")*fm.width('&');
951 w = QMAX( w, QApplication::globalStrut().width() );
952 h = QMAX( fm.height() + motifItemVMargin, QApplication::globalStrut().height() );
953 } else if ( mi->isSeparator() ) { // separator item
954 if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
955 separator = i; //### only motif?
956 }
957 if ( !mi->isSeparator() || mi->widget() ) {
958#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
959 if ( !mac_eaten_menubar ) {
960#endif
961 if ( gs == MotifStyle ) {
962 w += 2*motifItemFrame;
963 h += 2*motifItemFrame;
964 }
965#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
966 }
967#endif
968
969 if ( ( ( !reverse && x + w + frameWidth() - max_width > 0 ) ||
970 ( reverse && x - w - itemSpacing - frameWidth() < 0 ) )
971 && nlitems > 0 ) {
972 nlitems = 0;
973 x = frameWidth();
974 y += h;
975 if ( gs == MotifStyle ) {
976 x += motifBarHMargin;
977 y += motifBarVMargin;
978 }
979 if ( reverse )
980 x = max_width - x + itemSpacing;
981 if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle )
982 separator = -1;
983 }
984 if ( y + h + 2*frameWidth() > max_height )
985 max_height = y + h + 2*frameWidth();
986 if ( h > max_item_height )
987 max_item_height = h;
988 }
989
990 const bool isLast = (i == lastItem);
991
992 if( reverse ) {
993 x -= w;
994 if (!isLast && !mi->isSeparator())
995 x -= itemSpacing;
996 }
997 if ( update ) {
998 irects[i].setRect( x, y, w, h );
999 }
1000 if ( !reverse ) {
1001 x += w;
1002 if (!isLast && !mi->isSeparator())
1003 x += itemSpacing;
1004 }
1005 nlitems++;
1006 i++;
1007 }
1008 if ( gs == WindowsStyle ) {
1009 max_height += 2;
1010 max_width += 2;
1011 }
1012
1013 if ( update ) {
1014 if ( separator >= 0 ) {
1015 int moveBy = reverse ? - x - frameWidth() : max_width - x - frameWidth();
1016 rightSide = x;
1017 while( --i >= separator ) {
1018 irects[i].moveBy( moveBy, 0 );
1019 }
1020 } else {
1021 rightSide = width()-frameWidth();
1022 }
1023 if ( max_height != height() )
1024 resize( width(), max_height );
1025 for ( i = 0; i < (int)mitems->count(); i++ ) {
1026 irects[i].setHeight( max_item_height );
1027 QMenuItem *mi = mitems->at(i);
1028 if ( mi->widget() ) {
1029 QRect r ( QPoint(0,0), mi->widget()->sizeHint() );
1030 r.moveCenter( irects[i].center() );
1031 mi->widget()->setGeometry( r );
1032 if( mi->widget()->isHidden() )
1033 mi->widget()->show();
1034 }
1035 }
1036 badSize = FALSE;
1037 }
1038
1039 return max_height;
1040}
1041
1042/*!
1043 Returns the height that the menu would resize itself to if its
1044 parent (and hence itself) resized to the given \a max_width. This
1045 can be useful for simple layout tasks in which the height of the
1046 menu bar is needed after items have been inserted. See \l
1047 showimg/showimg.cpp for an example of the usage.
1048*/
1049int QMenuBar::heightForWidth(int max_width) const
1050{
1051 // Okay to cast away const, as we are not updating.
1052 if ( max_width < 0 ) max_width = 0;
1053 return ((QMenuBar*)this)->calculateRects( max_width );
1054}
1055
1056/*!
1057 \internal
1058 Return the bounding rectangle for the menu item at position \a index.
1059*/
1060
1061QRect QMenuBar::itemRect( int index )
1062{
1063 calculateRects();
1064 return irects ? irects[index] : QRect(0,0,0,0);
1065}
1066
1067/*!
1068 \internal
1069 Return the item at \a pos, or -1 if there is no item there or if
1070 it is a separator item.
1071*/
1072
1073int QMenuBar::itemAtPos( const QPoint &pos_ )
1074{
1075 calculateRects();
1076 if ( !irects )
1077 return -1;
1078 int i = 0;
1079 QPoint pos = pos_;
1080 // Fitts' Law for edges - compensate for the extra margin
1081 // added in calculateRects()
1082 const int margin = 2;
1083 pos.setX( QMAX( margin, QMIN( width() - margin, pos.x())));
1084 pos.setY( QMAX( margin, QMIN( height() - margin, pos.y())));
1085 while ( i < (int)mitems->count() ) {
1086 if ( !irects[i].isEmpty() && irects[i].contains( pos ) ) {
1087 QMenuItem *mi = mitems->at(i);
1088 return mi->isSeparator() ? -1 : i;
1089 }
1090 ++i;
1091 }
1092 return -1; // no match
1093}
1094
1095
1096/*!
1097 \property QMenuBar::separator
1098 \brief in which cases a menubar sparator is drawn
1099
1100 \obsolete
1101*/
1102void QMenuBar::setSeparator( Separator when )
1103{
1104 mseparator = when;
1105}
1106
1107QMenuBar::Separator QMenuBar::separator() const
1108{
1109 return mseparator ? InWindowsStyle : Never;
1110}
1111
1112/*****************************************************************************
1113 Event handlers
1114 *****************************************************************************/
1115
1116/*!
1117 Called from QFrame::paintEvent(). Draws the menu bar contents
1118 using painter \a p.
1119*/
1120
1121void QMenuBar::drawContents( QPainter *p )
1122{
1123 performDelayedChanges();
1124 QRegion reg( contentsRect() );
1125 QColorGroup g = colorGroup();
1126 bool e;
1127
1128 // this shouldn't happen
1129 if ( !irects )
1130 return;
1131
1132 for ( int i=0; i<(int)mitems->count(); i++ ) {
1133 QMenuItem *mi = mitems->at( i );
1134 if ( !mi->text().isNull() || mi->pixmap() ) {
1135 QRect r = irects[i];
1136 if(r.isEmpty() || !mi->isVisible())
1137 continue;
1138 e = mi->isEnabledAndVisible();
1139 if ( e )
1140 g = isEnabled() ? ( isActiveWindow() ? palette().active() :
1141 palette().inactive() ) : palette().disabled();
1142 else
1143 g = palette().disabled();
1144 reg = reg.subtract( r );
1145 QSharedDoubleBuffer buffer( p, r );
1146 buffer.painter()->setFont( p->font() );
1147 buffer.painter()->setPen( p->pen() );
1148 buffer.painter()->setBrush( p->brush() );
1149
1150 QStyle::SFlags flags = QStyle::Style_Default;
1151 if (isEnabled() && e)
1152 flags |= QStyle::Style_Enabled;
1153 if ( i == actItem )
1154 flags |= QStyle::Style_Active;
1155 if ( actItemDown )
1156 flags |= QStyle::Style_Down;
1157 if (hasFocus() || hasmouse || popupvisible)
1158 flags |= QStyle::Style_HasFocus;
1159 style().drawControl(QStyle::CE_MenuBarItem, buffer.painter(), this,
1160 r, g, flags, QStyleOption(mi));
1161 }
1162 }
1163
1164 p->save();
1165 p->setClipRegion(reg);
1166 style().drawControl(QStyle::CE_MenuBarEmptyArea, p, this, contentsRect(), g);
1167 p->restore();
1168
1169#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
1170 if ( !mac_eaten_menubar )
1171#endif
1172 {
1173 Qt::GUIStyle gs = (Qt::GUIStyle) style().styleHint(QStyle::SH_GUIStyle);
1174 if ( mseparator == InWindowsStyle && gs == WindowsStyle ) {
1175 p->setPen( g.light() );
1176 p->drawLine( 0, height()-1, width()-1, height()-1 );
1177 p->setPen( g.dark() );
1178 p->drawLine( 0, height()-2, width()-1, height()-2 );
1179 }
1180 }
1181}
1182
1183
1184/*!
1185 \reimp
1186*/
1187void QMenuBar::mousePressEvent( QMouseEvent *e )
1188{
1189 if ( e->button() != LeftButton )
1190 return;
1191 mouseBtDn = TRUE; // mouse button down
1192 int item = itemAtPos( e->pos() );
1193 if ( item == actItem && popupvisible )
1194 toggleclose = 1;
1195 if ( item >= 0 ) {
1196 QFocusEvent::Reason oldReason = QFocusEvent::reason();
1197 QMenuItem *mi = findItem( idAt( item ) );
1198 // we know that a popup will open, so set the reason to avoid
1199 // itemviews to redraw their selections
1200 if ( mi && mi->popup() )
1201 QFocusEvent::setReason( QFocusEvent::Popup );
1202 setAltMode( TRUE );
1203 QFocusEvent::setReason( oldReason );
1204 }
1205 setActiveItem( item, TRUE, FALSE );
1206}
1207
1208
1209/*!
1210 \reimp
1211*/
1212void QMenuBar::mouseReleaseEvent( QMouseEvent *e )
1213{
1214 if ( e->button() != LeftButton )
1215 return;
1216 if ( !mouseBtDn )
1217 return;
1218 mouseBtDn = FALSE; // mouse button up
1219 int item = itemAtPos( e->pos() );
1220 if ( item >= 0 && !mitems->at(item)->isEnabledAndVisible() ||
1221 actItem >= 0 && !mitems->at(actItem)->isEnabledAndVisible() ) {
1222 hidePopups();
1223 setActiveItem( -1 );
1224 return;
1225 }
1226 bool showMenu = TRUE;
1227 if ( toggleclose &&
1228 // pressing an item twice closes in windows, but not in motif :/
1229 style().styleHint(QStyle::SH_GUIStyle) == WindowsStyle &&
1230 actItem == item ) {
1231 showMenu = FALSE;
1232 setAltMode( FALSE );
1233 }
1234 setActiveItem( item, showMenu, !hasMouseTracking() );
1235 toggleclose = 0;
1236}
1237
1238
1239/*!
1240 \reimp
1241*/
1242void QMenuBar::mouseMoveEvent( QMouseEvent *e )
1243{
1244 int item = itemAtPos( e->pos() );
1245 if ( !mouseBtDn && !popupvisible) {
1246 if ( item >= 0 ) {
1247 if ( !hasmouse ) {
1248 hasmouse = 1;
1249 if ( actItem == item )
1250 actItem = -1; // trigger update
1251 }
1252 }
1253 setActiveItem( item, FALSE, FALSE );
1254 return;
1255 }
1256 if ( item != actItem && item >= 0 && ( popupvisible || mouseBtDn ) )
1257 setActiveItem( item, TRUE, FALSE );
1258}
1259
1260
1261/*!
1262 \reimp
1263*/
1264void QMenuBar::leaveEvent( QEvent * e )
1265{
1266 hasmouse = 0;
1267 int actId = idAt( actItem );
1268 if ( !hasFocus() && !popupvisible )
1269 actItem = -1;
1270 updateItem( actId );
1271 QFrame::leaveEvent( e );
1272}
1273
1274
1275/*!
1276 \reimp
1277*/
1278void QMenuBar::keyPressEvent( QKeyEvent *e )
1279{
1280 if ( actItem < 0 )
1281 return;
1282
1283 QMenuItem *mi = 0;
1284 int dx = 0;
1285
1286 if ( e->state() & Qt::ControlButton &&
1287 ( e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab ) )
1288 {
1289 e->ignore();
1290 return;
1291 }
1292
1293 switch ( e->key() ) {
1294 case Key_Left:
1295 dx = QApplication::reverseLayout() ? 1 : -1;
1296 break;
1297
1298 case Key_Right:
1299 case Key_Tab:
1300 dx = QApplication::reverseLayout() ? -1 : 1;
1301 break;
1302
1303 case Key_Up:
1304 case Key_Down:
1305 case Key_Enter:
1306 case Key_Return:
1307 if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation) )
1308 setActiveItem( actItem );
1309 break;
1310
1311 case Key_Escape:
1312 setAltMode( FALSE );
1313 break;
1314 }
1315
1316 if ( dx ) { // highlight next/prev
1317 register int i = actItem;
1318 int c = mitems->count();
1319 int n = c;
1320 while ( n-- ) {
1321 i = i + dx;
1322 if ( i == c )
1323 i = 0;
1324 else if ( i < 0 )
1325 i = c - 1;
1326 mi = mitems->at( i );
1327 // ### fix windows-style traversal - currently broken due to
1328 // QMenuBar's reliance on QPopupMenu
1329 if ( /* (style() == WindowsStyle || */ mi->isEnabledAndVisible() /* ) */
1330 && !mi->isSeparator() )
1331 break;
1332 }
1333 setActiveItem( i, popupvisible );
1334 } else if ( ( !e->state() || (e->state()&(MetaButton|AltButton)) ) && e->text().length()==1 && !popupvisible ) {
1335 QChar c = e->text()[0].upper();
1336
1337 QMenuItemListIt it(*mitems);
1338 QMenuItem* first = 0;
1339 QMenuItem* currentSelected = 0;
1340 QMenuItem* firstAfterCurrent = 0;
1341
1342 register QMenuItem *m;
1343 int indx = 0;
1344 int clashCount = 0;
1345 while ( (m=it.current()) ) {
1346 ++it;
1347 QString s = m->text();
1348 if ( !s.isEmpty() ) {
1349 int i = s.find( '&' );
1350 if ( i >= 0 )
1351 {
1352 if ( s[i+1].upper() == c ) {
1353 clashCount++;
1354 if ( !first )
1355 first = m;
1356 if ( indx == actItem )
1357 currentSelected = m;
1358 else if ( !firstAfterCurrent && currentSelected )
1359 firstAfterCurrent = m;
1360 }
1361 }
1362 }
1363 indx++;
1364 }
1365 if ( 0 == clashCount ) {
1366 return;
1367 } else if ( 1 == clashCount ) {
1368 indx = indexOf( first->id() );
1369 } else {
1370 // If there's clashes and no one is selected, use first one
1371 // or if there is no clashes _after_ current, use first one
1372 if ( !currentSelected || (currentSelected && !firstAfterCurrent))
1373 indx = indexOf( first->id() );
1374 else
1375 indx = indexOf( firstAfterCurrent->id() );
1376 }
1377
1378 setActiveItem( indx );
1379 }
1380}
1381
1382
1383/*!
1384 \reimp
1385*/
1386void QMenuBar::resizeEvent( QResizeEvent *e )
1387{
1388 QFrame::resizeEvent( e );
1389 if ( badSize )
1390 return;
1391 badSize = TRUE;
1392 calculateRects();
1393}
1394
1395/*
1396 Sets actItem to \a i and calls repaint for the changed things.
1397
1398 Takes care to optimize the repainting. Assumes that
1399 calculateRects() has been called as appropriate.
1400*/
1401
1402void QMenuBar::setActiveItem( int i, bool show, bool activate_first_item )
1403{
1404 if ( i == actItem && (uint)show == popupvisible )
1405 return;
1406
1407 QMenuItem* mi = 0;
1408 if ( i >= 0 )
1409 mi = mitems->at( i );
1410 if ( mi && !mi->isEnabledAndVisible() )
1411 return;
1412
1413 popupvisible = i >= 0 ? (show) : 0;
1414 actItemDown = popupvisible;
1415
1416 if ( i < 0 || actItem < 0 ) {
1417 // just one item needs repainting
1418 int n = QMAX( actItem, i );
1419 actItem = i;
1420 if ( irects && n >= 0 )
1421 repaint( irects[n], FALSE );
1422 } else if ( QABS(i-actItem) == 1 ) {
1423 // two neighbouring items need repainting
1424 int o = actItem;
1425 actItem = i;
1426 if ( irects )
1427 repaint( irects[i].unite( irects[o] ), FALSE );
1428 } else {
1429 // two non-neighbouring items need repainting
1430 int o = actItem;
1431 actItem = i;
1432 if ( irects ) {
1433 repaint( irects[o], FALSE );
1434 repaint( irects[i], FALSE );
1435 }
1436 }
1437
1438 hidePopups();
1439
1440 if ( !popupvisible && actItem >= 0 && irects ) {
1441 QRect mfrect = irects[actItem];
1442 setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
1443 }
1444
1445#if defined(QT_ACCESSIBILITY_SUPPORT)
1446 if ( mi )
1447 QAccessible::updateAccessibility( this, indexOf( mi->id() )+1, QAccessible::Focus );
1448#endif
1449
1450 if ( actItem < 0 || !popupvisible || !mi )
1451 return;
1452
1453 QPopupMenu *popup = mi->popup();
1454 if ( popup ) {
1455 emit highlighted( mi->id() );
1456 openActPopup();
1457 if ( activate_first_item )
1458 popup->setFirstItemActive();
1459 } else { // not a popup
1460 goodbye( FALSE );
1461 if ( mi->signal() ) // activate signal
1462 mi->signal()->activate();
1463 emit activated( mi->id() );
1464 }
1465}
1466
1467
1468void QMenuBar::setAltMode( bool enable )
1469{
1470#if defined(QT_ACCESSIBILITY_SUPPORT)
1471 if ( inMenu && !enable ) {
1472 QAccessible::updateAccessibility( this, 0, QAccessible::MenuEnd );
1473 inMenu = FALSE;
1474 } else if ( !inMenu && enable ) {
1475 QAccessible::updateAccessibility( this, 0, QAccessible::MenuStart );
1476 inMenu = TRUE;
1477 }
1478#endif
1479
1480 waitforalt = 0;
1481 actItemDown = FALSE;
1482 if ( enable ) {
1483 if ( !QMenuData::d->aWidget )
1484 QMenuData::d->aWidget = qApp->focusWidget();
1485 setFocus();
1486 updateItem( idAt( actItem ) );
1487 } else {
1488 // set the focus back to the previous widget if
1489 // we still have the focus.
1490 if ( qApp->focusWidget() == this ) {
1491 if ( QMenuData::d->aWidget )
1492 QMenuData::d->aWidget->setFocus();
1493 else
1494 clearFocus();
1495 }
1496 int actId = idAt( actItem );
1497 actItem = -1;
1498 updateItem( actId );
1499 QMenuData::d->aWidget = 0;
1500 }
1501}
1502
1503/*!
1504 Sets up keyboard accelerators for the menu bar.
1505*/
1506#ifndef QT_NO_ACCEL
1507
1508void QMenuBar::setupAccelerators()
1509{
1510 delete autoaccel;
1511 autoaccel = 0;
1512
1513 QMenuItemListIt it(*mitems);
1514 register QMenuItem *mi;
1515 while ( (mi=it.current()) ) {
1516 ++it;
1517 if ( !mi->isEnabledAndVisible() ) // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
1518 continue;
1519 QString s = mi->text();
1520 if ( !s.isEmpty() ) {
1521 int i = QAccel::shortcutKey( s );
1522 if ( i ) {
1523 if ( !autoaccel ) {
1524 autoaccel = new QAccel( this );
1525 Q_CHECK_PTR( autoaccel );
1526 autoaccel->setIgnoreWhatsThis( TRUE );
1527 connect( autoaccel, SIGNAL(activated(int)),
1528 SLOT(accelActivated(int)) );
1529 connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
1530 SLOT(accelActivated(int)) );
1531 connect( autoaccel, SIGNAL(destroyed()),
1532 SLOT(accelDestroyed()) );
1533 }
1534 autoaccel->insertItem( i, mi->id() );
1535 }
1536 }
1537 if ( mi->popup() ) {
1538 QPopupMenu* popup = mi->popup();
1539 popup->updateAccel( this );
1540 if ( !popup->isEnabled() )
1541 popup->enableAccel( FALSE );
1542 }
1543 }
1544}
1545#endif
1546
1547/*!
1548 \reimp
1549 */
1550bool QMenuBar::customWhatsThis() const
1551{
1552 return TRUE;
1553}
1554
1555
1556
1557/*!
1558 \reimp
1559 */
1560void QMenuBar::focusInEvent( QFocusEvent * )
1561{
1562 if ( actItem < 0 ) {
1563 int i = -1;
1564 while ( actItem < 0 && ++i < (int) mitems->count() ) {
1565 QMenuItem* mi = mitems->at( i );
1566 if ( mi && mi->isEnabledAndVisible() && !mi->isSeparator() )
1567 setActiveItem( i, FALSE );
1568 }
1569 } else if ( !popupvisible ) {
1570 updateItem( idAt( actItem ) );
1571 }
1572}
1573
1574/*!
1575 \reimp
1576 */
1577void QMenuBar::focusOutEvent( QFocusEvent * )
1578{
1579 updateItem( idAt( actItem ) );
1580 if ( !popupvisible )
1581 setAltMode( FALSE );
1582}
1583
1584/*!
1585 \reimp
1586*/
1587
1588QSize QMenuBar::sizeHint() const
1589{
1590 int h = height();
1591 if ( badSize )
1592 h = ( (QMenuBar*)this )->calculateRects();
1593 QSize s( 2*frameWidth(),0);
1594 if ( irects ) {
1595 for ( int i = 0; i < (int)mitems->count(); ++i )
1596 s.setWidth( s.width() + irects[ i ].width() + 2 );
1597 }
1598 s.setHeight( h );
1599 return (style().sizeFromContents(QStyle::CT_MenuBar, this, s.
1600 expandedTo(QApplication::globalStrut())));
1601}
1602
1603/*!
1604 \reimp
1605*/
1606
1607QSize QMenuBar::minimumSize() const
1608{
1609#ifndef QT_NO_TOOLBAR
1610 QToolBar *tb = ::qt_cast<QToolBar*>(parent());
1611 if ( tb )
1612 return sizeHint();
1613#endif
1614 return QFrame::minimumSize();
1615}
1616
1617/*!
1618 \reimp
1619*/
1620
1621QSize QMenuBar::minimumSizeHint() const
1622{
1623 return minimumSize();
1624}
1625
1626/*!
1627 \property QMenuBar::defaultUp
1628 \brief the popup orientation
1629
1630 The default popup orientation. By default, menus pop "down" the
1631 screen. By setting the property to TRUE, the menu will pop "up".
1632 You might call this for menus that are \e below the document to
1633 which they refer.
1634
1635 If the menu would not fit on the screen, the other direction is
1636 used automatically.
1637*/
1638void QMenuBar::setDefaultUp( bool on )
1639{
1640 defaultup = on;
1641}
1642
1643bool QMenuBar::isDefaultUp() const
1644{
1645 return defaultup;
1646}
1647
1648
1649/*!
1650 \reimp
1651 */
1652void QMenuBar::activateItemAt( int index )
1653{
1654 if ( index >= 0 && index < (int) mitems->count() )
1655 setActiveItem( index );
1656 else
1657 goodbye( FALSE );
1658}
1659
1660#endif // QT_NO_MENUBAR
Note: See TracBrowser for help on using the repository browser.