~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/qt3support/other/q3accel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the Qt 3 compatibility classes of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "q3accel.h"
 
30
 
 
31
#include "q3signal.h"
 
32
#include "qapplication.h"
 
33
#include "qwidget.h"
 
34
#include "q3ptrlist.h"
 
35
#include "qwhatsthis.h"
 
36
#include "qpointer.h"
 
37
#include "qstatusbar.h"
 
38
#include "qdockwidget.h"
 
39
#include "qevent.h"
 
40
#include "qkeysequence.h"
 
41
#include "private/qapplication_p.h"
 
42
using namespace Qt;
 
43
 
 
44
/*!
 
45
    \class Q3Accel
 
46
    \brief The Q3Accel class handles keyboard accelerator and shortcut keys.
 
47
 
 
48
    \compat
 
49
 
 
50
    A keyboard accelerator triggers an action when a certain key
 
51
    combination is pressed. The accelerator handles all keyboard
 
52
    activity for all the children of one top-level widget, so it is
 
53
    not affected by the keyboard focus.
 
54
 
 
55
    In most cases, you will not need to use this class directly. Use
 
56
    the QAction class to create actions with accelerators that can be
 
57
    used in both menus and toolbars. If you're only interested in
 
58
    menus use Q3MenuData::insertItem() or Q3MenuData::setAccel() to make
 
59
    accelerators for operations that are also available on menus. Many
 
60
    widgets automatically generate accelerators, such as QAbstractButton,
 
61
    QGroupBox, QLabel (with QLabel::setBuddy()), QMenuBar, and QTabBar.
 
62
    Example:
 
63
    \code
 
64
        QPushButton p("&Exit", parent); // automatic shortcut ALT+Key_E
 
65
        Q3PopupMenu *fileMenu = new fileMenu(parent);
 
66
        fileMenu->insertItem("Undo", parent, SLOT(undo()), CTRL+Key_Z);
 
67
    \endcode
 
68
 
 
69
    A Q3Accel contains a list of accelerator items that can be
 
70
    manipulated using insertItem(), removeItem(), clear(), key() and
 
71
    findKey().
 
72
 
 
73
    Each accelerator item consists of an identifier and a \l
 
74
    QKeySequence. A single key sequence consists of a keyboard code
 
75
    combined with modifiers (\c SHIFT, \c CTRL, \c ALT or \c
 
76
    UNICODE_ACCEL). For example, \c{CTRL + Key_P} could be a shortcut
 
77
    for printing a document. The key codes are listed in \c
 
78
    qnamespace.h. As an alternative, use \c UNICODE_ACCEL with the
 
79
    unicode code point of the character. For example, \c{UNICODE_ACCEL
 
80
    + 'A'} gives the same accelerator as \c Key_A.
 
81
 
 
82
    When an accelerator key is pressed, the accelerator sends out the
 
83
    signal activated() with a number that identifies this particular
 
84
    accelerator item. Accelerator items can also be individually
 
85
    connected, so that two different keys will activate two different
 
86
    slots (see connectItem() and disconnectItem()).
 
87
 
 
88
    The activated() signal is \e not emitted when two or more
 
89
    accelerators match the same key.  Instead, the first matching
 
90
    accelerator sends out the activatedAmbiguously() signal. By
 
91
    pressing the key multiple times, users can navigate between all
 
92
    matching accelerators. Some standard controls like QPushButton and
 
93
    QCheckBox connect the activatedAmbiguously() signal to the
 
94
    harmless setFocus() slot, whereas activated() is connected to a
 
95
    slot invoking the button's action.  Most controls, like QLabel and
 
96
    QTabBar, treat activated() and activatedAmbiguously() as
 
97
    equivalent.
 
98
 
 
99
    Use setEnabled() to enable or disable all the items in an
 
100
    accelerator, or setItemEnabled() to enable or disable individual
 
101
    items. An item is active only when both the Q3Accel and the item
 
102
    itself are enabled.
 
103
 
 
104
    The function setWhatsThis() specifies a help text that appears
 
105
    when the user presses an accelerator key in What's This mode.
 
106
 
 
107
    The accelerator will be deleted when \e parent is deleted,
 
108
    and will consume relevant key events until then.
 
109
 
 
110
    Please note that the accelerator
 
111
    \code
 
112
        accelerator->insertItem(QKeySequence("M"));
 
113
    \endcode
 
114
    can be triggered with both the 'M' key, and with Shift+M,
 
115
    unless a second accelerator is defined for the Shift+M
 
116
    combination.
 
117
 
 
118
 
 
119
    Example:
 
120
    \code
 
121
        Q3Accel *a = new Q3Accel(myWindow);        // create accels for myWindow
 
122
        a->connectItem(a->insertItem(Key_P+CTRL), // adds Ctrl+P accelerator
 
123
                        myWindow,                  // connected to myWindow's
 
124
                        SLOT(printDoc()));         // printDoc() slot
 
125
    \endcode
 
126
 
 
127
    \sa QKeyEvent QWidget::keyPressEvent()
 
128
    QAbstractButton::setAccel() QLabel::setBuddy() QKeySequence
 
129
*/
 
