util/src/gui/text/qtextcursor.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qtextcursor.h"
       
    43 #include "qtextcursor_p.h"
       
    44 #include "qglobal.h"
       
    45 #include "qtextdocumentfragment.h"
       
    46 #include "qtextdocumentfragment_p.h"
       
    47 #include "qtextlist.h"
       
    48 #include "qtexttable.h"
       
    49 #include "qtexttable_p.h"
       
    50 #include "qtextengine_p.h"
       
    51 #include "qabstracttextdocumentlayout.h"
       
    52 
       
    53 #include <qtextlayout.h>
       
    54 #include <qdebug.h>
       
    55 
       
    56 QT_BEGIN_NAMESPACE
       
    57 
       
    58 enum {
       
    59     AdjustPrev = 0x1,
       
    60     AdjustUp = 0x3,
       
    61     AdjustNext = 0x4,
       
    62     AdjustDown = 0x12
       
    63 };
       
    64 
       
    65 QTextCursorPrivate::QTextCursorPrivate(QTextDocumentPrivate *p)
       
    66     : priv(p), x(0), position(0), anchor(0), adjusted_anchor(0),
       
    67       currentCharFormat(-1), visualNavigation(false)
       
    68 {
       
    69     priv->addCursor(this);
       
    70 }
       
    71 
       
    72 QTextCursorPrivate::QTextCursorPrivate(const QTextCursorPrivate &rhs)
       
    73     : QSharedData(rhs)
       
    74 {
       
    75     position = rhs.position;
       
    76     anchor = rhs.anchor;
       
    77     adjusted_anchor = rhs.adjusted_anchor;
       
    78     priv = rhs.priv;
       
    79     x = rhs.x;
       
    80     currentCharFormat = rhs.currentCharFormat;
       
    81     visualNavigation = rhs.visualNavigation;
       
    82     priv->addCursor(this);
       
    83 }
       
    84 
       
    85 QTextCursorPrivate::~QTextCursorPrivate()
       
    86 {
       
    87     if (priv)
       
    88         priv->removeCursor(this);
       
    89 }
       
    90 
       
    91 QTextCursorPrivate::AdjustResult QTextCursorPrivate::adjustPosition(int positionOfChange, int charsAddedOrRemoved, QTextUndoCommand::Operation op)
       
    92 {
       
    93     QTextCursorPrivate::AdjustResult result = QTextCursorPrivate::CursorMoved;
       
    94     // not(!) <= , so that inserting text adjusts the cursor correctly
       
    95     if (position < positionOfChange
       
    96         || (position == positionOfChange
       
    97             && (op == QTextUndoCommand::KeepCursor
       
    98                 || anchor < position)
       
    99             )
       
   100          ) {
       
   101         result = CursorUnchanged;
       
   102     } else {
       
   103         if (charsAddedOrRemoved < 0 && position < positionOfChange - charsAddedOrRemoved)
       
   104             position = positionOfChange;
       
   105         else
       
   106             position += charsAddedOrRemoved;
       
   107 
       
   108         currentCharFormat = -1;
       
   109     }
       
   110 
       
   111     if (anchor >= positionOfChange
       
   112         && (anchor != positionOfChange || op != QTextUndoCommand::KeepCursor)) {
       
   113         if (charsAddedOrRemoved < 0 && anchor < positionOfChange - charsAddedOrRemoved)
       
   114             anchor = positionOfChange;
       
   115         else
       
   116             anchor += charsAddedOrRemoved;
       
   117     }
       
   118 
       
   119     if (adjusted_anchor >= positionOfChange
       
   120         && (adjusted_anchor != positionOfChange || op != QTextUndoCommand::KeepCursor)) {
       
   121         if (charsAddedOrRemoved < 0 && adjusted_anchor < positionOfChange - charsAddedOrRemoved)
       
   122             adjusted_anchor = positionOfChange;
       
   123         else
       
   124             adjusted_anchor += charsAddedOrRemoved;
       
   125     }
       
   126 
       
   127     return result;
       
   128 }
       
   129 
       
   130 void QTextCursorPrivate::setX()
       
   131 {
       
   132     if (priv->isInEditBlock()) {
       
   133         x = -1; // mark dirty
       
   134         return;
       
   135     }
       
   136 
       
   137     QTextBlock block = this->block();
       
   138     const QTextLayout *layout = blockLayout(block);
       
   139     int pos = position - block.position();
       
   140 
       
   141     QTextLine line = layout->lineForTextPosition(pos);
       
   142     if (line.isValid())
       
   143         x = line.cursorToX(pos);
       
   144     else
       
   145         x = -1; // delayed init.  Makes movePosition() call setX later on again.
       
   146 }
       
   147 
       
   148 void QTextCursorPrivate::remove()
       
   149 {
       
   150     if (anchor == position)
       
   151         return;
       
   152     currentCharFormat = -1;
       
   153     int pos1 = position;
       
   154     int pos2 = adjusted_anchor;
       
   155     QTextUndoCommand::Operation op = QTextUndoCommand::KeepCursor;
       
   156     if (pos1 > pos2) {
       
   157         pos1 = adjusted_anchor;
       
   158         pos2 = position;
       
   159         op = QTextUndoCommand::MoveCursor;
       
   160     }
       
   161 
       
   162     // deleting inside table? -> delete only content
       
   163     QTextTable *table = complexSelectionTable();
       
   164     if (table) {
       
   165         priv->beginEditBlock();
       
   166         int startRow, startCol, numRows, numCols;
       
   167         selectedTableCells(&startRow, &numRows, &startCol, &numCols);
       
   168         clearCells(table, startRow, startCol, numRows, numCols, op);
       
   169         adjusted_anchor = anchor = position;
       
   170         priv->endEditBlock();
       
   171     } else {
       
   172         priv->remove(pos1, pos2-pos1, op);
       
   173         adjusted_anchor = anchor = position;
       
   174         priv->finishEdit();
       
   175     }
       
   176 
       
   177 }
       
   178 
       
   179 void QTextCursorPrivate::clearCells(QTextTable *table, int startRow, int startCol, int numRows, int numCols, QTextUndoCommand::Operation op)
       
   180 {
       
   181     priv->beginEditBlock();
       
   182 
       
   183     for (int row = startRow; row < startRow + numRows; ++row)
       
   184         for (int col = startCol; col < startCol + numCols; ++col) {
       
   185             QTextTableCell cell = table->cellAt(row, col);
       
   186             const int startPos = cell.firstPosition();
       
   187             const int endPos = cell.lastPosition();
       
   188             Q_ASSERT(startPos <= endPos);
       
   189             priv->remove(startPos, endPos - startPos, op);
       
   190         }
       
   191 
       
   192     priv->endEditBlock();
       
   193 }
       
   194 
       
   195 bool QTextCursorPrivate::canDelete(int pos) const
       
   196 {
       
   197     QTextDocumentPrivate::FragmentIterator fit = priv->find(pos);
       
   198     QTextCharFormat fmt = priv->formatCollection()->charFormat((*fit)->format);
       
   199     return (fmt.objectIndex() == -1 || fmt.objectType() == QTextFormat::ImageObject);
       
   200 }
       
   201 
       
   202 void QTextCursorPrivate::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
       
   203 {
       
   204     QTextFormatCollection *formats = priv->formatCollection();
       
   205     int idx = formats->indexForFormat(format);
       
   206     Q_ASSERT(formats->format(idx).isBlockFormat());
       
   207 
       
   208     priv->insertBlock(position, idx, formats->indexForFormat(charFormat));
       
   209     currentCharFormat = -1;
       
   210 }
       
   211 
       
   212 void QTextCursorPrivate::adjustCursor(QTextCursor::MoveOperation m)
       
   213 {
       
   214     adjusted_anchor = anchor;
       
   215     if (position == anchor)
       
   216         return;
       
   217 
       
   218     QTextFrame *f_position = priv->frameAt(position);
       
   219     QTextFrame *f_anchor = priv->frameAt(adjusted_anchor);
       
   220 
       
   221     if (f_position != f_anchor) {
       
   222         // find common parent frame
       
   223         QList<QTextFrame *> positionChain;
       
   224         QList<QTextFrame *> anchorChain;
       
   225         QTextFrame *f = f_position;
       
   226         while (f) {
       
   227             positionChain.prepend(f);
       
   228             f = f->parentFrame();
       
   229         }
       
   230         f = f_anchor;
       
   231         while (f) {
       
   232             anchorChain.prepend(f);
       
   233             f = f->parentFrame();
       
   234         }
       
   235         Q_ASSERT(positionChain.at(0) == anchorChain.at(0));
       
   236         int i = 1;
       
   237         int l = qMin(positionChain.size(), anchorChain.size());
       
   238         for (; i < l; ++i) {
       
   239             if (positionChain.at(i) != anchorChain.at(i))
       
   240                 break;
       
   241         }
       
   242 
       
   243         if (m <= QTextCursor::WordLeft) {
       
   244             if (i < positionChain.size())
       
   245                 position = positionChain.at(i)->firstPosition() - 1;
       
   246         } else {
       
   247             if (i < positionChain.size())
       
   248                 position = positionChain.at(i)->lastPosition() + 1;
       
   249         }
       
   250         if (position < adjusted_anchor) {
       
   251             if (i < anchorChain.size())
       
   252                 adjusted_anchor = anchorChain.at(i)->lastPosition() + 1;
       
   253         } else {
       
   254             if (i < anchorChain.size())
       
   255                 adjusted_anchor = anchorChain.at(i)->firstPosition() - 1;
       
   256         }
       
   257 
       
   258         f_position = positionChain.at(i-1);
       
   259     }
       
   260 
       
   261     // same frame, either need to adjust to cell boundaries or return
       
   262     QTextTable *table = qobject_cast<QTextTable *>(f_position);
       
   263     if (!table)
       
   264         return;
       
   265 
       
   266     QTextTableCell c_position = table->cellAt(position);
       
   267     QTextTableCell c_anchor = table->cellAt(adjusted_anchor);
       
   268     if (c_position != c_anchor) {
       
   269         bool before;
       
   270         int col_position = c_position.column();
       
   271         int col_anchor = c_anchor.column();
       
   272         if (col_position == col_anchor) {
       
   273             before = c_position.row() < c_anchor.row();
       
   274         } else {
       
   275             before = col_position < col_anchor;
       
   276         }
       
   277 
       
   278         // adjust to cell boundaries
       
   279         if (m <= QTextCursor::WordLeft) {
       
   280             position = c_position.firstPosition();
       
   281             if (!before)
       
   282                 --position;
       
   283         } else {
       
   284             position = c_position.lastPosition();
       
   285             if (before)
       
   286                 ++position;
       
   287         }
       
   288         if (position < adjusted_anchor)
       
   289             adjusted_anchor = c_anchor.lastPosition();
       
   290         else
       
   291             adjusted_anchor = c_anchor.firstPosition();
       
   292     }
       
   293     currentCharFormat = -1;
       
   294 }
       
   295 
       
   296 void QTextCursorPrivate::aboutToRemoveCell(int from, int to)
       
   297 {
       
   298     Q_ASSERT(from <= to);
       
   299     if (position == anchor)
       
   300         return;
       
   301 
       
   302     QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
       
   303     if (!t)
       
   304         return;
       
   305     QTextTableCell removedCellFrom = t->cellAt(from);
       
   306     QTextTableCell removedCellEnd = t->cellAt(to);
       
   307     if (! removedCellFrom.isValid() || !removedCellEnd.isValid())
       
   308         return;
       
   309 
       
   310     int curFrom = position;
       
   311     int curTo = adjusted_anchor;
       
   312     if (curTo < curFrom)
       
   313         qSwap(curFrom, curTo);
       
   314 
       
   315     QTextTableCell cellStart = t->cellAt(curFrom);
       
   316     QTextTableCell cellEnd = t->cellAt(curTo);
       
   317 
       
   318     if (cellStart.row() >= removedCellFrom.row() && cellEnd.row() <= removedCellEnd.row()
       
   319             && cellStart.column() >= removedCellFrom.column()
       
   320               && cellEnd.column() <= removedCellEnd.column()) { // selection is completely removed
       
   321         // find a new position, as close as possible to where we were.
       
   322         QTextTableCell cell;
       
   323         if (removedCellFrom.row() == 0 && removedCellEnd.row() == t->rows()-1) // removed n columns
       
   324             cell = t->cellAt(cellStart.row(), removedCellEnd.column()+1);
       
   325         else if (removedCellFrom.column() == 0 && removedCellEnd.column() == t->columns()-1) // removed n rows
       
   326             cell = t->cellAt(removedCellEnd.row() + 1, cellStart.column());
       
   327 
       
   328         int newPosition;
       
   329         if (cell.isValid())
       
   330             newPosition = cell.firstPosition();
       
   331         else
       
   332             newPosition = t->lastPosition()+1;
       
   333 
       
   334         setPosition(newPosition);
       
   335         anchor = newPosition;
       
   336         adjusted_anchor = newPosition;
       
   337         x = 0;
       
   338     }
       
   339     else if (cellStart.row() >= removedCellFrom.row() && cellStart.row() <= removedCellEnd.row()
       
   340         && cellEnd.row() > removedCellEnd.row()) {
       
   341         int newPosition = t->cellAt(removedCellEnd.row() + 1, cellStart.column()).firstPosition();
       
   342         if (position < anchor)
       
   343             position = newPosition;
       
   344         else
       
   345             anchor = adjusted_anchor = newPosition;
       
   346     }
       
   347     else if (cellStart.column() >= removedCellFrom.column() && cellStart.column() <= removedCellEnd.column()
       
   348         && cellEnd.column() > removedCellEnd.column()) {
       
   349         int newPosition = t->cellAt(cellStart.row(), removedCellEnd.column()+1).firstPosition();
       
   350         if (position < anchor)
       
   351             position = newPosition;
       
   352         else
       
   353             anchor = adjusted_anchor = newPosition;
       
   354     }
       
   355 }
       
   356 
       
   357 bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
       
   358 {
       
   359     currentCharFormat = -1;
       
   360     bool adjustX = true;
       
   361     QTextBlock blockIt = block();
       
   362 
       
   363     if (op >= QTextCursor::Left && op <= QTextCursor::WordRight
       
   364         && blockIt.blockFormat().layoutDirection() == Qt::RightToLeft) {
       
   365         if (op == QTextCursor::Left)
       
   366             op = QTextCursor::NextCharacter;
       
   367         else if (op == QTextCursor::Right)
       
   368             op = QTextCursor::PreviousCharacter;
       
   369         else if (op == QTextCursor::WordLeft)
       
   370             op = QTextCursor::NextWord;
       
   371         else if (op == QTextCursor::WordRight)
       
   372             op = QTextCursor::PreviousWord;
       
   373     }
       
   374 
       
   375     const QTextLayout *layout = blockLayout(blockIt);
       
   376     int relativePos = position - blockIt.position();
       
   377     QTextLine line;
       
   378     if (!priv->isInEditBlock())
       
   379         line = layout->lineForTextPosition(relativePos);
       
   380 
       
   381     Q_ASSERT(priv->frameAt(position) == priv->frameAt(adjusted_anchor));
       
   382 
       
   383     int newPosition = position;
       
   384 
       
   385     if (x == -1 && !priv->isInEditBlock() && (op == QTextCursor::Up || op == QTextCursor::Down))
       
   386         setX();
       
   387 
       
   388     switch(op) {
       
   389     case QTextCursor::NoMove:
       
   390         return true;
       
   391 
       
   392     case QTextCursor::Start:
       
   393         newPosition = 0;
       
   394         break;
       
   395     case QTextCursor::StartOfLine: {
       
   396         newPosition = blockIt.position();
       
   397         if (line.isValid())
       
   398             newPosition += line.textStart();
       
   399 
       
   400         break;
       
   401     }
       
   402     case QTextCursor::StartOfBlock: {
       
   403         newPosition = blockIt.position();
       
   404         break;
       
   405     }
       
   406     case QTextCursor::PreviousBlock: {
       
   407         if (blockIt == priv->blocksBegin())
       
   408             return false;
       
   409         blockIt = blockIt.previous();
       
   410 
       
   411         newPosition = blockIt.position();
       
   412         break;
       
   413     }
       
   414     case QTextCursor::PreviousCharacter:
       
   415     case QTextCursor::Left:
       
   416         newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
       
   417         break;
       
   418     case QTextCursor::StartOfWord: {
       
   419         if (relativePos == 0)
       
   420             break;
       
   421 
       
   422         // skip if already at word start
       
   423         QTextEngine *engine = layout->engine();
       
   424         engine->attributes();
       
   425         if ((relativePos == blockIt.length() - 1)
       
   426             && (engine->atSpace(relativePos - 1) || engine->atWordSeparator(relativePos - 1)))
       
   427             return false;
       
   428 
       
   429         if (relativePos < blockIt.length()-1)
       
   430             ++position;
       
   431 
       
   432         // FALL THROUGH!
       
   433     }
       
   434     case QTextCursor::PreviousWord:
       
   435     case QTextCursor::WordLeft:
       
   436         newPosition = priv->previousCursorPosition(position, QTextLayout::SkipWords);
       
   437         break;
       
   438     case QTextCursor::Up: {
       
   439         int i = line.lineNumber() - 1;
       
   440         if (i == -1) {
       
   441             if (blockIt == priv->blocksBegin())
       
   442                 return false;
       
   443             int blockPosition = blockIt.position();
       
   444             QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(blockPosition));
       
   445             if (table) {
       
   446                 QTextTableCell cell = table->cellAt(blockPosition);
       
   447                 if (cell.firstPosition() == blockPosition) {
       
   448                     int row = cell.row() - 1;
       
   449                     if (row >= 0) {
       
   450                         blockPosition = table->cellAt(row, cell.column()).lastPosition();
       
   451                     } else {
       
   452                         // move to line above the table
       
   453                         blockPosition = table->firstPosition() - 1;
       
   454                     }
       
   455                     blockIt = priv->blocksFind(blockPosition);
       
   456                 } else {
       
   457                     blockIt = blockIt.previous();
       
   458                 }
       
   459             } else {
       
   460                 blockIt = blockIt.previous();
       
   461             }
       
   462             layout = blockLayout(blockIt);
       
   463             i = layout->lineCount()-1;
       
   464         }
       
   465         if (layout->lineCount()) {
       
   466             QTextLine line = layout->lineAt(i);
       
   467             newPosition = line.xToCursor(x) + blockIt.position();
       
   468         } else {
       
   469             newPosition = blockIt.position();
       
   470         }
       
   471         adjustX = false;
       
   472         break;
       
   473     }
       
   474 
       
   475     case QTextCursor::End:
       
   476         newPosition = priv->length() - 1;
       
   477         break;
       
   478     case QTextCursor::EndOfLine: {
       
   479         if (!line.isValid() || line.textLength() == 0) {
       
   480             if (blockIt.length() >= 1)
       
   481                 // position right before the block separator
       
   482                 newPosition = blockIt.position() + blockIt.length() - 1;
       
   483             break;
       
   484         }
       
   485         newPosition = blockIt.position() + line.textStart() + line.textLength();
       
   486         if (line.lineNumber() < layout->lineCount() - 1) {
       
   487             const QString text = blockIt.text();
       
   488             // ###### this relies on spaces being the cause for linebreaks.
       
   489             // this doesn't work with japanese
       
   490             if (text.at(line.textStart() + line.textLength() - 1).isSpace())
       
   491                 --newPosition;
       
   492         }
       
   493         break;
       
   494     }
       
   495     case QTextCursor::EndOfWord: {
       
   496         QTextEngine *engine = layout->engine();
       
   497         engine->attributes();
       
   498         const int len = blockIt.length() - 1;
       
   499         if (relativePos >= len)
       
   500             return false;
       
   501         if (engine->atWordSeparator(relativePos)) {
       
   502             ++relativePos;
       
   503             while (relativePos < len && engine->atWordSeparator(relativePos))
       
   504                 ++relativePos;
       
   505         } else {
       
   506             while (relativePos < len && !engine->atSpace(relativePos) && !engine->atWordSeparator(relativePos))
       
   507                 ++relativePos;
       
   508         }
       
   509         newPosition = blockIt.position() + relativePos;
       
   510         break;
       
   511     }
       
   512     case QTextCursor::EndOfBlock:
       
   513         if (blockIt.length() >= 1)
       
   514             // position right before the block separator
       
   515             newPosition = blockIt.position() + blockIt.length() - 1;
       
   516         break;
       
   517     case QTextCursor::NextBlock: {
       
   518         blockIt = blockIt.next();
       
   519         if (!blockIt.isValid())
       
   520             return false;
       
   521 
       
   522         newPosition = blockIt.position();
       
   523         break;
       
   524     }
       
   525     case QTextCursor::NextCharacter:
       
   526     case QTextCursor::Right:
       
   527         newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
       
   528         break;
       
   529     case QTextCursor::NextWord:
       
   530     case QTextCursor::WordRight:
       
   531         newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords);
       
   532         break;
       
   533 
       
   534     case QTextCursor::Down: {
       
   535         int i = line.lineNumber() + 1;
       
   536 
       
   537         if (i >= layout->lineCount()) {
       
   538             int blockPosition = blockIt.position() + blockIt.length() - 1;
       
   539             QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(blockPosition));
       
   540             if (table) {
       
   541                 QTextTableCell cell = table->cellAt(blockPosition);
       
   542                 if (cell.lastPosition() == blockPosition) {
       
   543                     int row = cell.row() + cell.rowSpan();
       
   544                     if (row < table->rows()) {
       
   545                         blockPosition = table->cellAt(row, cell.column()).firstPosition();
       
   546                     } else {
       
   547                         // move to line below the table
       
   548                         blockPosition = table->lastPosition() + 1;
       
   549                     }
       
   550                     blockIt = priv->blocksFind(blockPosition);
       
   551                 } else {
       
   552                     blockIt = blockIt.next();
       
   553                 }
       
   554             } else {
       
   555                 blockIt = blockIt.next();
       
   556             }
       
   557 
       
   558             if (blockIt == priv->blocksEnd())
       
   559                 return false;
       
   560             layout = blockLayout(blockIt);
       
   561             i = 0;
       
   562         }
       
   563         if (layout->lineCount()) {
       
   564             QTextLine line = layout->lineAt(i);
       
   565             newPosition = line.xToCursor(x) + blockIt.position();
       
   566         } else {
       
   567             newPosition = blockIt.position();
       
   568         }
       
   569         adjustX = false;
       
   570         break;
       
   571     }
       
   572     case QTextCursor::NextCell: // fall through
       
   573     case QTextCursor::PreviousCell: // fall through
       
   574     case QTextCursor::NextRow: // fall through
       
   575     case QTextCursor::PreviousRow: {
       
   576         QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
       
   577         if (!table)
       
   578             return false;
       
   579 
       
   580         QTextTableCell cell = table->cellAt(position);
       
   581         Q_ASSERT(cell.isValid());
       
   582         int column = cell.column();
       
   583         int row = cell.row();
       
   584         const int currentRow = row;
       
   585         if (op == QTextCursor::NextCell || op == QTextCursor::NextRow) {
       
   586             do {
       
   587                 column += cell.columnSpan();
       
   588                 if (column >= table->columns()) {
       
   589                     column = 0;
       
   590                     ++row;
       
   591                 }
       
   592                 cell = table->cellAt(row, column);
       
   593                 // note we also continue while we have not reached a cell thats not merged with one above us
       
   594             } while (cell.isValid()
       
   595                     && ((op == QTextCursor::NextRow && currentRow == cell.row())
       
   596                         || cell.row() < row));
       
   597         }
       
   598         else if (op == QTextCursor::PreviousCell || op == QTextCursor::PreviousRow) {
       
   599             do {
       
   600                 --column;
       
   601                 if (column < 0) {
       
   602                     column = table->columns()-1;
       
   603                     --row;
       
   604                 }
       
   605                 cell = table->cellAt(row, column);
       
   606                 // note we also continue while we have not reached a cell thats not merged with one above us
       
   607             } while (cell.isValid()
       
   608                     && ((op == QTextCursor::PreviousRow && currentRow == cell.row())
       
   609                         || cell.row() < row));
       
   610         }
       
   611         if (cell.isValid())
       
   612             newPosition = cell.firstPosition();
       
   613         break;
       
   614     }
       
   615     }
       
   616 
       
   617     if (mode == QTextCursor::KeepAnchor) {
       
   618         QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
       
   619         if (table && ((op >= QTextCursor::PreviousBlock && op <= QTextCursor::WordLeft)
       
   620                       || (op >= QTextCursor::NextBlock && op <= QTextCursor::WordRight))) {
       
   621             int oldColumn = table->cellAt(position).column();
       
   622 
       
   623             const QTextTableCell otherCell = table->cellAt(newPosition);
       
   624             if (!otherCell.isValid())
       
   625                 return false;
       
   626 
       
   627             int newColumn = otherCell.column();
       
   628             if ((oldColumn > newColumn && op >= QTextCursor::End)
       
   629                 || (oldColumn < newColumn && op <= QTextCursor::WordLeft))
       
   630                 return false;
       
   631         }
       
   632     }
       
   633 
       
   634     const bool moved = setPosition(newPosition);
       
   635 
       
   636     if (mode == QTextCursor::MoveAnchor) {
       
   637         anchor = position;
       
   638         adjusted_anchor = position;
       
   639     } else {
       
   640         adjustCursor(op);
       
   641     }
       
   642 
       
   643     if (adjustX)
       
   644         setX();
       
   645 
       
   646     return moved;
       
   647 }
       
   648 
       
   649 QTextTable *QTextCursorPrivate::complexSelectionTable() const
       
   650 {
       
   651     if (position == anchor)
       
   652         return 0;
       
   653 
       
   654     QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
       
   655     if (t) {
       
   656         QTextTableCell cell_pos = t->cellAt(position);
       
   657         QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
       
   658 
       
   659         Q_ASSERT(cell_anchor.isValid());
       
   660 
       
   661         if (cell_pos == cell_anchor)
       
   662             t = 0;
       
   663     }
       
   664     return t;
       
   665 }
       
   666 
       
   667 void QTextCursorPrivate::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
       
   668 {
       
   669     *firstRow = -1;
       
   670     *firstColumn = -1;
       
   671     *numRows = -1;
       
   672     *numColumns = -1;
       
   673 
       
   674     if (position == anchor)
       
   675         return;
       
   676 
       
   677     QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
       
   678     if (!t)
       
   679         return;
       
   680 
       
   681     QTextTableCell cell_pos = t->cellAt(position);
       
   682     QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
       
   683 
       
   684     Q_ASSERT(cell_anchor.isValid());
       
   685 
       
   686     if (cell_pos == cell_anchor)
       
   687         return;
       
   688 
       
   689     *firstRow = qMin(cell_pos.row(), cell_anchor.row());
       
   690     *firstColumn = qMin(cell_pos.column(), cell_anchor.column());
       
   691     *numRows = qMax(cell_pos.row() + cell_pos.rowSpan(), cell_anchor.row() + cell_anchor.rowSpan()) - *firstRow;
       
   692     *numColumns = qMax(cell_pos.column() + cell_pos.columnSpan(), cell_anchor.column() + cell_anchor.columnSpan()) - *firstColumn;
       
   693 }
       
   694 
       
   695 static void setBlockCharFormatHelper(QTextDocumentPrivate *priv, int pos1, int pos2,
       
   696                                const QTextCharFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
       
   697 {
       
   698     QTextBlock it = priv->blocksFind(pos1);
       
   699     QTextBlock end = priv->blocksFind(pos2);
       
   700     if (end.isValid())
       
   701         end = end.next();
       
   702 
       
   703     for (; it != end; it = it.next()) {
       
   704         priv->setCharFormat(it.position() - 1, 1, format, changeMode);
       
   705     }
       
   706 }
       
   707 
       
   708 void QTextCursorPrivate::setBlockCharFormat(const QTextCharFormat &_format,
       
   709     QTextDocumentPrivate::FormatChangeMode changeMode)
       
   710 {
       
   711     priv->beginEditBlock();
       
   712 
       
   713     QTextCharFormat format = _format;
       
   714     format.clearProperty(QTextFormat::ObjectIndex);
       
   715 
       
   716     QTextTable *table = complexSelectionTable();
       
   717     if (table) {
       
   718         int row_start, col_start, num_rows, num_cols;
       
   719         selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
       
   720 
       
   721         Q_ASSERT(row_start != -1);
       
   722         for (int r = row_start; r < row_start + num_rows; ++r) {
       
   723             for (int c = col_start; c < col_start + num_cols; ++c) {
       
   724                 QTextTableCell cell = table->cellAt(r, c);
       
   725                 int rspan = cell.rowSpan();
       
   726                 int cspan = cell.columnSpan();
       
   727                 if (rspan != 1) {
       
   728                     int cr = cell.row();
       
   729                     if (cr != r)
       
   730                         continue;
       
   731                 }
       
   732                 if (cspan != 1) {
       
   733                     int cc = cell.column();
       
   734                     if (cc != c)
       
   735                         continue;
       
   736                 }
       
   737 
       
   738                 int pos1 = cell.firstPosition();
       
   739                 int pos2 = cell.lastPosition();
       
   740                 setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
       
   741             }
       
   742         }
       
   743     } else {
       
   744         int pos1 = position;
       
   745         int pos2 = adjusted_anchor;
       
   746         if (pos1 > pos2) {
       
   747             pos1 = adjusted_anchor;
       
   748             pos2 = position;
       
   749         }
       
   750 
       
   751         setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
       
   752     }
       
   753     priv->endEditBlock();
       
   754 }
       
   755 
       
   756 
       
   757 void QTextCursorPrivate::setBlockFormat(const QTextBlockFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
       
   758 {
       
   759     QTextTable *table = complexSelectionTable();
       
   760     if (table) {
       
   761         priv->beginEditBlock();
       
   762         int row_start, col_start, num_rows, num_cols;
       
   763         selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
       
   764 
       
   765         Q_ASSERT(row_start != -1);
       
   766         for (int r = row_start; r < row_start + num_rows; ++r) {
       
   767             for (int c = col_start; c < col_start + num_cols; ++c) {
       
   768                 QTextTableCell cell = table->cellAt(r, c);
       
   769                 int rspan = cell.rowSpan();
       
   770                 int cspan = cell.columnSpan();
       
   771                 if (rspan != 1) {
       
   772                     int cr = cell.row();
       
   773                     if (cr != r)
       
   774                         continue;
       
   775                 }
       
   776                 if (cspan != 1) {
       
   777                     int cc = cell.column();
       
   778                     if (cc != c)
       
   779                         continue;
       
   780                 }
       
   781 
       
   782                 int pos1 = cell.firstPosition();
       
   783                 int pos2 = cell.lastPosition();
       
   784                 priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
       
   785             }
       
   786         }
       
   787         priv->endEditBlock();
       
   788     } else {
       
   789         int pos1 = position;
       
   790         int pos2 = adjusted_anchor;
       
   791         if (pos1 > pos2) {
       
   792             pos1 = adjusted_anchor;
       
   793             pos2 = position;
       
   794         }
       
   795 
       
   796         priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
       
   797     }
       
   798 }
       
   799 
       
   800 void QTextCursorPrivate::setCharFormat(const QTextCharFormat &_format, QTextDocumentPrivate::FormatChangeMode changeMode)
       
   801 {
       
   802     Q_ASSERT(position != anchor);
       
   803 
       
   804     QTextCharFormat format = _format;
       
   805     format.clearProperty(QTextFormat::ObjectIndex);
       
   806 
       
   807     QTextTable *table = complexSelectionTable();
       
   808     if (table) {
       
   809         priv->beginEditBlock();
       
   810         int row_start, col_start, num_rows, num_cols;
       
   811         selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
       
   812 
       
   813         Q_ASSERT(row_start != -1);
       
   814         for (int r = row_start; r < row_start + num_rows; ++r) {
       
   815             for (int c = col_start; c < col_start + num_cols; ++c) {
       
   816                 QTextTableCell cell = table->cellAt(r, c);
       
   817                 int rspan = cell.rowSpan();
       
   818                 int cspan = cell.columnSpan();
       
   819                 if (rspan != 1) {
       
   820                     int cr = cell.row();
       
   821                     if (cr != r)
       
   822                         continue;
       
   823                 }
       
   824                 if (cspan != 1) {
       
   825                     int cc = cell.column();
       
   826                     if (cc != c)
       
   827                         continue;
       
   828                 }
       
   829 
       
   830                 int pos1 = cell.firstPosition();
       
   831                 int pos2 = cell.lastPosition();
       
   832                 priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
       
   833             }
       
   834         }
       
   835         priv->endEditBlock();
       
   836     } else {
       
   837         int pos1 = position;
       
   838         int pos2 = adjusted_anchor;
       
   839         if (pos1 > pos2) {
       
   840             pos1 = adjusted_anchor;
       
   841             pos2 = position;
       
   842         }
       
   843 
       
   844         priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
       
   845     }
       
   846 }
       
   847 
       
   848 
       
   849 QTextLayout *QTextCursorPrivate::blockLayout(QTextBlock &block) const{
       
   850     QTextLayout *tl = block.layout();
       
   851     if (!tl->lineCount() && priv->layout())
       
   852         priv->layout()->blockBoundingRect(block);
       
   853     return tl;
       
   854 }
       
   855 
       
   856 /*!
       
   857     \class QTextCursor
       
   858     \reentrant
       
   859 
       
   860     \brief The QTextCursor class offers an API to access and modify QTextDocuments.
       
   861 
       
   862     \ingroup richtext-processing
       
   863     \ingroup shared
       
   864 
       
   865     Text cursors are objects that are used to access and modify the
       
   866     contents and underlying structure of text documents via a
       
   867     programming interface that mimics the behavior of a cursor in a
       
   868     text editor. QTextCursor contains information about both the
       
   869     cursor's position within a QTextDocument and any selection that it
       
   870     has made.
       
   871 
       
   872     QTextCursor is modeled on the way a text cursor behaves in a text
       
   873     editor, providing a programmatic means of performing standard
       
   874     actions through the user interface. A document can be thought of
       
   875     as a single string of characters. The cursor's current position()
       
   876     then is always either \e between two consecutive characters in the
       
   877     string, or else \e before the very first character or \e after the
       
   878     very last character in the string.  Documents can also contain
       
   879     tables, lists, images, and other objects in addition to text but,
       
   880     from the developer's point of view, the document can be treated as
       
   881     one long string.  Some portions of that string can be considered
       
   882     to lie within particular blocks (e.g. paragraphs), or within a
       
   883     table's cell, or a list's item, or other structural elements. When
       
   884     we refer to "current character" we mean the character immediately
       
   885     \e before the cursor position() in the document. Similarly, the
       
   886     "current block" is the block that contains the cursor position().
       
   887 
       
   888     A QTextCursor also has an anchor() position. The text that is
       
   889     between the anchor() and the position() is the selection. If
       
   890     anchor() == position() there is no selection.
       
   891 
       
   892     The cursor position can be changed programmatically using
       
   893     setPosition() and movePosition(); the latter can also be used to
       
   894     select text. For selections see selectionStart(), selectionEnd(),
       
   895     hasSelection(), clearSelection(), and removeSelectedText().
       
   896 
       
   897     If the position() is at the start of a block atBlockStart()
       
   898     returns true; and if it is at the end of a block atBlockEnd() returns
       
   899     true. The format of the current character is returned by
       
   900     charFormat(), and the format of the current block is returned by
       
   901     blockFormat().
       
   902 
       
   903     Formatting can be applied to the current text document using the
       
   904     setCharFormat(), mergeCharFormat(), setBlockFormat() and
       
   905     mergeBlockFormat() functions. The 'set' functions will replace the
       
   906     cursor's current character or block format, while the 'merge'
       
   907     functions add the given format properties to the cursor's current
       
   908     format. If the cursor has a selection the given format is applied
       
   909     to the current selection. Note that when only parts of a block is
       
   910     selected the block format is applied to the entire block. The text
       
   911     at the current character position can be turned into a list using
       
   912     createList().
       
   913 
       
   914     Deletions can be achieved using deleteChar(),
       
   915     deletePreviousChar(), and removeSelectedText().
       
   916 
       
   917     Text strings can be inserted into the document with the insertText()
       
   918     function, blocks (representing new paragraphs) can be inserted with
       
   919     insertBlock().
       
   920 
       
   921     Existing fragments of text can be inserted with insertFragment() but,
       
   922     if you want to insert pieces of text in various formats, it is usually
       
   923     still easier to use insertText() and supply a character format.
       
   924 
       
   925     Various types of higher-level structure can also be inserted into the
       
   926     document with the cursor:
       
   927 
       
   928     \list
       
   929     \i Lists are ordered sequences of block elements that are decorated with
       
   930        bullet points or symbols. These are inserted in a specified format
       
   931        with insertList().
       
   932     \i Tables are inserted with the insertTable() function, and can be
       
   933        given an optional format. These contain an array of cells that can
       
   934        be traversed using the cursor.
       
   935     \i Inline images are inserted with insertImage(). The image to be
       
   936        used can be specified in an image format, or by name.
       
   937     \i Frames are inserted by calling insertFrame() with a specified format.
       
   938     \endlist
       
   939 
       
   940     Actions can be grouped (i.e. treated as a single action for
       
   941     undo/redo) using beginEditBlock() and endEditBlock().
       
   942 
       
   943     Cursor movements are limited to valid cursor positions. In Latin
       
   944     writing this is between any two consecutive characters in the
       
   945     text, before the first character, or after the last character. In
       
   946     some other writing systems cursor movements are limited to
       
   947     "clusters" (e.g. a syllable in Devanagari, or a base letter plus
       
   948     diacritics).  Functions such as movePosition() and deleteChar()
       
   949     limit cursor movement to these valid positions.
       
   950 
       
   951     \sa \link richtext.html Rich Text Processing\endlink
       
   952 
       
   953 */
       
   954 
       
   955 /*!
       
   956     \enum QTextCursor::MoveOperation
       
   957 
       
   958     \value NoMove Keep the cursor where it is
       
   959 
       
   960     \value Start Move to the start of the document.
       
   961     \value StartOfLine Move to the start of the current line.
       
   962     \value StartOfBlock Move to the start of the current block.
       
   963     \value StartOfWord Move to the start of the current word.
       
   964     \value PreviousBlock Move to the start of the previous block.
       
   965     \value PreviousCharacter Move to the previous character.
       
   966     \value PreviousWord Move to the beginning of the previous word.
       
   967     \value Up Move up one line.
       
   968     \value Left Move left one character.
       
   969     \value WordLeft Move left one word.
       
   970 
       
   971     \value End Move to the end of the document.
       
   972     \value EndOfLine Move to the end of the current line.
       
   973     \value EndOfWord Move to the end of the current word.
       
   974     \value EndOfBlock Move to the end of the current block.
       
   975     \value NextBlock Move to the beginning of the next block.
       
   976     \value NextCharacter Move to the next character.
       
   977     \value NextWord Move to the next word.
       
   978     \value Down Move down one line.
       
   979     \value Right Move right one character.
       
   980     \value WordRight Move right one word.
       
   981 
       
   982     \value NextCell  Move to the beginning of the next table cell inside the
       
   983            current table. If the current cell is the last cell in the row, the
       
   984            cursor will move to the first cell in the next row.
       
   985     \value PreviousCell  Move to the beginning of the previous table cell
       
   986            inside the current table. If the current cell is the first cell in
       
   987            the row, the cursor will move to the last cell in the previous row.
       
   988     \value NextRow  Move to the first new cell of the next row in the current
       
   989            table.
       
   990     \value PreviousRow  Move to the last cell of the previous row in the
       
   991            current table.
       
   992 
       
   993     \sa movePosition()
       
   994 */
       
   995 
       
   996 /*!
       
   997     \enum QTextCursor::MoveMode
       
   998 
       
   999     \value MoveAnchor Moves the anchor to the same position as the cursor itself.
       
  1000     \value KeepAnchor Keeps the anchor where it is.
       
  1001 
       
  1002     If the anchor() is kept where it is and the position() is moved,
       
  1003     the text in between will be selected.
       
  1004 */
       
  1005 
       
  1006 /*!
       
  1007     \enum QTextCursor::SelectionType
       
  1008 
       
  1009     This enum describes the types of selection that can be applied with the
       
  1010     select() function.
       
  1011 
       
  1012     \value Document         Selects the entire document.
       
  1013     \value BlockUnderCursor Selects the block of text under the cursor.
       
  1014     \value LineUnderCursor  Selects the line of text under the cursor.
       
  1015     \value WordUnderCursor  Selects the word under the cursor. If the cursor
       
  1016            is not positioned within a string of selectable characters, no
       
  1017            text is selected.
       
  1018 */
       
  1019 
       
  1020 /*!
       
  1021     Constructs a null cursor.
       
  1022  */
       
  1023 QTextCursor::QTextCursor()
       
  1024     : d(0)
       
  1025 {
       
  1026 }
       
  1027 
       
  1028 /*!
       
  1029     Constructs a cursor pointing to the beginning of the \a document.
       
  1030  */
       
  1031 QTextCursor::QTextCursor(QTextDocument *document)
       
  1032     : d(new QTextCursorPrivate(document->docHandle()))
       
  1033 {
       
  1034 }
       
  1035 
       
  1036 /*!
       
  1037     Constructs a cursor pointing to the beginning of the \a frame.
       
  1038 */
       
  1039 QTextCursor::QTextCursor(QTextFrame *frame)
       
  1040     : d(new QTextCursorPrivate(frame->document()->docHandle()))
       
  1041 {
       
  1042     d->adjusted_anchor = d->anchor = d->position = frame->firstPosition();
       
  1043 }
       
  1044 
       
  1045 
       
  1046 /*!
       
  1047     Constructs a cursor pointing to the beginning of the \a block.
       
  1048 */
       
  1049 QTextCursor::QTextCursor(const QTextBlock &block)
       
  1050     : d(new QTextCursorPrivate(block.docHandle()))
       
  1051 {
       
  1052     d->adjusted_anchor = d->anchor = d->position = block.position();
       
  1053 }
       
  1054 
       
  1055 
       
  1056 /*!
       
  1057   \internal
       
  1058  */
       
  1059 QTextCursor::QTextCursor(QTextDocumentPrivate *p, int pos)
       
  1060     : d(new QTextCursorPrivate(p))
       
  1061 {
       
  1062     d->adjusted_anchor = d->anchor = d->position = pos;
       
  1063 
       
  1064     d->setX();
       
  1065 }
       
  1066 
       
  1067 /*!
       
  1068     \internal
       
  1069 */
       
  1070 QTextCursor::QTextCursor(QTextCursorPrivate *d)
       
  1071 {
       
  1072     Q_ASSERT(d);
       
  1073     this->d = d;
       
  1074 }
       
  1075 
       
  1076 /*!
       
  1077     Constructs a new cursor that is a copy of \a cursor.
       
  1078  */
       
  1079 QTextCursor::QTextCursor(const QTextCursor &cursor)
       
  1080 {
       
  1081     d = cursor.d;
       
  1082 }
       
  1083 
       
  1084 /*!
       
  1085     Makes a copy of \a cursor and assigns it to this QTextCursor. Note
       
  1086     that QTextCursor is an \l{Implicitly Shared Classes}{implicitly
       
  1087     shared} class.
       
  1088 
       
  1089  */
       
  1090 QTextCursor &QTextCursor::operator=(const QTextCursor &cursor)
       
  1091 {
       
  1092     d = cursor.d;
       
  1093     return *this;
       
  1094 }
       
  1095 
       
  1096 /*!
       
  1097     Destroys the QTextCursor.
       
  1098  */
       
  1099 QTextCursor::~QTextCursor()
       
  1100 {
       
  1101 }
       
  1102 
       
  1103 /*!
       
  1104     Returns true if the cursor is null; otherwise returns false. A null
       
  1105     cursor is created by the default constructor.
       
  1106  */
       
  1107 bool QTextCursor::isNull() const
       
  1108 {
       
  1109     return !d || !d->priv;
       
  1110 }
       
  1111 
       
  1112 /*!
       
  1113     Moves the cursor to the absolute position in the document specified by
       
  1114     \a pos using a \c MoveMode specified by \a m. The cursor is positioned
       
  1115     between characters.
       
  1116 
       
  1117     \sa position() movePosition() anchor()
       
  1118 */
       
  1119 void QTextCursor::setPosition(int pos, MoveMode m)
       
  1120 {
       
  1121     if (!d || !d->priv)
       
  1122         return;
       
  1123 
       
  1124     if (pos < 0 || pos >= d->priv->length()) {
       
  1125         qWarning("QTextCursor::setPosition: Position '%d' out of range", pos);
       
  1126         return;
       
  1127     }
       
  1128 
       
  1129     d->setPosition(pos);
       
  1130     if (m == MoveAnchor) {
       
  1131         d->anchor = pos;
       
  1132         d->adjusted_anchor = pos;
       
  1133     } else { // keep anchor
       
  1134         QTextCursor::MoveOperation op;
       
  1135         if (pos < d->anchor)
       
  1136             op = QTextCursor::Left;
       
  1137         else
       
  1138             op = QTextCursor::Right;
       
  1139         d->adjustCursor(op);
       
  1140     }
       
  1141     d->setX();
       
  1142 }
       
  1143 
       
  1144 /*!
       
  1145     Returns the absolute position of the cursor within the document.
       
  1146     The cursor is positioned between characters.
       
  1147 
       
  1148     \sa setPosition() movePosition() anchor()
       
  1149 */
       
  1150 int QTextCursor::position() const
       
  1151 {
       
  1152     if (!d || !d->priv)
       
  1153         return -1;
       
  1154     return d->position;
       
  1155 }
       
  1156 
       
  1157 /*!
       
  1158     Returns the anchor position; this is the same as position() unless
       
  1159     there is a selection in which case position() marks one end of the
       
  1160     selection and anchor() marks the other end. Just like the cursor
       
  1161     position, the anchor position is between characters.
       
  1162 
       
  1163     \sa position() setPosition() movePosition() selectionStart() selectionEnd()
       
  1164 */
       
  1165 int QTextCursor::anchor() const
       
  1166 {
       
  1167     if (!d || !d->priv)
       
  1168         return -1;
       
  1169     return d->anchor;
       
  1170 }
       
  1171 
       
  1172 /*!
       
  1173     \fn bool QTextCursor::movePosition(MoveOperation operation, MoveMode mode, int n)
       
  1174 
       
  1175     Moves the cursor by performing the given \a operation \a n times, using the specified
       
  1176     \a mode, and returns true if all operations were completed successfully; otherwise
       
  1177     returns false.
       
  1178 
       
  1179     For example, if this function is repeatedly used to seek to the end of the next
       
  1180     word, it will eventually fail when the end of the document is reached.
       
  1181 
       
  1182     By default, the move operation is performed once (\a n = 1).
       
  1183 
       
  1184     If \a mode is \c KeepAnchor, the cursor selects the text it moves
       
  1185     over. This is the same effect that the user achieves when they
       
  1186     hold down the Shift key and move the cursor with the cursor keys.
       
  1187 
       
  1188     \sa setVisualNavigation()
       
  1189 */
       
  1190 bool QTextCursor::movePosition(MoveOperation op, MoveMode mode, int n)
       
  1191 {
       
  1192     if (!d || !d->priv)
       
  1193         return false;
       
  1194     switch (op) {
       
  1195     case Start:
       
  1196     case StartOfLine:
       
  1197     case End:
       
  1198     case EndOfLine:
       
  1199         n = 1;
       
  1200         break;
       
  1201     default: break;
       
  1202     }
       
  1203 
       
  1204     int previousPosition = d->position;
       
  1205     for (; n > 0; --n) {
       
  1206         if (!d->movePosition(op, mode))
       
  1207             return false;
       
  1208     }
       
  1209 
       
  1210     if (d->visualNavigation && !d->block().isVisible()) {
       
  1211         QTextBlock b = d->block();
       
  1212         if (previousPosition < d->position) {
       
  1213             while (!b.next().isVisible())
       
  1214                 b = b.next();
       
  1215             d->setPosition(b.position() + b.length() - 1);
       
  1216         } else {
       
  1217             while (!b.previous().isVisible())
       
  1218                 b = b.previous();
       
  1219             d->setPosition(b.position());
       
  1220         }
       
  1221         if (mode == QTextCursor::MoveAnchor)
       
  1222             d->anchor = d->position;
       
  1223         while (d->movePosition(op, mode)
       
  1224                && !d->block().isVisible())
       
  1225             ;
       
  1226 
       
  1227     }
       
  1228     return true;
       
  1229 }
       
  1230 
       
  1231 /*!
       
  1232   \since 4.4
       
  1233 
       
  1234   Returns true if the cursor does visual navigation; otherwise
       
  1235   returns false.
       
  1236 
       
  1237   Visual navigation means skipping over hidden text pragraphs. The
       
  1238   default is false.
       
  1239 
       
  1240   \sa setVisualNavigation(), movePosition()
       
  1241  */
       
  1242 bool QTextCursor::visualNavigation() const
       
  1243 {
       
  1244     return d ? d->visualNavigation : false;
       
  1245 }
       
  1246 
       
  1247 /*!
       
  1248   \since 4.4
       
  1249 
       
  1250   Sets visual navigation to \a b.
       
  1251 
       
  1252   Visual navigation means skipping over hidden text pragraphs. The
       
  1253   default is false.
       
  1254 
       
  1255   \sa visualNavigation(), movePosition()
       
  1256  */
       
  1257 void QTextCursor::setVisualNavigation(bool b)
       
  1258 {
       
  1259     if (d)
       
  1260         d->visualNavigation = b;
       
  1261 }
       
  1262 
       
  1263 /*!
       
  1264     Inserts \a text at the current position, using the current
       
  1265     character format.
       
  1266 
       
  1267     If there is a selection, the selection is deleted and replaced by
       
  1268     \a text, for example:
       
  1269     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 0
       
  1270     This clears any existing selection, selects the word at the cursor
       
  1271     (i.e. from position() forward), and replaces the selection with
       
  1272     the phrase "Hello World".
       
  1273 
       
  1274     Any ASCII linefeed characters (\\n) in the inserted text are transformed
       
  1275     into unicode block separators, corresponding to insertBlock() calls.
       
  1276 
       
  1277     \sa charFormat() hasSelection()
       
  1278 */
       
  1279 void QTextCursor::insertText(const QString &text)
       
  1280 {
       
  1281     QTextCharFormat fmt = charFormat();
       
  1282     fmt.clearProperty(QTextFormat::ObjectType);
       
  1283     insertText(text, fmt);
       
  1284 }
       
  1285 
       
  1286 /*!
       
  1287     \fn void QTextCursor::insertText(const QString &text, const QTextCharFormat &format)
       
  1288     \overload
       
  1289 
       
  1290     Inserts \a text at the current position with the given \a format.
       
  1291 */
       
  1292 void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format)
       
  1293 {
       
  1294     if (!d || !d->priv)
       
  1295         return;
       
  1296 
       
  1297     Q_ASSERT(_format.isValid());
       
  1298 
       
  1299     QTextCharFormat format = _format;
       
  1300     format.clearProperty(QTextFormat::ObjectIndex);
       
  1301 
       
  1302     bool hasEditBlock = false;
       
  1303 
       
  1304     if (d->anchor != d->position) {
       
  1305         hasEditBlock = true;
       
  1306         d->priv->beginEditBlock();
       
  1307         d->remove();
       
  1308     }
       
  1309 
       
  1310     if (!text.isEmpty()) {
       
  1311         QTextFormatCollection *formats = d->priv->formatCollection();
       
  1312         int formatIdx = formats->indexForFormat(format);
       
  1313         Q_ASSERT(formats->format(formatIdx).isCharFormat());
       
  1314 
       
  1315         QTextBlockFormat blockFmt = blockFormat();
       
  1316 
       
  1317 
       
  1318         int textStart = d->priv->text.length();
       
  1319         int blockStart = 0;
       
  1320         d->priv->text += text;
       
  1321         int textEnd = d->priv->text.length();
       
  1322 
       
  1323         for (int i = 0; i < text.length(); ++i) {
       
  1324             QChar ch = text.at(i);
       
  1325 
       
  1326             const int blockEnd = i;
       
  1327 
       
  1328             if (ch == QLatin1Char('\r')
       
  1329                 && (i + 1) < text.length()
       
  1330                 && text.at(i + 1) == QLatin1Char('\n')) {
       
  1331                 ++i;
       
  1332                 ch = text.at(i);
       
  1333             }
       
  1334 
       
  1335             if (ch == QLatin1Char('\n')
       
  1336                 || ch == QChar::ParagraphSeparator
       
  1337                 || ch == QTextBeginningOfFrame
       
  1338                 || ch == QTextEndOfFrame
       
  1339                 || ch == QLatin1Char('\r')) {
       
  1340 
       
  1341                 if (!hasEditBlock) {
       
  1342                     hasEditBlock = true;
       
  1343                     d->priv->beginEditBlock();
       
  1344                 }
       
  1345 
       
  1346                 if (blockEnd > blockStart)
       
  1347                     d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx);
       
  1348 
       
  1349                 d->insertBlock(blockFmt, format);
       
  1350                 blockStart = i + 1;
       
  1351             }
       
  1352         }
       
  1353         if (textStart + blockStart < textEnd)
       
  1354             d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx);
       
  1355     }
       
  1356     if (hasEditBlock)
       
  1357         d->priv->endEditBlock();
       
  1358     d->setX();
       
  1359 }
       
  1360 
       
  1361 /*!
       
  1362     If there is no selected text, deletes the character \e at the
       
  1363     current cursor position; otherwise deletes the selected text.
       
  1364 
       
  1365     \sa deletePreviousChar() hasSelection() clearSelection()
       
  1366 */
       
  1367 void QTextCursor::deleteChar()
       
  1368 {
       
  1369     if (!d || !d->priv)
       
  1370         return;
       
  1371 
       
  1372     if (d->position != d->anchor) {
       
  1373         removeSelectedText();
       
  1374         return;
       
  1375     }
       
  1376 
       
  1377     if (!d->canDelete(d->position))
       
  1378         return;
       
  1379     d->adjusted_anchor = d->anchor =
       
  1380                          d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters);
       
  1381     d->remove();
       
  1382     d->setX();
       
  1383 }
       
  1384 
       
  1385 /*!
       
  1386     If there is no selected text, deletes the character \e before the
       
  1387     current cursor position; otherwise deletes the selected text.
       
  1388 
       
  1389     \sa deleteChar() hasSelection() clearSelection()
       
  1390 */
       
  1391 void QTextCursor::deletePreviousChar()
       
  1392 {
       
  1393     if (!d || !d->priv)
       
  1394         return;
       
  1395     
       
  1396     if (d->position != d->anchor) {
       
  1397         removeSelectedText();
       
  1398         return;
       
  1399     }
       
  1400     
       
  1401     if (d->anchor < 1 || !d->canDelete(d->anchor-1))
       
  1402         return;
       
  1403     d->anchor--;
       
  1404     
       
  1405     QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
       
  1406     const QTextFragmentData * const frag = fragIt.value();
       
  1407     int fpos = fragIt.position();
       
  1408     QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition);
       
  1409     if (d->anchor > fpos && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
       
  1410         // second half of a surrogate, check if we have the first half as well,
       
  1411         // if yes delete both at once
       
  1412         uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition);
       
  1413         if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
       
  1414             --d->anchor;
       
  1415     }
       
  1416     
       
  1417     d->adjusted_anchor = d->anchor;
       
  1418     d->remove();
       
  1419     d->setX();
       
  1420 }
       
  1421 
       
  1422 /*!
       
  1423     Selects text in the document according to the given \a selection.
       
  1424 */
       
  1425 void QTextCursor::select(SelectionType selection)
       
  1426 {
       
  1427     if (!d || !d->priv)
       
  1428         return;
       
  1429 
       
  1430     clearSelection();
       
  1431 
       
  1432     const QTextBlock block = d->block();
       
  1433 
       
  1434     switch (selection) {
       
  1435         case LineUnderCursor:
       
  1436             movePosition(StartOfLine);
       
  1437             movePosition(EndOfLine, KeepAnchor);
       
  1438             break;
       
  1439         case WordUnderCursor:
       
  1440             movePosition(StartOfWord);
       
  1441             movePosition(EndOfWord, KeepAnchor);
       
  1442             break;
       
  1443         case BlockUnderCursor:
       
  1444             if (block.length() == 1) // no content
       
  1445                 break;
       
  1446             movePosition(StartOfBlock);
       
  1447             // also select the paragraph separator
       
  1448             if (movePosition(PreviousBlock)) {
       
  1449                 movePosition(EndOfBlock);
       
  1450                 movePosition(NextBlock, KeepAnchor);
       
  1451             }
       
  1452             movePosition(EndOfBlock, KeepAnchor);
       
  1453             break;
       
  1454         case Document:
       
  1455             movePosition(Start);
       
  1456             movePosition(End, KeepAnchor);
       
  1457             break;
       
  1458     }
       
  1459 }
       
  1460 
       
  1461 /*!
       
  1462     Returns true if the cursor contains a selection; otherwise returns false.
       
  1463 */
       
  1464 bool QTextCursor::hasSelection() const
       
  1465 {
       
  1466     return !!d && d->position != d->anchor;
       
  1467 }
       
  1468 
       
  1469 
       
  1470 /*!
       
  1471     Returns true if the cursor contains a selection that is not simply a
       
  1472     range from selectionStart() to selectionEnd(); otherwise returns false.
       
  1473 
       
  1474     Complex selections are ones that span at least two cells in a table;
       
  1475     their extent is specified by selectedTableCells().
       
  1476 */
       
  1477 bool QTextCursor::hasComplexSelection() const
       
  1478 {
       
  1479     if (!d)
       
  1480         return false;
       
  1481 
       
  1482     return d->complexSelectionTable() != 0;
       
  1483 }
       
  1484 
       
  1485 /*!
       
  1486     If the selection spans over table cells, \a firstRow is populated
       
  1487     with the number of the first row in the selection, \a firstColumn
       
  1488     with the number of the first column in the selection, and \a
       
  1489     numRows and \a numColumns with the number of rows and columns in
       
  1490     the selection. If the selection does not span any table cells the
       
  1491     results are harmless but undefined.
       
  1492 */
       
  1493 void QTextCursor::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
       
  1494 {
       
  1495     *firstRow = -1;
       
  1496     *firstColumn = -1;
       
  1497     *numRows = -1;
       
  1498     *numColumns = -1;
       
  1499 
       
  1500     if (!d || d->position == d->anchor)
       
  1501         return;
       
  1502 
       
  1503     d->selectedTableCells(firstRow, numRows, firstColumn, numColumns);
       
  1504 }
       
  1505 
       
  1506 
       
  1507 /*!
       
  1508     Clears the current selection by setting the anchor to the cursor position.
       
  1509 
       
  1510     Note that it does \bold{not} delete the text of the selection.
       
  1511 
       
  1512     \sa removeSelectedText() hasSelection()
       
  1513 */
       
  1514 void QTextCursor::clearSelection()
       
  1515 {
       
  1516     if (!d)
       
  1517         return;
       
  1518     d->adjusted_anchor = d->anchor = d->position;
       
  1519     d->currentCharFormat = -1;
       
  1520 }
       
  1521 
       
  1522 /*!
       
  1523     If there is a selection, its content is deleted; otherwise does
       
  1524     nothing.
       
  1525 
       
  1526     \sa hasSelection()
       
  1527 */
       
  1528 void QTextCursor::removeSelectedText()
       
  1529 {
       
  1530     if (!d || !d->priv || d->position == d->anchor)
       
  1531         return;
       
  1532 
       
  1533     d->priv->beginEditBlock();
       
  1534     d->remove();
       
  1535     d->priv->endEditBlock();
       
  1536     d->setX();
       
  1537 }
       
  1538 
       
  1539 /*!
       
  1540     Returns the start of the selection or position() if the
       
  1541     cursor doesn't have a selection.
       
  1542 
       
  1543     \sa selectionEnd() position() anchor()
       
  1544 */
       
  1545 int QTextCursor::selectionStart() const
       
  1546 {
       
  1547     if (!d || !d->priv)
       
  1548         return -1;
       
  1549     return qMin(d->position, d->adjusted_anchor);
       
  1550 }
       
  1551 
       
  1552 /*!
       
  1553     Returns the end of the selection or position() if the cursor
       
  1554     doesn't have a selection.
       
  1555 
       
  1556     \sa selectionStart() position() anchor()
       
  1557 */
       
  1558 int QTextCursor::selectionEnd() const
       
  1559 {
       
  1560     if (!d || !d->priv)
       
  1561         return -1;
       
  1562     return qMax(d->position, d->adjusted_anchor);
       
  1563 }
       
  1564 
       
  1565 static void getText(QString &text, QTextDocumentPrivate *priv, const QString &docText, int pos, int end)
       
  1566 {
       
  1567     while (pos < end) {
       
  1568         QTextDocumentPrivate::FragmentIterator fragIt = priv->find(pos);
       
  1569         const QTextFragmentData * const frag = fragIt.value();
       
  1570 
       
  1571         const int offsetInFragment = qMax(0, pos - fragIt.position());
       
  1572         const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
       
  1573 
       
  1574         text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
       
  1575         pos += len;
       
  1576     }
       
  1577 }
       
  1578 
       
  1579 /*!
       
  1580     Returns the current selection's text (which may be empty). This
       
  1581     only returns the text, with no rich text formatting information.
       
  1582     If you want a document fragment (i.e. formatted rich text) use
       
  1583     selection() instead.
       
  1584 
       
  1585     \note If the selection obtained from an editor spans a line break,
       
  1586     the text will contain a Unicode U+2029 paragraph separator character
       
  1587     instead of a newline \c{\n} character. Use QString::replace() to
       
  1588     replace these characters with newlines.
       
  1589 */
       
  1590 QString QTextCursor::selectedText() const
       
  1591 {
       
  1592     if (!d || !d->priv || d->position == d->anchor)
       
  1593         return QString();
       
  1594 
       
  1595     const QString docText = d->priv->buffer();
       
  1596     QString text;
       
  1597 
       
  1598     QTextTable *table = d->complexSelectionTable();
       
  1599     if (table) {
       
  1600         int row_start, col_start, num_rows, num_cols;
       
  1601         selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
       
  1602 
       
  1603         Q_ASSERT(row_start != -1);
       
  1604         for (int r = row_start; r < row_start + num_rows; ++r) {
       
  1605             for (int c = col_start; c < col_start + num_cols; ++c) {
       
  1606                 QTextTableCell cell = table->cellAt(r, c);
       
  1607                 int rspan = cell.rowSpan();
       
  1608                 int cspan = cell.columnSpan();
       
  1609                 if (rspan != 1) {
       
  1610                     int cr = cell.row();
       
  1611                     if (cr != r)
       
  1612                         continue;
       
  1613                 }
       
  1614                 if (cspan != 1) {
       
  1615                     int cc = cell.column();
       
  1616                     if (cc != c)
       
  1617                         continue;
       
  1618                 }
       
  1619 
       
  1620                 getText(text, d->priv, docText, cell.firstPosition(), cell.lastPosition());
       
  1621             }
       
  1622         }
       
  1623     } else {
       
  1624         getText(text, d->priv, docText, selectionStart(), selectionEnd());
       
  1625     }
       
  1626 
       
  1627     return text;
       
  1628 }
       
  1629 
       
  1630 /*!
       
  1631     Returns the current selection (which may be empty) with all its
       
  1632     formatting information. If you just want the selected text (i.e.
       
  1633     plain text) use selectedText() instead.
       
  1634 
       
  1635     \note Unlike QTextDocumentFragment::toPlainText(),
       
  1636     selectedText() may include special unicode characters such as
       
  1637     QChar::ParagraphSeparator.
       
  1638 
       
  1639     \sa QTextDocumentFragment::toPlainText()
       
  1640 */
       
  1641 QTextDocumentFragment QTextCursor::selection() const
       
  1642 {
       
  1643     return QTextDocumentFragment(*this);
       
  1644 }
       
  1645 
       
  1646 /*!
       
  1647     Returns the block that contains the cursor.
       
  1648 */
       
  1649 QTextBlock QTextCursor::block() const
       
  1650 {
       
  1651     if (!d || !d->priv)
       
  1652         return QTextBlock();
       
  1653     return d->block();
       
  1654 }
       
  1655 
       
  1656 /*!
       
  1657     Returns the block format of the block the cursor is in.
       
  1658 
       
  1659     \sa setBlockFormat() charFormat()
       
  1660  */
       
  1661 QTextBlockFormat QTextCursor::blockFormat() const
       
  1662 {
       
  1663     if (!d || !d->priv)
       
  1664         return QTextBlockFormat();
       
  1665 
       
  1666     return d->block().blockFormat();
       
  1667 }
       
  1668 
       
  1669 /*!
       
  1670     Sets the block format of the current block (or all blocks that
       
  1671     are contained in the selection) to \a format.
       
  1672 
       
  1673     \sa blockFormat(), mergeBlockFormat()
       
  1674 */
       
  1675 void QTextCursor::setBlockFormat(const QTextBlockFormat &format)
       
  1676 {
       
  1677     if (!d || !d->priv)
       
  1678         return;
       
  1679 
       
  1680     d->setBlockFormat(format, QTextDocumentPrivate::SetFormat);
       
  1681 }
       
  1682 
       
  1683 /*!
       
  1684     Modifies the block format of the current block (or all blocks that
       
  1685     are contained in the selection) with the block format specified by
       
  1686     \a modifier.
       
  1687 
       
  1688     \sa setBlockFormat(), blockFormat()
       
  1689 */
       
  1690 void QTextCursor::mergeBlockFormat(const QTextBlockFormat &modifier)
       
  1691 {
       
  1692     if (!d || !d->priv)
       
  1693         return;
       
  1694 
       
  1695     d->setBlockFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1696 }
       
  1697 
       
  1698 /*!
       
  1699     Returns the block character format of the block the cursor is in.
       
  1700 
       
  1701     The block char format is the format used when inserting text at the
       
  1702     beginning of an empty block.
       
  1703 
       
  1704     \sa setBlockCharFormat()
       
  1705  */
       
  1706 QTextCharFormat QTextCursor::blockCharFormat() const
       
  1707 {
       
  1708     if (!d || !d->priv)
       
  1709         return QTextCharFormat();
       
  1710 
       
  1711     return d->block().charFormat();
       
  1712 }
       
  1713 
       
  1714 /*!
       
  1715     Sets the block char format of the current block (or all blocks that
       
  1716     are contained in the selection) to \a format.
       
  1717 
       
  1718     \sa blockCharFormat()
       
  1719 */
       
  1720 void QTextCursor::setBlockCharFormat(const QTextCharFormat &format)
       
  1721 {
       
  1722     if (!d || !d->priv)
       
  1723         return;
       
  1724 
       
  1725     d->setBlockCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
       
  1726 }
       
  1727 
       
  1728 /*!
       
  1729     Modifies the block char format of the current block (or all blocks that
       
  1730     are contained in the selection) with the block format specified by
       
  1731     \a modifier.
       
  1732 
       
  1733     \sa setBlockCharFormat()
       
  1734 */
       
  1735 void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier)
       
  1736 {
       
  1737     if (!d || !d->priv)
       
  1738         return;
       
  1739 
       
  1740     d->setBlockCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1741 }
       
  1742 
       
  1743 /*!
       
  1744     Returns the format of the character immediately before the cursor
       
  1745     position(). If the cursor is positioned at the beginning of a text
       
  1746     block that is not empty then the format of the character
       
  1747     immediately after the cursor is returned.
       
  1748 
       
  1749     \sa insertText(), blockFormat()
       
  1750  */
       
  1751 QTextCharFormat QTextCursor::charFormat() const
       
  1752 {
       
  1753     if (!d || !d->priv)
       
  1754         return QTextCharFormat();
       
  1755 
       
  1756     int idx = d->currentCharFormat;
       
  1757     if (idx == -1) {
       
  1758         QTextBlock block = d->block();
       
  1759 
       
  1760         int pos;
       
  1761         if (d->position == block.position()
       
  1762             && block.length() > 1)
       
  1763             pos = d->position;
       
  1764         else
       
  1765             pos = d->position - 1;
       
  1766 
       
  1767         if (pos == -1) {
       
  1768             idx = d->priv->blockCharFormatIndex(d->priv->blockMap().firstNode());
       
  1769         } else {
       
  1770             Q_ASSERT(pos >= 0 && pos < d->priv->length());
       
  1771 
       
  1772             QTextDocumentPrivate::FragmentIterator it = d->priv->find(pos);
       
  1773             Q_ASSERT(!it.atEnd());
       
  1774             idx = it.value()->format;
       
  1775         }
       
  1776     }
       
  1777 
       
  1778     QTextCharFormat cfmt = d->priv->formatCollection()->charFormat(idx);
       
  1779     cfmt.clearProperty(QTextFormat::ObjectIndex);
       
  1780 
       
  1781     Q_ASSERT(cfmt.isValid());
       
  1782     return cfmt;
       
  1783 }
       
  1784 
       
  1785 /*!
       
  1786     Sets the cursor's current character format to the given \a
       
  1787     format. If the cursor has a selection, the given \a format is
       
  1788     applied to the current selection.
       
  1789 
       
  1790     \sa hasSelection(), mergeCharFormat()
       
  1791 */
       
  1792 void QTextCursor::setCharFormat(const QTextCharFormat &format)
       
  1793 {
       
  1794     if (!d || !d->priv)
       
  1795         return;
       
  1796     if (d->position == d->anchor) {
       
  1797         d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
       
  1798         return;
       
  1799     }
       
  1800     d->setCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
       
  1801 }
       
  1802 
       
  1803 /*!
       
  1804     Merges the cursor's current character format with the properties
       
  1805     described by format \a modifier. If the cursor has a selection,
       
  1806     this function applies all the properties set in \a modifier to all
       
  1807     the character formats that are part of the selection.
       
  1808 
       
  1809     \sa hasSelection(), setCharFormat()
       
  1810 */
       
  1811 void QTextCursor::mergeCharFormat(const QTextCharFormat &modifier)
       
  1812 {
       
  1813     if (!d || !d->priv)
       
  1814         return;
       
  1815     if (d->position == d->anchor) {
       
  1816         QTextCharFormat format = charFormat();
       
  1817         format.merge(modifier);
       
  1818         d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
       
  1819         return;
       
  1820     }
       
  1821 
       
  1822     d->setCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1823 }
       
  1824 
       
  1825 /*!
       
  1826     Returns true if the cursor is at the start of a block; otherwise
       
  1827     returns false.
       
  1828 
       
  1829     \sa atBlockEnd(), atStart()
       
  1830 */
       
  1831 bool QTextCursor::atBlockStart() const
       
  1832 {
       
  1833     if (!d || !d->priv)
       
  1834         return false;
       
  1835 
       
  1836     return d->position == d->block().position();
       
  1837 }
       
  1838 
       
  1839 /*!
       
  1840     Returns true if the cursor is at the end of a block; otherwise
       
  1841     returns false.
       
  1842 
       
  1843     \sa atBlockStart(), atEnd()
       
  1844 */
       
  1845 bool QTextCursor::atBlockEnd() const
       
  1846 {
       
  1847     if (!d || !d->priv)
       
  1848         return false;
       
  1849 
       
  1850     return d->position == d->block().position() + d->block().length() - 1;
       
  1851 }
       
  1852 
       
  1853 /*!
       
  1854     Returns true if the cursor is at the start of the document;
       
  1855     otherwise returns false.
       
  1856 
       
  1857     \sa atBlockStart(), atEnd()
       
  1858 */
       
  1859 bool QTextCursor::atStart() const
       
  1860 {
       
  1861     if (!d || !d->priv)
       
  1862         return false;
       
  1863 
       
  1864     return d->position == 0;
       
  1865 }
       
  1866 
       
  1867 /*!
       
  1868     \since 4.6
       
  1869 
       
  1870     Returns true if the cursor is at the end of the document;
       
  1871     otherwise returns false.
       
  1872 
       
  1873     \sa atStart(), atBlockEnd()
       
  1874 */
       
  1875 bool QTextCursor::atEnd() const
       
  1876 {
       
  1877     if (!d || !d->priv)
       
  1878         return false;
       
  1879 
       
  1880     return d->position == d->priv->length() - 1;
       
  1881 }
       
  1882 
       
  1883 /*!
       
  1884     Inserts a new empty block at the cursor position() with the
       
  1885     current blockFormat() and charFormat().
       
  1886 
       
  1887     \sa setBlockFormat()
       
  1888 */
       
  1889 void QTextCursor::insertBlock()
       
  1890 {
       
  1891     insertBlock(blockFormat());
       
  1892 }
       
  1893 
       
  1894 /*!
       
  1895     \overload
       
  1896 
       
  1897     Inserts a new empty block at the cursor position() with block
       
  1898     format \a format and the current charFormat() as block char format.
       
  1899 
       
  1900     \sa setBlockFormat()
       
  1901 */
       
  1902 void QTextCursor::insertBlock(const QTextBlockFormat &format)
       
  1903 {
       
  1904     QTextCharFormat charFmt = charFormat();
       
  1905     charFmt.clearProperty(QTextFormat::ObjectType);
       
  1906     insertBlock(format, charFmt);
       
  1907 }
       
  1908 
       
  1909 /*!
       
  1910     \fn void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
       
  1911     \overload
       
  1912 
       
  1913     Inserts a new empty block at the cursor position() with block
       
  1914     format \a format and \a charFormat as block char format.
       
  1915 
       
  1916     \sa setBlockFormat()
       
  1917 */
       
  1918 void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &_charFormat)
       
  1919 {
       
  1920     if (!d || !d->priv)
       
  1921         return;
       
  1922 
       
  1923     QTextCharFormat charFormat = _charFormat;
       
  1924     charFormat.clearProperty(QTextFormat::ObjectIndex);
       
  1925 
       
  1926     d->priv->beginEditBlock();
       
  1927     d->remove();
       
  1928     d->insertBlock(format, charFormat);
       
  1929     d->priv->endEditBlock();
       
  1930     d->setX();
       
  1931 }
       
  1932 
       
  1933 /*!
       
  1934     Inserts a new block at the current position and makes it the first
       
  1935     list item of a newly created list with the given \a format. Returns
       
  1936     the created list.
       
  1937 
       
  1938     \sa currentList() createList() insertBlock()
       
  1939  */
       
  1940 QTextList *QTextCursor::insertList(const QTextListFormat &format)
       
  1941 {
       
  1942     insertBlock();
       
  1943     return createList(format);
       
  1944 }
       
  1945 
       
  1946 /*!
       
  1947     \overload
       
  1948 
       
  1949     Inserts a new block at the current position and makes it the first
       
  1950     list item of a newly created list with the given \a style. Returns
       
  1951     the created list.
       
  1952 
       
  1953     \sa currentList(), createList(), insertBlock()
       
  1954  */
       
  1955 QTextList *QTextCursor::insertList(QTextListFormat::Style style)
       
  1956 {
       
  1957     insertBlock();
       
  1958     return createList(style);
       
  1959 }
       
  1960 
       
  1961 /*!
       
  1962     Creates and returns a new list with the given \a format, and makes the
       
  1963     current paragraph the cursor is in the first list item.
       
  1964 
       
  1965     \sa insertList() currentList()
       
  1966  */
       
  1967 QTextList *QTextCursor::createList(const QTextListFormat &format)
       
  1968 {
       
  1969     if (!d || !d->priv)
       
  1970         return 0;
       
  1971 
       
  1972     QTextList *list = static_cast<QTextList *>(d->priv->createObject(format));
       
  1973     QTextBlockFormat modifier;
       
  1974     modifier.setObjectIndex(list->objectIndex());
       
  1975     mergeBlockFormat(modifier);
       
  1976     return list;
       
  1977 }
       
  1978 
       
  1979 /*!
       
  1980     \overload
       
  1981 
       
  1982     Creates and returns a new list with the given \a style, making the
       
  1983     cursor's current paragraph the first list item.
       
  1984 
       
  1985     The style to be used is defined by the QTextListFormat::Style enum.
       
  1986 
       
  1987     \sa insertList() currentList()
       
  1988  */
       
  1989 QTextList *QTextCursor::createList(QTextListFormat::Style style)
       
  1990 {
       
  1991     QTextListFormat fmt;
       
  1992     fmt.setStyle(style);
       
  1993     return createList(fmt);
       
  1994 }
       
  1995 
       
  1996 /*!
       
  1997     Returns the current list if the cursor position() is inside a
       
  1998     block that is part of a list; otherwise returns 0.
       
  1999 
       
  2000     \sa insertList() createList()
       
  2001  */
       
  2002 QTextList *QTextCursor::currentList() const
       
  2003 {
       
  2004     if (!d || !d->priv)
       
  2005         return 0;
       
  2006 
       
  2007     QTextBlockFormat b = blockFormat();
       
  2008     QTextObject *o = d->priv->objectForFormat(b);
       
  2009     return qobject_cast<QTextList *>(o);
       
  2010 }
       
  2011 
       
  2012 /*!
       
  2013     \fn QTextTable *QTextCursor::insertTable(int rows, int columns)
       
  2014 
       
  2015     \overload
       
  2016 
       
  2017     Creates a new table with the given number of \a rows and \a columns,
       
  2018     inserts it at the current cursor position() in the document, and returns
       
  2019     the table object. The cursor is moved to the beginning of the first cell.
       
  2020 
       
  2021     There must be at least one row and one column in the table.
       
  2022 
       
  2023     \sa currentTable()
       
  2024  */
       
  2025 QTextTable *QTextCursor::insertTable(int rows, int cols)
       
  2026 {
       
  2027     return insertTable(rows, cols, QTextTableFormat());
       
  2028 }
       
  2029 
       
  2030 /*!
       
  2031     \fn QTextTable *QTextCursor::insertTable(int rows, int columns, const QTextTableFormat &format)
       
  2032 
       
  2033     Creates a new table with the given number of \a rows and \a columns
       
  2034     in the specified \a format, inserts it at the current cursor position()
       
  2035     in the document, and returns the table object. The cursor is moved to
       
  2036     the beginning of the first cell.
       
  2037 
       
  2038     There must be at least one row and one column in the table.
       
  2039 
       
  2040     \sa currentTable()
       
  2041 */
       
  2042 QTextTable *QTextCursor::insertTable(int rows, int cols, const QTextTableFormat &format)
       
  2043 {
       
  2044     if(!d || !d->priv || rows == 0 || cols == 0)
       
  2045         return 0;
       
  2046 
       
  2047     int pos = d->position;
       
  2048     QTextTable *t = QTextTablePrivate::createTable(d->priv, d->position, rows, cols, format);
       
  2049     d->setPosition(pos+1);
       
  2050     // ##### what should we do if we have a selection?
       
  2051     d->anchor = d->position;
       
  2052     d->adjusted_anchor = d->anchor;
       
  2053     return t;
       
  2054 }
       
  2055 
       
  2056 /*!
       
  2057     Returns a pointer to the current table if the cursor position()
       
  2058     is inside a block that is part of a table; otherwise returns 0.
       
  2059 
       
  2060     \sa insertTable()
       
  2061 */
       
  2062 QTextTable *QTextCursor::currentTable() const
       
  2063 {
       
  2064     if(!d || !d->priv)
       
  2065         return 0;
       
  2066 
       
  2067     QTextFrame *frame = d->priv->frameAt(d->position);
       
  2068     while (frame) {
       
  2069         QTextTable *table = qobject_cast<QTextTable *>(frame);
       
  2070         if (table)
       
  2071             return table;
       
  2072         frame = frame->parentFrame();
       
  2073     }
       
  2074     return 0;
       
  2075 }
       
  2076 
       
  2077 /*!
       
  2078     Inserts a frame with the given \a format at the current cursor position(),
       
  2079     moves the cursor position() inside the frame, and returns the frame.
       
  2080 
       
  2081     If the cursor holds a selection, the whole selection is moved inside the
       
  2082     frame.
       
  2083 
       
  2084     \sa hasSelection()
       
  2085 */
       
  2086 QTextFrame *QTextCursor::insertFrame(const QTextFrameFormat &format)
       
  2087 {
       
  2088     if (!d || !d->priv)
       
  2089         return 0;
       
  2090 
       
  2091     return d->priv->insertFrame(selectionStart(), selectionEnd(), format);
       
  2092 }
       
  2093 
       
  2094 /*!
       
  2095     Returns a pointer to the current frame. Returns 0 if the cursor is invalid.
       
  2096 
       
  2097     \sa insertFrame()
       
  2098 */
       
  2099 QTextFrame *QTextCursor::currentFrame() const
       
  2100 {
       
  2101     if(!d || !d->priv)
       
  2102         return 0;
       
  2103 
       
  2104     return d->priv->frameAt(d->position);
       
  2105 }
       
  2106 
       
  2107 
       
  2108 /*!
       
  2109     Inserts the text \a fragment at the current position().
       
  2110 */
       
  2111 void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
       
  2112 {
       
  2113     if (!d || !d->priv || fragment.isEmpty())
       
  2114         return;
       
  2115 
       
  2116     d->priv->beginEditBlock();
       
  2117     d->remove();
       
  2118     fragment.d->insert(*this);
       
  2119     d->priv->endEditBlock();
       
  2120 
       
  2121     if (fragment.d && fragment.d->doc)
       
  2122         d->priv->mergeCachedResources(fragment.d->doc->docHandle());
       
  2123 }
       
  2124 
       
  2125 /*!
       
  2126     \since 4.2
       
  2127     Inserts the text \a html at the current position(). The text is interpreted as
       
  2128     HTML.
       
  2129 
       
  2130     \note When using this function with a style sheet, the style sheet will
       
  2131     only apply to the current block in the document. In order to apply a style
       
  2132     sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
       
  2133     instead.
       
  2134 */
       
  2135 
       
  2136 #ifndef QT_NO_TEXTHTMLPARSER
       
  2137 
       
  2138 void QTextCursor::insertHtml(const QString &html)
       
  2139 {
       
  2140     if (!d || !d->priv)
       
  2141         return;
       
  2142     QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html, d->priv->document());
       
  2143     insertFragment(fragment);
       
  2144 }
       
  2145 
       
  2146 #endif // QT_NO_TEXTHTMLPARSER
       
  2147 
       
  2148 /*!
       
  2149     \overload
       
  2150     \since 4.2
       
  2151 
       
  2152     Inserts the image defined by the given \a format at the cursor's current position
       
  2153     with the specified \a alignment.
       
  2154 
       
  2155     \sa position()
       
  2156 */
       
  2157 void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
       
  2158 {
       
  2159     if (!d || !d->priv)
       
  2160         return;
       
  2161 
       
  2162     QTextFrameFormat ffmt;
       
  2163     ffmt.setPosition(alignment);
       
  2164     QTextObject *obj = d->priv->createObject(ffmt);
       
  2165 
       
  2166     QTextImageFormat fmt = format;
       
  2167     fmt.setObjectIndex(obj->objectIndex());
       
  2168 
       
  2169     d->priv->beginEditBlock();
       
  2170     d->remove();
       
  2171     const int idx = d->priv->formatCollection()->indexForFormat(fmt);
       
  2172     d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
       
  2173     d->priv->endEditBlock();
       
  2174 }
       
  2175 
       
  2176 /*!
       
  2177     Inserts the image defined by \a format at the current position().
       
  2178 */
       
  2179 void QTextCursor::insertImage(const QTextImageFormat &format)
       
  2180 {
       
  2181     insertText(QString(QChar::ObjectReplacementCharacter), format);
       
  2182 }
       
  2183 
       
  2184 /*!
       
  2185     \overload
       
  2186 
       
  2187     Convenience method for inserting the image with the given \a name at the
       
  2188     current position().
       
  2189 
       
  2190     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 1
       
  2191 */
       
  2192 void QTextCursor::insertImage(const QString &name)
       
  2193 {
       
  2194     QTextImageFormat format;
       
  2195     format.setName(name);
       
  2196     insertImage(format);
       
  2197 }
       
  2198 
       
  2199 /*!
       
  2200     \since 4.5
       
  2201     \overload
       
  2202 
       
  2203     Convenience function for inserting the given \a image with an optional
       
  2204     \a name at the current position().
       
  2205 */
       
  2206 void QTextCursor::insertImage(const QImage &image, const QString &name)
       
  2207 {
       
  2208     if (image.isNull()) {
       
  2209         qWarning("QTextCursor::insertImage: attempt to add an invalid image");
       
  2210         return;
       
  2211     }
       
  2212     QString imageName = name;
       
  2213     if (name.isEmpty())
       
  2214         imageName = QString::number(image.serialNumber());
       
  2215     d->priv->document()->addResource(QTextDocument::ImageResource, QUrl(imageName), image);
       
  2216     QTextImageFormat format;
       
  2217     format.setName(imageName);
       
  2218     insertImage(format);
       
  2219 }
       
  2220 
       
  2221 /*!
       
  2222     \fn bool QTextCursor::operator!=(const QTextCursor &other) const
       
  2223 
       
  2224     Returns true if the \a other cursor is at a different position in
       
  2225     the document as this cursor; otherwise returns false.
       
  2226 */
       
  2227 bool QTextCursor::operator!=(const QTextCursor &rhs) const
       
  2228 {
       
  2229     return !operator==(rhs);
       
  2230 }
       
  2231 
       
  2232 /*!
       
  2233     \fn bool QTextCursor::operator<(const QTextCursor &other) const
       
  2234 
       
  2235     Returns true if the \a other cursor is positioned later in the
       
  2236     document than this cursor; otherwise returns false.
       
  2237 */
       
  2238 bool QTextCursor::operator<(const QTextCursor &rhs) const
       
  2239 {
       
  2240     if (!d)
       
  2241         return !!rhs.d;
       
  2242 
       
  2243     if (!rhs.d)
       
  2244         return false;
       
  2245 
       
  2246     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<", "cannot compare cursors attached to different documents");
       
  2247 
       
  2248     return d->position < rhs.d->position;
       
  2249 }
       
  2250 
       
  2251 /*!
       
  2252     \fn bool QTextCursor::operator<=(const QTextCursor &other) const
       
  2253 
       
  2254     Returns true if the \a other cursor is positioned later or at the
       
  2255     same position in the document as this cursor; otherwise returns
       
  2256     false.
       
  2257 */
       
  2258 bool QTextCursor::operator<=(const QTextCursor &rhs) const
       
  2259 {
       
  2260     if (!d)
       
  2261         return true;
       
  2262 
       
  2263     if (!rhs.d)
       
  2264         return false;
       
  2265 
       
  2266     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<=", "cannot compare cursors attached to different documents");
       
  2267 
       
  2268     return d->position <= rhs.d->position;
       
  2269 }
       
  2270 
       
  2271 /*!
       
  2272     \fn bool QTextCursor::operator==(const QTextCursor &other) const
       
  2273 
       
  2274     Returns true if the \a other cursor is at the same position in the
       
  2275     document as this cursor; otherwise returns false.
       
  2276 */
       
  2277 bool QTextCursor::operator==(const QTextCursor &rhs) const
       
  2278 {
       
  2279     if (!d)
       
  2280         return !rhs.d;
       
  2281 
       
  2282     if (!rhs.d)
       
  2283         return false;
       
  2284 
       
  2285     return d->position == rhs.d->position && d->priv == rhs.d->priv;
       
  2286 }
       
  2287 
       
  2288 /*!
       
  2289     \fn bool QTextCursor::operator>=(const QTextCursor &other) const
       
  2290 
       
  2291     Returns true if the \a other cursor is positioned earlier or at the
       
  2292     same position in the document as this cursor; otherwise returns
       
  2293     false.
       
  2294 */
       
  2295 bool QTextCursor::operator>=(const QTextCursor &rhs) const
       
  2296 {
       
  2297     if (!d)
       
  2298         return false;
       
  2299 
       
  2300     if (!rhs.d)
       
  2301         return true;
       
  2302 
       
  2303     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>=", "cannot compare cursors attached to different documents");
       
  2304 
       
  2305     return d->position >= rhs.d->position;
       
  2306 }
       
  2307 
       
  2308 /*!
       
  2309     \fn bool QTextCursor::operator>(const QTextCursor &other) const
       
  2310 
       
  2311     Returns true if the \a other cursor is positioned earlier in the
       
  2312     document than this cursor; otherwise returns false.
       
  2313 */
       
  2314 bool QTextCursor::operator>(const QTextCursor &rhs) const
       
  2315 {
       
  2316     if (!d)
       
  2317         return false;
       
  2318 
       
  2319     if (!rhs.d)
       
  2320         return true;
       
  2321 
       
  2322     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>", "cannot compare cursors attached to different documents");
       
  2323 
       
  2324     return d->position > rhs.d->position;
       
  2325 }
       
  2326 
       
  2327 /*!
       
  2328     Indicates the start of a block of editing operations on the
       
  2329     document that should appear as a single operation from an
       
  2330     undo/redo point of view.
       
  2331 
       
  2332     For example:
       
  2333 
       
  2334     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 2
       
  2335 
       
  2336     The call to undo() will cause both insertions to be undone,
       
  2337     causing both "World" and "Hello" to be removed.
       
  2338 
       
  2339     It is possible to nest calls to beginEditBlock and endEditBlock. The
       
  2340     top-most pair will determine the scope of the undo/redo operation.
       
  2341 
       
  2342     \sa endEditBlock()
       
  2343  */
       
  2344 void QTextCursor::beginEditBlock()
       
  2345 {
       
  2346     if (!d || !d->priv)
       
  2347         return;
       
  2348 
       
  2349     d->priv->beginEditBlock();
       
  2350 }
       
  2351 
       
  2352 /*!
       
  2353     Like beginEditBlock() indicates the start of a block of editing operations
       
  2354     that should appear as a single operation for undo/redo. However unlike
       
  2355     beginEditBlock() it does not start a new block but reverses the previous call to
       
  2356     endEditBlock() and therefore makes following operations part of the previous edit block created.
       
  2357 
       
  2358     For example:
       
  2359 
       
  2360     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 3
       
  2361 
       
  2362     The call to undo() will cause all three insertions to be undone.
       
  2363 
       
  2364     \sa beginEditBlock(), endEditBlock()
       
  2365  */
       
  2366 void QTextCursor::joinPreviousEditBlock()
       
  2367 {
       
  2368     if (!d || !d->priv)
       
  2369         return;
       
  2370 
       
  2371     d->priv->joinPreviousEditBlock();
       
  2372 }
       
  2373 
       
  2374 /*!
       
  2375     Indicates the end of a block of editing operations on the document
       
  2376     that should appear as a single operation from an undo/redo point
       
  2377     of view.
       
  2378 
       
  2379     \sa beginEditBlock()
       
  2380  */
       
  2381 
       
  2382 void QTextCursor::endEditBlock()
       
  2383 {
       
  2384     if (!d || !d->priv)
       
  2385         return;
       
  2386 
       
  2387     d->priv->endEditBlock();
       
  2388 }
       
  2389 
       
  2390 /*!
       
  2391     Returns true if this cursor and \a other are copies of each other, i.e.
       
  2392     one of them was created as a copy of the other and neither has moved since.
       
  2393     This is much stricter than equality.
       
  2394 
       
  2395     \sa operator=() operator==()
       
  2396 */
       
  2397 bool QTextCursor::isCopyOf(const QTextCursor &other) const
       
  2398 {
       
  2399     return d == other.d;
       
  2400 }
       
  2401 
       
  2402 /*!
       
  2403     \since 4.2
       
  2404     Returns the number of the block the cursor is in, or 0 if the cursor is invalid.
       
  2405 
       
  2406     Note that this function only makes sense in documents without complex objects such
       
  2407     as tables or frames.
       
  2408 */
       
  2409 int QTextCursor::blockNumber() const
       
  2410 {
       
  2411     if (!d || !d->priv)
       
  2412         return 0;
       
  2413 
       
  2414     return d->block().blockNumber();
       
  2415 }
       
  2416 
       
  2417 /*!
       
  2418     \since 4.2
       
  2419     Returns the position of the cursor within its containing line.
       
  2420 */
       
  2421 int QTextCursor::columnNumber() const
       
  2422 {
       
  2423     if (!d || !d->priv)
       
  2424         return 0;
       
  2425 
       
  2426     QTextBlock block = d->block();
       
  2427     if (!block.isValid())
       
  2428         return 0;
       
  2429 
       
  2430     const QTextLayout *layout = d->blockLayout(block);
       
  2431 
       
  2432     const int relativePos = d->position - block.position();
       
  2433 
       
  2434     if (layout->lineCount() == 0)
       
  2435         return relativePos;
       
  2436 
       
  2437     QTextLine line = layout->lineForTextPosition(relativePos);
       
  2438     if (!line.isValid())
       
  2439         return 0;
       
  2440     return relativePos - line.textStart();
       
  2441 }
       
  2442 
       
  2443 /*!
       
  2444     \since 4.5
       
  2445     Returns the document this cursor is associated with.
       
  2446 */
       
  2447 QTextDocument *QTextCursor::document() const
       
  2448 {
       
  2449     if (d->priv)
       
  2450         return d->priv->document();
       
  2451     return 0; // document went away
       
  2452 }
       
  2453 
       
  2454 QT_END_NAMESPACE