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