130
 
 
131
 
 
132
struct Q3AccelItem {                            // internal accelerator item
 
133
    Q3AccelItem(const QKeySequence &k, int i)
 
134
        { key=k; id=i; enabled=true; signal=0; }
 
135
   ~Q3AccelItem()              { delete signal; }
 
136
    int             id;
 
137
    QKeySequence    key;
 
138
    bool            enabled;
 
139
    Q3Signal       *signal;
 
140
    QString         whatsthis;
 
141
};
 
142
 
 
143
 
 
144
typedef Q3PtrList<Q3AccelItem> Q3AccelList; // internal accelerator list
 
145
 
 
146
class Q3AccelPrivate {
 
147
public:
 
148
    Q3AccelPrivate(Q3Accel* p);
 
149
    ~Q3AccelPrivate();
 
150
    Q3AccelList aitems;
 
151
    bool enabled;
 
152
    QPointer<QWidget> watch;
 
153
    bool ignorewhatsthis;
 
154
    Q3Accel* parent;
 
155
 
 
156
    void activate(Q3AccelItem* item);
 
157
    void activateAmbiguously(Q3AccelItem* item);
 
158
};
 
159
 
 
160
class Q3AccelManager {
 
161
public:
 
162
    static Q3AccelManager* self() { return self_ptr ? self_ptr : new Q3AccelManager; }
 
163
    void registerAccel(Q3AccelPrivate* a) { accels.append(a); }
 
164
    void unregisterAccel(Q3AccelPrivate* a) { accels.removeRef(a); if (accels.isEmpty()) delete this; }
 
165
    bool tryAccelEvent(QWidget* w, QKeyEvent* e);
 
166
    bool dispatchAccelEvent(QWidget* w, QKeyEvent* e);
 
167
    bool tryComposeUnicode(QWidget* w, QKeyEvent* e);
 
168
 
 
169
private:
 
170
    Q3AccelManager()
 
171
        : currentState(QKeySequence::NoMatch), clash(-1), metaComposeUnicode(false),composedUnicode(0)
 
172
        { setFuncPtr(); self_ptr = this; }
 
173
    ~Q3AccelManager() { self_ptr = 0; }
 
174
    void setFuncPtr();
 
175
 
 
176
    bool correctSubWindow(QWidget *w, Q3AccelPrivate* d);
 
177
    QKeySequence::SequenceMatch match(QKeyEvent* e, Q3AccelItem* item, QKeySequence& temp);
 
178
    int translateModifiers(ButtonState state);
 
179
 
 
180
    Q3PtrList<Q3AccelPrivate> accels;
 
181
    static Q3AccelManager* self_ptr;
 
182
    QKeySequence::SequenceMatch currentState;
 
183
    QKeySequence intermediate;
 
184
    int clash;
 
185
    bool metaComposeUnicode;
 
186
    int composedUnicode;
 
187
};
 
188
Q3AccelManager* Q3AccelManager::self_ptr = 0;
 
189
 
 
190
bool Q_COMPAT_EXPORT qt_tryAccelEvent(QWidget* w, QKeyEvent*  e){
 
191
    return Q3AccelManager::self()->tryAccelEvent(w, e);
 
192
}
 
193
 
 
194
bool Q_COMPAT_EXPORT qt_dispatchAccelEvent(QWidget* w, QKeyEvent*  e){
 
195
    return Q3AccelManager::self()->dispatchAccelEvent(w, e);
 
196
}
 
197
 
 
198
bool Q_COMPAT_EXPORT qt_tryComposeUnicode(QWidget* w, QKeyEvent*  e){
 
199
    return Q3AccelManager::self()->tryComposeUnicode(w, e);
 
200
}
 
201
 
 
202
void Q3AccelManager::setFuncPtr() {
 
203
    if (qApp->d_func()->qt_compat_used)
 
204
        return;
 
205
    QApplicationPrivate *data = static_cast<QApplicationPrivate*>(qApp->d_ptr);
 
206
    data->qt_tryAccelEvent = qt_tryAccelEvent;
 
207
    data->qt_tryComposeUnicode = qt_tryComposeUnicode;
 
208
    data->qt_dispatchAccelEvent = qt_dispatchAccelEvent;
 
209
    data->qt_compat_used = true;
 
210
}
 
211
 
 
212
#ifdef Q_WS_MAC
 
213
static bool qt_accel_no_shortcuts = true;
 
214
#else
 
215
static bool qt_accel_no_shortcuts = false;
 
216
#endif
 
217
void Q_COMPAT_EXPORT qt_set_accel_auto_shortcuts(bool b) { qt_accel_no_shortcuts = b; }
 
218
 
 
219
/*
 
220
    \internal
 
221
    Returns true if the accel is in the current subwindow, else false.
 
222
*/
 
