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 "qwidgettextcontrol_p.h"
43 #include "qwidgettextcontrol_p_p.h"
45 #ifndef QT_NO_TEXTCONTROL
52 #include <qclipboard.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"
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 <QtWidgets/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 QWidgetTextControlPrivate::QWidgetTextControlPrivate()
116 : doc(0), cursorOn(false), cursorIsFocusIndicator(false),
117 interactionFlags(Qt::TextEditorInteraction),
119 #ifndef QT_NO_DRAGANDDROP
120 mousePressed(false), mightStartDrag(false),
122 lastSelectionPosition(0), lastSelectionAnchor(0),
123 ignoreAutomaticScrollbarAdjustement(false),
124 overwriteMode(false),
125 acceptRichText(true),
126 preeditCursor(0), hideCursor(false),
128 #ifdef QT_KEYPAD_NAVIGATION
132 hadSelectionOnMousePress(false),
133 ignoreUnusedNavigationEvents(false),
134 openExternalLinks(false),
135 wordSelectionEnabled(false)
138 bool QWidgetTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
140 #ifdef QT_NO_SHORTCUT
144 Q_Q(QWidgetTextControl);
148 const QTextCursor oldSelection = cursor;
149 const int oldCursorPos = cursor.position();
151 QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
152 QTextCursor::MoveOperation op = QTextCursor::NoMove;
156 #ifndef QT_NO_SHORTCUT
157 if (e == QKeySequence::MoveToNextChar) {
158 op = QTextCursor::Right;
160 else if (e == QKeySequence::MoveToPreviousChar) {
161 op = QTextCursor::Left;
163 else if (e == QKeySequence::SelectNextChar) {
164 op = QTextCursor::Right;
165 mode = QTextCursor::KeepAnchor;
167 else if (e == QKeySequence::SelectPreviousChar) {
168 op = QTextCursor::Left;
169 mode = QTextCursor::KeepAnchor;
171 else if (e == QKeySequence::SelectNextWord) {
172 op = QTextCursor::WordRight;
173 mode = QTextCursor::KeepAnchor;
175 else if (e == QKeySequence::SelectPreviousWord) {
176 op = QTextCursor::WordLeft;
177 mode = QTextCursor::KeepAnchor;
179 else if (e == QKeySequence::SelectStartOfLine) {
180 op = QTextCursor::StartOfLine;
181 mode = QTextCursor::KeepAnchor;
183 else if (e == QKeySequence::SelectEndOfLine) {
184 op = QTextCursor::EndOfLine;
185 mode = QTextCursor::KeepAnchor;
187 else if (e == QKeySequence::SelectStartOfBlock) {
188 op = QTextCursor::StartOfBlock;
189 mode = QTextCursor::KeepAnchor;
191 else if (e == QKeySequence::SelectEndOfBlock) {
192 op = QTextCursor::EndOfBlock;
193 mode = QTextCursor::KeepAnchor;
195 else if (e == QKeySequence::SelectStartOfDocument) {
196 op = QTextCursor::Start;
197 mode = QTextCursor::KeepAnchor;
199 else if (e == QKeySequence::SelectEndOfDocument) {
200 op = QTextCursor::End;
201 mode = QTextCursor::KeepAnchor;
203 else if (e == QKeySequence::SelectPreviousLine) {
204 op = QTextCursor::Up;
205 mode = QTextCursor::KeepAnchor;
207 else if (e == QKeySequence::SelectNextLine) {
208 op = QTextCursor::Down;
209 mode = QTextCursor::KeepAnchor;
211 QTextBlock block = cursor.block();
212 QTextLine line = currentTextLine(cursor);
213 if (!block.next().isValid()
215 && line.lineNumber() == block.layout()->lineCount() - 1)
216 op = QTextCursor::End;
219 else if (e == QKeySequence::MoveToNextWord) {
220 op = QTextCursor::WordRight;
222 else if (e == QKeySequence::MoveToPreviousWord) {
223 op = QTextCursor::WordLeft;
225 else if (e == QKeySequence::MoveToEndOfBlock) {
226 op = QTextCursor::EndOfBlock;
228 else if (e == QKeySequence::MoveToStartOfBlock) {
229 op = QTextCursor::StartOfBlock;
231 else if (e == QKeySequence::MoveToNextLine) {
232 op = QTextCursor::Down;
234 else if (e == QKeySequence::MoveToPreviousLine) {
235 op = QTextCursor::Up;
237 else if (e == QKeySequence::MoveToPreviousLine) {
238 op = QTextCursor::Up;
240 else if (e == QKeySequence::MoveToStartOfLine) {
241 op = QTextCursor::StartOfLine;
243 else if (e == QKeySequence::MoveToEndOfLine) {
244 op = QTextCursor::EndOfLine;
246 else if (e == QKeySequence::MoveToStartOfDocument) {
247 op = QTextCursor::Start;
249 else if (e == QKeySequence::MoveToEndOfDocument) {
250 op = QTextCursor::End;
252 #endif // QT_NO_SHORTCUT
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)
267 bool visualNavigation = cursor.visualNavigation();
268 cursor.setVisualNavigation(true);
269 const bool moved = cursor.movePosition(op, mode);
270 cursor.setVisualNavigation(visualNavigation);
271 q->ensureCursorVisible();
273 bool ignoreNavigationEvents = ignoreUnusedNavigationEvents;
274 bool isNavigationEvent = e->key() == Qt::Key_Up || e->key() == Qt::Key_Down;
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));
282 isNavigationEvent = isNavigationEvent || e->key() == Qt::Key_Left || e->key() == Qt::Key_Right;
286 if (cursor.position() != oldCursorPos)
287 emit q->cursorPositionChanged();
288 emit q->microFocusChanged();
289 } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
293 selectionChanged(/*forceEmitSelectionChanged =*/(mode == QTextCursor::KeepAnchor));
295 repaintOldAndNewSelection(oldSelection);
300 void QWidgetTextControlPrivate::updateCurrentCharFormat()
302 Q_Q(QWidgetTextControl);
304 QTextCharFormat fmt = cursor.charFormat();
305 if (fmt == lastCharFormat)
307 lastCharFormat = fmt;
309 emit q->currentCharFormatChanged(fmt);
310 emit q->microFocusChanged();
313 void QWidgetTextControlPrivate::indent()
315 QTextBlockFormat blockFmt = cursor.blockFormat();
317 QTextList *list = cursor.currentList();
319 QTextBlockFormat modifier;
320 modifier.setIndent(blockFmt.indent() + 1);
321 cursor.mergeBlockFormat(modifier);
323 QTextListFormat format = list->format();
324 format.setIndent(format.indent() + 1);
326 if (list->itemNumber(cursor.block()) == 1)
327 list->setFormat(format);
329 cursor.createList(format);
333 void QWidgetTextControlPrivate::outdent()
335 QTextBlockFormat blockFmt = cursor.blockFormat();
337 QTextList *list = cursor.currentList();
340 QTextBlockFormat modifier;
341 modifier.setIndent(blockFmt.indent() - 1);
342 cursor.mergeBlockFormat(modifier);
344 QTextListFormat listFmt = list->format();
345 listFmt.setIndent(listFmt.indent() - 1);
346 list->setFormat(listFmt);
350 void QWidgetTextControlPrivate::gotoNextTableCell()
352 QTextTable *table = cursor.currentTable();
353 QTextTableCell cell = table->cellAt(cursor);
355 int newColumn = cell.column() + cell.columnSpan();
356 int newRow = cell.row();
358 if (newColumn >= table->columns()) {
361 if (newRow >= table->rows())
362 table->insertRows(table->rows(), 1);
365 cell = table->cellAt(newRow, newColumn);
366 cursor = cell.firstCursorPosition();
369 void QWidgetTextControlPrivate::gotoPreviousTableCell()
371 QTextTable *table = cursor.currentTable();
372 QTextTableCell cell = table->cellAt(cursor);
374 int newColumn = cell.column() - 1;
375 int newRow = cell.row();
378 newColumn = table->columns() - 1;
384 cell = table->cellAt(newRow, newColumn);
385 cursor = cell.firstCursorPosition();
388 void QWidgetTextControlPrivate::createAutoBulletList()
390 cursor.beginEditBlock();
392 QTextBlockFormat blockFmt = cursor.blockFormat();
394 QTextListFormat listFmt;
395 listFmt.setStyle(QTextListFormat::ListDisc);
396 listFmt.setIndent(blockFmt.indent() + 1);
398 blockFmt.setIndent(0);
399 cursor.setBlockFormat(blockFmt);
401 cursor.createList(listFmt);
403 cursor.endEditBlock();
406 void QWidgetTextControlPrivate::init(Qt::TextFormat format, const QString &text, QTextDocument *document)
408 Q_Q(QWidgetTextControl);
409 setContent(format, text, document);
411 doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
412 q->setCursorWidth(-1);
415 void QWidgetTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
417 Q_Q(QWidgetTextControl);
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();
423 bool clearDocument = true;
427 clearDocument = false;
429 palette = QApplication::palette("QWidgetTextControl");
430 doc = new QTextDocument(q);
432 _q_documentLayoutChanged();
433 cursor = QTextCursor(doc);
435 // #### doc->documentLayout()->setPaintDevice(viewport);
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()));
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)));
448 bool previousUndoRedoState = doc->isUndoRedoEnabled();
450 doc->setUndoRedoEnabled(false);
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);
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
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();
478 #ifndef QT_NO_TEXTHTMLPARSER
481 doc->setPlainText(text);
483 doc->setUndoRedoEnabled(false);
485 cursor = QTextCursor(doc);
486 } else if (clearDocument) {
489 cursor.setCharFormat(charFormatForInsertion);
491 QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
492 emit q->textChanged();
494 doc->setUndoRedoEnabled(previousUndoRedoState);
495 _q_updateCurrentCharFormatAndSelection();
497 doc->setModified(false);
499 q->ensureCursorVisible();
500 emit q->cursorPositionChanged();
503 void QWidgetTextControlPrivate::startDrag()
505 #ifndef QT_NO_DRAGANDDROP
506 Q_Q(QWidgetTextControl);
507 mousePressed = false;
510 QMimeData *data = q->createMimeDataFromSelection();
512 QDrag *drag = new QDrag(contextWidget);
513 drag->setMimeData(data);
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);
521 action = drag->exec(actions, Qt::CopyAction);
524 if (action == Qt::MoveAction && drag->target() != contextWidget)
525 cursor.removeSelectedText();
529 void QWidgetTextControlPrivate::setCursorPosition(const QPointF &pos)
531 Q_Q(QWidgetTextControl);
532 const int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
535 cursor.setPosition(cursorPos);
538 void QWidgetTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
540 cursor.setPosition(pos, mode);
542 if (mode != QTextCursor::KeepAnchor) {
543 selectedWordOnDoubleClick = QTextCursor();
544 selectedBlockOnTrippleClick = QTextCursor();
548 void QWidgetTextControlPrivate::repaintCursor()
550 Q_Q(QWidgetTextControl);
551 emit q->updateRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
554 void QWidgetTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
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()
564 QTextCursor differenceSelection(doc);
565 differenceSelection.setPosition(oldSelection.position());
566 differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
567 emit q->updateRequest(q->selectionRect(differenceSelection));
569 if (!oldSelection.isNull())
570 emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
571 emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
575 void QWidgetTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /*=false*/)
577 Q_Q(QWidgetTextControl);
578 if (forceEmitSelectionChanged)
579 emit q->selectionChanged();
581 if (cursor.position() == lastSelectionPosition
582 && cursor.anchor() == lastSelectionAnchor)
585 bool selectionStateChange = (cursor.hasSelection()
586 != (lastSelectionPosition != lastSelectionAnchor));
587 if (selectionStateChange)
588 emit q->copyAvailable(cursor.hasSelection());
590 if (!forceEmitSelectionChanged
591 && (selectionStateChange
592 || (cursor.hasSelection()
593 && (cursor.position() != lastSelectionPosition
594 || cursor.anchor() != lastSelectionAnchor))))
595 emit q->selectionChanged();
597 emit q->microFocusChanged();
598 lastSelectionPosition = cursor.position();
599 lastSelectionAnchor = cursor.anchor();
602 void QWidgetTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
604 updateCurrentCharFormat();
608 #ifndef QT_NO_CLIPBOARD
609 void QWidgetTextControlPrivate::setClipboardSelection()
611 QClipboard *clipboard = QApplication::clipboard();
612 if (!cursor.hasSelection() || !clipboard->supportsSelection())
614 Q_Q(QWidgetTextControl);
615 QMimeData *data = q->createMimeDataFromSelection();
616 clipboard->setMimeData(data, QClipboard::Selection);
620 void QWidgetTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
622 Q_Q(QWidgetTextControl);
623 if (someCursor.isCopyOf(cursor)) {
624 emit q->cursorPositionChanged();
625 emit q->microFocusChanged();
629 void QWidgetTextControlPrivate::_q_documentLayoutChanged()
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)));
639 void QWidgetTextControlPrivate::setBlinkingCursorEnabled(bool enable)
641 Q_Q(QWidgetTextControl);
643 if (enable && QApplication::cursorFlashTime() > 0)
644 cursorBlinkTimer.start(QApplication::cursorFlashTime() / 2, q);
646 cursorBlinkTimer.stop();
653 void QWidgetTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qreal mouseXPosition)
655 Q_Q(QWidgetTextControl);
657 // if inside the initial selected word keep that
658 if (suggestedNewPosition >= selectedWordOnDoubleClick.selectionStart()
659 && suggestedNewPosition <= selectedWordOnDoubleClick.selectionEnd()) {
660 q->setTextCursor(selectedWordOnDoubleClick);
664 QTextCursor curs = selectedWordOnDoubleClick;
665 curs.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
667 if (!curs.movePosition(QTextCursor::StartOfWord))
669 const int wordStartPos = curs.position();
671 const int blockPos = curs.block().position();
672 const QPointF blockCoordinates = q->blockBoundingRect(curs.block()).topLeft();
674 QTextLine line = currentTextLine(curs);
678 const qreal wordStartX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
680 if (!curs.movePosition(QTextCursor::EndOfWord))
682 const int wordEndPos = curs.position();
684 const QTextLine otherLine = currentTextLine(curs);
685 if (otherLine.textStart() != line.textStart()
686 || wordEndPos == wordStartPos)
689 const qreal wordEndX = line.cursorToX(curs.position() - blockPos) + blockCoordinates.x();
691 if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX))
694 // keep the already selected word even when moving to the left
696 if (suggestedNewPosition < selectedWordOnDoubleClick.position())
697 cursor.setPosition(selectedWordOnDoubleClick.selectionEnd());
699 cursor.setPosition(selectedWordOnDoubleClick.selectionStart());
701 const qreal differenceToStart = mouseXPosition - wordStartX;
702 const qreal differenceToEnd = wordEndX - mouseXPosition;
704 if (differenceToStart < differenceToEnd)
705 setCursorPosition(wordStartPos, QTextCursor::KeepAnchor);
707 setCursorPosition(wordEndPos, QTextCursor::KeepAnchor);
709 if (interactionFlags & Qt::TextSelectableByMouse) {
710 #ifndef QT_NO_CLIPBOARD
711 setClipboardSelection();
713 selectionChanged(true);
717 void QWidgetTextControlPrivate::extendBlockwiseSelection(int suggestedNewPosition)
719 Q_Q(QWidgetTextControl);
721 // if inside the initial selected line keep that
722 if (suggestedNewPosition >= selectedBlockOnTrippleClick.selectionStart()
723 && suggestedNewPosition <= selectedBlockOnTrippleClick.selectionEnd()) {
724 q->setTextCursor(selectedBlockOnTrippleClick);
728 if (suggestedNewPosition < selectedBlockOnTrippleClick.position()) {
729 cursor.setPosition(selectedBlockOnTrippleClick.selectionEnd());
730 cursor.setPosition(suggestedNewPosition, QTextCursor::KeepAnchor);
731 cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
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);
739 if (interactionFlags & Qt::TextSelectableByMouse) {
740 #ifndef QT_NO_CLIPBOARD
741 setClipboardSelection();
743 selectionChanged(true);
747 void QWidgetTextControlPrivate::_q_deleteSelected()
749 if (!(interactionFlags & Qt::TextEditable) || !cursor.hasSelection())
751 cursor.removeSelectedText();
754 void QWidgetTextControl::undo()
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();
766 void QWidgetTextControl::redo()
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();
778 QWidgetTextControl::QWidgetTextControl(QObject *parent)
779 : QObject(*new QWidgetTextControlPrivate, parent)
781 Q_D(QWidgetTextControl);
785 QWidgetTextControl::QWidgetTextControl(const QString &text, QObject *parent)
786 : QObject(*new QWidgetTextControlPrivate, parent)
788 Q_D(QWidgetTextControl);
789 d->init(Qt::RichText, text);
792 QWidgetTextControl::QWidgetTextControl(QTextDocument *doc, QObject *parent)
793 : QObject(*new QWidgetTextControlPrivate, parent)
795 Q_D(QWidgetTextControl);
796 d->init(Qt::RichText, QString(), doc);
799 QWidgetTextControl::~QWidgetTextControl()
803 void QWidgetTextControl::setDocument(QTextDocument *document)
805 Q_D(QWidgetTextControl);
806 if (d->doc == document)
809 d->doc->disconnect(this);
810 d->doc->documentLayout()->disconnect(this);
811 d->doc->documentLayout()->setPaintDevice(0);
813 if (d->doc->parent() == this)
817 d->setContent(Qt::RichText, QString(), document);
820 QTextDocument *QWidgetTextControl::document() const
822 Q_D(const QWidgetTextControl);
826 void QWidgetTextControl::setTextCursor(const QTextCursor &cursor)
828 Q_D(QWidgetTextControl);
829 d->cursorIsFocusIndicator = false;
830 const bool posChanged = cursor.position() != d->cursor.position();
831 const QTextCursor oldSelection = d->cursor;
833 d->cursorOn = d->hasFocus && (d->interactionFlags & Qt::TextEditable);
834 d->_q_updateCurrentCharFormatAndSelection();
835 ensureCursorVisible();
836 d->repaintOldAndNewSelection(oldSelection);
838 emit cursorPositionChanged();
841 QTextCursor QWidgetTextControl::textCursor() const
843 Q_D(const QWidgetTextControl);
847 #ifndef QT_NO_CLIPBOARD
849 void QWidgetTextControl::cut()
851 Q_D(QWidgetTextControl);
852 if (!(d->interactionFlags & Qt::TextEditable) || !d->cursor.hasSelection())
855 d->cursor.removeSelectedText();
858 void QWidgetTextControl::copy()
860 Q_D(QWidgetTextControl);
861 if (!d->cursor.hasSelection())
863 QMimeData *data = createMimeDataFromSelection();
864 QApplication::clipboard()->setMimeData(data);
867 void QWidgetTextControl::paste(QClipboard::Mode mode)
869 const QMimeData *md = QApplication::clipboard()->mimeData(mode);
871 insertFromMimeData(md);
875 void QWidgetTextControl::clear()
877 Q_D(QWidgetTextControl);
878 // clears and sets empty content
879 d->extraSelections.clear();
884 void QWidgetTextControl::selectAll()
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();
894 void QWidgetTextControl::processEvent(QEvent *e, const QPointF &coordinateOffset, QWidget *contextWidget)
897 m.translate(coordinateOffset.x(), coordinateOffset.y());
898 processEvent(e, m, contextWidget);
901 void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *contextWidget)
903 Q_D(QWidgetTextControl);
904 if (d->interactionFlags == Qt::NoTextInteraction) {
909 d->contextWidget = contextWidget;
911 if (!d->contextWidget) {
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();
931 #endif // QT_NO_GRAPHICSVIEW
937 case QEvent::KeyPress:
938 d->keyPressEvent(static_cast<QKeyEvent *>(e));
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());
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());
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());
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());
960 case QEvent::InputMethod:
961 d->inputMethodEvent(static_cast<QInputMethodEvent *>(e));
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);
968 #endif // QT_NO_CONTEXTMENU
969 case QEvent::FocusIn:
970 case QEvent::FocusOut:
971 d->focusEvent(static_cast<QFocusEvent *>(e));
974 case QEvent::EnabledChange:
975 d->isEnabled = e->isAccepted();
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);
984 #endif // QT_NO_TOOLTIP
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();
993 case QEvent::DragLeave:
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();
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();
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(),
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(),
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(),
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(),
1031 case QEvent::GraphicsSceneContextMenu: {
1032 QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e);
1033 d->contextMenuEvent(ev->screenPos(), matrix.map(ev->pos()), contextWidget);
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,
1042 case QEvent::GraphicsSceneDragEnter: {
1043 QGraphicsSceneDragDropEvent *ev = static_cast<QGraphicsSceneDragDropEvent *>(e);
1044 if (d->dragEnterEvent(e, ev->mimeData()))
1045 ev->acceptProposedAction();
1047 case QEvent::GraphicsSceneDragLeave:
1048 d->dragLeaveEvent();
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();
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()))
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);
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) {
1077 switch (ke->key()) {
1078 case Qt::Key_Return:
1080 case Qt::Key_Delete:
1083 case Qt::Key_Backspace:
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
1124 bool QWidgetTextControl::event(QEvent *e)
1126 return QObject::event(e);
1129 void QWidgetTextControl::timerEvent(QTimerEvent *e)
1131 Q_D(QWidgetTextControl);
1132 if (e->timerId() == d->cursorBlinkTimer.timerId()) {
1133 d->cursorOn = !d->cursorOn;
1135 if (d->cursor.hasSelection())
1136 d->cursorOn &= (QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected)
1140 } else if (e->timerId() == d->trippleClickTimer.timerId()) {
1141 d->trippleClickTimer.stop();
1145 void QWidgetTextControl::setPlainText(const QString &text)
1147 Q_D(QWidgetTextControl);
1148 d->setContent(Qt::PlainText, text);
1151 void QWidgetTextControl::setHtml(const QString &text)
1153 Q_D(QWidgetTextControl);
1154 d->setContent(Qt::RichText, text);
1157 void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
1159 Q_Q(QWidgetTextControl);
1160 #ifndef QT_NO_SHORTCUT
1161 if (e == QKeySequence::SelectAll) {
1166 #ifndef QT_NO_CLIPBOARD
1167 else if (e == QKeySequence::Copy) {
1173 #endif // QT_NO_SHORTCUT
1175 if (interactionFlags & Qt::TextSelectableByKeyboard
1176 && cursorMoveKeyEvent(e))
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
1186 && cursor.hasSelection()) {
1189 activateLinkUnderCursor();
1194 if (!(interactionFlags & Qt::TextEditable)) {
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);
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
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);
1221 QTextCursor localCursor = cursor;
1222 localCursor.deletePreviousChar();
1226 #ifndef QT_NO_SHORTCUT
1227 else if (e == QKeySequence::InsertParagraphSeparator) {
1228 cursor.insertBlock();
1231 } else if (e == QKeySequence::InsertLineSeparator) {
1232 cursor.insertText(QString(QChar::LineSeparator));
1239 #ifndef QT_NO_SHORTCUT
1240 else if (e == QKeySequence::Undo) {
1243 else if (e == QKeySequence::Redo) {
1246 #ifndef QT_NO_CLIPBOARD
1247 else if (e == QKeySequence::Cut) {
1250 else if (e == QKeySequence::Paste) {
1251 QClipboard::Mode mode = QClipboard::Clipboard;
1253 if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
1254 mode = QClipboard::Selection;
1259 else if (e == QKeySequence::Delete) {
1260 QTextCursor localCursor = cursor;
1261 localCursor.deleteChar();
1263 else if (e == QKeySequence::DeleteEndOfWord) {
1264 if (!cursor.hasSelection())
1265 cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
1266 cursor.removeSelectedText();
1268 else if (e == QKeySequence::DeleteStartOfWord) {
1269 if (!cursor.hasSelection())
1270 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor);
1271 cursor.removeSelectedText();
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);
1278 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1279 cursor.removeSelectedText();
1281 #endif // QT_NO_SHORTCUT
1289 QString text = e->text();
1290 if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
1292 // no need to call deleteChar() if we have a selection, insertText
1294 && !cursor.hasSelection()
1295 && !cursor.atBlockEnd())
1296 cursor.deleteChar();
1298 cursor.insertText(text);
1311 q->ensureCursorVisible();
1313 updateCurrentCharFormat();
1316 QVariant QWidgetTextControl::loadResource(int type, const QUrl &name)
1318 #ifdef QT_NO_TEXTEDIT
1322 if (QTextEdit *textEdit = qobject_cast<QTextEdit *>(parent())) {
1323 QUrl resolvedName = textEdit->d_func()->resolveUrl(name);
1324 return textEdit->loadResource(type, resolvedName);
1330 void QWidgetTextControlPrivate::_q_updateBlock(const QTextBlock &block)
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);
1338 QRectF QWidgetTextControlPrivate::rectForPosition(int position) const
1340 Q_Q(const QWidgetTextControl);
1341 const QTextBlock block = doc->findBlock(position);
1342 if (!block.isValid())
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();
1355 QTextLine line = layout->lineForTextPosition(relativePos);
1360 #ifndef QT_NO_PROPERTIES
1361 cursorWidth = docLayout->property("cursorWidth").toInt(&ok);
1369 if (line.isValid()) {
1370 qreal x = line.cursorToX(relativePos);
1372 if (overwriteMode) {
1373 if (relativePos < line.textLength() - line.textStart())
1374 w = line.cursorToX(relativePos + 1) - x;
1376 w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
1378 r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(),
1379 cursorWidth + w, line.height());
1381 r = QRectF(layoutPos.x(), layoutPos.y(), cursorWidth, 10); // #### correct height
1387 static inline bool firstFramePosLessThanCursorPos(QTextFrame *frame, int position)
1389 return frame->firstPosition() < position;
1392 static inline bool cursorPosLessThanLastFramePos(int position, QTextFrame *frame)
1394 return position < frame->lastPosition();
1397 static QRectF boundingRectOfFloatsInSelection(const QTextCursor &cursor)
1400 QTextFrame *frame = cursor.currentFrame();
1401 const QList<QTextFrame *> children = frame->childFrames();
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);
1414 QRectF QWidgetTextControl::selectionRect(const QTextCursor &cursor) const
1416 Q_D(const QWidgetTextControl);
1418 QRectF r = d->rectForPosition(cursor.selectionStart());
1420 if (cursor.hasComplexSelection() && cursor.currentTable()) {
1421 QTextTable *table = cursor.currentTable();
1423 r = d->doc->documentLayout()->frameBoundingRect(table);
1425 int firstRow, numRows, firstColumn, numColumns;
1426 cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns);
1428 const QTextTableCell firstCell = table->cellAt(firstRow, firstColumn);
1429 const QTextTableCell lastCell = table->cellAt(firstRow + numRows - 1, firstColumn + numColumns - 1);
1431 const QAbstractTextDocumentLayout * const layout = doc->documentLayout();
1433 QRectF tableSelRect = layout->blockBoundingRect(firstCell.firstCursorPosition().block());
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();
1439 tableSelRect.setTop(qMin(tableSelRect.top(), y));
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();
1446 tableSelRect.setLeft(qMin(tableSelRect.left(), x));
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();
1453 tableSelRect.setBottom(qMax(tableSelRect.bottom(), y));
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();
1460 tableSelRect.setRight(qMax(tableSelRect.right(), x));
1463 r = tableSelRect.toRect();
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());
1474 const int firstLine = qMin(posLine.lineNumber(), anchorLine.lineNumber());
1475 const int lastLine = qMax(posLine.lineNumber(), anchorLine.lineNumber());
1476 const QTextLayout *layout = posBlock.layout();
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
1482 r.translate(blockBoundingRect(posBlock).topLeft());
1484 QRectF anchorRect = d->rectForPosition(cursor.selectionEnd());
1486 r |= boundingRectOfFloatsInSelection(cursor);
1487 QRectF frameRect(d->doc->documentLayout()->frameBoundingRect(cursor.currentFrame()));
1488 r.setLeft(frameRect.left());
1489 r.setRight(frameRect.right());
1492 r.adjust(-1, -1, 1, 1);
1498 QRectF QWidgetTextControl::selectionRect() const
1500 Q_D(const QWidgetTextControl);
1501 return selectionRect(d->cursor);
1504 void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1505 Qt::MouseButtons buttons, const QPoint &globalPos)
1507 Q_Q(QWidgetTextControl);
1509 if (sendMouseEventToInputContext(
1510 e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) {
1514 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1515 anchorOnMousePress = q->anchorAt(pos);
1517 if (cursorIsFocusIndicator) {
1518 cursorIsFocusIndicator = false;
1520 cursor.clearSelection();
1523 if (!(button & Qt::LeftButton) ||
1524 !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) {
1529 cursorIsFocusIndicator = false;
1530 const QTextCursor oldSelection = cursor;
1531 const int oldCursorPos = cursor.position();
1533 mousePressed = (interactionFlags & Qt::TextSelectableByMouse);
1534 #ifndef QT_NO_DRAGANDDROP
1535 mightStartDrag = false;
1538 if (trippleClickTimer.isActive()
1539 && ((pos - trippleClickPoint).toPoint().manhattanLength() < QApplication::startDragDistance())) {
1541 cursor.movePosition(QTextCursor::StartOfBlock);
1542 cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
1543 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
1544 selectedBlockOnTrippleClick = cursor;
1546 anchorOnMousePress = QString();
1548 trippleClickTimer.stop();
1550 int cursorPos = q->hitTest(pos, Qt::FuzzyHit);
1551 if (cursorPos == -1) {
1556 if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) {
1557 if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1558 selectedWordOnDoubleClick = cursor;
1559 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
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);
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();
1583 setCursorPosition(cursorPos);
1587 if (interactionFlags & Qt::TextEditable) {
1588 q->ensureCursorVisible();
1589 if (cursor.position() != oldCursorPos)
1590 emit q->cursorPositionChanged();
1591 _q_updateCurrentCharFormatAndSelection();
1593 if (cursor.position() != oldCursorPos) {
1594 emit q->cursorPositionChanged();
1595 emit q->microFocusChanged();
1599 repaintOldAndNewSelection(oldSelection);
1600 hadSelectionOnMousePress = cursor.hasSelection();
1603 void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &mousePos, Qt::KeyboardModifiers modifiers,
1604 Qt::MouseButtons buttons, const QPoint &globalPos)
1606 Q_Q(QWidgetTextControl);
1608 if (sendMouseEventToInputContext(
1609 e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos)) {
1613 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1614 QString anchor = q->anchorAt(mousePos);
1615 if (anchor != highlightedAnchor) {
1616 highlightedAnchor = anchor;
1617 emit q->linkHovered(anchor);
1621 if (!(buttons & Qt::LeftButton))
1624 const bool editable = interactionFlags & Qt::TextEditable;
1629 || selectedWordOnDoubleClick.hasSelection()
1630 || selectedBlockOnTrippleClick.hasSelection()))
1633 const QTextCursor oldSelection = cursor;
1634 const int oldCursorPos = cursor.position();
1636 if (mightStartDrag) {
1637 if ((mousePos.toPoint() - dragStartPos).manhattanLength() > QApplication::startDragDistance())
1645 const qreal mouseX = qreal(mousePos.x());
1647 int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
1648 if (newCursorPos == -1)
1651 if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) {
1652 selectedWordOnDoubleClick = cursor;
1653 selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor);
1656 if (selectedBlockOnTrippleClick.hasSelection())
1657 extendBlockwiseSelection(newCursorPos);
1658 else if (selectedWordOnDoubleClick.hasSelection())
1659 extendWordwiseSelection(newCursorPos, mouseX);
1661 setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
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();
1671 if (contextWidget) {
1672 if (QInputContext *ic = qApp->inputContext()) {
1678 //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1)));
1679 if (cursor.position() != oldCursorPos)
1680 emit q->cursorPositionChanged();
1682 selectionChanged(true);
1683 repaintOldAndNewSelection(oldSelection);
1686 void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1687 Qt::MouseButtons buttons, const QPoint &globalPos)
1689 Q_Q(QWidgetTextControl);
1691 if (sendMouseEventToInputContext(
1692 e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) {
1696 const QTextCursor oldSelection = cursor;
1697 const int oldCursorPos = cursor.position();
1699 #ifndef QT_NO_DRAGANDDROP
1700 if (mightStartDrag && (button & Qt::LeftButton)) {
1701 mousePressed = false;
1702 setCursorPosition(pos);
1703 cursor.clearSelection();
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);
1718 q->insertFromMimeData(md);
1722 repaintOldAndNewSelection(oldSelection);
1724 if (cursor.position() != oldCursorPos)
1725 emit q->cursorPositionChanged();
1727 if (interactionFlags & Qt::LinksAccessibleByMouse) {
1728 if (!(button & Qt::LeftButton))
1731 const QString anchor = q->anchorAt(pos);
1733 if (anchor.isEmpty())
1736 if (!cursor.hasSelection()
1737 || (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
1739 const int anchorPos = q->hitTest(pos, Qt::ExactHit);
1740 if (anchorPos != -1) {
1741 cursor.setPosition(anchorPos);
1743 QString anchor = anchorOnMousePress;
1744 anchorOnMousePress = QString();
1745 activateLinkUnderCursor(anchor);
1751 void QWidgetTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers,
1752 Qt::MouseButtons buttons, const QPoint &globalPos)
1754 Q_Q(QWidgetTextControl);
1756 if (sendMouseEventToInputContext(
1757 e, QEvent::MouseButtonDblClick, button, pos, modifiers, buttons, globalPos)) {
1761 if (button != Qt::LeftButton
1762 || !(interactionFlags & Qt::TextSelectableByMouse)) {
1767 #ifndef QT_NO_DRAGANDDROP
1768 mightStartDrag = false;
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);
1778 repaintOldAndNewSelection(oldSelection);
1780 cursorIsFocusIndicator = false;
1781 selectedWordOnDoubleClick = cursor;
1783 trippleClickPoint = pos;
1784 trippleClickTimer.start(QApplication::doubleClickInterval(), q);
1787 #ifndef QT_NO_CLIPBOARD
1788 setClipboardSelection();
1790 emit q->cursorPositionChanged();
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)
1798 #if !defined(QT_NO_IM)
1799 Q_Q(QWidgetTextControl);
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();
1806 if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length()) {
1808 // don't send move events outside the preedit area
1809 if (eventType == QEvent::MouseMove)
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());
1819 if (!layout->preeditAreaText().isEmpty())
1824 Q_UNUSED(eventType);
1827 Q_UNUSED(modifiers);
1829 Q_UNUSED(globalPos);
1834 void QWidgetTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget)
1836 #ifdef QT_NO_CONTEXTMENU
1837 Q_UNUSED(screenPos);
1839 Q_UNUSED(contextWidget);
1841 Q_Q(QWidgetTextControl);
1844 QMenu *menu = q->createStandardContextMenu(docPos, contextWidget);
1847 menu->setAttribute(Qt::WA_DeleteOnClose);
1848 menu->popup(screenPos);
1852 bool QWidgetTextControlPrivate::dragEnterEvent(QEvent *e, const QMimeData *mimeData)
1854 Q_Q(QWidgetTextControl);
1855 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
1860 dndFeedbackCursor = QTextCursor();
1862 return true; // accept proposed action
1865 void QWidgetTextControlPrivate::dragLeaveEvent()
1867 Q_Q(QWidgetTextControl);
1869 const QRectF crect = q->cursorRect(dndFeedbackCursor);
1870 dndFeedbackCursor = QTextCursor();
1872 if (crect.isValid())
1873 emit q->updateRequest(crect);
1876 bool QWidgetTextControlPrivate::dragMoveEvent(QEvent *e, const QMimeData *mimeData, const QPointF &pos)
1878 Q_Q(QWidgetTextControl);
1879 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData)) {
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);
1890 dndFeedbackCursor = cursor;
1891 dndFeedbackCursor.setPosition(cursorPos);
1893 crect = q->cursorRect(dndFeedbackCursor);
1894 emit q->updateRequest(crect);
1897 return true; // accept proposed action
1900 bool QWidgetTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &pos, Qt::DropAction dropAction, QObject *source)
1902 Q_Q(QWidgetTextControl);
1903 dndFeedbackCursor = QTextCursor();
1905 if (!(interactionFlags & Qt::TextEditable) || !q->canInsertFromMimeData(mimeData))
1910 QTextCursor insertionCursor = q->cursorForPosition(pos);
1911 insertionCursor.beginEditBlock();
1913 if (dropAction == Qt::MoveAction && source == contextWidget)
1914 cursor.removeSelectedText();
1916 cursor = insertionCursor;
1917 q->insertFromMimeData(mimeData);
1918 insertionCursor.endEditBlock();
1919 q->ensureCursorVisible();
1920 return true; // accept proposed action
1923 void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
1925 Q_Q(QWidgetTextControl);
1926 if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) {
1930 bool isGettingInput = !e->commitString().isEmpty()
1931 || e->preeditString() != cursor.block().layout()->preeditAreaText()
1932 || e->replacementLength() > 0;
1934 cursor.beginEditBlock();
1935 if (isGettingInput) {
1936 cursor.removeSelectedText();
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());
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);
1959 QTextBlock block = cursor.block();
1960 QTextLayout *layout = block.layout();
1962 layout->setPreeditArea(cursor.position() - block.position(), e->preeditString());
1963 QList<QTextLayout::FormatRange> overrides;
1964 const int oldPreeditCursor = preeditCursor;
1965 preeditCursor = e->preeditString().length();
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();
1975 QTextLayout::FormatRange o;
1976 o.start = a.start + cursor.position() - block.position();
1977 o.length = a.length;
1979 overrides.append(o);
1983 layout->setAdditionalFormats(overrides);
1984 cursor.endEditBlock();
1987 if (oldPreeditCursor != preeditCursor)
1988 emit q->microFocusChanged();
1991 QVariant QWidgetTextControl::inputMethodQuery(Qt::InputMethodQuery property) const
1993 Q_D(const QWidgetTextControl);
1994 QTextBlock block = d->cursor.block();
1996 case Qt::ImCursorRectangle:
1997 return cursorRect();
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()));
2015 void QWidgetTextControl::setFocus(bool focus, Qt::FocusReason reason)
2017 QFocusEvent ev(focus ? QEvent::FocusIn : QEvent::FocusOut,
2022 void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
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
2030 || e->reason() == Qt::ActiveWindowFocusReason
2034 cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard);
2035 if (interactionFlags & Qt::TextEditable) {
2036 setBlinkingCursorEnabled(true);
2038 #ifdef QT_KEYPAD_NAVIGATION
2042 setBlinkingCursorEnabled(false);
2044 if (cursorIsFocusIndicator
2045 && e->reason() != Qt::ActiveWindowFocusReason
2046 && e->reason() != Qt::PopupFocusReason
2047 && cursor.hasSelection()) {
2048 cursor.clearSelection();
2051 hasFocus = e->gotFocus();
2054 QString QWidgetTextControlPrivate::anchorForCursor(const QTextCursor &anchorCursor) const
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);
2068 #ifdef QT_KEYPAD_NAVIGATION
2069 void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
2071 Q_Q(QWidgetTextControl);
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();
2080 if (cursor.position() != oldCursorPos)
2081 emit q->cursorPositionChanged();
2082 emit q->microFocusChanged();
2085 repaintOldAndNewSelection(oldSelection);
2087 setBlinkingCursorEnabled(true);
2089 setBlinkingCursorEnabled(false);
2092 hasEditFocus = e->type() == QEvent::EnterEditFocus ? true : false;
2096 #ifndef QT_NO_CONTEXTMENU
2097 QMenu *QWidgetTextControl::createStandardContextMenu(const QPointF &pos, QWidget *parent)
2099 Q_D(QWidgetTextControl);
2101 const bool showTextSelectionActions = d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
2103 d->linkToCopy = QString();
2105 d->linkToCopy = anchorAt(pos);
2107 if (d->linkToCopy.isEmpty() && !showTextSelectionActions)
2110 QMenu *menu = new QMenu(parent);
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();
2120 a = menu->addAction(tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut), this, SLOT(cut()));
2121 a->setEnabled(d->cursor.hasSelection());
2124 if (showTextSelectionActions) {
2125 a = menu->addAction(tr("&Copy") + ACCEL_KEY(QKeySequence::Copy), this, SLOT(copy()));
2126 a->setEnabled(d->cursor.hasSelection());
2129 if ((d->interactionFlags & Qt::LinksAccessibleByKeyboard)
2130 || (d->interactionFlags & Qt::LinksAccessibleByMouse)) {
2132 a = menu->addAction(tr("Copy &Link Location"), this, SLOT(_q_copyLink()));
2133 a->setEnabled(!d->linkToCopy.isEmpty());
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());
2141 a = menu->addAction(tr("Delete"), this, SLOT(_q_deleteSelected()));
2142 a->setEnabled(d->cursor.hasSelection());
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());
2152 #if !defined(QT_NO_IM)
2153 if (d->contextWidget) {
2154 QInputContext *qic = qApp->inputContext();
2156 QList<QAction *> imActions = qic->actions();
2157 for (int i = 0; i < imActions.size(); ++i)
2158 menu->addAction(imActions.at(i));
2163 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
2164 if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
2166 if (d->interactionFlags & Qt::TextEditable) {
2168 menu->addSeparator();
2169 QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, menu);
2170 menu->addMenu(ctrlCharacterMenu);
2175 #endif // QT_NO_CONTEXTMENU
2177 QTextCursor QWidgetTextControl::cursorForPosition(const QPointF &pos) const
2179 Q_D(const QWidgetTextControl);
2180 int cursorPos = hitTest(pos, Qt::FuzzyHit);
2181 if (cursorPos == -1)
2183 QTextCursor c(d->doc);
2184 c.setPosition(cursorPos);
2188 QRectF QWidgetTextControl::cursorRect(const QTextCursor &cursor) const
2190 Q_D(const QWidgetTextControl);
2191 if (cursor.isNull())
2194 return d->rectForPosition(cursor.position());
2197 QRectF QWidgetTextControl::cursorRect() const
2199 Q_D(const QWidgetTextControl);
2200 return cursorRect(d->cursor);
2203 QRectF QWidgetTextControlPrivate::cursorRectPlusUnicodeDirectionMarkers(const QTextCursor &cursor) const
2205 if (cursor.isNull())
2208 return rectForPosition(cursor.position()).adjusted(-4, 0, 4, 0);
2211 QString QWidgetTextControl::anchorAt(const QPointF &pos) const
2213 Q_D(const QWidgetTextControl);
2214 return d->doc->documentLayout()->anchorAt(pos);
2217 QString QWidgetTextControl::anchorAtCursor() const
2219 Q_D(const QWidgetTextControl);
2221 return d->anchorForCursor(d->cursor);
2224 bool QWidgetTextControl::overwriteMode() const
2226 Q_D(const QWidgetTextControl);
2227 return d->overwriteMode;
2230 void QWidgetTextControl::setOverwriteMode(bool overwrite)
2232 Q_D(QWidgetTextControl);
2233 d->overwriteMode = overwrite;
2236 int QWidgetTextControl::cursorWidth() const
2238 #ifndef QT_NO_PROPERTIES
2239 Q_D(const QWidgetTextControl);
2240 return d->doc->documentLayout()->property("cursorWidth").toInt();
2246 void QWidgetTextControl::setCursorWidth(int width)
2248 Q_D(QWidgetTextControl);
2249 #ifdef QT_NO_PROPERTIES
2253 width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth);
2254 d->doc->documentLayout()->setProperty("cursorWidth", width);
2259 bool QWidgetTextControl::acceptRichText() const
2261 Q_D(const QWidgetTextControl);
2262 return d->acceptRichText;
2265 void QWidgetTextControl::setAcceptRichText(bool accept)
2267 Q_D(QWidgetTextControl);
2268 d->acceptRichText = accept;
2271 #ifndef QT_NO_TEXTEDIT
2273 void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
2275 Q_D(QWidgetTextControl);
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);
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) {
2294 QRectF r = selectionRect(sel.cursor);
2295 if (sel.format.boolProperty(QTextFormat::FullWidthSelection)) {
2297 r.setWidth(qreal(INT_MAX));
2299 emit updateRequest(r);
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)) {
2307 r.setWidth(qreal(INT_MAX));
2309 emit updateRequest(r);
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;
2319 QList<QTextEdit::ExtraSelection> QWidgetTextControl::extraSelections() const
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);
2332 #endif // QT_NO_TEXTEDIT
2334 void QWidgetTextControl::setTextWidth(qreal width)
2336 Q_D(QWidgetTextControl);
2337 d->doc->setTextWidth(width);
2340 qreal QWidgetTextControl::textWidth() const
2342 Q_D(const QWidgetTextControl);
2343 return d->doc->textWidth();
2346 QSizeF QWidgetTextControl::size() const
2348 Q_D(const QWidgetTextControl);
2349 return d->doc->size();
2352 void QWidgetTextControl::setOpenExternalLinks(bool open)
2354 Q_D(QWidgetTextControl);
2355 d->openExternalLinks = open;
2358 bool QWidgetTextControl::openExternalLinks() const
2360 Q_D(const QWidgetTextControl);
2361 return d->openExternalLinks;
2364 bool QWidgetTextControl::ignoreUnusedNavigationEvents() const
2366 Q_D(const QWidgetTextControl);
2367 return d->ignoreUnusedNavigationEvents;
2370 void QWidgetTextControl::setIgnoreUnusedNavigationEvents(bool ignore)
2372 Q_D(QWidgetTextControl);
2373 d->ignoreUnusedNavigationEvents = ignore;
2376 void QWidgetTextControl::moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
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);
2385 emit cursorPositionChanged();
2388 bool QWidgetTextControl::canPaste() const
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);
2400 void QWidgetTextControl::setCursorIsFocusIndicator(bool b)
2402 Q_D(QWidgetTextControl);
2403 d->cursorIsFocusIndicator = b;
2407 bool QWidgetTextControl::cursorIsFocusIndicator() const
2409 Q_D(const QWidgetTextControl);
2410 return d->cursorIsFocusIndicator;
2414 void QWidgetTextControl::setDragEnabled(bool enabled)
2416 Q_D(QWidgetTextControl);
2417 d->dragEnabled = enabled;
2420 bool QWidgetTextControl::isDragEnabled() const
2422 Q_D(const QWidgetTextControl);
2423 return d->dragEnabled;
2426 void QWidgetTextControl::setWordSelectionEnabled(bool enabled)
2428 Q_D(QWidgetTextControl);
2429 d->wordSelectionEnabled = enabled;
2432 bool QWidgetTextControl::isWordSelectionEnabled() const
2434 Q_D(const QWidgetTextControl);
2435 return d->wordSelectionEnabled;
2438 void QWidgetTextControl::print(QPagedPaintDevice *printer) const
2440 Q_D(const QWidgetTextControl);
2443 QTextDocument *tempDoc = 0;
2444 const QTextDocument *doc = d->doc;
2445 if (QPagedPaintDevicePrivate::get(printer)->printSelectionOnly) {
2446 if (!d->cursor.hasSelection())
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());
2456 // copy the custom object handlers
2457 doc->documentLayout()->d_func()->handlers = d->doc->documentLayout()->d_func()->handlers;
2459 doc->print(printer);
2463 QMimeData *QWidgetTextControl::createMimeDataFromSelection() const
2465 Q_D(const QWidgetTextControl);
2466 const QTextDocumentFragment fragment(d->cursor);
2467 return new QTextEditMimeData(fragment);
2470 bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
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"));
2479 return source->hasText() && !source->text().isEmpty();
2482 void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
2484 Q_D(QWidgetTextControl);
2485 if (!(d->interactionFlags & Qt::TextEditable) || !source)
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);
2497 } else if (source->hasHtml() && d->acceptRichText) {
2498 fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
2501 QString text = source->text();
2502 if (!text.isNull()) {
2503 fragment = QTextDocumentFragment::fromPlainText(text);
2508 fragment = QTextDocumentFragment::fromPlainText(source->text());
2509 #endif // QT_NO_TEXTHTMLPARSER
2512 d->cursor.insertFragment(fragment);
2513 ensureCursorVisible();
2516 bool QWidgetTextControl::findNextPrevAnchor(const QTextCursor &startCursor, bool next, QTextCursor &newAnchor)
2518 Q_D(QWidgetTextControl);
2520 int anchorStart = -1;
2525 const int startPos = startCursor.selectionEnd();
2527 QTextBlock block = d->doc->findBlock(startPos);
2528 QTextBlock::Iterator it = block.begin();
2530 while (!it.atEnd() && it.fragment().position() < startPos)
2533 while (block.isValid()) {
2537 for (; !it.atEnd(); ++it) {
2538 const QTextFragment fragment = it.fragment();
2539 const QTextCharFormat fmt = fragment.charFormat();
2541 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2542 anchorStart = fragment.position();
2543 anchorHref = fmt.anchorHref();
2548 if (anchorStart != -1) {
2551 // find next non-anchor fragment
2552 for (; !it.atEnd(); ++it) {
2553 const QTextFragment fragment = it.fragment();
2554 const QTextCharFormat fmt = fragment.charFormat();
2556 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2557 anchorEnd = fragment.position();
2562 if (anchorEnd == -1)
2563 anchorEnd = block.position() + block.length() - 1;
2565 // make found selection
2569 block = block.next();
2573 int startPos = startCursor.selectionStart();
2577 QTextBlock block = d->doc->findBlock(startPos);
2578 QTextBlock::Iterator blockStart = block.begin();
2579 QTextBlock::Iterator it = block.end();
2581 if (startPos == block.position()) {
2585 if (it == blockStart) {
2586 it = QTextBlock::Iterator();
2587 block = QTextBlock();
2591 } while (!it.atEnd() && it.fragment().position() + it.fragment().length() - 1 > startPos);
2594 while (block.isValid()) {
2599 const QTextFragment fragment = it.fragment();
2600 const QTextCharFormat fmt = fragment.charFormat();
2602 if (fmt.isAnchor() && fmt.hasProperty(QTextFormat::AnchorHref)) {
2603 anchorStart = fragment.position() + fragment.length();
2604 anchorHref = fmt.anchorHref();
2608 if (it == blockStart)
2609 it = QTextBlock::Iterator();
2612 } while (!it.atEnd());
2615 if (anchorStart != -1 && !it.atEnd()) {
2619 const QTextFragment fragment = it.fragment();
2620 const QTextCharFormat fmt = fragment.charFormat();
2622 if (!fmt.isAnchor() || fmt.anchorHref() != anchorHref) {
2623 anchorEnd = fragment.position() + fragment.length();
2627 if (it == blockStart)
2628 it = QTextBlock::Iterator();
2631 } while (!it.atEnd());
2633 if (anchorEnd == -1)
2634 anchorEnd = qMax(0, block.position());
2639 block = block.previous();
2641 if (it != block.begin())
2643 blockStart = block.begin();
2648 if (anchorStart != -1 && anchorEnd != -1) {
2649 newAnchor = d->cursor;
2650 newAnchor.setPosition(anchorStart);
2651 newAnchor.setPosition(anchorEnd, QTextCursor::KeepAnchor);
2658 void QWidgetTextControlPrivate::activateLinkUnderCursor(QString href)
2660 QTextCursor oldCursor = cursor;
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();
2672 if (!cursor.hasSelection()) {
2673 QTextBlock block = cursor.block();
2674 const int cursorPos = cursor.position();
2676 QTextBlock::Iterator it = block.begin();
2677 QTextBlock::Iterator linkFragment;
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) {
2689 if (!linkFragment.atEnd()) {
2691 cursor.setPosition(it.fragment().position());
2692 if (it != block.begin()) {
2695 QTextFragment fragment = it.fragment();
2696 if (fragment.charFormat().anchorHref() != href)
2698 cursor.setPosition(fragment.position());
2699 } while (it != block.begin());
2702 for (it = linkFragment; !it.atEnd(); ++it) {
2703 QTextFragment fragment = it.fragment();
2704 if (fragment.charFormat().anchorHref() != href)
2706 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
2712 cursorIsFocusIndicator = true;
2714 cursorIsFocusIndicator = false;
2715 cursor.clearSelection();
2717 repaintOldAndNewSelection(oldCursor);
2719 #ifndef QT_NO_DESKTOPSERVICES
2720 if (openExternalLinks)
2721 QDesktopServices::openUrl(href);
2724 emit q_func()->linkActivated(href);
2727 #ifndef QT_NO_TOOLTIP
2728 void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget)
2730 const QString toolTip = q_func()->cursorForPosition(pos).charFormat().toolTip();
2731 if (toolTip.isEmpty())
2733 QToolTip::showText(globalPos, toolTip, contextWidget);
2735 #endif // QT_NO_TOOLTIP
2737 bool QWidgetTextControl::setFocusToNextOrPreviousAnchor(bool next)
2739 Q_D(QWidgetTextControl);
2741 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2744 QRectF crect = selectionRect();
2745 emit updateRequest(crect);
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);
2751 d->cursor.movePosition(QTextCursor::Start);
2753 d->cursor.movePosition(QTextCursor::End);
2756 QTextCursor newAnchor;
2757 if (findNextPrevAnchor(d->cursor, next, newAnchor)) {
2758 d->cursor = newAnchor;
2759 d->cursorIsFocusIndicator = true;
2761 d->cursor.clearSelection();
2764 if (d->cursor.hasSelection()) {
2765 crect = selectionRect();
2766 emit updateRequest(crect);
2767 emit visibilityRequest(crect);
2774 bool QWidgetTextControl::setFocusToAnchor(const QTextCursor &newCursor)
2776 Q_D(QWidgetTextControl);
2778 if (!(d->interactionFlags & Qt::LinksAccessibleByKeyboard))
2781 // Verify that this is an anchor.
2782 const QString anchorHref = d->anchorForCursor(newCursor);
2783 if (anchorHref.isEmpty())
2787 QRectF crect = selectionRect();
2788 emit updateRequest(crect);
2790 d->cursor.setPosition(newCursor.selectionStart());
2791 d->cursor.setPosition(newCursor.selectionEnd(), QTextCursor::KeepAnchor);
2792 d->cursorIsFocusIndicator = true;
2794 crect = selectionRect();
2795 emit updateRequest(crect);
2796 emit visibilityRequest(crect);
2800 void QWidgetTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
2802 Q_D(QWidgetTextControl);
2803 if (flags == d->interactionFlags)
2805 d->interactionFlags = flags;
2808 d->setBlinkingCursorEnabled(flags & Qt::TextEditable);
2811 Qt::TextInteractionFlags QWidgetTextControl::textInteractionFlags() const
2813 Q_D(const QWidgetTextControl);
2814 return d->interactionFlags;
2817 void QWidgetTextControl::mergeCurrentCharFormat(const QTextCharFormat &modifier)
2819 Q_D(QWidgetTextControl);
2820 d->cursor.mergeCharFormat(modifier);
2821 d->updateCurrentCharFormat();
2824 void QWidgetTextControl::setCurrentCharFormat(const QTextCharFormat &format)
2826 Q_D(QWidgetTextControl);
2827 d->cursor.setCharFormat(format);
2828 d->updateCurrentCharFormat();
2831 QTextCharFormat QWidgetTextControl::currentCharFormat() const
2833 Q_D(const QWidgetTextControl);
2834 return d->cursor.charFormat();
2837 void QWidgetTextControl::insertPlainText(const QString &text)
2839 Q_D(QWidgetTextControl);
2840 d->cursor.insertText(text);
2843 #ifndef QT_NO_TEXTHTMLPARSER
2844 void QWidgetTextControl::insertHtml(const QString &text)
2846 Q_D(QWidgetTextControl);
2847 d->cursor.insertHtml(text);
2849 #endif // QT_NO_TEXTHTMLPARSER
2851 QPointF QWidgetTextControl::anchorPosition(const QString &name) const
2853 Q_D(const QWidgetTextControl);
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());
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();
2877 return QPointF(0, r.top());
2880 void QWidgetTextControl::adjustSize()
2882 Q_D(QWidgetTextControl);
2883 d->doc->adjustSize();
2886 bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags options)
2888 Q_D(QWidgetTextControl);
2889 QTextCursor search = d->doc->find(exp, d->cursor, options);
2890 if (search.isNull())
2893 setTextCursor(search);
2899 void QWidgetTextControlPrivate::append(const QString &text, Qt::TextFormat format)
2901 QTextCursor tmp(doc);
2902 tmp.beginEditBlock();
2903 tmp.movePosition(QTextCursor::End);
2905 if (!doc->isEmpty())
2906 tmp.insertBlock(cursor.blockFormat(), cursor.charFormat());
2908 tmp.setCharFormat(cursor.charFormat());
2910 // preserve the char format
2911 QTextCharFormat oldCharFormat = cursor.charFormat();
2913 #ifndef QT_NO_TEXTHTMLPARSER
2914 if (format == Qt::RichText || (format == Qt::AutoText && Qt::mightBeRichText(text))) {
2915 tmp.insertHtml(text);
2917 tmp.insertText(text);
2920 tmp.insertText(text);
2921 #endif // QT_NO_TEXTHTMLPARSER
2922 if (!cursor.hasSelection())
2923 cursor.setCharFormat(oldCharFormat);
2928 void QWidgetTextControl::append(const QString &text)
2930 Q_D(QWidgetTextControl);
2931 d->append(text, Qt::AutoText);
2934 void QWidgetTextControl::appendHtml(const QString &html)
2936 Q_D(QWidgetTextControl);
2937 d->append(html, Qt::RichText);
2940 void QWidgetTextControl::appendPlainText(const QString &text)
2942 Q_D(QWidgetTextControl);
2943 d->append(text, Qt::PlainText);
2947 void QWidgetTextControl::ensureCursorVisible()
2949 Q_D(QWidgetTextControl);
2950 QRectF crect = d->rectForPosition(d->cursor.position()).adjusted(-5, 0, 5, 0);
2951 emit visibilityRequest(crect);
2952 emit microFocusChanged();
2955 QPalette QWidgetTextControl::palette() const
2957 Q_D(const QWidgetTextControl);
2961 void QWidgetTextControl::setPalette(const QPalette &pal)
2963 Q_D(QWidgetTextControl);
2967 QAbstractTextDocumentLayout::PaintContext QWidgetTextControl::getPaintContext(QWidget *widget) const
2969 Q_D(const QWidgetTextControl);
2971 QAbstractTextDocumentLayout::PaintContext ctx;
2973 ctx.selections = d->extraSelections;
2974 ctx.palette = d->palette;
2975 if (d->cursorOn && d->isEnabled) {
2977 ctx.cursorPosition = -1;
2978 else if (d->preeditCursor != 0)
2979 ctx.cursorPosition = - (d->preeditCursor + 2);
2981 ctx.cursorPosition = d->cursor.position();
2984 if (!d->dndFeedbackCursor.isNull())
2985 ctx.cursorPosition = d->dndFeedbackCursor.position();
2986 #ifdef QT_KEYPAD_NAVIGATION
2987 if (!QApplication::keypadNavigationEnabled() || d->hasEditFocus)
2989 if (d->cursor.hasSelection()) {
2990 QAbstractTextDocumentLayout::Selection selection;
2991 selection.cursor = d->cursor;
2992 if (d->cursorIsFocusIndicator) {
2994 opt.palette = ctx.palette;
2995 QStyleHintReturnVariant ret;
2996 QStyle *style = QApplication::style();
2998 style = widget->style();
2999 style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret);
3000 selection.format = qvariant_cast<QTextFormat>(ret.variant).toCharFormat();
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));
3006 QStyle *style = QApplication::style();
3008 opt.initFrom(widget);
3009 style = widget->style();
3011 if (style->styleHint(QStyle::SH_RichText_FullWidthSelection, &opt, widget))
3012 selection.format.setProperty(QTextFormat::FullWidthSelection, true);
3014 ctx.selections.append(selection);
3020 void QWidgetTextControl::drawContents(QPainter *p, const QRectF &rect, QWidget *widget)
3022 Q_D(QWidgetTextControl);
3024 QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext(widget);
3026 p->setClipRect(rect, Qt::IntersectClip);
3029 d->doc->documentLayout()->draw(p, ctx);
3033 void QWidgetTextControlPrivate::_q_copyLink()
3035 #ifndef QT_NO_CLIPBOARD
3036 QMimeData *md = new QMimeData;
3037 md->setText(linkToCopy);
3038 QApplication::clipboard()->setMimeData(md);
3042 int QWidgetTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
3044 Q_D(const QWidgetTextControl);
3045 return d->doc->documentLayout()->hitTest(point, accuracy);
3048 QRectF QWidgetTextControl::blockBoundingRect(const QTextBlock &block) const
3050 Q_D(const QWidgetTextControl);
3051 return d->doc->documentLayout()->blockBoundingRect(block);
3054 #ifndef QT_NO_CONTEXTMENU
3055 #define NUM_CONTROL_CHARACTERS 10
3056 const struct QUnicodeControlCharacter {
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 },
3072 QUnicodeControlCharacterMenu::QUnicodeControlCharacterMenu(QObject *_editWidget, QWidget *parent)
3073 : QMenu(parent), editWidget(_editWidget)
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()));
3081 void QUnicodeControlCharacterMenu::menuActionTriggered()
3083 QAction *a = qobject_cast<QAction *>(sender());
3084 int idx = actions().indexOf(a);
3085 if (idx < 0 || idx >= NUM_CONTROL_CHARACTERS)
3087 QChar c(qt_controlCharacters[idx].character);
3090 #ifndef QT_NO_TEXTEDIT
3091 if (QTextEdit *edit = qobject_cast<QTextEdit *>(editWidget)) {
3092 edit->insertPlainText(str);
3096 if (QWidgetTextControl *control = qobject_cast<QWidgetTextControl *>(editWidget)) {
3097 control->insertPlainText(str);
3099 #ifndef QT_NO_LINEEDIT
3100 if (QLineEdit *edit = qobject_cast<QLineEdit *>(editWidget)) {
3106 #endif // QT_NO_CONTEXTMENU
3108 QStringList QTextEditMimeData::formats() const
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")
3117 return QMimeData::formats();
3120 QVariant QTextEditMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
3122 if (!fragment.isEmpty())
3124 return QMimeData::retrieveData(mimeType, type);
3127 void QTextEditMimeData::setup() const
3129 QTextEditMimeData *that = const_cast<QTextEditMimeData *>(this);
3130 #ifndef QT_NO_TEXTHTMLPARSER
3131 that->setData(QLatin1String("text/html"), fragment.toHtml("utf-8").toUtf8());
3133 #ifndef QT_NO_TEXTODFWRITER
3136 QTextDocumentWriter writer(&buffer, "ODF");
3137 writer.write(fragment);
3139 that->setData(QLatin1String("application/vnd.oasis.opendocument.text"), buffer.data());
3142 that->setText(fragment.toPlainText());
3143 fragment = QTextDocumentFragment();
3148 #include "moc_qwidgettextcontrol_p.cpp"
3150 #endif // QT_NO_TEXTCONTROL