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

« back to all changes in this revision

Viewing changes to src/gui/kernel/qshortcutmap.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 gui module 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 "qshortcutmap_p.h"
 
30
#include "private/qobject_p.h"
 
31
#include "qkeysequence.h"
 
32
#include "qdebug.h"
 
33
#include "qevent.h"
 
34
#include "qwidget.h"
 
35
#include "qapplication.h"
 
36
#include "qvector.h"
 
37
#include "qmenu.h"
 
38
#include "qshortcut.h"
 
39
#include "qapplication_p.h"
 
40
#include <private/qaction_p.h>
 
41
 
 
42
// To enable verbose output uncomment below
 
43
//#define Debug_QShortcutMap
 
44
 
 
45
/* \internal
 
46
    Entry data for QShortcutMap
 
47
    Contains:
 
48
        Keysequence for entry
 
49
        Pointer to parent owning the sequence
 
50
*/
 
51
struct QShortcutEntry
 
52
{
 
53
    QShortcutEntry()
 
54
        : keyseq(0), context(Qt::WindowShortcut), enabled(false), id(0), owner(0)
 
55
    {}
 
56
 
 
57
    QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i)
 
58
        : keyseq(k), context(c), enabled(true), id(i), owner(o)
 
59
    {}
 
60
 
 
61
    bool operator<(const QShortcutEntry &f) const
 
62
    { return keyseq < f.keyseq; }
 
63
 
 
64
    QKeySequence keyseq;
 
65
    Qt::ShortcutContext context;
 
66
    bool enabled : 1;
 
67
    signed int id : 31;
 
68
    QObject *owner;
 
69
};
 
70
 
 
71
#ifndef QT_NO_DEBUG
 
72
/*! \internal
 
73
    QDebug operator<< for easy debug output of the shortcut entries.
 
74
*/
 
75
QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) {
 
76
    if (!se)
 
77
        return dbg << "QShortcutEntry(0x0)";
 
78
    dbg.nospace()
 
79
        << "QShortcutEntry(" << se->keyseq
 
80
        << "), id(" << se->id << "), enabled(" << se->enabled << ") owner(" << se->owner << ")";
 
81
    return dbg.space();
 
82
}
 
83
#endif // QT_NO_DEBUG
 
84
 
 
85
/* \internal
 
86
    Private data for QShortcutMap
 
87
*/
 
88
class QShortcutMapPrivate
 
89
{
 
90
    Q_DECLARE_PUBLIC(QShortcutMap)
 
91
 
 
92
public:
 
93
    QShortcutMapPrivate(QShortcutMap* parent)
 
94
        : q_ptr(parent), currentId(0), ambigCount(0), currentState(QKeySequence::NoMatch)
 
95
    { identicals.reserve(10); }
 
96
    QShortcutMap *q_ptr;                        // Private's parent
 
97
 
 
98
    QList<QShortcutEntry> sequences;            // All sequences!
 
99
 
 
100
    int currentId;                              // Global shortcut ID number
 
101
    int ambigCount;                             // Index of last enabled ambiguous dispatch
 
102
    QKeySequence::SequenceMatch currentState;
 
103
    QKeySequence currentSequence;               // Sequence for the current state
 
104
    QKeySequence prevSequence;                  // Sequence for the previous identical match
 
105
    QVector<const QShortcutEntry*> identicals;  // Last identical matches
 
106
};
 
107
 
 
108
 
 
109
/*! \internal
 
110
    QShortcutMap constructor.
 
111
*/
 
112
QShortcutMap::QShortcutMap()
 
113
{
 
114
    d_ptr = new QShortcutMapPrivate(this);
 
115
    Q_ASSERT(d_ptr != 0);
 
116
    resetState();
 
117
}
 
118
 
 
119
/*! \internal
 
120
    QShortcutMap destructor.
 
121
*/
 
122
QShortcutMap::~QShortcutMap()
 
123
{
 
124
    delete d_ptr;
 
125
    d_ptr = 0;
 
126
}
 
127
 
 
128
/*! \internal
 
129
    Adds a shortcut to the global map.
 
130
    Returns the id of the newly added shortcut.
 
131
*/
 
