From 5d4756fc1b0e0acc862509887fdb8d9767387dcc Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 12 Oct 2011 22:21:44 +0200 Subject: Move the widget dependent code away from the shortcutmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qshortcut.cpp now has the honour of hosting the code that detects whether the a given shortcutcontext is actually valid. Change-Id: I59d299bbd2fd62fca074a51d96e85b81a50ae73c Reviewed-by: Samuel Rødal --- src/widgets/kernel/qwidget_p.h | 4 + src/widgets/to_be_moved/qshortcut.cpp | 213 +++++++++++++++++++++++++++++ src/widgets/to_be_moved/qshortcutmap.cpp | 221 +------------------------------ src/widgets/to_be_moved/qshortcutmap_p.h | 5 - 4 files changed, 218 insertions(+), 225 deletions(-) (limited to 'src/widgets') diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 01891c74c7..51a76d6ce3 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -115,6 +115,10 @@ class QStyle; class QUnifiedToolbarSurface; +// implemented in qshortcut.cpp +bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context); + + class Q_AUTOTEST_EXPORT QWidgetBackingStoreTracker { diff --git a/src/widgets/to_be_moved/qshortcut.cpp b/src/widgets/to_be_moved/qshortcut.cpp index f66c87dd13..94f809d199 100644 --- a/src/widgets/to_be_moved/qshortcut.cpp +++ b/src/widgets/to_be_moved/qshortcut.cpp @@ -49,6 +49,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -58,6 +59,218 @@ QT_BEGIN_NAMESPACE return; \ } + +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 + Returns true if the widget \a w is a logical sub window of the current + top-level widget. +*/ +bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context) +{ + Q_ASSERT_X(object, "QShortcutMap", "Shortcut has no owner. Illegal map state!"); + + QWidget *active_window = QApplication::activeWindow(); + + // popups do not become the active window, + // so we fake it here to get the correct context + // for the shortcut system. + if (QApplication::activePopupWidget()) + active_window = QApplication::activePopupWidget(); + + if (!active_window) + return false; + +#ifndef QT_NO_ACTION + if (QAction *a = qobject_cast(object)) + return correctActionContext(context, a, active_window); +#endif + +#ifndef QT_NO_GRAPHICSVIEW + if (QGraphicsWidget *gw = qobject_cast(object)) + return correctGraphicsWidgetContext(context, gw, active_window); +#endif + + QWidget *w = qobject_cast(object); + if (!w) { + QShortcut *s = qobject_cast(object); + if (s) + w = s->parentWidget(); + } + + if (!w) + return false; + + return correctWidgetContext(context, w, active_window); +} + +static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window) +{ + bool visible = w->isVisible(); +#ifdef Q_WS_MAC + if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast(w)) + visible = true; +#endif + + if (!visible || !w->isEnabled()) + return false; + + if (context == Qt::ApplicationShortcut) + return QApplicationPrivate::tryModalHelper(w, 0); // true, unless w is shadowed by a modal dialog + + if (context == Qt::WidgetShortcut) + return w == QApplication::focusWidget(); + + if (context == Qt::WidgetWithChildrenShortcut) { + const QWidget *tw = QApplication::focusWidget(); + while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup)) + tw = tw->parentWidget(); + return tw == w; + } + + // Below is Qt::WindowShortcut context + QWidget *tlw = w->window(); +#ifndef QT_NO_GRAPHICSVIEW + if (QWExtra *topData = static_cast(QObjectPrivate::get(tlw))->extra) { + if (topData->proxyWidget) { + bool res = correctGraphicsWidgetContext(context, (QGraphicsWidget *)topData->proxyWidget, active_window); + return res; + } + } +#endif + + /* if a floating tool window is active, keep shortcuts on the + * parent working */ + if (active_window != tlw && active_window && active_window->windowType() == Qt::Tool && active_window->parentWidget()) { + active_window = active_window->parentWidget()->window(); + } + + if (active_window != tlw) + return false; + + /* if we live in a MDI subwindow, ignore the event if we are + not the active document window */ + const QWidget* sw = w; + while (sw && !(sw->windowType() == Qt::SubWindow) && !sw->isWindow()) + sw = sw->parentWidget(); + if (sw && (sw->windowType() == Qt::SubWindow)) { + QWidget *focus_widget = QApplication::focusWidget(); + while (focus_widget && focus_widget != sw) + focus_widget = focus_widget->parentWidget(); + return sw == focus_widget; + } + +#if defined(DEBUG_QSHORTCUTMAP) + qDebug().nospace() << "..true [Pass-through]"; +#endif + return true; +} + +#ifndef QT_NO_GRAPHICSVIEW +static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window) +{ + bool visible = w->isVisible(); +#ifdef Q_WS_MAC + if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast(w)) + visible = true; +#endif + + if (!visible || !w->isEnabled() || !w->scene()) + return false; + + if (context == Qt::ApplicationShortcut) { + // Applicationwide shortcuts are always reachable unless their owner + // is shadowed by modality. In QGV there's no modality concept, but we + // must still check if all views are shadowed. + QList views = w->scene()->views(); + for (int i = 0; i < views.size(); ++i) { + if (QApplicationPrivate::tryModalHelper(views.at(i), 0)) + return true; + } + return false; + } + + if (context == Qt::WidgetShortcut) + return static_cast(w) == w->scene()->focusItem(); + + if (context == Qt::WidgetWithChildrenShortcut) { + const QGraphicsItem *ti = w->scene()->focusItem(); + if (ti && ti->isWidget()) { + const QGraphicsWidget *tw = static_cast(ti); + while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup)) + tw = tw->parentWidget(); + return tw == w; + } + return false; + } + + // Below is Qt::WindowShortcut context + + // Find the active view (if any). + QList views = w->scene()->views(); + QGraphicsView *activeView = 0; + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + if (view->window() == active_window) { + activeView = view; + break; + } + } + if (!activeView) + return false; + + // The shortcut is reachable if owned by a windowless widget, or if the + // widget's window is the same as the focus item's window. + QGraphicsWidget *a = w->scene()->activeWindow(); + return !w->window() || a == w->window(); +} +#endif + +#ifndef QT_NO_ACTION +static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window) +{ + const QList &widgets = static_cast(QObjectPrivate::get(a))->widgets; +#if defined(DEBUG_QSHORTCUTMAP) + if (widgets.isEmpty()) + qDebug() << a << "not connected to any widgets; won't trigger"; +#endif + for (int i = 0; i < widgets.size(); ++i) { + QWidget *w = widgets.at(i); +#ifndef QT_NO_MENU + if (QMenu *menu = qobject_cast(w)) { + QAction *a = menu->menuAction(); + if (correctActionContext(context, a, active_window)) + return true; + } else +#endif + if (correctWidgetContext(context, w, active_window)) + return true; + } + +#ifndef QT_NO_GRAPHICSVIEW + const QList &graphicsWidgets = static_cast(QObjectPrivate::get(a))->graphicsWidgets; +#if defined(DEBUG_QSHORTCUTMAP) + if (graphicsWidgets.isEmpty()) + qDebug() << a << "not connected to any widgets; won't trigger"; +#endif + for (int i = 0; i < graphicsWidgets.size(); ++i) { + QGraphicsWidget *w = graphicsWidgets.at(i); + if (correctGraphicsWidgetContext(context, w, active_window)) + return true; + } +#endif + return false; +} +#endif // QT_NO_ACTION + + /*! \class QShortcut \brief The QShortcut class is used to create keyboard shortcuts. diff --git a/src/widgets/to_be_moved/qshortcutmap.cpp b/src/widgets/to_be_moved/qshortcutmap.cpp index 547daaf132..64b0aa1741 100644 --- a/src/widgets/to_be_moved/qshortcutmap.cpp +++ b/src/widgets/to_be_moved/qshortcutmap.cpp @@ -42,20 +42,11 @@ #include "qshortcutmap_p.h" #include "private/qobject_p.h" #include "qkeysequence.h" -#include "qgraphicsscene.h" -#include "qgraphicsview.h" #include "qdebug.h" #include "qevent.h" -#include "qwidget.h" -#include "qapplication.h" #include "qvector.h" -#include "qmenu.h" -#include "qmenubar.h" -#include "qshortcut.h" -#include "private/qapplication_p.h" -#include +#include "qcoreapplication.h" #include -#include #ifndef QT_NO_SHORTCUT @@ -619,216 +610,6 @@ QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1, } -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 - Returns true if the widget \a w is a logical sub window of the current - top-level widget. -*/ -bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context) -{ - Q_ASSERT_X(object, "QShortcutMap", "Shortcut has no owner. Illegal map state!"); - - QWidget *active_window = QApplication::activeWindow(); - - // popups do not become the active window, - // so we fake it here to get the correct context - // for the shortcut system. - if (QApplication::activePopupWidget()) - active_window = QApplication::activePopupWidget(); - - if (!active_window) - return false; - -#ifndef QT_NO_ACTION - if (QAction *a = qobject_cast(object)) - return correctActionContext(context, a, active_window); -#endif - -#ifndef QT_NO_GRAPHICSVIEW - if (QGraphicsWidget *gw = qobject_cast(object)) - return correctGraphicsWidgetContext(context, gw, active_window); -#endif - - QWidget *w = qobject_cast(object); - if (!w) { - QShortcut *s = qobject_cast(object); - if (s) - w = s->parentWidget(); - } - - if (!w) - return false; - - return correctWidgetContext(context, w, active_window); -} - -static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window) -{ - bool visible = w->isVisible(); -#ifdef Q_WS_MAC - if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast(w)) - visible = true; -#endif - - if (!visible || !w->isEnabled()) - return false; - - if (context == Qt::ApplicationShortcut) - return QApplicationPrivate::tryModalHelper(w, 0); // true, unless w is shadowed by a modal dialog - - if (context == Qt::WidgetShortcut) - return w == QApplication::focusWidget(); - - if (context == Qt::WidgetWithChildrenShortcut) { - const QWidget *tw = QApplication::focusWidget(); - while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup)) - tw = tw->parentWidget(); - return tw == w; - } - - // Below is Qt::WindowShortcut context - QWidget *tlw = w->window(); -#ifndef QT_NO_GRAPHICSVIEW - if (QWExtra *topData = static_cast(QObjectPrivate::get(tlw))->extra) { - if (topData->proxyWidget) { - bool res = correctGraphicsWidgetContext(context, (QGraphicsWidget *)topData->proxyWidget, active_window); - return res; - } - } -#endif - - /* if a floating tool window is active, keep shortcuts on the - * parent working */ - if (active_window != tlw && active_window && active_window->windowType() == Qt::Tool && active_window->parentWidget()) { - active_window = active_window->parentWidget()->window(); - } - - if (active_window != tlw) - return false; - - /* if we live in a MDI subwindow, ignore the event if we are - not the active document window */ - const QWidget* sw = w; - while (sw && !(sw->windowType() == Qt::SubWindow) && !sw->isWindow()) - sw = sw->parentWidget(); - if (sw && (sw->windowType() == Qt::SubWindow)) { - QWidget *focus_widget = QApplication::focusWidget(); - while (focus_widget && focus_widget != sw) - focus_widget = focus_widget->parentWidget(); - return sw == focus_widget; - } - -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() << "..true [Pass-through]"; -#endif - return true; -} - -#ifndef QT_NO_GRAPHICSVIEW -static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window) -{ - bool visible = w->isVisible(); -#ifdef Q_WS_MAC - if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast(w)) - visible = true; -#endif - - if (!visible || !w->isEnabled() || !w->scene()) - return false; - - if (context == Qt::ApplicationShortcut) { - // Applicationwide shortcuts are always reachable unless their owner - // is shadowed by modality. In QGV there's no modality concept, but we - // must still check if all views are shadowed. - QList views = w->scene()->views(); - for (int i = 0; i < views.size(); ++i) { - if (QApplicationPrivate::tryModalHelper(views.at(i), 0)) - return true; - } - return false; - } - - if (context == Qt::WidgetShortcut) - return static_cast(w) == w->scene()->focusItem(); - - if (context == Qt::WidgetWithChildrenShortcut) { - const QGraphicsItem *ti = w->scene()->focusItem(); - if (ti && ti->isWidget()) { - const QGraphicsWidget *tw = static_cast(ti); - while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup)) - tw = tw->parentWidget(); - return tw == w; - } - return false; - } - - // Below is Qt::WindowShortcut context - - // Find the active view (if any). - QList views = w->scene()->views(); - QGraphicsView *activeView = 0; - for (int i = 0; i < views.size(); ++i) { - QGraphicsView *view = views.at(i); - if (view->window() == active_window) { - activeView = view; - break; - } - } - if (!activeView) - return false; - - // The shortcut is reachable if owned by a windowless widget, or if the - // widget's window is the same as the focus item's window. - QGraphicsWidget *a = w->scene()->activeWindow(); - return !w->window() || a == w->window(); -} -#endif - -#ifndef QT_NO_ACTION -static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window) -{ - const QList &widgets = static_cast(QObjectPrivate::get(a))->widgets; -#if defined(DEBUG_QSHORTCUTMAP) - if (widgets.isEmpty()) - qDebug() << a << "not connected to any widgets; won't trigger"; -#endif - for (int i = 0; i < widgets.size(); ++i) { - QWidget *w = widgets.at(i); -#ifndef QT_NO_MENU - if (QMenu *menu = qobject_cast(w)) { - QAction *a = menu->menuAction(); - if (correctActionContext(context, a, active_window)) - return true; - } else -#endif - if (correctWidgetContext(context, w, active_window)) - return true; - } - -#ifndef QT_NO_GRAPHICSVIEW - const QList &graphicsWidgets = static_cast(QObjectPrivate::get(a))->graphicsWidgets; -#if defined(DEBUG_QSHORTCUTMAP) - if (graphicsWidgets.isEmpty()) - qDebug() << a << "not connected to any widgets; won't trigger"; -#endif - for (int i = 0; i < graphicsWidgets.size(); ++i) { - QGraphicsWidget *w = graphicsWidgets.at(i); - if (correctGraphicsWidgetContext(context, w, active_window)) - return true; - } -#endif - return false; -} -#endif // QT_NO_ACTION - /*! \internal Converts keyboard button states into modifier states */ diff --git a/src/widgets/to_be_moved/qshortcutmap_p.h b/src/widgets/to_be_moved/qshortcutmap_p.h index 1cc0fd6421..29045eb7db 100644 --- a/src/widgets/to_be_moved/qshortcutmap_p.h +++ b/src/widgets/to_be_moved/qshortcutmap_p.h @@ -67,13 +67,8 @@ QT_BEGIN_NAMESPACE class QKeyEvent; struct QShortcutEntry; class QShortcutMapPrivate; -class QGraphicsWidget; -class QWidget; -class QAction; class QObject; -bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context); - class QShortcutMap { Q_DECLARE_PRIVATE(QShortcutMap) -- cgit v1.2.3