|
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 HbWidgets 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 // |
|
27 // W A R N I N G |
|
28 // ------------- |
|
29 // |
|
30 // This file is not part of the Hb API. It exists purely as an |
|
31 // implementation detail. This file may change from version to |
|
32 // version without notice, or even be removed. |
|
33 // |
|
34 // We mean it. |
|
35 // |
|
36 |
|
37 #include "hbabstractedit_p.h" |
|
38 #include "hbabstractedit.h" |
|
39 #include "hbstyleoption.h" |
|
40 #include "hbscrollarea.h" |
|
41 #include "hbvalidator.h" |
|
42 #include "hbmeshlayout_p.h" |
|
43 #include "hbmenu.h" |
|
44 #include "hbselectioncontrol_p.h" |
|
45 #include "hbcolorscheme.h" |
|
46 #include "hbsmileyengine.h" |
|
47 #include "hbtextmeasurementutility_p.h" |
|
48 #include "hbfeaturemanager_p.h" |
|
49 #include "hbinputeditorinterface.h" |
|
50 #include "hbinputvkbhost.h" |
|
51 |
|
52 #include <QValidator> |
|
53 #include <QTextLayout> |
|
54 #include <QTextBlock> |
|
55 #include <QTextList> |
|
56 #include <QTextTable> |
|
57 #include <QApplication> |
|
58 #include <QGraphicsSceneMouseEvent> |
|
59 #include <QPainter> |
|
60 #include <QtDebug> |
|
61 #include <QClipboard> |
|
62 #include <QInputContext> |
|
63 #include <QRegExp> |
|
64 |
|
65 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position) |
|
66 { |
|
67 return frame->firstPosition() < position; |
|
68 } |
|
69 |
|
70 static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame) |
|
71 { |
|
72 return position < frame->lastPosition(); |
|
73 } |
|
74 |
|
75 static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor) |
|
76 { |
|
77 QRectF r; |
|
78 QTextFrame *frame = cursor.currentFrame(); |
|
79 const QList<QTextFrame *> children = frame->childFrames(); |
|
80 |
|
81 const QList<QTextFrame *>::ConstIterator firstFrame = qLowerBound(children.constBegin(), children.constEnd(), |
|
82 cursor.selectionStart(), firstFramePosLessThanCursorPos); |
|
83 const QList<QTextFrame *>::ConstIterator lastFrame = qUpperBound(children.constBegin(), children.constEnd(), |
|
84 cursor.selectionEnd(), cursorPosLessThanLastFramePos); |
|
85 for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) { |
|
86 if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow) |
|
87 r |= frame->document()->documentLayout()->frameBoundingRect(*it); |
|
88 } |
|
89 return r; |
|
90 } |
|
91 |
|
92 class HbEditItem : public HbWidget |
|
93 { |
|
94 public: |
|
95 |
|
96 HbEditItem(HbAbstractEdit *parent) : HbWidget(parent), edit(parent) |
|
97 { |
|
98 }; |
|
99 |
|
100 virtual ~HbEditItem() {}; |
|
101 |
|
102 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) |
|
103 { |
|
104 Q_UNUSED(widget) |
|
105 |
|
106 painter->save(); |
|
107 #ifdef HB_DEBUG_EDITOR_DRAW_RECTS |
|
108 painter->setPen(Qt::yellow); |
|
109 painter->drawRect(boundingRect().adjusted(3,3,-3,-3)); |
|
110 #endif |
|
111 if ( option) { |
|
112 edit->drawContents(painter, *option); |
|
113 } |
|
114 |
|
115 painter->restore(); |
|
116 }; |
|
117 |
|
118 HbAbstractEdit *edit; |
|
119 }; |
|
120 |
|
121 static QTextLine currentTextLine(const QTextCursor &cursor) |
|
122 { |
|
123 const QTextBlock block = cursor.block(); |
|
124 if (!block.isValid()) |
|
125 return QTextLine(); |
|
126 |
|
127 const QTextLayout *layout = block.layout(); |
|
128 if (!layout) |
|
129 return QTextLine(); |
|
130 |
|
131 const int relativePos = cursor.position() - block.position(); |
|
132 return layout->lineForTextPosition(relativePos); |
|
133 } |
|
134 |
|
135 |
|
136 /* |
|
137 * HbEditScrollArea |
|
138 */ |
|
139 |
|
140 HbEditScrollArea::HbEditScrollArea(HbAbstractEdit* edit, QGraphicsItem* parent) |
|
141 : HbScrollArea(parent), |
|
142 mEdit(edit) |
|
143 { |
|
144 setFlag(QGraphicsItem::ItemIsFocusable, false); |
|
145 } |
|
146 |
|
147 void HbEditScrollArea::updateScrollMetrics() { |
|
148 Q_D(HbScrollArea); |
|
149 d->updateScrollMetrics(); |
|
150 } |
|
151 |
|
152 void HbEditScrollArea::resizeEvent(QGraphicsSceneResizeEvent *event) { |
|
153 HbScrollArea::resizeEvent(event); |
|
154 emit scrollAreaSizeChanged(); |
|
155 } |
|
156 |
|
157 #ifdef HB_DEBUG_EDITOR_DRAW_RECTS |
|
158 void HbEditScrollArea::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) |
|
159 { |
|
160 Q_UNUSED(widget); |
|
161 Q_UNUSED(option); |
|
162 |
|
163 painter->save(); |
|
164 painter->setPen(Qt::red); |
|
165 painter->drawRect(boundingRect().adjusted(1,1,-1,-1)); |
|
166 |
|
167 painter->restore(); |
|
168 } |
|
169 #endif//HB_DEBUG_EDITOR_DRAW_RECTS |
|
170 |
|
171 |
|
172 void HbEditScrollArea::longPressGesture(const QPointF &point) |
|
173 { |
|
174 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
175 HbAbstractEditPrivate::d_ptr(mEdit)->longPressGesture(point); |
|
176 } |
|
177 |
|
178 void HbEditScrollArea::upGesture(int value){ |
|
179 HbScrollArea::upGesture(value); |
|
180 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
181 } |
|
182 |
|
183 void HbEditScrollArea::downGesture(int value){ |
|
184 HbScrollArea::downGesture(value); |
|
185 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
186 } |
|
187 |
|
188 void HbEditScrollArea::leftGesture(int value){ |
|
189 HbScrollArea::leftGesture(value); |
|
190 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
191 } |
|
192 |
|
193 void HbEditScrollArea::rightGesture(int value){ |
|
194 HbScrollArea::rightGesture(value); |
|
195 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
196 } |
|
197 |
|
198 void HbEditScrollArea::panGesture(const QPointF &point){ |
|
199 HbScrollArea::panGesture(point); |
|
200 HbAbstractEditPrivate::d_ptr(mEdit)->gestureReceived(); |
|
201 } |
|
202 |
|
203 QStringList HbAbstractEditMimeData::formats() const |
|
204 { |
|
205 if (!fragment.isEmpty()) |
|
206 return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html"); |
|
207 else |
|
208 return QMimeData::formats(); |
|
209 } |
|
210 |
|
211 QVariant HbAbstractEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const |
|
212 { |
|
213 if (!fragment.isEmpty()) |
|
214 setup(); |
|
215 return QMimeData::retrieveData(mimeType, type); |
|
216 } |
|
217 |
|
218 void HbAbstractEditMimeData::setup() const |
|
219 { |
|
220 HbAbstractEditMimeData *that = const_cast<HbAbstractEditMimeData *>(this); |
|
221 #ifndef QT_NO_TEXTHTMLPARSER |
|
222 that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8()); |
|
223 #endif |
|
224 that->setText(fragment.toPlainText()); |
|
225 fragment = QTextDocumentFragment(); |
|
226 } |
|
227 |
|
228 HbAbstractEditPrivate::HbAbstractEditPrivate () : |
|
229 HbWidgetPrivate(), |
|
230 doc(0), |
|
231 validator(0), |
|
232 imEditInProgress(false), |
|
233 imPosition(0), |
|
234 imAdded(0), |
|
235 imRemoved(0), |
|
236 interactionFlags(Qt::TextEditorInteraction), |
|
237 mousePressPos(-1, -1), |
|
238 cursorOn(false), |
|
239 preeditCursor(0), |
|
240 preeditCursorVisible(true), |
|
241 apiCursorVisible(true), |
|
242 canvas(0), |
|
243 scrollArea(0), |
|
244 scrollable(false), |
|
245 hadSelectionOnMousePress(false), |
|
246 selectionControl(0), |
|
247 acceptSignalContentsChange(true), |
|
248 acceptSignalContentsChanged(true), |
|
249 validRevision(0), |
|
250 wasGesture(false), |
|
251 smileysEnabled(false), |
|
252 smileyEngine(0), |
|
253 formatDialog(0) |
|
254 { |
|
255 } |
|
256 |
|
257 HbAbstractEditPrivate::~HbAbstractEditPrivate () |
|
258 { |
|
259 } |
|
260 |
|
261 void HbAbstractEditPrivate::init() |
|
262 { |
|
263 Q_Q(HbAbstractEdit); |
|
264 |
|
265 canvas = new HbEditItem(q); |
|
266 |
|
267 setContent(Qt::RichText, QString()); |
|
268 |
|
269 QTextOption textOption = doc->defaultTextOption(); |
|
270 textOption.setTextDirection(q->layoutDirection()); |
|
271 doc->setDefaultTextOption(textOption); |
|
272 doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable); |
|
273 |
|
274 updatePaletteFromTheme(); |
|
275 |
|
276 scrollArea = new HbEditScrollArea(q, q); |
|
277 //scrollArea->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); |
|
278 scrollArea->setClampingStyle(HbScrollArea::StrictClamping); |
|
279 scrollArea->setFrictionEnabled(true); |
|
280 scrollArea->setScrollDirections(Qt::Vertical); |
|
281 scrollArea->setVerticalScrollBarPolicy(HbScrollArea::ScrollBarAlwaysOff); |
|
282 scrollArea->setContentWidget(canvas); |
|
283 scrollArea->installEventFilter(q); |
|
284 scrollArea->setLongPressEnabled(true); |
|
285 scrollArea->setFlag(QGraphicsItem::ItemIsFocusable, false); |
|
286 QObject::connect(scrollArea, SIGNAL(scrollAreaSizeChanged()), q, SLOT(updatePrimitives())); |
|
287 QObject::connect(q, SIGNAL(selectionChanged(QTextCursor,QTextCursor)), q, SLOT(_q_selectionChanged())); |
|
288 HbStyle::setItemName(scrollArea, QString("text")); |
|
289 |
|
290 // These are the default values which are then overridden in subclasses |
|
291 // and when different options are enabled. |
|
292 q->setFlag(QGraphicsItem::ItemIsFocusable); |
|
293 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
|
294 q->setFlag(QGraphicsItem::ItemSendsScenePositionChanges); |
|
295 q->setFocusPolicy(Qt::StrongFocus); |
|
296 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
297 |
|
298 contextMenuShownOn = Hb::ShowTextContextMenuOnSelectionClicked | Hb::ShowTextContextMenuOnLongPress; |
|
299 |
|
300 } |
|
301 |
|
302 void HbAbstractEditPrivate::updatePaletteFromTheme() |
|
303 { |
|
304 Q_Q(HbAbstractEdit); |
|
305 |
|
306 // TODO: remove once these color dissapear from hbcolorgroup.css |
|
307 QColor textColor = HbColorScheme::color("qtc_editor_normal"); |
|
308 QColor selectedColor = HbColorScheme::color("qtc_editor_selected"); |
|
309 QColor selectedBackground = HbColorScheme::color("qtc_editor_marker_normal"); |
|
310 QPalette pal = q->palette(); |
|
311 |
|
312 if (textColor.isValid()) { |
|
313 pal.setColor(QPalette::Text, textColor); |
|
314 } |
|
315 |
|
316 if (selectedColor.isValid()) { |
|
317 pal.setColor(QPalette::HighlightedText, selectedColor); |
|
318 } |
|
319 |
|
320 if (selectedBackground.isValid()) { |
|
321 pal.setColor(QPalette::Highlight, selectedBackground); |
|
322 } |
|
323 q->setPalette(pal); |
|
324 |
|
325 |
|
326 // The link color is used from application's palette |
|
327 QColor linkColor = HbColorScheme::color("qtc_view_link_normal"); |
|
328 QColor linkVisitedColor = HbColorScheme::color("qtc_view_visited_normal"); |
|
329 QPalette appPal = qApp->palette(); |
|
330 if (linkColor.isValid()) { |
|
331 appPal.setColor(QPalette::Link, linkColor); |
|
332 } |
|
333 |
|
334 if (linkVisitedColor.isValid()) { |
|
335 appPal.setColor(QPalette::LinkVisited, linkVisitedColor); |
|
336 } |
|
337 qApp->setPalette(appPal); |
|
338 |
|
339 } |
|
340 |
|
341 void HbAbstractEditPrivate::setContent(Qt::TextFormat format, const QString &text) |
|
342 { |
|
343 Q_Q(HbAbstractEdit); |
|
344 |
|
345 // for localization text support |
|
346 QString txt( text ); |
|
347 #ifdef HB_TEXT_MEASUREMENT_UTILITY |
|
348 if ( HbFeatureManager::instance()->featureStatus( HbFeatureManager::TextMeasurement ) ) { |
|
349 if (text.endsWith(QChar(LOC_TEST_END))) { |
|
350 int index = text.indexOf(QChar(LOC_TEST_START)); |
|
351 q->setProperty( HbTextMeasurementUtilityNameSpace::textIdPropertyName, |
|
352 text.mid(index + 1, text.indexOf(QChar(LOC_TEST_END)) - index - 1) ); |
|
353 txt = text.left(index); |
|
354 } |
|
355 } |
|
356 #endif |
|
357 |
|
358 // for use when called from setPlainText. we may want to re-use the currently |
|
359 // set char format then. |
|
360 const QTextCharFormat charFormatForInsertion = cursor.charFormat(); |
|
361 |
|
362 const QTextCursor oldSelection = cursor; |
|
363 |
|
364 bool clearDocument = true; |
|
365 if (!doc) { |
|
366 connectToNewDocument(new QTextDocument(q)); |
|
367 } |
|
368 |
|
369 bool previousUndoRedoState = doc->isUndoRedoEnabled(); |
|
370 doc->setUndoRedoEnabled(false); |
|
371 |
|
372 // avoid multiple textChanged() signals being emitted |
|
373 acceptSignalContentsChanged = false; |
|
374 |
|
375 if (!txt.isEmpty()) { |
|
376 // clear 'our' cursor for insertion to prevent |
|
377 // the emission of the cursorPositionChanged() signal. |
|
378 // instead we emit it only once at the end instead of |
|
379 // at the end of the document after loading and when |
|
380 // positioning the cursor again to the start of the |
|
381 // document. |
|
382 cursor = QTextCursor(); |
|
383 |
|
384 if (format == Qt::PlainText) { |
|
385 QTextCursor formatCursor(doc); |
|
386 formatCursor.beginEditBlock(); |
|
387 // put the setPlainText and the setCharFormat into one edit block, |
|
388 // so that the syntax highlight triggers only /once/ for the entire |
|
389 // document, not twice. |
|
390 doc->setPlainText(txt); |
|
391 formatCursor.select(QTextCursor::Document); |
|
392 formatCursor.setCharFormat(charFormatForInsertion); |
|
393 formatCursor.endEditBlock(); |
|
394 } else { |
|
395 #ifndef QT_NO_TEXTHTMLPARSER |
|
396 doc->setHtml(txt); |
|
397 #else |
|
398 doc->setPlainText(txt); |
|
399 #endif |
|
400 } |
|
401 cursor = QTextCursor(doc); |
|
402 } else if (clearDocument) { |
|
403 doc->clear(); |
|
404 } |
|
405 cursor.setCharFormat(charFormatForInsertion); |
|
406 |
|
407 doc->setUndoRedoEnabled(previousUndoRedoState); |
|
408 |
|
409 acceptSignalContentsChanged = true; |
|
410 |
|
411 updateCurrentCharFormat(); |
|
412 |
|
413 emit q->contentsChanged(); |
|
414 |
|
415 cursorChanged(HbValidator::CursorChangeFromContentSet); |
|
416 |
|
417 doc->setModified(false); |
|
418 |
|
419 ensureCursorVisible(); |
|
420 |
|
421 smileyEngineInstance()->setDocument(doc); |
|
422 if(q->isSmileysEnabled()) { |
|
423 smileyEngineInstance()->insertSmileys(); |
|
424 } |
|
425 } |
|
426 |
|
427 bool HbAbstractEditPrivate::setFocusToAnchor(const QTextCursor &newCursor) |
|
428 { |
|
429 Q_UNUSED(newCursor); |
|
430 return false; |
|
431 } |
|
432 bool HbAbstractEditPrivate::setFocusToNextOrPreviousAnchor(bool next) |
|
433 { |
|
434 Q_UNUSED(next); |
|
435 return false; |
|
436 } |
|
437 |
|
438 bool HbAbstractEditPrivate::findNextPrevAnchor(const QTextCursor& from, bool next, QTextCursor& newAnchor) |
|
439 { |
|
440 Q_UNUSED(from); |
|
441 Q_UNUSED(next); |
|
442 Q_UNUSED(newAnchor); |
|
443 return false; |
|
444 } |
|
445 |
|
446 void HbAbstractEditPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode) |
|
447 { |
|
448 cursor.setPosition(pos, mode); |
|
449 |
|
450 cursorChanged(HbValidator::CursorChangeFromMouse); |
|
451 } |
|
452 |
|
453 bool HbAbstractEditPrivate::cursorMoveKeyEvent(QKeyEvent *e) |
|
454 { |
|
455 #ifdef QT_NO_SHORTCUT |
|
456 Q_UNUSED(e); |
|
457 #endif |
|
458 |
|
459 if (cursor.isNull()) |
|
460 return false; |
|
461 |
|
462 QTextCursor::MoveMode mode = QTextCursor::MoveAnchor; |
|
463 QTextCursor::MoveOperation op = QTextCursor::NoMove; |
|
464 |
|
465 if (false) { |
|
466 } |
|
467 #ifndef QT_NO_SHORTCUT |
|
468 if (e == QKeySequence::MoveToNextChar) { |
|
469 op = QTextCursor::Right; |
|
470 } |
|
471 else if (e == QKeySequence::MoveToPreviousChar) { |
|
472 op = QTextCursor::Left; |
|
473 } |
|
474 else if (e == QKeySequence::SelectNextChar) { |
|
475 op = QTextCursor::Right; |
|
476 mode = QTextCursor::KeepAnchor; |
|
477 } |
|
478 else if (e == QKeySequence::SelectPreviousChar) { |
|
479 op = QTextCursor::Left; |
|
480 mode = QTextCursor::KeepAnchor; |
|
481 } |
|
482 else if (e == QKeySequence::SelectNextWord) { |
|
483 op = QTextCursor::WordRight; |
|
484 mode = QTextCursor::KeepAnchor; |
|
485 } |
|
486 else if (e == QKeySequence::SelectPreviousWord) { |
|
487 op = QTextCursor::WordLeft; |
|
488 mode = QTextCursor::KeepAnchor; |
|
489 } |
|
490 else if (e == QKeySequence::SelectStartOfLine) { |
|
491 op = QTextCursor::StartOfLine; |
|
492 mode = QTextCursor::KeepAnchor; |
|
493 } |
|
494 else if (e == QKeySequence::SelectEndOfLine) { |
|
495 op = QTextCursor::EndOfLine; |
|
496 mode = QTextCursor::KeepAnchor; |
|
497 } |
|
498 else if (e == QKeySequence::SelectStartOfBlock) { |
|
499 op = QTextCursor::StartOfBlock; |
|
500 mode = QTextCursor::KeepAnchor; |
|
501 } |
|
502 else if (e == QKeySequence::SelectEndOfBlock) { |
|
503 op = QTextCursor::EndOfBlock; |
|
504 mode = QTextCursor::KeepAnchor; |
|
505 } |
|
506 else if (e == QKeySequence::SelectStartOfDocument) { |
|
507 op = QTextCursor::Start; |
|
508 mode = QTextCursor::KeepAnchor; |
|
509 } |
|
510 else if (e == QKeySequence::SelectEndOfDocument) { |
|
511 op = QTextCursor::End; |
|
512 mode = QTextCursor::KeepAnchor; |
|
513 } |
|
514 else if (e == QKeySequence::SelectPreviousLine) { |
|
515 op = QTextCursor::Up; |
|
516 mode = QTextCursor::KeepAnchor; |
|
517 } |
|
518 else if (e == QKeySequence::SelectNextLine) { |
|
519 op = QTextCursor::Down; |
|
520 mode = QTextCursor::KeepAnchor; |
|
521 { |
|
522 QTextBlock block = cursor.block(); |
|
523 QTextLine line = currentTextLine(cursor); |
|
524 if (!block.next().isValid() |
|
525 && line.isValid() |
|
526 && line.lineNumber() == block.layout()->lineCount() - 1) |
|
527 op = QTextCursor::End; |
|
528 } |
|
529 } |
|
530 else if (e == QKeySequence::MoveToNextWord) { |
|
531 op = QTextCursor::WordRight; |
|
532 } |
|
533 else if (e == QKeySequence::MoveToPreviousWord) { |
|
534 op = QTextCursor::WordLeft; |
|
535 } |
|
536 else if (e == QKeySequence::MoveToEndOfBlock) { |
|
537 op = QTextCursor::EndOfBlock; |
|
538 } |
|
539 else if (e == QKeySequence::MoveToStartOfBlock) { |
|
540 op = QTextCursor::StartOfBlock; |
|
541 } |
|
542 else if (e == QKeySequence::MoveToNextLine) { |
|
543 op = QTextCursor::Down; |
|
544 } |
|
545 else if (e == QKeySequence::MoveToPreviousLine) { |
|
546 op = QTextCursor::Up; |
|
547 } |
|
548 else if (e == QKeySequence::MoveToPreviousLine) { |
|
549 op = QTextCursor::Up; |
|
550 } |
|
551 else if (e == QKeySequence::MoveToStartOfLine) { |
|
552 op = QTextCursor::StartOfLine; |
|
553 } |
|
554 else if (e == QKeySequence::MoveToEndOfLine) { |
|
555 op = QTextCursor::EndOfLine; |
|
556 } |
|
557 else if (e == QKeySequence::MoveToStartOfDocument) { |
|
558 op = QTextCursor::Start; |
|
559 } |
|
560 else if (e == QKeySequence::MoveToEndOfDocument) { |
|
561 op = QTextCursor::End; |
|
562 } |
|
563 #endif // QT_NO_SHORTCUT |
|
564 else { |
|
565 return false; |
|
566 } |
|
567 |
|
568 const QTextCursor oldCursor = cursor; |
|
569 bool visualNavigation = cursor.visualNavigation(); |
|
570 cursor.setVisualNavigation(true); |
|
571 cursor.movePosition(op, mode); |
|
572 cursor.setVisualNavigation(visualNavigation); |
|
573 cursorChanged(HbValidator::CursorChangeFromOperation); |
|
574 repaintOldAndNewSelection(oldCursor); |
|
575 |
|
576 return true; |
|
577 } |
|
578 |
|
579 void HbAbstractEditPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection) |
|
580 { |
|
581 //Q_Q(HbAbstractEdit); |
|
582 if (cursor.hasSelection() |
|
583 && oldSelection.hasSelection() |
|
584 && cursor.currentFrame() == oldSelection.currentFrame() |
|
585 && !cursor.hasComplexSelection() |
|
586 && !oldSelection.hasComplexSelection() |
|
587 && cursor.anchor() == oldSelection.anchor() |
|
588 ) { |
|
589 QTextCursor differenceSelection(doc); |
|
590 differenceSelection.setPosition(oldSelection.position()); |
|
591 differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor); |
|
592 canvas->update(selectionRect(differenceSelection)); |
|
593 } else { |
|
594 if (!oldSelection.isNull()) |
|
595 canvas->update(selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection.position())); |
|
596 canvas->update(selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor.position())); |
|
597 } |
|
598 } |
|
599 |
|
600 void HbAbstractEditPrivate::updateCurrentCharFormat() |
|
601 { |
|
602 QTextCharFormat fmt = cursor.charFormat(); |
|
603 if (fmt == lastCharFormat) |
|
604 return; |
|
605 lastCharFormat = fmt; |
|
606 } |
|
607 |
|
608 QRectF HbAbstractEditPrivate::cursorRectPlusUnicodeDirectionMarkers(int position) const |
|
609 { |
|
610 return rectForPositionInCanvasCoords(position,QTextLine::Leading).adjusted(-4, 0, 4, 0); |
|
611 } |
|
612 |
|
613 void HbAbstractEditPrivate::setBlinkingCursorEnabled(bool enable) |
|
614 { |
|
615 Q_Q(HbAbstractEdit); |
|
616 |
|
617 if (enable && QApplication::cursorFlashTime() > 0) |
|
618 cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q); |
|
619 else |
|
620 cursorBlinkTimer.stop(); |
|
621 |
|
622 cursorOn = enable; |
|
623 |
|
624 repaintCursor(); |
|
625 } |
|
626 |
|
627 void HbAbstractEditPrivate::repaintCursor() |
|
628 { |
|
629 canvas->update(cursorRectPlusUnicodeDirectionMarkers(cursor.position())); |
|
630 } |
|
631 |
|
632 void HbAbstractEditPrivate::ensurePositionVisible(int position) |
|
633 { |
|
634 if (scrollArea && scrollable) { |
|
635 QRectF rect = rectForPositionInCanvasCoords(position, QTextLine::Leading); |
|
636 // TODO: it seems that scrollArea->ensureVisible() expects the point |
|
637 // in its content coordinates. Probably it should use viewport |
|
638 // coordinates i.e. its own item coordinate system |
|
639 //QRectF recScroll = canvas->mapToItem(scrollArea, rect).boundingRect(); |
|
640 scrollArea->ensureVisible(rect.center(), rect.width(), rect.height()/2); |
|
641 } |
|
642 } |
|
643 |
|
644 void HbAbstractEditPrivate::ensureCursorVisible() |
|
645 { |
|
646 ensurePositionVisible(cursor.position()); |
|
647 } |
|
648 |
|
649 void HbAbstractEditPrivate::setTextInteractionFlags(Qt::TextInteractionFlags flags) |
|
650 { |
|
651 Q_Q(HbAbstractEdit); |
|
652 |
|
653 if (flags == interactionFlags) |
|
654 return; |
|
655 interactionFlags = flags; |
|
656 |
|
657 if (q->hasFocus()) { |
|
658 setBlinkingCursorEnabled(flags & Qt::TextEditable); |
|
659 } |
|
660 } |
|
661 |
|
662 void HbAbstractEditPrivate::_q_updateRequest(QRectF rect) |
|
663 { |
|
664 canvas->update(rect); |
|
665 } |
|
666 |
|
667 void HbAbstractEditPrivate::_q_updateBlock(QTextBlock block) |
|
668 { |
|
669 Q_Q(HbAbstractEdit); |
|
670 _q_updateRequest(q->blockBoundingRect(block)); |
|
671 } |
|
672 |
|
673 void HbAbstractEditPrivate::_q_contentsChanged() |
|
674 { |
|
675 Q_Q(HbAbstractEdit); |
|
676 if(acceptSignalContentsChanged) { |
|
677 acceptSignalContentsChanged = false; // prevent recurence |
|
678 |
|
679 if(imPosition>=0) { |
|
680 validateAndCorrect(); |
|
681 } |
|
682 updateCurrentCharFormat(); |
|
683 |
|
684 emit q->contentsChanged(); |
|
685 |
|
686 acceptSignalContentsChanged = true; // end of prevent recurence |
|
687 } |
|
688 } |
|
689 |
|
690 void HbAbstractEditPrivate::_q_contentsChange(int position, int charsRemoved, int charsAdded) |
|
691 { |
|
692 if(acceptSignalContentsChange) { |
|
693 imPosition = position; |
|
694 imRemoved = charsRemoved; |
|
695 imAdded = charsAdded; |
|
696 } |
|
697 } |
|
698 |
|
699 void HbAbstractEditPrivate::_q_selectionChanged() |
|
700 { |
|
701 Q_Q(HbAbstractEdit); |
|
702 |
|
703 if (cursor.hasSelection()) { |
|
704 if (!selectionControl) { |
|
705 selectionControl = new HbSelectionControl(q); |
|
706 } |
|
707 selectionControl->showHandles(); |
|
708 q->update(); |
|
709 } else if (selectionControl){ |
|
710 selectionControl->hideHandles(); |
|
711 q->update(); |
|
712 } |
|
713 } |
|
714 |
|
715 void HbAbstractEditPrivate::validateAndCorrect() |
|
716 { |
|
717 if (validator && !imEditInProgress) { |
|
718 QValidator::State state = validateContent(imPosition, imRemoved, imAdded); |
|
719 if (state == QValidator::Invalid) { |
|
720 // workaround (undo doesn't decreases revision number in Qt 4.6 and it does in Qt 4.5.2): |
|
721 int undoCount = doc->revision() - validRevision; |
|
722 for( ;undoCount>0 && doc->isUndoRedoEnabled(); --undoCount) { |
|
723 doc->undo(); |
|
724 } |
|
725 validRevision = doc->revision(); |
|
726 } else if(state == QValidator::Acceptable) { |
|
727 doc->setModified(false); // store information to use undo in case Invalid values |
|
728 validRevision = doc->revision(); |
|
729 } |
|
730 } |
|
731 } |
|
732 |
|
733 QValidator::State HbAbstractEditPrivate::validateContent(int position, int charsRemoved, int charsAdded) |
|
734 { |
|
735 #ifdef HBVALIDATOR_DEBUG_ENABLE |
|
736 qDebug() << "HbAbstractEditPrivate::validateContent" |
|
737 << "Pos: " << position |
|
738 << "[-]: " << charsRemoved |
|
739 << "[+]: " << charsAdded; |
|
740 #endif |
|
741 // acceptSignalContentsChange = false; // not needed afrer corection |
|
742 QValidator::State state = validator->validateContent(cursor, position, charsRemoved, charsAdded); |
|
743 validator->updateTextCursor(cursor); |
|
744 // acceptSignalContentsChange = true; // not needed afrer corection |
|
745 #ifdef HBVALIDATOR_DEBUG_ENABLE |
|
746 qDebug() << "HbAbstractEditPrivate::validateContent" |
|
747 << ((state == QValidator::Acceptable) ? "Acceptable " : ((state == QValidator::Intermediate) ? "Intermediate" : "Invalid ")); |
|
748 #endif |
|
749 return state; |
|
750 } |
|
751 |
|
752 void HbAbstractEditPrivate::initValidator() |
|
753 { |
|
754 doc->setUndoRedoEnabled(true); |
|
755 doc->setPlainText(validator->defaultValue()); |
|
756 } |
|
757 |
|
758 void HbAbstractEditPrivate::cursorChanged(CursorChange origin) |
|
759 { |
|
760 Q_Q(HbAbstractEdit); |
|
761 if (previousCursorPosition != cursor.position() |
|
762 || previousCursorAnchor != cursor.anchor()) { |
|
763 |
|
764 if (validator && !imEditInProgress) { |
|
765 QTextCursor previousCursor(cursor); |
|
766 previousCursor.setPosition(previousCursorAnchor); |
|
767 previousCursor.setPosition(previousCursorPosition, QTextCursor::KeepAnchor); |
|
768 validator->validateCursorPosition(previousCursor, cursor, origin); |
|
769 |
|
770 if (previousCursorPosition == cursor.position() && previousCursorAnchor == cursor.anchor()) { |
|
771 // validator can cancel cursor position change |
|
772 return; |
|
773 } |
|
774 } // if validator |
|
775 |
|
776 // repaint the old cursor position |
|
777 canvas->update(cursorRectPlusUnicodeDirectionMarkers(previousCursorPosition)); |
|
778 |
|
779 emit q->cursorPositionChanged(previousCursorPosition, cursor.position()); |
|
780 previousCursorAnchor = cursor.anchor(); |
|
781 previousCursorPosition = cursor.position(); |
|
782 nextCharCursor = cursor; |
|
783 selectionChanged(); |
|
784 } |
|
785 } |
|
786 |
|
787 void HbAbstractEditPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/) |
|
788 { |
|
789 Q_Q(HbAbstractEdit); |
|
790 if (!forceEmitSelectionChanged) { |
|
791 if (selectionCursor.position() == cursor.position() |
|
792 && selectionCursor.anchor() == cursor.anchor()) { |
|
793 return; |
|
794 } |
|
795 if (!selectionCursor.hasSelection() && !cursor.hasSelection()) { |
|
796 return; |
|
797 } |
|
798 } |
|
799 |
|
800 emit q->selectionChanged(selectionCursor, cursor); |
|
801 selectionCursor = cursor; |
|
802 } |
|
803 |
|
804 void HbAbstractEditPrivate::acceptKeyPressEvent(QKeyEvent *event) |
|
805 { |
|
806 event->accept(); |
|
807 cursorOn = true; |
|
808 ensureCursorVisible(); |
|
809 |
|
810 updateCurrentCharFormat(); |
|
811 } |
|
812 |
|
813 QAbstractTextDocumentLayout::PaintContext HbAbstractEditPrivate::getPaintContext() const |
|
814 { |
|
815 Q_Q(const HbAbstractEdit); |
|
816 |
|
817 QAbstractTextDocumentLayout::PaintContext ctx; |
|
818 |
|
819 ctx.palette = q->palette(); |
|
820 if (cursorOn && q->isEnabled()) { |
|
821 if (!isCursorVisible()) |
|
822 ctx.cursorPosition = -1; |
|
823 else if (preeditCursor != 0) |
|
824 ctx.cursorPosition = - (preeditCursor + 2); |
|
825 else |
|
826 ctx.cursorPosition = cursor.position(); |
|
827 } |
|
828 |
|
829 if (cursor.hasSelection()) { |
|
830 QAbstractTextDocumentLayout::Selection selection; |
|
831 selection.cursor = cursor; |
|
832 QPalette::ColorGroup cg = q->hasFocus() ? QPalette::Active : QPalette::Inactive; |
|
833 selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight)); |
|
834 selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText)); |
|
835 |
|
836 HbStyleOption opt; |
|
837 q->initStyleOption(&opt); |
|
838 |
|
839 if (qApp->style()->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, 0)) { |
|
840 selection.format.setProperty(QTextFormat::FullWidthSelection, true); |
|
841 } |
|
842 ctx.selections.append(selection); |
|
843 } |
|
844 |
|
845 return ctx; |
|
846 } |
|
847 |
|
848 int HbAbstractEditPrivate::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const |
|
849 { |
|
850 Q_Q(const HbAbstractEdit); |
|
851 return doc->documentLayout()->hitTest(q->mapToItem(canvas, point), accuracy); |
|
852 } |
|
853 |
|
854 QRectF HbAbstractEditPrivate::cursorRect(const QTextCursor &cursor) const |
|
855 { |
|
856 Q_Q(const HbAbstractEdit); |
|
857 if (cursor.isNull()) |
|
858 return QRectF(); |
|
859 |
|
860 return q->rectForPosition(cursor.position()); |
|
861 } |
|
862 |
|
863 QRectF HbAbstractEditPrivate::cursorRect() const |
|
864 { |
|
865 return cursorRect(cursor); |
|
866 } |
|
867 |
|
868 QRectF HbAbstractEditPrivate::selectionRect(const QTextCursor &cursor) const |
|
869 { |
|
870 Q_Q(const HbAbstractEdit); |
|
871 |
|
872 QRectF r = q->rectForPosition(cursor.selectionStart()); |
|
873 |
|
874 if (cursor.hasComplexSelection() && cursor.currentTable()) { |
|
875 QTextTable *table = cursor.currentTable(); |
|
876 r = doc->documentLayout()->frameBoundingRect(table); |
|
877 } else if (cursor.hasSelection()) { |
|
878 const int position = cursor.selectionStart(); |
|
879 const int anchor = cursor.selectionEnd(); |
|
880 const QTextBlock posBlock = doc->findBlock(position); |
|
881 const QTextBlock anchorBlock = doc->findBlock(anchor); |
|
882 if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) { |
|
883 const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position()); |
|
884 const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position()); |
|
885 |
|
886 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber()); |
|
887 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber()); |
|
888 const QTextLayout *layout = posBlock.layout(); |
|
889 r = QRectF(); |
|
890 for (int i = firstLine; i <= lastLine; ++i) { |
|
891 r |= layout->lineAt(i).rect(); |
|
892 r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled |
|
893 } |
|
894 r.translate(q->blockBoundingRect(posBlock).topLeft()); |
|
895 } else { |
|
896 QRectF anchorRect = q->rectForPosition(cursor.selectionEnd()); |
|
897 r |= anchorRect; |
|
898 r |= boundingRectOfFloatsInSelection(cursor); |
|
899 QRectF frameRect(doc->documentLayout()->frameBoundingRect(cursor.currentFrame())); |
|
900 r.setLeft(frameRect.left()); |
|
901 r.setRight(frameRect.right()); |
|
902 } |
|
903 if (r.isValid()) |
|
904 r.adjust(-1, -1, 1, 1); |
|
905 } |
|
906 |
|
907 return r; |
|
908 } |
|
909 |
|
910 QRectF HbAbstractEditPrivate::selectionRect() const |
|
911 { |
|
912 return selectionRect(selectionCursor); |
|
913 } |
|
914 |
|
915 QRectF HbAbstractEditPrivate::rectForPositionInCanvasCoords(int position, QTextLine::Edge edge) const |
|
916 { |
|
917 Q_Q(const HbAbstractEdit); |
|
918 |
|
919 const QTextBlock block = doc->findBlock(position); |
|
920 if (!block.isValid()) |
|
921 return QRectF(); |
|
922 const QAbstractTextDocumentLayout *docLayout = doc->documentLayout(); |
|
923 const QTextLayout *layout = block.layout(); |
|
924 const QPointF layoutPos = q->blockBoundingRect(block).topLeft(); |
|
925 int relativePos = position - block.position(); |
|
926 if (preeditCursor != 0) { |
|
927 int preeditPos = layout->preeditAreaPosition(); |
|
928 if (relativePos == preeditPos) |
|
929 relativePos += preeditCursor; |
|
930 else if (relativePos > preeditPos) |
|
931 relativePos += layout->preeditAreaText().length(); |
|
932 } |
|
933 QTextLine line = layout->lineForTextPosition(relativePos); |
|
934 |
|
935 int cursorWidth; |
|
936 { |
|
937 bool ok = false; |
|
938 #ifndef QT_NO_PROPERTIES |
|
939 cursorWidth = docLayout->property("cursorWidth").toInt(&ok); |
|
940 #endif |
|
941 if (!ok) |
|
942 cursorWidth = 1; |
|
943 } |
|
944 |
|
945 QRectF r; |
|
946 |
|
947 if (line.isValid()) { |
|
948 qreal x = line.cursorToX(relativePos, edge); |
|
949 qreal w = 0; |
|
950 r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), |
|
951 cursorWidth + w, line.height()); |
|
952 } else { |
|
953 r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height |
|
954 } |
|
955 |
|
956 return r; |
|
957 } |
|
958 |
|
959 int HbAbstractEditPrivate::contentLength() const |
|
960 { |
|
961 QTextBlock block = doc->lastBlock(); |
|
962 return block.position() + block.length() - 1; |
|
963 } |
|
964 |
|
965 bool HbAbstractEditPrivate::hasAcceptableInput() const |
|
966 { |
|
967 QTextCursor cursorCopy = cursor; |
|
968 if (validator && |
|
969 validator->validateContent(cursorCopy, 0, 0, 0) != QValidator::Acceptable) { |
|
970 return false; |
|
971 } |
|
972 return true; |
|
973 } |
|
974 |
|
975 bool HbAbstractEditPrivate::canPaste() const |
|
976 { |
|
977 #ifndef QT_NO_CLIPBOARD |
|
978 Q_Q(const HbAbstractEdit); |
|
979 if (interactionFlags & Qt::TextEditable) { |
|
980 const QMimeData *md = QApplication::clipboard()->mimeData(); |
|
981 return md && q->canInsertFromMimeData(md); |
|
982 } |
|
983 #endif//QT_NO_CLIPBOARD |
|
984 return false; |
|
985 } |
|
986 |
|
987 bool HbAbstractEditPrivate::canCopy() const |
|
988 { |
|
989 #ifndef QT_NO_CLIPBOARD |
|
990 return true; |
|
991 #else |
|
992 return false; |
|
993 #endif//QT_NO_CLIPBOARD |
|
994 } |
|
995 |
|
996 bool HbAbstractEditPrivate::canFormat() const |
|
997 { |
|
998 return formatDialog != 0; |
|
999 } |
|
1000 |
|
1001 bool HbAbstractEditPrivate::isCursorVisible() const |
|
1002 { |
|
1003 return preeditCursorVisible && apiCursorVisible; |
|
1004 } |
|
1005 |
|
1006 void HbAbstractEditPrivate::sendMouseEventToInputContext(const QGraphicsSceneMouseEvent *e) const |
|
1007 { |
|
1008 QPointF pos = e->pos(); |
|
1009 int cursorPos = hitTest(pos, Qt::FuzzyHit); |
|
1010 if (cursorPos == -1) |
|
1011 return; |
|
1012 |
|
1013 QTextLayout *layout = cursor.block().layout(); |
|
1014 if (layout && !layout->preeditAreaText().isEmpty()) { |
|
1015 QInputContext *ctx = qApp->inputContext(); |
|
1016 if (ctx) { |
|
1017 QMouseEvent ev(QEvent::MouseButtonPress, pos.toPoint(), e->scenePos().toPoint(), |
|
1018 e->button(), e->buttons(), e->modifiers()); |
|
1019 ctx->mouseHandler(cursorPos - cursor.position(), &ev); |
|
1020 } |
|
1021 } |
|
1022 } |
|
1023 |
|
1024 void HbAbstractEditPrivate::updateEditingSize() |
|
1025 { |
|
1026 } |
|
1027 |
|
1028 void HbAbstractEditPrivate::removeCurrentDocument() |
|
1029 { |
|
1030 Q_Q(HbAbstractEdit); |
|
1031 |
|
1032 if( doc ) { |
|
1033 doc->disconnect(q); |
|
1034 doc->documentLayout()->disconnect(q); |
|
1035 doc->documentLayout()->setPaintDevice(0); |
|
1036 |
|
1037 if (doc->parent() == q) { |
|
1038 delete doc; |
|
1039 } |
|
1040 |
|
1041 doc = 0; |
|
1042 } |
|
1043 } |
|
1044 |
|
1045 void HbAbstractEditPrivate::connectToNewDocument(QTextDocument *newDoc) |
|
1046 { |
|
1047 Q_Q(HbAbstractEdit); |
|
1048 |
|
1049 doc = newDoc; |
|
1050 cursor = QTextCursor(doc); |
|
1051 |
|
1052 QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_contentsChanged())); |
|
1053 QObject::connect(doc, SIGNAL(contentsChange(int, int, int)), q, SLOT(_q_contentsChange(int, int, int))); |
|
1054 |
|
1055 //QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(emitCursorPosChanged(QTextCursor))); |
|
1056 QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(documentLayoutChanged())); |
|
1057 |
|
1058 QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SLOT(blockCountChanged(int))); |
|
1059 |
|
1060 doc->setModified(false); |
|
1061 |
|
1062 q->documentLayoutChanged(); |
|
1063 } |
|
1064 |
|
1065 void HbAbstractEditPrivate::longPressGesture(const QPointF &point) |
|
1066 { |
|
1067 Q_Q(HbAbstractEdit); |
|
1068 |
|
1069 if(contextMenuShownOn.testFlag(Hb::ShowTextContextMenuOnLongPress)) { |
|
1070 mousePressPos = q->mapFromScene(point); |
|
1071 |
|
1072 int cursorPos = hitTest(mousePressPos, Qt::FuzzyHit); |
|
1073 if (cursorPos == -1) |
|
1074 return; |
|
1075 |
|
1076 // don't do anything if longpress inside the selection |
|
1077 if (cursor.hasSelection() |
|
1078 && cursorPos >= cursor.selectionStart() |
|
1079 && cursorPos <= cursor.selectionEnd()){ |
|
1080 return; |
|
1081 } |
|
1082 q->showContextMenu(point); |
|
1083 } |
|
1084 |
|
1085 //TODO: |
|
1086 // this call is needed because now the panStarted is called in mousePressEvent |
|
1087 // and panFinished is called in mouseReleaseEvent, but in longPress case the mouseRelease is not called |
|
1088 // Once the this gesture bug is fixed this needs to be removed! |
|
1089 if (selectionControl) { |
|
1090 selectionControl->panFinished(); |
|
1091 } |
|
1092 } |
|
1093 |
|
1094 void HbAbstractEditPrivate::gestureReceived() |
|
1095 { |
|
1096 wasGesture = true; |
|
1097 } |
|
1098 |
|
1099 |
|
1100 void HbAbstractEditPrivate::hideSelectionHandles() |
|
1101 { |
|
1102 Q_Q(HbAbstractEdit); |
|
1103 if (selectionControl){ |
|
1104 selectionControl->hideHandles(); |
|
1105 } |
|
1106 q->update(); |
|
1107 } |
|
1108 |
|
1109 |
|
1110 void HbAbstractEditPrivate::drawSelectionEdges(QPainter *painter, QAbstractTextDocumentLayout::PaintContext ctx) |
|
1111 { |
|
1112 if (cursor.hasSelection() && selectionControl && selectionControl->isVisible()){ |
|
1113 painter->setPen(ctx.palette.color(QPalette::Text)); |
|
1114 painter->setBrush(ctx.palette.color(QPalette::Text)); |
|
1115 painter->drawRect(rectForPositionInCanvasCoords(cursor.selectionStart(), QTextLine::Leading)); |
|
1116 painter->drawRect(rectForPositionInCanvasCoords(cursor.selectionEnd(), QTextLine::Trailing)); |
|
1117 } |
|
1118 } |
|
1119 |
|
1120 /* |
|
1121 * Prepares the document for pasting. Derived classes can override this method, |
|
1122 * e.g. HbLineEdit clears the document before pasting when in password edit mode |
|
1123 */ |
|
1124 void HbAbstractEditPrivate::prepDocForPaste() |
|
1125 { |
|
1126 } |
|
1127 |
|
1128 /* |
|
1129 * this method should draw text background. it is temporary solution until |
|
1130 * HbTexdDocumentlayout will be implemented |
|
1131 * |
|
1132 * this method is reimplemented by HbTextEdit to draw text base lines |
|
1133 */ |
|
1134 void HbAbstractEditPrivate::drawContentBackground(QPainter *, |
|
1135 const QStyleOptionGraphicsItem &) const |
|
1136 { |
|
1137 // no implementation is needed |
|
1138 } |
|
1139 |
|
1140 HbSmileyEngine* HbAbstractEditPrivate::smileyEngineInstance() const |
|
1141 { |
|
1142 Q_Q(const HbAbstractEdit); |
|
1143 if(smileyEngine == 0) { |
|
1144 smileyEngine = new HbSmileyEngine(const_cast <HbAbstractEdit*>(q)); |
|
1145 smileyEngine->setDocument(doc); |
|
1146 |
|
1147 HbEditorInterface editorInterface(const_cast<HbAbstractEdit*>(q)); |
|
1148 |
|
1149 if(smileysEnabled) { |
|
1150 editorInterface.setSmileyTheme(smileyEngine->theme()); |
|
1151 } else { |
|
1152 editorInterface.setSmileyTheme(HbSmileyTheme()); |
|
1153 } |
|
1154 } |
|
1155 return smileyEngine; |
|
1156 } |
|
1157 |
|
1158 Qt::Alignment HbAbstractEditPrivate::alignmentFromString(const QString &text) |
|
1159 { |
|
1160 Qt::Alignment align(0); |
|
1161 static const struct { |
|
1162 Qt::Alignment align; |
|
1163 const char* pattern; |
|
1164 } stringToAlign[] = { |
|
1165 { Qt::AlignLeft, "\\bleft\\b" }, |
|
1166 { Qt::AlignRight, "\\bright\\b" }, |
|
1167 { Qt::AlignHCenter, "\\bhcenter\\b" }, |
|
1168 { Qt::AlignAbsolute, "\\babsolute\\b" }, |
|
1169 { Qt::AlignJustify, "\\bjustify\\b" }, |
|
1170 { Qt::AlignTop, "\\btop\\b" }, |
|
1171 { Qt::AlignBottom, "\\bbottom\\b" }, |
|
1172 { Qt::AlignVCenter, "\\bvcenter\\b" }, |
|
1173 { Qt::AlignCenter, "\\bcenter\\b" } |
|
1174 }; |
|
1175 static const int count = sizeof(stringToAlign)/sizeof(stringToAlign[0]); |
|
1176 |
|
1177 |
|
1178 QRegExp regExp; |
|
1179 regExp.setCaseSensitivity(Qt::CaseInsensitive); |
|
1180 |
|
1181 for(int i=0; i<count; ++i) { |
|
1182 regExp.setPattern(stringToAlign[i].pattern); |
|
1183 if(text.indexOf(regExp)>=0) { |
|
1184 align |= stringToAlign[i].align; |
|
1185 } |
|
1186 } |
|
1187 return align; |
|
1188 } |
|
1189 |
|
1190 // Send open input panel event. |
|
1191 void HbAbstractEditPrivate::sendInputPanelEvent(QEvent::Type type) |
|
1192 { |
|
1193 #if QT_VERSION >= 0x040600 |
|
1194 QInputContext *ic = qApp->inputContext(); |
|
1195 if (ic) { |
|
1196 QEvent *openEvent = new QEvent(type); |
|
1197 ic->filterEvent(openEvent); |
|
1198 delete openEvent; |
|
1199 } |
|
1200 #endif |
|
1201 } |
|
1202 |
|
1203 // Send open input panel event. |
|
1204 void HbAbstractEditPrivate::openInputPanel() |
|
1205 { |
|
1206 sendInputPanelEvent(QEvent::RequestSoftwareInputPanel); |
|
1207 } |
|
1208 |
|
1209 // Send close input panel event. |
|
1210 void HbAbstractEditPrivate::closeInputPanel() |
|
1211 { |
|
1212 sendInputPanelEvent(QEvent::CloseSoftwareInputPanel); |
|
1213 } |
|
1214 |
|
1215 #include "hbinputeditorinterface.h" |
|
1216 #include "hbinputvkbhost.h" |
|
1217 |
|
1218 void HbAbstractEditPrivate::minimizeInputPanel() |
|
1219 { |
|
1220 Q_Q(HbAbstractEdit); |
|
1221 |
|
1222 HbEditorInterface ei(q); |
|
1223 HbVkbHost* vkbHost = ei.vkbHost(); |
|
1224 vkbHost->minimizeKeypad(); |
|
1225 } |
|
1226 |
|
1227 #include "moc_hbabstractedit.cpp" |