summaryrefslogtreecommitdiffstats
path: root/src/kernel/qaccel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/qaccel.cpp')
-rw-r--r--src/kernel/qaccel.cpp1089
1 files changed, 1089 insertions, 0 deletions
diff --git a/src/kernel/qaccel.cpp b/src/kernel/qaccel.cpp
new file mode 100644
index 0000000..53814dc
--- /dev/null
+++ b/src/kernel/qaccel.cpp
@@ -0,0 +1,1089 @@
+/****************************************************************************
+**
+** Implementation of QAccel class
+**
+** Created : 950419
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at [email protected].
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qaccel.h"
+
+#ifndef QT_NO_ACCEL
+
+#include "qsignal.h"
+#include "qapplication.h"
+#include "qwidget.h"
+#include "qptrlist.h"
+#include "qwhatsthis.h"
+#include "qguardedptr.h"
+#include "qstatusbar.h"
+#include "qdockwindow.h"
+#include "qsignalslotimp.h"
+/*!
+ \class QAccel qaccel.h
+ \brief The QAccel class handles keyboard accelerator and shortcut keys.
+
+ \ingroup misc
+
+ A keyboard accelerator triggers an action when a certain key
+ combination is pressed. The accelerator handles all keyboard
+ activity for all the children of one top-level widget, so it is
+ not affected by the keyboard focus.
+
+ In most cases, you will not need to use this class directly. Use
+ the QAction class to create actions with accelerators that can be
+ used in both menus and toolbars. If you're only interested in
+ menus use QMenuData::insertItem() or QMenuData::setAccel() to make
+ accelerators for operations that are also available on menus. Many
+ widgets automatically generate accelerators, such as QButton,
+ QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar and QTabBar.
+ Example:
+ \code
+ QPushButton p( "&Exit", parent ); // automatic shortcut ALT+Key_E
+ QPopupMenu *fileMenu = new fileMenu( parent );
+ fileMenu->insertItem( "Undo", parent, SLOT(undo()), CTRL+Key_Z );
+ \endcode
+
+ A QAccel contains a list of accelerator items that can be
+ manipulated using insertItem(), removeItem(), clear(), key() and
+ findKey().
+
+ Each accelerator item consists of an identifier and a \l
+ QKeySequence. A single key sequence consists of a keyboard code
+ combined with modifiers (\c SHIFT, \c CTRL, \c ALT or \c
+ UNICODE_ACCEL). For example, \c{CTRL + Key_P} could be a shortcut
+ for printing a document. The key codes are listed in \c
+ qnamespace.h. As an alternative, use \c UNICODE_ACCEL with the
+ unicode code point of the character. For example, \c{UNICODE_ACCEL
+ + 'A'} gives the same accelerator as \c Key_A.
+
+ When an accelerator key is pressed, the accelerator sends out the
+ signal activated() with a number that identifies this particular
+ accelerator item. Accelerator items can also be individually
+ connected, so that two different keys will activate two different
+ slots (see connectItem() and disconnectItem()).
+
+ The activated() signal is \e not emitted when two or more
+ accelerators match the same key. Instead, the first matching
+ accelerator sends out the activatedAmbiguously() signal. By
+ pressing the key multiple times, users can navigate between all
+ matching accelerators. Some standard controls like QPushButton and
+ QCheckBox connect the activatedAmbiguously() signal to the
+ harmless setFocus() slot, whereas activated() is connected to a
+ slot invoking the button's action. Most controls, like QLabel and
+ QTabBar, treat activated() and activatedAmbiguously() as
+ equivalent.
+
+ Use setEnabled() to enable or disable all the items in an
+ accelerator, or setItemEnabled() to enable or disable individual
+ items. An item is active only when both the QAccel and the item
+ itself are enabled.
+
+ The function setWhatsThis() specifies a help text that appears
+ when the user presses an accelerator key in What's This mode.
+
+ The accelerator will be deleted when \e parent is deleted,
+ and will consume relevant key events until then.
+
+ Please note that the accelerator
+ \code
+ accelerator->insertItem( QKeySequence("M") );
+ \endcode
+ can be triggered with both the 'M' key, and with Shift+M,
+ unless a second accelerator is defined for the Shift+M
+ combination.
+
+
+ Example:
+ \code
+ QAccel *a = new QAccel( myWindow ); // create accels for myWindow
+ a->connectItem( a->insertItem(Key_P+CTRL), // adds Ctrl+P accelerator
+ myWindow, // connected to myWindow's
+ SLOT(printDoc()) ); // printDoc() slot
+ \endcode
+
+ \sa QKeyEvent QWidget::keyPressEvent() QMenuData::setAccel()
+ QButton::setAccel() QLabel::setBuddy() QKeySequence
+ \link guibooks.html#fowler GUI Design Handbook: Keyboard Shortcuts \endlink.
+*/
+
+
+struct QAccelItem { // internal accelerator item
+ QAccelItem( const QKeySequence &k, int i )
+ { key=k; id=i; enabled=TRUE; signal=0; }
+ ~QAccelItem() { delete signal; }
+ int id;
+ QKeySequence key;
+ bool enabled;
+ QSignal *signal;
+ QString whatsthis;
+};
+
+
+typedef QPtrList<QAccelItem> QAccelList; // internal accelerator list
+
+class QAccelPrivate : public Qt {
+public:
+ QAccelPrivate( QAccel* p );
+ ~QAccelPrivate();
+ QAccelList aitems;
+ bool enabled;
+ QGuardedPtr<QWidget> watch;
+ bool ignorewhatsthis;
+ QAccel* parent;
+
+ void activate( QAccelItem* item );
+ void activateAmbiguously( QAccelItem* item );
+};
+
+class QAccelManager : public Qt {
+public:
+ static QAccelManager* self() { return self_ptr ? self_ptr : new QAccelManager; }
+ void registerAccel( QAccelPrivate* a ) { accels.append( a ); }
+ void unregisterAccel( QAccelPrivate* a ) { accels.removeRef( a ); if ( accels.isEmpty() ) delete this; }
+ bool tryAccelEvent( QWidget* w, QKeyEvent* e );
+ bool dispatchAccelEvent( QWidget* w, QKeyEvent* e );
+ bool tryComposeUnicode( QWidget* w, QKeyEvent* e );
+
+private:
+ QAccelManager():currentState(Qt::NoMatch), clash(-1) { self_ptr = this; }
+ ~QAccelManager() { self_ptr = 0; }
+
+ bool correctSubWindow( QWidget *w, QAccelPrivate* d );
+ SequenceMatch match( QKeyEvent* e, QAccelItem* item, QKeySequence& temp );
+ int translateModifiers( ButtonState state );
+
+ QPtrList<QAccelPrivate> accels;
+ static QAccelManager* self_ptr;
+ Qt::SequenceMatch currentState;
+ QKeySequence intermediate;
+ int clash;
+};
+QAccelManager* QAccelManager::self_ptr = 0;
+
+bool Q_EXPORT qt_tryAccelEvent( QWidget* w, QKeyEvent* e){
+ return QAccelManager::self()->tryAccelEvent( w, e );
+}
+
+bool Q_EXPORT qt_dispatchAccelEvent( QWidget* w, QKeyEvent* e){
+ return QAccelManager::self()->dispatchAccelEvent( w, e );
+}
+
+bool Q_EXPORT qt_tryComposeUnicode( QWidget* w, QKeyEvent* e){
+ return QAccelManager::self()->tryComposeUnicode( w, e );
+}
+
+#ifdef Q_WS_MAC
+static bool qt_accel_no_shortcuts = TRUE;
+#else
+static bool qt_accel_no_shortcuts = FALSE;
+#endif
+void Q_EXPORT qt_setAccelAutoShortcuts(bool b) { qt_accel_no_shortcuts = b; }
+
+/*
+ \internal
+ Returns TRUE if the accel is in the current subwindow, else FALSE.
+*/
+bool QAccelManager::correctSubWindow( QWidget* w, QAccelPrivate* d ) {
+#if !defined ( Q_OS_MACX )
+ if ( !d->watch || !d->watch->isVisible() || !d->watch->isEnabled() )
+#else
+ if ( !d->watch || (!d->watch->isVisible() && !d->watch->inherits( "QMenuBar" )) || !d->watch->isEnabled() )
+#endif
+ return FALSE;
+ QWidget* tlw = w->topLevelWidget();
+ QWidget* wtlw = d->watch->topLevelWidget();
+
+ /* if we live in a floating dock window, keep our parent's
+ * accelerators working */
+#ifndef QT_NO_MAINWINDOW
+ if ( tlw->isDialog() && tlw->parentWidget() && ::qt_cast<QDockWindow*>(tlw) )
+ return tlw->parentWidget()->topLevelWidget() == wtlw;
+
+ if ( wtlw != tlw )
+ return FALSE;
+#endif
+ /* if we live in a MDI subwindow, ignore the event if we are
+ not the active document window */
+ QWidget* sw = d->watch;
+ while ( sw && !sw->testWFlags( WSubWindow ) )
+ sw = sw->parentWidget( TRUE );
+ if ( sw ) { // we are in a subwindow indeed
+ QWidget* fw = w;
+ while ( fw && fw != sw )
+ fw = fw->parentWidget( TRUE );
+ if ( fw != sw ) // focus widget not in our subwindow
+ return FALSE;
+ }
+ return TRUE;
+}
+
+inline int QAccelManager::translateModifiers( ButtonState state )
+{
+ int result = 0;
+ if ( state & ShiftButton )
+ result |= SHIFT;
+ if ( state & ControlButton )
+ result |= CTRL;
+ if ( state & MetaButton )
+ result |= META;
+ if ( state & AltButton )
+ result |= ALT;
+ return result;
+}
+
+/*
+ \internal
+ Matches the current intermediate key sequence + the latest
+ keyevent, with and AccelItem. Returns Identical,
+ PartialMatch or NoMatch, and fills \a temp with the
+ resulting key sequence.
+*/
+Qt::SequenceMatch QAccelManager::match( QKeyEvent *e, QAccelItem* item, QKeySequence& temp )
+{
+ SequenceMatch result = Qt::NoMatch;
+ int index = intermediate.count();
+ temp = intermediate;
+
+ int modifier = translateModifiers( e->state() );
+
+ if ( e->key() && e->key() != Key_unknown) {
+ int key = e->key() | modifier;
+ if ( e->key() == Key_BackTab ) {
+ /*
+ In QApplication, we map shift+tab to shift+backtab.
+ This code here reverts the mapping in a way that keeps
+ backtab and shift+tab accelerators working, in that
+ order, meaning backtab has priority.*/
+ key &= ~SHIFT;
+
+ temp.setKey( key, index );
+ if ( Qt::NoMatch != (result = temp.matches( item->key )) )
+ return result;
+ if ( e->state() & ShiftButton )
+ key |= SHIFT;
+ key = Key_Tab | ( key & MODIFIER_MASK );
+ temp.setKey( key, index );
+ if ( Qt::NoMatch != (result = temp.matches( item->key )) )
+ return result;
+ } else {
+ temp.setKey( key, index );
+ if ( Qt::NoMatch != (result = temp.matches( item->key )) )
+ return result;
+ }
+
+ if ( key == Key_BackTab ) {
+ if ( e->state() & ShiftButton )
+ key |= SHIFT;
+ temp.setKey( key, index );
+ if ( Qt::NoMatch != (result = temp.matches( item->key )) )
+ return result;
+ }
+ }
+ if ( !e->text().isEmpty() ) {
+ temp.setKey( (int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index );
+ result = temp.matches( item->key );
+ }
+ return result;
+}
+
+bool QAccelManager::tryAccelEvent( QWidget* w, QKeyEvent* e )
+{
+ if ( Qt::NoMatch == currentState ) {
+ e->t = QEvent::AccelOverride;
+ e->ignore();
+ QApplication::sendSpontaneousEvent( w, e );
+ if ( e->isAccepted() )
+ return FALSE;
+ }
+ e->t = QEvent::Accel;
+ e->ignore();
+ QApplication::sendSpontaneousEvent( w, e );
+ return e->isAccepted();
+}
+
+bool QAccelManager::tryComposeUnicode( QWidget* w, QKeyEvent* e )
+{
+ if ( QApplication::metaComposeUnicode ) {
+ int value = e->key() - Key_0;
+ // Ignore acceloverrides so we don't trigger
+ // accels on keypad when Meta compose is on
+ if ( (e->type() == QEvent::AccelOverride) &&
+ (e->state() == Qt::Keypad + Qt::MetaButton) ) {
+ e->accept();
+ // Meta compose start/continue
+ } else if ( (e->type() == QEvent::KeyPress) &&
+ (e->state() == Qt::Keypad + Qt::MetaButton) ) {
+ if ( value >= 0 && value <= 9 ) {
+ QApplication::composedUnicode *= 10;
+ QApplication::composedUnicode += value;
+ return TRUE;
+ } else {
+ // Composing interrupted, dispatch!
+ if ( QApplication::composedUnicode ) {
+ QChar ch( QApplication::composedUnicode );
+ QString s( ch );
+ QKeyEvent kep( QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s );
+ QKeyEvent ker( QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s );
+ QApplication::sendEvent( w, &kep );
+ QApplication::sendEvent( w, &ker );
+ }
+ QApplication::composedUnicode = 0;
+ return TRUE;
+ }
+ // Meta compose end, dispatch
+ } else if ( (e->type() == QEvent::KeyRelease) &&
+ (e->key() == Key_Meta) &&
+ (QApplication::composedUnicode != 0) ) {
+ if ( (QApplication::composedUnicode > 0) &&
+ (QApplication::composedUnicode < 0xFFFE) ) {
+ QChar ch( QApplication::composedUnicode );
+ QString s( ch );
+ QKeyEvent kep( QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s );
+ QKeyEvent ker( QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s );
+ QApplication::sendEvent( w, &kep );
+ QApplication::sendEvent( w, &ker );
+ }
+ QApplication::composedUnicode = 0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ \internal
+ Checks for possible accelerators, if no widget
+ ate the keypres, or we are in the middle of a
+ partial key sequence.
+*/
+bool QAccelManager::dispatchAccelEvent( QWidget* w, QKeyEvent* e )
+{
+#ifndef QT_NO_STATUSBAR
+ // Needs to be declared and used here because of "goto doclash"
+ QStatusBar* mainStatusBar = 0;
+#endif
+
+ // Modifiers can NOT be accelerators...
+ if ( e->key() >= Key_Shift &&
+ e->key() <= Key_Alt )
+ return FALSE;
+
+ SequenceMatch result = Qt::NoMatch;
+ QKeySequence tocheck, partial;
+ QAccelPrivate* accel = 0;
+ QAccelItem* item = 0;
+ QAccelPrivate* firstaccel = 0;
+ QAccelItem* firstitem = 0;
+ QAccelPrivate* lastaccel = 0;
+ QAccelItem* lastitem = 0;
+
+ QKeyEvent pe = *e;
+ int n = -1;
+ int hasShift = (e->state()&Qt::ShiftButton)?1:0;
+ bool identicalDisabled = FALSE;
+ bool matchFound = FALSE;
+ do {
+ accel = accels.first();
+ matchFound = FALSE;
+ while ( accel ) {
+ if ( correctSubWindow( w, accel ) ) {
+ if ( accel->enabled ) {
+ item = accel->aitems.last();
+ while( item ) {
+ if ( Qt::Identical == (result = match( &pe, item, tocheck )) ) {
+ if ( item->enabled ) {
+ if ( !firstaccel ) {
+ firstaccel = accel;
+ firstitem = item;
+ }
+ lastaccel = accel;
+ lastitem = item;
+ n++;
+ matchFound = TRUE;
+ if ( n > QMAX(clash,0) )
+ goto doclash;
+ } else {
+ identicalDisabled = TRUE;
+ }
+ }
+ if ( item->enabled && Qt::PartialMatch == result ) {
+ partial = tocheck;
+ matchFound = TRUE;
+ }
+ item = accel->aitems.prev();
+ }
+ } else {
+ item = accel->aitems.last();
+ while( item ) {
+ if ( Qt::Identical == match( &pe, item, tocheck ) )
+ identicalDisabled = TRUE;
+ item = accel->aitems.prev();
+ }
+ }
+ }
+ accel = accels.next();
+ }
+ pe = QKeyEvent( QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text() );
+ } while ( hasShift-- && !matchFound && !identicalDisabled );
+
+#ifndef QT_NO_STATUSBAR
+ mainStatusBar = (QStatusBar*) w->topLevelWidget()->child( 0, "QStatusBar" );
+#endif
+ if ( n < 0 ) { // no match found
+ currentState = partial.count() ? PartialMatch : NoMatch;
+#ifndef QT_NO_STATUSBAR
+ // Only display message if we are, or were, in a partial match
+ if ( mainStatusBar && (PartialMatch == currentState || intermediate.count() ) ) {
+ if ( currentState == Qt::PartialMatch ) {
+ mainStatusBar->message( (QString)partial + ", ...", 0 );
+ } else if (!identicalDisabled) {
+ QString message = QAccel::tr("%1, %2 not defined").
+ arg( (QString)intermediate ).
+ arg( QKeySequence::encodeString( e->key() | translateModifiers(e->state()) ) );
+ mainStatusBar->message( message, 2000 );
+ // Since we're a NoMatch, reset the clash count
+ clash = -1;
+ } else {
+ mainStatusBar->clear();
+ }
+ }
+#endif
+
+ bool eatKey = (PartialMatch == currentState || intermediate.count() );
+ intermediate = partial;
+ if ( eatKey )
+ e->accept();
+ return eatKey;
+ } else if ( n == 0 ) { // found exactly one match
+ clash = -1; // reset
+#ifndef QT_NO_STATUSBAR
+ if ( currentState == Qt::PartialMatch && mainStatusBar )
+ mainStatusBar->clear();
+#endif
+ currentState = Qt::NoMatch; // Free sequence keylock
+ intermediate = QKeySequence();
+ lastaccel->activate( lastitem );
+ e->accept();
+ return TRUE;
+ }
+
+ doclash: // found more than one match
+#ifndef QT_NO_STATUSBAR
+ if ( !mainStatusBar ) // if "goto doclash", we need to get statusbar again.
+ mainStatusBar = (QStatusBar*) w->topLevelWidget()->child( 0, "QStatusBar" );
+#endif
+
+ QString message = QAccel::tr( "Ambiguous \"%1\" not handled" ).arg( (QString)tocheck );
+ if ( clash >= 0 && n > clash ) { // pick next match
+ intermediate = QKeySequence();
+ currentState = Qt::NoMatch; // Free sequence keylock
+ clash++;
+#ifndef QT_NO_STATUSBAR
+ if ( mainStatusBar &&
+ !lastitem->signal &&
+ !(lastaccel->parent->receivers( "activatedAmbiguously(int)" )) )
+ mainStatusBar->message( message, 2000 );
+#endif
+ lastaccel->activateAmbiguously( lastitem );
+ } else { // start (or wrap) with the first matching
+ intermediate = QKeySequence();
+ currentState = Qt::NoMatch; // Free sequence keylock
+ clash = 0;
+#ifndef QT_NO_STATUSBAR
+ if ( mainStatusBar &&
+ !firstitem->signal &&
+ !(firstaccel->parent->receivers( "activatedAmbiguously(int)" )) )
+ mainStatusBar->message( message, 2000 );
+#endif
+ firstaccel->activateAmbiguously( firstitem );
+ }
+ e->accept();
+ return TRUE;
+}
+
+QAccelPrivate::QAccelPrivate( QAccel* p )
+ : parent( p )
+{
+ QAccelManager::self()->registerAccel( this );
+ aitems.setAutoDelete( TRUE );
+ ignorewhatsthis = FALSE;
+}
+
+QAccelPrivate::~QAccelPrivate()
+{
+ QAccelManager::self()->unregisterAccel( this );
+}
+
+static QAccelItem *find_id( QAccelList &list, int id )
+{
+ register QAccelItem *item = list.first();
+ while ( item && item->id != id )
+ item = list.next();
+ return item;
+}
+
+static QAccelItem *find_key( QAccelList &list, const QKeySequence &key )
+{
+ register QAccelItem *item = list.first();
+ while ( item && !( item->key == key ) )
+ item = list.next();
+ return item;
+}
+
+/*!
+ Constructs a QAccel object called \a name, with parent \a parent.
+ The accelerator operates on \a parent.
+*/
+
+QAccel::QAccel( QWidget *parent, const char *name )
+ : QObject( parent, name )
+{
+ d = new QAccelPrivate( this );
+ d->enabled = TRUE;
+ d->watch = parent;
+#if defined(QT_CHECK_NULL)
+ if ( !d->watch )
+ qWarning( "QAccel: An accelerator must have a parent or a watch widget" );
+#endif
+}
+
+/*!
+ Constructs a QAccel object called \a name, that operates on \a
+ watch, and is a child of \a parent.
+
+ This constructor is not needed for normal application programming.
+*/
+QAccel::QAccel( QWidget* watch, QObject *parent, const char *name )
+ : QObject( parent, name )
+{
+ d = new QAccelPrivate( this );
+ d->enabled = TRUE;
+ d->watch = watch;
+#if defined(QT_CHECK_NULL)
+ if ( !d->watch )
+ qWarning( "QAccel: An accelerator must have a parent or a watch widget" );
+#endif
+}
+
+/*!
+ Destroys the accelerator object and frees all allocated resources.
+*/
+
+QAccel::~QAccel()
+{
+ delete d;
+}
+
+
+/*!
+ \fn void QAccel::activated( int id )
+
+ This signal is emitted when an accelerator key is pressed. \a id
+ is a number that identifies this particular accelerator item.
+
+ \sa activatedAmbiguously()
+*/
+
+/*!
+ \fn void QAccel::activatedAmbiguously( int id )
+
+ This signal is emitted when an accelerator key is pressed. \a id
+ is a number that identifies this particular accelerator item.
+
+ \sa activated()
+*/
+
+
+/*!
+ Returns TRUE if the accelerator is enabled; otherwise returns
+ FALSE.
+
+ \sa setEnabled(), isItemEnabled()
+*/
+
+bool QAccel::isEnabled() const
+{
+ return d->enabled;
+}
+
+
+/*!
+ Enables the accelerator if \a enable is TRUE, or disables it if \a
+ enable is FALSE.
+
+ Individual keys can also be enabled or disabled using
+ setItemEnabled(). To work, a key must be an enabled item in an
+ enabled QAccel.
+
+ \sa isEnabled(), setItemEnabled()
+*/
+
+void QAccel::setEnabled( bool enable )
+{
+ d->enabled = enable;
+}
+
+
+/*!
+ Returns the number of accelerator items in this accelerator.
+*/
+
+uint QAccel::count() const
+{
+ return d->aitems.count();
+}
+
+
+static int get_seq_id()
+{
+ static int seq_no = -2; // -1 is used as return value in findKey()
+ return seq_no--;
+}
+
+/*!
+ Inserts an accelerator item and returns the item's identifier.
+
+ \a key is a key code and an optional combination of SHIFT, CTRL
+ and ALT. \a id is the accelerator item id.
+
+ If \a id is negative, then the item will be assigned a unique
+ negative identifier less than -1.
+
+ \code
+ QAccel *a = new QAccel( myWindow ); // create accels for myWindow
+ a->insertItem( CTRL + Key_P, 200 ); // Ctrl+P, e.g. to print document
+ a->insertItem( ALT + Key_X, 201 ); // Alt+X, e.g. to quit
+ a->insertItem( UNICODE_ACCEL + 'q', 202 ); // Unicode 'q', e.g. to quit
+ a->insertItem( Key_D ); // gets a unique negative id < -1
+ a->insertItem( CTRL + SHIFT + Key_P ); // gets a unique negative id < -1
+ \endcode
+*/
+
+int QAccel::insertItem( const QKeySequence& key, int id )
+{
+ if ( id == -1 )
+ id = get_seq_id();
+ d->aitems.insert( 0, new QAccelItem(key,id) );
+ return id;
+}
+
+/*!
+ Removes the accelerator item with the identifier \a id.
+*/
+
+void QAccel::removeItem( int id )
+{
+ if ( find_id( d->aitems, id) )
+ d->aitems.remove();
+}
+
+
+/*!
+ Removes all accelerator items.
+*/
+
+void QAccel::clear()
+{
+ d->aitems.clear();
+}
+
+
+/*!
+ Returns the key sequence of the accelerator item with identifier
+ \a id, or an invalid key sequence (0) if the id cannot be found.
+*/
+
+QKeySequence QAccel::key( int id )
+{
+ QAccelItem *item = find_id( d->aitems, id);
+ return item ? item->key : QKeySequence( 0 );
+}
+
+
+/*!
+ Returns the identifier of the accelerator item with the key code
+ \a key, or -1 if the item cannot be found.
+*/
+
+int QAccel::findKey( const QKeySequence& key ) const
+{
+ QAccelItem *item = find_key( d->aitems, key );
+ return item ? item->id : -1;
+}
+
+
+/*!
+ Returns TRUE if the accelerator item with the identifier \a id is
+ enabled. Returns FALSE if the item is disabled or cannot be found.
+
+ \sa setItemEnabled(), isEnabled()
+*/
+
+bool QAccel::isItemEnabled( int id ) const
+{
+ QAccelItem *item = find_id( d->aitems, id);
+ return item ? item->enabled : FALSE;
+}
+
+
+/*!
+ Enables the accelerator item with the identifier \a id if \a
+ enable is TRUE, and disables item \a id if \a enable is FALSE.
+
+ To work, an item must be enabled and be in an enabled QAccel.
+
+ \sa isItemEnabled(), isEnabled()
+*/
+
+void QAccel::setItemEnabled( int id, bool enable )
+{
+ QAccelItem *item = find_id( d->aitems, id);
+ if ( item )
+ item->enabled = enable;
+}
+
+
+/*!
+ Connects the accelerator item \a id to the slot \a member of \a
+ receiver.
+
+ \code
+ a->connectItem( 201, mainView, SLOT(quit()) );
+ \endcode
+
+ Of course, you can also send a signal as \a member.
+
+ Normally accelerators are connected to slots which then receive
+ the \c activated(int id) signal with the id of the accelerator
+ item that was activated. If you choose to connect a specific
+ accelerator item using this function, the \c activated() signal is
+ emitted if the associated key sequence is pressed but no \c
+ activated(int id) signal is emitted.
+
+ \sa disconnectItem()
+*/
+
+bool QAccel::connectItem( int id, const QObject *receiver, const char *member )
+{
+ QAccelItem *item = find_id( d->aitems, id);
+ if ( item ) {
+ if ( !item->signal ) {
+ item->signal = new QSignal;
+ Q_CHECK_PTR( item->signal );
+ }
+ return item->signal->connect( receiver, member );
+ }
+ return FALSE;
+}
+
+/*!
+ Disconnects an accelerator item with id \a id from the function
+ called \a member in the \a receiver object.
+
+ \sa connectItem()
+*/
+
+bool QAccel::disconnectItem( int id, const QObject *receiver,
+ const char *member )
+{
+ QAccelItem *item = find_id( d->aitems, id);
+ if ( item && item->signal )
+ return item->signal->disconnect( receiver, member );
+ return FALSE;
+}
+
+void QAccelPrivate::activate( QAccelItem* item )
+{
+#ifndef QT_NO_WHATSTHIS
+ if ( QWhatsThis::inWhatsThisMode() && !ignorewhatsthis ) {
+ QWhatsThis::leaveWhatsThisMode( item->whatsthis );
+ return;
+ }
+#endif
+ if ( item->signal )
+ item->signal->activate();
+ else
+ emit parent->activated( item->id );
+}
+
+void QAccelPrivate::activateAmbiguously( QAccelItem* item )
+{
+ if ( item->signal )
+ item->signal->activate();
+ else
+ emit parent->activatedAmbiguously( item->id );
+}
+
+
+/*!
+ Returns the shortcut key sequence for \a str, or an invalid key
+ sequence (0) if \a str has no shortcut sequence.
+
+ For example, shortcutKey("E&amp;xit") returns ALT+Key_X,
+ shortcutKey("&amp;Quit") returns ALT+Key_Q and shortcutKey("Quit")
+ returns 0. (In code that does not inherit the Qt namespace class,
+ you must write e.g. Qt::ALT+Qt::Key_Q.)
+
+ We provide a \link accelerators.html list of common accelerators
+ \endlink in English. At the time of writing, Microsoft and Open
+ Group do not appear to have issued equivalent recommendations for
+ other languages.
+*/
+
+QKeySequence QAccel::shortcutKey( const QString &str )
+{
+ if(qt_accel_no_shortcuts)
+ return QKeySequence();
+
+ int p = 0;
+ while ( p >= 0 ) {
+ p = str.find( '&', p ) + 1;
+ if ( p <= 0 || p >= (int)str.length() )
+ return 0;
+ if ( str[p] != '&' ) {
+ QChar c = str[p];
+ if ( c.isPrint() ) {
+ char ltr = c.upper().latin1();
+ if ( ltr >= (char)Key_A && ltr <= (char)Key_Z )
+ c = ltr;
+ else
+ c = c.lower();
+ return QKeySequence( c.unicode() + ALT + UNICODE_ACCEL );
+ }
+ }
+ p++;
+ }
+ return QKeySequence();
+}
+
+/*! \obsolete
+
+ Creates an accelerator string for the key \a k.
+ For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc.
+ are translated (using QObject::tr()) in the "QAccel" context.
+
+ The function is superfluous. Cast the QKeySequence \a k to a
+ QString for the same effect.
+*/
+QString QAccel::keyToString( QKeySequence k )
+{
+ return (QString) k;
+}
+
+/*!\obsolete
+
+ Returns an accelerator code for the string \a s. For example
+ "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl",
+ "Shift", "Alt" are recognized, as well as their translated
+ equivalents in the "QAccel" context (using QObject::tr()). Returns 0
+ if \a s is not recognized.
+
+ This function is typically used with \link QObject::tr() tr
+ \endlink(), so that accelerator keys can be replaced in
+ translations:
+
+ \code
+ QPopupMenu *file = new QPopupMenu( this );
+ file->insertItem( p1, tr("&Open..."), this, SLOT(open()),
+ QAccel::stringToKey(tr("Ctrl+O", "File|Open")) );
+ \endcode
+
+ Notice the \c "File|Open" translator comment. It is by no means
+ necessary, but it provides some context for the human translator.
+
+
+ The function is superfluous. Construct a QKeySequence from the
+ string \a s for the same effect.
+
+ \sa QObject::tr()
+ \link i18n.html Internationalization with Qt \endlink
+*/
+QKeySequence QAccel::stringToKey( const QString & s )
+{
+ return QKeySequence( s );
+}
+
+
+/*!
+ Sets a What's This help text for the accelerator item \a id to \a
+ text.
+
+ The text will be shown when the application is in What's This mode
+ and the user hits the accelerator key.
+
+ To set What's This help on a menu item (with or without an
+ accelerator key), use QMenuData::setWhatsThis().
+
+ \sa whatsThis(), QWhatsThis::inWhatsThisMode(),
+ QMenuData::setWhatsThis(), QAction::setWhatsThis()
+*/
+void QAccel::setWhatsThis( int id, const QString& text )
+{
+
+ QAccelItem *item = find_id( d->aitems, id);
+ if ( item )
+ item->whatsthis = text;
+}
+
+/*!
+ Returns the What's This help text for the specified item \a id or
+ QString::null if no text has been specified.
+
+ \sa setWhatsThis()
+*/
+QString QAccel::whatsThis( int id ) const
+{
+
+ QAccelItem *item = find_id( d->aitems, id);
+ return item? item->whatsthis : QString::null;
+}
+
+/*!\internal */
+void QAccel::setIgnoreWhatsThis( bool b)
+{
+ d->ignorewhatsthis = b;
+}
+
+/*!\internal */
+bool QAccel::ignoreWhatsThis() const
+{
+ return d->ignorewhatsthis;
+}
+
+
+/*!
+
+\page accelerators.html
+
+\title Standard Accelerator Keys
+
+Applications invariably need to define accelerator keys for actions.
+Qt fully supports accelerators, for example with \l QAccel::shortcutKey().
+
+Here are Microsoft's recommendations for accelerator keys, with
+comments about the Open Group's recommendations where they exist
+and differ. For most commands, the Open Group either has no advice or
+agrees with Microsoft.
+
+The emboldened letter plus Alt is Microsoft's recommended choice, and
+we recommend supporting it. For an Apply button, for example, we
+recommend QButton::setText( \link QWidget::tr() tr \endlink("&amp;Apply") );
+
+If you have conflicting commands (e.g. About and Apply buttons in the
+same dialog), you must decide for yourself.
+
+\list
+\i <b><u>A</u></b>bout
+\i Always on <b><u>T</u></b>op
+\i <b><u>A</u></b>pply
+\i <b><u>B</u></b>ack
+\i <b><u>B</u></b>rowse
+\i <b><u>C</u></b>lose (CDE: Alt+F4; Alt+F4 is "close window" in Windows)
+\i <b><u>C</u></b>opy (CDE: Ctrl+C, Ctrl+Insert)
+\i <b><u>C</u></b>opy Here
+\i Create <b><u>S</u></b>hortcut
+\i Create <b><u>S</u></b>hortcut Here
+\i Cu<b><u>t</u></b>
+\i <b><u>D</u></b>elete
+\i <b><u>E</u></b>dit
+\i <b><u>E</u></b>xit (CDE: E<b><u>x</u></b>it)
+\i <b><u>E</u></b>xplore
+\i <b><u>F</u></b>ile
+\i <b><u>F</u></b>ind
+\i <b><u>H</u></b>elp
+\i Help <b><u>T</u></b>opics
+\i <b><u>H</u></b>ide
+\i <b><u>I</u></b>nsert
+\i Insert <b><u>O</u></b>bject
+\i <b><u>L</u></b>ink Here
+\i Ma<b><u>x</u></b>imize
+\i Mi<b><u>n</u></b>imize
+\i <b><u>M</u></b>ove
+\i <b><u>M</u></b>ove Here
+\i <b><u>N</u></b>ew
+\i <b><u>N</u></b>ext
+\i <b><u>N</u></b>o
+\i <b><u>O</u></b>pen
+\i Open <b><u>W</u></b>ith
+\i Page Set<b><u>u</u></b>p
+\i <b><u>P</u></b>aste
+\i Paste <b><u>L</u></b>ink
+\i Paste <b><u>S</u></b>hortcut
+\i Paste <b><u>S</u></b>pecial
+\i <b><u>P</u></b>ause
+\i <b><u>P</u></b>lay
+\i <b><u>P</u></b>rint
+\i <b><u>P</u></b>rint Here
+\i P<b><u>r</u></b>operties
+\i <b><u>Q</u></b>uick View
+\i <b><u>R</u></b>edo (CDE: Ctrl+Y, Shift+Alt+Backspace)
+\i <b><u>R</u></b>epeat
+\i <b><u>R</u></b>estore
+\i <b><u>R</u></b>esume
+\i <b><u>R</u></b>etry
+\i <b><u>R</u></b>un
+\i <b><u>S</u></b>ave
+\i Save <b><u>A</u></b>s
+\i Select <b><u>A</u></b>ll
+\i Se<b><u>n</u></b>d To
+\i <b><u>S</u></b>how
+\i <b><u>S</u></b>ize
+\i S<b><u>p</u></b>lit
+\i <b><u>S</u></b>top
+\i <b><u>U</u></b>ndo (CDE: Ctrl+Z or Alt+Backspace)
+\i <b><u>V</u></b>iew
+\i <b><u>W</u></b>hat's This?
+\i <b><u>W</u></b>indow
+\i <b><u>Y</u></b>es
+\endlist
+
+There are also a lot of other keys and actions (that use other
+modifier keys than Alt). See the Microsoft and The Open Group
+documentation for details.
+
+The \link http://www.amazon.com/exec/obidos/ASIN/0735605661/trolltech/t
+Microsoft book \endlink has ISBN 0735605661. The corresponding Open Group
+book is very hard to find, rather expensive and we cannot recommend
+it. However, if you really want it, [email protected] might be able
+to help. Ask them for ISBN 1859121047.
+
+*/
+
+/*! \obsolete serves no purpose anymore */
+void QAccel::repairEventFilter() {}
+/*! \obsolete serves no purpose anymore */
+bool QAccel::eventFilter( QObject *, QEvent * ) { return FALSE; }
+#endif // QT_NO_ACCEL