68dad9fe7a8de71003f2c050619b4ab2d64a0ca6
[profile/ivi/qtbase.git] / src / widgets / widgets / qwidgettextcontrol.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 "qwidgettextcontrol_p.h"
43 #include "qwidgettextcontrol_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 <qmenu.h>
54 #include <qstyle.h>
55 #include <qtimer.h>
56 #include "private/qtextdocumentlayout_p.h"
57 #include "private/qabstracttextdocumentlayout_p.h"
58 #include "private/qtextedit_p.h"
59 #include "qtextdocument.h"
60 #include "private/qtextdocument_p.h"
61 #include "qtextlist.h"
62 #include "private/qwidgettextcontrol_p.h"
63 #include "qgraphicssceneevent.h"
64 #include "qpagedpaintdevice.h"
65 #include "private/qpagedpaintdevice_p.h"
66 #include "qtextdocumentwriter.h"
67 #include "private/qtextcursor_p.h"
68
69 #include <qtextformat.h>
70 #include <qdatetime.h>
71 #include <qbuffer.h>
72 #include <qapplication.h>
73 #include <limits.h>
74 #include <qtexttable.h>
75 #include <qvariant.h>
76 #include <qurl.h>
77 #include <qdesktopservices.h>
78 #include <qinputcontext.h>
79 #include <qtooltip.h>
80 #include <qstyleoption.h>
81 #include <QtWidgets/qlineedit.h>
82
83 #ifndef QT_NO_SHORTCUT
84 #include "private/qapplication_p.h"
85 #include "private/qshortcutmap_p.h"
86 #include <qkeysequence.h>
87 #define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? QLatin1Char('\t') + QString(QKeySequence(k)) : QString())
88 #else
89 #define ACCEL_KEY(k) QString()
90 #endif
91
92 QT_BEGIN_NAMESPACE
93
94 #ifndef QT_NO_CONTEXTMENU
95 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
96 extern bool qt_use_rtl_extensions;
97 #endif
98 #endif
99
100 // could go into QTextCursor...
101 static QTextLine currentTextLine(const QTextCursor &cursor)
102 {
103     const QTextBlock block = cursor.block();
104     if (!block.isValid())
105         return QTextLine();
106
107     const QTextLayout *layout = block.layout();
108     if (!layout)
109         return QTextLine();
110
111     const int relativePos = cursor.position() - block.position();
112     return layout->lineForTextPosition(relativePos);
113 }
114
115 QWidgetTextControlPrivate::QWidgetTextControlPrivate()
116     : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
117       interactionFlags(Qt::TextEditorInteraction),
118       dragEnabled(true),
119 #ifndef QT_NO_DRAGANDDROP
120       mousePressed(false), mightStartDrag(false),
121 #endif
122       lastSelectionPosition(0), lastSelectionAnchor(0),
123       ignoreAutomaticScrollbarAdjustement(false),
124       overwriteMode(false),
125       acceptRichText(true),
126       preeditCursor(0), hideCursor(false),
127       hasFocus(false),
128 #ifdef QT_KEYPAD_NAVIGATION
129       hasEditFocus(false),
130 #endif
131       isEnabled(true),
132       hadSelectionOnMousePress(false),
133       ignoreUnusedNavigationEvents(false),
134       openExternalLinks(false),
135       wordSelectionEnabled(false)
136 {}
137
138 bool QWidgetTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
139 {
140 #ifdef QT_NO_SHORTCUT
141     Q_UNUSED(e);
142 #endif
143
144     Q_Q(QWidgetTextControl);
145     if (cursor.isNull())
146         return false;
147
148     const QTextCursor oldSelection = cursor;
149     const int oldCursorPos = cursor.position();
150
151     QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
152     QTextCursor::MoveOperation op = QTextCursor::NoMove;
153
154     if (false) {
155     }
156 #ifndef QT_NO_SHORTCUT
157     if (e == QKeySequence::MoveToNextChar) {
158             op = QTextCursor::Right;
159     }
160     else if (e == QKeySequence::MoveToPreviousChar) {
161             op = QTextCursor::Left;
162     }
163     else if (e == QKeySequence::SelectNextChar) {
164            op = QTextCursor::Right;
165            mode = QTextCursor::KeepAnchor;
166     }
167     else if (e == QKeySequence::SelectPreviousChar) {
168             op = QTextCursor::Left;
169             mode = QTextCursor::KeepAnchor;
170     }
171     else if (e == QKeySequence::SelectNextWord) {
172             op = QTextCursor::WordRight;
173             mode = QTextCursor::KeepAnchor;
174     }
175     else if (e == QKeySequence::SelectPreviousWord) {
176             op = QTextCursor::WordLeft;
177             mode = QTextCursor::KeepAnchor;
178     }
179     else if (e == QKeySequence::SelectStartOfLine) {
180             op = QTextCursor::StartOfLine;
181             mode = QTextCursor::KeepAnchor;
182     }
183     else if (e == QKeySequence::SelectEndOfLine) {
184             op = QTextCursor::EndOfLine;
185             mode = QTextCursor::KeepAnchor;
186     }
187     else if (e == QKeySequence::SelectStartOfBlock) {
188             op = QTextCursor::StartOfBlock;
189             mode = QTextCursor::KeepAnchor;
190     }
191     else if (e == QKeySequence::SelectEndOfBlock) {
192             op = QTextCursor::EndOfBlock;
193             mode = QTextCursor::KeepAnchor;
194     }
195     else if (e == QKeySequence::SelectStartOfDocument) {
196             op = QTextCursor::Start;
197             mode = QTextCursor::KeepAnchor;
198     }
199     else if (e == QKeySequence::SelectEndOfDocument) {
200             op = QTextCursor::End;
201             mode = QTextCursor::KeepAnchor;
202     }
203     else if (e == QKeySequence::SelectPreviousLine) {
204             op = QTextCursor::Up;
205             mode = QTextCursor::KeepAnchor;
206     }
207     else if (e == QKeySequence::SelectNextLine) {
208             op = QTextCursor::Down;
209             mode = QTextCursor::KeepAnchor;
210             {
211                 QTextBlock block = cursor.block();
212                 QTextLine line = currentTextLine(cursor);
213                 if (!block.next().isValid()
214                     && line.isValid()
215                     && line.lineNumber() == block.layout()->lineCount() - 1)
216                     op = QTextCursor::End;
217             }
218     }
219     else if (e == QKeySequence::MoveToNextWord) {
220             op = QTextCursor::WordRight;
221     }
222     else if (e == QKeySequence::MoveToPreviousWord) {
223             op = QTextCursor::WordLeft;
224     }
225     else if (e == QKeySequence::MoveToEndOfBlock) {
226             op = QTextCursor::EndOfBlock;
227     }
228     else if (e == QKeySequence::MoveToStartOfBlock) {
229             op = QTextCursor::StartOfBlock;
230     }
231     else if (e == QKeySequence::MoveToNextLine) {
232             op = QTextCursor::Down;
233     }
234     else if (e == QKeySequence::MoveToPreviousLine) {
235             op = QTextCursor::Up;
236     }
237     else if (e == QKeySequence::MoveToPreviousLine) {
238             op = QTextCursor::Up;
239     }
240     else if (e == QKeySequence::MoveToStartOfLine) {
241             op = QTextCursor::StartOfLine;
242     }
243     else if (e == QKeySequence::MoveToEndOfLine) {
244             op = QTextCursor::EndOfLine;
245     }
246     else if (e == QKeySequence::MoveToStartOfDocument) {
247             op = QTextCursor::Start;
248     }
249     else if (e == QKeySequence::MoveToEndOfDocument) {
250             op = QTextCursor::End;
251     }
252 #endif // QT_NO_SHORTCUT
253     else {
254         return false;
255     }
256
257 // Except for pageup and pagedown, Mac OS X has very different behavior, we don't do it all, but
258 // here's the breakdown:
259 // Shift still works as an anchor, but only one of the other keys can be down Ctrl (Command),
260 // Alt (Option), or Meta (Control).
261 // Command/Control + Left/Right -- Move to left or right of the line
262 //                 + Up/Down -- Move to top bottom of the file. (Control doesn't move the cursor)
263 // Option + Left/Right -- Move one word Left/right.
264 //        + Up/Down  -- Begin/End of Paragraph.
265 // Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
266
267     bool visualNavigation = cursor.visualNavigation();
268     cursor.setVisualNavigation(true);
269     const bool moved = cursor.movePosition(op, mode);
270     cursor.setVisualNavigation(visualNavigation);
271     q->ensureCursorVisible();
272
273     bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
274     bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
275
276 #ifdef QT_KEYPAD_NAVIGATION
277     ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled();
278     isNavigationEvent = isNavigationEvent ||
279                         (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
280                          && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
281 #else
282     isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
283 #endif
284
285     if (moved) {
286         if (cursor.position() != oldCursorPos)
287             emit q->cursorPositionChanged();
288         emit q->microFocusChanged();
289     } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
290         return false;
291     }
292
293     selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
294
295     repaintOldAndNewSelection(oldSelection);
296
297     return true;
298 }
299
300 void QWidgetTextControlPrivate::updateCurrentCharFormat()
301 {
302     Q_Q(QWidgetTextControl);
303
304     QTextCharFormat fmt = cursor.charFormat();
305     if (fmt == lastCharFormat)
306         return;
307     lastCharFormat = fmt;
308
309     emit q->currentCharFormatChanged(fmt);
310     emit q->microFocusChanged();
311 }
312
313 void QWidgetTextControlPrivate::indent()
314 {
315     QTextBlockFormat blockFmt = cursor.blockFormat();
316
317     QTextList *list = cursor.currentList();
318     if (!list) {
319         QTextBlockFormat modifier;
320         modifier.setIndent(blockFmt.indent() + 1);
321         cursor.mergeBlockFormat(modifier);
322     } else {
323         QTextListFormat format = list->format();
324         format.setIndent(format.indent() + 1);
325
326         if (list->itemNumber(cursor.block()) == 1)
327             list->setFormat(format);
328         else
329             cursor.createList(format);
330     }
331 }
332
333 void QWidgetTextControlPrivate::outdent()
334 {
335     QTextBlockFormat blockFmt = cursor.blockFormat();
336
337     QTextList *list = cursor.currentList();
338
339     if (!list) {
340         QTextBlockFormat modifier;
341         modifier.setIndent(blockFmt.indent() - 1);
342         cursor.mergeBlockFormat(modifier);
343     } else {
344         QTextListFormat listFmt = list->format();
345         listFmt.setIndent(listFmt.indent() - 1);
346         list->setFormat(listFmt);
347     }
348 }
349
350 void QWidgetTextControlPrivate::gotoNextTableCell()
351 {
352     QTextTable *table = cursor.currentTable();
353     QTextTableCell cell = table->cellAt(cursor);
354
355     int newColumn = cell.column() + cell.columnSpan();
356     int newRow = cell.row();
357
358     if (newColumn >= table->columns()) {
359         newColumn = 0;
360         ++newRow;
361         if (newRow >= table->rows())
362             table->insertRows(table->rows(), 1);
363     }
364
365     cell = table->cellAt(newRow, newColumn);
366     cursor = cell.firstCursorPosition();
367 }
368
369 void QWidgetTextControlPrivate::gotoPreviousTableCell()
370 {
371     QTextTable *table = cursor.currentTable();
372     QTextTableCell cell = table->cellAt(cursor);
373
374     int newColumn = cell.column() - 1;
375     int newRow = cell.row();
376
377     if (newColumn < 0) {
378         newColumn = table->columns() - 1;
379         --newRow;
380         if (newRow < 0)
381             return;
382     }
383
384     cell = table->cellAt(newRow, newColumn);
385     cursor = cell.firstCursorPosition();
386 }
387
388 void QWidgetTextControlPrivate::createAutoBulletList()
389 {
390     cursor.beginEditBlock();
391
392     QTextBlockFormat blockFmt = cursor.blockFormat();
393
394     QTextListFormat listFmt;
395     listFmt.setStyle(QTextListFormat::ListDisc);
396     listFmt.setIndent(blockFmt.indent() + 1);
397
398     blockFmt.setIndent(0);
399     cursor.setBlockFormat(blockFmt);
400
401     cursor.createList(listFmt);
402
403     cursor.endEditBlock();
404 }
405
406 void QWidgetTextControlPrivate::init(Qt::TextFormat format, const QString &text, QTextDocument *document)
407 {
408     Q_Q(QWidgetTextControl);
409     setContent(format, text, document);
410
411     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
412     q->setCursorWidth(-1);
413 }
414
415 void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
416 {
417     Q_Q(QWidgetTextControl);
418
419     // for use when called from setPlainText. we may want to re-use the currently
420     // set char format then.
421     const QTextCharFormat charFormatForInsertion = cursor.charFormat();
422
423     bool clearDocument = true;
424     if (!doc) {
425         if (document) {
426             doc = document;
427             clearDocument = false;
428         } else {
429             palette = QApplication::palette("QWidgetTextControl");
430             doc = new QTextDocument(q);
431         }
432         _q_documentLayoutChanged();
433         cursor = QTextCursor(doc);
434
435 // ####        doc->documentLayout()->setPaintDevice(viewport);
436
437         QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
438         QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
439         QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged()));
440
441         // convenience signal forwards
442         QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
443         QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
444         QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
445         QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
446     }
447
448     bool previousUndoRedoState = doc->isUndoRedoEnabled();
449     if (!document)
450         doc->setUndoRedoEnabled(false);
451
452     //Saving the index save some time.
453     static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()");
454     static int textChangedIndex = QWidgetTextControl::staticMetaObject.indexOfSignal("textChanged()");
455     // avoid multiple textChanged() signals being emitted
456     QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
457
458     if (!text.isEmpty()) {
459         // clear 'our' cursor for insertion to prevent
460         // the emission of the cursorPositionChanged() signal.
461         // instead we emit it only once at the end instead of
462         // at the end of the document after loading and when
463         // positioning the cursor again to the start of the
464         // document.
465         cursor = QTextCursor();
466         if (format == Qt::PlainText) {
467             QTextCursor formatCursor(doc);
468             // put the setPlainText and the setCharFormat into one edit block,
469             // so that the syntax highlight triggers only /once/ for the entire
470             // document, not twice.
471             formatCursor.beginEditBlock();
472             doc->setPlainText(text);
473             doc->setUndoRedoEnabled(false);
474             formatCursor.select(QTextCursor::Document);
475             formatCursor.setCharFormat(charFormatForInsertion);
476             formatCursor.endEditBlock();
477         } else {
478 #ifndef QT_NO_TEXTHTMLPARSER
479             doc->setHtml(text);
480 #else
481             doc->setPlainText(text);
482 #endif
483             doc->setUndoRedoEnabled(false);
484         }
485         cursor = QTextCursor(doc);
486     } else if (clearDocument) {
487         doc->clear();
488     }
489     cursor.setCharFormat(charFormatForInsertion);
490
491     QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
492     emit q->textChanged();
493     if (!document)
494         doc->setUndoRedoEnabled(previousUndoRedoState);
495     _q_updateCurrentCharFormatAndSelection();
496     if (!document)
497         doc->setModified(false);
498
499     q->ensureCursorVisible();
500     emit q->cursorPositionChanged();
501 }
502
503 void QWidgetTextControlPrivate::startDrag()
504 {
505 #ifndef QT_NO_DRAGANDDROP
506     Q_Q(QWidgetTextControl);
507     mousePressed = false;
508     if (!contextWidget)
509         return;
510     QMimeData *data = q->createMimeDataFromSelection();
511
512     QDrag *drag = new QDrag(contextWidget);
513     drag->setMimeData(data);
514
515     Qt::DropActions actions = Qt::CopyAction;
516     Qt::DropAction action;
517     if (interactionFlags & Qt::TextEditable) {
518         actions |= Qt::MoveAction;
519         action = drag->exec(actions, Qt::MoveAction);
520     } else {
521         action = drag->exec(actions, Qt::CopyAction);
522     }
523
524     if (action == Qt::MoveAction && drag->target() != contextWidget)
525         cursor.removeSelectedText();
526 #endif
527 }
528
529 void QWidgetTextControlPrivate::setCursorPosition(const QPointF &pos)
530 {
531     Q_Q(QWidgetTextControl);
532     const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
533     if (cursorPos == -1)
534         return;
535     cursor.setPosition(cursorPos);
536 }
537
538 void QWidgetTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
539 {
540     cursor.setPosition(pos, mode);
541
542     if (mode != QTextCursor::KeepAnchor) {
543         selectedWordOnDoubleClick = QTextCursor();
544         selectedBlockOnTrippleClick = QTextCursor();
545     }
546 }
547
548 void QWidgetTextControlPrivate::repaintCursor()
549 {
550     Q_Q(QWidgetTextControl);
551     emit q->updateRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
552 }
553
554 void QWidgetTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
555 {
556     Q_Q(QWidgetTextControl);
557     if (cursor.hasSelection()
558         && oldSelection.hasSelection()
559         && cursor.currentFrame() == oldSelection.currentFrame()
560         && !cursor.hasComplexSelection()
561         && !oldSelection.hasComplexSelection()
562         && cursor.anchor() == oldSelection.anchor()
563         ) {
564         QTextCursor differenceSelection(doc);
565         differenceSelection.setPosition(oldSelection.position());
566         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
567         emit q->updateRequest(q->selectionRect(differenceSelection));
568     } else {
569         if (!oldSelection.isNull())
570             emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
571         emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
572     }
573 }
574
575 void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
576 {
577     Q_Q(QWidgetTextControl);
578     if (forceEmitSelectionChanged)
579         emit q->selectionChanged();
580
581     if (cursor.position() == lastSelectionPosition
582         && cursor.anchor() == lastSelectionAnchor)
583         return;
584
585     bool selectionStateChange = (cursor.hasSelection()
586                                  != (lastSelectionPosition != lastSelectionAnchor));
587     if (selectionStateChange)
588         emit q->copyAvailable(cursor.hasSelection());
589
590     if (!forceEmitSelectionChanged
591         && (selectionStateChange
592             || (cursor.hasSelection()
593                 && (cursor.position() != lastSelectionPosition
594                     || cursor.anchor() != lastSelectionAnchor))))
595         emit q->selectionChanged();
596
597     emit q->microFocusChanged();
598     lastSelectionPosition = cursor.position();
599     lastSelectionAnchor = cursor.anchor();
600 }
601
602 void QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
603 {
604     updateCurrentCharFormat();
605     selectionChanged();
606 }
607
608 #ifndef QT_NO_CLIPBOARD
609 void QWidgetTextControlPrivate::setClipboardSelection()
610 {
611     QClipboard *clipboard = QApplication::clipboard();
612     if (!cursor.hasSelection() || !clipboard->supportsSelection())
613         return;
614     Q_Q(QWidgetTextControl);
615     QMimeData *data = q->createMimeDataFromSelection();
616     clipboard->setMimeData(data, QClipboard::Selection);
617 }
618 #endif
619
620 void QWidgetTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
621 {
622     Q_Q(QWidgetTextControl);
623     if (someCursor.isCopyOf(cursor)) {
624         emit q->cursorPositionChanged();
625         emit q->microFocusChanged();
626     }
627 }
628
629 void QWidgetTextControlPrivate::_q_documentLayoutChanged()
630 {
631     Q_Q(QWidgetTextControl);
632     QAbstractTextDocumentLayout *layout = doc->documentLayout();
633     QObject::connect(layout, SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
634     QObject::connect(layout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(_q_updateBlock(QTextBlock)));
635     QObject::connect(layout, SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
636
637 }
638
639 void QWidgetTextControlPrivate::setBlinkingCursorEnabled(bool enable)
640 {
641     Q_Q(QWidgetTextControl);
642
643     if (enable && QApplication::cursorFlashTime() > 0)
644         cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
645     else
646         cursorBlinkTimer.stop();
647
648     cursorOn = enable;
649
650     repaintCursor();
651 }
652
653 void QWidgetTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
654 {
655     Q_Q(QWidgetTextControl);
656
657     // if inside the initial selected word keep that
658     if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
659         && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
660         q->setTextCursor(selectedWordOnDoubleClick);
661         return;
662     }
663
664     QTextCursor curs = selectedWordOnDoubleClick;
665     curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
666
667     if (!curs.movePosition(QTextCursor::StartOfWord))
668         return;
669     const int wordStartPos = curs.position();
670
671     const int blockPos = curs.block().position();
672     const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
673
674     QTextLine line = currentTextLine(curs);
675     if (!line.isValid())
676         return;
677
678     const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
679
680     if (!curs.movePosition(QTextCursor::EndOfWord))
681         return;
682     const int wordEndPos = curs.position();
683
684     const QTextLine otherLine = currentTextLine(curs);
685     if (otherLine.textStart() != line.textStart()
686         || wordEndPos == wordStartPos)
687         return;
688
689     const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
690
691     if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
692         return;
693
694     // keep the already selected word even when moving to the left
695     // (#39164)
696     if (suggestedNewPosition < selectedWordOnDoubleClick.position())
697         cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
698     else
699         cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
700
701     const qreal differenceToStart = mouseXPosition - wordStartX;
702     const qreal differenceToEnd = wordEndX - mouseXPosition;
703
704     if (differenceToStart < differenceToEnd)
705         setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
706     else
707         setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
708
709     if (interactionFlags & Qt::TextSelectableByMouse) {
710 #ifndef QT_NO_CLIPBOARD
711         setClipboardSelection();
712 #endif
713         selectionChanged(true);
714     }
715 }
716
717 void QWidgetTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition)
718 {
719     Q_Q(QWidgetTextControl);
720
721     // if inside the initial selected line keep that
722     if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
723         && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
724         q->setTextCursor(selectedBlockOnTrippleClick);
725         return;
726     }
727
728     if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
729         cursor.setPosition(selectedBlockOnTrippleClick.selectionEnd());
730         cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
731         cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
732     } else {
733         cursor.setPosition(selectedBlockOnTrippleClick.selectionStart());
734         cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
735         cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
736         cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
737     }
738
739     if (interactionFlags & Qt::TextSelectableByMouse) {
740 #ifndef QT_NO_CLIPBOARD
741         setClipboardSelection();
742 #endif
743         selectionChanged(true);
744     }
745 }
746
747 void QWidgetTextControlPrivate::_q_deleteSelected()
748 {
749     if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
750         return;
751     cursor.removeSelectedText();
752 }
753
754 void QWidgetTextControl::undo()
755 {
756     Q_D(QWidgetTextControl);
757     d->repaintSelection();
758     const int oldCursorPos = d->cursor.position();
759     d->doc->undo(&d->cursor);
760     if (d->cursor.position() != oldCursorPos)
761         emit cursorPositionChanged();
762     emit microFocusChanged();
763     ensureCursorVisible();
764 }
765
766 void QWidgetTextControl::redo()
767 {
768     Q_D(QWidgetTextControl);
769     d->repaintSelection();
770     const int oldCursorPos = d->cursor.position();
771     d->doc->redo(&d->cursor);
772         if (d->cursor.position() != oldCursorPos)
773         emit cursorPositionChanged();
774     emit microFocusChanged();
775     ensureCursorVisible();
776 }
777
778 QWidgetTextControl::QWidgetTextControl(QObject *parent)
779     : QObject(*new QWidgetTextControlPrivate, parent)
780 {
781     Q_D(QWidgetTextControl);
782     d->init();
783 }
784
785 QWidgetTextControl::QWidgetTextControl(const QString &text, QObject *parent)
786     : QObject(*new QWidgetTextControlPrivate, parent)
787 {
788     Q_D(QWidgetTextControl);
789     d->init(Qt::RichText, text);
790 }
791
792 QWidgetTextControl::QWidgetTextControl(QTextDocument *doc, QObject *parent)
793     : QObject(*new QWidgetTextControlPrivate, parent)
794 {
795     Q_D(QWidgetTextControl);
796     d->init(Qt::RichText, QString(), doc);
797 }
798
799 QWidgetTextControl::~QWidgetTextControl()
800 {
801 }
802
803 void QWidgetTextControl::setDocument(QTextDocument *document)
804 {
805     Q_D(QWidgetTextControl);
806     if (d->doc == document)
807         return;
808
809     d->doc->disconnect(this);
810     d->doc->documentLayout()->disconnect(this);
811     d->doc->documentLayout()->setPaintDevice(0);
812
813     if (d->doc->parent() == this)
814         delete d->doc;
815
816     d->doc = 0;
817     d->setContent(Qt::RichText, QString(), document);
818 }
819
820 QTextDocument *QWidgetTextControl::document() const
821 {
822     Q_D(const QWidgetTextControl);
823     return d->doc;
824 }
825
826 void QWidgetTextControl::setTextCursor(const QTextCursor &cursor)
827 {
828     Q_D(QWidgetTextControl);
829     d->cursorIsFocusIndicator = false;
830     const bool posChanged = cursor.position() != d->cursor.position();
831     const QTextCursor oldSelection = d->cursor;
832     d->cursor = cursor;
833     d->cursorOn = d->hasFocus && (d->interactionFlags & Qt::TextEditable);
834     d->_q_updateCurrentCharFormatAndSelection();
835     ensureCursorVisible();
836     d->repaintOldAndNewSelection(oldSelection);
837     if (posChanged)
838         emit cursorPositionChanged();
839 }
840
841 QTextCursor QWidgetTextControl::textCursor() const
842 {
843     Q_D(const QWidgetTextControl);
844     return d->cursor;
845 }
846
847 #ifndef QT_NO_CLIPBOARD
848
849 void QWidgetTextControl::cut()
850 {
851     Q_D(QWidgetTextControl);
852     if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
853         return;
854     copy();
855     d->cursor.removeSelectedText();
856 }
857
858 void QWidgetTextControl::copy()
859 {
860     Q_D(QWidgetTextControl);
861     if (!d->cursor.hasSelection())
862         return;
863     QMimeData *data = createMimeDataFromSelection();
864     QApplication::clipboard()->setMimeData(data);
865 }
866
867 void QWidgetTextControl::paste(QClipboard::Mode mode)
868 {
869     const QMimeData *md = QApplication::clipboard()->mimeData(mode);
870     if (md)
871         insertFromMimeData(md);
872 }
873 #endif
874
875 void QWidgetTextControl::clear()
876 {
877     Q_D(QWidgetTextControl);
878     // clears and sets empty content
879     d->extraSelections.clear();
880     d->setContent();
881 }
882
883
884 void QWidgetTextControl::selectAll()
885 {
886     Q_D(QWidgetTextControl);
887     const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
888     d->cursor.select(QTextCursor::Document);
889     d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
890     d->cursorIsFocusIndicator = false;
891     emit updateRequest();
892 }
893
894 void QWidgetTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
895 {
896     QMatrix m;
897     m.translate(coordinateOffset.x(), coordinateOffset.y());
898     processEvent(e, m, contextWidget);
899 }
900
901 void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
902 {
903     Q_D(QWidgetTextControl);
904     if (d->interactionFlags == Qt::NoTextInteraction) {
905         e->ignore();
906         return;
907     }
908
909     d->contextWidget = contextWidget;
910
911     if (!d->contextWidget) {
912         switch (e->type()) {
913 #ifndef QT_NO_GRAPHICSVIEW
914             case QEvent::GraphicsSceneMouseMove:
915             case QEvent::GraphicsSceneMousePress:
916             case QEvent::GraphicsSceneMouseRelease:
917             case QEvent::GraphicsSceneMouseDoubleClick:
918             case QEvent::GraphicsSceneContextMenu:
919             case QEvent::GraphicsSceneHoverEnter:
920             case QEvent::GraphicsSceneHoverMove:
921             case QEvent::GraphicsSceneHoverLeave:
922             case QEvent::GraphicsSceneHelp:
923             case QEvent::GraphicsSceneDragEnter:
924             case QEvent::GraphicsSceneDragMove:
925             case QEvent::GraphicsSceneDragLeave:
926             case QEvent::GraphicsSceneDrop: {
927                 QGraphicsSceneEvent *ev = static_cast<QGraphicsSceneEvent *>(e);
928                 d->contextWidget = ev->widget();
929                 break;
930             }
931 #endif // QT_NO_GRAPHICSVIEW
932             default: break;
933         };
934     }
935
936     switch (e->type()) {
937         case QEvent::KeyPress:
938             d->keyPressEvent(static_cast<QKeyEvent *>(e));
939             break;
940         case QEvent::MouseButtonPress: {
941             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
942             d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
943                                ev->buttons(), ev->globalPos());
944             break; }
945         case QEvent::MouseMove: {
946             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
947             d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
948                               ev->buttons(), ev->globalPos());
949             break; }
950         case QEvent::MouseButtonRelease: {
951             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
952             d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
953                                  ev->buttons(), ev->globalPos());
954             break; }
955         case QEvent::MouseButtonDblClick: {
956             QMouseEvent *ev = static_cast<QMouseEvent *>(e);
957             d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
958                                      ev->buttons(), ev->globalPos());
959             break; }
960         case QEvent::InputMethod:
961             d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
962             break;
963 #ifndef QT_NO_CONTEXTMENU
964     case QEvent::ContextMenu: {
965             QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
966             d->contextMenuEvent(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
967             break; }
968 #endif // QT_NO_CONTEXTMENU
969         case QEvent::FocusIn:
970         case QEvent::FocusOut:
971             d->focusEvent(static_cast<QFocusEvent *>(e));
972             break;
973
974         case QEvent::EnabledChange:
975             d->isEnabled = e->isAccepted();
976             break;
977
978 #ifndef QT_NO_TOOLTIP
979         case QEvent::ToolTip: {
980             QHelpEvent *ev = static_cast<QHelpEvent *>(e);
981             d->showToolTip(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
982             break;
983         }
984 #endif // QT_NO_TOOLTIP
985
986 #ifndef QT_NO_DRAGANDDROP
987         case QEvent::DragEnter: {
988             QDragEnterEvent *ev = static_cast<QDragEnterEvent *>(e);
989             if (d->dragEnterEvent(e, ev->mimeData()))
990                 ev->acceptProposedAction();
991             break;
992         }
993         case QEvent::DragLeave:
994             d->dragLeaveEvent();
995             break;
996         case QEvent::DragMove: {
997             QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
998             if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
999                 ev->acceptProposedAction();
1000             break;
1001         }
1002         case QEvent::Drop: {
1003             QDropEvent *ev = static_cast<QDropEvent *>(e);
1004             if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
1005                 ev->acceptProposedAction();
1006             break;
1007         }
1008 #endif
1009
1010 #ifndef QT_NO_GRAPHICSVIEW
1011         case QEvent::GraphicsSceneMousePress: {
1012             QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1013             d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1014                                ev->screenPos());
1015             break; }
1016         case QEvent::GraphicsSceneMouseMove: {
1017             QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1018             d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1019                               ev->screenPos());
1020             break; }
1021         case QEvent::GraphicsSceneMouseRelease: {
1022             QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1023             d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1024                                  ev->screenPos());
1025             break; }
1026         case QEvent::GraphicsSceneMouseDoubleClick: {
1027             QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1028             d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1029                                      ev->screenPos());
1030             break; }
1031         case QEvent::GraphicsSceneContextMenu: {
1032             QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
1033             d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
1034             break; }
1035
1036         case QEvent::GraphicsSceneHoverMove: {
1037             QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
1038             d->mouseMoveEvent(ev, Qt::NoButton, matrix.map(ev->pos()), ev->modifiers(),Qt::NoButton,
1039                               ev->screenPos());
1040             break; }
1041
1042         case QEvent::GraphicsSceneDragEnter: {
1043             QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1044             if (d->dragEnterEvent(e, ev->mimeData()))
1045                 ev->acceptProposedAction();
1046             break; }
1047         case QEvent::GraphicsSceneDragLeave:
1048             d->dragLeaveEvent();
1049             break;
1050         case QEvent::GraphicsSceneDragMove: {
1051             QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1052             if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
1053                 ev->acceptProposedAction();
1054             break; }
1055         case QEvent::GraphicsSceneDrop: {
1056             QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1057             if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
1058                 ev->accept();
1059             break; }
1060 #endif // QT_NO_GRAPHICSVIEW
1061 #ifdef QT_KEYPAD_NAVIGATION
1062         case QEvent::EnterEditFocus:
1063         case QEvent::LeaveEditFocus:
1064             if (QApplication::keypadNavigationEnabled())
1065                 d->editFocusEvent(e);
1066             break;
1067 #endif
1068         case QEvent::ShortcutOverride:
1069             if (d->interactionFlags & Qt::TextEditable) {
1070                 QKeyEvent* ke = static_cast<QKeyEvent *>(e);
1071                 if (ke->modifiers() == Qt::NoModifier
1072                     || ke->modifiers() == Qt::ShiftModifier
1073                     || ke->modifiers() == Qt::KeypadModifier) {
1074                     if (ke->key() < Qt::Key_Escape) {
1075                         ke->accept();
1076                     } else {
1077                         switch (ke->key()) {
1078                             case Qt::Key_Return:
1079                             case Qt::Key_Enter:
1080                             case Qt::Key_Delete:
1081                             case Qt::Key_Home:
1082                             case Qt::Key_End:
1083                             case Qt::Key_Backspace:
1084                             case Qt::Key_Left:
1085                             case Qt::Key_Right:
1086                             case Qt::Key_Up:
1087                             case Qt::Key_Down:
1088                             case Qt::Key_Tab:
1089                             ke->accept();
1090                         default:
1091                             break;
1092                         }
1093                     }
1094 #ifndef QT_NO_SHORTCUT
1095                 } else if (ke == QKeySequence::Copy
1096                            || ke == QKeySequence::Paste
1097                            || ke == QKeySequence::Cut
1098                            || ke == QKeySequence::Redo
1099                            || ke == QKeySequence::Undo
1100                            || ke == QKeySequence::MoveToNextWord
1101                            || ke == QKeySequence::MoveToPreviousWord
1102                            || ke == QKeySequence::MoveToStartOfDocument
1103                            || ke == QKeySequence::MoveToEndOfDocument
1104                            || ke == QKeySequence::SelectNextWord
1105                            || ke == QKeySequence::SelectPreviousWord
1106                            || ke == QKeySequence::SelectStartOfLine
1107                            || ke == QKeySequence::SelectEndOfLine
1108                            || ke == QKeySequence::SelectStartOfBlock
1109                            || ke == QKeySequence::SelectEndOfBlock
1110                            || ke == QKeySequence::SelectStartOfDocument
1111                            || ke == QKeySequence::SelectEndOfDocument
1112                            || ke == QKeySequence::SelectAll
1113                           ) {
1114                     ke->accept();
1115 #endif
1116                 }
1117             }
1118             break;
1119         default:
1120             break;
1121     }
1122 }
1123
1124 bool QWidgetTextControl::event(QEvent *e)
1125 {
1126     return QObject::event(e);
1127 }
1128
1129 void QWidgetTextControl::timerEvent(QTimerEvent *e)
1130 {
1131     Q_D(QWidgetTextControl);
1132     if (e->timerId() == d->cursorBlinkTimer.timerId()) {
1133         d->cursorOn = !d->cursorOn;
1134
1135         if (d->cursor.hasSelection())
1136             d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
1137                             != 0);
1138
1139         d->repaintCursor();
1140     } else if (e->timerId() == d->trippleClickTimer.timerId()) {
1141         d->trippleClickTimer.stop();
1142     }
1143 }
1144
1145 void QWidgetTextControl::setPlainText(const QString &text)
1146 {
1147     Q_D(QWidgetTextControl);
1148     d->setContent(Qt::PlainText, text);
1149 }
1150
1151 void QWidgetTextControl::setHtml(const QString &text)
1152 {
1153     Q_D(QWidgetTextControl);
1154     d->setContent(Qt::RichText, text);
1155 }
1156
1157 void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
1158 {
1159     Q_Q(QWidgetTextControl);
1160 #ifndef QT_NO_SHORTCUT
1161     if (e == QKeySequence::SelectAll) {
1162             e->accept();
1163             q->selectAll();
1164             return;
1165     }
1166 #ifndef QT_NO_CLIPBOARD
1167     else if (e == QKeySequence::Copy) {
1168             e->accept();
1169             q->copy();
1170             return;
1171     }
1172 #endif
1173 #endif // QT_NO_SHORTCUT
1174
1175     if (interactionFlags & Qt::TextSelectableByKeyboard
1176         && cursorMoveKeyEvent(e))
1177         goto accept;
1178
1179     if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
1180         if ((e->key() == Qt::Key_Return
1181              || e->key() == Qt::Key_Enter
1182 #ifdef QT_KEYPAD_NAVIGATION
1183              || e->key() == Qt::Key_Select
1184 #endif
1185              )
1186             && cursor.hasSelection()) {
1187
1188             e->accept();
1189             activateLinkUnderCursor();
1190             return;
1191         }
1192     }
1193
1194     if (!(interactionFlags & Qt::TextEditable)) {
1195         e->ignore();
1196         return;
1197     }
1198
1199     if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
1200         QTextBlockFormat fmt;
1201         fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1202         cursor.mergeBlockFormat(fmt);
1203         goto accept;
1204     }
1205
1206     // schedule a repaint of the region of the cursor, as when we move it we
1207     // want to make sure the old cursor disappears (not noticeable when moving
1208     // only a few pixels but noticeable when jumping between cells in tables for
1209     // example)
1210     repaintSelection();
1211
1212     if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~Qt::ShiftModifier)) {
1213         QTextBlockFormat blockFmt = cursor.blockFormat();
1214         QTextList *list = cursor.currentList();
1215         if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
1216             list->remove(cursor.block());
1217         } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1218             blockFmt.setIndent(blockFmt.indent() - 1);
1219             cursor.setBlockFormat(blockFmt);
1220         } else {
1221             QTextCursor localCursor = cursor;
1222             localCursor.deletePreviousChar();
1223         }
1224         goto accept;
1225     }
1226 #ifndef QT_NO_SHORTCUT
1227       else if (e == QKeySequence::InsertParagraphSeparator) {
1228         cursor.insertBlock();
1229         e->accept();
1230         goto accept;
1231     } else if (e == QKeySequence::InsertLineSeparator) {
1232         cursor.insertText(QString(QChar::LineSeparator));
1233         e->accept();
1234         goto accept;
1235     }
1236 #endif
1237     if (false) {
1238     }
1239 #ifndef QT_NO_SHORTCUT
1240     else if (e == QKeySequence::Undo) {
1241             q->undo();
1242     }
1243     else if (e == QKeySequence::Redo) {
1244            q->redo();
1245     }
1246 #ifndef QT_NO_CLIPBOARD
1247     else if (e == QKeySequence::Cut) {
1248            q->cut();
1249     }
1250     else if (e == QKeySequence::Paste) {
1251         QClipboard::Mode mode = QClipboard::Clipboard;
1252 #ifdef Q_WS_X11
1253         if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
1254             mode = QClipboard::Selection;
1255 #endif
1256         q->paste(mode);
1257     }
1258 #endif
1259     else if (e == QKeySequence::Delete) {
1260         QTextCursor localCursor = cursor;
1261         localCursor.deleteChar();
1262     }
1263     else if (e == QKeySequence::DeleteEndOfWord) {
1264         if (!cursor.hasSelection())
1265             cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
1266         cursor.removeSelectedText();
1267     }
1268     else if (e == QKeySequence::DeleteStartOfWord) {
1269         if (!cursor.hasSelection())
1270             cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
1271         cursor.removeSelectedText();
1272     }
1273     else if (e == QKeySequence::DeleteEndOfLine) {
1274         QTextBlock block = cursor.block();
1275         if (cursor.position() == block.position() + block.length() - 2)
1276             cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
1277         else
1278             cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1279         cursor.removeSelectedText();
1280     }
1281 #endif // QT_NO_SHORTCUT
1282     else {
1283         goto process;
1284     }
1285     goto accept;
1286
1287 process:
1288     {
1289         QString text = e->text();
1290         if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
1291             if (overwriteMode
1292                 // no need to call deleteChar() if we have a selection, insertText
1293                 // does it already
1294                 && !cursor.hasSelection()
1295                 && !cursor.atBlockEnd())
1296                 cursor.deleteChar();
1297
1298             cursor.insertText(text);
1299             selectionChanged();
1300         } else {
1301             e->ignore();
1302             return;
1303         }
1304     }
1305
1306  accept:
1307
1308     e->accept();
1309     cursorOn = true;
1310
1311     q->ensureCursorVisible();
1312
1313     updateCurrentCharFormat();
1314 }
1315
1316 QVariant QWidgetTextControl::loadResource(int type, const QUrl &name)
1317 {
1318 #ifdef QT_NO_TEXTEDIT
1319     Q_UNUSED(type);
1320     Q_UNUSED(name);
1321 #else
1322     if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent())) {
1323         QUrl resolvedName = textEdit->d_func()->resolveUrl(name);
1324         return textEdit->loadResource(type, resolvedName);
1325     }
1326 #endif
1327     return QVariant();
1328 }
1329
1330 void QWidgetTextControlPrivate::_q_updateBlock(const QTextBlock &block)
1331 {
1332     Q_Q(QWidgetTextControl);
1333     QRectF br = q->blockBoundingRect(block);
1334     br.setRight(qreal(INT_MAX)); // the block might have shrunk
1335     emit q->updateRequest(br);
1336 }
1337
1338 QRectF QWidgetTextControlPrivate::rectForPosition(int position) const
1339 {
1340     Q_Q(const QWidgetTextControl);
1341     const QTextBlock block = doc->findBlock(position);
1342     if (!block.isValid())
1343         return QRectF();
1344     const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
1345     const QTextLayout *layout = block.layout();
1346     const QPointF layoutPos = q->blockBoundingRect(block).topLeft();
1347     int relativePos = position - block.position();
1348     if (preeditCursor != 0) {
1349         int preeditPos = layout->preeditAreaPosition();
1350         if (relativePos == preeditPos)
1351             relativePos += preeditCursor;
1352         else if (relativePos > preeditPos)
1353             relativePos += layout->preeditAreaText().length();
1354     }
1355     QTextLine line = layout->lineForTextPosition(relativePos);
1356
1357     int cursorWidth;
1358     {
1359         bool ok = false;
1360 #ifndef QT_NO_PROPERTIES
1361         cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
1362 #endif
1363         if (!ok)
1364             cursorWidth = 1;
1365     }
1366
1367     QRectF r;
1368
1369     if (line.isValid()) {
1370         qreal x = line.cursorToX(relativePos);
1371         qreal w = 0;
1372         if (overwriteMode) {
1373             if (relativePos < line.textLength() - line.textStart())
1374                 w = line.cursorToX(relativePos + 1) - x;
1375             else
1376                 w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
1377         }
1378         r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
1379                    cursorWidth + w, line.height());
1380     } else {
1381         r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
1382     }
1383
1384     return r;
1385 }
1386
1387 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
1388 {
1389     return frame->firstPosition() < position;
1390 }
1391
1392 static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame)
1393 {
1394     return position < frame->lastPosition();
1395 }
1396
1397 static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
1398 {
1399     QRectF r;
1400     QTextFrame *frame = cursor.currentFrame();
1401     const QList<QTextFrame *> children = frame->childFrames();
1402
1403     const QList<QTextFrame *>::ConstIterator firstFrame = qLowerBound(children.constBegin(), children.constEnd(),
1404                                                                       cursor.selectionStart(), firstFramePosLessThanCursorPos);
1405     const QList<QTextFrame *>::ConstIterator lastFrame = qUpperBound(children.constBegin(), children.constEnd(),
1406                                                                      cursor.selectionEnd(), cursorPosLessThanLastFramePos);
1407     for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) {
1408         if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow)
1409             r |= frame->document()->documentLayout()->frameBoundingRect(*it);
1410     }
1411     return r;
1412 }
1413
1414 QRectF QWidgetTextControl::selectionRect(const QTextCursor &cursor) const
1415 {
1416     Q_D(const QWidgetTextControl);
1417
1418     QRectF r = d->rectForPosition(cursor.selectionStart());
1419
1420     if (cursor.hasComplexSelection() && cursor.currentTable()) {
1421         QTextTable *table = cursor.currentTable();
1422
1423         r = d->doc->documentLayout()->frameBoundingRect(table);
1424         /*
1425         int firstRow, numRows, firstColumn, numColumns;
1426         cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
1427
1428         const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
1429         const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
1430
1431         const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
1432
1433         QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
1434
1435         for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1436             const QTextTableCell cell = table->cellAt(firstRow, col);
1437             const qreal y = layout->blockBoundingRect(cell.firstCursorPosition().block()).top();
1438
1439             tableSelRect.setTop(qMin(tableSelRect.top(), y));
1440         }
1441
1442         for (int row = firstRow; row < firstRow + numRows; ++row) {
1443             const QTextTableCell cell = table->cellAt(row, firstColumn);
1444             const qreal x = layout->blockBoundingRect(cell.firstCursorPosition().block()).left();
1445
1446             tableSelRect.setLeft(qMin(tableSelRect.left(), x));
1447         }
1448
1449         for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1450             const QTextTableCell cell = table->cellAt(firstRow + numRows - 1, col);
1451             const qreal y = layout->blockBoundingRect(cell.lastCursorPosition().block()).bottom();
1452
1453             tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
1454         }
1455
1456         for (int row = firstRow; row < firstRow + numRows; ++row) {
1457             const QTextTableCell cell = table->cellAt(row, firstColumn + numColumns - 1);
1458             const qreal x = layout->blockBoundingRect(cell.lastCursorPosition().block()).right();
1459
1460             tableSelRect.setRight(qMax(tableSelRect.right(), x));
1461         }
1462
1463         r = tableSelRect.toRect();
1464         */
1465     } else if (cursor.hasSelection()) {
1466         const int position = cursor.selectionStart();
1467         const int anchor = cursor.selectionEnd();
1468         const QTextBlock posBlock = d->doc->findBlock(position);
1469         const QTextBlock anchorBlock = d->doc->findBlock(anchor);
1470         if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
1471             const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
1472             const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
1473
1474             const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1475             const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1476             const QTextLayout *layout = posBlock.layout();
1477             r = QRectF();
1478             for (int i = firstLine; i <= lastLine; ++i) {
1479                 r |= layout->lineAt(i).rect();
1480                 r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled
1481             }
1482             r.translate(blockBoundingRect(posBlock).topLeft());
1483         } else {
1484             QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1485             r |= anchorRect;
1486             r |= boundingRectOfFloatsInSelection(cursor);
1487             QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1488             r.setLeft(frameRect.left());
1489             r.setRight(frameRect.right());
1490         }
1491         if (r.isValid())
1492             r.adjust(-1, -1, 1, 1);
1493     }
1494
1495     return r;
1496 }
1497
1498 QRectF QWidgetTextControl::selectionRect() const
1499 {
1500     Q_D(const QWidgetTextControl);
1501     return selectionRect(d->cursor);
1502 }
1503
1504 void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1505                                           Qt::MouseButtons buttons, const QPoint &globalPos)
1506 {
1507     Q_Q(QWidgetTextControl);
1508
1509     if (sendMouseEventToInputContext(
1510             e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
1511         return;
1512     }
1513
1514     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1515         anchorOnMousePress = q->anchorAt(pos);
1516
1517         if (cursorIsFocusIndicator) {
1518             cursorIsFocusIndicator = false;
1519             repaintSelection();
1520             cursor.clearSelection();
1521         }
1522     }
1523     if (!(button & Qt::LeftButton) ||
1524         !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
1525             e->ignore();
1526             return;
1527     }
1528
1529     cursorIsFocusIndicator = false;
1530     const QTextCursor oldSelection = cursor;
1531     const int oldCursorPos = cursor.position();
1532
1533     mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
1534 #ifndef QT_NO_DRAGANDDROP
1535     mightStartDrag = false;
1536 #endif
1537
1538     if (trippleClickTimer.isActive()
1539         && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
1540
1541         cursor.movePosition(QTextCursor::StartOfBlock);
1542         cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1543         cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1544         selectedBlockOnTrippleClick = cursor;
1545
1546         anchorOnMousePress = QString();
1547
1548         trippleClickTimer.stop();
1549     } else {
1550         int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1551         if (cursorPos == -1) {
1552             e->ignore();
1553             return;
1554         }
1555
1556         if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
1557             if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1558                 selectedWordOnDoubleClick = cursor;
1559                 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1560             }
1561
1562             if (selectedBlockOnTrippleClick.hasSelection())
1563                 extendBlockwiseSelection(cursorPos);
1564             else if (selectedWordOnDoubleClick.hasSelection())
1565                 extendWordwiseSelection(cursorPos, pos.x());
1566             else if (!wordSelectionEnabled)
1567                 setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
1568         } else {
1569
1570             if (dragEnabled
1571                 && cursor.hasSelection()
1572                 && !cursorIsFocusIndicator
1573                 && cursorPos >= cursor.selectionStart()
1574                 && cursorPos <= cursor.selectionEnd()
1575                 && q->hitTest(pos, Qt::ExactHit) != -1) {
1576 #ifndef QT_NO_DRAGANDDROP
1577                 mightStartDrag = true;
1578                 dragStartPos = pos.toPoint();
1579 #endif
1580                 return;
1581             }
1582
1583             setCursorPosition(cursorPos);
1584         }
1585     }
1586
1587     if (interactionFlags & Qt::TextEditable) {
1588         q->ensureCursorVisible();
1589         if (cursor.position() != oldCursorPos)
1590             emit q->cursorPositionChanged();
1591         _q_updateCurrentCharFormatAndSelection();
1592     } else {
1593         if (cursor.position() != oldCursorPos) {
1594             emit q->cursorPositionChanged();
1595             emit q->microFocusChanged();
1596         }
1597         selectionChanged();
1598     }
1599     repaintOldAndNewSelection(oldSelection);
1600     hadSelectionOnMousePress = cursor.hasSelection();
1601 }
1602
1603 void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &mousePos, Qt::KeyboardModifiers modifiers,
1604                                          Qt::MouseButtons buttons, const QPoint &globalPos)
1605 {
1606     Q_Q(QWidgetTextControl);
1607
1608     if (sendMouseEventToInputContext(
1609             e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos)) {
1610         return;
1611     }
1612
1613     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1614         QString anchor = q->anchorAt(mousePos);
1615         if (anchor != highlightedAnchor) {
1616             highlightedAnchor = anchor;
1617             emit q->linkHovered(anchor);
1618         }
1619     }
1620
1621     if (!(buttons & Qt::LeftButton))
1622         return;
1623
1624     const bool editable = interactionFlags & Qt::TextEditable;
1625
1626     if (!(mousePressed
1627           || editable
1628           || mightStartDrag
1629           || selectedWordOnDoubleClick.hasSelection()
1630           || selectedBlockOnTrippleClick.hasSelection()))
1631         return;
1632
1633     const QTextCursor oldSelection = cursor;
1634     const int oldCursorPos = cursor.position();
1635
1636     if (mightStartDrag) {
1637         if ((mousePos.toPoint() - dragStartPos).manhattanLength() > QApplication::startDragDistance())
1638             startDrag();
1639         return;
1640     }
1641
1642     if (!mousePressed)
1643         return;
1644
1645     const qreal mouseX = qreal(mousePos.x());
1646
1647     int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1648     if (newCursorPos == -1)
1649         return;
1650
1651     if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1652         selectedWordOnDoubleClick = cursor;
1653         selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1654     }
1655
1656     if (selectedBlockOnTrippleClick.hasSelection())
1657         extendBlockwiseSelection(newCursorPos);
1658     else if (selectedWordOnDoubleClick.hasSelection())
1659         extendWordwiseSelection(newCursorPos, mouseX);
1660     else
1661         setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
1662
1663     if (interactionFlags & Qt::TextEditable) {
1664         // don't call ensureVisible for the visible cursor to avoid jumping
1665         // scrollbars. the autoscrolling ensures smooth scrolling if necessary.
1666         //q->ensureCursorVisible();
1667         if (cursor.position() != oldCursorPos)
1668             emit q->cursorPositionChanged();
1669         _q_updateCurrentCharFormatAndSelection();
1670 #ifndef QT_NO_IM
1671         if (contextWidget) {
1672             if (QInputContext *ic = qApp->inputContext()) {
1673                 ic->update();
1674             }
1675         }
1676 #endif //QT_NO_IM
1677     } else {
1678         //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
1679         if (cursor.position() != oldCursorPos)
1680             emit q->cursorPositionChanged();
1681     }
1682     selectionChanged(true);
1683     repaintOldAndNewSelection(oldSelection);
1684 }
1685
1686 void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1687                                             Qt::MouseButtons buttons, const QPoint &globalPos)
1688 {
1689     Q_Q(QWidgetTextControl);
1690
1691     if (sendMouseEventToInputContext(
1692             e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
1693         return;
1694     }
1695
1696     const QTextCursor oldSelection = cursor;
1697     const int oldCursorPos = cursor.position();
1698
1699 #ifndef QT_NO_DRAGANDDROP
1700     if (mightStartDrag && (button & Qt::LeftButton)) {
1701         mousePressed = false;
1702         setCursorPosition(pos);
1703         cursor.clearSelection();
1704         selectionChanged();
1705     }
1706 #endif
1707     if (mousePressed) {
1708         mousePressed = false;
1709 #ifndef QT_NO_CLIPBOARD
1710         setClipboardSelection();
1711         selectionChanged(true);
1712     } else if (button == Qt::MidButton
1713                && (interactionFlags & Qt::TextEditable)
1714                && QApplication::clipboard()->supportsSelection()) {
1715         setCursorPosition(pos);
1716         const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Selection);
1717         if (md)
1718             q->insertFromMimeData(md);
1719 #endif
1720     }
1721
1722     repaintOldAndNewSelection(oldSelection);
1723
1724     if (cursor.position() != oldCursorPos)
1725         emit q->cursorPositionChanged();
1726
1727     if (interactionFlags & Qt::LinksAccessibleByMouse) {
1728         if (!(button & Qt::LeftButton))
1729             return;
1730
1731         const QString anchor = q->anchorAt(pos);
1732
1733         if (anchor.isEmpty())
1734             return;
1735
1736         if (!cursor.hasSelection()
1737             || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1738
1739             const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1740             if (anchorPos != -1) {
1741                 cursor.setPosition(anchorPos);
1742
1743                 QString anchor = anchorOnMousePress;
1744                 anchorOnMousePress = QString();
1745                 activateLinkUnderCursor(anchor);
1746             }
1747         }
1748     }
1749 }
1750
1751 void QWidgetTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1752                                                 Qt::MouseButtons buttons, const QPoint &globalPos)
1753 {
1754     Q_Q(QWidgetTextControl);
1755
1756     if (sendMouseEventToInputContext(
1757             e, QEvent::MouseButtonDblClick, button, pos, modifiers, buttons, globalPos)) {
1758         return;
1759     }
1760
1761     if (button != Qt::LeftButton
1762         || !(interactionFlags & Qt::TextSelectableByMouse)) {
1763         e->ignore();
1764         return;
1765     }
1766
1767 #ifndef QT_NO_DRAGANDDROP
1768     mightStartDrag = false;
1769 #endif
1770     const QTextCursor oldSelection = cursor;
1771     setCursorPosition(pos);
1772     QTextLine line = currentTextLine(cursor);
1773     bool doEmit = false;
1774     if (line.isValid() && line.textLength()) {
1775         cursor.select(QTextCursor::WordUnderCursor);
1776         doEmit = true;
1777     }
1778     repaintOldAndNewSelection(oldSelection);
1779
1780     cursorIsFocusIndicator = false;
1781     selectedWordOnDoubleClick = cursor;
1782
1783     trippleClickPoint = pos;
1784     trippleClickTimer.start(QApplication::doubleClickInterval(), q);
1785     if (doEmit) {
1786         selectionChanged();
1787 #ifndef QT_NO_CLIPBOARD
1788         setClipboardSelection();
1789 #endif
1790         emit q->cursorPositionChanged();
1791     }
1792 }
1793
1794 bool QWidgetTextControlPrivate::sendMouseEventToInputContext(
1795         QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos,
1796         Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
1797 {
1798 #if !defined(QT_NO_IM)
1799     Q_Q(QWidgetTextControl);
1800
1801     QTextLayout *layout = cursor.block().layout();
1802     if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) {
1803         QInputContext *ctx = qApp->inputContext();
1804         int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
1805
1806         if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length()) {
1807             cursorPos = -1;
1808             // don't send move events outside the preedit area
1809             if (eventType == QEvent::MouseMove)
1810                 return true;
1811         }
1812         if (ctx) {
1813             QMouseEvent ev(eventType, contextWidget->mapFromGlobal(globalPos),
1814                            contextWidget->topLevelWidget()->mapFromGlobal(globalPos), globalPos,
1815                            button, buttons, modifiers);
1816             ctx->mouseHandler(cursorPos, &ev);
1817             e->setAccepted(ev.isAccepted());
1818         }
1819         if (!layout->preeditAreaText().isEmpty())
1820             return true;
1821     }
1822 #else
1823     Q_UNUSED(e);
1824     Q_UNUSED(eventType);
1825     Q_UNUSED(button);
1826     Q_UNUSED(pos);
1827     Q_UNUSED(modifiers);
1828     Q_UNUSED(buttons);
1829     Q_UNUSED(globalPos);
1830 #endif
1831     return false;
1832 }
1833
1834 void QWidgetTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
1835 {
1836 #ifdef QT_NO_CONTEXTMENU
1837     Q_UNUSED(screenPos);
1838     Q_UNUSED(docPos);
1839     Q_UNUSED(contextWidget);
1840 #else
1841     Q_Q(QWidgetTextControl);
1842     if (!hasFocus)
1843         return;
1844     QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
1845     if (!menu)
1846         return;
1847     menu->setAttribute(Qt::WA_DeleteOnClose);
1848     menu->popup(screenPos);
1849 #endif
1850 }
1851
1852 bool QWidgetTextControlPrivate::dragEnterEvent(QEvent *e, const QMimeData *mimeData)
1853 {
1854     Q_Q(QWidgetTextControl);
1855     if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1856         e->ignore();
1857         return false;
1858     }
1859
1860     dndFeedbackCursor = QTextCursor();
1861
1862     return true; // accept proposed action
1863 }
1864
1865 void QWidgetTextControlPrivate::dragLeaveEvent()
1866 {
1867     Q_Q(QWidgetTextControl);
1868
1869     const QRectF crect = q->cursorRect(dndFeedbackCursor);
1870     dndFeedbackCursor = QTextCursor();
1871
1872     if (crect.isValid())
1873         emit q->updateRequest(crect);
1874 }
1875
1876 bool QWidgetTextControlPrivate::dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
1877 {
1878     Q_Q(QWidgetTextControl);
1879     if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1880         e->ignore();
1881         return false;
1882     }
1883
1884     const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1885     if (cursorPos != -1) {
1886         QRectF crect = q->cursorRect(dndFeedbackCursor);
1887         if (crect.isValid())
1888             emit q->updateRequest(crect);
1889
1890         dndFeedbackCursor = cursor;
1891         dndFeedbackCursor.setPosition(cursorPos);
1892
1893         crect = q->cursorRect(dndFeedbackCursor);
1894         emit q->updateRequest(crect);
1895     }
1896
1897     return true; // accept proposed action
1898 }
1899
1900 bool QWidgetTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QObject *source)
1901 {
1902     Q_Q(QWidgetTextControl);
1903     dndFeedbackCursor = QTextCursor();
1904
1905     if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
1906         return false;
1907
1908     repaintSelection();
1909
1910     QTextCursor insertionCursor = q->cursorForPosition(pos);
1911     insertionCursor.beginEditBlock();
1912
1913     if (dropAction == Qt::MoveAction && source == contextWidget)
1914         cursor.removeSelectedText();
1915
1916     cursor = insertionCursor;
1917     q->insertFromMimeData(mimeData);
1918     insertionCursor.endEditBlock();
1919     q->ensureCursorVisible();
1920     return true; // accept proposed action
1921 }
1922
1923 void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
1924 {
1925     Q_Q(QWidgetTextControl);
1926     if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
1927         e->ignore();
1928         return;
1929     }
1930     bool isGettingInput = !e->commitString().isEmpty()
1931             || e->preeditString() != cursor.block().layout()->preeditAreaText()
1932             || e->replacementLength() > 0;
1933
1934     cursor.beginEditBlock();
1935     if (isGettingInput) {
1936         cursor.removeSelectedText();
1937     }
1938
1939     // insert commit string
1940     if (!e->commitString().isEmpty() || e->replacementLength()) {
1941         QTextCursor c = cursor;
1942         c.setPosition(c.position() + e->replacementStart());
1943         c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
1944         c.insertText(e->commitString());
1945     }
1946
1947     for (int i = 0; i < e->attributes().size(); ++i) {
1948         const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1949         if (a.type == QInputMethodEvent::Selection) {
1950             QTextCursor oldCursor = cursor;
1951             int blockStart = a.start + cursor.block().position();
1952             cursor.setPosition(blockStart, QTextCursor::MoveAnchor);
1953             cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
1954             q->ensureCursorVisible();
1955             repaintOldAndNewSelection(oldCursor);
1956         }
1957     }
1958
1959     QTextBlock block = cursor.block();
1960     QTextLayout *layout = block.layout();
1961     if (isGettingInput)
1962         layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
1963     QList<QTextLayout::FormatRange> overrides;
1964     const int oldPreeditCursor = preeditCursor;
1965     preeditCursor = e->preeditString().length();
1966     hideCursor = false;
1967     for (int i = 0; i < e->attributes().size(); ++i) {
1968         const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1969         if (a.type == QInputMethodEvent::Cursor) {
1970             preeditCursor = a.start;
1971             hideCursor = !a.length;
1972         } else if (a.type == QInputMethodEvent::TextFormat) {
1973             QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
1974             if (f.isValid()) {
1975                 QTextLayout::FormatRange o;
1976                 o.start = a.start + cursor.position() - block.position();
1977                 o.length = a.length;
1978                 o.format = f;
1979                 overrides.append(o);
1980             }
1981         }
1982     }
1983     layout->setAdditionalFormats(overrides);
1984     cursor.endEditBlock();
1985     if (cursor.d)
1986         cursor.d->setX();
1987     if (oldPreeditCursor != preeditCursor)
1988         emit q->microFocusChanged();
1989 }
1990
1991 QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
1992 {
1993     Q_D(const QWidgetTextControl);
1994     QTextBlock block = d->cursor.block();
1995     switch(property) {
1996     case Qt::ImCursorRectangle:
1997         return cursorRect();
1998     case Qt::ImFont:
1999         return QVariant(d->cursor.charFormat().font());
2000     case Qt::ImCursorPosition:
2001         return QVariant(d->cursor.position() - block.position());
2002     case Qt::ImSurroundingText:
2003         return QVariant(block.text());
2004     case Qt::ImCurrentSelection:
2005         return QVariant(d->cursor.selectedText());
2006     case Qt::ImMaximumTextLength:
2007         return QVariant(); // No limit.
2008     case Qt::ImAnchorPosition:
2009         return QVariant(qBound(0, d->cursor.anchor() - block.position(), block.length()));
2010     default:
2011         return QVariant();
2012     }
2013 }
2014
2015 void QWidgetTextControl::setFocus(bool focus, Qt::FocusReason reason)
2016 {
2017     QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
2018                    reason);
2019     processEvent(&ev);
2020 }
2021
2022 void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
2023 {
2024     Q_Q(QWidgetTextControl);
2025     emit q->updateRequest(q->selectionRect());
2026     if (e->gotFocus()) {
2027 #ifdef QT_KEYPAD_NAVIGATION
2028         if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason
2029 #ifdef Q_OS_SYMBIAN
2030             || e->reason() == Qt::ActiveWindowFocusReason
2031 #endif
2032             ))) {
2033 #endif
2034         cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard);
2035         if (interactionFlags & Qt::TextEditable) {
2036             setBlinkingCursorEnabled(true);
2037         }
2038 #ifdef QT_KEYPAD_NAVIGATION
2039         }
2040 #endif
2041     } else {
2042         setBlinkingCursorEnabled(false);
2043
2044         if (cursorIsFocusIndicator
2045             && e->reason() != Qt::ActiveWindowFocusReason
2046             && e->reason() != Qt::PopupFocusReason
2047             && cursor.hasSelection()) {
2048             cursor.clearSelection();
2049         }
2050     }
2051     hasFocus = e->gotFocus();
2052 }
2053
2054 QString QWidgetTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
2055 {
2056     if (anchorCursor.hasSelection()) {
2057         QTextCursor cursor = anchorCursor;
2058         if (cursor.selectionStart() != cursor.position())
2059             cursor.setPosition(cursor.selectionStart());
2060         cursor.movePosition(QTextCursor::NextCharacter);
2061         QTextCharFormat fmt = cursor.charFormat();
2062         if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
2063             return fmt.stringProperty(QTextFormat::AnchorHref);
2064     }
2065     return QString();
2066 }
2067
2068 #ifdef QT_KEYPAD_NAVIGATION
2069 void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
2070 {
2071     Q_Q(QWidgetTextControl);
2072
2073     if (QApplication::keypadNavigationEnabled()) {
2074         if (e->type() == QEvent::EnterEditFocus && interactionFlags & Qt::TextEditable) {
2075             const QTextCursor oldSelection = cursor;
2076             const int oldCursorPos = cursor.position();
2077             const bool moved = cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
2078             q->ensureCursorVisible();
2079             if (moved) {
2080                 if (cursor.position() != oldCursorPos)
2081                     emit q->cursorPositionChanged();
2082                 emit q->microFocusChanged();
2083             }
2084             selectionChanged();
2085             repaintOldAndNewSelection(oldSelection);
2086
2087             setBlinkingCursorEnabled(true);
2088         } else
2089             setBlinkingCursorEnabled(false);
2090     }
2091
2092     hasEditFocus = e->type() == QEvent::EnterEditFocus ? true : false;
2093 }
2094 #endif
2095
2096 #ifndef QT_NO_CONTEXTMENU
2097 QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent)
2098 {
2099     Q_D(QWidgetTextControl);
2100
2101     const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
2102
2103     d->linkToCopy = QString();
2104     if (!pos.isNull())
2105         d->linkToCopy = anchorAt(pos);
2106
2107     if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
2108         return 0;
2109
2110     QMenu *menu = new QMenu(parent);
2111     QAction *a;
2112
2113     if (d->interactionFlags & Qt::TextEditable) {
2114         a = menu->addAction(tr("&Undo") + ACCEL_KEY(QKeySequence::Undo), this, SLOT(undo()));
2115         a->setEnabled(d->doc->isUndoAvailable());
2116         a = menu->addAction(tr("&Redo") + ACCEL_KEY(QKeySequence::Redo), this, SLOT(redo()));
2117         a->setEnabled(d->doc->isRedoAvailable());
2118         menu->addSeparator();
2119
2120         a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut()));
2121         a->setEnabled(d->cursor.hasSelection());
2122     }
2123
2124     if (showTextSelectionActions) {
2125         a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy()));
2126         a->setEnabled(d->cursor.hasSelection());
2127     }
2128
2129     if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
2130             || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
2131
2132         a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
2133         a->setEnabled(!d->linkToCopy.isEmpty());
2134     }
2135
2136     if (d->interactionFlags & Qt::TextEditable) {
2137 #if !defined(QT_NO_CLIPBOARD)
2138         a = menu->addAction(tr("&Paste") + ACCEL_KEY(QKeySequence::Paste), this, SLOT(paste()));
2139         a->setEnabled(canPaste());
2140 #endif
2141         a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
2142         a->setEnabled(d->cursor.hasSelection());
2143     }
2144
2145
2146     if (showTextSelectionActions) {
2147         menu->addSeparator();
2148         a = menu->addAction(tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll), this, SLOT(selectAll()));
2149         a->setEnabled(!d->doc->isEmpty());
2150     }
2151
2152 #if !defined(QT_NO_IM)
2153     if (d->contextWidget) {
2154         QInputContext *qic = qApp->inputContext();
2155         if (qic) {
2156             QList<QAction *> imActions = qic->actions();
2157             for (int i = 0; i < imActions.size(); ++i)
2158                 menu->addAction(imActions.at(i));
2159         }
2160     }
2161 #endif
2162
2163 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
2164     if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
2165 #else
2166     if (d->interactionFlags & Qt::TextEditable) {
2167 #endif
2168         menu->addSeparator();
2169         QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
2170         menu->addMenu(ctrlCharacterMenu);
2171     }
2172
2173     return menu;
2174 }
2175 #endif // QT_NO_CONTEXTMENU
2176
2177 QTextCursor QWidgetTextControl::cursorForPosition(const QPointF &pos) const
2178 {
2179     Q_D(const QWidgetTextControl);
2180     int cursorPos = hitTest(pos, Qt::FuzzyHit);
2181     if (cursorPos == -1)
2182         cursorPos = 0;
2183     QTextCursor c(d->doc);
2184     c.setPosition(cursorPos);
2185     return c;
2186 }
2187
2188 QRectF QWidgetTextControl::cursorRect(const QTextCursor &cursor) const
2189 {
2190     Q_D(const QWidgetTextControl);
2191     if (cursor.isNull())
2192         return QRectF();
2193
2194     return d->rectForPosition(cursor.position());
2195 }
2196
2197 QRectF QWidgetTextControl::cursorRect() const
2198 {
2199     Q_D(const QWidgetTextControl);
2200     return cursorRect(d->cursor);
2201 }
2202
2203 QRectF QWidgetTextControlPrivate::cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
2204 {
2205     if (cursor.isNull())
2206         return QRectF();
2207
2208     return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
2209 }
2210
2211 QString QWidgetTextControl::anchorAt(const QPointF &pos) const
2212 {
2213     Q_D(const QWidgetTextControl);
2214     return d->doc->documentLayout()->anchorAt(pos);
2215 }
2216
2217 QString QWidgetTextControl::anchorAtCursor() const
2218 {
2219     Q_D(const QWidgetTextControl);
2220
2221     return d->anchorForCursor(d->cursor);
2222 }
2223
2224 bool QWidgetTextControl::overwriteMode() const
2225 {
2226     Q_D(const QWidgetTextControl);
2227     return d->overwriteMode;
2228 }
2229
2230 void QWidgetTextControl::setOverwriteMode(bool overwrite)
2231 {
2232     Q_D(QWidgetTextControl);
2233     d->overwriteMode = overwrite;
2234 }
2235
2236 int QWidgetTextControl::cursorWidth() const
2237 {
2238 #ifndef QT_NO_PROPERTIES
2239     Q_D(const QWidgetTextControl);
2240     return d->doc->documentLayout()->property("cursorWidth").toInt();
2241 #else
2242     return 1;
2243 #endif
2244 }
2245
2246 void QWidgetTextControl::setCursorWidth(int width)
2247 {
2248     Q_D(QWidgetTextControl);
2249 #ifdef QT_NO_PROPERTIES
2250     Q_UNUSED(width);
2251 #else
2252     if (width == -1)
2253         width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth);
2254     d->doc->documentLayout()->setProperty("cursorWidth", width);
2255 #endif
2256     d->repaintCursor();
2257 }
2258
2259 bool QWidgetTextControl::acceptRichText() const
2260 {
2261     Q_D(const QWidgetTextControl);
2262     return d->acceptRichText;
2263 }
2264
2265 void QWidgetTextControl::setAcceptRichText(bool accept)
2266 {
2267     Q_D(QWidgetTextControl);
2268     d->acceptRichText = accept;
2269 }
2270
2271 #ifndef QT_NO_TEXTEDIT
2272
2273 void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
2274 {
2275     Q_D(QWidgetTextControl);
2276
2277     QHash<int, int> hash;
2278     for (int i = 0; i < d->extraSelections.count(); ++i) {
2279         const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(i);
2280         hash.insertMulti(esel.cursor.anchor(), i);
2281     }
2282
2283     for (int i = 0; i < selections.count(); ++i) {
2284         const QTextEdit::ExtraSelection &sel = selections.at(i);
2285         QHash<int, int>::iterator it = hash.find(sel.cursor.anchor());
2286         if (it != hash.end()) {
2287             const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2288             if (esel.cursor.position() == sel.cursor.position()
2289                 && esel.format == sel.format) {
2290                 hash.erase(it);
2291                 continue;
2292             }
2293         }
2294         QRectF r = selectionRect(sel.cursor);
2295         if (sel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2296             r.setLeft(0);
2297             r.setWidth(qreal(INT_MAX));
2298         }
2299         emit updateRequest(r);
2300     }
2301
2302     for (QHash<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
2303         const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2304         QRectF r = selectionRect(esel.cursor);
2305         if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2306             r.setLeft(0);
2307             r.setWidth(qreal(INT_MAX));
2308         }
2309         emit updateRequest(r);
2310     }
2311
2312     d->extraSelections.resize(selections.count());
2313     for (int i = 0; i < selections.count(); ++i) {
2314         d->extraSelections[i].cursor = selections.at(i).cursor;
2315         d->extraSelections[i].format = selections.at(i).format;
2316     }
2317 }
2318
2319 QList<QTextEdit::ExtraSelection> QWidgetTextControl::extraSelections() const
2320 {
2321     Q_D(const QWidgetTextControl);
2322     QList<QTextEdit::ExtraSelection> selections;
2323     for (int i = 0; i < d->extraSelections.count(); ++i) {
2324         QTextEdit::ExtraSelection sel;
2325         sel.cursor = d->extraSelections.at(i).cursor;
2326         sel.format = d->extraSelections.at(i).format;
2327         selections.append(sel);
2328     }
2329     return selections;
2330 }
2331
2332 #endif // QT_NO_TEXTEDIT
2333
2334 void QWidgetTextControl::setTextWidth(qreal width)
2335 {
2336     Q_D(QWidgetTextControl);
2337     d->doc->setTextWidth(width);
2338 }
2339
2340 qreal QWidgetTextControl::textWidth() const
2341 {
2342     Q_D(const QWidgetTextControl);
2343     return d->doc->textWidth();
2344 }
2345
2346 QSizeF QWidgetTextControl::size() const
2347 {
2348     Q_D(const QWidgetTextControl);
2349     return d->doc->size();
2350 }
2351
2352 void QWidgetTextControl::setOpenExternalLinks(bool open)
2353 {
2354     Q_D(QWidgetTextControl);
2355     d->openExternalLinks = open;
2356 }
2357
2358 bool QWidgetTextControl::openExternalLinks() const
2359 {
2360     Q_D(const QWidgetTextControl);
2361     return d->openExternalLinks;
2362 }
2363
2364 bool QWidgetTextControl::ignoreUnusedNavigationEvents() const
2365 {
2366     Q_D(const QWidgetTextControl);
2367     return d->ignoreUnusedNavigationEvents;
2368 }
2369
2370 void QWidgetTextControl::setIgnoreUnusedNavigationEvents(bool ignore)
2371 {
2372     Q_D(QWidgetTextControl);
2373     d->ignoreUnusedNavigationEvents = ignore;
2374 }
2375
2376 void QWidgetTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
2377 {
2378     Q_D(QWidgetTextControl);
2379     const QTextCursor oldSelection = d->cursor;
2380     const bool moved = d->cursor.movePosition(op, mode);
2381     d->_q_updateCurrentCharFormatAndSelection();
2382     ensureCursorVisible();
2383     d->repaintOldAndNewSelection(oldSelection);
2384     if (moved)
2385         emit cursorPositionChanged();
2386 }
2387
2388 bool QWidgetTextControl::canPaste() const
2389 {
2390 #ifndef QT_NO_CLIPBOARD
2391     Q_D(const QWidgetTextControl);
2392     if (d->interactionFlags & Qt::TextEditable) {
2393         const QMimeData *md = QApplication::clipboard()->mimeData();
2394         return md && canInsertFromMimeData(md);
2395     }
2396 #endif
2397     return false;
2398 }
2399
2400 void QWidgetTextControl::setCursorIsFocusIndicator(bool b)
2401 {
2402     Q_D(QWidgetTextControl);
2403     d->cursorIsFocusIndicator = b;
2404     d->repaintCursor();
2405 }
2406
2407 bool QWidgetTextControl::cursorIsFocusIndicator() const
2408 {
2409     Q_D(const QWidgetTextControl);
2410     return d->cursorIsFocusIndicator;
2411 }
2412
2413
2414 void QWidgetTextControl::setDragEnabled(bool enabled)
2415 {
2416     Q_D(QWidgetTextControl);
2417     d->dragEnabled = enabled;
2418 }
2419
2420 bool QWidgetTextControl::isDragEnabled() const
2421 {
2422     Q_D(const QWidgetTextControl);
2423     return d->dragEnabled;
2424 }
2425
2426 void QWidgetTextControl::setWordSelectionEnabled(bool enabled)
2427 {
2428     Q_D(QWidgetTextControl);
2429     d->wordSelectionEnabled = enabled;
2430 }
2431
2432 bool QWidgetTextControl::isWordSelectionEnabled() const
2433 {
2434     Q_D(const QWidgetTextControl);
2435     return d->wordSelectionEnabled;
2436 }
2437
2438 void QWidgetTextControl::print(QPagedPaintDevice *printer) const
2439 {
2440     Q_D(const QWidgetTextControl);
2441     if (!printer)
2442         return;
2443     QTextDocument *tempDoc = 0;
2444     const QTextDocument *doc = d->doc;
2445     if (QPagedPaintDevicePrivate::get(printer)->printSelectionOnly) {
2446         if (!d->cursor.hasSelection())
2447             return;
2448         tempDoc = new QTextDocument(const_cast<QTextDocument *>(doc));
2449         tempDoc->setMetaInformation(QTextDocument::DocumentTitle, doc->metaInformation(QTextDocument::DocumentTitle));
2450         tempDoc->setPageSize(doc->pageSize());
2451         tempDoc->setDefaultFont(doc->defaultFont());
2452         tempDoc->setUseDesignMetrics(doc->useDesignMetrics());
2453         QTextCursor(tempDoc).insertFragment(d->cursor.selection());
2454         doc = tempDoc;
2455
2456         // copy the custom object handlers
2457         doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
2458     }
2459     doc->print(printer);
2460     delete tempDoc;
2461 }
2462
2463 QMimeData *QWidgetTextControl::createMimeDataFromSelection() const
2464 {
2465     Q_D(const QWidgetTextControl);
2466     const QTextDocumentFragment fragment(d->cursor);
2467     return new QTextEditMimeData(fragment);
2468 }
2469
2470 bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
2471 {
2472     Q_D(const QWidgetTextControl);
2473     if (d->acceptRichText)
2474         return (source->hasText() && !source->text().isEmpty())
2475             || source->hasHtml()
2476             || source->hasFormat(QLatin1String("application/x-qrichtext"))
2477             || source->hasFormat(QLatin1String("application/x-qt-richtext"));
2478     else
2479         return source->hasText() && !source->text().isEmpty();
2480 }
2481
2482 void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
2483 {
2484     Q_D(QWidgetTextControl);
2485     if (!(d->interactionFlags & Qt::TextEditable) || !source)
2486         return;
2487
2488     bool hasData = false;
2489     QTextDocumentFragment fragment;
2490 #ifndef QT_NO_TEXTHTMLPARSER
2491     if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
2492         // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
2493         QString richtext = QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
2494         richtext.prepend(QLatin1String("<meta name=\"qrichtext\" content=\"1\" />"));
2495         fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
2496         hasData = true;
2497     } else if (source->hasHtml() && d->acceptRichText) {
2498         fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
2499         hasData = true;
2500     } else {
2501         QString text = source->text();
2502         if (!text.isNull()) {
2503             fragment = QTextDocumentFragment::fromPlainText(text);
2504             hasData = true;
2505         }
2506     }
2507 #else
2508     fragment = QTextDocumentFragment::fromPlainText(source->text());
2509 #endif // QT_NO_TEXTHTMLPARSER
2510
2511     if (hasData)
2512         d->cursor.insertFragment(fragment);
2513     ensureCursorVisible();
2514 }
2515
2516 bool QWidgetTextControl::findNextPrevAnchor(const QTextCursor &startCursor, bool next, QTextCursor &newAnchor)
2517 {
2518     Q_D(QWidgetTextControl);
2519
2520     int anchorStart = -1;
2521     QString anchorHref;
2522     int anchorEnd = -1;
2523
2524     if (next) {
2525         const int startPos = startCursor.selectionEnd();
2526
2527         QTextBlock block = d->doc->findBlock(startPos);
2528         QTextBlock::Iterator it = block.begin();
2529
2530         while (!it.atEnd() && it.fragment().position() < startPos)
2531             ++it;
2532
2533         while (block.isValid()) {
2534             anchorStart = -1;
2535
2536             // find next anchor
2537             for (; !it.atEnd(); ++it) {
2538                 const QTextFragment fragment = it.fragment();
2539                 const QTextCharFormat fmt = fragment.charFormat();
2540
2541                 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2542                     anchorStart = fragment.position();
2543                     anchorHref = fmt.anchorHref();
2544                     break;
2545                 }
2546             }
2547
2548             if (anchorStart != -1) {
2549                 anchorEnd = -1;
2550
2551                 // find next non-anchor fragment
2552                 for (; !it.atEnd(); ++it) {
2553                     const QTextFragment fragment = it.fragment();
2554                     const QTextCharFormat fmt = fragment.charFormat();
2555
2556                     if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2557                         anchorEnd = fragment.position();
2558                         break;
2559                     }
2560                 }
2561
2562                 if (anchorEnd == -1)
2563                     anchorEnd = block.position() + block.length() - 1;
2564
2565                 // make found selection
2566                 break;
2567             }
2568
2569             block = block.next();
2570             it = block.begin();
2571         }
2572     } else {
2573         int startPos = startCursor.selectionStart();
2574         if (startPos > 0)
2575             --startPos;
2576
2577         QTextBlock block = d->doc->findBlock(startPos);
2578         QTextBlock::Iterator blockStart = block.begin();
2579         QTextBlock::Iterator it = block.end();
2580
2581         if (startPos == block.position()) {
2582             it = block.begin();
2583         } else {
2584             do {
2585                 if (it == blockStart) {
2586                     it = QTextBlock::Iterator();
2587                     block = QTextBlock();
2588                 } else {
2589                     --it;
2590                 }
2591             } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
2592         }
2593
2594         while (block.isValid()) {
2595             anchorStart = -1;
2596
2597             if (!it.atEnd()) {
2598                 do {
2599                     const QTextFragment fragment = it.fragment();
2600                     const QTextCharFormat fmt = fragment.charFormat();
2601
2602                     if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2603                         anchorStart = fragment.position() + fragment.length();
2604                         anchorHref = fmt.anchorHref();
2605                         break;
2606                     }
2607
2608                     if (it == blockStart)
2609                         it = QTextBlock::Iterator();
2610                     else
2611                         --it;
2612                 } while (!it.atEnd());
2613             }
2614
2615             if (anchorStart != -1 && !it.atEnd()) {
2616                 anchorEnd = -1;
2617
2618                 do {
2619                     const QTextFragment fragment = it.fragment();
2620                     const QTextCharFormat fmt = fragment.charFormat();
2621
2622                     if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2623                         anchorEnd = fragment.position() + fragment.length();
2624                         break;
2625                     }
2626
2627                     if (it == blockStart)
2628                         it = QTextBlock::Iterator();
2629                     else
2630                         --it;
2631                 } while (!it.atEnd());
2632
2633                 if (anchorEnd == -1)
2634                     anchorEnd = qMax(0, block.position());
2635
2636                 break;
2637             }
2638
2639             block = block.previous();
2640             it = block.end();
2641             if (it != block.begin())
2642                 --it;
2643             blockStart = block.begin();
2644         }
2645
2646     }
2647
2648     if (anchorStart != -1 && anchorEnd != -1) {
2649         newAnchor = d->cursor;
2650         newAnchor.setPosition(anchorStart);
2651         newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
2652         return true;
2653     }
2654
2655     return false;
2656 }
2657
2658 void QWidgetTextControlPrivate::activateLinkUnderCursor(QString href)
2659 {
2660     QTextCursor oldCursor = cursor;
2661
2662     if (href.isEmpty()) {
2663         QTextCursor tmp = cursor;
2664         if (tmp.selectionStart() != tmp.position())
2665             tmp.setPosition(tmp.selectionStart());
2666         tmp.movePosition(QTextCursor::NextCharacter);
2667         href = tmp.charFormat().anchorHref();
2668     }
2669     if (href.isEmpty())
2670         return;
2671
2672     if (!cursor.hasSelection()) {
2673         QTextBlock block = cursor.block();
2674         const int cursorPos = cursor.position();
2675
2676         QTextBlock::Iterator it = block.begin();
2677         QTextBlock::Iterator linkFragment;
2678
2679         for (; !it.atEnd(); ++it) {
2680             QTextFragment fragment = it.fragment();
2681             const int fragmentPos = fragment.position();
2682             if (fragmentPos <= cursorPos &&
2683                 fragmentPos + fragment.length() > cursorPos) {
2684                 linkFragment = it;
2685                 break;
2686             }
2687         }
2688
2689         if (!linkFragment.atEnd()) {
2690             it = linkFragment;
2691             cursor.setPosition(it.fragment().position());
2692             if (it != block.begin()) {
2693                 do {
2694                     --it;
2695                     QTextFragment fragment = it.fragment();
2696                     if (fragment.charFormat().anchorHref() != href)
2697                         break;
2698                     cursor.setPosition(fragment.position());
2699                 } while (it != block.begin());
2700             }
2701
2702             for (it = linkFragment; !it.atEnd(); ++it) {
2703                 QTextFragment fragment = it.fragment();
2704                 if (fragment.charFormat().anchorHref() != href)
2705                     break;
2706                 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
2707             }
2708         }
2709     }
2710
2711     if (hasFocus) {
2712         cursorIsFocusIndicator = true;
2713     } else {
2714         cursorIsFocusIndicator = false;
2715         cursor.clearSelection();
2716     }
2717     repaintOldAndNewSelection(oldCursor);
2718
2719 #ifndef QT_NO_DESKTOPSERVICES
2720     if (openExternalLinks)
2721         QDesktopServices::openUrl(href);
2722     else
2723 #endif
2724         emit q_func()->linkActivated(href);
2725 }
2726
2727 #ifndef QT_NO_TOOLTIP
2728 void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
2729 {
2730     const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
2731     if (toolTip.isEmpty())
2732         return;
2733     QToolTip::showText(globalPos, toolTip, contextWidget);
2734 }
2735 #endif // QT_NO_TOOLTIP
2736
2737 bool QWidgetTextControl::setFocusToNextOrPreviousAnchor(bool next)
2738 {
2739     Q_D(QWidgetTextControl);
2740
2741     if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2742         return false;
2743
2744     QRectF crect = selectionRect();
2745     emit updateRequest(crect);
2746
2747     // If we don't have a current anchor, we start from the start/end
2748     if (!d->cursor.hasSelection()) {
2749         d->cursor = QTextCursor(d->doc);
2750         if (next)
2751             d->cursor.movePosition(QTextCursor::Start);
2752         else
2753             d->cursor.movePosition(QTextCursor::End);
2754     }
2755
2756     QTextCursor newAnchor;
2757     if (findNextPrevAnchor(d->cursor, next, newAnchor)) {
2758         d->cursor = newAnchor;
2759         d->cursorIsFocusIndicator = true;
2760     } else {
2761         d->cursor.clearSelection();
2762     }
2763
2764     if (d->cursor.hasSelection()) {
2765         crect = selectionRect();
2766         emit updateRequest(crect);
2767         emit visibilityRequest(crect);
2768         return true;
2769     } else {
2770         return false;
2771     }
2772 }
2773
2774 bool QWidgetTextControl::setFocusToAnchor(const QTextCursor &newCursor)
2775 {
2776     Q_D(QWidgetTextControl);
2777
2778     if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2779         return false;
2780
2781     // Verify that this is an anchor.
2782     const QString anchorHref = d->anchorForCursor(newCursor);
2783     if (anchorHref.isEmpty())
2784         return false;
2785
2786     // and process it
2787     QRectF crect = selectionRect();
2788     emit updateRequest(crect);
2789
2790     d->cursor.setPosition(newCursor.selectionStart());
2791     d->cursor.setPosition(newCursor.selectionEnd(), QTextCursor::KeepAnchor);
2792     d->cursorIsFocusIndicator = true;
2793
2794     crect = selectionRect();
2795     emit updateRequest(crect);
2796     emit visibilityRequest(crect);
2797     return true;
2798 }
2799
2800 void QWidgetTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2801 {
2802     Q_D(QWidgetTextControl);
2803     if (flags == d->interactionFlags)
2804         return;
2805     d->interactionFlags = flags;
2806
2807     if (d->hasFocus)
2808         d->setBlinkingCursorEnabled(flags & Qt::TextEditable);
2809 }
2810
2811 Qt::TextInteractionFlags QWidgetTextControl::textInteractionFlags() const
2812 {
2813     Q_D(const QWidgetTextControl);
2814     return d->interactionFlags;
2815 }
2816
2817 void QWidgetTextControl::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2818 {
2819     Q_D(QWidgetTextControl);
2820     d->cursor.mergeCharFormat(modifier);
2821     d->updateCurrentCharFormat();
2822 }
2823
2824 void QWidgetTextControl::setCurrentCharFormat(const QTextCharFormat &format)
2825 {
2826     Q_D(QWidgetTextControl);
2827     d->cursor.setCharFormat(format);
2828     d->updateCurrentCharFormat();
2829 }
2830
2831 QTextCharFormat QWidgetTextControl::currentCharFormat() const
2832 {
2833     Q_D(const QWidgetTextControl);
2834     return d->cursor.charFormat();
2835 }
2836
2837 void QWidgetTextControl::insertPlainText(const QString &text)
2838 {
2839     Q_D(QWidgetTextControl);
2840     d->cursor.insertText(text);
2841 }
2842
2843 #ifndef QT_NO_TEXTHTMLPARSER
2844 void QWidgetTextControl::insertHtml(const QString &text)
2845 {
2846     Q_D(QWidgetTextControl);
2847     d->cursor.insertHtml(text);
2848 }
2849 #endif // QT_NO_TEXTHTMLPARSER
2850
2851 QPointF QWidgetTextControl::anchorPosition(const QString &name) const
2852 {
2853     Q_D(const QWidgetTextControl);
2854     if (name.isEmpty())
2855         return QPointF();
2856
2857     QRectF r;
2858     for (QTextBlock block = d->doc->begin(); block.isValid(); block = block.next()) {
2859         QTextCharFormat format = block.charFormat();
2860         if (format.isAnchor() && format.anchorNames().contains(name)) {
2861             r = d->rectForPosition(block.position());
2862             break;
2863         }
2864
2865         for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
2866             QTextFragment fragment = it.fragment();
2867             format = fragment.charFormat();
2868             if (format.isAnchor() && format.anchorNames().contains(name)) {
2869                 r = d->rectForPosition(fragment.position());
2870                 block = QTextBlock();
2871                 break;
2872             }
2873         }
2874     }
2875     if (!r.isValid())
2876         return QPointF();
2877     return QPointF(0, r.top());
2878 }
2879
2880 void QWidgetTextControl::adjustSize()
2881 {
2882     Q_D(QWidgetTextControl);
2883     d->doc->adjustSize();
2884 }
2885
2886 bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags options)
2887 {
2888     Q_D(QWidgetTextControl);
2889     QTextCursor search = d->doc->find(exp, d->cursor, options);
2890     if (search.isNull())
2891         return false;
2892
2893     setTextCursor(search);
2894     return true;
2895 }
2896
2897
2898
2899 void QWidgetTextControlPrivate::append(const QString &text, Qt::TextFormat format)
2900 {
2901     QTextCursor tmp(doc);
2902     tmp.beginEditBlock();
2903     tmp.movePosition(QTextCursor::End);
2904
2905     if (!doc->isEmpty())
2906         tmp.insertBlock(cursor.blockFormat(), cursor.charFormat());
2907     else
2908         tmp.setCharFormat(cursor.charFormat());
2909
2910     // preserve the char format
2911     QTextCharFormat oldCharFormat = cursor.charFormat();
2912
2913 #ifndef QT_NO_TEXTHTMLPARSER
2914     if (format == Qt::RichText || (format == Qt::AutoText && Qt::mightBeRichText(text))) {
2915         tmp.insertHtml(text);
2916     } else {
2917         tmp.insertText(text);
2918     }
2919 #else
2920     tmp.insertText(text);
2921 #endif // QT_NO_TEXTHTMLPARSER
2922     if (!cursor.hasSelection())
2923         cursor.setCharFormat(oldCharFormat);
2924
2925     tmp.endEditBlock();
2926 }
2927
2928 void QWidgetTextControl::append(const QString &text)
2929 {
2930     Q_D(QWidgetTextControl);
2931     d->append(text, Qt::AutoText);
2932 }
2933
2934 void QWidgetTextControl::appendHtml(const QString &html)
2935 {
2936     Q_D(QWidgetTextControl);
2937     d->append(html, Qt::RichText);
2938 }
2939
2940 void QWidgetTextControl::appendPlainText(const QString &text)
2941 {
2942     Q_D(QWidgetTextControl);
2943     d->append(text, Qt::PlainText);
2944 }
2945
2946
2947 void QWidgetTextControl::ensureCursorVisible()
2948 {
2949     Q_D(QWidgetTextControl);
2950     QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
2951     emit visibilityRequest(crect);
2952     emit microFocusChanged();
2953 }
2954
2955 QPalette QWidgetTextControl::palette() const
2956 {
2957     Q_D(const QWidgetTextControl);
2958     return d->palette;
2959 }
2960
2961 void QWidgetTextControl::setPalette(const QPalette &pal)
2962 {
2963     Q_D(QWidgetTextControl);
2964     d->palette = pal;
2965 }
2966
2967 QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QWidget *widget) const
2968 {
2969     Q_D(const QWidgetTextControl);
2970
2971     QAbstractTextDocumentLayout::PaintContext ctx;
2972
2973     ctx.selections = d->extraSelections;
2974     ctx.palette = d->palette;
2975     if (d->cursorOn && d->isEnabled) {
2976         if (d->hideCursor)
2977             ctx.cursorPosition = -1;
2978         else if (d->preeditCursor != 0)
2979             ctx.cursorPosition = - (d->preeditCursor + 2);
2980         else
2981             ctx.cursorPosition = d->cursor.position();
2982     }
2983
2984     if (!d->dndFeedbackCursor.isNull())
2985         ctx.cursorPosition = d->dndFeedbackCursor.position();
2986 #ifdef QT_KEYPAD_NAVIGATION
2987     if (!QApplication::keypadNavigationEnabled() || d->hasEditFocus)
2988 #endif
2989     if (d->cursor.hasSelection()) {
2990         QAbstractTextDocumentLayout::Selection selection;
2991         selection.cursor = d->cursor;
2992         if (d->cursorIsFocusIndicator) {
2993             QStyleOption opt;
2994             opt.palette = ctx.palette;
2995             QStyleHintReturnVariant ret;
2996             QStyle *style = QApplication::style();
2997             if (widget)
2998                 style = widget->style();
2999             style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
3000             selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
3001         } else {
3002             QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
3003             selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
3004             selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
3005             QStyleOption opt;
3006             QStyle *style = QApplication::style();
3007             if (widget) {
3008                 opt.initFrom(widget);
3009                 style = widget->style();
3010             }
3011             if (style->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, widget))
3012                 selection.format.setProperty(QTextFormat::FullWidthSelection, true);
3013         }
3014         ctx.selections.append(selection);
3015     }
3016
3017     return ctx;
3018 }
3019
3020 void QWidgetTextControl::drawContents(QPainter *p, const QRectF &rect, QWidget *widget)
3021 {
3022     Q_D(QWidgetTextControl);
3023     p->save();
3024     QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext(widget);
3025     if (rect.isValid())
3026         p->setClipRect(rect, Qt::IntersectClip);
3027     ctx.clip = rect;
3028
3029     d->doc->documentLayout()->draw(p, ctx);
3030     p->restore();
3031 }
3032
3033 void QWidgetTextControlPrivate::_q_copyLink()
3034 {
3035 #ifndef QT_NO_CLIPBOARD
3036     QMimeData *md = new QMimeData;
3037     md->setText(linkToCopy);
3038     QApplication::clipboard()->setMimeData(md);
3039 #endif
3040 }
3041
3042 int QWidgetTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
3043 {
3044     Q_D(const QWidgetTextControl);
3045     return d->doc->documentLayout()->hitTest(point, accuracy);
3046 }
3047
3048 QRectF QWidgetTextControl::blockBoundingRect(const QTextBlock &block) const
3049 {
3050     Q_D(const QWidgetTextControl);
3051     return d->doc->documentLayout()->blockBoundingRect(block);
3052 }
3053
3054 #ifndef QT_NO_CONTEXTMENU
3055 #define NUM_CONTROL_CHARACTERS 10
3056 const struct QUnicodeControlCharacter {
3057     const char *text;
3058     ushort character;
3059 } qt_controlCharacters[NUM_CONTROL_CHARACTERS] = {
3060     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRM Left-to-right mark"), 0x200e },
3061     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLM Right-to-left mark"), 0x200f },
3062     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWJ Zero width joiner"), 0x200d },
3063     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWNJ Zero width non-joiner"), 0x200c },
3064     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWSP Zero width space"), 0x200b },
3065     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRE Start of left-to-right embedding"), 0x202a },
3066     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLE Start of right-to-left embedding"), 0x202b },
3067     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRO Start of left-to-right override"), 0x202d },
3068     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLO Start of right-to-left override"), 0x202e },
3069     { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "PDF Pop directional formatting"), 0x202c },
3070 };
3071
3072 QUnicodeControlCharacterMenu::QUnicodeControlCharacterMenu(QObject *_editWidget, QWidget *parent)
3073     : QMenu(parent), editWidget(_editWidget)
3074 {
3075     setTitle(tr("Insert Unicode control character"));
3076     for (int i = 0; i < NUM_CONTROL_CHARACTERS; ++i) {
3077         addAction(tr(qt_controlCharacters[i].text), this, SLOT(menuActionTriggered()));
3078     }
3079 }
3080
3081 void QUnicodeControlCharacterMenu::menuActionTriggered()
3082 {
3083     QAction *a = qobject_cast<QAction *>(sender());
3084     int idx = actions().indexOf(a);
3085     if (idx < 0 || idx >= NUM_CONTROL_CHARACTERS)
3086         return;
3087     QChar c(qt_controlCharacters[idx].character);
3088     QString str(c);
3089
3090 #ifndef QT_NO_TEXTEDIT
3091     if (QTextEdit *edit = qobject_cast<QTextEdit *>(editWidget)) {
3092         edit->insertPlainText(str);
3093         return;
3094     }
3095 #endif
3096     if (QWidgetTextControl *control = qobject_cast<QWidgetTextControl *>(editWidget)) {
3097         control->insertPlainText(str);
3098     }
3099 #ifndef QT_NO_LINEEDIT
3100     if (QLineEdit *edit = qobject_cast<QLineEdit *>(editWidget)) {
3101         edit->insert(str);
3102         return;
3103     }
3104 #endif
3105 }
3106 #endif // QT_NO_CONTEXTMENU
3107
3108 QStringList QTextEditMimeData::formats() const
3109 {
3110     if (!fragment.isEmpty())
3111         return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html")
3112 #ifndef QT_NO_TEXTODFWRITER
3113             << QString::fromLatin1("application/vnd.oasis.opendocument.text")
3114 #endif
3115         ;
3116     else
3117         return QMimeData::formats();
3118 }
3119
3120 QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
3121 {
3122     if (!fragment.isEmpty())
3123         setup();
3124     return QMimeData::retrieveData(mimeType, type);
3125 }
3126
3127 void QTextEditMimeData::setup() const
3128 {
3129     QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
3130 #ifndef QT_NO_TEXTHTMLPARSER
3131     that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
3132 #endif
3133 #ifndef QT_NO_TEXTODFWRITER
3134     {
3135         QBuffer buffer;
3136         QTextDocumentWriter writer(&buffer, "ODF");
3137         writer.write(fragment);
3138         buffer.close();
3139         that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
3140     }
3141 #endif
3142     that->setText(fragment.toPlainText());
3143     fragment = QTextDocumentFragment();
3144 }
3145
3146 QT_END_NAMESPACE
3147
3148 #include "moc_qwidgettextcontrol_p.cpp"
3149
3150 #endif // QT_NO_TEXTCONTROL