223
bool Q3AccelManager::correctSubWindow(QWidget* w, Q3AccelPrivate* d) {
 
224
#if !defined (Q_OS_MACX)
 
225
     if (!d->watch || !d->watch->isVisible() || !d->watch->isEnabled())
 
226
#else
 
227
    if (!d->watch || (!d->watch->isVisible() && !d->watch->inherits("QMenuBar")) || !d->watch->isEnabled())
 
228
#endif
 
229
        return false;
 
230
    QWidget* tlw = w->window();
 
231
    QWidget* wtlw = d->watch->window();
 
232
 
 
233
    /* if we live in a floating dock window, keep our parent's
 
234
     * accelerators working */
 
235
#ifndef QT_NO_MAINWINDOW
 
236
    if ((tlw->windowType() == Qt::Dialog) && tlw->parentWidget() && ::qobject_cast<QDockWidget*>(tlw))
 
237
        return tlw->parentWidget()->window() == wtlw;
 
238
 
 
239
    if (wtlw  != tlw)
 
240
        return false;
 
241
#endif
 
242
    /* if we live in a MDI subwindow, ignore the event if we are
 
243
       not the active document window */
 
244
    QWidget* sw = d->watch;
 
245
    while (sw && sw->windowType() != Qt::SubWindow)
 
246
        sw = sw->parentWidget(true);
 
247
    if (sw)  { // we are in a subwindow indeed
 
248
        QWidget* fw = w;
 
249
        while (fw && fw != sw)
 
250
            fw = fw->parentWidget(true);
 
251
        if (fw != sw) // focus widget not in our subwindow
 
252
            return false;
 
253
    }
 
254
    return true;
 
255
}
 
256
 
 
257
inline int Q3AccelManager::translateModifiers(ButtonState state)
 
258
{
 
259
    int result = 0;
 
260
    if (state & ShiftButton)
 
261
        result |= SHIFT;
 
262
    if (state & ControlButton)
 
263
        result |= CTRL;
 
264
    if (state & MetaButton)
 
265
        result |= META;
 
266
    if (state & AltButton)
 
267
        result |= ALT;
 
268
    return result;
 
269
}
 
270
 
 
271
/*
 
272
    \internal
 
273
    Matches the current intermediate key sequence + the latest
 
274
    keyevent, with and AccelItem. Returns Identical,
 
275
    PartialMatch or NoMatch, and fills \a temp with the
 
276
    resulting key sequence.
 
277
*/
 
278
QKeySequence::SequenceMatch Q3AccelManager::match(QKeyEvent *e, Q3AccelItem* item, QKeySequence& temp)
 
279
{
 
280
    QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
 
281
    int index = intermediate.count();
 
282
    temp = intermediate;
 
283
 
 
284
    int modifier = translateModifiers(e->state());
 
285
 
 
286
    if (e->key() && e->key() != Key_unknown) {
 
287
        int key = e->key()  | modifier;
 
288
        if (e->key() == Key_BackTab) {
 
289
            /*
 
290
            In QApplication, we map shift+tab to shift+backtab.
 
291
            This code here reverts the mapping in a way that keeps
 
292
            backtab and shift+tab accelerators working, in that
 
293
            order, meaning backtab has priority.*/
 
294
            key &= ~SHIFT;
 
295
 
 
296
            temp.setKey(key, index);
 
297
            if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
 
298
                return result;
 
299
            if (e->state() & ShiftButton)
 
300
                key |= SHIFT;
 
301
            key = Key_Tab | (key & MODIFIER_MASK);
 
302
            temp.setKey(key, index);
 
303
            if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
 
304
                return result;
 
305
        } else {
 
306
            temp.setKey(key, index);
 
307
            if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
 
308
                return result;
 
309
        }
 
310
 
 
311
        if (key == Key_BackTab) {
 
312
            if (e->state() & ShiftButton)
 
313
                key |= SHIFT;
 
314
            temp.setKey(key, index);
 
315
            if (QKeySequence::NoMatch != (result = temp.matches(item->key)))
 
316
                return result;
 
317
        }
 
318
    }
 
319
    if (!e->text().isEmpty()) {
 
320
        temp.setKey((int)e->text()[0].unicode() | UNICODE_ACCEL | modifier, index);
 
321
        result = temp.matches(item->key);
 
322
    }
 
323
    return result;
 
324
}
 
325
 
 
326
bool Q3AccelManager::tryAccelEvent(QWidget* w, QKeyEvent* e)
 
327
{
 
328
    if (QKeySequence::NoMatch == currentState) {
 
329
        e->t = QEvent::AccelOverride;
 
330
        e->ignore();
 
331
        QApplication::sendSpontaneousEvent(w, e);
 
332
        if (e->isAccepted())
 
333
            return false;
 
334
    }
 
335
    e->t = QEvent::Accel;
 
336
    e->ignore();
 
337
    QApplication::sendSpontaneousEvent(w, e);
 
338
    return e->isAccepted();
 
339
}
 
340
 
 
341
bool Q3AccelManager::tryComposeUnicode(QWidget* w, QKeyEvent* e)
 