132
int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context)
 
133
{
 
134
    Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner");
 
135
    Q_ASSERT_X(!key.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
 
136
    Q_D(QShortcutMap);
 
137
    
 
138
    QShortcutEntry newEntry(owner, key, context, --(d->currentId));
 
139
    QList<QShortcutEntry>::iterator it = qUpperBound(d->sequences.begin(), d->sequences.end(), newEntry);
 
140
    d->sequences.insert(it, newEntry); // Insert sorted
 
141
#if defined(Debug_QShortcutMap)
 
142
    qDebug().nospace()
 
143
        << "QShortcutMap::addShortcut(" << owner << ", "
 
144
        << key << ", " << context << ") = " << d->currentId;
 
145
#endif
 
146
    return d->currentId;
 
147
}
 
148
 
 
149
/*! \internal
 
150
    Removes a shortcut from the global map.
 
151
    If \a owner is 0, all entries in the map with the keysequence specified
 
152
    is removed. If \a key is null, all sequences for \a owner is removed from
 
153
    the map. If \a id is 0, any identical \a key sequences owned by \a owner
 
154
    are removed.
 
155
    Returns the number of sequences removed from the map.
 
156
*/
 
157
 
 
158
int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key)
 
159
{
 
160
    Q_D(QShortcutMap);
 
161
    int itemsRemoved = 0;
 
162
    bool allOwners = (owner == 0);
 
163
    bool allKeys = key.isEmpty();
 
164
    bool allIds = id == 0;
 
165
 
 
166
    // Special case, remove everything
 
167
    if (allOwners && allKeys && id == 0) {
 
168
        itemsRemoved = d->sequences.size();
 
169
        d->sequences.clear();
 
170
        return itemsRemoved;
 
171
    }
 
172
 
 
173
    int i = d->sequences.size()-1;
 
174
    while (i>=0)
 
175
    {
 
176
        const QShortcutEntry &entry = d->sequences.at(i);
 
177
        int entryId = entry.id;
 
178
        if ((allOwners || entry.owner == owner)
 
179
            && (allIds || entry.id == id)
 
180
            && (allKeys || entry.keyseq == key)) {
 
181
            d->sequences.removeAt(i);
 
182
            ++itemsRemoved;
 
183
        }
 
184
        if (id == entryId)
 
185
            return itemsRemoved;
 
186
        --i;
 
187
    }
 
188
#if defined(Debug_QShortcutMap)
 
189
    qDebug().nospace()
 
190
        << "QShortcutMap::removeShortcut(" << id << ", " << owner << ", "
 
191
        << key << ") = " << itemsRemoved;
 
192
#endif
 
193
    return itemsRemoved;
 
194
}
 
195
 
 
196
/*! \internal
 
197
    Changes the enable state of a shortcut to \a enable.
 
198
    If \a owner is 0, all entries in the map with the keysequence specified
 
199
    is removed. If \a key is null, all sequences for \a owner is removed from
 
200
    the map. If \a id is 0, any identical \a key sequences owned by \a owner
 
201
    are changed.
 
202
    Returns the number of sequences which are matched in the map.
 
203
*/
 
204
int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key)
 
205
{
 
206
    Q_D(QShortcutMap);
 
207
    int itemsChanged = 0;
 
208
    bool allOwners = (owner == 0);
 
209
    bool allKeys = key.isEmpty();
 
210
    bool allIds = id == 0;
 
211
 
 
212
    int i = d->sequences.size()-1;
 
213
    while (i>=0)
 
214
    {
 
215
        QShortcutEntry entry = d->sequences.at(i);
 
216
        if ((allOwners || entry.owner == owner)
 
217
            && (allIds || entry.id == id)
 
218
            && (allKeys || entry.keyseq == key)) {
 
219
            d->sequences[i].enabled = enable;
 
220
            ++itemsChanged;
 
221
        }
 
222
        if (id == entry.id)
 
223
            return itemsChanged;
 
224
        --i;
 
225
    }
 
226
#if defined(Debug_QShortcutMap)
 
227
    qDebug().nospace()
 
228
        << "QShortcutMap::setShortcutEnabled(" << enable << ", " << id << ", "
 
229
        << owner << ", " << key << ") = " << itemsChanged;
 
230
#endif
 
231
    return itemsChanged;
 
232
}
 
