Remove unused code from QQuickTextControl.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktextcontrol.cpp
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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquicktextcontrol_p.h"
43 #include "qquicktextcontrol_p_p.h"
44
45 #ifndef QT_NO_TEXTCONTROL
46
47 #include <qfont.h>
48 #include <qpainter.h>
49 #include <qevent.h>
50 #include <qdebug.h>
51 #include <qdrag.h>
52 #include <qclipboard.h>
53 #include <qtimer.h>
54 #include <qinputpanel.h>
55 #include "private/qtextdocumentlayout_p.h"
56 #include "private/qabstracttextdocumentlayout_p.h"
57 #include "qtextdocument.h"
58 #include "private/qtextdocument_p.h"
59 #include "qtextlist.h"
60 #include "qtextdocumentwriter.h"
61 #include "private/qtextcursor_p.h"
62 #include "qpagedpaintdevice.h"
63 #include "private/qpagedpaintdevice_p.h"
64
65 #include <qtextformat.h>
66 #include <qdatetime.h>
67 #include <qbuffer.h>
68 #include <qguiapplication.h>
69 #include <limits.h>
70 #include <qtexttable.h>
71 #include <qvariant.h>
72 #include <qurl.h>
73 #include <qstylehints.h>
74
75 // ### these should come from QStyleHints
76 const int textCursorWidth = 1;
77 const bool fullWidthSelection = true;
78
79 QT_BEGIN_NAMESPACE
80
81 #ifndef QT_NO_CONTEXTMENU
82 #endif
83
84 // could go into QTextCursor...
85 static QTextLine currentTextLine(const QTextCursor &cursor)
86 {
87     const QTextBlock block = cursor.block();
88     if (!block.isValid())
89         return QTextLine();
90
91     const QTextLayout *layout = block.layout();
92     if (!layout)
93         return QTextLine();
94
95     const int relativePos = cursor.position() - block.position();
96     return layout->lineForTextPosition(relativePos);
97 }
98
99 QQuickTextControlPrivate::QQuickTextControlPrivate()
100     : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
101       interactionFlags(Qt::TextEditorInteraction),
102       mousePressed(false),
103       lastSelectionState(false), ignoreAutomaticScrollbarAdjustement(false),
104       overwriteMode(false),
105       acceptRichText(true),
106       preeditCursor(0), hideCursor(false),
107       hasFocus(false),
108       isEnabled(true),
109       hadSelectionOnMousePress(false),
110       wordSelectionEnabled(false)
111 {}
112
113 bool QQuickTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
114 {
115 #ifdef QT_NO_SHORTCUT
116     Q_UNUSED(e);
117 #endif
118
119     Q_Q(QQuickTextControl);
120     if (cursor.isNull())
121         return false;
122
123     const QTextCursor oldSelection = cursor;
124     const int oldCursorPos = cursor.position();
125
126     QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
127     QTextCursor::MoveOperation op = QTextCursor::NoMove;
128
129     if (false) {
130     }
131 #ifndef QT_NO_SHORTCUT
132     if (e == QKeySequence::MoveToNextChar) {
133             op = QTextCursor::Right;
134     }
135     else if (e == QKeySequence::MoveToPreviousChar) {
136             op = QTextCursor::Left;
137     }
138     else if (e == QKeySequence::SelectNextChar) {
139            op = QTextCursor::Right;
140            mode = QTextCursor::KeepAnchor;
141     }
142     else if (e == QKeySequence::SelectPreviousChar) {
143             op = QTextCursor::Left;
144             mode = QTextCursor::KeepAnchor;
145     }
146     else if (e == QKeySequence::SelectNextWord) {
147             op = QTextCursor::WordRight;
148             mode = QTextCursor::KeepAnchor;
149     }
150     else if (e == QKeySequence::SelectPreviousWord) {
151             op = QTextCursor::WordLeft;
152             mode = QTextCursor::KeepAnchor;
153     }
154     else if (e == QKeySequence::SelectStartOfLine) {
155             op = QTextCursor::StartOfLine;
156             mode = QTextCursor::KeepAnchor;
157     }
158     else if (e == QKeySequence::SelectEndOfLine) {
159             op = QTextCursor::EndOfLine;
160             mode = QTextCursor::KeepAnchor;
161     }
162     else if (e == QKeySequence::SelectStartOfBlock) {
163             op = QTextCursor::StartOfBlock;
164             mode = QTextCursor::KeepAnchor;
165     }
166     else if (e == QKeySequence::SelectEndOfBlock) {
167             op = QTextCursor::EndOfBlock;
168             mode = QTextCursor::KeepAnchor;
169     }
170     else if (e == QKeySequence::SelectStartOfDocument) {
171             op = QTextCursor::Start;
172             mode = QTextCursor::KeepAnchor;
173     }
174     else if (e == QKeySequence::SelectEndOfDocument) {
175             op = QTextCursor::End;
176             mode = QTextCursor::KeepAnchor;
177     }
178     else if (e == QKeySequence::SelectPreviousLine) {
179             op = QTextCursor::Up;
180             mode = QTextCursor::KeepAnchor;
181     }
182     else if (e == QKeySequence::SelectNextLine) {
183             op = QTextCursor::Down;
184             mode = QTextCursor::KeepAnchor;
185             {
186                 QTextBlock block = cursor.block();
187                 QTextLine line = currentTextLine(cursor);
188                 if (!block.next().isValid()
189                     && line.isValid()
190                     && line.lineNumber() == block.layout()->lineCount() - 1)
191                     op = QTextCursor::End;
192             }
193     }
194     else if (e == QKeySequence::MoveToNextWord) {
195             op = QTextCursor::WordRight;
196     }
197     else if (e == QKeySequence::MoveToPreviousWord) {
198             op = QTextCursor::WordLeft;
199     }
200     else if (e == QKeySequence::MoveToEndOfBlock) {
201             op = QTextCursor::EndOfBlock;
202     }
203     else if (e == QKeySequence::MoveToStartOfBlock) {
204             op = QTextCursor::StartOfBlock;
205     }
206     else if (e == QKeySequence::MoveToNextLine) {
207             op = QTextCursor::Down;
208     }
209     else if (e == QKeySequence::MoveToPreviousLine) {
210             op = QTextCursor::Up;
211     }
212     else if (e == QKeySequence::MoveToStartOfLine) {
213             op = QTextCursor::StartOfLine;
214     }
215     else if (e == QKeySequence::MoveToEndOfLine) {
216             op = QTextCursor::EndOfLine;
217     }
218     else if (e == QKeySequence::MoveToStartOfDocument) {
219             op = QTextCursor::Start;
220     }
221     else if (e == QKeySequence::MoveToEndOfDocument) {
222             op = QTextCursor::End;
223     }
224 #endif // QT_NO_SHORTCUT
225     else {
226         return false;
227     }
228
229 // Except for pageup and pagedown, Mac OS X has very different behavior, we don't do it all, but
230 // here's the breakdown:
231 // Shift still works as an anchor, but only one of the other keys can be down Ctrl (Command),
232 // Alt (Option), or Meta (Control).
233 // Command/Control + Left/Right -- Move to left or right of the line
234 //                 + Up/Down -- Move to top bottom of the file. (Control doesn't move the cursor)
235 // Option + Left/Right -- Move one word Left/right.
236 //        + Up/Down  -- Begin/End of Paragraph.
237 // Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
238
239     bool visualNavigation = cursor.visualNavigation();
240     cursor.setVisualNavigation(true);
241     const bool moved = cursor.movePosition(op, mode);
242     cursor.setVisualNavigation(visualNavigation);
243     q->ensureCursorVisible();
244
245     bool isNavigationEvent
246             =  e->key() == Qt::Key_Up
247             || e->key() == Qt::Key_Down
248             || e->key() == Qt::Key_Left
249             || e->key() == Qt::Key_Right;
250
251     if (moved) {
252         if (cursor.position() != oldCursorPos)
253             emit q->cursorPositionChanged();
254         emit q->microFocusChanged();
255     } else if (isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
256         return false;
257     }
258
259     selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
260
261     repaintOldAndNewSelection(oldSelection);
262
263     return true;
264 }
265
266 void QQuickTextControlPrivate::updateCurrentCharFormat()
267 {
268     Q_Q(QQuickTextControl);
269
270     QTextCharFormat fmt = cursor.charFormat();
271     if (fmt == lastCharFormat)
272         return;
273     lastCharFormat = fmt;
274
275     emit q->currentCharFormatChanged(fmt);
276     emit q->microFocusChanged();
277 }
278
279 void QQuickTextControlPrivate::init(Qt::TextFormat format, const QString &text, QTextDocument *document)
280 {
281     Q_Q(QQuickTextControl);
282     setContent(format, text, document);
283
284     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
285     q->setCursorWidth(-1);
286 }
287
288 void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
289 {
290     Q_Q(QQuickTextControl);
291
292     // for use when called from setPlainText. we may want to re-use the currently
293     // set char format then.
294     const QTextCharFormat charFormatForInsertion = cursor.charFormat();
295
296     bool clearDocument = true;
297     if (!doc) {
298         if (document) {
299             doc = document;
300             clearDocument = false;
301         } else {
302             palette = QGuiApplication::palette();
303             doc = new QTextDocument(q);
304         }
305         _q_documentLayoutChanged();
306         cursor = QTextCursor(doc);
307
308 // ####        doc->documentLayout()->setPaintDevice(viewport);
309
310         QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
311         QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
312         QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged()));
313
314         // convenience signal forwards
315         QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
316         QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
317         QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
318         QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
319     }
320
321     bool previousUndoRedoState = doc->isUndoRedoEnabled();
322     if (!document)
323         doc->setUndoRedoEnabled(false);
324
325     //Saving the index save some time.
326     static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()");
327     static int textChangedIndex = QQuickTextControl::staticMetaObject.indexOfSignal("textChanged()");
328     // avoid multiple textChanged() signals being emitted
329     QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
330
331     if (!text.isEmpty()) {
332         // clear 'our' cursor for insertion to prevent
333         // the emission of the cursorPositionChanged() signal.
334         // instead we emit it only once at the end instead of
335         // at the end of the document after loading and when
336         // positioning the cursor again to the start of the
337         // document.
338         cursor = QTextCursor();
339         if (format == Qt::PlainText) {
340             QTextCursor formatCursor(doc);
341             // put the setPlainText and the setCharFormat into one edit block,
342             // so that the syntax highlight triggers only /once/ for the entire
343             // document, not twice.
344             formatCursor.beginEditBlock();
345             doc->setPlainText(text);
346             doc->setUndoRedoEnabled(false);
347             formatCursor.select(QTextCursor::Document);
348             formatCursor.setCharFormat(charFormatForInsertion);
349             formatCursor.endEditBlock();
350         } else {
351 #ifndef QT_NO_TEXTHTMLPARSER
352             doc->setHtml(text);
353 #else
354             doc->setPlainText(text);
355 #endif
356             doc->setUndoRedoEnabled(false);
357         }
358         cursor = QTextCursor(doc);
359     } else if (clearDocument) {
360         doc->clear();
361     }
362     cursor.setCharFormat(charFormatForInsertion);
363
364     QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
365     emit q->textChanged();
366     if (!document)
367         doc->setUndoRedoEnabled(previousUndoRedoState);
368     _q_updateCurrentCharFormatAndSelection();
369     if (!document)
370         doc->setModified(false);
371
372     q->ensureCursorVisible();
373     emit q->cursorPositionChanged();
374 }
375
376 void QQuickTextControlPrivate::setCursorPosition(const QPointF &pos)
377 {
378     Q_Q(QQuickTextControl);
379     const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
380     if (cursorPos == -1)
381         return;
382     cursor.setPosition(cursorPos);
383 }
384
385 void QQuickTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
386 {
387     cursor.setPosition(pos, mode);
388
389     if (mode != QTextCursor::KeepAnchor) {
390         selectedWordOnDoubleClick = QTextCursor();
391         selectedBlockOnTrippleClick = QTextCursor();
392     }
393 }
394
395 void QQuickTextControlPrivate::repaintCursor()
396 {
397     Q_Q(QQuickTextControl);
398     emit q->updateCursorRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
399 }
400
401 void QQuickTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
402 {
403     Q_Q(QQuickTextControl);
404     if (cursor.hasSelection()
405         && oldSelection.hasSelection()
406         && cursor.currentFrame() == oldSelection.currentFrame()
407         && !cursor.hasComplexSelection()
408         && !oldSelection.hasComplexSelection()
409         && cursor.anchor() == oldSelection.anchor()
410         ) {
411         QTextCursor differenceSelection(doc);
412         differenceSelection.setPosition(oldSelection.position());
413         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
414         emit q->updateRequest(q->selectionRect(differenceSelection));
415     } else {
416         if (!oldSelection.hasSelection() && !cursor.hasSelection()) {
417             if (!oldSelection.isNull())
418                 emit q->updateCursorRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
419             emit q->updateCursorRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
420
421         } else {
422             if (!oldSelection.isNull())
423                 emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
424             emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
425         }
426     }
427 }
428
429 void QQuickTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
430 {
431     Q_Q(QQuickTextControl);
432     if (forceEmitSelectionChanged)
433         emit q->selectionChanged();
434
435     bool current = cursor.hasSelection();
436     if (current == lastSelectionState)
437         return;
438
439     lastSelectionState = current;
440     emit q->copyAvailable(current);
441     if (!forceEmitSelectionChanged)
442         emit q->selectionChanged();
443     emit q->microFocusChanged();
444 }
445
446 void QQuickTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
447 {
448     updateCurrentCharFormat();
449     selectionChanged();
450 }
451
452 #ifndef QT_NO_CLIPBOARD
453 void QQuickTextControlPrivate::setClipboardSelection()
454 {
455     QClipboard *clipboard = QGuiApplication::clipboard();
456     if (!cursor.hasSelection() || !clipboard->supportsSelection())
457         return;
458     Q_Q(QQuickTextControl);
459     QMimeData *data = q->createMimeDataFromSelection();
460     clipboard->setMimeData(data, QClipboard::Selection);
461 }
462 #endif
463
464 void QQuickTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
465 {
466     Q_Q(QQuickTextControl);
467     if (someCursor.isCopyOf(cursor)) {
468         emit q->cursorPositionChanged();
469         emit q->microFocusChanged();
470     }
471 }
472
473 void QQuickTextControlPrivate::_q_documentLayoutChanged()
474 {
475     Q_Q(QQuickTextControl);
476     QAbstractTextDocumentLayout *layout = doc->documentLayout();
477     QObject::connect(layout, SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
478     QObject::connect(layout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(_q_updateBlock(QTextBlock)));
479     QObject::connect(layout, SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
480
481 }
482
483 void QQuickTextControlPrivate::setBlinkingCursorEnabled(bool enable)
484 {
485     Q_Q(QQuickTextControl);
486
487     if (enable && qApp->styleHints()->cursorFlashTime() > 0)
488         cursorBlinkTimer.start(qApp->styleHints()->cursorFlashTime() / 2, q);
489     else
490         cursorBlinkTimer.stop();
491
492     cursorOn = enable;
493
494     repaintCursor();
495 }
496
497 void QQuickTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
498 {
499     Q_Q(QQuickTextControl);
500
501     // if inside the initial selected word keep that
502     if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
503         && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
504         q->setTextCursor(selectedWordOnDoubleClick);
505         return;
506     }
507
508     QTextCursor curs = selectedWordOnDoubleClick;
509     curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
510
511     if (!curs.movePosition(QTextCursor::StartOfWord))
512         return;
513     const int wordStartPos = curs.position();
514
515     const int blockPos = curs.block().position();
516     const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
517
518     QTextLine line = currentTextLine(curs);
519     if (!line.isValid())
520         return;
521
522     const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
523
524     if (!curs.movePosition(QTextCursor::EndOfWord))
525         return;
526     const int wordEndPos = curs.position();
527
528     const QTextLine otherLine = currentTextLine(curs);
529     if (otherLine.textStart() != line.textStart()
530         || wordEndPos == wordStartPos)
531         return;
532
533     const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
534
535     if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
536         return;
537
538     if (wordSelectionEnabled) {
539         if (suggestedNewPosition < selectedWordOnDoubleClick.position()) {
540             cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
541             setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
542         } else {
543             cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
544             setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
545         }
546     } else {
547         // keep the already selected word even when moving to the left
548         // (#39164)
549         if (suggestedNewPosition < selectedWordOnDoubleClick.position())
550             cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
551         else
552             cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
553
554         const qreal differenceToStart = mouseXPosition - wordStartX;
555         const qreal differenceToEnd = wordEndX - mouseXPosition;
556
557         if (differenceToStart < differenceToEnd)
558             setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
559         else
560             setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
561     }
562
563     if (interactionFlags & Qt::TextSelectableByMouse) {
564 #ifndef QT_NO_CLIPBOARD
565         setClipboardSelection();
566 #endif
567         selectionChanged(true);
568     }
569 }
570
571 void QQuickTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition)
572 {
573     Q_Q(QQuickTextControl);
574
575     // if inside the initial selected line keep that
576     if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
577         && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
578         q->setTextCursor(selectedBlockOnTrippleClick);
579         return;
580     }
581
582     if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
583         cursor.setPosition(selectedBlockOnTrippleClick.selectionEnd());
584         cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
585         cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
586     } else {
587         cursor.setPosition(selectedBlockOnTrippleClick.selectionStart());
588         cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
589         cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
590         cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
591     }
592
593     if (interactionFlags & Qt::TextSelectableByMouse) {
594 #ifndef QT_NO_CLIPBOARD
595         setClipboardSelection();
596 #endif
597         selectionChanged(true);
598     }
599 }
600
601 void QQuickTextControlPrivate::_q_deleteSelected()
602 {
603     if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
604         return;
605     cursor.removeSelectedText();
606 }
607
608 void QQuickTextControl::undo()
609 {
610     Q_D(QQuickTextControl);
611     d->repaintSelection();
612     const int oldCursorPos = d->cursor.position();
613     d->doc->undo(&d->cursor);
614     if (d->cursor.position() != oldCursorPos)
615         emit cursorPositionChanged();
616     emit microFocusChanged();
617     ensureCursorVisible();
618 }
619
620 void QQuickTextControl::redo()
621 {
622     Q_D(QQuickTextControl);
623     d->repaintSelection();
624     const int oldCursorPos = d->cursor.position();
625     d->doc->redo(&d->cursor);
626         if (d->cursor.position() != oldCursorPos)
627         emit cursorPositionChanged();
628     emit microFocusChanged();
629     ensureCursorVisible();
630 }
631
632 QQuickTextControl::QQuickTextControl(QTextDocument *doc, QObject *parent)
633     : QObject(*new QQuickTextControlPrivate, parent)
634 {
635     Q_D(QQuickTextControl);
636     d->init(Qt::RichText, QString(), doc);
637 }
638
639 QQuickTextControl::~QQuickTextControl()
640 {
641 }
642
643 void QQuickTextControl::setView(QObject *view)
644 {
645     Q_D(QQuickTextControl);
646     d->contextObject = view;
647 }
648
649 QObject *QQuickTextControl::view() const
650 {
651     Q_D(const QQuickTextControl);
652     return d->contextObject;
653 }
654
655 QTextDocument *QQuickTextControl::document() const
656 {
657     Q_D(const QQuickTextControl);
658     return d->doc;
659 }
660
661 void QQuickTextControl::setTextCursor(const QTextCursor &cursor)
662 {
663     Q_D(QQuickTextControl);
664     d->commitPreedit();
665     d->cursorIsFocusIndicator = false;
666     const bool posChanged = cursor.position() != d->cursor.position();
667     const QTextCursor oldSelection = d->cursor;
668     d->cursor = cursor;
669     d->cursorOn = d->hasFocus && (d->interactionFlags & Qt::TextEditable);
670     d->_q_updateCurrentCharFormatAndSelection();
671     ensureCursorVisible();
672     d->repaintOldAndNewSelection(oldSelection);
673     if (posChanged)
674         emit cursorPositionChanged();
675 }
676
677 QTextCursor QQuickTextControl::textCursor() const
678 {
679     Q_D(const QQuickTextControl);
680     return d->cursor;
681 }
682
683 #ifndef QT_NO_CLIPBOARD
684
685 void QQuickTextControl::cut()
686 {
687     Q_D(QQuickTextControl);
688     if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
689         return;
690     copy();
691     d->cursor.removeSelectedText();
692 }
693
694 void QQuickTextControl::copy()
695 {
696     Q_D(QQuickTextControl);
697     if (!d->cursor.hasSelection())
698         return;
699     QMimeData *data = createMimeDataFromSelection();
700     QGuiApplication::clipboard()->setMimeData(data);
701 }
702
703 void QQuickTextControl::paste(QClipboard::Mode mode)
704 {
705     const QMimeData *md = QGuiApplication::clipboard()->mimeData(mode);
706     if (md)
707         insertFromMimeData(md);
708 }
709 #endif
710
711 void QQuickTextControl::clear()
712 {
713     Q_D(QQuickTextControl);
714     // clears and sets empty content
715     d->setContent();
716 }
717
718
719 void QQuickTextControl::selectAll()
720 {
721     Q_D(QQuickTextControl);
722     const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
723     d->cursor.select(QTextCursor::Document);
724     d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
725     d->cursorIsFocusIndicator = false;
726     emit updateRequest();
727 }
728
729 void QQuickTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset)
730 {
731     QMatrix m;
732     m.translate(coordinateOffset.x(), coordinateOffset.y());
733     processEvent(e, m);
734 }
735
736 void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix)
737 {
738     Q_D(QQuickTextControl);
739     if (d->interactionFlags == Qt::NoTextInteraction) {
740         e->ignore();
741         return;
742     }
743
744     switch (e->type()) {
745         case QEvent::KeyPress:
746             d->keyPressEvent(static_cast<QKeyEvent *>(e));
747             break;
748         case QEvent::MouseButtonPress: {
749             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
750             d->mousePressEvent(ev, matrix.map(ev->localPos()));
751             break; }
752         case QEvent::MouseMove: {
753             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
754             d->mouseMoveEvent(ev, matrix.map(ev->localPos()));
755             break; }
756         case QEvent::MouseButtonRelease: {
757             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
758             d->mouseReleaseEvent(ev, matrix.map(ev->localPos()));
759             break; }
760         case QEvent::MouseButtonDblClick: {
761             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
762             d->mouseDoubleClickEvent(ev, matrix.map(ev->localPos()));
763             break; }
764         case QEvent::InputMethod:
765             d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
766             break;
767         case QEvent::FocusIn:
768         case QEvent::FocusOut:
769             d->focusEvent(static_cast<QFocusEvent *>(e));
770             break;
771
772         case QEvent::EnabledChange:
773             d->isEnabled = e->isAccepted();
774             break;
775
776         case QEvent::ShortcutOverride:
777             if (d->interactionFlags & Qt::TextEditable) {
778                 QKeyEvent* ke = static_cast<QKeyEvent *>(e);
779                 if (ke->modifiers() == Qt::NoModifier
780                     || ke->modifiers() == Qt::ShiftModifier
781                     || ke->modifiers() == Qt::KeypadModifier) {
782                     if (ke->key() < Qt::Key_Escape) {
783                         ke->accept();
784                     } else {
785                         switch (ke->key()) {
786                             case Qt::Key_Return:
787                             case Qt::Key_Enter:
788                             case Qt::Key_Delete:
789                             case Qt::Key_Home:
790                             case Qt::Key_End:
791                             case Qt::Key_Backspace:
792                             case Qt::Key_Left:
793                             case Qt::Key_Right:
794                             case Qt::Key_Up:
795                             case Qt::Key_Down:
796                             case Qt::Key_Tab:
797                             ke->accept();
798                         default:
799                             break;
800                         }
801                     }
802 #ifndef QT_NO_SHORTCUT
803                 } else if (ke == QKeySequence::Copy
804                            || ke == QKeySequence::Paste
805                            || ke == QKeySequence::Cut
806                            || ke == QKeySequence::Redo
807                            || ke == QKeySequence::Undo
808                            || ke == QKeySequence::MoveToNextWord
809                            || ke == QKeySequence::MoveToPreviousWord
810                            || ke == QKeySequence::MoveToStartOfDocument
811                            || ke == QKeySequence::MoveToEndOfDocument
812                            || ke == QKeySequence::SelectNextWord
813                            || ke == QKeySequence::SelectPreviousWord
814                            || ke == QKeySequence::SelectStartOfLine
815                            || ke == QKeySequence::SelectEndOfLine
816                            || ke == QKeySequence::SelectStartOfBlock
817                            || ke == QKeySequence::SelectEndOfBlock
818                            || ke == QKeySequence::SelectStartOfDocument
819                            || ke == QKeySequence::SelectEndOfDocument
820                            || ke == QKeySequence::SelectAll
821                           ) {
822                     ke->accept();
823 #endif
824                 }
825             }
826             break;
827         default:
828             break;
829     }
830 }
831
832 bool QQuickTextControl::event(QEvent *e)
833 {
834     return QObject::event(e);
835 }
836
837 void QQuickTextControl::timerEvent(QTimerEvent *e)
838 {
839     Q_D(QQuickTextControl);
840     if (e->timerId() == d->cursorBlinkTimer.timerId()) {
841         d->cursorOn = !d->cursorOn;
842
843         // ###
844 //        if (d->cursor.hasSelection())
845 //            d->cursorOn &= (QGuiApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
846 //                            != 0);
847
848         d->repaintCursor();
849     } else if (e->timerId() == d->trippleClickTimer.timerId()) {
850         d->trippleClickTimer.stop();
851     }
852 }
853
854 void QQuickTextControl::setPlainText(const QString &text)
855 {
856     Q_D(QQuickTextControl);
857     d->setContent(Qt::PlainText, text);
858 }
859
860 void QQuickTextControl::setHtml(const QString &text)
861 {
862     Q_D(QQuickTextControl);
863     d->setContent(Qt::RichText, text);
864 }
865
866 void QQuickTextControlPrivate::keyPressEvent(QKeyEvent *e)
867 {
868     Q_Q(QQuickTextControl);
869 #ifndef QT_NO_SHORTCUT
870     if (e == QKeySequence::SelectAll) {
871             e->accept();
872             q->selectAll();
873             return;
874     }
875 #ifndef QT_NO_CLIPBOARD
876     else if (e == QKeySequence::Copy) {
877             e->accept();
878             q->copy();
879             return;
880     }
881 #endif
882 #endif // QT_NO_SHORTCUT
883
884     if (interactionFlags & Qt::TextSelectableByKeyboard
885         && cursorMoveKeyEvent(e))
886         goto accept;
887
888     if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
889         if ((e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) && cursor.hasSelection()) {
890             e->accept();
891             activateLinkUnderCursor();
892             return;
893         }
894     }
895
896     if (!(interactionFlags & Qt::TextEditable)) {
897         e->ignore();
898         return;
899     }
900
901     if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
902         QTextBlockFormat fmt;
903         fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
904         cursor.mergeBlockFormat(fmt);
905         goto accept;
906     }
907
908     // schedule a repaint of the region of the cursor, as when we move it we
909     // want to make sure the old cursor disappears (not noticeable when moving
910     // only a few pixels but noticeable when jumping between cells in tables for
911     // example)
912     repaintSelection();
913
914     if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~Qt::ShiftModifier)) {
915         QTextBlockFormat blockFmt = cursor.blockFormat();
916         QTextList *list = cursor.currentList();
917         if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
918             list->remove(cursor.block());
919         } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
920             blockFmt.setIndent(blockFmt.indent() - 1);
921             cursor.setBlockFormat(blockFmt);
922         } else {
923             QTextCursor localCursor = cursor;
924             localCursor.deletePreviousChar();
925         }
926         goto accept;
927     }
928 #ifndef QT_NO_SHORTCUT
929       else if (e == QKeySequence::InsertParagraphSeparator) {
930         cursor.insertBlock();
931         e->accept();
932         goto accept;
933     } else if (e == QKeySequence::InsertLineSeparator) {
934         cursor.insertText(QString(QChar::LineSeparator));
935         e->accept();
936         goto accept;
937     }
938 #endif
939     if (false) {
940     }
941 #ifndef QT_NO_SHORTCUT
942     else if (e == QKeySequence::Undo) {
943             q->undo();
944     }
945     else if (e == QKeySequence::Redo) {
946            q->redo();
947     }
948 #ifndef QT_NO_CLIPBOARD
949     else if (e == QKeySequence::Cut) {
950            q->cut();
951     }
952     else if (e == QKeySequence::Paste) {
953         QClipboard::Mode mode = QClipboard::Clipboard;
954         q->paste(mode);
955     }
956 #endif
957     else if (e == QKeySequence::Delete) {
958         QTextCursor localCursor = cursor;
959         localCursor.deleteChar();
960     }
961     else if (e == QKeySequence::DeleteEndOfWord) {
962         if (!cursor.hasSelection())
963             cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
964         cursor.removeSelectedText();
965     }
966     else if (e == QKeySequence::DeleteStartOfWord) {
967         if (!cursor.hasSelection())
968             cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
969         cursor.removeSelectedText();
970     }
971     else if (e == QKeySequence::DeleteEndOfLine) {
972         QTextBlock block = cursor.block();
973         if (cursor.position() == block.position() + block.length() - 2)
974             cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
975         else
976             cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
977         cursor.removeSelectedText();
978     }
979 #endif // QT_NO_SHORTCUT
980     else {
981         goto process;
982     }
983     goto accept;
984
985 process:
986     {
987         QString text = e->text();
988         if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
989             cursor.insertText(text);
990             selectionChanged();
991         } else {
992             e->ignore();
993             return;
994         }
995     }
996
997  accept:
998
999     e->accept();
1000     cursorOn = true;
1001
1002     q->ensureCursorVisible();
1003
1004     updateCurrentCharFormat();
1005 }
1006
1007 void QQuickTextControlPrivate::_q_updateBlock(const QTextBlock &block)
1008 {
1009     Q_Q(QQuickTextControl);
1010     QRectF br = q->blockBoundingRect(block);
1011     br.setRight(qreal(INT_MAX)); // the block might have shrunk
1012     emit q->updateRequest(br);
1013 }
1014
1015 QRectF QQuickTextControlPrivate::rectForPosition(int position) const
1016 {
1017     Q_Q(const QQuickTextControl);
1018     const QTextBlock block = doc->findBlock(position);
1019     if (!block.isValid())
1020         return QRectF();
1021     const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
1022     const QTextLayout *layout = block.layout();
1023     const QPointF layoutPos = q->blockBoundingRect(block).topLeft();
1024     int relativePos = position - block.position();
1025     if (preeditCursor != 0) {
1026         int preeditPos = layout->preeditAreaPosition();
1027         if (relativePos == preeditPos)
1028             relativePos += preeditCursor;
1029         else if (relativePos > preeditPos)
1030             relativePos += layout->preeditAreaText().length();
1031     }
1032     QTextLine line = layout->lineForTextPosition(relativePos);
1033
1034     int cursorWidth;
1035     {
1036         bool ok = false;
1037 #ifndef QT_NO_PROPERTIES
1038         cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
1039 #endif
1040         if (!ok)
1041             cursorWidth = 1;
1042     }
1043
1044     QRectF r;
1045
1046     if (line.isValid()) {
1047         qreal x = line.cursorToX(relativePos);
1048         qreal w = 0;
1049         r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), cursorWidth + w, line.height());
1050     } else {
1051         r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
1052     }
1053
1054     return r;
1055 }
1056
1057 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
1058 {
1059     return frame->firstPosition() < position;
1060 }
1061
1062 static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame)
1063 {
1064     return position < frame->lastPosition();
1065 }
1066
1067 static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
1068 {
1069     QRectF r;
1070     QTextFrame *frame = cursor.currentFrame();
1071     const QList<QTextFrame *> children = frame->childFrames();
1072
1073     const QList<QTextFrame *>::ConstIterator firstFrame = qLowerBound(children.constBegin(), children.constEnd(),
1074                                                                       cursor.selectionStart(), firstFramePosLessThanCursorPos);
1075     const QList<QTextFrame *>::ConstIterator lastFrame = qUpperBound(children.constBegin(), children.constEnd(),
1076                                                                      cursor.selectionEnd(), cursorPosLessThanLastFramePos);
1077     for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) {
1078         if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow)
1079             r |= frame->document()->documentLayout()->frameBoundingRect(*it);
1080     }
1081     return r;
1082 }
1083
1084 QRectF QQuickTextControl::selectionRect(const QTextCursor &cursor) const
1085 {
1086     Q_D(const QQuickTextControl);
1087
1088     QRectF r = d->rectForPosition(cursor.selectionStart());
1089
1090     if (cursor.hasComplexSelection() && cursor.currentTable()) {
1091         QTextTable *table = cursor.currentTable();
1092
1093         r = d->doc->documentLayout()->frameBoundingRect(table);
1094         /*
1095         int firstRow, numRows, firstColumn, numColumns;
1096         cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
1097
1098         const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
1099         const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
1100
1101         const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
1102
1103         QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
1104
1105         for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1106             const QTextTableCell cell = table->cellAt(firstRow, col);
1107             const qreal y = layout->blockBoundingRect(cell.firstCursorPosition().block()).top();
1108
1109             tableSelRect.setTop(qMin(tableSelRect.top(), y));
1110         }
1111
1112         for (int row = firstRow; row < firstRow + numRows; ++row) {
1113             const QTextTableCell cell = table->cellAt(row, firstColumn);
1114             const qreal x = layout->blockBoundingRect(cell.firstCursorPosition().block()).left();
1115
1116             tableSelRect.setLeft(qMin(tableSelRect.left(), x));
1117         }
1118
1119         for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1120             const QTextTableCell cell = table->cellAt(firstRow + numRows - 1, col);
1121             const qreal y = layout->blockBoundingRect(cell.lastCursorPosition().block()).bottom();
1122
1123             tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
1124         }
1125
1126         for (int row = firstRow; row < firstRow + numRows; ++row) {
1127             const QTextTableCell cell = table->cellAt(row, firstColumn + numColumns - 1);
1128             const qreal x = layout->blockBoundingRect(cell.lastCursorPosition().block()).right();
1129
1130             tableSelRect.setRight(qMax(tableSelRect.right(), x));
1131         }
1132
1133         r = tableSelRect.toRect();
1134         */
1135     } else if (cursor.hasSelection()) {
1136         const int position = cursor.selectionStart();
1137         const int anchor = cursor.selectionEnd();
1138         const QTextBlock posBlock = d->doc->findBlock(position);
1139         const QTextBlock anchorBlock = d->doc->findBlock(anchor);
1140         if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
1141             const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
1142             const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
1143
1144             const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1145             const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1146             const QTextLayout *layout = posBlock.layout();
1147             r = QRectF();
1148             for (int i = firstLine; i <= lastLine; ++i) {
1149                 r |= layout->lineAt(i).rect();
1150                 r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled
1151             }
1152             r.translate(blockBoundingRect(posBlock).topLeft());
1153         } else {
1154             QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1155             r |= anchorRect;
1156             r |= boundingRectOfFloatsInSelection(cursor);
1157             QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1158             r.setLeft(frameRect.left());
1159             r.setRight(frameRect.right());
1160         }
1161         if (r.isValid())
1162             r.adjust(-1, -1, 1, 1);
1163     }
1164
1165     return r;
1166 }
1167
1168 QRectF QQuickTextControl::selectionRect() const
1169 {
1170     Q_D(const QQuickTextControl);
1171     return selectionRect(d->cursor);
1172 }
1173
1174 void QQuickTextControlPrivate::mousePressEvent(QMouseEvent *e, const QPointF &pos)
1175 {
1176     Q_Q(QQuickTextControl);
1177
1178     mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
1179     mousePressPos = pos.toPoint();
1180
1181     if (sendMouseEventToInputContext(e, pos))
1182         return;
1183
1184     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1185         anchorOnMousePress = q->anchorAt(pos);
1186
1187         if (cursorIsFocusIndicator) {
1188             cursorIsFocusIndicator = false;
1189             repaintSelection();
1190             cursor.clearSelection();
1191         }
1192     }
1193     if (!(e->button() & Qt::LeftButton) ||
1194         !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
1195             e->ignore();
1196             return;
1197     }
1198
1199     cursorIsFocusIndicator = false;
1200     const QTextCursor oldSelection = cursor;
1201     const int oldCursorPos = cursor.position();
1202
1203     commitPreedit();
1204
1205     if (trippleClickTimer.isActive()
1206         && ((pos - trippleClickPoint).toPoint().manhattanLength() < qApp->styleHints()->startDragDistance())) {
1207
1208         cursor.movePosition(QTextCursor::StartOfBlock);
1209         cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1210         cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1211         selectedBlockOnTrippleClick = cursor;
1212
1213         anchorOnMousePress = QString();
1214
1215         trippleClickTimer.stop();
1216     } else {
1217         int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1218         if (cursorPos == -1) {
1219             e->ignore();
1220             return;
1221         }
1222
1223         if (e->modifiers() == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
1224             if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1225                 selectedWordOnDoubleClick = cursor;
1226                 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1227             }
1228
1229             if (selectedBlockOnTrippleClick.hasSelection())
1230                 extendBlockwiseSelection(cursorPos);
1231             else if (selectedWordOnDoubleClick.hasSelection())
1232                 extendWordwiseSelection(cursorPos, pos.x());
1233             else if (!wordSelectionEnabled)
1234                 setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
1235         } else {
1236             setCursorPosition(cursorPos);
1237         }
1238     }
1239
1240     if (interactionFlags & Qt::TextEditable) {
1241         q->ensureCursorVisible();
1242         if (cursor.position() != oldCursorPos)
1243             emit q->cursorPositionChanged();
1244         _q_updateCurrentCharFormatAndSelection();
1245     } else {
1246         if (cursor.position() != oldCursorPos) {
1247             emit q->cursorPositionChanged();
1248             emit q->microFocusChanged();
1249         }
1250         selectionChanged();
1251     }
1252     repaintOldAndNewSelection(oldSelection);
1253     hadSelectionOnMousePress = cursor.hasSelection();
1254 }
1255
1256 void QQuickTextControlPrivate::mouseMoveEvent(QMouseEvent *e, const QPointF &mousePos)
1257 {
1258     Q_Q(QQuickTextControl);
1259
1260     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1261         QString anchor = q->anchorAt(mousePos);
1262         if (anchor != highlightedAnchor) {
1263             highlightedAnchor = anchor;
1264             emit q->linkHovered(anchor);
1265         }
1266     }
1267
1268     if ((e->buttons() & Qt::LeftButton)) {
1269         const bool editable = interactionFlags & Qt::TextEditable;
1270
1271         if (!(mousePressed
1272               || editable
1273               || selectedWordOnDoubleClick.hasSelection()
1274               || selectedBlockOnTrippleClick.hasSelection()))
1275             return;
1276
1277         const QTextCursor oldSelection = cursor;
1278         const int oldCursorPos = cursor.position();
1279
1280         if (!mousePressed)
1281             return;
1282
1283         const qreal mouseX = qreal(mousePos.x());
1284
1285         int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1286
1287         if (isPreediting()) {
1288             // note: oldCursorPos not including preedit
1289             int selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1290             if (newCursorPos != selectionStartPos) {
1291                 commitPreedit();
1292                 // commit invalidates positions
1293                 newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1294                 selectionStartPos = q->hitTest(mousePressPos, Qt::FuzzyHit);
1295                 setCursorPosition(selectionStartPos);
1296             }
1297         }
1298
1299         if (newCursorPos == -1)
1300             return;
1301
1302         if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1303             selectedWordOnDoubleClick = cursor;
1304             selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1305         }
1306
1307         if (selectedBlockOnTrippleClick.hasSelection())
1308             extendBlockwiseSelection(newCursorPos);
1309         else if (selectedWordOnDoubleClick.hasSelection())
1310             extendWordwiseSelection(newCursorPos, mouseX);
1311         else if (!isPreediting())
1312             setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
1313
1314         if (interactionFlags & Qt::TextEditable) {
1315             if (cursor.position() != oldCursorPos)
1316                 emit q->cursorPositionChanged();
1317             _q_updateCurrentCharFormatAndSelection();
1318             if (qGuiApp)
1319                 qGuiApp->inputPanel()->update(Qt::ImQueryInput);
1320         } else {
1321             if (cursor.position() != oldCursorPos) {
1322                 emit q->cursorPositionChanged();
1323                 emit q->microFocusChanged();
1324             }
1325         }
1326         selectionChanged(true);
1327         repaintOldAndNewSelection(oldSelection);
1328     }
1329
1330     sendMouseEventToInputContext(e, mousePos);
1331 }
1332
1333 void QQuickTextControlPrivate::mouseReleaseEvent(QMouseEvent *e, const QPointF &pos)
1334 {
1335     Q_Q(QQuickTextControl);
1336
1337     if (sendMouseEventToInputContext(e, pos))
1338         return;
1339
1340     const QTextCursor oldSelection = cursor;
1341     const int oldCursorPos = cursor.position();
1342
1343     if (mousePressed) {
1344         mousePressed = false;
1345 #ifndef QT_NO_CLIPBOARD
1346         setClipboardSelection();
1347         selectionChanged(true);
1348     } else if (e->button() == Qt::MidButton
1349                && (interactionFlags & Qt::TextEditable)
1350                && QGuiApplication::clipboard()->supportsSelection()) {
1351         setCursorPosition(pos);
1352         const QMimeData *md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection);
1353         if (md)
1354             q->insertFromMimeData(md);
1355 #endif
1356     }
1357
1358     repaintOldAndNewSelection(oldSelection);
1359
1360     if (cursor.position() != oldCursorPos) {
1361         emit q->cursorPositionChanged();
1362         emit q->microFocusChanged();
1363     }
1364
1365     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1366         if (!(e->button() & Qt::LeftButton))
1367             return;
1368
1369         const QString anchor = q->anchorAt(pos);
1370
1371         if (anchor.isEmpty())
1372             return;
1373
1374         if (!cursor.hasSelection()
1375             || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1376
1377             const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1378             if (anchorPos != -1) {
1379                 cursor.setPosition(anchorPos);
1380
1381                 QString anchor = anchorOnMousePress;
1382                 anchorOnMousePress = QString();
1383                 activateLinkUnderCursor(anchor);
1384             }
1385         }
1386     }
1387 }
1388
1389 void QQuickTextControlPrivate::mouseDoubleClickEvent(QMouseEvent *e, const QPointF &pos)
1390 {
1391     Q_Q(QQuickTextControl);
1392
1393     if (e->button() == Qt::LeftButton && (interactionFlags & Qt::TextSelectableByMouse)) {
1394         commitPreedit();
1395
1396         const QTextCursor oldSelection = cursor;
1397         setCursorPosition(pos);
1398         QTextLine line = currentTextLine(cursor);
1399         bool doEmit = false;
1400         if (line.isValid() && line.textLength()) {
1401             cursor.select(QTextCursor::WordUnderCursor);
1402             doEmit = true;
1403         }
1404         repaintOldAndNewSelection(oldSelection);
1405
1406         cursorIsFocusIndicator = false;
1407         selectedWordOnDoubleClick = cursor;
1408
1409         trippleClickPoint = pos;
1410         trippleClickTimer.start(qApp->styleHints()->mouseDoubleClickInterval(), q);
1411         if (doEmit) {
1412             selectionChanged();
1413 #ifndef QT_NO_CLIPBOARD
1414             setClipboardSelection();
1415 #endif
1416             emit q->cursorPositionChanged();
1417         }
1418     } else if (!sendMouseEventToInputContext(e, pos)) {
1419         e->ignore();
1420     }
1421 }
1422
1423 bool QQuickTextControlPrivate::sendMouseEventToInputContext(QMouseEvent *e, const QPointF &pos)
1424 {
1425 #if !defined(QT_NO_IM)
1426     Q_Q(QQuickTextControl);
1427
1428     Q_UNUSED(e);
1429
1430     if (contextObject && isPreediting()) {
1431         QTextLayout *layout = cursor.block().layout();
1432         int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
1433
1434         if (cursorPos >= 0 && cursorPos <= layout->preeditAreaText().length()) {
1435             if (e->type() == QEvent::MouseButtonRelease) {
1436                 qApp->inputPanel()->invokeAction(QInputPanel::Click, cursorPos);
1437             }
1438
1439             return true;
1440         }
1441     }
1442 #else
1443     Q_UNUSED(e);
1444     Q_UNUSED(pos);
1445 #endif
1446     return false;
1447 }
1448
1449 void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
1450 {
1451     Q_Q(QQuickTextControl);
1452     if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
1453         e->ignore();
1454         return;
1455     }
1456     bool isGettingInput = !e->commitString().isEmpty()
1457             || e->preeditString() != cursor.block().layout()->preeditAreaText()
1458             || e->replacementLength() > 0;
1459     bool forceSelectionChanged = false;
1460
1461     cursor.beginEditBlock();
1462     if (isGettingInput) {
1463         cursor.removeSelectedText();
1464     }
1465
1466     // insert commit string
1467     if (!e->commitString().isEmpty() || e->replacementLength()) {
1468         QTextCursor c = cursor;
1469         c.setPosition(c.position() + e->replacementStart());
1470         c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
1471         c.insertText(e->commitString());
1472     }
1473
1474     for (int i = 0; i < e->attributes().size(); ++i) {
1475         const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1476         if (a.type == QInputMethodEvent::Selection) {
1477             QTextCursor oldCursor = cursor;
1478             int blockStart = a.start + cursor.block().position();
1479             cursor.setPosition(blockStart, QTextCursor::MoveAnchor);
1480             cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
1481             q->ensureCursorVisible();
1482             repaintOldAndNewSelection(oldCursor);
1483             forceSelectionChanged = true;
1484         }
1485     }
1486
1487     QTextBlock block = cursor.block();
1488     QTextLayout *layout = block.layout();
1489     if (isGettingInput)
1490         layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
1491     QList<QTextLayout::FormatRange> overrides;
1492     const int oldPreeditCursor = preeditCursor;
1493     preeditCursor = e->preeditString().length();
1494     hideCursor = false;
1495     for (int i = 0; i < e->attributes().size(); ++i) {
1496         const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1497         if (a.type == QInputMethodEvent::Cursor) {
1498             preeditCursor = a.start;
1499             hideCursor = !a.length;
1500         } else if (a.type == QInputMethodEvent::TextFormat) {
1501             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
1502             if (f.isValid()) {
1503                 QTextLayout::FormatRange o;
1504                 o.start = a.start + cursor.position() - block.position();
1505                 o.length = a.length;
1506                 o.format = f;
1507                 overrides.append(o);
1508             }
1509         }
1510     }
1511     layout->setAdditionalFormats(overrides);
1512     tentativeCommit = e->tentativeCommitString();
1513
1514     cursor.endEditBlock();
1515
1516     QTextCursorPrivate *cursor_d = QTextCursorPrivate::getPrivate(&cursor);
1517     if (cursor_d)
1518         cursor_d->setX();
1519     if (oldPreeditCursor != preeditCursor)
1520         emit q->microFocusChanged();
1521     selectionChanged(forceSelectionChanged);
1522 }
1523
1524 QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
1525 {
1526     Q_D(const QQuickTextControl);
1527     QTextBlock block = d->cursor.block();
1528     switch (property) {
1529     case Qt::ImCursorRectangle:
1530         return cursorRect();
1531     case Qt::ImFont:
1532         return QVariant(d->cursor.charFormat().font());
1533     case Qt::ImCursorPosition:
1534         return QVariant(d->cursor.position() - block.position());
1535     case Qt::ImSurroundingText:
1536         return QVariant(block.text());
1537     case Qt::ImCurrentSelection:
1538         return QVariant(d->cursor.selectedText());
1539     case Qt::ImMaximumTextLength:
1540         return QVariant(); // No limit.
1541     case Qt::ImAnchorPosition:
1542         return QVariant(d->cursor.anchor() - block.position());
1543     default:
1544         return QVariant();
1545     }
1546 }
1547
1548 void QQuickTextControl::setFocus(bool focus, Qt::FocusReason reason)
1549 {
1550     QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
1551                    reason);
1552     processEvent(&ev);
1553 }
1554
1555 void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
1556 {
1557     Q_Q(QQuickTextControl);
1558     emit q->updateRequest(q->selectionRect());
1559     if (e->gotFocus()) {
1560         setBlinkingCursorEnabled(interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard));
1561     } else {
1562         commitPreedit();
1563         setBlinkingCursorEnabled(false);
1564
1565         if (cursorIsFocusIndicator
1566             && e->reason() != Qt::ActiveWindowFocusReason
1567             && e->reason() != Qt::PopupFocusReason
1568             && cursor.hasSelection()) {
1569             cursor.clearSelection();
1570         }
1571     }
1572     hasFocus = e->gotFocus();
1573 }
1574
1575 QString QQuickTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
1576 {
1577     if (anchorCursor.hasSelection()) {
1578         QTextCursor cursor = anchorCursor;
1579         if (cursor.selectionStart() != cursor.position())
1580             cursor.setPosition(cursor.selectionStart());
1581         cursor.movePosition(QTextCursor::NextCharacter);
1582         QTextCharFormat fmt = cursor.charFormat();
1583         if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
1584             return fmt.stringProperty(QTextFormat::AnchorHref);
1585     }
1586     return QString();
1587 }
1588
1589 QTextCursor QQuickTextControl::cursorForPosition(const QPointF &pos) const
1590 {
1591     Q_D(const QQuickTextControl);
1592     int cursorPos = hitTest(pos, Qt::FuzzyHit);
1593     if (cursorPos == -1)
1594         cursorPos = 0;
1595     QTextCursor c(d->doc);
1596     c.setPosition(cursorPos);
1597     return c;
1598 }
1599
1600 QRectF QQuickTextControl::cursorRect(const QTextCursor &cursor) const
1601 {
1602     Q_D(const QQuickTextControl);
1603     if (cursor.isNull())
1604         return QRectF();
1605
1606     return d->rectForPosition(cursor.position());
1607 }
1608
1609 QRectF QQuickTextControl::cursorRect() const
1610 {
1611     Q_D(const QQuickTextControl);
1612     return cursorRect(d->cursor);
1613 }
1614
1615 QRectF QQuickTextControlPrivate::cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
1616 {
1617     if (cursor.isNull())
1618         return QRectF();
1619
1620     return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
1621 }
1622
1623 QString QQuickTextControl::anchorAt(const QPointF &pos) const
1624 {
1625     Q_D(const QQuickTextControl);
1626     return d->doc->documentLayout()->anchorAt(pos);
1627 }
1628
1629 QString QQuickTextControl::anchorAtCursor() const
1630 {
1631     Q_D(const QQuickTextControl);
1632
1633     return d->anchorForCursor(d->cursor);
1634 }
1635
1636 int QQuickTextControl::cursorWidth() const
1637 {
1638 #ifndef QT_NO_PROPERTIES
1639     Q_D(const QQuickTextControl);
1640     return d->doc->documentLayout()->property("cursorWidth").toInt();
1641 #else
1642     return 1;
1643 #endif
1644 }
1645
1646 void QQuickTextControl::setCursorWidth(int width)
1647 {
1648     Q_D(QQuickTextControl);
1649 #ifdef QT_NO_PROPERTIES
1650     Q_UNUSED(width);
1651 #else
1652     if (width == -1)
1653         width = textCursorWidth;
1654     d->doc->documentLayout()->setProperty("cursorWidth", width);
1655 #endif
1656     d->repaintCursor();
1657 }
1658
1659 bool QQuickTextControl::acceptRichText() const
1660 {
1661     Q_D(const QQuickTextControl);
1662     return d->acceptRichText;
1663 }
1664
1665 void QQuickTextControl::setAcceptRichText(bool accept)
1666 {
1667     Q_D(QQuickTextControl);
1668     d->acceptRichText = accept;
1669 }
1670
1671 void QQuickTextControl::setTextWidth(qreal width)
1672 {
1673     Q_D(QQuickTextControl);
1674     d->doc->setTextWidth(width);
1675 }
1676
1677 qreal QQuickTextControl::textWidth() const
1678 {
1679     Q_D(const QQuickTextControl);
1680     return d->doc->textWidth();
1681 }
1682
1683 QSizeF QQuickTextControl::size() const
1684 {
1685     Q_D(const QQuickTextControl);
1686     return d->doc->size();
1687 }
1688
1689 void QQuickTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
1690 {
1691     Q_D(QQuickTextControl);
1692     const QTextCursor oldSelection = d->cursor;
1693     const bool moved = d->cursor.movePosition(op, mode);
1694     d->_q_updateCurrentCharFormatAndSelection();
1695     ensureCursorVisible();
1696     d->repaintOldAndNewSelection(oldSelection);
1697     if (moved)
1698         emit cursorPositionChanged();
1699 }
1700
1701 bool QQuickTextControl::canPaste() const
1702 {
1703 #ifndef QT_NO_CLIPBOARD
1704     Q_D(const QQuickTextControl);
1705     if (d->interactionFlags & Qt::TextEditable) {
1706         const QMimeData *md = QGuiApplication::clipboard()->mimeData();
1707         return md && canInsertFromMimeData(md);
1708     }
1709 #endif
1710     return false;
1711 }
1712
1713 void QQuickTextControl::setCursorIsFocusIndicator(bool b)
1714 {
1715     Q_D(QQuickTextControl);
1716     d->cursorIsFocusIndicator = b;
1717     d->repaintCursor();
1718 }
1719
1720 bool QQuickTextControl::cursorIsFocusIndicator() const
1721 {
1722     Q_D(const QQuickTextControl);
1723     return d->cursorIsFocusIndicator;
1724 }
1725
1726 void QQuickTextControl::setWordSelectionEnabled(bool enabled)
1727 {
1728     Q_D(QQuickTextControl);
1729     d->wordSelectionEnabled = enabled;
1730 }
1731
1732 bool QQuickTextControl::isWordSelectionEnabled() const
1733 {
1734     Q_D(const QQuickTextControl);
1735     return d->wordSelectionEnabled;
1736 }
1737
1738 QMimeData *QQuickTextControl::createMimeDataFromSelection() const
1739 {
1740     Q_D(const QQuickTextControl);
1741     const QTextDocumentFragment fragment(d->cursor);
1742     return new QQuickTextEditMimeData(fragment);
1743 }
1744
1745 bool QQuickTextControl::canInsertFromMimeData(const QMimeData *source) const
1746 {
1747     Q_D(const QQuickTextControl);
1748     if (d->acceptRichText)
1749         return (source->hasText() && !source->text().isEmpty())
1750             || source->hasHtml()
1751             || source->hasFormat(QLatin1String("application/x-qrichtext"))
1752             || source->hasFormat(QLatin1String("application/x-qt-richtext"));
1753     else
1754         return source->hasText() && !source->text().isEmpty();
1755 }
1756
1757 void QQuickTextControl::insertFromMimeData(const QMimeData *source)
1758 {
1759     Q_D(QQuickTextControl);
1760     if (!(d->interactionFlags & Qt::TextEditable) || !source)
1761         return;
1762
1763     bool hasData = false;
1764     QTextDocumentFragment fragment;
1765 #ifndef QT_NO_TEXTHTMLPARSER
1766     if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
1767         // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
1768         QString richtext = QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
1769         richtext.prepend(QLatin1String("<meta name=\"qrichtext\" content=\"1\" />"));
1770         fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
1771         hasData = true;
1772     } else if (source->hasHtml() && d->acceptRichText) {
1773         fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
1774         hasData = true;
1775     } else {
1776         QString text = source->text();
1777         if (!text.isNull()) {
1778             fragment = QTextDocumentFragment::fromPlainText(text);
1779             hasData = true;
1780         }
1781     }
1782 #else
1783     fragment = QTextDocumentFragment::fromPlainText(source->text());
1784 #endif // QT_NO_TEXTHTMLPARSER
1785
1786     if (hasData)
1787         d->cursor.insertFragment(fragment);
1788     ensureCursorVisible();
1789 }
1790
1791 void QQuickTextControlPrivate::activateLinkUnderCursor(QString href)
1792 {
1793     QTextCursor oldCursor = cursor;
1794
1795     if (href.isEmpty()) {
1796         QTextCursor tmp = cursor;
1797         if (tmp.selectionStart() != tmp.position())
1798             tmp.setPosition(tmp.selectionStart());
1799         tmp.movePosition(QTextCursor::NextCharacter);
1800         href = tmp.charFormat().anchorHref();
1801     }
1802     if (href.isEmpty())
1803         return;
1804
1805     if (!cursor.hasSelection()) {
1806         QTextBlock block = cursor.block();
1807         const int cursorPos = cursor.position();
1808
1809         QTextBlock::Iterator it = block.begin();
1810         QTextBlock::Iterator linkFragment;
1811
1812         for (; !it.atEnd(); ++it) {
1813             QTextFragment fragment = it.fragment();
1814             const int fragmentPos = fragment.position();
1815             if (fragmentPos <= cursorPos &&
1816                 fragmentPos + fragment.length() > cursorPos) {
1817                 linkFragment = it;
1818                 break;
1819             }
1820         }
1821
1822         if (!linkFragment.atEnd()) {
1823             it = linkFragment;
1824             cursor.setPosition(it.fragment().position());
1825             if (it != block.begin()) {
1826                 do {
1827                     --it;
1828                     QTextFragment fragment = it.fragment();
1829                     if (fragment.charFormat().anchorHref() != href)
1830                         break;
1831                     cursor.setPosition(fragment.position());
1832                 } while (it != block.begin());
1833             }
1834
1835             for (it = linkFragment; !it.atEnd(); ++it) {
1836                 QTextFragment fragment = it.fragment();
1837                 if (fragment.charFormat().anchorHref() != href)
1838                     break;
1839                 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
1840             }
1841         }
1842     }
1843
1844     if (hasFocus) {
1845         cursorIsFocusIndicator = true;
1846     } else {
1847         cursorIsFocusIndicator = false;
1848         cursor.clearSelection();
1849     }
1850     repaintOldAndNewSelection(oldCursor);
1851
1852     emit q_func()->linkActivated(href);
1853 }
1854
1855 bool QQuickTextControlPrivate::isPreediting() const
1856 {
1857     QTextLayout *layout = cursor.block().layout();
1858     if (layout && !layout->preeditAreaText().isEmpty())
1859         return true;
1860
1861     return false;
1862 }
1863
1864 void QQuickTextControlPrivate::commitPreedit()
1865 {
1866     if (!isPreediting())
1867         return;
1868
1869     cursor.beginEditBlock();
1870     qApp->inputPanel()->reset();
1871
1872     if (!tentativeCommit.isEmpty()) {
1873         cursor.insertText(tentativeCommit);
1874         tentativeCommit.clear();
1875     }
1876
1877     preeditCursor = 0;
1878     QTextBlock block = cursor.block();
1879     QTextLayout *layout = block.layout();
1880     layout->setPreeditArea(-1, QString());
1881     layout->clearAdditionalFormats();
1882     cursor.endEditBlock();
1883 }
1884
1885 void QQuickTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1886 {
1887     Q_D(QQuickTextControl);
1888     if (flags == d->interactionFlags)
1889         return;
1890     d->interactionFlags = flags;
1891
1892     if (d->hasFocus)
1893         d->setBlinkingCursorEnabled(flags & (Qt::TextEditable | Qt::TextSelectableByKeyboard));
1894 }
1895
1896 Qt::TextInteractionFlags QQuickTextControl::textInteractionFlags() const
1897 {
1898     Q_D(const QQuickTextControl);
1899     return d->interactionFlags;
1900 }
1901
1902 QString QQuickTextControl::toPlainText() const
1903 {
1904     Q_D(const QQuickTextControl);
1905     QString plainText = document()->toPlainText();
1906     if (!d->tentativeCommit.isEmpty())
1907         plainText.insert(textCursor().position(), d->tentativeCommit);
1908     return plainText;
1909 }
1910
1911 #ifndef QT_NO_TEXTHTMLPARSER
1912 QString QQuickTextControl::toHtml() const
1913 {
1914     // note: currently not including tentative commit
1915     return document()->toHtml();
1916 }
1917 #endif
1918
1919 void QQuickTextControl::ensureCursorVisible()
1920 {
1921     Q_D(QQuickTextControl);
1922     QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
1923     emit visibilityRequest(crect);
1924     emit microFocusChanged();
1925 }
1926
1927 QPalette QQuickTextControl::palette() const
1928 {
1929     Q_D(const QQuickTextControl);
1930     return d->palette;
1931 }
1932
1933 void QQuickTextControl::setPalette(const QPalette &pal)
1934 {
1935     Q_D(QQuickTextControl);
1936     d->palette = pal;
1937 }
1938
1939 bool QQuickTextControl::cursorOn() const
1940 {
1941     Q_D(const QQuickTextControl);
1942     return d->cursorOn;
1943 }
1944
1945 QAbstractTextDocumentLayout::PaintContext QQuickTextControl::getPaintContext() const
1946 {
1947     Q_D(const QQuickTextControl);
1948
1949     QAbstractTextDocumentLayout::PaintContext ctx;
1950
1951     ctx.palette = d->palette;
1952     if (d->cursorOn && d->isEnabled) {
1953         if (d->hideCursor)
1954             ctx.cursorPosition = -1;
1955         else if (d->preeditCursor != 0)
1956             ctx.cursorPosition = - (d->preeditCursor + 2);
1957         else
1958             ctx.cursorPosition = d->cursor.position();
1959     }
1960
1961     if (d->cursor.hasSelection()) {
1962         QAbstractTextDocumentLayout::Selection selection;
1963         selection.cursor = d->cursor;
1964         if (0 && d->cursorIsFocusIndicator) {
1965 #if 0
1966             // ###
1967             QStyleOption opt;
1968             opt.palette = ctx.palette;
1969             QStyleHintReturnVariant ret;
1970             QStyle *style = QGuiApplication::style();
1971             if (widget)
1972                 style = widget->style();
1973             style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
1974             selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
1975 #endif
1976         } else {
1977             QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
1978             selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
1979             selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
1980             if (fullWidthSelection)
1981                 selection.format.setProperty(QTextFormat::FullWidthSelection, true);
1982         }
1983         ctx.selections.append(selection);
1984     }
1985
1986     return ctx;
1987 }
1988
1989 void QQuickTextControl::drawContents(QPainter *p, const QRectF &rect)
1990 {
1991     Q_D(QQuickTextControl);
1992     p->save();
1993     QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext();
1994     if (rect.isValid())
1995         p->setClipRect(rect, Qt::IntersectClip);
1996     ctx.clip = rect;
1997
1998     d->doc->documentLayout()->draw(p, ctx);
1999     p->restore();
2000 }
2001
2002 int QQuickTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
2003 {
2004     Q_D(const QQuickTextControl);
2005     return d->doc->documentLayout()->hitTest(point, accuracy);
2006 }
2007
2008 QRectF QQuickTextControl::blockBoundingRect(const QTextBlock &block) const
2009 {
2010     Q_D(const QQuickTextControl);
2011     return d->doc->documentLayout()->blockBoundingRect(block);
2012 }
2013
2014
2015
2016 QStringList QQuickTextEditMimeData::formats() const
2017 {
2018     if (!fragment.isEmpty())
2019         return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html")
2020 #ifndef QT_NO_TEXTODFWRITER
2021             << QString::fromLatin1("application/vnd.oasis.opendocument.text")
2022 #endif
2023         ;
2024     else
2025         return QMimeData::formats();
2026 }
2027
2028 QVariant QQuickTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
2029 {
2030     if (!fragment.isEmpty())
2031         setup();
2032     return QMimeData::retrieveData(mimeType, type);
2033 }
2034
2035 void QQuickTextEditMimeData::setup() const
2036 {
2037     QQuickTextEditMimeData *that = const_cast<QQuickTextEditMimeData *>(this);
2038 #ifndef QT_NO_TEXTHTMLPARSER
2039     that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
2040 #endif
2041 #ifndef QT_NO_TEXTODFWRITER
2042     {
2043         QBuffer buffer;
2044         QTextDocumentWriter writer(&buffer, "ODF");
2045         writer.write(fragment);
2046         buffer.close();
2047         that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
2048     }
2049 #endif
2050     that->setText(fragment.toPlainText());
2051     fragment = QTextDocumentFragment();
2052 }
2053
2054
2055 QT_END_NAMESPACE
2056
2057 #include "moc_qquicktextcontrol_p.cpp"
2058
2059 #endif // QT_NO_TEXTCONTROL