QNX: Adding native file dialog support for Blackberry
authorSean Harmer <sean.harmer.qnx@kdab.com>
Wed, 25 Apr 2012 12:16:24 +0000 (13:16 +0100)
committerQt by Nokia <qt-info@nokia.com>
Fri, 25 May 2012 22:34:40 +0000 (00:34 +0200)
This patch enables use of native file dialogs in the application
modal case.

The native file open dialog is reasonable but the native file save
dialog could do with some improvements to make it more usable.
Perhaps providing our own "native" dialog UI would be an option
once the widget style is finished.

Change-Id: If5fb7cf73d27e52db7bfa6d97d8f8fb7912960bb
Reviewed-by: Nicolas Arnaud-Cormos <nicolas@kdab.com>
src/plugins/platforms/qnx/qnx.pro
src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
src/plugins/platforms/qnx/qqnxbpseventfilter.h
src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp [new file with mode: 0644]
src/plugins/platforms/qnx/qqnxfiledialoghelper.h [new file with mode: 0644]
src/plugins/platforms/qnx/qqnxintegration.cpp
src/plugins/platforms/qnx/qqnxintegration.h
src/plugins/platforms/qnx/qqnxtheme.cpp
src/plugins/platforms/qnx/qqnxtheme.h

index f9af954..7c25707 100644 (file)
@@ -22,6 +22,7 @@ CONFIG(blackberry) {
 #DEFINES += QQNXBPSEVENTFILTER_DEBUG
 #DEFINES += QQNXBUFFER_DEBUG
 #DEFINES += QQNXCLIPBOARD_DEBUG
+#DEFINES += QQNXFILEDIALOGHELPER_DEBUG
 #DEFINES += QQNXGLBACKINGSTORE_DEBUG
 #DEFINES += QQNXGLCONTEXT_DEBUG
 #DEFINES += QQNXINPUTCONTEXT_DEBUG
@@ -88,14 +89,16 @@ CONFIG(blackberry) {
                qqnxbpseventfilter.cpp \
                qqnxvirtualkeyboardbps.cpp \
                qqnxtheme.cpp \
-               qqnxsystemsettings.cpp
+               qqnxsystemsettings.cpp \
+               qqnxfiledialoghelper.cpp
 
     HEADERS += qqnxnavigatorbps.h \
                qqnxeventdispatcher_blackberry.h \
                qqnxbpseventfilter.h \
                qqnxvirtualkeyboardbps.h  \
                qqnxtheme.h \
-               qqnxsystemsettings.h
+               qqnxsystemsettings.h \
+               qqnxfiledialoghelper.h
 
     LIBS += -lbps
 }
index f5185e3..fd1bfd3 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "qqnxbpseventfilter.h"
 #include "qqnxnavigatoreventhandler.h"
+#include "qqnxfiledialoghelper.h"
 #include "qqnxscreen.h"
 #include "qqnxscreeneventhandler.h"
 #include "qqnxvirtualkeyboardbps.h"
@@ -110,6 +111,22 @@ void QQnxBpsEventFilter::unregisterForScreenEvents(QQnxScreen *screen)
         qWarning("QQNX: failed to unregister for screen events on screen %p", screen->nativeContext());
 }
 
+void QQnxBpsEventFilter::registerForDialogEvents(QQnxFileDialogHelper *dialog)
+{
+    if (dialog_request_events(0) != BPS_SUCCESS)
+        qWarning("QQNX: failed to register for dialog events");
+    dialog_instance_t nativeDialog = dialog->nativeDialog();
+    if (!m_dialogMapper.contains(nativeDialog))
+        m_dialogMapper.insert(nativeDialog, dialog);
+}
+
+void QQnxBpsEventFilter::unregisterForDialogEvents(QQnxFileDialogHelper *dialog)
+{
+    int count = m_dialogMapper.remove(dialog->nativeDialog());
+    if (count == 0)
+        qWarning("QQNX: attempting to unregister dialog that was not registered");
+}
+
 bool QQnxBpsEventFilter::dispatcherEventFilter(void *message)
 {
     qBpsEventFilterDebug() << Q_FUNC_INFO;
@@ -131,6 +148,13 @@ bool QQnxBpsEventFilter::bpsEventFilter(bps_event_t *event)
         return m_screenEventHandler->handleEvent(screenEvent);
     }
 