233
 
 
234
 
 
235
/*! \internal
 
236
    Resets the state of the statemachine to NoMatch
 
237
*/
 
238
void QShortcutMap::resetState()
 
239
{
 
240
    Q_D(QShortcutMap);
 
241
    d->currentState = QKeySequence::NoMatch;
 
242
    clearSequence(d->currentSequence);
 
243
}
 
244
 
 
245
/*! \internal
 
246
    Returns the current state of the statemachine
 
247
*/
 
248
QKeySequence::SequenceMatch QShortcutMap::state()
 
249
{
 
250
    Q_D(QShortcutMap);
 
251
    return d->currentState;
 
252
}
 
253
 
 
254
/*! \internal
 
255
    Uses ShortcutOverride event to see if any widgets want to override
 
256
    the event. If not, uses nextState(QKeyEvent) to check for a grabbed
 
257
    Shortcut, and dispatchEvent() is found an identical.
 
258
    \sa nextState dispatchEvent
 
259
*/
 
260
bool QShortcutMap::tryShortcutEvent(QWidget *w, QKeyEvent *e)
 
261
{
 
262
    Q_D(QShortcutMap);
 
263
    bool wasAccepted = e->isAccepted();
 
264
    if (d->currentState == QKeySequence::NoMatch) {
 
265
        ushort orgType = e->t;
 
266
        e->t = QEvent::ShortcutOverride;
 
267
        e->ignore();
 
268
        QApplication::sendSpontaneousEvent(w, e);
 
269
        e->t = orgType;
 
270
        if (e->isAccepted()) {
 
271
            if (!wasAccepted)
 
272
                e->ignore();
 
273
            return false;
 
274
        }
 
275
    }
 
276
 
 
277
    QKeySequence::SequenceMatch result = nextState(e);
 
278
    bool stateWasAccepted = e->isAccepted();
 
279
    if (wasAccepted)
 
280
        e->accept();
 
281
    else
 
282
        e->ignore();
 
283
 
 
284
    switch(result) {
 
285
    case QKeySequence::NoMatch:
 
286
        return stateWasAccepted;
 
287
    case QKeySequence::ExactMatch:
 
288
        resetState();
 
289
        dispatchEvent();
 
290
    default:
 
291
        break;
 
292
    }
 
293
    // If nextState is QKeySequence::ExactMatch && identicals.count == 0
 
294
    // we've only found disabled shortcuts
 
295
    return d->identicals.count() > 0 || result == QKeySequence::PartialMatch;
 
296
}
 
297
 
 
298
/*! \internal
 
299
    Returns the next state of the statemachine
 
300
    If return value is SequenceMatch::ExactMatch, then a call to matches()
 
301
    will return a QObjects* list of all matching objects for the last matching
 
302
    sequence.
 
303
*/
 
304
QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e)
 
305
{
 
306
    Q_D(QShortcutMap);
 
307
    // Modifiers can NOT be shortcuts...
 
308
    if (e->key() >= Qt::Key_Shift &&
 
309
        e->key() <= Qt::Key_Alt)
 
310
        return d->currentState;
 
311
 
 
312
    QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
 
313
 
 
314
    // We start fresh each time..
 
315
    d->identicals.resize(0);
 
316
 
 
317
    result = find(e);
 
318
    if (result == QKeySequence::NoMatch && e->modifiers() & Qt::ShiftModifier) {
 
319
        // If Shift + Key_Backtab, also try Shift + Qt::Key_Tab
 
320
        if (e->key() == Qt::Key_Backtab) {
 
321
            QKeyEvent pe = QKeyEvent(e->type(), Qt::Key_Tab, e->modifiers(), e->text());
 
322
            result = find(&pe);
 
323
        }
 
324
        // If still no result, try removing the Shift modifier
 
325
        if (result == QKeySequence::NoMatch) {
 
326
            QKeyEvent pe = QKeyEvent(e->type(), e->key(),
 
327
                                     e->modifiers()&~Qt::ShiftModifier, e->text());
 
328
            result = find(&pe);
 
329
        }
 
330
    }
 
331
 
 
332
    // Should we eat this key press?
 
333
    if (d->currentState == QKeySequence::PartialMatch
 
334
        || (d->currentState == QKeySequence::ExactMatch && d->identicals.count()))
 
335
        e->accept();
 
336
    // Does the new state require us to clean up?
 
337
    if (result == QKeySequence::NoMatch)
 
338
        clearSequence(d->currentSequence);
 
339
    d->currentState = result;
 
340
 
 
341
#if defined(Debug_QShortcutMap)
 
342
    qDebug().nospace() << "QShortcutMap::nextState(" << e << ") = " << result;
 
343
#endif
 
344
    return result;
 
345
}
 
