Remove dependencies of QShortcutMap onto widgets

This is the first towards bringing shortcut support
back into QtGui.

Change-Id: Ic2cf376d08c326402fb90a0cf170a987b07ac304
Reviewed-on: http://codereview.qt-project.org/6577
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
This commit is contained in:
Lars Knoll 2011-10-12 22:07:45 +02:00 committed by Qt by Nokia
parent 3bdce9a8ba
commit 046740f5ce
8 changed files with 57 additions and 43 deletions

View File

@ -1898,7 +1898,7 @@ int QGraphicsWidget::grabShortcut(const QKeySequence &sequence, Qt::ShortcutCont
if (sequence.isEmpty()) if (sequence.isEmpty())
return 0; return 0;
// ### setAttribute(Qt::WA_GrabbedShortcut); // ### setAttribute(Qt::WA_GrabbedShortcut);
return qApp->d_func()->shortcutMap.addShortcut(this, sequence, context); return qApp->d_func()->shortcutMap.addShortcut(this, sequence, context, qWidgetShortcutContextMatcher);
} }
/*! /*!

View File

@ -139,7 +139,7 @@ void QActionPrivate::redoGrab(QShortcutMap &map)
map.removeShortcut(shortcutId, q); map.removeShortcut(shortcutId, q);
if (shortcut.isEmpty()) if (shortcut.isEmpty())
return; return;
shortcutId = map.addShortcut(q, shortcut, shortcutContext); shortcutId = map.addShortcut(q, shortcut, shortcutContext, qWidgetShortcutContextMatcher);
if (!enabled) if (!enabled)
map.setShortcutEnabled(false, shortcutId, q); map.setShortcutEnabled(false, shortcutId, q);
if (!autorepeat) if (!autorepeat)
@ -159,7 +159,7 @@ void QActionPrivate::redoGrabAlternate(QShortcutMap &map)
for(int i = 0; i < alternateShortcuts.count(); ++i) { for(int i = 0; i < alternateShortcuts.count(); ++i) {
const QKeySequence& alternate = alternateShortcuts.at(i); const QKeySequence& alternate = alternateShortcuts.at(i);
if (!alternate.isEmpty()) if (!alternate.isEmpty())
alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext)); alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext, qWidgetShortcutContextMatcher));
else else
alternateShortcutIds.append(0); alternateShortcutIds.append(0);
} }

View File

@ -214,7 +214,6 @@ private:
friend class QMenu; friend class QMenu;
friend class QMenuPrivate; friend class QMenuPrivate;
friend class QMenuBar; friend class QMenuBar;
friend class QShortcutMap;
friend class QToolButton; friend class QToolButton;
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
friend void qt_mac_clear_status_text(QAction *action); friend void qt_mac_clear_status_text(QAction *action);

View File

@ -10713,7 +10713,7 @@ int QWidget::grabShortcut(const QKeySequence &key, Qt::ShortcutContext context)
if (key.isEmpty()) if (key.isEmpty())
return 0; return 0;
setAttribute(Qt::WA_GrabbedShortcut); setAttribute(Qt::WA_GrabbedShortcut);
return qApp->d_func()->shortcutMap.addShortcut(this, key, context); return qApp->d_func()->shortcutMap.addShortcut(this, key, context, qWidgetShortcutContextMatcher);
} }
/*! /*!

View File

@ -750,7 +750,6 @@ private:
friend class QX11PaintEngine; friend class QX11PaintEngine;
friend class QWin32PaintEngine; friend class QWin32PaintEngine;
friend class QShortcutPrivate; friend class QShortcutPrivate;
friend class QShortcutMap;
friend class QWindowSurface; friend class QWindowSurface;
friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidget;
friend class QGraphicsProxyWidgetPrivate; friend class QGraphicsProxyWidgetPrivate;

View File

@ -172,7 +172,7 @@ void QShortcutPrivate::redoGrab(QShortcutMap &map)
map.removeShortcut(sc_id, q); map.removeShortcut(sc_id, q);
if (sc_sequence.isEmpty()) if (sc_sequence.isEmpty())
return; return;
sc_id = map.addShortcut(q, sc_sequence, sc_context); sc_id = map.addShortcut(q, sc_sequence, sc_context, qWidgetShortcutContextMatcher);
if (!sc_enabled) if (!sc_enabled)
map.setShortcutEnabled(false, sc_id, q); map.setShortcutEnabled(false, sc_id, q);
if (!sc_autorepeat) if (!sc_autorepeat)

View File

@ -70,23 +70,22 @@ QT_BEGIN_NAMESPACE
Keysequence for entry Keysequence for entry
Pointer to parent owning the sequence Pointer to parent owning the sequence
*/ */
struct QShortcutEntry struct QShortcutEntry
{ {
QShortcutEntry() QShortcutEntry()
: keyseq(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0) : keyseq(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0), contextMatcher(0)
{} {}
QShortcutEntry(const QKeySequence &k) QShortcutEntry(const QKeySequence &k)
: keyseq(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0) : keyseq(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(0), contextMatcher(0)
{} {}
QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i) QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a, QShortcutMap::ContextMatcher m)
: keyseq(k), context(c), enabled(true), autorepeat(1), id(i), owner(o) : keyseq(k), context(c), enabled(true), autorepeat(a), id(i), owner(o), contextMatcher(m)
{} {}
QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a) bool correctContext() const { return contextMatcher(owner, context); }
: keyseq(k), context(c), enabled(true), autorepeat(a), id(i), owner(o)
{}
bool operator<(const QShortcutEntry &f) const bool operator<(const QShortcutEntry &f) const
{ return keyseq < f.keyseq; } { return keyseq < f.keyseq; }
@ -97,6 +96,7 @@ struct QShortcutEntry
bool autorepeat : 1; bool autorepeat : 1;
signed int id; signed int id;
QObject *owner; QObject *owner;
QShortcutMap::ContextMatcher contextMatcher;
}; };
#if 0 //ndef QT_NO_DEBUG_STREAM #if 0 //ndef QT_NO_DEBUG_STREAM
@ -162,13 +162,13 @@ QShortcutMap::~QShortcutMap()
Adds a shortcut to the global map. Adds a shortcut to the global map.
Returns the id of the newly added shortcut. Returns the id of the newly added shortcut.
*/ */
int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context) int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context, ContextMatcher matcher)
{ {
Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner"); Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner");
Q_ASSERT_X(!key.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map"); Q_ASSERT_X(!key.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
Q_D(QShortcutMap); Q_D(QShortcutMap);
QShortcutEntry newEntry(owner, key, context, --(d->currentId), true); QShortcutEntry newEntry(owner, key, context, --(d->currentId), true, matcher);
QList<QShortcutEntry>::iterator it = qUpperBound(d->sequences.begin(), d->sequences.end(), newEntry); QList<QShortcutEntry>::iterator it = qUpperBound(d->sequences.begin(), d->sequences.end(), newEntry);
d->sequences.insert(it, newEntry); // Insert sorted d->sequences.insert(it, newEntry); // Insert sorted
#if defined(DEBUG_QSHORTCUTMAP) #if defined(DEBUG_QSHORTCUTMAP)
@ -425,7 +425,7 @@ bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
QList<QShortcutEntry>::ConstIterator it = qLowerBound(d->sequences.constBegin(), itEnd, entry); QList<QShortcutEntry>::ConstIterator it = qLowerBound(d->sequences.constBegin(), itEnd, entry);
for (;it != itEnd; ++it) { for (;it != itEnd; ++it) {
if (matches(entry.keyseq, (*it).keyseq) == QKeySequence::ExactMatch && correctContext(*it) && (*it).enabled) { if (matches(entry.keyseq, (*it).keyseq) == QKeySequence::ExactMatch && (*it).correctContext() && (*it).enabled) {
return true; return true;
} }
} }
@ -479,7 +479,7 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e)
break; break;
tempRes = matches(entry.keyseq, (*it).keyseq); tempRes = matches(entry.keyseq, (*it).keyseq);
oneKSResult = qMax(oneKSResult, tempRes); oneKSResult = qMax(oneKSResult, tempRes);
if (tempRes != QKeySequence::NoMatch && correctContext(*it)) { if (tempRes != QKeySequence::NoMatch && (*it).correctContext()) {
if (tempRes == QKeySequence::ExactMatch) { if (tempRes == QKeySequence::ExactMatch) {
if ((*it).enabled) if ((*it).enabled)
d->identicals.append(&*it); d->identicals.append(&*it);
@ -618,12 +618,23 @@ QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1,
return match; return match;
} }
static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window);
#ifndef QT_NO_GRAPHICSVIEW
static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window);
#endif
#ifndef QT_NO_ACTION
static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window);
#endif
/*! \internal /*! \internal
Returns true if the widget \a w is a logical sub window of the current Returns true if the widget \a w is a logical sub window of the current
top-level widget. top-level widget.
*/ */
bool QShortcutMap::correctContext(const QShortcutEntry &item) const { bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context)
Q_ASSERT_X(item.owner, "QShortcutMap", "Shortcut has no owner. Illegal map state!"); {
Q_ASSERT_X(object, "QShortcutMap", "Shortcut has no owner. Illegal map state!");
QWidget *active_window = QApplication::activeWindow(); QWidget *active_window = QApplication::activeWindow();
@ -635,23 +646,31 @@ bool QShortcutMap::correctContext(const QShortcutEntry &item) const {
if (!active_window) if (!active_window)
return false; return false;
#ifndef QT_NO_ACTION #ifndef QT_NO_ACTION
if (QAction *a = qobject_cast<QAction *>(item.owner)) if (QAction *a = qobject_cast<QAction *>(object))
return correctContext(item.context, a, active_window); return correctActionContext(context, a, active_window);
#endif #endif
#ifndef QT_NO_GRAPHICSVIEW #ifndef QT_NO_GRAPHICSVIEW
if (QGraphicsWidget *gw = qobject_cast<QGraphicsWidget *>(item.owner)) if (QGraphicsWidget *gw = qobject_cast<QGraphicsWidget *>(object))
return correctGraphicsWidgetContext(item.context, gw, active_window); return correctGraphicsWidgetContext(context, gw, active_window);
#endif #endif
QWidget *w = qobject_cast<QWidget *>(item.owner);
QWidget *w = qobject_cast<QWidget *>(object);
if (!w) { if (!w) {
QShortcut *s = qobject_cast<QShortcut *>(item.owner); QShortcut *s = qobject_cast<QShortcut *>(object);
if (s)
w = s->parentWidget(); w = s->parentWidget();
} }
return correctWidgetContext(item.context, w, active_window);
if (!w)
return false;
return correctWidgetContext(context, w, active_window);
} }
bool QShortcutMap::correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window) const static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window)
{ {
bool visible = w->isVisible(); bool visible = w->isVisible();
#ifdef Q_WS_MAC #ifdef Q_WS_MAC
@ -678,7 +697,7 @@ bool QShortcutMap::correctWidgetContext(Qt::ShortcutContext context, QWidget *w,
// Below is Qt::WindowShortcut context // Below is Qt::WindowShortcut context
QWidget *tlw = w->window(); QWidget *tlw = w->window();
#ifndef QT_NO_GRAPHICSVIEW #ifndef QT_NO_GRAPHICSVIEW
if (QWExtra *topData = tlw->d_func()->extra) { if (QWExtra *topData = static_cast<QWidgetPrivate *>(QObjectPrivate::get(tlw))->extra) {
if (topData->proxyWidget) { if (topData->proxyWidget) {
bool res = correctGraphicsWidgetContext(context, (QGraphicsWidget *)topData->proxyWidget, active_window); bool res = correctGraphicsWidgetContext(context, (QGraphicsWidget *)topData->proxyWidget, active_window);
return res; return res;
@ -714,7 +733,7 @@ bool QShortcutMap::correctWidgetContext(Qt::ShortcutContext context, QWidget *w,
} }
#ifndef QT_NO_GRAPHICSVIEW #ifndef QT_NO_GRAPHICSVIEW
bool QShortcutMap::correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window) const static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window)
{ {
bool visible = w->isVisible(); bool visible = w->isVisible();
#ifdef Q_WS_MAC #ifdef Q_WS_MAC
@ -774,9 +793,9 @@ bool QShortcutMap::correctGraphicsWidgetContext(Qt::ShortcutContext context, QGr
#endif #endif
#ifndef QT_NO_ACTION #ifndef QT_NO_ACTION
bool QShortcutMap::correctContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window) const static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window)
{ {
const QList<QWidget *> &widgets = a->d_func()->widgets; const QList<QWidget *> &widgets = static_cast<QActionPrivate *>(QObjectPrivate::get(a))->widgets;
#if defined(DEBUG_QSHORTCUTMAP) #if defined(DEBUG_QSHORTCUTMAP)
if (widgets.isEmpty()) if (widgets.isEmpty())
qDebug() << a << "not connected to any widgets; won't trigger"; qDebug() << a << "not connected to any widgets; won't trigger";
@ -786,7 +805,7 @@ bool QShortcutMap::correctContext(Qt::ShortcutContext context, QAction *a, QWidg
#ifndef QT_NO_MENU #ifndef QT_NO_MENU
if (QMenu *menu = qobject_cast<QMenu *>(w)) { if (QMenu *menu = qobject_cast<QMenu *>(w)) {
QAction *a = menu->menuAction(); QAction *a = menu->menuAction();
if (correctContext(context, a, active_window)) if (correctActionContext(context, a, active_window))
return true; return true;
} else } else
#endif #endif
@ -795,7 +814,7 @@ bool QShortcutMap::correctContext(Qt::ShortcutContext context, QAction *a, QWidg
} }
#ifndef QT_NO_GRAPHICSVIEW #ifndef QT_NO_GRAPHICSVIEW
const QList<QGraphicsWidget *> &graphicsWidgets = a->d_func()->graphicsWidgets; const QList<QGraphicsWidget *> &graphicsWidgets = static_cast<QActionPrivate *>(QObjectPrivate::get(a))->graphicsWidgets;
#if defined(DEBUG_QSHORTCUTMAP) #if defined(DEBUG_QSHORTCUTMAP)
if (graphicsWidgets.isEmpty()) if (graphicsWidgets.isEmpty())
qDebug() << a << "not connected to any widgets; won't trigger"; qDebug() << a << "not connected to any widgets; won't trigger";

View File

@ -72,6 +72,8 @@ class QWidget;
class QAction; class QAction;
class QObject; class QObject;
bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context);
class QShortcutMap class QShortcutMap
{ {
Q_DECLARE_PRIVATE(QShortcutMap) Q_DECLARE_PRIVATE(QShortcutMap)
@ -79,7 +81,9 @@ public:
QShortcutMap(); QShortcutMap();
~QShortcutMap(); ~QShortcutMap();
int addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context); typedef bool (*ContextMatcher)(QObject *object, Qt::ShortcutContext context);
int addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context, ContextMatcher matcher);
int removeShortcut(int id, QObject *owner, const QKeySequence &key = QKeySequence()); int removeShortcut(int id, QObject *owner, const QKeySequence &key = QKeySequence());
int setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key = QKeySequence()); int setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key = QKeySequence());
int setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &key = QKeySequence()); int setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &key = QKeySequence());
@ -98,13 +102,6 @@ public:
private: private:
bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window) const;
#ifndef QT_NO_GRAPHICSVIEW
bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window) const;
#endif
#ifndef QT_NO_ACTION
bool correctContext(Qt::ShortcutContext context,QAction *a, QWidget *active_window) const;
#endif
QScopedPointer<QShortcutMapPrivate> d_ptr; QScopedPointer<QShortcutMapPrivate> d_ptr;
QKeySequence::SequenceMatch find(QKeyEvent *e); QKeySequence::SequenceMatch find(QKeyEvent *e);