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