346
 
 
347
/*! \internal
 
348
    Returns the next state of the statemachine, based
 
349
    on the new key event \a e.
 
350
    Matches are appended to the vector of identicals,
 
351
    which can be access through matches().
 
352
    \sa matches
 
353
*/
 
354
QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e)
 
355
{
 
356
    Q_D(QShortcutMap);
 
357
    if (!d->sequences.count())
 
358
        return QKeySequence::NoMatch;
 
359
    
 
360
    static QShortcutEntry newEntry;
 
361
    createNewSequence(e, newEntry.keyseq);
 
362
 
 
363
    // Should never happen
 
364
    if (newEntry.keyseq == d->currentSequence) {
 
365
        Q_ASSERT_X(e->key() != Qt::Key_unknown || e->text().length(),
 
366
                   "QShortcutMap::find", "New sequence to find identical to previous");
 
367
        return QKeySequence::NoMatch;
 
368
    }
 
369
 
 
370
    // Looking for new identicals, scrap old
 
371
    d->identicals.resize(0);
 
372
 
 
373
    QList<QShortcutEntry>::ConstIterator itEnd = d->sequences.constEnd();
 
374
    QList<QShortcutEntry>::ConstIterator it =
 
375
        qLowerBound(d->sequences.constBegin(), itEnd, newEntry);
 
376
 
 
377
    bool partialFound = false;
 
378
    bool identicalDisabledFound = false;
 
379
    QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
 
380
    do {
 
381
        if (it == itEnd)
 
382
            break;
 
383
        result = newEntry.keyseq.matches((*it).keyseq);
 
384
        if (result != QKeySequence::NoMatch && correctContext(*it)) {
 
385
            if (result == QKeySequence::ExactMatch) {
 
386
                if ((*it).enabled)
 
387
                    d->identicals.append(&*it);
 
388
                else
 
389
                    identicalDisabledFound = true;
 
390
            } else if (result == QKeySequence::PartialMatch) {
 
391
                // We don't need partials, if we have identicals
 
392
                if (d->identicals.size())
 
393
                    break;
 
394
                // We only care about enabled partials, so we don't consume
 
395
                // key events when all partials are disabled!
 
396
                partialFound |= (*it).enabled;
 
397
            }
 
398
        }
 
399
        ++it;
 
400
    } while (result != QKeySequence::NoMatch);
 
401
 
 
402
    if (d->identicals.size()) {
 
403
        result = QKeySequence::ExactMatch;
 
404
    } else if (partialFound) {
 
405
        result = QKeySequence::PartialMatch;
 
406
    } else if (identicalDisabledFound) {
 
407
        result = QKeySequence::ExactMatch;
 
408
    } else {
 
409
        clearSequence(d->currentSequence);
 
410
        result = QKeySequence::NoMatch;
 
411
    }
 
412
    if (result != QKeySequence::NoMatch)
 
413
        d->currentSequence = newEntry.keyseq;
 
414
    return result;
 
415
}
 
416
 
 
417
/*! \internal
 
418
    Clears \a seq to an empty QKeySequence.
 
419
    Same as doing (the slower)
 
420
    \code
 
421
        key = QKeySequence();
 
422
    \endcode
 
423
*/
 
424
void QShortcutMap::clearSequence(QKeySequence &seq)
 