342
{
 
343
    if (metaComposeUnicode) {
 
344
        int value = e->key() - Key_0;
 
345
        // Ignore acceloverrides so we don't trigger
 
346
        // accels on keypad when Meta compose is on
 
347
        if ((e->type() == QEvent::AccelOverride) &&
 
348
             (e->state() == Qt::Keypad + Qt::MetaButton)) {
 
349
            e->accept();
 
350
        // Meta compose start/continue
 
351
        } else if ((e->type() == QEvent::KeyPress) &&
 
352
             (e->state() == Qt::Keypad + Qt::MetaButton)) {
 
353
            if (value >= 0 && value <= 9) {
 
354
                composedUnicode *= 10;
 
355
                composedUnicode += value;
 
356
                return true;
 
357
            } else {
 
358
                // Composing interrupted, dispatch!
 
359
                if (composedUnicode) {
 
360
                    QChar ch(composedUnicode);
 
361
                    QString s(ch);
 
362
                    QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
 
363
                    QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
 
364
                    QApplication::sendEvent(w, &kep);
 
365
                    QApplication::sendEvent(w, &ker);
 
366
                }
 
367
                composedUnicode = 0;
 
368
                return true;
 
369
            }
 
370
        // Meta compose end, dispatch
 
371
        } else if ((e->type() == QEvent::KeyRelease) &&
 
372
                    (e->key() == Key_Meta) &&
 
373
                    (composedUnicode != 0)) {
 
374
            if ((composedUnicode > 0) &&
 
375
                 (composedUnicode < 0xFFFE)) {
 
376
                QChar ch(composedUnicode);
 
377
                QString s(ch);
 
378
                QKeyEvent kep(QEvent::KeyPress, 0, ch.row() ? 0 : ch.cell(), 0, s);
 
379
                QKeyEvent ker(QEvent::KeyRelease, 0, ch.row() ? 0 : ch.cell(), 0, s);
 
380
                QApplication::sendEvent(w, &kep);
 
381
                QApplication::sendEvent(w, &ker);
 
382
            }
 
383
            composedUnicode = 0;
 
384
            return true;
 
385
        }
 
386
    }
 
387
    return false;
 
388
}
 
389
 
 
390
/*
 
391
    \internal
 
392
    Checks for possible accelerators, if no widget
 
393
    ate the keypres, or we are in the middle of a
 
394
    partial key sequence.
 
395
*/
 
396
bool Q3AccelManager::dispatchAccelEvent(QWidget* w, QKeyEvent* e)
 
