|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (developer.feedback@nokia.com) |
|
6 ** |
|
7 ** This file is part of the HbInput module of the UI Extensions for Mobile. |
|
8 ** |
|
9 ** GNU Lesser General Public License Usage |
|
10 ** This file may be used under the terms of the GNU Lesser General Public |
|
11 ** License version 2.1 as published by the Free Software Foundation and |
|
12 ** appearing in the file LICENSE.LGPL included in the packaging of this file. |
|
13 ** Please review the following information to ensure the GNU Lesser General |
|
14 ** Public License version 2.1 requirements will be met: |
|
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
16 ** |
|
17 ** In addition, as a special exception, Nokia gives you certain additional |
|
18 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
20 ** |
|
21 ** If you have questions regarding the use of this file, please contact |
|
22 ** Nokia at developer.feedback@nokia.com. |
|
23 ** |
|
24 ****************************************************************************/ |
|
25 |
|
26 #include <hbapplication.h> |
|
27 #include <QGraphicsSceneMouseEvent> |
|
28 #include <QGraphicsLinearLayout> |
|
29 #include <QGraphicsGridLayout> |
|
30 #include <QVector> |
|
31 #include <QSignalMapper> |
|
32 #include <QKeyEvent> |
|
33 #include <QPointer> |
|
34 #include <math.h> |
|
35 |
|
36 #include <hbinstance.h> |
|
37 #include <hbinputmethod.h> |
|
38 #include <hbinputkeymap.h> |
|
39 #include <hbinputvkbhost.h> |
|
40 #include <hbinputsettingproxy.h> |
|
41 #include <hbabstractedit.h> |
|
42 #include "hbinputsctportrait.h" |
|
43 #include "hbinputtouchkeypadbutton.h" |
|
44 #include "hbinputvkbwidget.h" |
|
45 |
|
46 #include "hbinputsctportrait_p.h" |
|
47 #include "hbinputvkbwidget_p.h" |
|
48 |
|
49 /*! |
|
50 @proto |
|
51 @hbinput |
|
52 \class HbInputSctPortrait |
|
53 \brief A widget for displaying special character table in portrait mode. |
|
54 |
|
55 This widget displays special character table. Characters are organized in grid |
|
56 format. The widget inherits from touch keypad base class. When a character |
|
57 is selected it will emit signal sctCharacterSelected. |
|
58 |
|
59 \sa HbInputVkbWidget |
|
60 \sa HbInputTopSctLine |
|
61 */ |
|
62 |
|
63 /// @cond |
|
64 |
|
65 const int HbSctGridColumns = 5; |
|
66 const int HbSctGridRows = 5; |
|
67 const int HbNumSctButtons = HbSctGridColumns*HbSctGridRows; |
|
68 const qreal HbSctButtonPreferredHeight = 56.0; |
|
69 const QSizeF HbSctInitialDimensions(90.0, HbSctButtonPreferredHeight); |
|
70 |
|
71 const int HbDelButtonId = HbSctGridColumns-1; |
|
72 const int HbAbcButtonId = 2*HbSctGridColumns-1; |
|
73 const int HbSpecialCharacterButtonId = 3*HbSctGridColumns-1; |
|
74 const int HbSmileyButtonId = 4*HbSctGridColumns-1; |
|
75 |
|
76 const QString HbDelButtonObjName = "SCT delete"; |
|
77 const QString HbAbcButtonObjName = "SCT abc"; |
|
78 const QString HbSpecialCharacterButtonObjName = "SCT special character"; |
|
79 const QString HbSmileyButtonObjName = "SCT smiley"; |
|
80 const QString HbCustomButtonObjName = "SCT custom button "; |
|
81 |
|
82 const QString HbSctPortraitButtonTextLayout = "_hb_sctp_button_text_layout"; |
|
83 const QString HbSctPortraitButtonIconLayout = "_hb_sctp_button_icon_layout"; |
|
84 |
|
85 HbInputSctPortraitPrivate::HbInputSctPortraitPrivate() |
|
86 : mActiveView(HbInputSctPortrait::HbSctViewSpecialCharacter), |
|
87 mClickMapper(0), |
|
88 mStartIndex(0), |
|
89 mCurrentPage(0), |
|
90 mSize(QSizeF()) |
|
91 { |
|
92 mFlickAnimation = true; |
|
93 } |
|
94 |
|
95 /* |
|
96 This function defines the layout porperties for sct. |
|
97 */ |
|
98 void HbInputSctPortraitPrivate::createSctButtons() |
|
99 { |
|
100 Q_Q(HbInputSctPortrait); |
|
101 |
|
102 q->setupToolCluster(); |
|
103 |
|
104 if (mSctButtons.size() == 0) { |
|
105 for (int i = 0; i < HbNumSctButtons-1; ++i) { |
|
106 HbTouchKeypadButton *button = new HbTouchKeypadButton(q, QString(""), q); |
|
107 q->connect(button, SIGNAL(pressed()),mPressMapper, SLOT(map())); |
|
108 mPressMapper->setMapping(button, i); |
|
109 q->connect(button, SIGNAL(released()),mReleaseMapper, SLOT(map())); |
|
110 mReleaseMapper->setMapping(button, i); |
|
111 q->connect(button, SIGNAL(clicked()), mClickMapper, SLOT(map())); |
|
112 mClickMapper->setMapping(button, i); |
|
113 mSctButtons.append(button); |
|
114 button->setProperty(HbStyleRulesCacheId::hbStyleRulesForNodeCache, HbSctPortraitButtonTextLayout); |
|
115 } |
|
116 |
|
117 mSctButtons.append(mApplicationButton); |
|
118 |
|
119 for (int i = 0; i < HbNumSctButtons; ++i) { |
|
120 mButtonLayout->addItem(mSctButtons.at(i), i/HbSctGridColumns, i%HbSctGridColumns); |
|
121 } |
|
122 } |
|
123 } |
|
124 |
|
125 /* |
|
126 This function defines the layout porperties for sct. |
|
127 */ |
|
128 void HbInputSctPortraitPrivate::setLayoutDimensions(QSizeF dimensions) |
|
129 { |
|
130 // only update the dimensions if they are not previously set |
|
131 if (mSize == dimensions) { |
|
132 return; |
|
133 } |
|
134 mSize = dimensions; |
|
135 |
|
136 mButtonLayout->setContentsMargins(0.0, 0.0, 0.0, 0.0); |
|
137 |
|
138 for (int i = 0; i < HbSctGridColumns; i++) { |
|
139 mButtonLayout->setColumnFixedWidth(i, dimensions.width()); |
|
140 } |
|
141 for (int i = 0; i < HbSctGridRows; i++) { |
|
142 mButtonLayout->setRowFixedHeight(i, dimensions.height()); |
|
143 } |
|
144 |
|
145 mButtonLayout->setHorizontalSpacing(0.0); |
|
146 mButtonLayout->setVerticalSpacing(0.0); |
|
147 foreach (HbTouchKeypadButton* button, mSctButtons) { |
|
148 if (button) { |
|
149 button->setInitialSize(dimensions); |
|
150 } |
|
151 } |
|
152 } |
|
153 |
|
154 |
|
155 void HbInputSctPortraitPrivate::initialize() |
|
156 { |
|
157 mSctButtons.at(HbDelButtonId)->setText(""); |
|
158 mSctButtons.at(HbDelButtonId)->setIcon(HbIcon("qtg_mono_backspace2")); |
|
159 mSctButtons.at(HbDelButtonId)->setObjectName(HbDelButtonObjName); |
|
160 mSctButtons.at(HbDelButtonId)->setAutoRepeatDelay(HbRepeatTimeout); |
|
161 mSctButtons.at(HbDelButtonId)->setAutoRepeatInterval(HbRepeatTimeoutShort); |
|
162 mSctButtons.at(HbDelButtonId)->setAutoRepeat(true); |
|
163 mSctButtons.at(HbDelButtonId)->setProperty(HbStyleRulesCacheId::hbStyleRulesForNodeCache, HbSctPortraitButtonIconLayout); |
|
164 |
|
165 mSctButtons.at(HbAbcButtonId)->setIcon(HbIcon("qtg_mono_alpha_mode")); |
|
166 mSctButtons.at(HbAbcButtonId)->setObjectName(HbAbcButtonObjName); |
|
167 mSctButtons.at(HbAbcButtonId)->setObjectName(HbAbcButtonObjName); |
|
168 mSctButtons.at(HbAbcButtonId)->setProperty(HbStyleRulesCacheId::hbStyleRulesForNodeCache, HbSctPortraitButtonIconLayout); |
|
169 |
|
170 mSctButtons.at(HbSpecialCharacterButtonId)->setIcon(HbIcon("qtg_mono_special_characters_itut")); |
|
171 mSctButtons.at(HbSpecialCharacterButtonId)->setObjectName(HbSpecialCharacterButtonObjName); |
|
172 mSctButtons.at(HbSpecialCharacterButtonId)->setProperty(HbStyleRulesCacheId::hbStyleRulesForNodeCache, HbSctPortraitButtonIconLayout); |
|
173 |
|
174 mSctButtons.at(HbSmileyButtonId)->setIcon(HbIcon("qtg_mono_smiley")); |
|
175 mSctButtons.at(HbSmileyButtonId)->setObjectName(HbSmileyButtonObjName); |
|
176 mSctButtons.at(HbSmileyButtonId)->setProperty(HbStyleRulesCacheId::hbStyleRulesForNodeCache, HbSctPortraitButtonIconLayout); |
|
177 |
|
178 if (mApplicationButton) { |
|
179 mApplicationButton->setObjectName(HbCustomButtonObjName + QString::number(1)); |
|
180 } |
|
181 |
|
182 for (int i = HbSctGridColumns-1; i < HbNumSctButtons-1; i+=HbSctGridColumns) { |
|
183 mSctButtons.at(i)->setButtonType(HbTouchKeypadButton::HbTouchButtonFunction); |
|
184 mSctButtons.at(i)->setBackgroundAttributes(HbTouchKeypadButton::HbTouchButtonReleased); |
|
185 } |
|
186 } |
|
187 |
|
188 /* |
|
189 apply editor constraints on buttons |
|
190 */ |
|
191 void HbInputSctPortraitPrivate::applyEditorConstraints() |
|
192 { |
|
193 HbInputFocusObject *focusedObject = 0; |
|
194 if (mOwner) { |
|
195 focusedObject = mOwner->focusObject(); |
|
196 } |
|
197 |
|
198 if(!focusedObject || isKeyboardDimmed()) { |
|
199 // dont need to apply constraints when keypad is dimmed. |
|
200 // applyEditorConstraints will be called from setKeyboardDimmed(false) |
|
201 return; |
|
202 } |
|
203 |
|
204 for (int i=0; i < mSctButtons.size()-1; ++i) { |
|
205 if (i%HbSctGridColumns != HbSctGridColumns-1) { |
|
206 QString buttonText = mSctButtons.at(i)->text(); |
|
207 if (buttonText.isEmpty() || !focusedObject->characterAllowedInEditor(buttonText[0])) { |
|
208 // if the data mapped to button is empty or the data mapped is not allowed to the editor |
|
209 mSctButtons.at(i)->setFade(true); |
|
210 } else { |
|
211 mSctButtons.at(i)->setFade(false); |
|
212 } |
|
213 } |
|
214 } |
|
215 |
|
216 mSctButtons.at(HbSmileyButtonId)->setFade(focusedObject->editorInterface().isNumericEditor() |
|
217 || !focusedObject->editorInterface().editorClass() == HbInputEditorClassUnknown |
|
218 || !isSmileysEnabled()); |
|
219 } |
|
220 |
|
221 void HbInputSctPortraitPrivate::setSctButtons(const QString &aCharSet) |
|
222 { |
|
223 Q_Q(HbInputSctPortrait); |
|
224 q->setupToolCluster(); |
|
225 |
|
226 int i = 0; |
|
227 int j = 0; |
|
228 for (; i < mSctButtons.size()-1 && (j+mStartIndex) < aCharSet.size(); ++i) { |
|
229 if (i%HbSctGridColumns != HbSctGridColumns-1) { |
|
230 const QChar &character = aCharSet[j+mStartIndex]; |
|
231 mSctButtons.at(i)->setText(character); |
|
232 mSctButtons.at(i)->setObjectName("Sct portrait " + QString(character)); |
|
233 j++; |
|
234 } |
|
235 } |
|
236 |
|
237 for (; i < mSctButtons.size()-1; ++i) { |
|
238 if (i%HbSctGridColumns != HbSctGridColumns-1) { |
|
239 mSctButtons.at(i)->setText(""); |
|
240 } |
|
241 } |
|
242 |
|
243 mCurrentPage = mStartIndex/(HbNumSctButtons-HbSctGridRows); |
|
244 mStartIndex += j; |
|
245 if (mStartIndex == aCharSet.size()) { |
|
246 // We have reached end of special character list, reset the mStartIndex to 0 |
|
247 // so that we show first set of special characters next time |
|
248 mStartIndex = 0; |
|
249 } |
|
250 applyEditorConstraints(); |
|
251 } |
|
252 |
|
253 |
|
254 void HbInputSctPortraitPrivate::setActiveView(HbInputVkbWidget::HbSctView view) |
|
255 { |
|
256 Q_Q(HbInputSctPortrait); |
|
257 mActiveView = view; |
|
258 |
|
259 switch (view) { |
|
260 case HbInputSctPortrait::HbSctViewSpecialCharacter: |
|
261 setSctButtons(mSpecialCharacterSet); |
|
262 mSctButtons.at(HbSpecialCharacterButtonId)->setLatch(true); |
|
263 mSctButtons.at(HbSmileyButtonId)->setLatch(false); |
|
264 break; |
|
265 |
|
266 case HbInputSctPortrait::HbSctViewSmiley: |
|
267 q->showSmileyPicker(HbSctGridRows, HbSctGridColumns); |
|
268 break; |
|
269 |
|
270 default: |
|
271 break; |
|
272 }; |
|
273 } |
|
274 |
|
275 /* |
|
276 Gets the special character sets from set keymapping. |
|
277 */ |
|
278 void HbInputSctPortraitPrivate::getSpecialCharacters() |
|
279 { |
|
280 mSpecialCharacterSet.clear(); |
|
281 if (mKeymap) { |
|
282 const HbKeyboardMap* keyboardMap = mKeymap->keyboard(HbKeyboardSctPortrait); |
|
283 if (keyboardMap) { |
|
284 foreach (const HbMappedKey* mappedKey, keyboardMap->keys) { |
|
285 mSpecialCharacterSet.append(mappedKey->characters(HbModifierNone)); |
|
286 } |
|
287 } |
|
288 } |
|
289 } |
|
290 |
|
291 |
|
292 |
|
293 int HbInputSctPortraitPrivate::keyCode(int buttonId) |
|
294 { |
|
295 int code = 0; |
|
296 if (buttonId == HbDelButtonId) { |
|
297 code = Qt::Key_Delete; |
|
298 } else if (buttonId == HbAbcButtonId) { |
|
299 code = Qt::Key_Asterisk; |
|
300 } else if (buttonId == HbSpecialCharacterButtonId) { |
|
301 code = Qt::Key_F1; |
|
302 } else if (buttonId == HbSmileyButtonId) { |
|
303 code = Qt::Key_F2; |
|
304 } |
|
305 return code; |
|
306 } |
|
307 |
|
308 /*! |
|
309 |
|
310 */ |
|
311 void HbInputSctPortraitPrivate::handleStandardButtonPress(int buttonId) |
|
312 { |
|
313 Q_UNUSED(buttonId); |
|
314 //dont need to do anything here |
|
315 |
|
316 } |
|
317 |
|
318 /* |
|
319 Handles button clicks. |
|
320 */ |
|
321 void HbInputSctPortraitPrivate::handleStandardButtonClick(int buttonId) |
|
322 { |
|
323 Q_Q(HbInputSctPortrait); |
|
324 |
|
325 if (buttonId >= 0 && buttonId < HbNumSctButtons && |
|
326 buttonId%HbSctGridColumns != HbSctGridColumns-1) { |
|
327 QString buttonText = mSctButtons.at(buttonId)->text(); |
|
328 |
|
329 if (buttonText.length() > 0) { |
|
330 emit q->sctCharacterSelected(buttonText.at(0)); |
|
331 } |
|
332 } else if (keyCode(buttonId) == Qt::Key_F1) { |
|
333 if(mActiveView != HbInputVkbWidget::HbSctViewSpecialCharacter) { |
|
334 mStartIndex = 0; |
|
335 } |
|
336 setActiveView(HbInputVkbWidget::HbSctViewSpecialCharacter); |
|
337 } else if (keyCode(buttonId) == Qt::Key_F2) { |
|
338 if(mActiveView != HbInputVkbWidget::HbSctViewSmiley) { |
|
339 mStartIndex = 0; |
|
340 } |
|
341 // dont show the smiley picker, if the button is inactive |
|
342 if (!mSctButtons.at(HbSmileyButtonId)->isFaded()) { |
|
343 setActiveView(HbInputSctPortrait::HbSctViewSmiley); |
|
344 } |
|
345 } else { |
|
346 // we should pass both the press and release event. As mode handlers work according to |
|
347 // the press and release event. |
|
348 QKeyEvent pressEvent(QEvent::KeyPress, keyCode(buttonId), Qt::NoModifier); |
|
349 if (mOwner) { |
|
350 mOwner->filterEvent(&pressEvent); |
|
351 QKeyEvent releaseEvent(QEvent::KeyRelease, keyCode(buttonId), Qt::NoModifier); |
|
352 mOwner->filterEvent(&releaseEvent); |
|
353 } |
|
354 } |
|
355 } |
|
356 |
|
357 /* |
|
358 Handles the sct keypad button releas. Internally it hides character preview pane |
|
359 if visible. |
|
360 */ |
|
361 void HbInputSctPortraitPrivate::handleStandardButtonRelease(int buttonId) |
|
362 { |
|
363 Q_UNUSED(buttonId); |
|
364 //dont need to do anything here |
|
365 } |
|
366 |
|
367 /*! |
|
368 Handles virtual key clicks |
|
369 */ |
|
370 void HbInputSctPortraitPrivate::_q_mappedKeyClick(int buttonid) |
|
371 { |
|
372 handleStandardButtonClick(buttonid); |
|
373 } |
|
374 /// @endcond |
|
375 |
|
376 /*! |
|
377 Constructs the object. |
|
378 */ |
|
379 HbInputSctPortrait::HbInputSctPortrait(HbInputMethod* owner, const HbKeymap *keymap, QGraphicsItem* parent) |
|
380 : HbInputVkbWidget(*new HbInputSctPortraitPrivate, parent) |
|
381 { |
|
382 Q_D(HbInputSctPortrait); |
|
383 d->q_ptr = this; |
|
384 d->mOwner = owner; |
|
385 |
|
386 d->mButtonLayout = new QGraphicsGridLayout(); |
|
387 d->mButtonLayout->setSpacing(0.0); |
|
388 d->mButtonLayout->setContentsMargins(0.0, 0.0, 0.0, 0.0); |
|
389 |
|
390 d->mClickMapper = new QSignalMapper(this); |
|
391 |
|
392 // create buttons. |
|
393 d->createSctButtons(); |
|
394 |
|
395 // connect mappers. |
|
396 connect(d->mPressMapper, SIGNAL(mapped(int)), this, SLOT(mappedKeyPress(int))); |
|
397 connect(d->mReleaseMapper, SIGNAL(mapped(int)), this, SLOT(mappedKeyRelease(int))); |
|
398 connect(d->mClickMapper, SIGNAL(mapped(int)), this, SLOT(_q_mappedKeyClick(int))); |
|
399 |
|
400 connect(this, SIGNAL(flickEvent(HbInputVkbWidget::HbFlickDirection)), this, SLOT(flickTriggered(HbInputVkbWidget::HbFlickDirection))); |
|
401 |
|
402 // now set the keymap data. |
|
403 setKeymap(keymap); |
|
404 } |
|
405 |
|
406 HbInputSctPortrait::HbInputSctPortrait(HbInputSctPortraitPrivate &dd, QGraphicsItem* parent) |
|
407 : HbInputVkbWidget(dd, parent) |
|
408 { |
|
409 } |
|
410 |
|
411 /*! |
|
412 Destructs the object. |
|
413 */ |
|
414 HbInputSctPortrait::~HbInputSctPortrait() |
|
415 { |
|
416 } |
|
417 |
|
418 /*! |
|
419 Returns keyboard type. |
|
420 */ |
|
421 HbKeyboardType HbInputSctPortrait::keyboardType() const |
|
422 { |
|
423 return HbKeyboardSctPortrait; |
|
424 } |
|
425 |
|
426 void HbInputSctPortrait::setSct(HbSctView view) |
|
427 { |
|
428 Q_D(HbInputSctPortrait); |
|
429 |
|
430 d->initialize(); |
|
431 |
|
432 d->mStartIndex = 0; |
|
433 d->setActiveView(view); |
|
434 } |
|
435 |
|
436 /*! |
|
437 This function should be called when ever there is a language change. |
|
438 This gets the accented and special characters from the given keymappings. |
|
439 */ |
|
440 void HbInputSctPortrait::setKeymap(const HbKeymap* keymap) |
|
441 { |
|
442 Q_D(HbInputSctPortrait); |
|
443 HbInputVkbWidget::setKeymap(keymap); |
|
444 d->getSpecialCharacters(); |
|
445 } |
|
446 |
|
447 QGraphicsLayout *HbInputSctPortrait::keypadLayout() |
|
448 { |
|
449 Q_D(HbInputSctPortrait); |
|
450 return d->mButtonLayout; |
|
451 } |
|
452 |
|
453 void HbInputSctPortrait::aboutToOpen(HbVkbHost *host) |
|
454 { |
|
455 Q_D(HbInputSctPortrait); |
|
456 |
|
457 HbInputVkbWidget::aboutToOpen(host); |
|
458 |
|
459 QSizeF keypadSize = keypadButtonAreaSize(); |
|
460 keypadSize.setWidth(keypadSize.width() / (qreal)HbSctGridColumns); |
|
461 keypadSize.setHeight(keypadSize.height() / (qreal)HbSctGridRows); |
|
462 d->setLayoutDimensions(keypadSize); |
|
463 } |
|
464 |
|
465 void HbInputSctPortrait::flickTriggered(HbInputVkbWidget::HbFlickDirection direction) |
|
466 { |
|
467 Q_D(HbInputSctPortrait); |
|
468 |
|
469 d->initialize(); |
|
470 int iNumSctButtons = HbNumSctButtons - HbSctGridRows; |
|
471 if(direction == HbInputVkbWidget::HbFlickDirectionLeft) { |
|
472 d->mCurrentPage--; |
|
473 if(d->mCurrentPage<0) { |
|
474 if (d->mSpecialCharacterSet.size()) { |
|
475 d->mCurrentPage = (int)ceil((float)d->mSpecialCharacterSet.size()/iNumSctButtons)-1; |
|
476 } else { |
|
477 d->mCurrentPage = 0; |
|
478 } |
|
479 } |
|
480 d->mStartIndex = d->mCurrentPage*iNumSctButtons; |
|
481 } |
|
482 d->setActiveView(HbInputSctPortrait::HbSctViewSpecialCharacter); |
|
483 } |
|
484 |
|
485 #include "moc_hbinputsctportrait.cpp" |
|
486 |
|
487 // End of file |