source: vendor/trolltech/current/src/kernel/qaccel.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: 31.9 KB
Line 
1/****************************************************************************
2** $Id: qaccel.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QAccel class
5**
6** Created : 950419
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel 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
14** 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#include "qaccel.h"
39
40#ifndef QT_NO_ACCEL
41
42#include "qsignal.h"
43#include "qapplication.h"
44#include "qwidget.h"
45#include "qptrlist.h"
46#include "qwhatsthis.h"
47#include "qguardedptr.h"
48#include "qstatusbar.h"
49#include "qdockwindow.h"
50#include "qsignalslotimp.h"
51/*!
52 \class QAccel qaccel.h
53 \brief The QAccel class handles keyboard accelerator and shortcut keys.
54
55 \ingroup misc
56
57 A keyboard accelerator triggers an action when a certain key
58 combination is pressed. The accelerator handles all keyboard
59 activity for all the children of one top-level widget, so it is
60 not affected by the keyboard focus.
61
62 In most cases, you will not need to use this class directly. Use
63 the QAction class to create actions with accelerators that can be
64 used in both menus and toolbars. If you're only interested in
65 menus use QMenuData::insertItem() or QMenuData::setAccel() to make
66 accelerators for operations that are also available on menus. Many
67 widgets automatically generate accelerators, such as QButton,
68 QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar and QTabBar.
69 Example:
70 \code
71 QPushButton p( "&Exit", parent ); // automatic shortcut ALT+Key_E
72 QPopupMenu *fileMenu = new fileMenu( parent );
73 fileMenu->insertItem( "Undo", parent, SLOT(undo()), CTRL+Key_Z );
74 \endcode
75
76 A QAccel contains a list of accelerator items that can be
77 manipulated using insertItem(), removeItem(), clear(), key() and
78 findKey().
79
80 Each accelerator item consists of an identifier and a \l
81 QKeySequence. A single key sequence consists of a keyboard code
82 combined with modifiers (\c SHIFT, \c CTRL, \c ALT or \c
83 UNICODE_ACCEL). For example, \c{CTRL + Key_P} could be a shortcut
84 for printing a document. The key codes are listed in \c
85 qnamespace.h. As an alternative, use \c UNICODE_ACCEL with the
86 unicode code point of the character. For example, \c{UNICODE_ACCEL
87 + 'A'} gives the same accelerator as \c Key_A.
88
89 When an accelerator key is pressed, the accelerator sends out the
90 signal activated() with a number that identifies this particular
91 accelerator item. Accelerator items can also be individually
92 connected, so that two different keys will activate two different
93 slots (see connectItem() and disconnectItem()).
94
95 The activated() signal is \e not emitted when two or more
96 accelerators match the same key. Instead, the first matching
97 accelerator sends out the activatedAmbiguously() signal. By
98 pressing the key multiple times, users can navigate between all
99 matching accelerators. Some standard controls like QPushButton and
100 QCheckBox connect the activatedAmbiguously() signal to the
101 harmless setFocus() slot, whereas activated() is connected to a
102 slot invoking the button's action. Most controls, like QLabel and
103 QTabBar, treat activated() and activatedAmbiguously() as
104 equivalent.
105
106 Use setEnabled() to enable or disable all the items in an
107 accelerator, or setItemEnabled() to enable or disable individual
108 items. An item is active only when both the QAccel and the item
109 itself are enabled.
110
111 The function setWhatsThis() specifies a help text that appears
112 when the user presses an accelerator key in What's This mode.
113
114 The accelerator will be deleted when \e parent is deleted,
115 and will consume relevant key events until then.
116
117 Please note that the accelerator
118 \code
119 accelerator->insertItem( QKeySequence("M") );
120 \endcode
121 can be triggered with both the 'M' key, and with Shift+M,
122 unless a second accelerator is defined for the Shift+M
123 combination.
124
125
126 Example:
127 \code
128 QAccel *a = new QAccel( myWindow ); // create accels for myWindow
129 a->connectItem( a->insertItem(Key_P+CTRL), // adds Ctrl+P accelerator
130 myWindow, // connected to myWindow's
131 SLOT(printDoc()) ); // printDoc() slot
132 \endcode
133
134 \sa QKeyEvent QWidget::keyPressEvent() QMenuData::setAccel()
135 QButton::setAccel() QLabel::setBuddy() QKeySequence
136 \link guibooks.html#fowler GUI Design Handbook: Keyboard Shortcuts \endlink.
137*/
138
139
140struct QAccelItem { // internal accelerator item
141 QAccelItem( const QKeySequence &k, int i )
142 { key=k; id=i; enabled=TRUE; signal=0; }
143 ~QAccelItem() { delete signal; }
144 int id;
145 QKeySequence key;
146 bool enabled;
147 QSignal *signal;
148 QString whatsthis;
149};
150
151
152typedef QPtrList<QAccelItem> QAccelList; // internal accelerator list
153
154class QAccelPrivate : public Qt {
155public:
156 QAccelPrivate( QAccel* p );
157 ~QAccelPrivate();
158 QAccelList aitems;
159 bool enabled;
160 QGuardedPtr<QWidget> watch;
161 bool ignorewhatsthis;
162 QAccel* parent;
163
164 void activate( QAccelItem* item );
165 void activateAmbiguously( QAccelItem* item );
166};
167
168class QAccelManager : public Qt {
169public:
170 static QAccelManager* self() { return self_ptr ? self_ptr : new QAccelManager; }
171 void registerAccel( QAccelPrivate* a ) { accels.append( a ); }
172 void unregisterAccel( QAccelPrivate* a ) { accels.removeRef( a ); if ( accels.isEmpty() ) delete this; }
173 bool tryAccelEvent( QWidget* w, QKeyEvent* e );
174 bool dispatchAccelEvent( QWidget* w, QKeyEvent* e );
175 bool tryComposeUnicode( QWidget* w, QKeyEvent* e );
176
177private:
178 QAccelManager():currentState(Qt::NoMatch), clash(-1) { self_ptr = this; }
179 ~QAccelManager() { self_ptr = 0; }
180
181 bool correctSubWindow( QWidget *w, QAccelPrivate* d );
182 SequenceMatch match( QKeyEvent* e, QAccelItem* item, QKeySequence& temp );
183 int translateModifiers( ButtonState state );
184
185 QPtrList<QAccelPrivate> accels;
186 static QAccelManager* self_ptr;
187 Qt::SequenceMatch currentState;
188 QKeySequence intermediate;
189 int clash;
190};
191QAccelManager* QAccelManager::self_ptr = 0;
192
193bool Q_EXPORT qt_tryAccelEvent( QWidget* w, QKeyEvent* e){
194 return QAccelManager::self()->tryAccelEvent( w, e );
195}
196
197bool Q_EXPORT qt_dispatchAccelEvent( QWidget* w, QKeyEvent* e){
198 return QAccelManager::self()->dispatchAccelEvent( w, e );
199}
200
201bool Q_EXPORT qt_tryComposeUnicode( QWidget* w, QKeyEvent* e){
202 return QAccelManager::self()->tryComposeUnicode( w, e );
203}
204
205#ifdef Q_WS_MAC
206static bool qt_accel_no_shortcuts = TRUE;
207#else
208static bool qt_accel_no_shortcuts = FALSE;
209#endif
210void Q_EXPORT qt_setAccelAutoShortcuts(bool b) { qt_accel_no_shortcuts = b; }
211
212/*
213 \internal
214 Returns TRUE if the accel is in the current subwindow, else FALSE.
215*/
216bool QAccelManager::correctSubWindow( QWidget* w, QAccelPrivate* d ) {
217#if !defined ( Q_OS_MACX )
218 if ( !d->watch || !d->watch->isVisible() || !d->watch->isEnabled() )
219#else
220 if ( !d->watch || (!d->watch->isVisible() && !d->watch->inherits( "QMenuBar" )) || !d->watch->isEnabled() )
221#endif
222 return FALSE;
223 QWidget* tlw = w->topLevelWidget();
224 QWidget* wtlw = d->watch->topLevelWidget();
225
226 /* if we live in a floating dock window, keep our parent's
227 * accelerators working */
228#ifndef QT_NO_MAINWINDOW
229 if ( tlw->isDialog() && tlw->parentWidget() && ::qt_cast<QDockWindow*>(tlw) )
230 return tlw->parentWidget()->topLevelWidget() == wtlw;
231
232 if ( wtlw != tlw )
233 return FALSE;
234#endif
235 /* if we live in a MDI subwindow, ignore the event if we are
236 not the active document window */
237 QWidget* sw = d->watch;
238 while ( sw && !sw->testWFlags( WSubWindow ) )
239 sw = sw->parentWidget( TRUE );
240 if ( sw ) { // we are in a subwindow indeed
241 QWidget* fw = w;
242 while ( fw && fw != sw )
243 fw = fw->parentWidget( TRUE );
244 if ( fw != sw ) // focus widget not in our subwindow
245 return FALSE;
246 }
247 return TRUE;
248}
249
250inline int QAccelManager::translateModifiers( ButtonState state )
251{
252 int result = 0;
253 if ( state & ShiftButton )
254 result |= SHIFT;
255 if ( state & ControlButton )
256 result |= CTRL;
257 if ( state & MetaButton )
258 result |= META;
259 if ( state & AltButton )
260 result |= ALT;
261 return result;
262}
263
264/*
265 \internal
266 Matches the current intermediate key sequence + the latest
267 keyevent, with and AccelItem. Returns Identical,
268 PartialMatch or NoMatch, and fills \a temp with the
269 resulting key sequence.
270*/
271Qt::SequenceMatch QAccelManager::match( QKeyEvent *e, QAccelItem* item, QKeySequence& temp )
272{
273 SequenceMatch result = Qt::NoMatch;
274 int index = intermediate.count();
275 temp = intermediate;
276
277 int modifier = translateModifiers( e->state() );
278
279 if ( e->key() && e->key() != Key_unknown) {
280 int key = e->key() | modifier;
281 if ( e->key() == Key_BackTab ) {
282 /*
283 In QApplication, we map shift+tab to shift+backtab.
284 This code here reverts the mapping in a way that keeps
285 backtab and shift+tab accelerators working, in that
286 order, meaning backtab has priority.*/
287 key &= ~SHIFT;
288
289 temp.setKey( key, index );
290 if ( Qt::NoMatch != (result = temp.matches( item->key )) )
291 return result;
292 if ( e->state() & ShiftButton )
293 key |= SHIFT;
294 key = Key_Tab | ( key & MODIFIER_MASK );
295 temp.setKey( key, index );
296 if ( Qt::NoMatch != (result = temp.matches( item->key )) )
297 return result;
298 } else {
299 temp.setKey( key, index );
300 if ( Qt::NoMatch != (result = temp.matches( item->key )) )
301 return result;
302 }
303
304 if ( key == Key_BackTab ) {
305 if ( e->state() & ShiftButton )
306 key |= SHIFT;
307 temp.setKey( key, index );
308 if ( Qt::NoMatch != (result = temp.matches( item->key )) )
309 return result;
310 }
311 }
312 if ( !e->text().isEmpty() ) {
313 temp.setKey( (int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index );
314 result = temp.matches( item->key );
315 }
316 return result;
317}
318
319bool QAccelManager::tryAccelEvent( QWidget* w, QKeyEvent* e )
320{
321 if ( Qt::NoMatch == currentState ) {
322 e->t = QEvent::AccelOverride;
323 e->ignore();
324 QApplication::sendSpontaneousEvent( w, e );
325 if ( e->isAccepted() )
326 return FALSE;
327 }
328 e->t = QEvent::Accel;
329 e->ignore();
330 QApplication::sendSpontaneousEvent( w, e );
331 return e->isAccepted();
332}
333
334bool QAccelManager::tryComposeUnicode( QWidget* w, QKeyEvent* e )
335{
336 if ( QApplication::metaComposeUnicode ) {
337 int value = e->key() - Key_0;
338 // Ignore acceloverrides so we don't trigger
339 // accels on keypad when Meta compose is on
340 if ( (e->type() == QEvent::AccelOverride) &&
341 (e->state() == Qt::Keypad + Qt::MetaButton) ) {
342 e->accept();
343 // Meta compose start/continue
344 } else if ( (e->type() == QEvent::KeyPress) &&
345 (e->state() == Qt::Keypad + Qt::MetaButton) ) {
346 if ( value >= 0 && value <= 9 ) {
347 QApplication::composedUnicode *= 10;
348 QApplication::composedUnicode += value;
349 return TRUE;
350 } else {
351 // Composing interrupted, dispatch!
352 if ( QApplication::composedUnicode ) {
353 QChar ch( QApplication::composedUnicode );
354 QString s( ch );
355 QKeyEvent kep( QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s );
356 QKeyEvent ker( QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s );
357 QApplication::sendEvent( w, &kep );
358 QApplication::sendEvent( w, &ker );
359 }
360 QApplication::composedUnicode = 0;
361 return TRUE;
362 }
363 // Meta compose end, dispatch
364 } else if ( (e->type() == QEvent::KeyRelease) &&
365 (e->key() == Key_Meta) &&
366 (QApplication::composedUnicode != 0) ) {
367 if ( (QApplication::composedUnicode > 0) &&
368 (QApplication::composedUnicode < 0xFFFE) ) {
369 QChar ch( QApplication::composedUnicode );
370 QString s( ch );
371 QKeyEvent kep( QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s );
372 QKeyEvent ker( QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s );
373 QApplication::sendEvent( w, &kep );
374 QApplication::sendEvent( w, &ker );
375 }
376 QApplication::composedUnicode = 0;
377 return TRUE;
378 }
379 }
380 return FALSE;
381}
382
383/*
384 \internal
385 Checks for possible accelerators, if no widget
386 ate the keypres, or we are in the middle of a
387 partial key sequence.
388*/
389bool QAccelManager::dispatchAccelEvent( QWidget* w, QKeyEvent* e )
390{
391#ifndef QT_NO_STATUSBAR
392 // Needs to be declared and used here because of "goto doclash"
393 QStatusBar* mainStatusBar = 0;
394#endif
395
396 // Modifiers can NOT be accelerators...
397 if ( e->key() >= Key_Shift &&
398 e->key() <= Key_Alt )
399 return FALSE;
400
401 SequenceMatch result = Qt::NoMatch;
402 QKeySequence tocheck, partial;
403 QAccelPrivate* accel = 0;
404 QAccelItem* item = 0;
405 QAccelPrivate* firstaccel = 0;
406 QAccelItem* firstitem = 0;
407 QAccelPrivate* lastaccel = 0;
408 QAccelItem* lastitem = 0;
409
410 QKeyEvent pe = *e;
411 int n = -1;
412 int hasShift = (e->state()&Qt::ShiftButton)?1:0;
413 bool identicalDisabled = FALSE;
414 bool matchFound = FALSE;
415 do {
416 accel = accels.first();
417 matchFound = FALSE;
418 while ( accel ) {
419 if ( correctSubWindow( w, accel ) ) {
420 if ( accel->enabled ) {
421 item = accel->aitems.last();
422 while( item ) {
423 if ( Qt::Identical == (result = match( &pe, item, tocheck )) ) {
424 if ( item->enabled ) {
425 if ( !firstaccel ) {
426 firstaccel = accel;
427 firstitem = item;
428 }
429 lastaccel = accel;
430 lastitem = item;
431 n++;
432 matchFound = TRUE;
433 if ( n > QMAX(clash,0) )
434 goto doclash;
435 } else {
436 identicalDisabled = TRUE;
437 }
438 }
439 if ( item->enabled && Qt::PartialMatch == result ) {
440 partial = tocheck;
441 matchFound = TRUE;
442 }
443 item = accel->aitems.prev();
444 }
445 } else {
446 item = accel->aitems.last();
447 while( item ) {
448 if ( Qt::Identical == match( &pe, item, tocheck ) )
449 identicalDisabled = TRUE;
450 item = accel->aitems.prev();
451 }
452 }
453 }
454 accel = accels.next();
455 }
456 pe = QKeyEvent( QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text() );
457 } while ( hasShift-- && !matchFound && !identicalDisabled );
458
459#ifndef QT_NO_STATUSBAR
460 mainStatusBar = (QStatusBar*) w->topLevelWidget()->child( 0, "QStatusBar" );
461#endif
462 if ( n < 0 ) { // no match found
463 currentState = partial.count() ? PartialMatch : NoMatch;
464#ifndef QT_NO_STATUSBAR
465 // Only display message if we are, or were, in a partial match
466 if ( mainStatusBar && (PartialMatch == currentState || intermediate.count() ) ) {
467 if ( currentState == Qt::PartialMatch ) {
468 mainStatusBar->message( (QString)partial + ", ...", 0 );
469 } else if (!identicalDisabled) {
470 QString message = QAccel::tr("%1, %2 not defined").
471 arg( (QString)intermediate ).
472 arg( QKeySequence::encodeString( e->key() | translateModifiers(e->state()) ) );
473 mainStatusBar->message( message, 2000 );
474 // Since we're a NoMatch, reset the clash count
475 clash = -1;
476 } else {
477 mainStatusBar->clear();
478 }
479 }
480#endif
481
482 bool eatKey = (PartialMatch == currentState || intermediate.count() );
483 intermediate = partial;
484 if ( eatKey )
485 e->accept();
486 return eatKey;
487 } else if ( n == 0 ) { // found exactly one match
488 clash = -1; // reset
489#ifndef QT_NO_STATUSBAR
490 if ( currentState == Qt::PartialMatch && mainStatusBar )
491 mainStatusBar->clear();
492#endif
493 currentState = Qt::NoMatch; // Free sequence keylock
494 intermediate = QKeySequence();
495 lastaccel->activate( lastitem );
496 e->accept();
497 return TRUE;
498 }
499
500 doclash: // found more than one match
501#ifndef QT_NO_STATUSBAR
502 if ( !mainStatusBar ) // if "goto doclash", we need to get statusbar again.
503 mainStatusBar = (QStatusBar*) w->topLevelWidget()->child( 0, "QStatusBar" );
504#endif
505
506 QString message = QAccel::tr( "Ambiguous \"%1\" not handled" ).arg( (QString)tocheck );
507 if ( clash >= 0 && n > clash ) { // pick next match
508 intermediate = QKeySequence();
509 currentState = Qt::NoMatch; // Free sequence keylock
510 clash++;
511#ifndef QT_NO_STATUSBAR
512 if ( mainStatusBar &&
513 !lastitem->signal &&
514 !(lastaccel->parent->receivers( "activatedAmbiguously(int)" )) )
515 mainStatusBar->message( message, 2000 );
516#endif
517 lastaccel->activateAmbiguously( lastitem );
518 } else { // start (or wrap) with the first matching
519 intermediate = QKeySequence();
520 currentState = Qt::NoMatch; // Free sequence keylock
521 clash = 0;
522#ifndef QT_NO_STATUSBAR
523 if ( mainStatusBar &&
524 !firstitem->signal &&
525 !(firstaccel->parent->receivers( "activatedAmbiguously(int)" )) )
526 mainStatusBar->message( message, 2000 );
527#endif
528 firstaccel->activateAmbiguously( firstitem );
529 }
530 e->accept();
531 return TRUE;
532}
533
534QAccelPrivate::QAccelPrivate( QAccel* p )
535 : parent( p )
536{
537 QAccelManager::self()->registerAccel( this );
538 aitems.setAutoDelete( TRUE );
539 ignorewhatsthis = FALSE;
540}
541
542QAccelPrivate::~QAccelPrivate()
543{
544 QAccelManager::self()->unregisterAccel( this );
545}
546
547static QAccelItem *find_id( QAccelList &list, int id )
548{
549 register QAccelItem *item = list.first();
550 while ( item && item->id != id )
551 item = list.next();
552 return item;
553}
554
555static QAccelItem *find_key( QAccelList &list, const QKeySequence &key )
556{
557 register QAccelItem *item = list.first();
558 while ( item && !( item->key == key ) )
559 item = list.next();
560 return item;
561}
562
563/*!
564 Constructs a QAccel object called \a name, with parent \a parent.
565 The accelerator operates on \a parent.
566*/
567
568QAccel::QAccel( QWidget *parent, const char *name )
569 : QObject( parent, name )
570{
571 d = new QAccelPrivate( this );
572 d->enabled = TRUE;
573 d->watch = parent;
574#if defined(QT_CHECK_NULL)
575 if ( !d->watch )
576 qWarning( "QAccel: An accelerator must have a parent or a watch widget" );
577#endif
578}
579
580/*!
581 Constructs a QAccel object called \a name, that operates on \a
582 watch, and is a child of \a parent.
583
584 This constructor is not needed for normal application programming.
585*/
586QAccel::QAccel( QWidget* watch, QObject *parent, const char *name )
587 : QObject( parent, name )
588{
589 d = new QAccelPrivate( this );
590 d->enabled = TRUE;
591 d->watch = watch;
592#if defined(QT_CHECK_NULL)
593 if ( !d->watch )
594 qWarning( "QAccel: An accelerator must have a parent or a watch widget" );
595#endif
596}
597
598/*!
599 Destroys the accelerator object and frees all allocated resources.
600*/
601
602QAccel::~QAccel()
603{
604 delete d;
605}
606
607
608/*!
609 \fn void QAccel::activated( int id )
610
611 This signal is emitted when an accelerator key is pressed. \a id
612 is a number that identifies this particular accelerator item.
613
614 \sa activatedAmbiguously()
615*/
616
617/*!
618 \fn void QAccel::activatedAmbiguously( int id )
619
620 This signal is emitted when an accelerator key is pressed. \a id
621 is a number that identifies this particular accelerator item.
622
623 \sa activated()
624*/
625
626
627/*!
628 Returns TRUE if the accelerator is enabled; otherwise returns
629 FALSE.
630
631 \sa setEnabled(), isItemEnabled()
632*/
633
634bool QAccel::isEnabled() const
635{
636 return d->enabled;
637}
638
639
640/*!
641 Enables the accelerator if \a enable is TRUE, or disables it if \a
642 enable is FALSE.
643
644 Individual keys can also be enabled or disabled using
645 setItemEnabled(). To work, a key must be an enabled item in an
646 enabled QAccel.
647
648 \sa isEnabled(), setItemEnabled()
649*/
650
651void QAccel::setEnabled( bool enable )
652{
653 d->enabled = enable;
654}
655
656
657/*!
658 Returns the number of accelerator items in this accelerator.
659*/
660
661uint QAccel::count() const
662{
663 return d->aitems.count();
664}
665
666
667static int get_seq_id()
668{
669 static int seq_no = -2; // -1 is used as return value in findKey()
670 return seq_no--;
671}
672
673/*!
674 Inserts an accelerator item and returns the item's identifier.
675
676 \a key is a key code and an optional combination of SHIFT, CTRL
677 and ALT. \a id is the accelerator item id.
678
679 If \a id is negative, then the item will be assigned a unique
680 negative identifier less than -1.
681
682 \code
683 QAccel *a = new QAccel( myWindow ); // create accels for myWindow
684 a->insertItem( CTRL + Key_P, 200 ); // Ctrl+P, e.g. to print document
685 a->insertItem( ALT + Key_X, 201 ); // Alt+X, e.g. to quit
686 a->insertItem( UNICODE_ACCEL + 'q', 202 ); // Unicode 'q', e.g. to quit
687 a->insertItem( Key_D ); // gets a unique negative id < -1
688 a->insertItem( CTRL + SHIFT + Key_P ); // gets a unique negative id < -1
689 \endcode
690*/
691
692int QAccel::insertItem( const QKeySequence& key, int id )
693{
694 if ( id == -1 )
695 id = get_seq_id();
696 d->aitems.insert( 0, new QAccelItem(key,id) );
697 return id;
698}
699
700/*!
701 Removes the accelerator item with the identifier \a id.
702*/
703
704void QAccel::removeItem( int id )
705{
706 if ( find_id( d->aitems, id) )
707 d->aitems.remove();
708}
709
710
711/*!
712 Removes all accelerator items.
713*/
714
715void QAccel::clear()
716{
717 d->aitems.clear();
718}
719
720
721/*!
722 Returns the key sequence of the accelerator item with identifier
723 \a id, or an invalid key sequence (0) if the id cannot be found.
724*/
725
726QKeySequence QAccel::key( int id )
727{
728 QAccelItem *item = find_id( d->aitems, id);
729 return item ? item->key : QKeySequence( 0 );
730}
731
732
733/*!
734 Returns the identifier of the accelerator item with the key code
735 \a key, or -1 if the item cannot be found.
736*/
737
738int QAccel::findKey( const QKeySequence& key ) const
739{
740 QAccelItem *item = find_key( d->aitems, key );
741 return item ? item->id : -1;
742}
743
744
745/*!
746 Returns TRUE if the accelerator item with the identifier \a id is
747 enabled. Returns FALSE if the item is disabled or cannot be found.
748
749 \sa setItemEnabled(), isEnabled()
750*/
751
752bool QAccel::isItemEnabled( int id ) const
753{
754 QAccelItem *item = find_id( d->aitems, id);
755 return item ? item->enabled : FALSE;
756}
757
758
759/*!
760 Enables the accelerator item with the identifier \a id if \a
761 enable is TRUE, and disables item \a id if \a enable is FALSE.
762
763 To work, an item must be enabled and be in an enabled QAccel.
764
765 \sa isItemEnabled(), isEnabled()
766*/
767
768void QAccel::setItemEnabled( int id, bool enable )
769{
770 QAccelItem *item = find_id( d->aitems, id);
771 if ( item )
772 item->enabled = enable;
773}
774
775
776/*!
777 Connects the accelerator item \a id to the slot \a member of \a
778 receiver.
779
780 \code
781 a->connectItem( 201, mainView, SLOT(quit()) );
782 \endcode
783
784 Of course, you can also send a signal as \a member.
785
786 Normally accelerators are connected to slots which then receive
787 the \c activated(int id) signal with the id of the accelerator
788 item that was activated. If you choose to connect a specific
789 accelerator item using this function, the \c activated() signal is
790 emitted if the associated key sequence is pressed but no \c
791 activated(int id) signal is emitted.
792
793 \sa disconnectItem()
794*/
795
796bool QAccel::connectItem( int id, const QObject *receiver, const char *member )
797{
798 QAccelItem *item = find_id( d->aitems, id);
799 if ( item ) {
800 if ( !item->signal ) {
801 item->signal = new QSignal;
802 Q_CHECK_PTR( item->signal );
803 }
804 return item->signal->connect( receiver, member );
805 }
806 return FALSE;
807}
808
809/*!
810 Disconnects an accelerator item with id \a id from the function
811 called \a member in the \a receiver object.
812
813 \sa connectItem()
814*/
815
816bool QAccel::disconnectItem( int id, const QObject *receiver,
817 const char *member )
818{
819 QAccelItem *item = find_id( d->aitems, id);
820 if ( item && item->signal )
821 return item->signal->disconnect( receiver, member );
822 return FALSE;
823}
824
825void QAccelPrivate::activate( QAccelItem* item )
826{
827#ifndef QT_NO_WHATSTHIS
828 if ( QWhatsThis::inWhatsThisMode() && !ignorewhatsthis ) {
829 QWhatsThis::leaveWhatsThisMode( item->whatsthis );
830 return;
831 }
832#endif
833 if ( item->signal )
834 item->signal->activate();
835 else
836 emit parent->activated( item->id );
837}
838
839void QAccelPrivate::activateAmbiguously( QAccelItem* item )
840{
841 if ( item->signal )
842 item->signal->activate();
843 else
844 emit parent->activatedAmbiguously( item->id );
845}
846
847
848/*!
849 Returns the shortcut key sequence for \a str, or an invalid key
850 sequence (0) if \a str has no shortcut sequence.
851
852 For example, shortcutKey("E&amp;xit") returns ALT+Key_X,
853 shortcutKey("&amp;Quit") returns ALT+Key_Q and shortcutKey("Quit")
854 returns 0. (In code that does not inherit the Qt namespace class,
855 you must write e.g. Qt::ALT+Qt::Key_Q.)
856
857 We provide a \link accelerators.html list of common accelerators
858 \endlink in English. At the time of writing, Microsoft and Open
859 Group do not appear to have issued equivalent recommendations for
860 other languages.
861*/
862
863QKeySequence QAccel::shortcutKey( const QString &str )
864{
865 if(qt_accel_no_shortcuts)
866 return QKeySequence();
867
868 int p = 0;
869 while ( p >= 0 ) {
870 p = str.find( '&', p ) + 1;
871 if ( p <= 0 || p >= (int)str.length() )
872 return 0;
873 if ( str[p] != '&' ) {
874 QChar c = str[p];
875 if ( c.isPrint() ) {
876 c = c.upper();
877 return QKeySequence( c.unicode() + ALT + UNICODE_ACCEL );
878 }
879 }
880 p++;
881 }
882 return QKeySequence();
883}
884
885/*! \obsolete
886
887 Creates an accelerator string for the key \a k.
888 For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc.
889 are translated (using QObject::tr()) in the "QAccel" context.
890
891 The function is superfluous. Cast the QKeySequence \a k to a
892 QString for the same effect.
893*/
894QString QAccel::keyToString( QKeySequence k )
895{
896 return (QString) k;
897}
898
899/*!\obsolete
900
901 Returns an accelerator code for the string \a s. For example
902 "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl",
903 "Shift", "Alt" are recognized, as well as their translated
904 equivalents in the "QAccel" context (using QObject::tr()). Returns 0
905 if \a s is not recognized.
906
907 This function is typically used with \link QObject::tr() tr
908 \endlink(), so that accelerator keys can be replaced in
909 translations:
910
911 \code
912 QPopupMenu *file = new QPopupMenu( this );
913 file->insertItem( p1, tr("&Open..."), this, SLOT(open()),
914 QAccel::stringToKey(tr("Ctrl+O", "File|Open")) );
915 \endcode
916
917 Notice the \c "File|Open" translator comment. It is by no means
918 necessary, but it provides some context for the human translator.
919
920
921 The function is superfluous. Construct a QKeySequence from the
922 string \a s for the same effect.
923
924 \sa QObject::tr()
925 \link i18n.html Internationalization with Qt \endlink
926*/
927QKeySequence QAccel::stringToKey( const QString & s )
928{
929 return QKeySequence( s );
930}
931
932
933/*!
934 Sets a What's This help text for the accelerator item \a id to \a
935 text.
936
937 The text will be shown when the application is in What's This mode
938 and the user hits the accelerator key.
939
940 To set What's This help on a menu item (with or without an
941 accelerator key), use QMenuData::setWhatsThis().
942
943 \sa whatsThis(), QWhatsThis::inWhatsThisMode(),
944 QMenuData::setWhatsThis(), QAction::setWhatsThis()
945*/
946void QAccel::setWhatsThis( int id, const QString& text )
947{
948
949 QAccelItem *item = find_id( d->aitems, id);
950 if ( item )
951 item->whatsthis = text;
952}
953
954/*!
955 Returns the What's This help text for the specified item \a id or
956 QString::null if no text has been specified.
957
958 \sa setWhatsThis()
959*/
960QString QAccel::whatsThis( int id ) const
961{
962
963 QAccelItem *item = find_id( d->aitems, id);
964 return item? item->whatsthis : QString::null;
965}
966
967/*!\internal */
968void QAccel::setIgnoreWhatsThis( bool b)
969{
970 d->ignorewhatsthis = b;
971}
972
973/*!\internal */
974bool QAccel::ignoreWhatsThis() const
975{
976 return d->ignorewhatsthis;
977}
978
979
980/*!
981
982\page accelerators.html
983
984\title Standard Accelerator Keys
985
986Applications invariably need to define accelerator keys for actions.
987Qt fully supports accelerators, for example with \l QAccel::shortcutKey().
988
989Here are Microsoft's recommendations for accelerator keys, with
990comments about the Open Group's recommendations where they exist
991and differ. For most commands, the Open Group either has no advice or
992agrees with Microsoft.
993
994The emboldened letter plus Alt is Microsoft's recommended choice, and
995we recommend supporting it. For an Apply button, for example, we
996recommend QButton::setText( \link QWidget::tr() tr \endlink("&amp;Apply") );
997
998If you have conflicting commands (e.g. About and Apply buttons in the
999same dialog), you must decide for yourself.
1000
1001\list
1002\i <b><u>A</u></b>bout
1003\i Always on <b><u>T</u></b>op
1004\i <b><u>A</u></b>pply
1005\i <b><u>B</u></b>ack
1006\i <b><u>B</u></b>rowse
1007\i <b><u>C</u></b>lose (CDE: Alt+F4; Alt+F4 is "close window" in Windows)
1008\i <b><u>C</u></b>opy (CDE: Ctrl+C, Ctrl+Insert)
1009\i <b><u>C</u></b>opy Here
1010\i Create <b><u>S</u></b>hortcut
1011\i Create <b><u>S</u></b>hortcut Here
1012\i Cu<b><u>t</u></b>
1013\i <b><u>D</u></b>elete
1014\i <b><u>E</u></b>dit
1015\i <b><u>E</u></b>xit (CDE: E<b><u>x</u></b>it)
1016\i <b><u>E</u></b>xplore
1017\i <b><u>F</u></b>ile
1018\i <b><u>F</u></b>ind
1019\i <b><u>H</u></b>elp
1020\i Help <b><u>T</u></b>opics
1021\i <b><u>H</u></b>ide
1022\i <b><u>I</u></b>nsert
1023\i Insert <b><u>O</u></b>bject
1024\i <b><u>L</u></b>ink Here
1025\i Ma<b><u>x</u></b>imize
1026\i Mi<b><u>n</u></b>imize
1027\i <b><u>M</u></b>ove
1028\i <b><u>M</u></b>ove Here
1029\i <b><u>N</u></b>ew
1030\i <b><u>N</u></b>ext
1031\i <b><u>N</u></b>o
1032\i <b><u>O</u></b>pen
1033\i Open <b><u>W</u></b>ith
1034\i Page Set<b><u>u</u></b>p
1035\i <b><u>P</u></b>aste
1036\i Paste <b><u>L</u></b>ink
1037\i Paste <b><u>S</u></b>hortcut
1038\i Paste <b><u>S</u></b>pecial
1039\i <b><u>P</u></b>ause
1040\i <b><u>P</u></b>lay
1041\i <b><u>P</u></b>rint
1042\i <b><u>P</u></b>rint Here
1043\i P<b><u>r</u></b>operties
1044\i <b><u>Q</u></b>uick View
1045\i <b><u>R</u></b>edo (CDE: Ctrl+Y, Shift+Alt+Backspace)
1046\i <b><u>R</u></b>epeat
1047\i <b><u>R</u></b>estore
1048\i <b><u>R</u></b>esume
1049\i <b><u>R</u></b>etry
1050\i <b><u>R</u></b>un
1051\i <b><u>S</u></b>ave
1052\i Save <b><u>A</u></b>s
1053\i Select <b><u>A</u></b>ll
1054\i Se<b><u>n</u></b>d To
1055\i <b><u>S</u></b>how
1056\i <b><u>S</u></b>ize
1057\i S<b><u>p</u></b>lit
1058\i <b><u>S</u></b>top
1059\i <b><u>U</u></b>ndo (CDE: Ctrl+Z or Alt+Backspace)
1060\i <b><u>V</u></b>iew
1061\i <b><u>W</u></b>hat's This?
1062\i <b><u>W</u></b>indow
1063\i <b><u>Y</u></b>es
1064\endlist
1065
1066There are also a lot of other keys and actions (that use other
1067modifier keys than Alt). See the Microsoft and The Open Group
1068documentation for details.
1069
1070The \link http://www.amazon.com/exec/obidos/ASIN/0735605661/trolltech/t
1071Microsoft book \endlink has ISBN 0735605661. The corresponding Open Group
1072book is very hard to find, rather expensive and we cannot recommend
1073it. However, if you really want it, OGPubs@opengroup.org might be able
1074to help. Ask them for ISBN 1859121047.
1075
1076*/
1077
1078/*! \obsolete serves no purpose anymore */
1079void QAccel::repairEventFilter() {}
1080/*! \obsolete serves no purpose anymore */
1081bool QAccel::eventFilter( QObject *, QEvent * ) { return FALSE; }
1082#endif // QT_NO_ACCEL
Note: See TracBrowser for help on using the repository browser.