397
{
 
398
#ifndef QT_NO_STATUSBAR
 
399
    // Needs to be declared and used here because of "goto doclash"
 
400
    QStatusBar* mainStatusBar = 0;
 
401
#endif
 
402
 
 
403
    // Modifiers can NOT be accelerators...
 
404
    if (e->key() >= Key_Shift &&
 
405
         e->key() <= Key_Alt)
 
406
         return false;
 
407
 
 
408
    QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
 
409
    QKeySequence tocheck, partial;
 
410
    Q3AccelPrivate* accel = 0;
 
411
    Q3AccelItem* item = 0;
 
412
    Q3AccelPrivate* firstaccel = 0;
 
413
    Q3AccelItem* firstitem = 0;
 
414
    Q3AccelPrivate* lastaccel = 0;
 
415
    Q3AccelItem* lastitem = 0;
 
416
 
 
417
    QKeyEvent pe = *e;
 
418
    int n = -1;
 
419
    int hasShift = (e->state()&Qt::ShiftButton)?1:0;
 
420
    bool identicalDisabled = false;
 
421
    bool matchFound = false;
 
422
    do {
 
423
        accel = accels.first();
 
424
        matchFound = false;
 
425
        while (accel) {
 
426
            if (correctSubWindow(w, accel)) {
 
427
                if (accel->enabled) {
 
428
                    item = accel->aitems.last();
 
429
                    while(item) {
 
430
                        if (QKeySequence::Identical == (result = match(&pe, item, tocheck))) {
 
431
                            if (item->enabled) {
 
432
                                if (!firstaccel) {
 
433
                                    firstaccel = accel;
 
434
                                    firstitem = item;
 
435
                                }
 
436
                                lastaccel = accel;
 
437
                                lastitem = item;
 
438
                                n++;
 
439
                                matchFound = true;
 
440
                                if (n > QMAX(clash,0))
 
441
                                    goto doclash;
 
442
                            } else {
 
443
                                identicalDisabled = true;
 
444
                            }
 
445
                        }
 
446
                        if (item->enabled && QKeySequence::PartialMatch == result) {
 
447
                            partial = tocheck;
 
448
                            matchFound = true;
 
449
                        }
 
450
                        item = accel->aitems.prev();
 
451
                    }
 
452
                } else {
 
453
                    item = accel->aitems.last();
 
454
                    while(item) {
 
455
                        if (QKeySequence::Identical == match(&pe, item, tocheck))
 
456
                            identicalDisabled = true;
 
457
                        item = accel->aitems.prev();
 
458
                    }
 
459
                }
 
460
            }
 
461
            accel = accels.next();
 
462
        }
 
463
        pe = QKeyEvent(QEvent::Accel, pe.key(), pe.ascii(), pe.state()&~Qt::ShiftButton, pe.text());
 
464
    } while (hasShift-- && !matchFound && !identicalDisabled);
 
465
 
 
466
#ifndef QT_NO_STATUSBAR
 
467
    mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
 
468
#endif
 
469
    if (n < 0) { // no match found
 
470
        currentState = partial.count() ? QKeySequence::PartialMatch : QKeySequence::NoMatch;
 
471
#ifndef QT_NO_STATUSBAR
 
472
        // Only display message if we are, or were, in a partial match
 
473
        if (mainStatusBar && (QKeySequence::PartialMatch == currentState || intermediate.count())) {
 
474
            if (currentState == QKeySequence::PartialMatch) {
 
475
                mainStatusBar->showMessage((QString)partial + ", ...");
 
476
            } else if (!identicalDisabled) {
 
477
                QString message = Q3Accel::tr("%1, %2 not defined").
 
478
                    arg((QString)intermediate).
 
479
                    arg(QKeySequence::encodeString(e->key() | translateModifiers(e->state())));
 
480
                mainStatusBar->showMessage(message, 2000);
 
481
                // Since we're a NoMatch, reset the clash count
 
482
                clash = -1;
 
483
            } else {
 
484
                mainStatusBar->clearMessage();
 
485
            }
 
486
        }
 
487
#endif
 
488
 
 
489
        bool eatKey = (QKeySequence::PartialMatch == currentState || intermediate.count());
 
490
        intermediate = partial;
 
491
        if (eatKey)
 
492
            e->accept();
 
493
        return eatKey;
 
494
    } else if (n == 0) { // found exactly one match
 
495
        clash = -1; // reset
 
496
#ifndef QT_NO_STATUSBAR
 
497
        if (currentState == QKeySequence::PartialMatch && mainStatusBar)
 
498
                mainStatusBar->clearMessage();
 
499
#endif
 
500
        currentState = QKeySequence::NoMatch; // Free sequence keylock
 
501
        intermediate = QKeySequence();
 
502
        lastaccel->activate(lastitem);
 
503
        e->accept();
 
504
        return true;
 
505
    }
 
506
 
 
507
 doclash: // found more than one match
 
508
#ifndef QT_NO_STATUSBAR
 
509
    if (!mainStatusBar) // if "goto doclash", we need to get statusbar again.
 
510
        mainStatusBar = (QStatusBar*) w->window()->child(0, "QStatusBar");
 
511
#endif
 
512
 
 
513
    QString message = Q3Accel::tr("Ambiguous \"%1\" not handled").arg((QString)tocheck);
 
514
    if (clash >= 0 && n > clash) { // pick next  match
 
515
        intermediate = QKeySequence();
 
516
        currentState = QKeySequence::NoMatch; // Free sequence keylock
 
517
        clash++;
 
518
#ifndef QT_NO_STATUSBAR
 
519
        if (mainStatusBar &&
 
520
             !lastitem->signal &&
 
521
             !(lastaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
 
522
            mainStatusBar->showMessage(message, 2000);
 
523
#endif
 
524
        lastaccel->activateAmbiguously(lastitem);
 
525
    } else { // start (or wrap) with the first matching
 
526
        intermediate = QKeySequence();
 
527
        currentState = QKeySequence::NoMatch; // Free sequence keylock
 
528
        clash = 0;
 
529
#ifndef QT_NO_STATUSBAR
 
530
        if (mainStatusBar &&
 
531
             !firstitem->signal &&
 
532
             !(firstaccel->parent->receivers(SIGNAL(activatedAmbiguously(int)))))
 
533
            mainStatusBar->showMessage(message, 2000);
 
534
#endif
 
535
        firstaccel->activateAmbiguously(firstitem);
 
536
    }
 
537
    e->accept();
 
538
    return true;
 
539
}
 
540
 
 
541
Q3AccelPrivate::Q3AccelPrivate(Q3Accel* p)
 
542
    : parent(p)
 
543
{
 
544
    Q3AccelManager::self()->registerAccel(this);
 
545
    aitems.setAutoDelete(true);
 
546
    ignorewhatsthis = false;
 
547
}
 
548
 
 
549
Q3AccelPrivate::~Q3AccelPrivate()
 
550
{
 
551
    Q3AccelManager::self()->unregisterAccel(this);
 
552
}
 
553
 
 
554
static Q3AccelItem *find_id(Q3AccelList &list, int id)
 
555
{
 
556
    register Q3AccelItem *item = list.first();
 
557
    while (item && item->id != id)
 
558
        item = list.next();
 
559
    return item;
 
560
}
 
561
 
 
562
static Q3AccelItem *find_key(Q3AccelList &list, const QKeySequence &key)
 
563
{
 
564
    register Q3AccelItem *item = list.first();
 
565
    while (item && !(item->key == key))
 
566
        item = list.next();
 
567
    return item;
 
568
}
 
569
 
 
570
/*!
 
571
    Constructs a Q3Accel object called \a name, with parent \a parent.
 
572
    The accelerator operates on \a parent.
 
573
*/
 
574
 
 
575
Q3Accel::Q3Accel(QWidget *parent, const char *name)
 
576
    : QObject(parent, name)
 
577
{
 
578
    d = new Q3AccelPrivate(this);
 
579
    d->enabled = true;
 
580
    d->watch = parent;
 
581
#if defined(QT_CHECK_NULL)
 
582
    if (!d->watch)
 
583
        qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
 
584
#endif
 
585
}
 
586
 
 
587
/*!
 
588
    Constructs a Q3Accel object called \a name, that operates on \a
 
589
    watch, and is a child of \a parent.
 
590
 
 
591
    This constructor is not needed for normal application programming.
 
592
*/
 
593
Q3Accel::Q3Accel(QWidget* watch, QObject *parent, const char *name)
 
594
    : QObject(parent, name)
 
595
{
 
596
    d = new Q3AccelPrivate(this);
 
597
    d->enabled = true;
 
598
    d->watch = watch;
 
599
#if defined(QT_CHECK_NULL)
 
600
    if (!d->watch)
 
601
        qWarning("Q3Accel: An accelerator must have a parent or a watch widget");
 
602
#endif
 
603
}
 
604
 
 
605
/*!
 
606
    Destroys the accelerator object and frees all allocated resources.
 
607
*/
 
608
 
 
609
Q3Accel::~Q3Accel()
 
610
{
 
611
    delete d;
 
612
}
 
613
 
 
614
 
 
615
/*!
 
616
    \fn void Q3Accel::activated(int id)
 
617
 
 
618
    This signal is emitted when an accelerator key is pressed. \a id
 
619
    is a number that identifies this particular accelerator item.
 
620
 
 
621
    \sa activatedAmbiguously()
 
622
*/
 
623
 
 
624
/*!
 
625
    \fn void Q3Accel::activatedAmbiguously(int id)
 
626
 
 
627
    This signal is emitted when an accelerator key is pressed. \a id
 
628
    is a number that identifies this particular accelerator item.
 
629
 
 
630
    \sa activated()
 
631
*/
 
632
 
 
633
 
 
634
/*!
 
635
    Returns true if the accelerator is enabled; otherwise returns
 
636
    false.
 
637
 
 
638
    \sa setEnabled(), isItemEnabled()
 
639
*/
 
640
 
 
641
bool Q3Accel::isEnabled() const
 
642
{
 
643
    return d->enabled;
 
644
}
 
645
 
 
646
 
 
647
/*!
 
648
    Enables the accelerator if \a enable is true, or disables it if \a
 
649
    enable is false.
 
650
 
 
651
    Individual keys can also be enabled or disabled using
 
652
    setItemEnabled(). To work, a key must be an enabled item in an
 
653
    enabled Q3Accel.
 
654
 
 
655
    \sa isEnabled(), setItemEnabled()
 
656
*/
 
657
 
 
658
void Q3Accel::setEnabled(bool enable)
 
659
{
 
660
    d->enabled = enable;
 
661
}
 
662
 
 
663
 
 
664
/*!
 
665
    Returns the number of accelerator items in this accelerator.
 
666
*/
 
667
 
 
668
uint Q3Accel::count() const
 
669
{
 
670
    return d->aitems.count();
 
671
}
 
672
 
 
673
 
 
674
static int get_seq_id()
 
675
{
 
676
    static int seq_no = -2;  // -1 is used as return value in findKey()
 
677
    return seq_no--;
 
678
}
 
679
 
 
680
/*!
 
681
    Inserts an accelerator item and returns the item's identifier.
 
682
 
 
683
    \a key is a key code and an optional combination of SHIFT, CTRL
 
684
    and ALT. \a id is the accelerator item id.
 
685
 
 
686
    If \a id is negative, then the item will be assigned a unique
 
687
    negative identifier less than -1.
 
688
 
 
689
    \code
 
690
        Q3Accel *a = new Q3Accel(myWindow);        // create accels for myWindow
 
691
        a->insertItem(CTRL + Key_P, 200);          // Ctrl+P, e.g. to print document
 
692
        a->insertItem(ALT + Key_X, 201);           // Alt+X, e.g. to quit
 
693
        a->insertItem(UNICODE_ACCEL + 'q', 202); // Unicode 'q', e.g. to quit
 
694
        a->insertItem(Key_D);                      // gets a unique negative id < -1
 
695
        a->insertItem(CTRL + SHIFT + Key_P);       // gets a unique negative id < -1
 
696
    \endcode
 
697
*/
 
698
 
 
699
int Q3Accel::insertItem(const QKeySequence& key, int id)
 
700
{
 
701
    if (id == -1)
 
702
        id = get_seq_id();
 
703
    d->aitems.insert(0, new Q3AccelItem(key,id));
 
704
    return id;
 
705
}
 
706
 
 
707
/*!
 
708
    Removes the accelerator item with the identifier \a id.
 
709
*/
 
710
 
 
711
void Q3Accel::removeItem(int id)
 
712
{
 
713
    if (find_id(d->aitems, id))
 
714
        d->aitems.remove();
 
715
}
 
716
 
 
717
 
 
718
/*!
 
719
    Removes all accelerator items.
 
720
*/
 
721
 
 
722
void Q3Accel::clear()
 
723
{
 
724
    d->aitems.clear();
 
725
}
 
726
 
 
727
 
 
728
/*!
 
729
    Returns the key sequence of the accelerator item with identifier
 
730
    \a id, or an invalid key sequence (0) if the id cannot be found.
 
731
*/
 
732
 
 
733
QKeySequence Q3Accel::key(int id)
 
734
{
 
735
    Q3AccelItem *item = find_id(d->aitems, id);
 
736
    return item ? item->key : QKeySequence(0);
 
737
}
 
738
 
 
739
 
 
740
/*!
 
741
    Returns the identifier of the accelerator item with the key code
 
742
    \a key, or -1 if the item cannot be found.
 
743
*/
 
744
 
 
745
int Q3Accel::findKey(const QKeySequence& key) const
 
746
{
 
747
    Q3AccelItem *item = find_key(d->aitems, key);
 
748
    return item ? item->id : -1;
 
749
}
 
750
 
 
751
 
 
752
/*!
 
753
    Returns true if the accelerator item with the identifier \a id is
 
754
    enabled. Returns false if the item is disabled or cannot be found.
 
755
 
 
756
    \sa setItemEnabled(), isEnabled()
 
757
*/
 
758
 
 
759
bool Q3Accel::isItemEnabled(int id) const
 
760
{
 
761
    Q3AccelItem *item = find_id(d->aitems, id);
 
762
    return item ? item->enabled : false;
 
763
}
 
764
 
 
765
 
 
766
/*!
 
767
    Enables the accelerator item with the identifier \a id if \a
 
768
    enable is true, and disables item \a id if \a enable is false.
 
769
 
 
770
    To work, an item must be enabled and be in an enabled Q3Accel.
 
771
 
 
772
    \sa isItemEnabled(), isEnabled()
 
773
*/
 
774
 
 
775
void Q3Accel::setItemEnabled(int id, bool enable)
 
776
{
 
777
    Q3AccelItem *item = find_id(d->aitems, id);
 
778
    if (item)
 
779
        item->enabled = enable;
 
780
}
 
781
 
 
782
 
 
783
/*!
 
784
    Connects the accelerator item \a id to the slot \a member of \a
 
785
    receiver.
 
786
 
 
787
    \code
 
788
        a->connectItem(201, mainView, SLOT(quit()));
 
789
    \endcode
 
790
 
 
791
    Of course, you can also send a signal as \a member.
 
792
 
 
793
    Normally accelerators are connected to slots which then receive
 
794
    the \c activated(int id) signal with the id of the accelerator
 
795
    item that was activated. If you choose to connect a specific
 
796
    accelerator item using this function, the \c activated() signal is
 
797
    emitted if the associated key sequence is pressed but no \c
 
798
    activated(int id) signal is emitted.
 
799
 
 
800
    \sa disconnectItem()
 
801
*/
 
802
 
 
803
bool Q3Accel::connectItem(int id, const QObject *receiver, const char *member)
 
804
{
 
805
    Q3AccelItem *item = find_id(d->aitems, id);
 
806
    if (item) {
 
807
        if (!item->signal) {
 
808
            item->signal = new Q3Signal;
 
809
            Q_CHECK_PTR(item->signal);
 
810
        }
 
811
        return item->signal->connect(receiver, member);
 
812
    }
 
813
    return false;
 
814
}
 
815
 
 
816
/*!
 
817
    Disconnects an accelerator item with id \a id from the function
 
818
    called \a member in the \a receiver object.
 
819
 
 
820
    \sa connectItem()
 
821
*/
 
822
 
 
823
bool Q3Accel::disconnectItem(int id, const QObject *receiver,
 
824
                             const char *member)
 
825
{
 
826
    Q3AccelItem *item = find_id(d->aitems, id);
 
827
    if (item && item->signal)
 
828
        return item->signal->disconnect(receiver, member);
 
829
    return false;
 
830
}
 
831
 
 
832
void Q3AccelPrivate::activate(Q3AccelItem* item)
 
833
{
 
834
#ifndef QT_NO_WHATSTHIS
 
835
    if (QWhatsThis::inWhatsThisMode() && !ignorewhatsthis) {
 
836
        QWhatsThis::showText(QCursor::pos(), item->whatsthis);
 
837
        return;
 
838
    }
 
839
#endif
 
840
    if (item->signal)
 
841
        item->signal->activate();
 
842
    else
 
843
        emit parent->activated(item->id);
 
844
}
 
845
 
 
846
void Q3AccelPrivate::activateAmbiguously(Q3AccelItem* item)
 
847
{
 
848
    if (item->signal)
 
849
        item->signal->activate();
 
850
    else
 
851
        emit parent->activatedAmbiguously(item->id);
 
852
}
 
853
 
 
854
 
 
855
/*!
 
856
    Returns the shortcut key sequence for \a str, or an invalid key
 
857
    sequence (0) if \a str has no shortcut sequence.
 
858
 
 
859
    For example, shortcutKey("E&amp;xit") returns ALT+Key_X,
 
860
    shortcutKey("&amp;Quit") returns ALT+Key_Q and shortcutKey("Quit")
 
861
    returns 0. (In code that does not inherit the Qt namespace class,
 
862
    you must write e.g. Qt::ALT+Qt::Key_Q.)
 
863
 
 
864
    We provide a \link accelerators.html list of common accelerators
 
865
    \endlink in English. At the time of writing, Microsoft and Open
 
866
    Group do not appear to have issued equivalent recommendations for
 
867
    other languages.
 
868
*/
 
869
 
 
870
QKeySequence Q3Accel::shortcutKey(const QString &str)
 
871
{
 
872
    if(qt_accel_no_shortcuts)
 
873
        return QKeySequence();
 
874
 
 
875
    int p = 0;
 
876
    while (p >= 0) {
 
877
        p = str.find('&', p) + 1;
 
878
        if (p <= 0 || p >= (int)str.length())
 
879
            return 0;
 
880
        if (str[p] != '&') {
 
881
            QChar c = str[p];
 
882
            if (c.isPrint()) {
 
883
                char ltr = c.upper().latin1();
 
884
                if (ltr >= (char)Key_A && ltr <= (char)Key_Z)
 
885
                    c = ltr;
 
886
                else
 
887
                    c = c.lower();
 
888
                return QKeySequence(c.unicode() + ALT + UNICODE_ACCEL);
 
889
            }
 
890
        }
 
891
        p++;
 
892
    }
 
893
    return QKeySequence();
 
894
}
 
895
 
 
896
/*! \obsolete
 
897
 
 
898
   Creates an accelerator string for the key \a k.
 
899
   For instance CTRL+Key_O gives "Ctrl+O". The "Ctrl" etc.
 
900
   are translated (using QObject::tr()) in the "Q3Accel" context.
 
901
 
 
902
   The function is superfluous. Cast the QKeySequence \a k to a
 
903
   QString for the same effect.
 
904
*/
 
905
QString Q3Accel::keyToString(QKeySequence k)
 
906
{
 
907
    return (QString) k;
 
908
}
 
909
 
 
910
/*!\obsolete
 
911
 
 
912
  Returns an accelerator code for the string \a s. For example
 
913
  "Ctrl+O" gives CTRL+UNICODE_ACCEL+'O'. The strings "Ctrl",
 
914
  "Shift", "Alt" are recognized, as well as their translated
 
915
  equivalents in the "Q3Accel" context (using QObject::tr()). Returns 0
 
916
  if \a s is not recognized.
 
917
 
 
918
  This function is typically used with \link QObject::tr() tr
 
919
  \endlink(), so that accelerator keys can be replaced in
 
920
  translations:
 
921
 
 
922
  \code
 
923
    Q3PopupMenu *file = new Q3PopupMenu(this);
 
924
    file->insertItem(p1, tr("&Open..."), this, SLOT(open()),
 
925
                      Q3Accel::stringToKey(tr("Ctrl+O", "File|Open")));
 
926
  \endcode
 
927
 
 
928
  Notice the \c "File|Open" translator comment. It is by no means
 
929
  necessary, but it provides some context for the human translator.
 
930
 
 
931
  The function is superfluous. Construct a QKeySequence from the
 
932
  string \a s for the same effect.
 
933
 
 
934
  \sa QObject::tr(), {Internationalization with Qt}
 
935
*/
 
936
QKeySequence Q3Accel::stringToKey(const QString & s)
 
937
{
 
938
    return QKeySequence(s);
 
939
}
 
940
 
 
941
 
 
942
/*!
 
943
    Sets a What's This help text for the accelerator item \a id to \a
 
944
    text.
 
945
 
 
946
    The text will be shown when the application is in What's This mode
 
947
    and the user hits the accelerator key.
 
948
 
 
949
    To set What's This help on a menu item (with or without an
 
950
    accelerator key), use Q3MenuData::setWhatsThis().
 
951
 
 
952
    \sa whatsThis(), QWhatsThis::inWhatsThisMode(), QAction::setWhatsThis()
 
953
*/
 
954
void Q3Accel::setWhatsThis(int id, const QString& text)
 
955
{
 
956
    Q3AccelItem *item = find_id(d->aitems, id);
 
957
    if (item)
 
958
        item->whatsthis = text;
 
959
}
 
960
 
 
961
/*!
 
962
    Returns the What's This help text for the specified item \a id or
 
963
    an empty string if no text has been specified.
 
964
 
 
965
    \sa setWhatsThis()
 
966
*/
 
967
QString Q3Accel::whatsThis(int id) const
 
968
{
 
969
 
 
970
    Q3AccelItem *item = find_id(d->aitems, id);
 
971
    return item? item->whatsthis : QString();
 
972
}
 
973
 
 
974
/*!\internal */
 
975
void Q3Accel::setIgnoreWhatsThis(bool b)
 
976
{
 
977
    d->ignorewhatsthis = b;
 
978
}
 
979
 
 
980
/*!\internal */
 
981
bool Q3Accel::ignoreWhatsThis() const
 
982
{
 
983
    return d->ignorewhatsthis;
 
984
}
 
985
 
 
986
/*!
 
987
    \fn void Q3Accel::repairEventFilter()
 
988
    \internal
 
989
*/