21 ** If you have questions regarding the use of this file, please contact |
21 ** If you have questions regarding the use of this file, please contact |
22 ** Nokia at developer.feedback@nokia.com. |
22 ** Nokia at developer.feedback@nokia.com. |
23 ** |
23 ** |
24 ****************************************************************************/ |
24 ****************************************************************************/ |
25 #include "hbinputfocusobject.h" |
25 #include "hbinputfocusobject.h" |
|
26 #include "hbinputfocusobject_p.h" |
26 |
27 |
27 #include <QInputMethodEvent> |
28 #include <QInputMethodEvent> |
28 #include <QGraphicsWidget> |
29 #include <QGraphicsObject> |
29 #include <QGraphicsScene> |
30 #include <QGraphicsScene> |
30 #include <QGraphicsProxyWidget> |
31 #include <QGraphicsProxyWidget> |
31 #include <QLineEdit> |
32 #include <QLineEdit> |
32 #include <QTextEdit> |
33 #include <QTextEdit> |
33 #include <QPointer> |
|
34 #include <QGraphicsView> |
|
35 |
34 |
36 #include "hbinputmethod.h" |
35 #include "hbinputmethod.h" |
37 #include "hbinputeditorinterface.h" |
|
38 #include "hbinputvkbhost.h" |
36 #include "hbinputvkbhost.h" |
39 #include "hbinputstandardfilters.h" |
37 #include "hbinputstandardfilters.h" |
40 #include "hbdeviceprofile.h" |
38 #include "hbdeviceprofile.h" |
41 #include "hbinpututils.h" |
|
42 #include "hbnamespace_p.h" |
39 #include "hbnamespace_p.h" |
43 #include "hbmainwindow.h" |
40 #include "hbmainwindow.h" |
44 #include "hbevent.h" |
41 #include "hbevent.h" |
45 #include "hbwidget.h" |
42 #include "hbwidget.h" |
46 #include "hbinputmainwindow_p.h" |
43 #include "hbinputmainwindow_p.h" |
47 |
44 |
48 /*! |
45 /*! |
49 @alpha |
46 @beta |
50 @hbcore |
47 @hbcore |
51 \class HbInputFocusObject |
48 \class HbInputFocusObject |
52 \brief A helper class for accessing editor widget in abstract way. |
49 \brief A helper class for accessing editor widget in abstract way. |
53 |
50 |
54 This class is input method side API for accessing editor widgets. It was added because |
51 This class is input method side API for accessing editor widgets. It hides |
55 in some cases Qt's QInputMethodEvent/inputMethodQuery system is not enough and direct |
52 the details of performing editor related operations, such as sending input |
56 access via type casting between QWidget and QGraphiscWidget based editors is needed. |
53 method events, querying editor geometry, querying editor attributes and so on. |
57 Focus object hides those cases behind a convinience API. |
54 It implements a collection of convenience methods for most commonly used |
|
55 editor operations. |
58 |
56 |
59 This class is purely a convenience or helper type of class in nature. Everything |
57 This class is purely a convenience or helper type of class in nature. Everything |
60 it does, can be done directly in input method code as well. It just wraps |
58 it does, can be done directly in input method code as well. The benefit from using |
61 most commonly used operations behind one API to avoid duplicate code. |
59 this class is that an input method implementation doesn't need to care whether |
62 |
60 the focused editor is QWidget or QGraphicsWidget based (or proxied QWidget). |
63 Application developers should never need to use this class, it is for input method developers only. |
61 |
|
62 Application developers typically do not need this class, it is for input method |
|
63 developers only. |
|
64 |
|
65 The active focus object can be accessed through HbInputMethod::focusObject() |
|
66 method. |
64 |
67 |
65 \sa HbEditorInterface |
68 \sa HbEditorInterface |
|
69 \sa HbInputMethod |
66 */ |
70 */ |
67 |
71 |
68 /// @cond |
72 /// @cond |
69 |
73 |
70 /* |
74 /*! |
71 This function ensures cursor visibility for known editor types. |
75 \internal |
72 */ |
76 Returns main window in case the editor is QGraphicsObject based and lives |
73 void ensureCursorVisible(QObject *widget) |
77 inside HbGraphicsScene. |
74 { |
78 */ |
75 if (widget) { |
|
76 QTextEdit *textEdit = qobject_cast<QTextEdit *>(widget); |
|
77 if (textEdit) { |
|
78 textEdit->ensureCursorVisible(); |
|
79 } |
|
80 } |
|
81 } |
|
82 |
|
83 class HbInputFocusObjectPrivate |
|
84 { |
|
85 Q_DECLARE_PUBLIC(HbInputFocusObject) |
|
86 |
|
87 public: |
|
88 HbInputFocusObjectPrivate(QObject *focusedObject) |
|
89 : mFocusedObject(focusedObject), |
|
90 mEditorInterface(focusedObject) |
|
91 {} |
|
92 |
|
93 HbMainWindow *mainWindow() const; |
|
94 |
|
95 public: |
|
96 HbInputFocusObject *q_ptr; |
|
97 QPointer<QObject> mFocusedObject; |
|
98 HbEditorInterface mEditorInterface; |
|
99 QString mPreEditString; |
|
100 }; |
|
101 |
|
102 HbMainWindow *HbInputFocusObjectPrivate::mainWindow() const |
79 HbMainWindow *HbInputFocusObjectPrivate::mainWindow() const |
103 { |
80 { |
104 QWidget *qWidgetObject = qobject_cast<QWidget *>(mFocusedObject); |
|
105 QGraphicsObject *graphicsObject = 0; |
81 QGraphicsObject *graphicsObject = 0; |
106 |
82 |
107 // check for graphics view related widgets. |
83 // check for graphics view related widgets. |
108 if (qWidgetObject) { |
84 if (mWidget) { |
109 if (qWidgetObject->graphicsProxyWidget()) { |
85 if (mWidget->graphicsProxyWidget()) { |
110 graphicsObject = qWidgetObject->graphicsProxyWidget(); |
86 graphicsObject = mWidget->graphicsProxyWidget(); |
111 } else { |
87 } else { |
112 return HbInputMainWindow::instance(); |
88 return HbInputMainWindow::instance(); |
113 } |
89 } |
114 } else { |
90 } else { |
115 graphicsObject = qobject_cast<QGraphicsObject *>(mFocusedObject); |
91 graphicsObject = mGraphicsObject; |
116 } |
92 } |
117 |
93 |
118 if (graphicsObject) { |
94 if (graphicsObject) { |
119 if (graphicsObject->scene()) { |
95 if (graphicsObject->scene()) { |
120 QList<QGraphicsView*> views = graphicsObject->scene()->views(); |
96 QList<QGraphicsView*> views = graphicsObject->scene()->views(); |
130 } |
106 } |
131 |
107 |
132 return 0; |
108 return 0; |
133 } |
109 } |
134 |
110 |
|
111 /*! |
|
112 \internal |
|
113 Ensures cursor visibility for known editor types. |
|
114 */ |
|
115 void HbInputFocusObjectPrivate::ensureCursorVisible(QObject *widget) |
|
116 { |
|
117 if (widget) { |
|
118 QTextEdit *textEdit = qobject_cast<QTextEdit *>(widget); |
|
119 if (textEdit) { |
|
120 textEdit->ensureCursorVisible(); |
|
121 } |
|
122 } |
|
123 } |
|
124 |
135 /// @endcond |
125 /// @endcond |
136 |
126 |
137 HbInputFocusObject::HbInputFocusObject(QObject *focusedObject) |
127 HbInputFocusObject::HbInputFocusObject(QObject *focusedObject) |
138 : d_ptr(new HbInputFocusObjectPrivate(focusedObject)) |
128 : d_ptr(new HbInputFocusObjectPrivate(focusedObject)) |
139 { |
129 { |
140 Q_D(HbInputFocusObject); |
130 Q_D(HbInputFocusObject); |
141 d->q_ptr = this; |
131 d->q_ptr = this; |
142 |
132 |
143 if (focusedObject) { |
133 if (focusedObject) { |
|
134 if (focusedObject->isWidgetType()) { |
|
135 d->mWidget = qobject_cast<QWidget*>(focusedObject); |
|
136 } else { |
|
137 QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget*>(focusedObject); |
|
138 if (proxy) { |
|
139 d->mWidget = proxy->widget(); |
|
140 } else { |
|
141 d->mGraphicsObject = qobject_cast<QGraphicsObject*>(focusedObject); |
|
142 } |
|
143 } |
|
144 |
144 HbEvent *event = new HbEvent(HbEvent::InputMethodFocusIn); |
145 HbEvent *event = new HbEvent(HbEvent::InputMethodFocusIn); |
145 QCoreApplication::sendEvent(focusedObject, event); |
146 QCoreApplication::sendEvent(focusedObject, event); |
146 delete event; |
147 delete event; |
147 |
148 |
148 HbMainWindow *mainWindow = d->mainWindow(); |
149 HbMainWindow *mainWindow = d->mainWindow(); |
202 } else { |
202 } else { |
203 d->mPreEditString = imEvent->preeditString(); |
203 d->mPreEditString = imEvent->preeditString(); |
204 } |
204 } |
205 } |
205 } |
206 |
206 |
207 if (d->mFocusedObject) { |
207 QObject *obj = object(); |
|
208 if (obj) { |
208 if (event.type() == QEvent::InputMethod) { |
209 if (event.type() == QEvent::InputMethod) { |
209 QInputContext *ic = qApp->inputContext(); |
210 QInputContext *ic = qApp->inputContext(); |
210 QInputMethodEvent *imEvent = static_cast<QInputMethodEvent *>(&event); |
211 QInputMethodEvent *imEvent = static_cast<QInputMethodEvent *>(&event); |
211 if (ic) { |
212 if (ic) { |
212 ic->sendEvent(*imEvent); |
213 ic->sendEvent(*imEvent); |
213 } |
214 } |
214 // Currently in Qt, QTextEdit doesn't ensure cursor visibility |
215 // Currently in Qt, QTextEdit doesn't ensure cursor visibility |
215 // in case we are sending text in the form of QInputMethodEvent. So we need |
216 // in case we are sending text in the form of QInputMethodEvent. So we need |
216 // to call QTextEdit:ensureCursorVisible() here till we get a fix from Qt. |
217 // to call QTextEdit:ensureCursorVisible() here till we get a fix from Qt. |
217 ensureCursorVisible(d->mFocusedObject); |
218 d->ensureCursorVisible(obj); |
218 } else { |
219 } else { |
219 QInputContext *ic = qApp->inputContext(); |
220 QInputContext *ic = qApp->inputContext(); |
220 if (ic && ic->focusWidget()) { |
221 if (ic && ic->focusWidget()) { |
221 QApplication::sendEvent(ic->focusWidget(), &event); |
222 QApplication::sendEvent(ic->focusWidget(), &event); |
222 } |
223 } |
238 } else { |
239 } else { |
239 d->mPreEditString = imEvent->preeditString(); |
240 d->mPreEditString = imEvent->preeditString(); |
240 } |
241 } |
241 } |
242 } |
242 |
243 |
243 if (d->mFocusedObject) { |
244 QObject *obj = object(); |
244 QApplication::postEvent(d->mFocusedObject, &event); |
245 if (obj) { |
245 } |
246 QApplication::postEvent(obj, &event); |
246 } |
247 } |
247 |
248 } |
248 /*! |
249 |
249 Passes input method query to focused editor. |
250 /*! |
|
251 Passes input method query to focused editor widget. |
250 */ |
252 */ |
251 QVariant HbInputFocusObject::inputMethodQuery(Qt::InputMethodQuery query) const |
253 QVariant HbInputFocusObject::inputMethodQuery(Qt::InputMethodQuery query) const |
252 { |
254 { |
253 Q_D(const HbInputFocusObject); |
255 Q_D(const HbInputFocusObject); |
254 |
256 |
255 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(d->mFocusedObject); |
257 QGraphicsObject *graphicsObject = d->mGraphicsObject; |
256 if (graphicsObject && graphicsObject->scene()) { |
258 if (graphicsObject) { |
257 return graphicsObject->scene()->inputMethodQuery(query); |
259 if (graphicsObject->scene()) { |
258 } |
260 return graphicsObject->scene()->inputMethodQuery(query); |
259 |
261 } |
260 // check if QWidget is embedded as a proxy in scene. If yes try to get details |
262 |
261 // from the scene. |
263 return QVariant(); |
262 QWidget *widget = qobject_cast<QWidget *>(d->mFocusedObject); |
264 } |
263 QGraphicsProxyWidget *pw = HbInputUtils::graphicsProxyWidget(widget); |
265 |
264 if (pw && pw->scene()) { |
266 QWidget *widget = d->mWidget; |
265 return pw->scene()->inputMethodQuery(query); |
|
266 } |
|
267 |
|
268 if (widget) { |
267 if (widget) { |
269 // QWidget returns microfocus in local coordinate. |
268 // QWidget returns microfocus in local coordinate. |
270 // we need to map it to global coordinate. |
269 // we need to map it to global coordinate. |
271 QVariant v = widget->inputMethodQuery(query); |
270 QVariant v = widget->inputMethodQuery(query); |
272 if (v.type() == QVariant::Rect) { |
271 if (v.type() == QVariant::Rect) { |
397 */ |
398 */ |
398 QRectF HbInputFocusObject::editorGeometry() const |
399 QRectF HbInputFocusObject::editorGeometry() const |
399 { |
400 { |
400 Q_D(const HbInputFocusObject); |
401 Q_D(const HbInputFocusObject); |
401 |
402 |
402 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(d->mFocusedObject); |
403 QGraphicsObject *graphicsObject = d->mGraphicsObject; |
403 if (!graphicsObject) { |
404 if (!graphicsObject) { |
404 QWidget *widget = qobject_cast<QWidget *>(d->mFocusedObject); |
405 QWidget *widget = d->mWidget; |
405 if (widget) { |
406 if (widget) { |
406 // check if widget is inside a proxy. |
407 // Check if widget is inside a proxy. |
407 QGraphicsProxyWidget *pw = HbInputUtils::graphicsProxyWidget(widget); |
408 QGraphicsProxyWidget *pw = widget->graphicsProxyWidget(); |
408 if (pw) { |
409 if (pw) { |
409 // check if we are pointing to the toplevel |
410 graphicsObject = pw; |
410 // proxy widget, if not then we must check for |
|
411 // the widgets window and see if it is a proxy. |
|
412 if (pw->widget() == widget) { |
|
413 graphicsObject = pw; |
|
414 } else if (pw->widget() == widget->window()) { |
|
415 // focused object is not a proxy but it is |
|
416 // inside a proxy, query to proxy about |
|
417 // the focused objects rect. |
|
418 QRectF rect = pw->subWidgetRect(widget); |
|
419 rect.translate(pw->scenePos()); |
|
420 return rect; |
|
421 } |
|
422 } else { |
411 } else { |
423 return QRectF(widget->mapToGlobal(QPoint(0, 0)), widget->size()); |
412 return QRectF(widget->mapToGlobal(QPoint(0, 0)), widget->size()); |
424 } |
413 } |
425 } |
414 } |
426 } |
415 } |
427 |
416 |
428 // we need to find the editor which is inside |
|
429 if (graphicsObject) { |
417 if (graphicsObject) { |
430 return QRectF(graphicsObject->scenePos(), graphicsObject->boundingRect().size()); |
418 return QRectF(graphicsObject->scenePos(), graphicsObject->boundingRect().size()); |
431 } |
419 } |
432 |
420 |
433 return QRectF(); |
421 return QRectF(); |
588 */ |
576 */ |
589 QPointF HbInputFocusObject::scenePos() const |
577 QPointF HbInputFocusObject::scenePos() const |
590 { |
578 { |
591 Q_D(const HbInputFocusObject); |
579 Q_D(const HbInputFocusObject); |
592 |
580 |
593 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(d->mFocusedObject); |
581 QGraphicsObject *graphicsObject = d->mGraphicsObject; |
594 if (graphicsObject) { |
582 if (graphicsObject) { |
595 return graphicsObject->scenePos(); |
583 return graphicsObject->scenePos(); |
596 } |
584 } |
597 |
585 |
598 QWidget *w = qobject_cast<QWidget *>(d->mFocusedObject); |
586 QWidget *widget = d->mWidget; |
599 // check if widget is inside a proxy. |
587 if (widget) { |
600 QGraphicsProxyWidget *pw = HbInputUtils::graphicsProxyWidget(w); |
588 QGraphicsProxyWidget *proxy = widget->graphicsProxyWidget(); |
601 if (pw) { |
589 if (proxy) { |
602 // check if we are pointing to the toplevel |
590 return proxy->scenePos(); |
603 // proxy widget, if not then we must check for |
591 } |
604 // the widgets window and see if it is a proxy. |
592 return widget->mapToGlobal(QPoint(0, 0)); |
605 if (pw->widget() == w) { |
|
606 return pw->scenePos(); |
|
607 } else if (pw->widget() == w->window()) { |
|
608 QRectF rect = pw->subWidgetRect(w); |
|
609 rect.translate(pw->scenePos()); |
|
610 return rect.topLeft(); |
|
611 } |
|
612 } |
|
613 |
|
614 if (w) { |
|
615 // not a proxy.. Meaning widget is inside a QWidget window. |
|
616 return w->mapToGlobal(QPoint(0, 0)); |
|
617 } |
593 } |
618 |
594 |
619 return QPointF(0.0, 0.0); |
595 return QPointF(0.0, 0.0); |
620 } |
596 } |
621 |
597 |
653 /*! |
629 /*! |
654 Commits given smiley. |
630 Commits given smiley. |
655 */ |
631 */ |
656 void HbInputFocusObject::commitSmiley(QString smiley) |
632 void HbInputFocusObject::commitSmiley(QString smiley) |
657 { |
633 { |
658 Q_D(HbInputFocusObject); |
634 QObject *obj = object(); |
659 |
635 if (obj) { |
660 if (d->mFocusedObject) { |
636 obj->setProperty("SmileyIcon", smiley); |
661 d->mFocusedObject->setProperty("SmileyIcon", smiley); |
|
662 } |
637 } |
663 } |
638 } |
664 |
639 |
665 /*! |
640 /*! |
666 Returns the editor widget as QObject. |
641 Returns the editor widget as QObject. |
667 */ |
642 */ |
668 QObject *HbInputFocusObject::object() const |
643 QObject *HbInputFocusObject::object() const |
669 { |
644 { |
670 Q_D(const HbInputFocusObject); |
645 Q_D(const HbInputFocusObject); |
671 return d->mFocusedObject; |
646 |
|
647 if (d->mGraphicsObject) { |
|
648 return d->mGraphicsObject.data(); |
|
649 } |
|
650 |
|
651 return d->mWidget.data(); |
672 } |
652 } |
673 |
653 |
674 /*! |
654 /*! |
675 Returns true if widget is read-only widget. This works |
655 Returns true if widget is read-only widget. This works |
676 only for known editor types. |
656 only for known editor types. |
737 */ |
717 */ |
738 void HbInputFocusObject::setFocus() |
718 void HbInputFocusObject::setFocus() |
739 { |
719 { |
740 Q_D(HbInputFocusObject); |
720 Q_D(HbInputFocusObject); |
741 |
721 |
742 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(d->mFocusedObject); |
722 bool sendRequest = false; |
|
723 QGraphicsObject *graphicsObject = d->mGraphicsObject; |
743 if (graphicsObject && graphicsObject->scene()) { |
724 if (graphicsObject && graphicsObject->scene()) { |
744 graphicsObject->scene()->setFocusItem(graphicsObject); |
725 graphicsObject->scene()->setFocusItem(graphicsObject); |
|
726 sendRequest = true; |
745 } else { |
727 } else { |
746 QWidget *widget = qobject_cast<QWidget *>(d->mFocusedObject); |
728 QWidget *widget = d->mWidget; |
747 if (widget) { |
729 if (widget) { |
748 widget->setFocus(); |
730 widget->setFocus(); |
749 } |
731 sendRequest = true; |
750 } |
732 } |
751 |
733 } |
752 QInputContext* ic = qApp->inputContext(); |
734 |
753 if (ic) { |
735 if (sendRequest) { |
754 QEvent *openEvent = new QEvent(QEvent::RequestSoftwareInputPanel); |
736 QInputContext* ic = qApp->inputContext(); |
755 ic->filterEvent(openEvent); |
737 if (ic) { |
756 delete openEvent; |
738 QEvent *openEvent = new QEvent(QEvent::RequestSoftwareInputPanel); |
|
739 ic->filterEvent(openEvent); |
|
740 delete openEvent; |
|
741 } |
757 } |
742 } |
758 } |
743 } |
759 |
744 |
760 /*! |
745 /*! |
761 Returns the screen orientation in editor widget's context. For widgets |
746 Returns the screen orientation in editor widget's context. For widgets |