+    if (eventDomain == dialog_get_domain()) {
+        dialog_instance_t nativeDialog = dialog_event_get_dialog_instance(event);
+        QQnxFileDialogHelper *dialog = m_dialogMapper.value(nativeDialog, 0);
+        if (dialog)
+            return dialog->handleEvent(event);
+    }
+
     if (eventDomain == navigator_get_domain())
         return handleNavigatorEvent(event);
 
index 215027e..aafca0f 100644 (file)
@@ -43,6 +43,9 @@
 #define QQNXBPSEVENTFILTER_H
 
 #include <QObject>
+#include <QHash>
+
+#include <bps/dialog.h>
 
 struct bps_event_t;
 
@@ -50,6 +53,7 @@ QT_BEGIN_NAMESPACE
 
 class QAbstractEventDispatcher;
 class QQnxNavigatorEventHandler;
+class QQnxFileDialogHelper;
 class QQnxScreen;
 class QQnxScreenEventHandler;
 class QQnxVirtualKeyboardBps;
@@ -68,6 +72,9 @@ public:
     void registerForScreenEvents(QQnxScreen *screen);
     void unregisterForScreenEvents(QQnxScreen *screen);
 
+    void registerForDialogEvents(QQnxFileDialogHelper *dialog);
+    void unregisterForDialogEvents(QQnxFileDialogHelper *dialog);
+
 private:
     static bool dispatcherEventFilter(void *message);
     bool bpsEventFilter(bps_event_t *event);
@@ -78,6 +85,7 @@ private:
     QQnxNavigatorEventHandler *m_navigatorEventHandler;
     QQnxScreenEventHandler *m_screenEventHandler;
     QQnxVirtualKeyboardBps *m_virtualKeyboard;
+    QHash<dialog_instance_t, QQnxFileDialogHelper*> m_dialogMapper;
 };
 
 QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp
new file mode 100644 (file)
index 0000000..e0e84db
--- /dev/null
@@ -0,0 +1,309 @@
+/***************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqnxfiledialoghelper.h"
+
+#include "qqnxbpseventfilter.h"
+#include "qqnxscreen.h"
+
+#include <QDebug>
+#include <QEventLoop>
+#include <QScreen>
+#include <QTimer>
+#include <QWindow>
+
+#ifdef QQNXFILEDIALOGHELPER_DEBUG
+#define qFileDialogHelperDebug qDebug
+#else
+#define qFileDialogHelperDebug QT_NO_QDEBUG_MACRO
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QQnxFileDialogHelper::QQnxFileDialogHelper(QQnxBpsEventFilter *eventFilter)
+    : QPlatformFileDialogHelper(),
+      m_eventFilter(eventFilter),
+      m_dialog(0),
+      m_acceptMode(QFileDialogOptions::AcceptOpen),
+      m_selectedFilter(),
+      m_result(QPlatformDialogHelper::Rejected),
+      m_paths()
+{
+}
+
+QQnxFileDialogHelper::~QQnxFileDialogHelper()
+{
+    if (m_dialog)
+        dialog_destroy(m_dialog);
+}
+
+bool QQnxFileDialogHelper::handleEvent(bps_event_t *event)
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+
+    // Check dialog event response type (OK vs CANCEL)
+    // CANCEL => index = 0
+    //     OK => index = 1
+    int index = dialog_event_get_selected_index(event);
+    qFileDialogHelperDebug() << "Index =" << index;
+    if (index == 1) {
+        m_result = QPlatformDialogHelper::Accepted;
+
+        if (m_acceptMode == QFileDialogOptions::AcceptOpen) {
+            // File open dialog
+
+            // ###TODO Check that this actually gets multiple paths and cleans up properly
+            char **filePaths = 0;
+            int pathCount = 0;
+            int result = dialog_event_get_filebrowse_filepaths(event, &filePaths, &pathCount);
+            if (result != BPS_SUCCESS) {
+                qWarning() << "Could not get paths from native file dialog";
+                return false;
+            }
+
+            for (int i = 0; i < pathCount; ++i) {
+                QString path = QFile::decodeName(filePaths[i]);
+                m_paths.append(path);
+                qFileDialogHelperDebug() << "path =" << path;
+            }
+
+            bps_free(filePaths);
+        } else {
+            // File save dialog
+            const char *filePath = dialog_event_get_filesave_filepath(event);
+            QString path = QFile::decodeName(filePath);
+            qFileDialogHelperDebug() << "path =" << path;
+            m_paths.append(path);
+        }
+    } else { // Cancel
+        m_result = QPlatformDialogHelper::Rejected;
+    }
+
+    emit dialogClosed();
+
+    return true;
+}
+
+void QQnxFileDialogHelper::exec()
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+
+    // Clear any previous results
+    m_paths.clear();
+
+    QEventLoop loop;
+    connect(this, SIGNAL(dialogClosed()), &loop, SLOT(quit()));
+    loop.exec();
+
+    if (m_result == QPlatformDialogHelper::Accepted)
+        emit accept();
+    else
+        emit reject();
+}
+
+bool QQnxFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+    Q_UNUSED(flags);
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+
+    // We *really* need the bps event filter ;)
+    if (!m_eventFilter)
+        return false;
+
+    // Native dialogs can only handle application modal use cases so far
+    if (modality != Qt::ApplicationModal)
+        return false;
+
+    // Tear down any existing dialog and start again as dialog mode may have changed
+    if (m_dialog) {
+        dialog_destroy(m_dialog);
+        m_dialog = 0;
+    }
+
+    // Create dialog
+    const QSharedPointer<QFileDialogOptions> &opts = options();
+    if (opts->acceptMode() == QFileDialogOptions::AcceptOpen) {
+        if (dialog_create_filebrowse(&m_dialog) != BPS_SUCCESS) {
+            qWarning("dialog_create_filebrowse failed");
+            return false;
+        }
+
+        // Select one or many files?
+        bool multiSelect = (opts->fileMode() == QFileDialogOptions::ExistingFiles);
+        dialog_set_filebrowse_multiselect(m_dialog, multiSelect);
+
+        // Set the actual list of extensions
+        if (!opts->nameFilters().isEmpty()) {
+            qFileDialogHelperDebug() << "nameFilters =" << opts->nameFilters();
+            setNameFilter(opts->nameFilters().first());
+        } else {
+            QString defaultNameFilter = QStringLiteral("*.*");
+            setNameFilter(defaultNameFilter);
+        }
+    } else {
+        if (dialog_create_filesave(&m_dialog) != BPS_SUCCESS) {
+            qWarning("dialog_create_filesave failed");
+            return false;
+        }
+
+        // Maybe pre-select a filename
+        if (!opts->initiallySelectedFiles().isEmpty()) {
+            QString fileName = opts->initiallySelectedFiles().first();
+            dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData());
+        }
+
+        // Add OK and Cancel buttons. We add the buttons in the order "CANCEL" followed by "OK
+        // such that they have indices matching the buttons on the file open dialog which
+        // is automatically populated with buttons.
+        if (dialog_add_button(m_dialog, tr("CANCEL").toLocal8Bit().constData(), true, 0, true) != BPS_SUCCESS) {
+            qWarning("dialog_add_button failed");
+            return false;
+        }
+
+        if (dialog_add_button(m_dialog, tr("OK").toLocal8Bit().constData(), true, 0, true) != BPS_SUCCESS) {
+            qWarning("dialog_add_button failed");
+            return false;
+        }
+    }
+
+    // Cache the accept mode so we know which functions to use to get the results back
+    m_acceptMode = opts->acceptMode();
+
+    // Set the libscreen window group and common properties
+    QQnxScreen *nativeScreen = static_cast<QQnxScreen *>(parent->screen()->handle());
+    dialog_set_group_id(m_dialog, nativeScreen->windowGroupName());
+    dialog_set_title_text(m_dialog, opts->windowTitle().toLocal8Bit().constData());
+
+    // Register ourselves for dialog domain events from bps
+    m_eventFilter->registerForDialogEvents(this);
+
+    // Show the dialog
+    dialog_show(m_dialog);
+
+    return true;
+}
+
+void QQnxFileDialogHelper::hide()
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+    if (!m_dialog)
+        return;
+    dialog_cancel(m_dialog);
+}
+
+bool QQnxFileDialogHelper::defaultNameFilterDisables() const
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+    return false;
+}
+
+void QQnxFileDialogHelper::setDirectory(const QString &directory)
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO << "directory =" << directory;
+    // No native API for setting the directory(!). The best we can do is to
+    // set it as the file name but even then only with a file save dialog.
+    if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave)
+        dialog_set_filesave_filename(m_dialog, QFile::encodeName(directory).constData());
+}
+
+QString QQnxFileDialogHelper::directory() const
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+    return m_paths.first();
+}
+
+void QQnxFileDialogHelper::selectFile(const QString &fileName)
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO << "filename =" << fileName;
+    if (m_dialog && m_acceptMode == QFileDialogOptions::AcceptSave)
+        dialog_set_filesave_filename(m_dialog, QFile::encodeName(fileName).constData());
+}
+
+QStringList QQnxFileDialogHelper::selectedFiles() const
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+    return m_paths;
+}
+
+void QQnxFileDialogHelper::setFilter()
+{
+    // No native api to support setting a filter from QDir::Filters
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+}
+
+void QQnxFileDialogHelper::selectNameFilter(const QString &filter)
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter;
+    setNameFilter(filter);
+}
+
+QString QQnxFileDialogHelper::selectedNameFilter() const
+{
+    // For now there is no way for the user to change the selected filter
+    // so this just reflects what the developer has set programmatically.
+    qFileDialogHelperDebug() << Q_FUNC_INFO;
+    return m_selectedFilter;
+}
+
+void QQnxFileDialogHelper::setNameFilter(const QString &filter)
+{
+    qFileDialogHelperDebug() << Q_FUNC_INFO << "filter =" << filter;
+
+    // Extract the globbing expressions
+    QStringList filters = QPlatformFileDialogHelper::cleanFilterList(filter);
+    char **globs = new char*[filters.size()];
+    for (int i = 0; i < filters.size(); ++i) {
+        QByteArray glob = filters.at(i).toLocal8Bit();
+        globs[i] = new char[glob.length()];
+        strcpy(globs[i], glob.constData());
+    }
+
+    // Set the filters
+    dialog_set_filebrowse_filter(m_dialog, const_cast<const char**>(globs), filters.size());
+    m_selectedFilter = filter;
+
+    // Cleanup
+    for (int i = 0; i < filters.size(); ++i)
+        delete[] globs[i];
+    delete[] globs;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h
new file mode 100644 (file)
index 0000000..9b05da2
--- /dev/null
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXFILEDIALOGHELPER_H
+#define QQNXFILEDIALOGHELPER_H
+
+#include <qpa/qplatformdialoghelper.h>
+
+#include <bps/dialog.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxBpsEventFilter;
+
+class QQnxFileDialogHelper : public QPlatformFileDialogHelper
+{
+    Q_OBJECT
+public:
+    explicit QQnxFileDialogHelper(QQnxBpsEventFilter *eventFilter);
+    ~QQnxFileDialogHelper();
+
+    bool handleEvent(bps_event_t *event);
+
+    void exec();
+
+    bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+    void hide();
+
+    bool defaultNameFilterDisables() const;
+    void setDirectory(const QString &directory);
+    QString directory() const;
+    void selectFile(const QString &fileName);
+    QStringList selectedFiles() const;
+    void setFilter();
+    void selectNameFilter(const QString &filter);
+    QString selectedNameFilter() const;
+
+    dialog_instance_t nativeDialog() const { return m_dialog; }
+
+Q_SIGNALS:
+    void dialogClosed();
+
+private:
+    void setNameFilter(const QString &filter);
+
+    QQnxBpsEventFilter *m_eventFilter;
+    dialog_instance_t m_dialog;
+    QFileDialogOptions::AcceptMode m_acceptMode;
+    QString m_selectedFilter;
+
+    QPlatformDialogHelper::DialogCode m_result;
+    QStringList m_paths;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXFILEDIALOGHELPER_H
index e6e99d2..eb95f2d 100644 (file)
@@ -382,7 +382,7 @@ QPlatformTheme *QQnxIntegration::createPlatformTheme(const QString &name) const
 {
     qIntegrationDebug() << Q_FUNC_INFO << "name =" << name;
     if (name == QQnxTheme::name())
-        return new QQnxTheme(m_fontDatabase);
+        return new QQnxTheme(m_fontDatabase, m_bpsEventFilter);
     return QPlatformIntegration::createPlatformTheme(name);
 }
 #endif
index 6820dc1..9682567 100644 (file)
@@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE
 
 class QQnxBpsEventFilter;
 class QQnxScreenEventThread;
+class QQnxFileDialogHelper;
 class QQnxNativeInterface;
 class QQnxWindow;
 class QQnxScreen;
@@ -115,6 +116,7 @@ public:
 #if defined(Q_OS_BLACKBERRY)
     QStringList themeNames() const;
     QPlatformTheme *createPlatformTheme(const QString &name) const;
+    QQnxBpsEventFilter *bpsEventFilter() const { return m_bpsEventFilter; }
 #endif
 
     static QWindow *window(screen_window_t qnxWindow);
index cd82e0c..472f471 100644 (file)
 
 #include "qqnxtheme.h"
 
+#include "qqnxfiledialoghelper.h"
 #include "qqnxsystemsettings.h"
 
 QT_BEGIN_NAMESPACE
 
-QQnxTheme::QQnxTheme(QPlatformFontDatabase *fontDatabase)
-    : m_fontDatabase(fontDatabase)
+QQnxTheme::QQnxTheme(QPlatformFontDatabase *fontDatabase,
+                     QQnxBpsEventFilter *eventFilter)
+    : m_fontDatabase(fontDatabase),
+      m_eventFilter(eventFilter)
 {
 }
 
@@ -55,6 +58,37 @@ QQnxTheme::~QQnxTheme()
     qDeleteAll(m_fonts);
 }
 
+bool QQnxTheme::usePlatformNativeDialog(DialogType type) const
+{
+    if (type == QPlatformTheme::FileDialog)
+        return true;
+#if !defined(QT_NO_COLORDIALOG)
+    if (type == QPlatformTheme::ColorDialog)
+        return false;
+#endif
+#if !defined(QT_NO_FONTDIALOG)
+    if (type == QPlatformTheme::FontDialog)
+        return false;
+#endif
+    return false;
+}
+
+QPlatformDialogHelper *QQnxTheme::createPlatformDialogHelper(DialogType type) const
+{
+    switch (type) {
+    case QPlatformTheme::FileDialog:
+        return new QQnxFileDialogHelper(m_eventFilter);
+#ifndef QT_NO_COLORDIALOG
+    case QPlatformTheme::ColorDialog:
+#endif
+#ifndef QT_NO_FONTDIALOG
+    case QPlatformTheme::FontDialog:
+#endif
+    default:
+        return 0;
+    }
+}
+
 const QFont *QQnxTheme::font(Font type) const
 {
     if (m_fonts.isEmpty() && m_fontDatabase)
index dc9c7be..c2c81a5 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
+class QQnxBpsEventFilter;
+
 class QPlatformFontDatabase;
 
 class QQnxTheme : public QPlatformTheme
 {
 public:
-    QQnxTheme(QPlatformFontDatabase *fontDatabase);
+    QQnxTheme(QPlatformFontDatabase *fontDatabase, QQnxBpsEventFilter *eventFilter);
     ~QQnxTheme();
 
     static QString name() { return QStringLiteral("blackberry"); }
 
+    bool usePlatformNativeDialog(DialogType type) const;
+    QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
+
     const QFont *font(Font type = SystemFont) const;
 
 private:
     QPlatformFontDatabase *m_fontDatabase;
+    QQnxBpsEventFilter *m_eventFilter;
     mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
 };