425
{
 
426
    seq.setKey(0, 0);
 
427
    seq.setKey(0, 1);
 
428
    seq.setKey(0, 2);
 
429
    seq.setKey(0, 3);
 
430
}
 
431
 
 
432
/*! \internal
 
433
    Alters \a seq to the new sequence state, based on the
 
434
    current sequence state, and the new key event \a e.
 
435
*/
 
436
void QShortcutMap::createNewSequence(QKeyEvent *e, QKeySequence &seq)
 
437
{
 
438
    Q_D(QShortcutMap);
 
439
    seq.setKey(d->currentSequence[0], 0);
 
440
    seq.setKey(d->currentSequence[1], 1);
 
441
    seq.setKey(d->currentSequence[2], 2);
 
442
    seq.setKey(d->currentSequence[3], 3);
 
443
    int index = d->currentSequence.count();
 
444
    int modifier = translateModifiers(e->modifiers());
 
445
 
 
446
    // Use the key code, if possible to prevent Ctrl+<Key> text problems,
 
447
    // else use unicode of text
 
448
    if (e->key() && e->key() != Qt::Key_unknown)
 
449
        seq.setKey(e->key() | modifier, index);
 
450
    else
 
451
        seq.setKey((int)e->text().unicode()->toUpper().unicode() | modifier, index);
 
452
}
 
453
 
 
454
/*! \internal
 
455
    Returns true if the widget \a w is a logical sub window of the current
 
456
    top-level widget.
 
457
*/
 
458
bool QShortcutMap::correctContext(const QShortcutEntry &item) {
 
459
    Q_ASSERT_X(item.owner, "QShortcutMap", "Shortcut has no owner. Illegal map state!");
 
460
 
 
461
    QWidget *active_window = qApp->activeWindow();
 
462
 
 
463
    // popups do not become the active window,
 
464
    // so we fake it here to get the correct context
 
465
    // for the shortcut system.
 
466
    if (qApp->activePopupWidget())
 
467
        active_window = qApp->activePopupWidget();
 
468
    
 
469
    if (!active_window)
 
470
        return false;
 
471
 
 
472
    if (QAction *a = qobject_cast<QAction *>(item.owner))
 
473
        return correctContext(item.context, a, active_window);
 
474
 
 
475
    QWidget *w = qobject_cast<QWidget *>(item.owner);
 
476
    if (!w) {
 
477
        QShortcut *s = qobject_cast<QShortcut *>(item.owner);
 
478
        w = s->parentWidget();
 
479
    }
 
480
    return correctContext(item.context, w, active_window);
 
481
}
 
482
 
 
483
bool QShortcutMap::correctContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window)
 
484
{
 
485
    if (!w->isVisible() || !w->isEnabled())
 
486
        return false;
 
487
 
 
488
    if (context == Qt::ApplicationShortcut)
 
489
        return QApplicationPrivate::tryModalHelper(w, 0); // true, unless w is shadowed by a modal dialog
 
490
 
 
491
    if (context == Qt::WidgetShortcut)
 
492
        return w == QApplication::focusWidget();
 
493
 
 
494
    QWidget *tlw = w->window();
 
495
 
 
496
    /* if a floating tool window is active, keep shortcuts on the
 
497
     * parent working */
 
498
    if (active_window != tlw && active_window && active_window->windowType() == Qt::Tool && active_window->parentWidget()) {
 
499
        active_window = active_window->parentWidget()->window();
 
500
    }
 
501
 
 
502
    if (active_window  != tlw)
 
503
        return false;
 
504
 
 
505
    /* if we live in a MDI subwindow, ignore the event if we are
 
506
       not the active document window */
 
507
    const QWidget* sw = w;
 
508
    while (sw && !(sw->windowType() == Qt::SubWindow) && !sw->isWindow())
 
509
        sw = sw->parentWidget();
 
510
    if (sw && (sw->windowType() == Qt::SubWindow)) {
 
511
        QWidget *focus_widget = QApplication::focusWidget();
 
512
        while (focus_widget && focus_widget != sw)
 
513
            focus_widget = focus_widget->parentWidget();
 
514
        return sw == focus_widget;
 
515
    }
 
516
 
 
517
#if defined(Debug_QShortcutMap)
 
518
    qDebug().nospace() << "..true [Pass-through]";
 
519
#endif
 
520
    return true;
 
521
}
 
