1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qtextcontrol_p.h"
43 #include "qtextcontrol_p_p.h"
45 #ifndef QT_NO_TEXTCONTROL
53 #include <qclipboard.h>
57 #include "private/qtextdocumentlayout_p.h"
58 #include "private/qabstracttextdocumentlayout_p.h"
59 #include "private/qtextedit_p.h"
60 #include "qtextdocument.h"
61 #include "private/qtextdocument_p.h"
62 #include "qtextlist.h"
63 #include "private/qtextcontrol_p.h"
64 #include "qgraphicssceneevent.h"
66 #include "qtextdocumentwriter.h"
67 #include "private/qtextcursor_p.h"
69 #include <qtextformat.h>
70 #include <qdatetime.h>
72 #include <qapplication.h>
74 #include <qtexttable.h>
77 #include <qdesktopservices.h>
78 #include <qinputcontext.h>
80 #include <qstyleoption.h>
81 #include <QtGui/qlineedit.h>
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())
89 #define ACCEL_KEY(k) QString()
94 #ifndef QT_NO_CONTEXTMENU
95 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
96 extern bool qt_use_rtl_extensions;
100 // could go into QTextCursor...
101 static QTextLine currentTextLine(const QTextCursor &cursor)
103 const QTextBlock block = cursor.block();
104 if (!block.isValid())
107 const QTextLayout *layout = block.layout();
111 const int relativePos = cursor.position() - block.position();
112 return layout->lineForTextPosition(relativePos);
115 QTextControlPrivate::QTextControlPrivate()
116 : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
117 interactionFlags(Qt::TextEditorInteraction),
119 #ifndef QT_NO_DRAGANDDROP
120 mousePressed(false), mightStartDrag(false),
122 lastSelectionState(false), ignoreAutomaticScrollbarAdjustement(false),
123 overwriteMode(false),
124 acceptRichText(true),
125 preeditCursor(0), hideCursor(false),
127 #ifdef QT_KEYPAD_NAVIGATION
131 hadSelectionOnMousePress(false),
132 ignoreUnusedNavigationEvents(false),
133 openExternalLinks(false),
134 wordSelectionEnabled(false)
137 bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
139 #ifdef QT_NO_SHORTCUT
147 const QTextCursor oldSelection = cursor;
148 const int oldCursorPos = cursor.position();
150 QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
151 QTextCursor::MoveOperation op = QTextCursor::NoMove;
155 #ifndef QT_NO_SHORTCUT
156 if (e == QKeySequence::MoveToNextChar) {
157 op = QTextCursor::Right;
159 else if (e == QKeySequence::MoveToPreviousChar) {
160 op = QTextCursor::Left;
162 else if (e == QKeySequence::SelectNextChar) {
163 op = QTextCursor::Right;
164 mode = QTextCursor::KeepAnchor;
166 else if (e == QKeySequence::SelectPreviousChar) {
167 op = QTextCursor::Left;
168 mode = QTextCursor::KeepAnchor;
170 else if (e == QKeySequence::SelectNextWord) {
171 op = QTextCursor::WordRight;
172 mode = QTextCursor::KeepAnchor;
174 else if (e == QKeySequence::SelectPreviousWord) {
175 op = QTextCursor::WordLeft;
176 mode = QTextCursor::KeepAnchor;
178 else if (e == QKeySequence::SelectStartOfLine) {
179 op = QTextCursor::StartOfLine;
180 mode = QTextCursor::KeepAnchor;
182 else if (e == QKeySequence::SelectEndOfLine) {
183 op = QTextCursor::EndOfLine;
184 mode = QTextCursor::KeepAnchor;
186 else if (e == QKeySequence::SelectStartOfBlock) {
187 op = QTextCursor::StartOfBlock;
188 mode = QTextCursor::KeepAnchor;
190 else if (e == QKeySequence::SelectEndOfBlock) {
191 op = QTextCursor::EndOfBlock;
192 mode = QTextCursor::KeepAnchor;
194 else if (e == QKeySequence::SelectStartOfDocument) {
195 op = QTextCursor::Start;
196 mode = QTextCursor::KeepAnchor;
198 else if (e == QKeySequence::SelectEndOfDocument) {
199 op = QTextCursor::End;
200 mode = QTextCursor::KeepAnchor;
202 else if (e == QKeySequence::SelectPreviousLine) {
203 op = QTextCursor::Up;
204 mode = QTextCursor::KeepAnchor;
206 else if (e == QKeySequence::SelectNextLine) {
207 op = QTextCursor::Down;
208 mode = QTextCursor::KeepAnchor;
210 QTextBlock block = cursor.block();
211 QTextLine line = currentTextLine(cursor);
212 if (!block.next().isValid()
214 && line.lineNumber() == block.layout()->lineCount() - 1)
215 op = QTextCursor::End;
218 else if (e == QKeySequence::MoveToNextWord) {
219 op = QTextCursor::WordRight;
221 else if (e == QKeySequence::MoveToPreviousWord) {
222 op = QTextCursor::WordLeft;
224 else if (e == QKeySequence::MoveToEndOfBlock) {
225 op = QTextCursor::EndOfBlock;
227 else if (e == QKeySequence::MoveToStartOfBlock) {
228 op = QTextCursor::StartOfBlock;
230 else if (e == QKeySequence::MoveToNextLine) {
231 op = QTextCursor::Down;
233 else if (e == QKeySequence::MoveToPreviousLine) {
234 op = QTextCursor::Up;
236 else if (e == QKeySequence::MoveToPreviousLine) {
237 op = QTextCursor::Up;
239 else if (e == QKeySequence::MoveToStartOfLine) {
240 op = QTextCursor::StartOfLine;
242 else if (e == QKeySequence::MoveToEndOfLine) {
243 op = QTextCursor::EndOfLine;
245 else if (e == QKeySequence::MoveToStartOfDocument) {
246 op = QTextCursor::Start;
248 else if (e == QKeySequence::MoveToEndOfDocument) {
249 op = QTextCursor::End;
251 #endif // QT_NO_SHORTCUT
256 // Except for pageup and pagedown, Mac OS X has very different behavior, we don't do it all, but
257 // here's the breakdown:
258 // Shift still works as an anchor, but only one of the other keys can be down Ctrl (Command),
259 // Alt (Option), or Meta (Control).
260 // Command/Control + Left/Right -- Move to left or right of the line
261 // + Up/Down -- Move to top bottom of the file. (Control doesn't move the cursor)
262 // Option + Left/Right -- Move one word Left/right.
263 // + Up/Down -- Begin/End of Paragraph.
264 // Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
266 bool visualNavigation = cursor.visualNavigation();
267 cursor.setVisualNavigation(true);
268 const bool moved = cursor.movePosition(op, mode);
269 cursor.setVisualNavigation(visualNavigation);
270 q->ensureCursorVisible();
272 bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
273 bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
275 #ifdef QT_KEYPAD_NAVIGATION
276 ignoreNavigationEvents = ignoreNavigationEvents || QApplication::keypadNavigationEnabled();
277 isNavigationEvent = isNavigationEvent ||
278 (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional
279 && (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right));
281 isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
285 if (cursor.position() != oldCursorPos)
286 emit q->cursorPositionChanged();
287 emit q->microFocusChanged();
288 } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
292 selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
294 repaintOldAndNewSelection(oldSelection);
299 void QTextControlPrivate::updateCurrentCharFormat()
303 QTextCharFormat fmt = cursor.charFormat();
304 if (fmt == lastCharFormat)
306 lastCharFormat = fmt;
308 emit q->currentCharFormatChanged(fmt);
309 emit q->microFocusChanged();
312 void QTextControlPrivate::indent()
314 QTextBlockFormat blockFmt = cursor.blockFormat();
316 QTextList *list = cursor.currentList();
318 QTextBlockFormat modifier;
319 modifier.setIndent(blockFmt.indent() + 1);
320 cursor.mergeBlockFormat(modifier);
322 QTextListFormat format = list->format();
323 format.setIndent(format.indent() + 1);
325 if (list->itemNumber(cursor.block()) == 1)
326 list->setFormat(format);
328 cursor.createList(format);
332 void QTextControlPrivate::outdent()
334 QTextBlockFormat blockFmt = cursor.blockFormat();
336 QTextList *list = cursor.currentList();
339 QTextBlockFormat modifier;
340 modifier.setIndent(blockFmt.indent() - 1);
341 cursor.mergeBlockFormat(modifier);
343 QTextListFormat listFmt = list->format();
344 listFmt.setIndent(listFmt.indent() - 1);
345 list->setFormat(listFmt);
349 void QTextControlPrivate::gotoNextTableCell()
351 QTextTable *table = cursor.currentTable();
352 QTextTableCell cell = table->cellAt(cursor);
354 int newColumn = cell.column() + cell.columnSpan();
355 int newRow = cell.row();
357 if (newColumn >= table->columns()) {
360 if (newRow >= table->rows())
361 table->insertRows(table->rows(), 1);
364 cell = table->cellAt(newRow, newColumn);
365 cursor = cell.firstCursorPosition();
368 void QTextControlPrivate::gotoPreviousTableCell()
370 QTextTable *table = cursor.currentTable();
371 QTextTableCell cell = table->cellAt(cursor);
373 int newColumn = cell.column() - 1;
374 int newRow = cell.row();
377 newColumn = table->columns() - 1;
383 cell = table->cellAt(newRow, newColumn);
384 cursor = cell.firstCursorPosition();
387 void QTextControlPrivate::createAutoBulletList()
389 cursor.beginEditBlock();
391 QTextBlockFormat blockFmt = cursor.blockFormat();
393 QTextListFormat listFmt;
394 listFmt.setStyle(QTextListFormat::ListDisc);
395 listFmt.setIndent(blockFmt.indent() + 1);
397 blockFmt.setIndent(0);
398 cursor.setBlockFormat(blockFmt);
400 cursor.createList(listFmt);
402 cursor.endEditBlock();
405 void QTextControlPrivate::init(Qt::TextFormat format, const QString &text, QTextDocument *document)
408 setContent(format, text, document);
410 doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
411 q->setCursorWidth(-1);
414 void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
418 // for use when called from setPlainText. we may want to re-use the currently
419 // set char format then.
420 const QTextCharFormat charFormatForInsertion = cursor.charFormat();
422 bool clearDocument = true;
426 clearDocument = false;
428 palette = QApplication::palette("QTextControl");
429 doc = new QTextDocument(q);
431 _q_documentLayoutChanged();
432 cursor = QTextCursor(doc);
434 // #### doc->documentLayout()->setPaintDevice(viewport);
436 QObject::connect(doc, SIGNAL(contentsChanged()), q, SLOT(_q_updateCurrentCharFormatAndSelection()));
437 QObject::connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), q, SLOT(_q_emitCursorPosChanged(QTextCursor)));
438 QObject::connect(doc, SIGNAL(documentLayoutChanged()), q, SLOT(_q_documentLayoutChanged()));
440 // convenience signal forwards
441 QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
442 QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
443 QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(modificationChanged(bool)));
444 QObject::connect(doc, SIGNAL(blockCountChanged(int)), q, SIGNAL(blockCountChanged(int)));
447 bool previousUndoRedoState = doc->isUndoRedoEnabled();
449 doc->setUndoRedoEnabled(false);
451 //Saving the index save some time.
452 static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()");
453 static int textChangedIndex = QTextControl::staticMetaObject.indexOfSignal("textChanged()");
454 // avoid multiple textChanged() signals being emitted
455 QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
457 if (!text.isEmpty()) {
458 // clear 'our' cursor for insertion to prevent
459 // the emission of the cursorPositionChanged() signal.
460 // instead we emit it only once at the end instead of
461 // at the end of the document after loading and when
462 // positioning the cursor again to the start of the
464 cursor = QTextCursor();
465 if (format == Qt::PlainText) {
466 QTextCursor formatCursor(doc);
467 // put the setPlainText and the setCharFormat into one edit block,
468 // so that the syntax highlight triggers only /once/ for the entire
469 // document, not twice.
470 formatCursor.beginEditBlock();
471 doc->setPlainText(text);
472 doc->setUndoRedoEnabled(false);
473 formatCursor.select(QTextCursor::Document);
474 formatCursor.setCharFormat(charFormatForInsertion);
475 formatCursor.endEditBlock();
477 #ifndef QT_NO_TEXTHTMLPARSER
480 doc->setPlainText(text);
482 doc->setUndoRedoEnabled(false);
484 cursor = QTextCursor(doc);
485 } else if (clearDocument) {
488 cursor.setCharFormat(charFormatForInsertion);
490 QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
491 emit q->textChanged();
493 doc->setUndoRedoEnabled(previousUndoRedoState);
494 _q_updateCurrentCharFormatAndSelection();
496 doc->setModified(false);
498 q->ensureCursorVisible();
499 emit q->cursorPositionChanged();
502 void QTextControlPrivate::startDrag()
504 #ifndef QT_NO_DRAGANDDROP
506 mousePressed = false;
509 QMimeData *data = q->createMimeDataFromSelection();
511 QDrag *drag = new QDrag(contextWidget);
512 drag->setMimeData(data);
514 Qt::DropActions actions = Qt::CopyAction;
515 Qt::DropAction action;
516 if (interactionFlags & Qt::TextEditable) {
517 actions |= Qt::MoveAction;
518 action = drag->exec(actions, Qt::MoveAction);
520 action = drag->exec(actions, Qt::CopyAction);
523 if (action == Qt::MoveAction && drag->target() != contextWidget)
524 cursor.removeSelectedText();
528 void QTextControlPrivate::setCursorPosition(const QPointF &pos)
531 const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
534 cursor.setPosition(cursorPos);
537 void QTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
539 cursor.setPosition(pos, mode);
541 if (mode != QTextCursor::KeepAnchor) {
542 selectedWordOnDoubleClick = QTextCursor();
543 selectedBlockOnTrippleClick = QTextCursor();
547 void QTextControlPrivate::repaintCursor()
550 emit q->updateRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
553 void QTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
556 if (cursor.hasSelection()
557 && oldSelection.hasSelection()
558 && cursor.currentFrame() == oldSelection.currentFrame()
559 && !cursor.hasComplexSelection()
560 && !oldSelection.hasComplexSelection()
561 && cursor.anchor() == oldSelection.anchor()
563 QTextCursor differenceSelection(doc);
564 differenceSelection.setPosition(oldSelection.position());
565 differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
566 emit q->updateRequest(q->selectionRect(differenceSelection));
568 if (!oldSelection.isNull())
569 emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
570 emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
574 void QTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
577 if (forceEmitSelectionChanged)
578 emit q->selectionChanged();
580 bool current = cursor.hasSelection();
581 if (current == lastSelectionState)
584 lastSelectionState = current;
585 emit q->copyAvailable(current);
586 if (!forceEmitSelectionChanged)
587 emit q->selectionChanged();
588 emit q->microFocusChanged();
591 void QTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
593 updateCurrentCharFormat();
597 #ifndef QT_NO_CLIPBOARD
598 void QTextControlPrivate::setClipboardSelection()
600 QClipboard *clipboard = QApplication::clipboard();
601 if (!cursor.hasSelection() || !clipboard->supportsSelection())
604 QMimeData *data = q->createMimeDataFromSelection();
605 clipboard->setMimeData(data, QClipboard::Selection);
609 void QTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
612 if (someCursor.isCopyOf(cursor)) {
613 emit q->cursorPositionChanged();
614 emit q->microFocusChanged();
618 void QTextControlPrivate::_q_documentLayoutChanged()
621 QAbstractTextDocumentLayout *layout = doc->documentLayout();
622 QObject::connect(layout, SIGNAL(update(QRectF)), q, SIGNAL(updateRequest(QRectF)));
623 QObject::connect(layout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(_q_updateBlock(QTextBlock)));
624 QObject::connect(layout, SIGNAL(documentSizeChanged(QSizeF)), q, SIGNAL(documentSizeChanged(QSizeF)));
628 void QTextControlPrivate::setBlinkingCursorEnabled(bool enable)
632 if (enable && QApplication::cursorFlashTime() > 0)
633 cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
635 cursorBlinkTimer.stop();
642 void QTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
646 // if inside the initial selected word keep that
647 if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
648 && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
649 q->setTextCursor(selectedWordOnDoubleClick);
653 QTextCursor curs = selectedWordOnDoubleClick;
654 curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
656 if (!curs.movePosition(QTextCursor::StartOfWord))
658 const int wordStartPos = curs.position();
660 const int blockPos = curs.block().position();
661 const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
663 QTextLine line = currentTextLine(curs);
667 const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
669 if (!curs.movePosition(QTextCursor::EndOfWord))
671 const int wordEndPos = curs.position();
673 const QTextLine otherLine = currentTextLine(curs);
674 if (otherLine.textStart() != line.textStart()
675 || wordEndPos == wordStartPos)
678 const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
680 if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
683 // keep the already selected word even when moving to the left
685 if (suggestedNewPosition < selectedWordOnDoubleClick.position())
686 cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
688 cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
690 const qreal differenceToStart = mouseXPosition - wordStartX;
691 const qreal differenceToEnd = wordEndX - mouseXPosition;
693 if (differenceToStart < differenceToEnd)
694 setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
696 setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
698 if (interactionFlags & Qt::TextSelectableByMouse) {
699 #ifndef QT_NO_CLIPBOARD
700 setClipboardSelection();
702 selectionChanged(true);
706 void QTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition)
710 // if inside the initial selected line keep that
711 if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
712 && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
713 q->setTextCursor(selectedBlockOnTrippleClick);
717 if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
718 cursor.setPosition(selectedBlockOnTrippleClick.selectionEnd());
719 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
720 cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
722 cursor.setPosition(selectedBlockOnTrippleClick.selectionStart());
723 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
724 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
725 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
728 if (interactionFlags & Qt::TextSelectableByMouse) {
729 #ifndef QT_NO_CLIPBOARD
730 setClipboardSelection();
732 selectionChanged(true);
736 void QTextControlPrivate::_q_deleteSelected()
738 if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
740 cursor.removeSelectedText();
743 void QTextControl::undo()
746 d->repaintSelection();
747 const int oldCursorPos = d->cursor.position();
748 d->doc->undo(&d->cursor);
749 if (d->cursor.position() != oldCursorPos)
750 emit cursorPositionChanged();
751 emit microFocusChanged();
752 ensureCursorVisible();
755 void QTextControl::redo()
758 d->repaintSelection();
759 const int oldCursorPos = d->cursor.position();
760 d->doc->redo(&d->cursor);
761 if (d->cursor.position() != oldCursorPos)
762 emit cursorPositionChanged();
763 emit microFocusChanged();
764 ensureCursorVisible();
767 QTextControl::QTextControl(QObject *parent)
768 : QObject(*new QTextControlPrivate, parent)
774 QTextControl::QTextControl(const QString &text, QObject *parent)
775 : QObject(*new QTextControlPrivate, parent)
778 d->init(Qt::RichText, text);
781 QTextControl::QTextControl(QTextDocument *doc, QObject *parent)
782 : QObject(*new QTextControlPrivate, parent)
785 d->init(Qt::RichText, QString(), doc);
788 QTextControl::~QTextControl()
792 void QTextControl::setDocument(QTextDocument *document)
795 if (d->doc == document)
798 d->doc->disconnect(this);
799 d->doc->documentLayout()->disconnect(this);
800 d->doc->documentLayout()->setPaintDevice(0);
802 if (d->doc->parent() == this)
806 d->setContent(Qt::RichText, QString(), document);
809 QTextDocument *QTextControl::document() const
811 Q_D(const QTextControl);
815 void QTextControl::setTextCursor(const QTextCursor &cursor)
818 d->cursorIsFocusIndicator = false;
819 const bool posChanged = cursor.position() != d->cursor.position();
820 const QTextCursor oldSelection = d->cursor;
822 d->cursorOn = d->hasFocus && (d->interactionFlags & Qt::TextEditable);
823 d->_q_updateCurrentCharFormatAndSelection();
824 ensureCursorVisible();
825 d->repaintOldAndNewSelection(oldSelection);
827 emit cursorPositionChanged();
830 QTextCursor QTextControl::textCursor() const
832 Q_D(const QTextControl);
836 #ifndef QT_NO_CLIPBOARD
838 void QTextControl::cut()
841 if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
844 d->cursor.removeSelectedText();
847 void QTextControl::copy()
850 if (!d->cursor.hasSelection())
852 QMimeData *data = createMimeDataFromSelection();
853 QApplication::clipboard()->setMimeData(data);
856 void QTextControl::paste(QClipboard::Mode mode)
858 const QMimeData *md = QApplication::clipboard()->mimeData(mode);
860 insertFromMimeData(md);
864 void QTextControl::clear()
867 // clears and sets empty content
868 d->extraSelections.clear();
873 void QTextControl::selectAll()
876 const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
877 d->cursor.select(QTextCursor::Document);
878 d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
879 d->cursorIsFocusIndicator = false;
880 emit updateRequest();
883 void QTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
886 m.translate(coordinateOffset.x(), coordinateOffset.y());
887 processEvent(e, m, contextWidget);
890 void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
893 if (d->interactionFlags == Qt::NoTextInteraction) {
898 d->contextWidget = contextWidget;
900 if (!d->contextWidget) {
902 #ifndef QT_NO_GRAPHICSVIEW
903 case QEvent::GraphicsSceneMouseMove:
904 case QEvent::GraphicsSceneMousePress:
905 case QEvent::GraphicsSceneMouseRelease:
906 case QEvent::GraphicsSceneMouseDoubleClick:
907 case QEvent::GraphicsSceneContextMenu:
908 case QEvent::GraphicsSceneHoverEnter:
909 case QEvent::GraphicsSceneHoverMove:
910 case QEvent::GraphicsSceneHoverLeave:
911 case QEvent::GraphicsSceneHelp:
912 case QEvent::GraphicsSceneDragEnter:
913 case QEvent::GraphicsSceneDragMove:
914 case QEvent::GraphicsSceneDragLeave:
915 case QEvent::GraphicsSceneDrop: {
916 QGraphicsSceneEvent *ev = static_cast<QGraphicsSceneEvent *>(e);
917 d->contextWidget = ev->widget();
920 #endif // QT_NO_GRAPHICSVIEW
926 case QEvent::KeyPress:
927 d->keyPressEvent(static_cast<QKeyEvent *>(e));
929 case QEvent::MouseButtonPress: {
930 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
931 d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
932 ev->buttons(), ev->globalPos());
934 case QEvent::MouseMove: {
935 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
936 d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
937 ev->buttons(), ev->globalPos());
939 case QEvent::MouseButtonRelease: {
940 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
941 d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
942 ev->buttons(), ev->globalPos());
944 case QEvent::MouseButtonDblClick: {
945 QMouseEvent *ev = static_cast<QMouseEvent *>(e);
946 d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(),
947 ev->buttons(), ev->globalPos());
949 case QEvent::InputMethod:
950 d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
952 #ifndef QT_NO_CONTEXTMENU
953 case QEvent::ContextMenu: {
954 QContextMenuEvent *ev = static_cast<QContextMenuEvent *>(e);
955 d->contextMenuEvent(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
957 #endif // QT_NO_CONTEXTMENU
958 case QEvent::FocusIn:
959 case QEvent::FocusOut:
960 d->focusEvent(static_cast<QFocusEvent *>(e));
963 case QEvent::EnabledChange:
964 d->isEnabled = e->isAccepted();
967 #ifndef QT_NO_TOOLTIP
968 case QEvent::ToolTip: {
969 QHelpEvent *ev = static_cast<QHelpEvent *>(e);
970 d->showToolTip(ev->globalPos(), matrix.map(ev->pos()), contextWidget);
973 #endif // QT_NO_TOOLTIP
975 #ifndef QT_NO_DRAGANDDROP
976 case QEvent::DragEnter: {
977 QDragEnterEvent *ev = static_cast<QDragEnterEvent *>(e);
978 if (d->dragEnterEvent(e, ev->mimeData()))
979 ev->acceptProposedAction();
982 case QEvent::DragLeave:
985 case QEvent::DragMove: {
986 QDragMoveEvent *ev = static_cast<QDragMoveEvent *>(e);
987 if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
988 ev->acceptProposedAction();
992 QDropEvent *ev = static_cast<QDropEvent *>(e);
993 if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
994 ev->acceptProposedAction();
999 #ifndef QT_NO_GRAPHICSVIEW
1000 case QEvent::GraphicsSceneMousePress: {
1001 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1002 d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1005 case QEvent::GraphicsSceneMouseMove: {
1006 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1007 d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1010 case QEvent::GraphicsSceneMouseRelease: {
1011 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1012 d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1015 case QEvent::GraphicsSceneMouseDoubleClick: {
1016 QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e);
1017 d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(),
1020 case QEvent::GraphicsSceneContextMenu: {
1021 QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
1022 d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
1025 case QEvent::GraphicsSceneHoverMove: {
1026 QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e);
1027 d->mouseMoveEvent(ev, Qt::NoButton, matrix.map(ev->pos()), ev->modifiers(),Qt::NoButton,
1031 case QEvent::GraphicsSceneDragEnter: {
1032 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1033 if (d->dragEnterEvent(e, ev->mimeData()))
1034 ev->acceptProposedAction();
1036 case QEvent::GraphicsSceneDragLeave:
1037 d->dragLeaveEvent();
1039 case QEvent::GraphicsSceneDragMove: {
1040 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1041 if (d->dragMoveEvent(e, ev->mimeData(), matrix.map(ev->pos())))
1042 ev->acceptProposedAction();
1044 case QEvent::GraphicsSceneDrop: {
1045 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1046 if (d->dropEvent(ev->mimeData(), matrix.map(ev->pos()), ev->dropAction(), ev->source()))
1049 #endif // QT_NO_GRAPHICSVIEW
1050 #ifdef QT_KEYPAD_NAVIGATION
1051 case QEvent::EnterEditFocus:
1052 case QEvent::LeaveEditFocus:
1053 if (QApplication::keypadNavigationEnabled())
1054 d->editFocusEvent(e);
1057 case QEvent::ShortcutOverride:
1058 if (d->interactionFlags & Qt::TextEditable) {
1059 QKeyEvent* ke = static_cast<QKeyEvent *>(e);
1060 if (ke->modifiers() == Qt::NoModifier
1061 || ke->modifiers() == Qt::ShiftModifier
1062 || ke->modifiers() == Qt::KeypadModifier) {
1063 if (ke->key() < Qt::Key_Escape) {
1066 switch (ke->key()) {
1067 case Qt::Key_Return:
1069 case Qt::Key_Delete:
1072 case Qt::Key_Backspace:
1083 #ifndef QT_NO_SHORTCUT
1084 } else if (ke == QKeySequence::Copy
1085 || ke == QKeySequence::Paste
1086 || ke == QKeySequence::Cut
1087 || ke == QKeySequence::Redo
1088 || ke == QKeySequence::Undo
1089 || ke == QKeySequence::MoveToNextWord
1090 || ke == QKeySequence::MoveToPreviousWord
1091 || ke == QKeySequence::MoveToStartOfDocument
1092 || ke == QKeySequence::MoveToEndOfDocument
1093 || ke == QKeySequence::SelectNextWord
1094 || ke == QKeySequence::SelectPreviousWord
1095 || ke == QKeySequence::SelectStartOfLine
1096 || ke == QKeySequence::SelectEndOfLine
1097 || ke == QKeySequence::SelectStartOfBlock
1098 || ke == QKeySequence::SelectEndOfBlock
1099 || ke == QKeySequence::SelectStartOfDocument
1100 || ke == QKeySequence::SelectEndOfDocument
1101 || ke == QKeySequence::SelectAll
1113 bool QTextControl::event(QEvent *e)
1115 return QObject::event(e);
1118 void QTextControl::timerEvent(QTimerEvent *e)
1121 if (e->timerId() == d->cursorBlinkTimer.timerId()) {
1122 d->cursorOn = !d->cursorOn;
1124 if (d->cursor.hasSelection())
1125 d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
1129 } else if (e->timerId() == d->trippleClickTimer.timerId()) {
1130 d->trippleClickTimer.stop();
1134 void QTextControl::setPlainText(const QString &text)
1137 d->setContent(Qt::PlainText, text);
1140 void QTextControl::setHtml(const QString &text)
1143 d->setContent(Qt::RichText, text);
1146 void QTextControlPrivate::keyPressEvent(QKeyEvent *e)
1149 #ifndef QT_NO_SHORTCUT
1150 if (e == QKeySequence::SelectAll) {
1155 #ifndef QT_NO_CLIPBOARD
1156 else if (e == QKeySequence::Copy) {
1162 #endif // QT_NO_SHORTCUT
1164 if (interactionFlags & Qt::TextSelectableByKeyboard
1165 && cursorMoveKeyEvent(e))
1168 if (interactionFlags & Qt::LinksAccessibleByKeyboard) {
1169 if ((e->key() == Qt::Key_Return
1170 || e->key() == Qt::Key_Enter
1171 #ifdef QT_KEYPAD_NAVIGATION
1172 || e->key() == Qt::Key_Select
1175 && cursor.hasSelection()) {
1178 activateLinkUnderCursor();
1183 if (!(interactionFlags & Qt::TextEditable)) {
1188 if (e->key() == Qt::Key_Direction_L || e->key() == Qt::Key_Direction_R) {
1189 QTextBlockFormat fmt;
1190 fmt.setLayoutDirection((e->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft);
1191 cursor.mergeBlockFormat(fmt);
1195 // schedule a repaint of the region of the cursor, as when we move it we
1196 // want to make sure the old cursor disappears (not noticeable when moving
1197 // only a few pixels but noticeable when jumping between cells in tables for
1201 if (e->key() == Qt::Key_Backspace && !(e->modifiers() & ~Qt::ShiftModifier)) {
1202 QTextBlockFormat blockFmt = cursor.blockFormat();
1203 QTextList *list = cursor.currentList();
1204 if (list && cursor.atBlockStart() && !cursor.hasSelection()) {
1205 list->remove(cursor.block());
1206 } else if (cursor.atBlockStart() && blockFmt.indent() > 0) {
1207 blockFmt.setIndent(blockFmt.indent() - 1);
1208 cursor.setBlockFormat(blockFmt);
1210 QTextCursor localCursor = cursor;
1211 localCursor.deletePreviousChar();
1215 #ifndef QT_NO_SHORTCUT
1216 else if (e == QKeySequence::InsertParagraphSeparator) {
1217 cursor.insertBlock();
1220 } else if (e == QKeySequence::InsertLineSeparator) {
1221 cursor.insertText(QString(QChar::LineSeparator));
1228 #ifndef QT_NO_SHORTCUT
1229 else if (e == QKeySequence::Undo) {
1232 else if (e == QKeySequence::Redo) {
1235 #ifndef QT_NO_CLIPBOARD
1236 else if (e == QKeySequence::Cut) {
1239 else if (e == QKeySequence::Paste) {
1240 QClipboard::Mode mode = QClipboard::Clipboard;
1242 if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
1243 mode = QClipboard::Selection;
1248 else if (e == QKeySequence::Delete) {
1249 QTextCursor localCursor = cursor;
1250 localCursor.deleteChar();
1252 else if (e == QKeySequence::DeleteEndOfWord) {
1253 if (!cursor.hasSelection())
1254 cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
1255 cursor.removeSelectedText();
1257 else if (e == QKeySequence::DeleteStartOfWord) {
1258 if (!cursor.hasSelection())
1259 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
1260 cursor.removeSelectedText();
1262 else if (e == QKeySequence::DeleteEndOfLine) {
1263 QTextBlock block = cursor.block();
1264 if (cursor.position() == block.position() + block.length() - 2)
1265 cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
1267 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1268 cursor.removeSelectedText();
1270 #endif // QT_NO_SHORTCUT
1278 QString text = e->text();
1279 if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
1281 // no need to call deleteChar() if we have a selection, insertText
1283 && !cursor.hasSelection()
1284 && !cursor.atBlockEnd())
1285 cursor.deleteChar();
1287 cursor.insertText(text);
1300 q->ensureCursorVisible();
1302 updateCurrentCharFormat();
1305 QVariant QTextControl::loadResource(int type, const QUrl &name)
1307 #ifdef QT_NO_TEXTEDIT
1311 if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent())) {
1312 QUrl resolvedName = textEdit->d_func()->resolveUrl(name);
1313 return textEdit->loadResource(type, resolvedName);
1319 void QTextControlPrivate::_q_updateBlock(const QTextBlock &block)
1322 QRectF br = q->blockBoundingRect(block);
1323 br.setRight(qreal(INT_MAX)); // the block might have shrunk
1324 emit q->updateRequest(br);
1327 QRectF QTextControlPrivate::rectForPosition(int position) const
1329 Q_Q(const QTextControl);
1330 const QTextBlock block = doc->findBlock(position);
1331 if (!block.isValid())
1333 const QAbstractTextDocumentLayout *docLayout = doc->documentLayout();
1334 const QTextLayout *layout = block.layout();
1335 const QPointF layoutPos = q->blockBoundingRect(block).topLeft();
1336 int relativePos = position - block.position();
1337 if (preeditCursor != 0) {
1338 int preeditPos = layout->preeditAreaPosition();
1339 if (relativePos == preeditPos)
1340 relativePos += preeditCursor;
1341 else if (relativePos > preeditPos)
1342 relativePos += layout->preeditAreaText().length();
1344 QTextLine line = layout->lineForTextPosition(relativePos);
1349 #ifndef QT_NO_PROPERTIES
1350 cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
1358 if (line.isValid()) {
1359 qreal x = line.cursorToX(relativePos);
1361 if (overwriteMode) {
1362 if (relativePos < line.textLength() - line.textStart())
1363 w = line.cursorToX(relativePos + 1) - x;
1365 w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
1367 r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
1368 cursorWidth + w, line.height());
1370 r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
1376 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
1378 return frame->firstPosition() < position;
1381 static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame)
1383 return position < frame->lastPosition();
1386 static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
1389 QTextFrame *frame = cursor.currentFrame();
1390 const QList<QTextFrame *> children = frame->childFrames();
1392 const QList<QTextFrame *>::ConstIterator firstFrame = qLowerBound(children.constBegin(), children.constEnd(),
1393 cursor.selectionStart(), firstFramePosLessThanCursorPos);
1394 const QList<QTextFrame *>::ConstIterator lastFrame = qUpperBound(children.constBegin(), children.constEnd(),
1395 cursor.selectionEnd(), cursorPosLessThanLastFramePos);
1396 for (QList<QTextFrame *>::ConstIterator it = firstFrame; it != lastFrame; ++it) {
1397 if ((*it)->frameFormat().position() != QTextFrameFormat::InFlow)
1398 r |= frame->document()->documentLayout()->frameBoundingRect(*it);
1403 QRectF QTextControl::selectionRect(const QTextCursor &cursor) const
1405 Q_D(const QTextControl);
1407 QRectF r = d->rectForPosition(cursor.selectionStart());
1409 if (cursor.hasComplexSelection() && cursor.currentTable()) {
1410 QTextTable *table = cursor.currentTable();
1412 r = d->doc->documentLayout()->frameBoundingRect(table);
1414 int firstRow, numRows, firstColumn, numColumns;
1415 cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
1417 const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
1418 const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
1420 const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
1422 QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
1424 for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1425 const QTextTableCell cell = table->cellAt(firstRow, col);
1426 const qreal y = layout->blockBoundingRect(cell.firstCursorPosition().block()).top();
1428 tableSelRect.setTop(qMin(tableSelRect.top(), y));
1431 for (int row = firstRow; row < firstRow + numRows; ++row) {
1432 const QTextTableCell cell = table->cellAt(row, firstColumn);
1433 const qreal x = layout->blockBoundingRect(cell.firstCursorPosition().block()).left();
1435 tableSelRect.setLeft(qMin(tableSelRect.left(), x));
1438 for (int col = firstColumn; col < firstColumn + numColumns; ++col) {
1439 const QTextTableCell cell = table->cellAt(firstRow + numRows - 1, col);
1440 const qreal y = layout->blockBoundingRect(cell.lastCursorPosition().block()).bottom();
1442 tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
1445 for (int row = firstRow; row < firstRow + numRows; ++row) {
1446 const QTextTableCell cell = table->cellAt(row, firstColumn + numColumns - 1);
1447 const qreal x = layout->blockBoundingRect(cell.lastCursorPosition().block()).right();
1449 tableSelRect.setRight(qMax(tableSelRect.right(), x));
1452 r = tableSelRect.toRect();
1454 } else if (cursor.hasSelection()) {
1455 const int position = cursor.selectionStart();
1456 const int anchor = cursor.selectionEnd();
1457 const QTextBlock posBlock = d->doc->findBlock(position);
1458 const QTextBlock anchorBlock = d->doc->findBlock(anchor);
1459 if (posBlock == anchorBlock && posBlock.isValid() && posBlock.layout()->lineCount()) {
1460 const QTextLine posLine = posBlock.layout()->lineForTextPosition(position - posBlock.position());
1461 const QTextLine anchorLine = anchorBlock.layout()->lineForTextPosition(anchor - anchorBlock.position());
1463 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1464 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1465 const QTextLayout *layout = posBlock.layout();
1467 for (int i = firstLine; i <= lastLine; ++i) {
1468 r |= layout->lineAt(i).rect();
1469 r |= layout->lineAt(i).naturalTextRect(); // might be bigger in the case of wrap not enabled
1471 r.translate(blockBoundingRect(posBlock).topLeft());
1473 QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1475 r |= boundingRectOfFloatsInSelection(cursor);
1476 QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1477 r.setLeft(frameRect.left());
1478 r.setRight(frameRect.right());
1481 r.adjust(-1, -1, 1, 1);
1487 QRectF QTextControl::selectionRect() const
1489 Q_D(const QTextControl);
1490 return selectionRect(d->cursor);
1493 void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1494 Qt::MouseButtons buttons, const QPoint &globalPos)
1498 if (sendMouseEventToInputContext(
1499 e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
1503 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1504 anchorOnMousePress = q->anchorAt(pos);
1506 if (cursorIsFocusIndicator) {
1507 cursorIsFocusIndicator = false;
1509 cursor.clearSelection();
1512 if (!(button & Qt::LeftButton) ||
1513 !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
1518 cursorIsFocusIndicator = false;
1519 const QTextCursor oldSelection = cursor;
1520 const int oldCursorPos = cursor.position();
1522 mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
1523 #ifndef QT_NO_DRAGANDDROP
1524 mightStartDrag = false;
1527 if (trippleClickTimer.isActive()
1528 && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
1530 cursor.movePosition(QTextCursor::StartOfBlock);
1531 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1532 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1533 selectedBlockOnTrippleClick = cursor;
1535 anchorOnMousePress = QString();
1537 trippleClickTimer.stop();
1539 int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1540 if (cursorPos == -1) {
1545 if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
1546 if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1547 selectedWordOnDoubleClick = cursor;
1548 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1551 if (selectedBlockOnTrippleClick.hasSelection())
1552 extendBlockwiseSelection(cursorPos);
1553 else if (selectedWordOnDoubleClick.hasSelection())
1554 extendWordwiseSelection(cursorPos, pos.x());
1555 else if (!wordSelectionEnabled)
1556 setCursorPosition(cursorPos, QTextCursor::KeepAnchor);
1560 && cursor.hasSelection()
1561 && !cursorIsFocusIndicator
1562 && cursorPos >= cursor.selectionStart()
1563 && cursorPos <= cursor.selectionEnd()
1564 && q->hitTest(pos, Qt::ExactHit) != -1) {
1565 #ifndef QT_NO_DRAGANDDROP
1566 mightStartDrag = true;
1567 dragStartPos = pos.toPoint();
1572 setCursorPosition(cursorPos);
1576 if (interactionFlags & Qt::TextEditable) {
1577 q->ensureCursorVisible();
1578 if (cursor.position() != oldCursorPos)
1579 emit q->cursorPositionChanged();
1580 _q_updateCurrentCharFormatAndSelection();
1582 if (cursor.position() != oldCursorPos) {
1583 emit q->cursorPositionChanged();
1584 emit q->microFocusChanged();
1588 repaintOldAndNewSelection(oldSelection);
1589 hadSelectionOnMousePress = cursor.hasSelection();
1592 void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &mousePos, Qt::KeyboardModifiers modifiers,
1593 Qt::MouseButtons buttons, const QPoint &globalPos)
1597 if (sendMouseEventToInputContext(
1598 e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos)) {
1602 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1603 QString anchor = q->anchorAt(mousePos);
1604 if (anchor != highlightedAnchor) {
1605 highlightedAnchor = anchor;
1606 emit q->linkHovered(anchor);
1610 if (!(buttons & Qt::LeftButton))
1613 const bool editable = interactionFlags & Qt::TextEditable;
1618 || selectedWordOnDoubleClick.hasSelection()
1619 || selectedBlockOnTrippleClick.hasSelection()))
1622 const QTextCursor oldSelection = cursor;
1623 const int oldCursorPos = cursor.position();
1625 if (mightStartDrag) {
1626 if ((mousePos.toPoint() - dragStartPos).manhattanLength() > QApplication::startDragDistance())
1634 const qreal mouseX = qreal(mousePos.x());
1636 int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1637 if (newCursorPos == -1)
1640 if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1641 selectedWordOnDoubleClick = cursor;
1642 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1645 if (selectedBlockOnTrippleClick.hasSelection())
1646 extendBlockwiseSelection(newCursorPos);
1647 else if (selectedWordOnDoubleClick.hasSelection())
1648 extendWordwiseSelection(newCursorPos, mouseX);
1650 setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
1652 if (interactionFlags & Qt::TextEditable) {
1653 // don't call ensureVisible for the visible cursor to avoid jumping
1654 // scrollbars. the autoscrolling ensures smooth scrolling if necessary.
1655 //q->ensureCursorVisible();
1656 if (cursor.position() != oldCursorPos)
1657 emit q->cursorPositionChanged();
1658 _q_updateCurrentCharFormatAndSelection();
1660 if (contextWidget) {
1661 if (QInputContext *ic = inputContext()) {
1667 //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
1668 if (cursor.position() != oldCursorPos)
1669 emit q->cursorPositionChanged();
1671 selectionChanged(true);
1672 repaintOldAndNewSelection(oldSelection);
1675 void QTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1676 Qt::MouseButtons buttons, const QPoint &globalPos)
1680 if (sendMouseEventToInputContext(
1681 e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
1685 const QTextCursor oldSelection = cursor;
1686 const int oldCursorPos = cursor.position();
1688 #ifndef QT_NO_DRAGANDDROP
1689 if (mightStartDrag && (button & Qt::LeftButton)) {
1690 mousePressed = false;
1691 setCursorPosition(pos);
1692 cursor.clearSelection();
1697 mousePressed = false;
1698 #ifndef QT_NO_CLIPBOARD
1699 setClipboardSelection();
1700 selectionChanged(true);
1701 } else if (button == Qt::MidButton
1702 && (interactionFlags & Qt::TextEditable)
1703 && QApplication::clipboard()->supportsSelection()) {
1704 setCursorPosition(pos);
1705 const QMimeData *md = QApplication::clipboard()->mimeData(QClipboard::Selection);
1707 q->insertFromMimeData(md);
1711 repaintOldAndNewSelection(oldSelection);
1713 if (cursor.position() != oldCursorPos)
1714 emit q->cursorPositionChanged();
1716 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1717 if (!(button & Qt::LeftButton))
1720 const QString anchor = q->anchorAt(pos);
1722 if (anchor.isEmpty())
1725 if (!cursor.hasSelection()
1726 || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1728 const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1729 if (anchorPos != -1) {
1730 cursor.setPosition(anchorPos);
1732 QString anchor = anchorOnMousePress;
1733 anchorOnMousePress = QString();
1734 activateLinkUnderCursor(anchor);
1740 void QTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1741 Qt::MouseButtons buttons, const QPoint &globalPos)
1745 if (sendMouseEventToInputContext(
1746 e, QEvent::MouseButtonDblClick, button, pos, modifiers, buttons, globalPos)) {
1750 if (button != Qt::LeftButton
1751 || !(interactionFlags & Qt::TextSelectableByMouse)) {
1756 #ifndef QT_NO_DRAGANDDROP
1757 mightStartDrag = false;
1759 const QTextCursor oldSelection = cursor;
1760 setCursorPosition(pos);
1761 QTextLine line = currentTextLine(cursor);
1762 bool doEmit = false;
1763 if (line.isValid() && line.textLength()) {
1764 cursor.select(QTextCursor::WordUnderCursor);
1767 repaintOldAndNewSelection(oldSelection);
1769 cursorIsFocusIndicator = false;
1770 selectedWordOnDoubleClick = cursor;
1772 trippleClickPoint = pos;
1773 trippleClickTimer.start(QApplication::doubleClickInterval(), q);
1776 #ifndef QT_NO_CLIPBOARD
1777 setClipboardSelection();
1779 emit q->cursorPositionChanged();
1783 bool QTextControlPrivate::sendMouseEventToInputContext(
1784 QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos,
1785 Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos)
1787 #if !defined(QT_NO_IM)
1790 QTextLayout *layout = cursor.block().layout();
1791 if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) {
1792 QInputContext *ctx = inputContext();
1793 int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position();
1795 if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length()) {
1797 // don't send move events outside the preedit area
1798 if (eventType == QEvent::MouseMove)
1802 QMouseEvent ev(eventType, contextWidget->mapFromGlobal(globalPos), globalPos,
1803 button, buttons, modifiers);
1804 ctx->mouseHandler(cursorPos, &ev);
1805 e->setAccepted(ev.isAccepted());
1807 if (!layout->preeditAreaText().isEmpty())
1812 Q_UNUSED(eventType);
1815 Q_UNUSED(modifiers);
1817 Q_UNUSED(globalPos);
1822 void QTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
1824 #ifdef QT_NO_CONTEXTMENU
1825 Q_UNUSED(screenPos);
1827 Q_UNUSED(contextWidget);
1832 QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
1835 menu->setAttribute(Qt::WA_DeleteOnClose);
1836 menu->popup(screenPos);
1840 bool QTextControlPrivate::dragEnterEvent(QEvent *e, const QMimeData *mimeData)
1843 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1848 dndFeedbackCursor = QTextCursor();
1850 return true; // accept proposed action
1853 void QTextControlPrivate::dragLeaveEvent()
1857 const QRectF crect = q->cursorRect(dndFeedbackCursor);
1858 dndFeedbackCursor = QTextCursor();
1860 if (crect.isValid())
1861 emit q->updateRequest(crect);
1864 bool QTextControlPrivate::dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
1867 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1872 const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1873 if (cursorPos != -1) {
1874 QRectF crect = q->cursorRect(dndFeedbackCursor);
1875 if (crect.isValid())
1876 emit q->updateRequest(crect);
1878 dndFeedbackCursor = cursor;
1879 dndFeedbackCursor.setPosition(cursorPos);
1881 crect = q->cursorRect(dndFeedbackCursor);
1882 emit q->updateRequest(crect);
1885 return true; // accept proposed action
1888 bool QTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QWidget *source)
1891 dndFeedbackCursor = QTextCursor();
1893 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
1898 QTextCursor insertionCursor = q->cursorForPosition(pos);
1899 insertionCursor.beginEditBlock();
1901 if (dropAction == Qt::MoveAction && source == contextWidget)
1902 cursor.removeSelectedText();
1904 cursor = insertionCursor;
1905 q->insertFromMimeData(mimeData);
1906 insertionCursor.endEditBlock();
1907 q->ensureCursorVisible();
1908 return true; // accept proposed action
1911 void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
1914 if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
1918 bool isGettingInput = !e->commitString().isEmpty()
1919 || e->preeditString() != cursor.block().layout()->preeditAreaText()
1920 || e->replacementLength() > 0;
1921 bool forceSelectionChanged = false;
1923 cursor.beginEditBlock();
1924 if (isGettingInput) {
1925 cursor.removeSelectedText();
1928 // insert commit string
1929 if (!e->commitString().isEmpty() || e->replacementLength()) {
1930 QTextCursor c = cursor;
1931 c.setPosition(c.position() + e->replacementStart());
1932 c.setPosition(c.position() + e->replacementLength(), QTextCursor::KeepAnchor);
1933 c.insertText(e->commitString());
1936 for (int i = 0; i < e->attributes().size(); ++i) {
1937 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1938 if (a.type == QInputMethodEvent::Selection) {
1939 QTextCursor oldCursor = cursor;
1940 int blockStart = a.start + cursor.block().position();
1941 cursor.setPosition(blockStart, QTextCursor::MoveAnchor);
1942 cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
1943 q->ensureCursorVisible();
1944 repaintOldAndNewSelection(oldCursor);
1945 forceSelectionChanged = true;
1949 QTextBlock block = cursor.block();
1950 QTextLayout *layout = block.layout();
1952 layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
1953 QList<QTextLayout::FormatRange> overrides;
1954 const int oldPreeditCursor = preeditCursor;
1955 preeditCursor = e->preeditString().length();
1957 for (int i = 0; i < e->attributes().size(); ++i) {
1958 const QInputMethodEvent::Attribute &a = e->attributes().at(i);
1959 if (a.type == QInputMethodEvent::Cursor) {
1960 preeditCursor = a.start;
1961 hideCursor = !a.length;
1962 } else if (a.type == QInputMethodEvent::TextFormat) {
1963 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
1965 QTextLayout::FormatRange o;
1966 o.start = a.start + cursor.position() - block.position();
1967 o.length = a.length;
1969 overrides.append(o);
1973 layout->setAdditionalFormats(overrides);
1974 cursor.endEditBlock();
1977 if (oldPreeditCursor != preeditCursor)
1978 emit q->microFocusChanged();
1979 selectionChanged(forceSelectionChanged);
1982 QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
1984 Q_D(const QTextControl);
1985 QTextBlock block = d->cursor.block();
1987 case Qt::ImMicroFocus:
1988 return cursorRect();
1990 return QVariant(d->cursor.charFormat().font());
1991 case Qt::ImCursorPosition:
1992 return QVariant(d->cursor.position() - block.position());
1993 case Qt::ImSurroundingText:
1994 return QVariant(block.text());
1995 case Qt::ImCurrentSelection:
1996 return QVariant(d->cursor.selectedText());
1997 case Qt::ImMaximumTextLength:
1998 return QVariant(); // No limit.
1999 case Qt::ImAnchorPosition:
2000 return QVariant(qBound(0, d->cursor.anchor() - block.position(), block.length()));
2006 void QTextControl::setFocus(bool focus, Qt::FocusReason reason)
2008 QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
2013 void QTextControlPrivate::focusEvent(QFocusEvent *e)
2016 emit q->updateRequest(q->selectionRect());
2017 if (e->gotFocus()) {
2018 #ifdef QT_KEYPAD_NAVIGATION
2019 if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason
2021 || e->reason() == Qt::ActiveWindowFocusReason
2025 cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard);
2026 if (interactionFlags & Qt::TextEditable) {
2027 setBlinkingCursorEnabled(true);
2029 #ifdef QT_KEYPAD_NAVIGATION
2033 setBlinkingCursorEnabled(false);
2035 if (cursorIsFocusIndicator
2036 && e->reason() != Qt::ActiveWindowFocusReason
2037 && e->reason() != Qt::PopupFocusReason
2038 && cursor.hasSelection()) {
2039 cursor.clearSelection();
2042 hasFocus = e->gotFocus();
2045 QString QTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
2047 if (anchorCursor.hasSelection()) {
2048 QTextCursor cursor = anchorCursor;
2049 if (cursor.selectionStart() != cursor.position())
2050 cursor.setPosition(cursor.selectionStart());
2051 cursor.movePosition(QTextCursor::NextCharacter);
2052 QTextCharFormat fmt = cursor.charFormat();
2053 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref))
2054 return fmt.stringProperty(QTextFormat::AnchorHref);
2059 #ifdef QT_KEYPAD_NAVIGATION
2060 void QTextControlPrivate::editFocusEvent(QEvent *e)
2064 if (QApplication::keypadNavigationEnabled()) {
2065 if (e->type() == QEvent::EnterEditFocus && interactionFlags & Qt::TextEditable) {
2066 const QTextCursor oldSelection = cursor;
2067 const int oldCursorPos = cursor.position();
2068 const bool moved = cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
2069 q->ensureCursorVisible();
2071 if (cursor.position() != oldCursorPos)
2072 emit q->cursorPositionChanged();
2073 emit q->microFocusChanged();
2076 repaintOldAndNewSelection(oldSelection);
2078 setBlinkingCursorEnabled(true);
2080 setBlinkingCursorEnabled(false);
2083 hasEditFocus = e->type() == QEvent::EnterEditFocus ? true : false;
2087 #ifndef QT_NO_CONTEXTMENU
2088 QMenu *QTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent)
2092 const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
2094 d->linkToCopy = QString();
2096 d->linkToCopy = anchorAt(pos);
2098 if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
2101 QMenu *menu = new QMenu(parent);
2104 if (d->interactionFlags & Qt::TextEditable) {
2105 a = menu->addAction(tr("&Undo") + ACCEL_KEY(QKeySequence::Undo), this, SLOT(undo()));
2106 a->setEnabled(d->doc->isUndoAvailable());
2107 a = menu->addAction(tr("&Redo") + ACCEL_KEY(QKeySequence::Redo), this, SLOT(redo()));
2108 a->setEnabled(d->doc->isRedoAvailable());
2109 menu->addSeparator();
2111 a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut()));
2112 a->setEnabled(d->cursor.hasSelection());
2115 if (showTextSelectionActions) {
2116 a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy()));
2117 a->setEnabled(d->cursor.hasSelection());
2120 if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
2121 || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
2123 a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
2124 a->setEnabled(!d->linkToCopy.isEmpty());
2127 if (d->interactionFlags & Qt::TextEditable) {
2128 #if !defined(QT_NO_CLIPBOARD)
2129 a = menu->addAction(tr("&Paste") + ACCEL_KEY(QKeySequence::Paste), this, SLOT(paste()));
2130 a->setEnabled(canPaste());
2132 a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
2133 a->setEnabled(d->cursor.hasSelection());
2137 if (showTextSelectionActions) {
2138 menu->addSeparator();
2139 a = menu->addAction(tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll), this, SLOT(selectAll()));
2140 a->setEnabled(!d->doc->isEmpty());
2143 #if !defined(QT_NO_IM)
2144 if (d->contextWidget) {
2145 QInputContext *qic = d->inputContext();
2147 QList<QAction *> imActions = qic->actions();
2148 for (int i = 0; i < imActions.size(); ++i)
2149 menu->addAction(imActions.at(i));
2154 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
2155 if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
2157 if (d->interactionFlags & Qt::TextEditable) {
2159 menu->addSeparator();
2160 QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
2161 menu->addMenu(ctrlCharacterMenu);
2166 #endif // QT_NO_CONTEXTMENU
2168 QTextCursor QTextControl::cursorForPosition(const QPointF &pos) const
2170 Q_D(const QTextControl);
2171 int cursorPos = hitTest(pos, Qt::FuzzyHit);
2172 if (cursorPos == -1)
2174 QTextCursor c(d->doc);
2175 c.setPosition(cursorPos);
2179 QRectF QTextControl::cursorRect(const QTextCursor &cursor) const
2181 Q_D(const QTextControl);
2182 if (cursor.isNull())
2185 return d->rectForPosition(cursor.position());
2188 QRectF QTextControl::cursorRect() const
2190 Q_D(const QTextControl);
2191 return cursorRect(d->cursor);
2194 QRectF QTextControlPrivate::cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
2196 if (cursor.isNull())
2199 return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
2202 QString QTextControl::anchorAt(const QPointF &pos) const
2204 Q_D(const QTextControl);
2205 return d->doc->documentLayout()->anchorAt(pos);
2208 QString QTextControl::anchorAtCursor() const
2210 Q_D(const QTextControl);
2212 return d->anchorForCursor(d->cursor);
2215 bool QTextControl::overwriteMode() const
2217 Q_D(const QTextControl);
2218 return d->overwriteMode;
2221 void QTextControl::setOverwriteMode(bool overwrite)
2224 d->overwriteMode = overwrite;
2227 int QTextControl::cursorWidth() const
2229 #ifndef QT_NO_PROPERTIES
2230 Q_D(const QTextControl);
2231 return d->doc->documentLayout()->property("cursorWidth").toInt();
2237 void QTextControl::setCursorWidth(int width)
2240 #ifdef QT_NO_PROPERTIES
2244 width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth);
2245 d->doc->documentLayout()->setProperty("cursorWidth", width);
2250 bool QTextControl::acceptRichText() const
2252 Q_D(const QTextControl);
2253 return d->acceptRichText;
2256 void QTextControl::setAcceptRichText(bool accept)
2259 d->acceptRichText = accept;
2262 #ifndef QT_NO_TEXTEDIT
2264 void QTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
2268 QHash<int, int> hash;
2269 for (int i = 0; i < d->extraSelections.count(); ++i) {
2270 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(i);
2271 hash.insertMulti(esel.cursor.anchor(), i);
2274 for (int i = 0; i < selections.count(); ++i) {
2275 const QTextEdit::ExtraSelection &sel = selections.at(i);
2276 QHash<int, int>::iterator it = hash.find(sel.cursor.anchor());
2277 if (it != hash.end()) {
2278 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2279 if (esel.cursor.position() == sel.cursor.position()
2280 && esel.format == sel.format) {
2285 QRectF r = selectionRect(sel.cursor);
2286 if (sel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2288 r.setWidth(qreal(INT_MAX));
2290 emit updateRequest(r);
2293 for (QHash<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
2294 const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
2295 QRectF r = selectionRect(esel.cursor);
2296 if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2298 r.setWidth(qreal(INT_MAX));
2300 emit updateRequest(r);
2303 d->extraSelections.resize(selections.count());
2304 for (int i = 0; i < selections.count(); ++i) {
2305 d->extraSelections[i].cursor = selections.at(i).cursor;
2306 d->extraSelections[i].format = selections.at(i).format;
2310 QList<QTextEdit::ExtraSelection> QTextControl::extraSelections() const
2312 Q_D(const QTextControl);
2313 QList<QTextEdit::ExtraSelection> selections;
2314 for (int i = 0; i < d->extraSelections.count(); ++i) {
2315 QTextEdit::ExtraSelection sel;
2316 sel.cursor = d->extraSelections.at(i).cursor;
2317 sel.format = d->extraSelections.at(i).format;
2318 selections.append(sel);
2323 #endif // QT_NO_TEXTEDIT
2325 void QTextControl::setTextWidth(qreal width)
2328 d->doc->setTextWidth(width);
2331 qreal QTextControl::textWidth() const
2333 Q_D(const QTextControl);
2334 return d->doc->textWidth();
2337 QSizeF QTextControl::size() const
2339 Q_D(const QTextControl);
2340 return d->doc->size();
2343 void QTextControl::setOpenExternalLinks(bool open)
2346 d->openExternalLinks = open;
2349 bool QTextControl::openExternalLinks() const
2351 Q_D(const QTextControl);
2352 return d->openExternalLinks;
2355 bool QTextControl::ignoreUnusedNavigationEvents() const
2357 Q_D(const QTextControl);
2358 return d->ignoreUnusedNavigationEvents;
2361 void QTextControl::setIgnoreUnusedNavigationEvents(bool ignore)
2364 d->ignoreUnusedNavigationEvents = ignore;
2367 void QTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
2370 const QTextCursor oldSelection = d->cursor;
2371 const bool moved = d->cursor.movePosition(op, mode);
2372 d->_q_updateCurrentCharFormatAndSelection();
2373 ensureCursorVisible();
2374 d->repaintOldAndNewSelection(oldSelection);
2376 emit cursorPositionChanged();
2379 bool QTextControl::canPaste() const
2381 #ifndef QT_NO_CLIPBOARD
2382 Q_D(const QTextControl);
2383 if (d->interactionFlags & Qt::TextEditable) {
2384 const QMimeData *md = QApplication::clipboard()->mimeData();
2385 return md && canInsertFromMimeData(md);
2391 void QTextControl::setCursorIsFocusIndicator(bool b)
2394 d->cursorIsFocusIndicator = b;
2398 bool QTextControl::cursorIsFocusIndicator() const
2400 Q_D(const QTextControl);
2401 return d->cursorIsFocusIndicator;
2405 void QTextControl::setDragEnabled(bool enabled)
2408 d->dragEnabled = enabled;
2411 bool QTextControl::isDragEnabled() const
2413 Q_D(const QTextControl);
2414 return d->dragEnabled;
2417 void QTextControl::setWordSelectionEnabled(bool enabled)
2420 d->wordSelectionEnabled = enabled;
2423 bool QTextControl::isWordSelectionEnabled() const
2425 Q_D(const QTextControl);
2426 return d->wordSelectionEnabled;
2429 #ifndef QT_NO_PRINTER
2430 void QTextControl::print(QPrinter *printer) const
2432 #ifndef QT_NO_PRINTER
2433 Q_D(const QTextControl);
2434 if (!printer || !printer->isValid())
2436 QTextDocument *tempDoc = 0;
2437 const QTextDocument *doc = d->doc;
2438 if (printer->printRange() == QPrinter::Selection) {
2439 if (!d->cursor.hasSelection())
2441 tempDoc = new QTextDocument(const_cast<QTextDocument *>(doc));
2442 tempDoc->setMetaInformation(QTextDocument::DocumentTitle, doc->metaInformation(QTextDocument::DocumentTitle));
2443 tempDoc->setPageSize(doc->pageSize());
2444 tempDoc->setDefaultFont(doc->defaultFont());
2445 tempDoc->setUseDesignMetrics(doc->useDesignMetrics());
2446 QTextCursor(tempDoc).insertFragment(d->cursor.selection());
2449 // copy the custom object handlers
2450 doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
2452 doc->print(printer);
2456 #endif // QT_NO_PRINTER
2458 QMimeData *QTextControl::createMimeDataFromSelection() const
2460 Q_D(const QTextControl);
2461 const QTextDocumentFragment fragment(d->cursor);
2462 return new QTextEditMimeData(fragment);
2465 bool QTextControl::canInsertFromMimeData(const QMimeData *source) const
2467 Q_D(const QTextControl);
2468 if (d->acceptRichText)
2469 return (source->hasText() && !source->text().isEmpty())
2470 || source->hasHtml()
2471 || source->hasFormat(QLatin1String("application/x-qrichtext"))
2472 || source->hasFormat(QLatin1String("application/x-qt-richtext"));
2474 return source->hasText() && !source->text().isEmpty();
2477 void QTextControl::insertFromMimeData(const QMimeData *source)
2480 if (!(d->interactionFlags & Qt::TextEditable) || !source)
2483 bool hasData = false;
2484 QTextDocumentFragment fragment;
2485 #ifndef QT_NO_TEXTHTMLPARSER
2486 if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
2487 // x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
2488 QString richtext = QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
2489 richtext.prepend(QLatin1String("<meta name=\"qrichtext\" content=\"1\" />"));
2490 fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
2492 } else if (source->hasHtml() && d->acceptRichText) {
2493 fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
2496 QString text = source->text();
2497 if (!text.isNull()) {
2498 fragment = QTextDocumentFragment::fromPlainText(text);
2503 fragment = QTextDocumentFragment::fromPlainText(source->text());
2504 #endif // QT_NO_TEXTHTMLPARSER
2507 d->cursor.insertFragment(fragment);
2508 ensureCursorVisible();
2511 bool QTextControl::findNextPrevAnchor(const QTextCursor &startCursor, bool next, QTextCursor &newAnchor)
2515 int anchorStart = -1;
2520 const int startPos = startCursor.selectionEnd();
2522 QTextBlock block = d->doc->findBlock(startPos);
2523 QTextBlock::Iterator it = block.begin();
2525 while (!it.atEnd() && it.fragment().position() < startPos)
2528 while (block.isValid()) {
2532 for (; !it.atEnd(); ++it) {
2533 const QTextFragment fragment = it.fragment();
2534 const QTextCharFormat fmt = fragment.charFormat();
2536 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2537 anchorStart = fragment.position();
2538 anchorHref = fmt.anchorHref();
2543 if (anchorStart != -1) {
2546 // find next non-anchor fragment
2547 for (; !it.atEnd(); ++it) {
2548 const QTextFragment fragment = it.fragment();
2549 const QTextCharFormat fmt = fragment.charFormat();
2551 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2552 anchorEnd = fragment.position();
2557 if (anchorEnd == -1)
2558 anchorEnd = block.position() + block.length() - 1;
2560 // make found selection
2564 block = block.next();
2568 int startPos = startCursor.selectionStart();
2572 QTextBlock block = d->doc->findBlock(startPos);
2573 QTextBlock::Iterator blockStart = block.begin();
2574 QTextBlock::Iterator it = block.end();
2576 if (startPos == block.position()) {
2580 if (it == blockStart) {
2581 it = QTextBlock::Iterator();
2582 block = QTextBlock();
2586 } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
2589 while (block.isValid()) {
2594 const QTextFragment fragment = it.fragment();
2595 const QTextCharFormat fmt = fragment.charFormat();
2597 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2598 anchorStart = fragment.position() + fragment.length();
2599 anchorHref = fmt.anchorHref();
2603 if (it == blockStart)
2604 it = QTextBlock::Iterator();
2607 } while (!it.atEnd());
2610 if (anchorStart != -1 && !it.atEnd()) {
2614 const QTextFragment fragment = it.fragment();
2615 const QTextCharFormat fmt = fragment.charFormat();
2617 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2618 anchorEnd = fragment.position() + fragment.length();
2622 if (it == blockStart)
2623 it = QTextBlock::Iterator();
2626 } while (!it.atEnd());
2628 if (anchorEnd == -1)
2629 anchorEnd = qMax(0, block.position());
2634 block = block.previous();
2636 if (it != block.begin())
2638 blockStart = block.begin();
2643 if (anchorStart != -1 && anchorEnd != -1) {
2644 newAnchor = d->cursor;
2645 newAnchor.setPosition(anchorStart);
2646 newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
2653 void QTextControlPrivate::activateLinkUnderCursor(QString href)
2655 QTextCursor oldCursor = cursor;
2657 if (href.isEmpty()) {
2658 QTextCursor tmp = cursor;
2659 if (tmp.selectionStart() != tmp.position())
2660 tmp.setPosition(tmp.selectionStart());
2661 tmp.movePosition(QTextCursor::NextCharacter);
2662 href = tmp.charFormat().anchorHref();
2667 if (!cursor.hasSelection()) {
2668 QTextBlock block = cursor.block();
2669 const int cursorPos = cursor.position();
2671 QTextBlock::Iterator it = block.begin();
2672 QTextBlock::Iterator linkFragment;
2674 for (; !it.atEnd(); ++it) {
2675 QTextFragment fragment = it.fragment();
2676 const int fragmentPos = fragment.position();
2677 if (fragmentPos <= cursorPos &&
2678 fragmentPos + fragment.length() > cursorPos) {
2684 if (!linkFragment.atEnd()) {
2686 cursor.setPosition(it.fragment().position());
2687 if (it != block.begin()) {
2690 QTextFragment fragment = it.fragment();
2691 if (fragment.charFormat().anchorHref() != href)
2693 cursor.setPosition(fragment.position());
2694 } while (it != block.begin());
2697 for (it = linkFragment; !it.atEnd(); ++it) {
2698 QTextFragment fragment = it.fragment();
2699 if (fragment.charFormat().anchorHref() != href)
2701 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
2707 cursorIsFocusIndicator = true;
2709 cursorIsFocusIndicator = false;
2710 cursor.clearSelection();
2712 repaintOldAndNewSelection(oldCursor);
2714 #ifndef QT_NO_DESKTOPSERVICES
2715 if (openExternalLinks)
2716 QDesktopServices::openUrl(href);
2719 emit q_func()->linkActivated(href);
2722 #ifndef QT_NO_TOOLTIP
2723 void QTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
2725 const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
2726 if (toolTip.isEmpty())
2728 QToolTip::showText(globalPos, toolTip, contextWidget);
2730 #endif // QT_NO_TOOLTIP
2732 bool QTextControl::setFocusToNextOrPreviousAnchor(bool next)
2736 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2739 QRectF crect = selectionRect();
2740 emit updateRequest(crect);
2742 // If we don't have a current anchor, we start from the start/end
2743 if (!d->cursor.hasSelection()) {
2744 d->cursor = QTextCursor(d->doc);
2746 d->cursor.movePosition(QTextCursor::Start);
2748 d->cursor.movePosition(QTextCursor::End);
2751 QTextCursor newAnchor;
2752 if (findNextPrevAnchor(d->cursor, next, newAnchor)) {
2753 d->cursor = newAnchor;
2754 d->cursorIsFocusIndicator = true;
2756 d->cursor.clearSelection();
2759 if (d->cursor.hasSelection()) {
2760 crect = selectionRect();
2761 emit updateRequest(crect);
2762 emit visibilityRequest(crect);
2769 bool QTextControl::setFocusToAnchor(const QTextCursor &newCursor)
2773 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2776 // Verify that this is an anchor.
2777 const QString anchorHref = d->anchorForCursor(newCursor);
2778 if (anchorHref.isEmpty())
2782 QRectF crect = selectionRect();
2783 emit updateRequest(crect);
2785 d->cursor.setPosition(newCursor.selectionStart());
2786 d->cursor.setPosition(newCursor.selectionEnd(), QTextCursor::KeepAnchor);
2787 d->cursorIsFocusIndicator = true;
2789 crect = selectionRect();
2790 emit updateRequest(crect);
2791 emit visibilityRequest(crect);
2795 void QTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2798 if (flags == d->interactionFlags)
2800 d->interactionFlags = flags;
2803 d->setBlinkingCursorEnabled(flags & Qt::TextEditable);
2806 Qt::TextInteractionFlags QTextControl::textInteractionFlags() const
2808 Q_D(const QTextControl);
2809 return d->interactionFlags;
2812 void QTextControl::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2815 d->cursor.mergeCharFormat(modifier);
2816 d->updateCurrentCharFormat();
2819 void QTextControl::setCurrentCharFormat(const QTextCharFormat &format)
2822 d->cursor.setCharFormat(format);
2823 d->updateCurrentCharFormat();
2826 QTextCharFormat QTextControl::currentCharFormat() const
2828 Q_D(const QTextControl);
2829 return d->cursor.charFormat();
2832 void QTextControl::insertPlainText(const QString &text)
2835 d->cursor.insertText(text);
2838 #ifndef QT_NO_TEXTHTMLPARSER
2839 void QTextControl::insertHtml(const QString &text)
2842 d->cursor.insertHtml(text);
2844 #endif // QT_NO_TEXTHTMLPARSER
2846 QPointF QTextControl::anchorPosition(const QString &name) const
2848 Q_D(const QTextControl);
2853 for (QTextBlock block = d->doc->begin(); block.isValid(); block = block.next()) {
2854 QTextCharFormat format = block.charFormat();
2855 if (format.isAnchor() && format.anchorNames().contains(name)) {
2856 r = d->rectForPosition(block.position());
2860 for (QTextBlock::Iterator it = block.begin(); !it.atEnd(); ++it) {
2861 QTextFragment fragment = it.fragment();
2862 format = fragment.charFormat();
2863 if (format.isAnchor() && format.anchorNames().contains(name)) {
2864 r = d->rectForPosition(fragment.position());
2865 block = QTextBlock();
2872 return QPointF(0, r.top());
2875 void QTextControl::adjustSize()
2878 d->doc->adjustSize();
2881 bool QTextControl::find(const QString &exp, QTextDocument::FindFlags options)
2884 QTextCursor search = d->doc->find(exp, d->cursor, options);
2885 if (search.isNull())
2888 setTextCursor(search);
2894 void QTextControlPrivate::append(const QString &text, Qt::TextFormat format)
2896 QTextCursor tmp(doc);
2897 tmp.beginEditBlock();
2898 tmp.movePosition(QTextCursor::End);
2900 if (!doc->isEmpty())
2901 tmp.insertBlock(cursor.blockFormat(), cursor.charFormat());
2903 tmp.setCharFormat(cursor.charFormat());
2905 // preserve the char format
2906 QTextCharFormat oldCharFormat = cursor.charFormat();
2908 #ifndef QT_NO_TEXTHTMLPARSER
2909 if (format == Qt::RichText || (format == Qt::AutoText && Qt::mightBeRichText(text))) {
2910 tmp.insertHtml(text);
2912 tmp.insertText(text);
2915 tmp.insertText(text);
2916 #endif // QT_NO_TEXTHTMLPARSER
2917 if (!cursor.hasSelection())
2918 cursor.setCharFormat(oldCharFormat);
2923 void QTextControl::append(const QString &text)
2926 d->append(text, Qt::AutoText);
2929 void QTextControl::appendHtml(const QString &html)
2932 d->append(html, Qt::RichText);
2935 void QTextControl::appendPlainText(const QString &text)
2938 d->append(text, Qt::PlainText);
2942 void QTextControl::ensureCursorVisible()
2945 QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
2946 emit visibilityRequest(crect);
2947 emit microFocusChanged();
2950 QPalette QTextControl::palette() const
2952 Q_D(const QTextControl);
2956 void QTextControl::setPalette(const QPalette &pal)
2962 QAbstractTextDocumentLayout::PaintContext QTextControl::getPaintContext(QWidget *widget) const
2964 Q_D(const QTextControl);
2966 QAbstractTextDocumentLayout::PaintContext ctx;
2968 ctx.selections = d->extraSelections;
2969 ctx.palette = d->palette;
2970 if (d->cursorOn && d->isEnabled) {
2972 ctx.cursorPosition = -1;
2973 else if (d->preeditCursor != 0)
2974 ctx.cursorPosition = - (d->preeditCursor + 2);
2976 ctx.cursorPosition = d->cursor.position();
2979 if (!d->dndFeedbackCursor.isNull())
2980 ctx.cursorPosition = d->dndFeedbackCursor.position();
2981 #ifdef QT_KEYPAD_NAVIGATION
2982 if (!QApplication::keypadNavigationEnabled() || d->hasEditFocus)
2984 if (d->cursor.hasSelection()) {
2985 QAbstractTextDocumentLayout::Selection selection;
2986 selection.cursor = d->cursor;
2987 if (d->cursorIsFocusIndicator) {
2989 opt.palette = ctx.palette;
2990 QStyleHintReturnVariant ret;
2991 QStyle *style = QApplication::style();
2993 style = widget->style();
2994 style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
2995 selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
2997 QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive;
2998 selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight));
2999 selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText));
3001 QStyle *style = QApplication::style();
3003 opt.initFrom(widget);
3004 style = widget->style();
3006 if (style->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, widget))
3007 selection.format.setProperty(QTextFormat::FullWidthSelection, true);
3009 ctx.selections.append(selection);
3015 void QTextControl::drawContents(QPainter *p, const QRectF &rect, QWidget *widget)
3019 QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext(widget);
3021 p->setClipRect(rect, Qt::IntersectClip);
3024 d->doc->documentLayout()->draw(p, ctx);
3028 void QTextControlPrivate::_q_copyLink()
3030 #ifndef QT_NO_CLIPBOARD
3031 QMimeData *md = new QMimeData;
3032 md->setText(linkToCopy);
3033 QApplication::clipboard()->setMimeData(md);
3037 QInputContext *QTextControlPrivate::inputContext()
3039 QInputContext *ctx = contextWidget->inputContext();
3040 if (!ctx && contextWidget->parentWidget())
3041 ctx = contextWidget->parentWidget()->inputContext();
3045 int QTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
3047 Q_D(const QTextControl);
3048 return d->doc->documentLayout()->hitTest(point, accuracy);
3051 QRectF QTextControl::blockBoundingRect(const QTextBlock &block) const
3053 Q_D(const QTextControl);
3054 return d->doc->documentLayout()->blockBoundingRect(block);
3057 #ifndef QT_NO_CONTEXTMENU
3058 #define NUM_CONTROL_CHARACTERS 10
3059 const struct QUnicodeControlCharacter {
3062 } qt_controlCharacters[NUM_CONTROL_CHARACTERS] = {
3063 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRM Left-to-right mark"), 0x200e },
3064 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLM Right-to-left mark"), 0x200f },
3065 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWJ Zero width joiner"), 0x200d },
3066 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWNJ Zero width non-joiner"), 0x200c },
3067 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "ZWSP Zero width space"), 0x200b },
3068 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRE Start of left-to-right embedding"), 0x202a },
3069 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLE Start of right-to-left embedding"), 0x202b },
3070 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "LRO Start of left-to-right override"), 0x202d },
3071 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "RLO Start of right-to-left override"), 0x202e },
3072 { QT_TRANSLATE_NOOP("QUnicodeControlCharacterMenu", "PDF Pop directional formatting"), 0x202c },
3075 QUnicodeControlCharacterMenu::QUnicodeControlCharacterMenu(QObject *_editWidget, QWidget *parent)
3076 : QMenu(parent), editWidget(_editWidget)
3078 setTitle(tr("Insert Unicode control character"));
3079 for (int i = 0; i < NUM_CONTROL_CHARACTERS; ++i) {
3080 addAction(tr(qt_controlCharacters[i].text), this, SLOT(menuActionTriggered()));
3084 void QUnicodeControlCharacterMenu::menuActionTriggered()
3086 QAction *a = qobject_cast<QAction *>(sender());
3087 int idx = actions().indexOf(a);
3088 if (idx < 0 || idx >= NUM_CONTROL_CHARACTERS)
3090 QChar c(qt_controlCharacters[idx].character);
3093 #ifndef QT_NO_TEXTEDIT
3094 if (QTextEdit *edit = qobject_cast<QTextEdit *>(editWidget)) {
3095 edit->insertPlainText(str);
3099 if (QTextControl *control = qobject_cast<QTextControl *>(editWidget)) {
3100 control->insertPlainText(str);
3102 #ifndef QT_NO_LINEEDIT
3103 if (QLineEdit *edit = qobject_cast<QLineEdit *>(editWidget)) {
3109 #endif // QT_NO_CONTEXTMENU
3111 QStringList QTextEditMimeData::formats() const
3113 if (!fragment.isEmpty())
3114 return QStringList() << QString::fromLatin1("text/plain") << QString::fromLatin1("text/html")
3115 #ifndef QT_NO_TEXTODFWRITER
3116 << QString::fromLatin1("application/vnd.oasis.opendocument.text")
3120 return QMimeData::formats();
3123 QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
3125 if (!fragment.isEmpty())
3127 return QMimeData::retrieveData(mimeType, type);
3130 void QTextEditMimeData::setup() const
3132 QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
3133 #ifndef QT_NO_TEXTHTMLPARSER
3134 that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
3136 #ifndef QT_NO_TEXTODFWRITER
3139 QTextDocumentWriter writer(&buffer, "ODF");
3140 writer.write(fragment);
3142 that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
3145 that->setText(fragment.toPlainText());
3146 fragment = QTextDocumentFragment();
3151 #include "moc_qtextcontrol_p.cpp"
3153 #endif // QT_NO_TEXTCONTROL