src/hbcore/inputfw/hbinputfocusobject.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbcore/inputfw/hbinputfocusobject.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,631 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbCore module of the UI Extensions for Mobile.
+**
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+#include <QInputMethodEvent>
+#include <QGraphicsWidget>
+#include <QGraphicsScene>
+#include <QGraphicsProxyWidget>
+#include <QLineEdit>
+#include <QTextEdit>
+#include <QPointer>
+
+#include "hbinputmethod.h"
+#include "hbinputfocusobject.h"
+#include "hbinputeditorinterface.h"
+#include "hbinputvkbhost.h"
+#include "hbinputstandardfilters.h"
+
+const qreal HbInputVkbZPlaneEpsilon = 0.5;
+
+/*!
+@alpha
+@hbcore
+\class HbInputFocusObject
+\brief A helper class for accessing editor widget in abstract way.
+
+This class is input method side API for accessing editor widgets. It was added because
+in some cases Qt's QInputMethodEvent/inputMethodQuery system is not enough for our purposes
+and direct access via type casting between QWidget and QGraphiscWidget based editors is needed.
+
+This class is purely a convenience or helper type of class in nature. Everything
+it does, can be done directly in input method code as well. It just wraps
+most commonly used operations behind one API to avoid duplicate code in input method implementations.
+
+Application developers should never need to use this class, it is for input method developers only.
+
+\sa HbEditorInterface
+*/
+
+
+
+/// @cond
+
+/*
+This function ensures cursor visibility for known editor types.
+*/
+void ensureCursorVisible(QObject *widget)
+{
+    if (widget) {
+        QTextEdit *textEdit = qobject_cast<QTextEdit*>(widget);
+        if (textEdit) {
+            textEdit->ensureCursorVisible();
+        }
+    }
+}
+
+
+class HbInputFocusObjectPrivate
+{
+public:
+    HbInputFocusObjectPrivate(QObject *focusedObject)
+        : mFocusedObject(focusedObject),
+          mEditorInterface(focusedObject)
+    {}
+
+public:
+    QPointer<QObject> mFocusedObject;
+    HbEditorInterface mEditorInterface;
+    QString mPreEditString;
+};
+
+
+/// @endcond
+
+HbInputFocusObject::HbInputFocusObject(QObject *focusedObject)
+    : d_ptr(new HbInputFocusObjectPrivate(focusedObject))
+{
+}
+
+
+HbInputFocusObject::~HbInputFocusObject()
+{
+    delete d_ptr;
+}
+
+/*!
+Creates an input method event where given string is a pre-edit string and sends
+it to focused editor. See QInputMethodEvent for more information on pre-edit strings.
+*/
+void HbInputFocusObject::sendPreEditString(const QString& string)
+{
+    QList<QInputMethodEvent::Attribute> list;
+    QInputMethodEvent event(string, list);
+    sendEvent(event);
+}
+
+/*!
+Creates an input method event where given string is a commit string and sends
+it to focused editor. See QInputMethodEvent for more information on commit strings.
+*/
+void HbInputFocusObject::sendCommitString(const QString& string)
+{
+    QList<QInputMethodEvent::Attribute> list;
+    QInputMethodEvent event(QString(), list);
+    event.setCommitString(string);
+    sendEvent(event);
+}
+
+/*!
+Sends given event to focused editor.
+*/
+void HbInputFocusObject::sendEvent(QEvent& event)
+{
+    Q_D(HbInputFocusObject);
+
+    if (event.type() == QEvent::InputMethod) {
+        QInputMethodEvent* imEvent = static_cast<QInputMethodEvent*>(&event);
+        if (imEvent->commitString().size() > 0) {
+            d->mPreEditString = QString();
+        } else {
+            d->mPreEditString = imEvent->preeditString();
+        }
+    }
+
+    if (d->mFocusedObject) {
+        QApplication::sendEvent(d->mFocusedObject, &event);
+        if (event.type() == QEvent::InputMethod) {
+            // Currently in Qt, QTextEdit doesn't ensure cursor visibility
+            // in case we are sending text in the form of QInputMethodEvent. So we need
+            // to call QTextEdit:ensureCursorVisible() here till we get a fix from Qt.
+            ensureCursorVisible(d->mFocusedObject);
+        }
+    }
+}
+
+/*!
+Posts given event to focused editor in an asynchronous manner.
+*/
+void HbInputFocusObject::postEvent(QEvent& event)
+{
+    Q_D(HbInputFocusObject);
+
+    if (event.type() == QEvent::InputMethod) {
+        QInputMethodEvent* imEvent = static_cast<QInputMethodEvent*>(&event);
+        if (imEvent->commitString().size() > 0) {
+            d->mPreEditString = QString();
+        } else {
+            d->mPreEditString = imEvent->preeditString();
+        }
+    }
+
+    if (d->mFocusedObject) {
+        QApplication::postEvent(d->mFocusedObject, &event);
+    }
+}
+
+/*!
+Passes input method query to focused editor.
+*/
+QVariant HbInputFocusObject::inputMethodQuery(Qt::InputMethodQuery query) const
+{
+    Q_D(const HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (graphicsWidget && graphicsWidget->scene()) {
+        return graphicsWidget->scene()->inputMethodQuery(query);
+    }
+
+    QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+    if (widget) {
+        return widget->inputMethodQuery(query);
+    }
+
+    return QVariant();
+}
+
+/*!
+Returns editor cursor position by sending Qt::ImCursorPosition event to it.
+*/
+int HbInputFocusObject::editorCursorPosition()
+{
+    return inputMethodQuery(Qt::ImCursorPosition).toInt();
+}
+
+/*!
+Returns editor's font by sending Qt::ImFont input method query to it.
+*/
+QFont HbInputFocusObject::editorFont()
+{
+    return inputMethodQuery(Qt::ImFont).value<QFont>();
+}
+
+/*!
+Returns text selection by sending Qt::ImCurrentTextSelection to editor.
+*/
+QString HbInputFocusObject::editorTextSelection()
+{
+    return inputMethodQuery(Qt::ImCurrentSelection).toString();
+}
+
+/*!
+Returns text surrounding the editor cursor position by sending Qt::ImSurroundingText event to editor.
+*/
+QString HbInputFocusObject::editorSurroundingText()
+{
+    return inputMethodQuery(Qt::ImSurroundingText).toString();
+}
+
+/*!
+Returns editor interface object pointing to focused editor.
+*/
+HbEditorInterface& HbInputFocusObject::editorInterface() const
+{
+    return d_ptr->mEditorInterface;
+}
+
+/*!
+Sends left arrow key press to focused editor.
+*/
+void HbInputFocusObject::cursorLeft(int modifiers)
+{
+    QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Left, (Qt::KeyboardModifiers)modifiers);
+    sendEvent(keyEvent);
+}
+
+/*!
+Sends right arrow key press to focused editor.
+*/
+void HbInputFocusObject::cursorRight(int modifiers)
+{
+    QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Right, (Qt::KeyboardModifiers)modifiers);
+    sendEvent(keyEvent);
+}
+
+/*!
+Removes focus from the editor.
+*/
+void HbInputFocusObject::releaseFocus()
+{
+    Q_D(HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (!graphicsWidget) {
+        QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+        if (widget) {
+            if (widget->graphicsProxyWidget()) {
+                graphicsWidget = widget->graphicsProxyWidget();
+            } else {
+                widget->clearFocus();
+            }
+        }
+    }
+
+    if (graphicsWidget && graphicsWidget->scene()) {
+        graphicsWidget->scene()->setFocusItem(0);
+    }
+}
+
+/*!
+Runs the given character through active input filter and commits it if it was accepted.
+Returns true if the character was accepted.
+*/
+bool HbInputFocusObject::filterAndCommitCharacter(QChar aChar)
+{
+    // Two pass filtering because this may be a case constrained editor
+    // with a filter.
+    Qt::InputMethodHints hints = inputMethodHints();
+    if (hints & Qt::ImhLowercaseOnly) {
+        if (!HbInputLowerCaseFilter::instance()->filter(aChar)) {
+            return false;
+        }
+    } else if (hints & Qt::ImhUppercaseOnly) {
+        if (!HbInputUpperCaseFilter::instance()->filter(aChar)) {
+            return false;
+        }
+    }
+
+    HbInputFilter *filter = editorInterface().filter();
+    if (filter) {
+        if (!filter->filter(aChar)) {
+            return false;
+        }
+    }
+
+    QString cString;
+    cString.append(aChar);
+    sendCommitString(cString);
+
+    return true;
+}
+
+/*!
+Returns editor widget geometry. In case of QGraphicsWidget, the returned value is in scene coordinates.
+*/
+QRectF HbInputFocusObject::editorGeometry() const
+{
+    Q_D(const HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (!graphicsWidget) {
+        QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+        if (widget) {
+            if (widget->graphicsProxyWidget()) {
+                graphicsWidget = widget->graphicsProxyWidget();
+            } else {
+                return widget->geometry();
+            }
+        }
+    }
+
+    if (graphicsWidget) {
+        return QRectF(graphicsWidget->scenePos(), graphicsWidget->size());
+    }
+
+    return QRectF();
+}
+
+/*!
+Returns cursor micro focus by sending Qt::ImMicroFocus to focused editor.
+In case of QGraphicsWidget, the returned rectangle is in scene coordinates.
+*/
+QRectF HbInputFocusObject::microFocus() const
+{  
+    return inputMethodQuery(Qt::ImMicroFocus).toRectF();
+}
+
+/*!
+Returns active pre-edit string. Note that this method works only if the pre-edit
+string was set by using this class.
+*/
+QString HbInputFocusObject::preEditString() const
+{
+    Q_D(const HbInputFocusObject);
+    return d->mPreEditString;
+}
+
+/*!
+Returns the Z-value that should be used with virtual keyboard widget. Usually only HbVkbHost
+needs this value.
+*/
+qreal HbInputFocusObject::findVkbZValue() const
+{
+    Q_D(const HbInputFocusObject);
+
+    QGraphicsWidget *editorWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (!editorWidget) {
+        QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+        if (widget) {
+            editorWidget = widget->graphicsProxyWidget();
+        }
+    }
+
+    if (editorWidget) {
+        qreal result = editorWidget->zValue();
+        for (QGraphicsWidget *parent = editorWidget->parentWidget(); parent; parent = parent->parentWidget()) {
+            result += parent->zValue();
+        }
+
+        return result + HbInputVkbZPlaneEpsilon;
+    }
+
+    return 0.0;
+}
+
+/*!
+Returns input method hints. See QWidget and QGraphicsWidget documentation for more information.
+*/
+Qt::InputMethodHints HbInputFocusObject::inputMethodHints() const
+{
+    Q_D(const HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (graphicsWidget) {
+        return graphicsWidget->inputMethodHints();
+    }
+
+    QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+    if (widget) {
+        return widget->inputMethodHints();
+    }
+
+    return Qt::ImhNone;
+}
+
+/*!
+Sets input method hints. See QWidget and QGraphicsWidget documentation for more information.
+*/
+void HbInputFocusObject::setInputMethodHints(Qt::InputMethodHints hints)
+{
+    Q_D(HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (graphicsWidget) {
+        graphicsWidget->setInputMethodHints(hints);
+        return;
+    }
+
+    QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+    if (widget) {
+        widget->setInputMethodHints(hints);
+    }
+}
+
+/*!
+A convenience method for filtering strings. Uses filter attached to connected editor
+and filters given string with it.
+*/
+void HbInputFocusObject::filterStringWithEditorFilter(const QString& source, QString& result)
+{
+    QString intermediate = source;
+
+    // Chained two-pass filtering because this can be case-constrained editor with a filter.
+    Qt::InputMethodHints hints = inputMethodHints();
+    if (hints & Qt::ImhLowercaseOnly) {
+        intermediate.clear();
+        HbInputLowerCaseFilter::instance()->filterString(source, intermediate);
+    } else if (hints & Qt::ImhUppercaseOnly) {
+        intermediate.clear();
+        HbInputUpperCaseFilter::instance()->filterString(source, intermediate);
+    }
+
+    HbInputFilter *filter = editorInterface().filter();
+    if (filter) {
+        filter->filterString(intermediate, result);
+        return;
+    }
+
+    result = intermediate;
+}
+
+/*!
+Returns true if given character is allowed in active editor.
+*/
+bool HbInputFocusObject::characterAllowedInEditor(QChar character) const
+{
+    // Two pass filtering, this can be case constrained editor with a filter.
+    Qt::InputMethodHints hints = inputMethodHints();
+    if (hints & Qt::ImhLowercaseOnly) {
+        if (HbInputLowerCaseFilter::instance()->filter(character) == false) {
+            return false;
+        }
+    } else if (hints & Qt::ImhUppercaseOnly) {
+        if (HbInputUpperCaseFilter::instance()->filter(character) == false) {
+            return false;
+        }
+    }
+
+    HbInputFilter *filter = editorInterface().filter();
+    if (filter) {
+        return filter->filter(character);
+    }
+
+    return true;
+}
+
+/*!
+Returns the scenePos of the associated editor widget, if the concept makes sense
+in its context (i.e. the editor is part of a scene, either being a QGraphicsWidget or
+a QWidget embedded in a QGraphicsProxyWidget). Otherwise returns QPointF(0.0, 0.0).
+*/
+QPointF HbInputFocusObject::scenePos() const
+{
+    Q_D(const HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (graphicsWidget) {
+        return graphicsWidget->scenePos();
+    }
+
+    QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+    if (widget && widget->graphicsProxyWidget()) {
+        return widget->graphicsProxyWidget()->scenePos();
+    }
+
+    return QPointF(0.0, 0.0);
+}
+
+/*!
+Returns true if all the characters in given string are allowed in active editor.
+*/
+bool HbInputFocusObject::stringAllowedInEditor(const QString& string) const
+{
+    // Two pass filtering. This can be a case constrained editor with a filter.
+    Qt::InputMethodHints hints;
+    if (hints & Qt::ImhLowercaseOnly) {
+        QString outStr;
+        HbInputLowerCaseFilter::instance()->filterString(string, outStr);
+        if (string != outStr) {
+            return false;
+        }
+    } else if (hints & Qt::ImhUppercaseOnly) {
+        QString outStr;
+        HbInputUpperCaseFilter::instance()->filterString(string, outStr);
+        if (string != outStr) {
+            return false;
+        }
+    }
+
+    HbInputFilter *filter = editorInterface().filter();
+    if (filter) {
+        QString outStr;
+        filter->filterString(string, outStr);
+        return string == outStr;
+    }
+
+    return true;
+}
+
+/*!
+Commits given smiley.
+*/
+void HbInputFocusObject::commitSmiley(QString smiley)
+{    
+     Q_D(HbInputFocusObject);
+
+     if (d->mFocusedObject) {
+         d->mFocusedObject->setProperty("SmileyIcon", smiley);
+     }
+}
+
+/*!
+Returns the editor widget as QObject.
+*/
+QObject *HbInputFocusObject::object() const
+{
+    Q_D(const HbInputFocusObject);
+    return d->mFocusedObject;
+}
+
+/*!
+Returns true if widget is read-only widget. This works
+only for known editor types.
+*/
+bool HbInputFocusObject::isReadOnlyWidget(QObject *editorObject)
+{
+    if (editorObject) {
+        QWidget *widget = qobject_cast<QWidget*>(editorObject);
+        if (widget) {
+            if (!widget->testAttribute(Qt::WA_InputMethodEnabled)) {
+                return true;
+            }
+
+            QLineEdit *lineEdit = qobject_cast<QLineEdit*>(widget);
+            if (lineEdit) {
+                return lineEdit->isReadOnly();
+            }
+
+            QTextEdit *textEdit = qobject_cast<QTextEdit*>(widget);
+            if (textEdit) {
+                return textEdit->isReadOnly();
+            }
+
+            return false;
+        } else {
+            QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(editorObject);
+            if (graphicsWidget) {
+                if (!(graphicsWidget->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/*!
+Returns true if the input framework recognizes given object as editor.
+*/
+bool HbInputFocusObject::isEditor(QObject *object)
+{
+    if (object && object->inherits("HbAbstractEdit")) {
+         return true;
+    }
+
+    if (qobject_cast<QLineEdit*>(object)) {
+        return true;
+    }
+
+    if (qobject_cast<QTextEdit*>(object)) {
+        return true;
+    }
+
+    return false;
+}
+
+/*!
+Sets focus to the editor point by this focus objetc. This method is needed because sometimes
+input method does something that temporarily removes focus from the original editor,
+for example displays a dialog which itself contains an editor in it. This method can
+be used to return the focus to the original editor.
+*/
+void HbInputFocusObject::setFocus()
+{
+    Q_D(HbInputFocusObject);
+
+    QGraphicsWidget *graphicsWidget = qobject_cast<QGraphicsWidget*>(d->mFocusedObject);
+    if (graphicsWidget && graphicsWidget->scene()) {
+        graphicsWidget->scene()->setFocusItem(graphicsWidget);
+    } else {
+        QWidget *widget = qobject_cast<QWidget*>(d->mFocusedObject);
+        if (widget) {
+            widget->setFocus();
+        }
+    }
+}
+
+// End of file
+