522
 
 
523
 
 
524
bool QShortcutMap::correctContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window)
 
525
{
 
526
    const QList<QWidget *> &widgets = a->d_func()->widgets;
 
527
    for (int i = 0; i < widgets.size(); ++i) {
 
528
        QWidget *w = widgets.at(i);
 
529
        if (QMenu *menu = qobject_cast<QMenu *>(w)) {
 
530
            QAction *a = menu->menuAction();
 
531
            if (correctContext(context, a, active_window))
 
532
                return true;
 
533
        } else {
 
534
            if (correctContext(context, w, active_window))
 
535
                return true;
 
536
        }
 
537
    }
 
538
    return false;
 
539
}
 
540
 
 
541
 
 
542
/*! \internal
 
543
    Converts keyboard button states into modifier states
 
544
*/
 
545
int QShortcutMap::translateModifiers(Qt::KeyboardModifiers modifiers)
 
546
{
 
547
    int result = 0;
 
548
    if (modifiers & Qt::ShiftModifier)
 
549
        result |= Qt::SHIFT;
 
550
    if (modifiers & Qt::ControlModifier)
 
551
        result |= Qt::CTRL;
 
552
    if (modifiers & Qt::MetaModifier)
 
553
        result |= Qt::META;
 
554
    if (modifiers & Qt::AltModifier)
 
555
        result |= Qt::ALT;
 
556
    return result;
 
557
}
 
558
 
 
559
/*! \internal
 
560
    Returns the vector of QShortcutEntry's matching the last Identical state.
 
561
*/
 
562
QVector<const QShortcutEntry*> QShortcutMap::matches() const
 
563
{
 
564
    Q_D(const QShortcutMap);
 
565
    return d->identicals;
 
566
}
 
567
 
 
568
/*! \internal
 
569
    Dispatches QShortcutEvents to widgets who grabbed the matched key sequence.
 
570
*/
 
571
void QShortcutMap::dispatchEvent()
 
572
{
 
573
    Q_D(QShortcutMap);
 
574
    if (!d->identicals.size())
 
575
        return;
 
576
 
 
577
    const QKeySequence &curKey = d->identicals.at(0)->keyseq;
 
578
    if (d->prevSequence != curKey) {
 
579
        d->ambigCount = 0;
 
580
        d->prevSequence = curKey;
 
581
    }
 
582
    // Find next
 
583
    const QShortcutEntry *current = 0, *next = 0;
 
584
    int i = 0, enabledShortcuts = 0;
 
585
    while(i < d->identicals.size()) {
 
586
        current = d->identicals.at(i);
 
587
        if (current->enabled || !next){
 
588
            ++enabledShortcuts;
 
589
            if (enabledShortcuts > d->ambigCount + 1)
 
590
                break;
 
591
            next = current;
 
592
        }
 
593
        ++i;
 
594
    }
 
595
    d->ambigCount = (d->identicals.size() == i ? 0 : d->ambigCount + 1);
 
596
    if (!next)
 
597
        return;
 
598
    // Dispatch next enabled
 
599
#if defined(Debug_QShortcutMap)
 
600
    qDebug().nospace()
 
601
        << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\""
 
602
        << (QString)curKey << "\", " << next->id << ", "
 
603
        << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ")";
 
604
#endif
 
605
    QShortcutEvent se(curKey, next->id, enabledShortcuts>1);
 
606
    QApplication::sendEvent(const_cast<QObject *>(next->owner), &se);
 
607
}
 
608
 
 
609
/* \internal
 
610
    QShortcutMap dump function, only available when Debug_QShortcutMap is
 
611
    defined.
 
612
*/
 
613
#if defined(Dump_QShortcutMap)
 
614
void QShortcutMap::dumpMap() const
 
615
{
 
616
    Q_D(const QShortcutMap);
 
617
    for (int i = 0; i < d->sequences.size(); ++i)
 
618
        qDebug().nospace() << &(d->sequences.at(i));
 
619
}
 
620
#endif