1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
6 | **
|
---|
7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at qt-info@nokia.com.
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #ifndef QT_NO_IM
|
---|
43 |
|
---|
44 | #include "qcoefepinputcontext_p.h"
|
---|
45 | #include <qapplication.h>
|
---|
46 | #include <qtextformat.h>
|
---|
47 | #include <qgraphicsview.h>
|
---|
48 | #include <qgraphicsscene.h>
|
---|
49 | #include <qgraphicswidget.h>
|
---|
50 | #include <qsymbianevent.h>
|
---|
51 | #include <private/qcore_symbian_p.h>
|
---|
52 |
|
---|
53 | #include <fepitfr.h>
|
---|
54 | #include <hal.h>
|
---|
55 |
|
---|
56 | #include <limits.h>
|
---|
57 | // You only find these enumerations on SDK 5 onwards, so we need to provide our own
|
---|
58 | // to remain compatible with older releases. They won't be called by pre-5.0 SDKs.
|
---|
59 |
|
---|
60 | // MAknEdStateObserver::EAknCursorPositionChanged
|
---|
61 | #define QT_EAknCursorPositionChanged MAknEdStateObserver::EAknEdwinStateEvent(6)
|
---|
62 | // MAknEdStateObserver::EAknActivatePenInputRequest
|
---|
63 | #define QT_EAknActivatePenInputRequest MAknEdStateObserver::EAknEdwinStateEvent(7)
|
---|
64 |
|
---|
65 | // EAknEditorFlagSelectionVisible is only valid from 3.2 onwards.
|
---|
66 | // Sym^3 AVKON FEP manager expects that this flag is used for FEP-aware editors
|
---|
67 | // that support text selection.
|
---|
68 | #define QT_EAknEditorFlagSelectionVisible 0x100000
|
---|
69 |
|
---|
70 | QT_BEGIN_NAMESPACE
|
---|
71 |
|
---|
72 | QCoeFepInputContext::QCoeFepInputContext(QObject *parent)
|
---|
73 | : QInputContext(parent),
|
---|
74 | m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new
|
---|
75 | m_lastImHints(Qt::ImhNone),
|
---|
76 | m_textCapabilities(TCoeInputCapabilities::EAllText),
|
---|
77 | m_inDestruction(false),
|
---|
78 | m_pendingInputCapabilitiesChanged(false),
|
---|
79 | m_cursorVisibility(1),
|
---|
80 | m_inlinePosition(0),
|
---|
81 | m_formatRetriever(0),
|
---|
82 | m_pointerHandler(0),
|
---|
83 | m_hasTempPreeditString(false)
|
---|
84 | {
|
---|
85 | m_fepState->SetObjectProvider(this);
|
---|
86 | if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
|
---|
87 | m_fepState->SetFlags(EAknEditorFlagDefault | QT_EAknEditorFlagSelectionVisible);
|
---|
88 | else
|
---|
89 | m_fepState->SetFlags(EAknEditorFlagDefault);
|
---|
90 | m_fepState->SetDefaultInputMode( EAknEditorTextInputMode );
|
---|
91 | m_fepState->SetPermittedInputModes( EAknEditorAllInputModes );
|
---|
92 | m_fepState->SetDefaultCase( EAknEditorTextCase );
|
---|
93 | m_fepState->SetPermittedCases( EAknEditorAllCaseModes );
|
---|
94 | m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG);
|
---|
95 | m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap );
|
---|
96 | }
|
---|
97 |
|
---|
98 | QCoeFepInputContext::~QCoeFepInputContext()
|
---|
99 | {
|
---|
100 | m_inDestruction = true;
|
---|
101 |
|
---|
102 | // This is to make sure that the FEP manager "forgets" about us,
|
---|
103 | // otherwise we may get callbacks even after we're destroyed.
|
---|
104 | // The call below is essentially equivalent to InputCapabilitiesChanged(),
|
---|
105 | // but is synchronous, rather than asynchronous.
|
---|
106 | CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus();
|
---|
107 |
|
---|
108 | if (m_fepState)
|
---|
109 | delete m_fepState;
|
---|
110 | }
|
---|
111 |
|
---|
112 | void QCoeFepInputContext::reset()
|
---|
113 | {
|
---|
114 | commitCurrentString(true);
|
---|
115 | }
|
---|
116 |
|
---|
117 | void QCoeFepInputContext::ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateEvent aEventType)
|
---|
118 | {
|
---|
119 | QT_TRAP_THROWING(m_fepState->ReportAknEdStateEventL(aEventType));
|
---|
120 | }
|
---|
121 |
|
---|
122 | void QCoeFepInputContext::update()
|
---|
123 | {
|
---|
124 | updateHints(false);
|
---|
125 |
|
---|
126 | // For pre-5.0 SDKs, we don't do text updates on S60 side.
|
---|
127 | if (QSysInfo::s60Version() < QSysInfo::SV_S60_5_0) {
|
---|
128 | return;
|
---|
129 | }
|
---|
130 |
|
---|
131 | // Don't be fooled (as I was) by the name of this enumeration.
|
---|
132 | // What it really does is tell the virtual keyboard UI that the text has been
|
---|
133 | // updated and it should be reflected in the internal display of the VK.
|
---|
134 | ReportAknEdStateEvent(QT_EAknCursorPositionChanged);
|
---|
135 | }
|
---|
136 |
|
---|
137 | void QCoeFepInputContext::setFocusWidget(QWidget *w)
|
---|
138 | {
|
---|
139 | commitCurrentString(true);
|
---|
140 |
|
---|
141 | QInputContext::setFocusWidget(w);
|
---|
142 |
|
---|
143 | updateHints(true);
|
---|
144 | }
|
---|
145 |
|
---|
146 | void QCoeFepInputContext::widgetDestroyed(QWidget *w)
|
---|
147 | {
|
---|
148 | // Make sure that the input capabilities of whatever new widget got focused are queried.
|
---|
149 | CCoeControl *ctrl = w->effectiveWinId();
|
---|
150 | if (ctrl->IsFocused()) {
|
---|
151 | queueInputCapabilitiesChanged();
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | QString QCoeFepInputContext::language()
|
---|
156 | {
|
---|
157 | TLanguage lang = m_fepState->LocalLanguage();
|
---|
158 | const QByteArray localeName = qt_symbianLocaleName(lang);
|
---|
159 | if (!localeName.isEmpty()) {
|
---|
160 | return QString::fromLatin1(localeName);
|
---|
161 | } else {
|
---|
162 | return QString::fromLatin1("C");
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | bool QCoeFepInputContext::needsInputPanel()
|
---|
167 | {
|
---|
168 | switch (QSysInfo::s60Version()) {
|
---|
169 | case QSysInfo::SV_S60_3_1:
|
---|
170 | case QSysInfo::SV_S60_3_2:
|
---|
171 | // There are no touch phones for pre-5.0 SDKs.
|
---|
172 | return false;
|
---|
173 | #ifdef Q_CC_NOKIAX86
|
---|
174 | default:
|
---|
175 | // For emulator we assume that we need an input panel, since we can't
|
---|
176 | // separate between phone types.
|
---|
177 | return true;
|
---|
178 | #else
|
---|
179 | case QSysInfo::SV_S60_5_0: {
|
---|
180 | // For SDK == 5.0, we need phone specific detection, since the HAL API
|
---|
181 | // is no good on most phones. However, all phones at the time of writing use the
|
---|
182 | // input panel, except N97 in landscape mode, but in this mode it refuses to bring
|
---|
183 | // up the panel anyway, so we don't have to care.
|
---|
184 | return true;
|
---|
185 | }
|
---|
186 | default:
|
---|
187 | // For unknown/newer types, we try to use the HAL API.
|
---|
188 | int keyboardEnabled;
|
---|
189 | int keyboardType;
|
---|
190 | int err[2];
|
---|
191 | err[0] = HAL::Get(HAL::EKeyboard, keyboardType);
|
---|
192 | err[1] = HAL::Get(HAL::EKeyboardState, keyboardEnabled);
|
---|
193 | if (err[0] == KErrNone && err[1] == KErrNone
|
---|
194 | && keyboardType != 0 && keyboardEnabled)
|
---|
195 | // Means that we have some sort of keyboard.
|
---|
196 | return false;
|
---|
197 |
|
---|
198 | // Fall back to using the input panel.
|
---|
199 | return true;
|
---|
200 | #endif // !Q_CC_NOKIAX86
|
---|
201 | }
|
---|
202 | }
|
---|
203 |
|
---|
204 | bool QCoeFepInputContext::filterEvent(const QEvent *event)
|
---|
205 | {
|
---|
206 | // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically
|
---|
207 | // close when it discovers that the underlying widget does not have input capabilities.
|
---|
208 |
|
---|
209 | if (!focusWidget())
|
---|
210 | return false;
|
---|
211 |
|
---|
212 | switch (event->type()) {
|
---|
213 | case QEvent::KeyPress:
|
---|
214 | commitTemporaryPreeditString();
|
---|
215 | // fall through intended
|
---|
216 | case QEvent::KeyRelease:
|
---|
217 | const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
|
---|
218 | switch (keyEvent->key()) {
|
---|
219 | case Qt::Key_F20:
|
---|
220 | Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints());
|
---|
221 | if (m_lastImHints & Qt::ImhHiddenText) {
|
---|
222 | // Special case in Symbian. On editors with secret text, F20 is for some reason
|
---|
223 | // considered to be a backspace.
|
---|
224 | QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(),
|
---|
225 | keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count());
|
---|
226 | QApplication::sendEvent(focusWidget(), &modifiedEvent);
|
---|
227 | return true;
|
---|
228 | }
|
---|
229 | break;
|
---|
230 | case Qt::Key_Select:
|
---|
231 | if (!m_preeditString.isEmpty()) {
|
---|
232 | commitCurrentString(true);
|
---|
233 | return true;
|
---|
234 | }
|
---|
235 | break;
|
---|
236 | default:
|
---|
237 | break;
|
---|
238 | }
|
---|
239 |
|
---|
240 | QString widgetText = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
|
---|
241 | bool validLength;
|
---|
242 | int maxLength = focusWidget()->inputMethodQuery(Qt::ImMaximumTextLength).toInt(&validLength);
|
---|
243 | if (!keyEvent->text().isEmpty() && validLength
|
---|
244 | && widgetText.size() + m_preeditString.size() >= maxLength) {
|
---|
245 | // Don't send key events with string content if the widget is "full".
|
---|
246 | return true;
|
---|
247 | }
|
---|
248 |
|
---|
249 | if (keyEvent->type() == QEvent::KeyPress
|
---|
250 | && focusWidget()->inputMethodHints() & Qt::ImhHiddenText
|
---|
251 | && !keyEvent->text().isEmpty()) {
|
---|
252 | // Send some temporary preedit text in order to make text visible for a moment.
|
---|
253 | m_preeditString = keyEvent->text();
|
---|
254 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
255 | QInputMethodEvent imEvent(m_preeditString, attributes);
|
---|
256 | sendEvent(imEvent);
|
---|
257 | m_tempPreeditStringTimeout.start(1000, this);
|
---|
258 | m_hasTempPreeditString = true;
|
---|
259 | update();
|
---|
260 | return true;
|
---|
261 | }
|
---|
262 | break;
|
---|
263 | }
|
---|
264 |
|
---|
265 | if (!needsInputPanel())
|
---|
266 | return false;
|
---|
267 |
|
---|
268 | if (event->type() == QEvent::RequestSoftwareInputPanel) {
|
---|
269 | // Notify S60 that we want the virtual keyboard to show up.
|
---|
270 | QSymbianControl *sControl;
|
---|
271 | sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl);
|
---|
272 | Q_ASSERT(sControl);
|
---|
273 |
|
---|
274 | // The FEP UI temporarily steals focus when it shows up the first time, causing
|
---|
275 | // all sorts of weird effects on the focused widgets. Since it will immediately give
|
---|
276 | // back focus to us, we temporarily disable focus handling until the job's done.
|
---|
277 | if (sControl) {
|
---|
278 | sControl->setIgnoreFocusChanged(true);
|
---|
279 | }
|
---|
280 |
|
---|
281 | ensureInputCapabilitiesChanged();
|
---|
282 | m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::QT_EAknActivatePenInputRequest);
|
---|
283 |
|
---|
284 | if (sControl) {
|
---|
285 | sControl->setIgnoreFocusChanged(false);
|
---|
286 | }
|
---|
287 | return true;
|
---|
288 | }
|
---|
289 |
|
---|
290 | return false;
|
---|
291 | }
|
---|
292 |
|
---|
293 | bool QCoeFepInputContext::symbianFilterEvent(QWidget *keyWidget, const QSymbianEvent *event)
|
---|
294 | {
|
---|
295 | Q_UNUSED(keyWidget);
|
---|
296 | if (event->type() == QSymbianEvent::CommandEvent)
|
---|
297 | // A command basically means the same as a button being pushed. With Qt buttons
|
---|
298 | // that would normally result in a reset of the input method due to the focus change.
|
---|
299 | // This should also happen for commands.
|
---|
300 | reset();
|
---|
301 |
|
---|
302 | return false;
|
---|
303 | }
|
---|
304 |
|
---|
305 | void QCoeFepInputContext::timerEvent(QTimerEvent *timerEvent)
|
---|
306 | {
|
---|
307 | if (timerEvent->timerId() == m_tempPreeditStringTimeout.timerId())
|
---|
308 | commitTemporaryPreeditString();
|
---|
309 | }
|
---|
310 |
|
---|
311 | void QCoeFepInputContext::commitTemporaryPreeditString()
|
---|
312 | {
|
---|
313 | if (m_tempPreeditStringTimeout.isActive())
|
---|
314 | m_tempPreeditStringTimeout.stop();
|
---|
315 |
|
---|
316 | if (!m_hasTempPreeditString)
|
---|
317 | return;
|
---|
318 |
|
---|
319 | commitCurrentString(false);
|
---|
320 | }
|
---|
321 |
|
---|
322 | void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event)
|
---|
323 | {
|
---|
324 | Q_ASSERT(focusWidget());
|
---|
325 |
|
---|
326 | if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) {
|
---|
327 | commitCurrentString(true);
|
---|
328 | int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
|
---|
329 |
|
---|
330 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
331 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos + x, 0, QVariant());
|
---|
332 | QInputMethodEvent event(QLatin1String(""), attributes);
|
---|
333 | sendEvent(event);
|
---|
334 | }
|
---|
335 | }
|
---|
336 |
|
---|
337 | TCoeInputCapabilities QCoeFepInputContext::inputCapabilities()
|
---|
338 | {
|
---|
339 | if (m_inDestruction || !focusWidget()) {
|
---|
340 | return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
|
---|
341 | }
|
---|
342 |
|
---|
343 | return TCoeInputCapabilities(m_textCapabilities, this, 0);
|
---|
344 | }
|
---|
345 |
|
---|
346 | static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat, bool validStyleColor)
|
---|
347 | {
|
---|
348 | QTextCharFormat qFormat;
|
---|
349 |
|
---|
350 | if (validStyleColor) {
|
---|
351 | QBrush foreground(QColor(cFormat.iFontPresentation.iTextColor.Internal()));
|
---|
352 | qFormat.setForeground(foreground);
|
---|
353 | }
|
---|
354 |
|
---|
355 | qFormat.setFontStrikeOut(cFormat.iFontPresentation.iStrikethrough == EStrikethroughOn);
|
---|
356 | qFormat.setFontUnderline(cFormat.iFontPresentation.iUnderline == EUnderlineOn);
|
---|
357 |
|
---|
358 | return qFormat;
|
---|
359 | }
|
---|
360 |
|
---|
361 | void QCoeFepInputContext::updateHints(bool mustUpdateInputCapabilities)
|
---|
362 | {
|
---|
363 | QWidget *w = focusWidget();
|
---|
364 | if (w) {
|
---|
365 | Qt::InputMethodHints hints = w->inputMethodHints();
|
---|
366 | if (hints != m_lastImHints) {
|
---|
367 | m_lastImHints = hints;
|
---|
368 | applyHints(hints);
|
---|
369 | } else if (!mustUpdateInputCapabilities) {
|
---|
370 | // Optimization. Return immediately if there was no change.
|
---|
371 | return;
|
---|
372 | }
|
---|
373 | }
|
---|
374 | queueInputCapabilitiesChanged();
|
---|
375 | }
|
---|
376 |
|
---|
377 | void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints)
|
---|
378 | {
|
---|
379 | using namespace Qt;
|
---|
380 |
|
---|
381 | commitTemporaryPreeditString();
|
---|
382 |
|
---|
383 | const bool anynumbermodes = hints & (ImhDigitsOnly | ImhFormattedNumbersOnly | ImhDialableCharactersOnly);
|
---|
384 | const bool anytextmodes = hints & (ImhUppercaseOnly | ImhLowercaseOnly | ImhEmailCharactersOnly | ImhUrlCharactersOnly);
|
---|
385 | const bool numbersOnly = anynumbermodes && !anytextmodes;
|
---|
386 | const bool noOnlys = !(hints & ImhExclusiveInputMask);
|
---|
387 | // if alphanumeric input, or if multiple incompatible number modes are selected;
|
---|
388 | // then make all symbols available in numeric mode too.
|
---|
389 | const bool needsCharMap= !numbersOnly || ((hints & ImhFormattedNumbersOnly) && (hints & ImhDialableCharactersOnly));
|
---|
390 | TInt flags;
|
---|
391 | Qt::InputMethodHints oldHints = hints;
|
---|
392 |
|
---|
393 | // Some sanity checking. Make sure that only one preference is set.
|
---|
394 | InputMethodHints prefs = ImhPreferNumbers | ImhPreferUppercase | ImhPreferLowercase;
|
---|
395 | prefs &= hints;
|
---|
396 | if (prefs != ImhPreferNumbers && prefs != ImhPreferUppercase && prefs != ImhPreferLowercase) {
|
---|
397 | hints &= ~prefs;
|
---|
398 | }
|
---|
399 | if (!noOnlys) {
|
---|
400 | // Make sure that the preference is within the permitted set.
|
---|
401 | if (hints & ImhPreferNumbers && !anynumbermodes) {
|
---|
402 | hints &= ~ImhPreferNumbers;
|
---|
403 | } else if (hints & ImhPreferUppercase && !(hints & ImhUppercaseOnly)) {
|
---|
404 | hints &= ~ImhPreferUppercase;
|
---|
405 | } else if (hints & ImhPreferLowercase && !(hints & ImhLowercaseOnly)) {
|
---|
406 | hints &= ~ImhPreferLowercase;
|
---|
407 | }
|
---|
408 | // If there is no preference, set it to something within the permitted set.
|
---|
409 | if (!(hints & ImhPreferNumbers || hints & ImhPreferUppercase || hints & ImhPreferLowercase)) {
|
---|
410 | if (hints & ImhLowercaseOnly) {
|
---|
411 | hints |= ImhPreferLowercase;
|
---|
412 | } else if (hints & ImhUppercaseOnly) {
|
---|
413 | hints |= ImhPreferUppercase;
|
---|
414 | } else if (numbersOnly) {
|
---|
415 | hints |= ImhPreferNumbers;
|
---|
416 | }
|
---|
417 | }
|
---|
418 | }
|
---|
419 |
|
---|
420 | if (hints & ImhPreferNumbers) {
|
---|
421 | m_fepState->SetDefaultInputMode(EAknEditorNumericInputMode);
|
---|
422 | m_fepState->SetCurrentInputMode(EAknEditorNumericInputMode);
|
---|
423 | } else {
|
---|
424 | m_fepState->SetDefaultInputMode(EAknEditorTextInputMode);
|
---|
425 | m_fepState->SetCurrentInputMode(EAknEditorTextInputMode);
|
---|
426 | }
|
---|
427 | flags = 0;
|
---|
428 | if (noOnlys || (anynumbermodes && anytextmodes)) {
|
---|
429 | flags = EAknEditorAllInputModes;
|
---|
430 | }
|
---|
431 | else if (anynumbermodes) {
|
---|
432 | flags |= EAknEditorNumericInputMode;
|
---|
433 | if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0
|
---|
434 | && ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly))) {
|
---|
435 | //workaround - the * key does not launch the symbols menu, making it impossible to use these modes unless text mode is enabled.
|
---|
436 | flags |= EAknEditorTextInputMode;
|
---|
437 | }
|
---|
438 | }
|
---|
439 | else if (anytextmodes) {
|
---|
440 | flags |= EAknEditorTextInputMode;
|
---|
441 | }
|
---|
442 | else {
|
---|
443 | flags = EAknEditorAllInputModes;
|
---|
444 | }
|
---|
445 | m_fepState->SetPermittedInputModes(flags);
|
---|
446 | ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateInputModeUpdate);
|
---|
447 |
|
---|
448 | if (hints & ImhPreferLowercase) {
|
---|
449 | m_fepState->SetDefaultCase(EAknEditorLowerCase);
|
---|
450 | m_fepState->SetCurrentCase(EAknEditorLowerCase);
|
---|
451 | } else if (hints & ImhPreferUppercase) {
|
---|
452 | m_fepState->SetDefaultCase(EAknEditorUpperCase);
|
---|
453 | m_fepState->SetCurrentCase(EAknEditorUpperCase);
|
---|
454 | } else if (hints & ImhNoAutoUppercase) {
|
---|
455 | m_fepState->SetDefaultCase(EAknEditorLowerCase);
|
---|
456 | m_fepState->SetCurrentCase(EAknEditorLowerCase);
|
---|
457 | } else {
|
---|
458 | m_fepState->SetDefaultCase(EAknEditorTextCase);
|
---|
459 | m_fepState->SetCurrentCase(EAknEditorTextCase);
|
---|
460 | }
|
---|
461 | flags = 0;
|
---|
462 | if (hints & ImhUppercaseOnly) {
|
---|
463 | flags |= EAknEditorUpperCase;
|
---|
464 | }
|
---|
465 | if (hints & ImhLowercaseOnly) {
|
---|
466 | flags |= EAknEditorLowerCase;
|
---|
467 | }
|
---|
468 | if (flags == 0) {
|
---|
469 | flags = EAknEditorAllCaseModes;
|
---|
470 | if (hints & ImhNoAutoUppercase) {
|
---|
471 | flags &= ~EAknEditorTextCase;
|
---|
472 | }
|
---|
473 | }
|
---|
474 | m_fepState->SetPermittedCases(flags);
|
---|
475 | ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate);
|
---|
476 |
|
---|
477 | if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
|
---|
478 | flags = QT_EAknEditorFlagSelectionVisible;
|
---|
479 | else
|
---|
480 | flags = 0;
|
---|
481 | if (hints & ImhUppercaseOnly && !(hints & ImhLowercaseOnly)
|
---|
482 | || hints & ImhLowercaseOnly && !(hints & ImhUppercaseOnly)) {
|
---|
483 | flags |= EAknEditorFlagFixedCase;
|
---|
484 | }
|
---|
485 | // Using T9 and hidden text together may actually crash the FEP, so check for hidden text too.
|
---|
486 | if (hints & ImhNoPredictiveText || hints & ImhHiddenText) {
|
---|
487 | flags |= EAknEditorFlagNoT9;
|
---|
488 | }
|
---|
489 | if (needsCharMap)
|
---|
490 | flags |= EAknEditorFlagUseSCTNumericCharmap;
|
---|
491 | m_fepState->SetFlags(flags);
|
---|
492 | ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateFlagsUpdate);
|
---|
493 |
|
---|
494 | if (hints & ImhDialableCharactersOnly) {
|
---|
495 | // This is first, because if (ImhDialableCharactersOnly | ImhFormattedNumbersOnly)
|
---|
496 | // is specified, this one is more natural (# key enters a #)
|
---|
497 | flags = EAknEditorStandardNumberModeKeymap;
|
---|
498 | } else if (hints & ImhFormattedNumbersOnly) {
|
---|
499 | // # key enters decimal point
|
---|
500 | flags = EAknEditorCalculatorNumberModeKeymap;
|
---|
501 | } else if (hints & ImhDigitsOnly) {
|
---|
502 | // This is last, because it is most restrictive (# key is inactive)
|
---|
503 | flags = EAknEditorPlainNumberModeKeymap;
|
---|
504 | } else {
|
---|
505 | flags = EAknEditorStandardNumberModeKeymap;
|
---|
506 | }
|
---|
507 | m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags));
|
---|
508 |
|
---|
509 | if (hints & ImhUrlCharactersOnly) {
|
---|
510 | // URL characters is everything except space, so a superset of the other restrictions
|
---|
511 | m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_URL_SPECIAL_CHARACTER_TABLE_DIALOG);
|
---|
512 | } else if (hints & ImhEmailCharactersOnly) {
|
---|
513 | m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG);
|
---|
514 | } else if (needsCharMap) {
|
---|
515 | m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG);
|
---|
516 | } else {
|
---|
517 | m_fepState->SetSpecialCharacterTableResourceId(0);
|
---|
518 | }
|
---|
519 |
|
---|
520 | if (hints & ImhHiddenText) {
|
---|
521 | m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText;
|
---|
522 | } else {
|
---|
523 | m_textCapabilities = TCoeInputCapabilities::EAllText;
|
---|
524 | }
|
---|
525 | }
|
---|
526 |
|
---|
527 | void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes)
|
---|
528 | {
|
---|
529 | TCharFormat cFormat;
|
---|
530 | QColor styleTextColor;
|
---|
531 | if (QWidget *focused = focusWidget()) {
|
---|
532 | QGraphicsView *gv = qobject_cast<QGraphicsView*>(focused);
|
---|
533 | if (!gv) // could be either the QGV or its viewport that has focus
|
---|
534 | gv = qobject_cast<QGraphicsView*>(focused->parentWidget());
|
---|
535 | if (gv) {
|
---|
536 | if (QGraphicsScene *scene = gv->scene()) {
|
---|
537 | if (QGraphicsItem *focusItem = scene->focusItem()) {
|
---|
538 | if (focusItem->isWidget()) {
|
---|
539 | styleTextColor = static_cast<QGraphicsWidget*>(focusItem)->palette().text().color();
|
---|
540 | }
|
---|
541 | }
|
---|
542 | }
|
---|
543 | } else {
|
---|
544 | styleTextColor = focused->palette().text().color();
|
---|
545 | }
|
---|
546 | } else {
|
---|
547 | styleTextColor = QApplication::palette("QLineEdit").text().color();
|
---|
548 | }
|
---|
549 |
|
---|
550 | if (styleTextColor.isValid()) {
|
---|
551 | const TLogicalRgb fontColor(TRgb(styleTextColor.red(), styleTextColor.green(), styleTextColor.blue(), styleTextColor.alpha()));
|
---|
552 | cFormat.iFontPresentation.iTextColor = fontColor;
|
---|
553 | }
|
---|
554 |
|
---|
555 | TInt numChars = 0;
|
---|
556 | TInt charPos = 0;
|
---|
557 | int oldSize = attributes->size();
|
---|
558 | while (m_formatRetriever) {
|
---|
559 | m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos);
|
---|
560 | if (numChars <= 0) {
|
---|
561 | // This shouldn't happen according to S60 docs, but apparently does sometimes.
|
---|
562 | break;
|
---|
563 | }
|
---|
564 | attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
|
---|
565 | charPos,
|
---|
566 | numChars,
|
---|
567 | QVariant(qt_TCharFormat2QTextCharFormat(cFormat, styleTextColor.isValid()))));
|
---|
568 | charPos += numChars;
|
---|
569 | if (charPos >= m_preeditString.size()) {
|
---|
570 | break;
|
---|
571 | }
|
---|
572 | }
|
---|
573 |
|
---|
574 | if (attributes->size() == oldSize) {
|
---|
575 | // S60 didn't provide any format, so let's give our own instead.
|
---|
576 | attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
|
---|
577 | 0,
|
---|
578 | m_preeditString.size(),
|
---|
579 | standardFormat(PreeditFormat)));
|
---|
580 | }
|
---|
581 | }
|
---|
582 |
|
---|
583 | void QCoeFepInputContext::queueInputCapabilitiesChanged()
|
---|
584 | {
|
---|
585 | if (m_pendingInputCapabilitiesChanged)
|
---|
586 | return;
|
---|
587 |
|
---|
588 | // Call ensureInputCapabilitiesChanged asynchronously. This is done to improve performance
|
---|
589 | // by not updating input capabilities too often. The reason we don't call the Symbian
|
---|
590 | // asynchronous version of InputCapabilitiesChanged is because we need to ensure that it
|
---|
591 | // is synchronous in some specific cases. Those will call ensureInputCapabilitesChanged.
|
---|
592 | QMetaObject::invokeMethod(this, "ensureInputCapabilitiesChanged", Qt::QueuedConnection);
|
---|
593 | m_pendingInputCapabilitiesChanged = true;
|
---|
594 | }
|
---|
595 |
|
---|
596 | void QCoeFepInputContext::ensureInputCapabilitiesChanged()
|
---|
597 | {
|
---|
598 | if (!m_pendingInputCapabilitiesChanged)
|
---|
599 | return;
|
---|
600 |
|
---|
601 | // The call below is essentially equivalent to InputCapabilitiesChanged(),
|
---|
602 | // but is synchronous, rather than asynchronous.
|
---|
603 | CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus();
|
---|
604 | m_pendingInputCapabilitiesChanged = false;
|
---|
605 | }
|
---|
606 |
|
---|
607 | void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText,
|
---|
608 | TInt aPositionOfInsertionPointInInlineText, TBool aCursorVisibility, const MFormCustomDraw* /*aCustomDraw*/,
|
---|
609 | MFepInlineTextFormatRetriever& aInlineTextFormatRetriever,
|
---|
610 | MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit)
|
---|
611 | {
|
---|
612 | QWidget *w = focusWidget();
|
---|
613 | if (!w)
|
---|
614 | return;
|
---|
615 |
|
---|
616 | commitTemporaryPreeditString();
|
---|
617 |
|
---|
618 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
619 |
|
---|
620 | m_cursorVisibility = aCursorVisibility ? 1 : 0;
|
---|
621 | m_inlinePosition = aPositionOfInsertionPointInInlineText;
|
---|
622 | m_preeditString = qt_TDesC2QString(aInitialInlineText);
|
---|
623 |
|
---|
624 | m_formatRetriever = &aInlineTextFormatRetriever;
|
---|
625 | m_pointerHandler = &aPointerEventHandlerDuringInlineEdit;
|
---|
626 |
|
---|
627 | // With T9 aInitialInlineText is typically empty when StartFepInlineEditL is called,
|
---|
628 | // but FEP requires that selected text is always removed at StartFepInlineEditL.
|
---|
629 | // Let's remove the selected text if aInitialInlineText is empty and there is selected text
|
---|
630 | if (m_preeditString.isEmpty()) {
|
---|
631 | int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt();
|
---|
632 | int cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
|
---|
633 | int replacementLength = qAbs(cursorPos-anchor);
|
---|
634 | if (replacementLength > 0) {
|
---|
635 | int replacementStart = cursorPos < anchor ? 0 : -replacementLength;
|
---|
636 | QList<QInputMethodEvent::Attribute> clearSelectionAttributes;
|
---|
637 | QInputMethodEvent clearSelectionEvent(QLatin1String(""), clearSelectionAttributes);
|
---|
638 | clearSelectionEvent.setCommitString(QLatin1String(""), replacementStart, replacementLength);
|
---|
639 | sendEvent(clearSelectionEvent);
|
---|
640 | }
|
---|
641 | }
|
---|
642 |
|
---|
643 | applyFormat(&attributes);
|
---|
644 |
|
---|
645 | attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
|
---|
646 | m_inlinePosition,
|
---|
647 | m_cursorVisibility,
|
---|
648 | QVariant()));
|
---|
649 | QInputMethodEvent event(m_preeditString, attributes);
|
---|
650 | sendEvent(event);
|
---|
651 | }
|
---|
652 |
|
---|
653 | void QCoeFepInputContext::UpdateFepInlineTextL(const TDesC& aNewInlineText,
|
---|
654 | TInt aPositionOfInsertionPointInInlineText)
|
---|
655 | {
|
---|
656 | QWidget *w = focusWidget();
|
---|
657 | if (!w)
|
---|
658 | return;
|
---|
659 |
|
---|
660 | commitTemporaryPreeditString();
|
---|
661 |
|
---|
662 | m_inlinePosition = aPositionOfInsertionPointInInlineText;
|
---|
663 |
|
---|
664 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
665 | applyFormat(&attributes);
|
---|
666 | attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
|
---|
667 | m_inlinePosition,
|
---|
668 | m_cursorVisibility,
|
---|
669 | QVariant()));
|
---|
670 | QString newPreeditString = qt_TDesC2QString(aNewInlineText);
|
---|
671 | QInputMethodEvent event(newPreeditString, attributes);
|
---|
672 | if (newPreeditString.isEmpty() && m_preeditString.isEmpty()) {
|
---|
673 | // In Symbian world this means "erase last character".
|
---|
674 | event.setCommitString(QLatin1String(""), -1, 1);
|
---|
675 | }
|
---|
676 | m_preeditString = newPreeditString;
|
---|
677 | sendEvent(event);
|
---|
678 | }
|
---|
679 |
|
---|
680 | void QCoeFepInputContext::SetInlineEditingCursorVisibilityL(TBool aCursorVisibility)
|
---|
681 | {
|
---|
682 | QWidget *w = focusWidget();
|
---|
683 | if (!w)
|
---|
684 | return;
|
---|
685 |
|
---|
686 | m_cursorVisibility = aCursorVisibility ? 1 : 0;
|
---|
687 |
|
---|
688 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
689 | attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
|
---|
690 | m_inlinePosition,
|
---|
691 | m_cursorVisibility,
|
---|
692 | QVariant()));
|
---|
693 | QInputMethodEvent event(m_preeditString, attributes);
|
---|
694 | sendEvent(event);
|
---|
695 | }
|
---|
696 |
|
---|
697 | void QCoeFepInputContext::CancelFepInlineEdit()
|
---|
698 | {
|
---|
699 | // We are not supposed to ever have a tempPreeditString and a real preedit string
|
---|
700 | // from S60 at the same time, so it should be safe to rely on this test to determine
|
---|
701 | // whether we should honor S60's request to clear the text or not.
|
---|
702 | if (m_hasTempPreeditString)
|
---|
703 | return;
|
---|
704 |
|
---|
705 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
706 | QInputMethodEvent event(QLatin1String(""), attributes);
|
---|
707 | event.setCommitString(QLatin1String(""), 0, 0);
|
---|
708 | m_preeditString.clear();
|
---|
709 | m_inlinePosition = 0;
|
---|
710 | sendEvent(event);
|
---|
711 | }
|
---|
712 |
|
---|
713 | TInt QCoeFepInputContext::DocumentLengthForFep() const
|
---|
714 | {
|
---|
715 | QWidget *w = focusWidget();
|
---|
716 | if (!w)
|
---|
717 | return 0;
|
---|
718 |
|
---|
719 | QVariant variant = w->inputMethodQuery(Qt::ImSurroundingText);
|
---|
720 | return variant.value<QString>().size() + m_preeditString.size();
|
---|
721 | }
|
---|
722 |
|
---|
723 | TInt QCoeFepInputContext::DocumentMaximumLengthForFep() const
|
---|
724 | {
|
---|
725 | QWidget *w = focusWidget();
|
---|
726 | if (!w)
|
---|
727 | return 0;
|
---|
728 |
|
---|
729 | QVariant variant = w->inputMethodQuery(Qt::ImMaximumTextLength);
|
---|
730 | int size;
|
---|
731 | if (variant.isValid()) {
|
---|
732 | size = variant.toInt();
|
---|
733 | } else {
|
---|
734 | size = INT_MAX; // Sensible default for S60.
|
---|
735 | }
|
---|
736 | return size;
|
---|
737 | }
|
---|
738 |
|
---|
739 | void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection)
|
---|
740 | {
|
---|
741 | QWidget *w = focusWidget();
|
---|
742 | if (!w)
|
---|
743 | return;
|
---|
744 |
|
---|
745 | commitTemporaryPreeditString();
|
---|
746 |
|
---|
747 | int pos = aCursorSelection.iAnchorPos;
|
---|
748 | int length = aCursorSelection.iCursorPos - pos;
|
---|
749 |
|
---|
750 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
751 | attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, length, QVariant());
|
---|
752 | QInputMethodEvent event(m_preeditString, attributes);
|
---|
753 | sendEvent(event);
|
---|
754 | }
|
---|
755 |
|
---|
756 | void QCoeFepInputContext::GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const
|
---|
757 | {
|
---|
758 | QWidget *w = focusWidget();
|
---|
759 | if (!w) {
|
---|
760 | aCursorSelection.SetSelection(0,0);
|
---|
761 | return;
|
---|
762 | }
|
---|
763 |
|
---|
764 | int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size();
|
---|
765 | int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size();
|
---|
766 | QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>();
|
---|
767 | int combinedSize = text.size() + m_preeditString.size();
|
---|
768 | if (combinedSize < anchor || combinedSize < cursor) {
|
---|
769 | // ### TODO! FIXME! QTBUG-5050
|
---|
770 | // This is a hack to prevent crashing in 4.6 with QLineEdits that use input masks.
|
---|
771 | // The root problem is that cursor position is relative to displayed text instead of the
|
---|
772 | // actual text we get.
|
---|
773 | //
|
---|
774 | // To properly fix this we would need to know the displayText of QLineEdits instead
|
---|
775 | // of just the text, which on itself should be a trivial change. The difficulties start
|
---|
776 | // when we need to commit the changes back to the QLineEdit, which would have to be somehow
|
---|
777 | // able to handle displayText, too.
|
---|
778 | //
|
---|
779 | // Until properly fixed, the cursor and anchor positions will not reflect correct positions
|
---|
780 | // for masked QLineEdits, unless all the masked positions are filled in order so that
|
---|
781 | // cursor position relative to the displayed text matches position relative to actual text.
|
---|
782 | aCursorSelection.iAnchorPos = combinedSize;
|
---|
783 | aCursorSelection.iCursorPos = combinedSize;
|
---|
784 | } else {
|
---|
785 | aCursorSelection.iAnchorPos = anchor;
|
---|
786 | aCursorSelection.iCursorPos = cursor;
|
---|
787 | }
|
---|
788 | }
|
---|
789 |
|
---|
790 | void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition,
|
---|
791 | TInt aLengthToRetrieve) const
|
---|
792 | {
|
---|
793 | QWidget *w = focusWidget();
|
---|
794 | if (!w) {
|
---|
795 | aEditorContent.FillZ(aLengthToRetrieve);
|
---|
796 | return;
|
---|
797 | }
|
---|
798 |
|
---|
799 | QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>();
|
---|
800 | // FEP expects the preedit string to be part of the editor content, so let's mix it in.
|
---|
801 | int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
|
---|
802 | text.insert(cursor, m_preeditString);
|
---|
803 | aEditorContent.Copy(qt_QString2TPtrC(text.mid(aDocumentPosition, aLengthToRetrieve)));
|
---|
804 | }
|
---|
805 |
|
---|
806 | void QCoeFepInputContext::GetFormatForFep(TCharFormat& aFormat, TInt /* aDocumentPosition */) const
|
---|
807 | {
|
---|
808 | QWidget *w = focusWidget();
|
---|
809 | if (!w) {
|
---|
810 | aFormat = TCharFormat();
|
---|
811 | return;
|
---|
812 | }
|
---|
813 |
|
---|
814 | QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>();
|
---|
815 | QFontMetrics metrics(font);
|
---|
816 | //QString name = font.rawName();
|
---|
817 | QString name = font.defaultFamily(); // TODO! FIXME! Should be the above.
|
---|
818 | QHBufC hBufC(name);
|
---|
819 | aFormat = TCharFormat(hBufC->Des(), metrics.height());
|
---|
820 | }
|
---|
821 |
|
---|
822 | void QCoeFepInputContext::GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight,
|
---|
823 | TInt& aAscent, TInt /* aDocumentPosition */) const
|
---|
824 | {
|
---|
825 | QWidget *w = focusWidget();
|
---|
826 | if (!w) {
|
---|
827 | aLeftSideOfBaseLine = TPoint(0,0);
|
---|
828 | aHeight = 0;
|
---|
829 | aAscent = 0;
|
---|
830 | return;
|
---|
831 | }
|
---|
832 |
|
---|
833 | QRect rect = w->inputMethodQuery(Qt::ImMicroFocus).value<QRect>();
|
---|
834 | aLeftSideOfBaseLine.iX = rect.left();
|
---|
835 | aLeftSideOfBaseLine.iY = rect.bottom();
|
---|
836 |
|
---|
837 | QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>();
|
---|
838 | QFontMetrics metrics(font);
|
---|
839 | aHeight = metrics.height();
|
---|
840 | aAscent = metrics.ascent();
|
---|
841 | }
|
---|
842 |
|
---|
843 | void QCoeFepInputContext::DoCommitFepInlineEditL()
|
---|
844 | {
|
---|
845 | commitCurrentString(false);
|
---|
846 | if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
|
---|
847 | ReportAknEdStateEvent(QT_EAknCursorPositionChanged);
|
---|
848 |
|
---|
849 | }
|
---|
850 |
|
---|
851 | void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction)
|
---|
852 | {
|
---|
853 | QList<QInputMethodEvent::Attribute> attributes;
|
---|
854 | QInputMethodEvent event(QLatin1String(""), attributes);
|
---|
855 | event.setCommitString(m_preeditString, 0, 0);
|
---|
856 | m_preeditString.clear();
|
---|
857 | m_inlinePosition = 0;
|
---|
858 | sendEvent(event);
|
---|
859 |
|
---|
860 | m_hasTempPreeditString = false;
|
---|
861 |
|
---|
862 | if (cancelFepTransaction) {
|
---|
863 | CCoeFep* fep = CCoeEnv::Static()->Fep();
|
---|
864 | if (fep)
|
---|
865 | fep->CancelTransaction();
|
---|
866 | }
|
---|
867 | }
|
---|
868 |
|
---|
869 | MCoeFepAwareTextEditor_Extension1* QCoeFepInputContext::Extension1(TBool& aSetToTrue)
|
---|
870 | {
|
---|
871 | aSetToTrue = ETrue;
|
---|
872 | return this;
|
---|
873 | }
|
---|
874 |
|
---|
875 | void QCoeFepInputContext::SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState,
|
---|
876 | TUid /*aTypeSafetyUid*/)
|
---|
877 | {
|
---|
878 | // Note: The S60 docs are wrong! See the State() function.
|
---|
879 | if (m_fepState)
|
---|
880 | delete m_fepState;
|
---|
881 | m_fepState = static_cast<CAknEdwinState *>(aState);
|
---|
882 | }
|
---|
883 |
|
---|
884 | MCoeFepAwareTextEditor_Extension1::CState* QCoeFepInputContext::State(TUid /*aTypeSafetyUid*/)
|
---|
885 | {
|
---|
886 | // Note: The S60 docs are horribly wrong when describing the
|
---|
887 | // SetStateTransferingOwnershipL function and this function. They say that the former
|
---|
888 | // sets a CState object identified by the TUid, and the latter retrieves it.
|
---|
889 | // In reality, the CState is expected to always be a CAknEdwinState (even if it was not
|
---|
890 | // previously set), and the TUid is ignored. All in all, there is a single CAknEdwinState
|
---|
891 | // per QCoeFepInputContext, which should be deleted if the SetStateTransferingOwnershipL
|
---|
892 | // function is used to set a new one.
|
---|
893 | return m_fepState;
|
---|
894 | }
|
---|
895 |
|
---|
896 | TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/)
|
---|
897 | {
|
---|
898 | return TTypeUid::Null();
|
---|
899 | }
|
---|
900 |
|
---|
901 | MObjectProvider *QCoeFepInputContext::MopNext()
|
---|
902 | {
|
---|
903 | QWidget *w = focusWidget();
|
---|
904 | if (w)
|
---|
905 | return w->effectiveWinId();
|
---|
906 | return 0;
|
---|
907 | }
|
---|
908 |
|
---|
909 | QT_END_NAMESPACE
|
---|
910 |
|
---|
911 | #endif // QT_NO_IM
|
---|