src/gui/text/qtextcursor.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "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 
       
   866     Text cursors are objects that are used to access and modify the contents
       
   867     and underlying structure of text documents via a programming interface
       
   868     that mimics the behavior of a cursor in a text editor. QTextCursor contains
       
   869     information about both the cursor's position within a QTextDocument and any
       
   870     selection that it 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 actions
       
   874     through the user interface. A document can be thought of as a
       
   875     single string of characters with the cursor's position() being \e
       
   876     between any two characters (or at the very beginning or very end
       
   877     of the document). Documents can also contain tables, lists,
       
   878     images, and other objects in addition to text but, from the developer's
       
   879     point of view, the document can be treated as one long string.
       
   880     Some portions of that string can be considered to lie within particular
       
   881     blocks (e.g. paragraphs), or within a table's cell, or a list's item,
       
   882     or other structural elements. When we refer to "current character" we
       
   883     mean the character immediately after the cursor position() in the
       
   884     document; similarly the "current block" is the block that contains the
       
   885     cursor position().
       
   886 
       
   887     A QTextCursor also has an anchor() position. The text that is
       
   888     between the anchor() and the position() is the selection. If
       
   889     anchor() == position() there is no selection.
       
   890 
       
   891     The cursor position can be changed programmatically using
       
   892     setPosition() and movePosition(); the latter can also be used to
       
   893     select text. For selections see selectionStart(), selectionEnd(),
       
   894     hasSelection(), clearSelection(), and removeSelectedText().
       
   895 
       
   896     If the position() is at the start of a block atBlockStart()
       
   897     returns true; and if it is at the end of a block atBlockEnd() returns
       
   898     true. The format of the current character is returned by
       
   899     charFormat(), and the format of the current block is returned by
       
   900     blockFormat().
       
   901 
       
   902     Formatting can be applied to the current text document using the
       
   903     setCharFormat(), mergeCharFormat(), setBlockFormat() and
       
   904     mergeBlockFormat() functions. The 'set' functions will replace the
       
   905     cursor's current character or block format, while the 'merge'
       
   906     functions add the given format properties to the cursor's current
       
   907     format. If the cursor has a selection the given format is applied
       
   908     to the current selection. Note that when only parts of a block is
       
   909     selected the block format is applied to the entire block. The text
       
   910     at the current character position can be turned into a list using
       
   911     createList().
       
   912 
       
   913     Deletions can be achieved using deleteChar(),
       
   914     deletePreviousChar(), and removeSelectedText().
       
   915 
       
   916     Text strings can be inserted into the document with the insertText()
       
   917     function, blocks (representing new paragraphs) can be inserted with
       
   918     insertBlock().
       
   919 
       
   920     Existing fragments of text can be inserted with insertFragment() but,
       
   921     if you want to insert pieces of text in various formats, it is usually
       
   922     still easier to use insertText() and supply a character format.
       
   923 
       
   924     Various types of higher-level structure can also be inserted into the
       
   925     document with the cursor:
       
   926 
       
   927     \list
       
   928     \i Lists are ordered sequences of block elements that are decorated with
       
   929        bullet points or symbols. These are inserted in a specified format
       
   930        with insertList().
       
   931     \i Tables are inserted with the insertTable() function, and can be
       
   932        given an optional format. These contain an array of cells that can
       
   933        be traversed using the cursor.
       
   934     \i Inline images are inserted with insertImage(). The image to be
       
   935        used can be specified in an image format, or by name.
       
   936     \i Frames are inserted by calling insertFrame() with a specified format.
       
   937     \endlist
       
   938 
       
   939     Actions can be grouped (i.e. treated as a single action for
       
   940     undo/redo) using beginEditBlock() and endEditBlock().
       
   941 
       
   942     Cursor movements are limited to valid cursor positions. In Latin
       
   943     writing this is usually after every character in the text. In some
       
   944     other writing systems cursor movements are limited to "clusters"
       
   945     (e.g. a syllable in Devanagari, or a base letter plus diacritics).
       
   946     Functions such as movePosition() and deleteChar() limit cursor
       
   947     movement to these valid positions.
       
   948 
       
   949     \sa \link richtext.html Rich Text Processing\endlink
       
   950 
       
   951 */
       
   952 
       
   953 /*!
       
   954     \enum QTextCursor::MoveOperation
       
   955 
       
   956     \value NoMove Keep the cursor where it is
       
   957 
       
   958     \value Start Move to the start of the document.
       
   959     \value StartOfLine Move to the start of the current line.
       
   960     \value StartOfBlock Move to the start of the current block.
       
   961     \value StartOfWord Move to the start of the current word.
       
   962     \value PreviousBlock Move to the start of the previous block.
       
   963     \value PreviousCharacter Move to the previous character.
       
   964     \value PreviousWord Move to the beginning of the previous word.
       
   965     \value Up Move up one line.
       
   966     \value Left Move left one character.
       
   967     \value WordLeft Move left one word.
       
   968 
       
   969     \value End Move to the end of the document.
       
   970     \value EndOfLine Move to the end of the current line.
       
   971     \value EndOfWord Move to the end of the current word.
       
   972     \value EndOfBlock Move to the end of the current block.
       
   973     \value NextBlock Move to the beginning of the next block.
       
   974     \value NextCharacter Move to the next character.
       
   975     \value NextWord Move to the next word.
       
   976     \value Down Move down one line.
       
   977     \value Right Move right one character.
       
   978     \value WordRight Move right one word.
       
   979 
       
   980     \value NextCell  Move to the beginning of the next table cell inside the
       
   981            current table. If the current cell is the last cell in the row, the
       
   982            cursor will move to the first cell in the next row.
       
   983     \value PreviousCell  Move to the beginning of the previous table cell
       
   984            inside the current table. If the current cell is the first cell in
       
   985            the row, the cursor will move to the last cell in the previous row.
       
   986     \value NextRow  Move to the first new cell of the next row in the current
       
   987            table.
       
   988     \value PreviousRow  Move to the last cell of the previous row in the
       
   989            current table.
       
   990 
       
   991     \sa movePosition()
       
   992 */
       
   993 
       
   994 /*!
       
   995     \enum QTextCursor::MoveMode
       
   996 
       
   997     \value MoveAnchor Moves the anchor to the same position as the cursor itself.
       
   998     \value KeepAnchor Keeps the anchor where it is.
       
   999 
       
  1000     If the anchor() is kept where it is and the position() is moved,
       
  1001     the text in between will be selected.
       
  1002 */
       
  1003 
       
  1004 /*!
       
  1005     \enum QTextCursor::SelectionType
       
  1006 
       
  1007     This enum describes the types of selection that can be applied with the
       
  1008     select() function.
       
  1009 
       
  1010     \value Document         Selects the entire document.
       
  1011     \value BlockUnderCursor Selects the block of text under the cursor.
       
  1012     \value LineUnderCursor  Selects the line of text under the cursor.
       
  1013     \value WordUnderCursor  Selects the word under the cursor. If the cursor
       
  1014            is not positioned within a string of selectable characters, no
       
  1015            text is selected.
       
  1016 */
       
  1017 
       
  1018 /*!
       
  1019     Constructs a null cursor.
       
  1020  */
       
  1021 QTextCursor::QTextCursor()
       
  1022     : d(0)
       
  1023 {
       
  1024 }
       
  1025 
       
  1026 /*!
       
  1027     Constructs a cursor pointing to the beginning of the \a document.
       
  1028  */
       
  1029 QTextCursor::QTextCursor(QTextDocument *document)
       
  1030     : d(new QTextCursorPrivate(document->docHandle()))
       
  1031 {
       
  1032 }
       
  1033 
       
  1034 /*!
       
  1035     Constructs a cursor pointing to the beginning of the \a frame.
       
  1036 */
       
  1037 QTextCursor::QTextCursor(QTextFrame *frame)
       
  1038     : d(new QTextCursorPrivate(frame->document()->docHandle()))
       
  1039 {
       
  1040     d->adjusted_anchor = d->anchor = d->position = frame->firstPosition();
       
  1041 }
       
  1042 
       
  1043 
       
  1044 /*!
       
  1045     Constructs a cursor pointing to the beginning of the \a block.
       
  1046 */
       
  1047 QTextCursor::QTextCursor(const QTextBlock &block)
       
  1048     : d(new QTextCursorPrivate(block.docHandle()))
       
  1049 {
       
  1050     d->adjusted_anchor = d->anchor = d->position = block.position();
       
  1051 }
       
  1052 
       
  1053 
       
  1054 /*!
       
  1055   \internal
       
  1056  */
       
  1057 QTextCursor::QTextCursor(QTextDocumentPrivate *p, int pos)
       
  1058     : d(new QTextCursorPrivate(p))
       
  1059 {
       
  1060     d->adjusted_anchor = d->anchor = d->position = pos;
       
  1061 
       
  1062     d->setX();
       
  1063 }
       
  1064 
       
  1065 /*!
       
  1066     \internal
       
  1067 */
       
  1068 QTextCursor::QTextCursor(QTextCursorPrivate *d)
       
  1069 {
       
  1070     Q_ASSERT(d);
       
  1071     this->d = d;
       
  1072 }
       
  1073 
       
  1074 /*!
       
  1075     Constructs a new cursor that is a copy of \a cursor.
       
  1076  */
       
  1077 QTextCursor::QTextCursor(const QTextCursor &cursor)
       
  1078 {
       
  1079     d = cursor.d;
       
  1080 }
       
  1081 
       
  1082 /*!
       
  1083     Makes a copy of \a cursor and assigns it to this QTextCursor. Note
       
  1084     that QTextCursor is an \l{Implicitly Shared Classes}{implicitly
       
  1085     shared} class.
       
  1086 
       
  1087  */
       
  1088 QTextCursor &QTextCursor::operator=(const QTextCursor &cursor)
       
  1089 {
       
  1090     d = cursor.d;
       
  1091     return *this;
       
  1092 }
       
  1093 
       
  1094 /*!
       
  1095     Destroys the QTextCursor.
       
  1096  */
       
  1097 QTextCursor::~QTextCursor()
       
  1098 {
       
  1099 }
       
  1100 
       
  1101 /*!
       
  1102     Returns true if the cursor is null; otherwise returns false. A null
       
  1103     cursor is created by the default constructor.
       
  1104  */
       
  1105 bool QTextCursor::isNull() const
       
  1106 {
       
  1107     return !d || !d->priv;
       
  1108 }
       
  1109 
       
  1110 /*!
       
  1111     Moves the cursor to the absolute position in the document specified by
       
  1112     \a pos using a \c MoveMode specified by \a m. The cursor is positioned
       
  1113     between characters.
       
  1114 
       
  1115     \sa position() movePosition() anchor()
       
  1116 */
       
  1117 void QTextCursor::setPosition(int pos, MoveMode m)
       
  1118 {
       
  1119     if (!d || !d->priv)
       
  1120         return;
       
  1121 
       
  1122     if (pos < 0 || pos >= d->priv->length()) {
       
  1123         qWarning("QTextCursor::setPosition: Position '%d' out of range", pos);
       
  1124         return;
       
  1125     }
       
  1126 
       
  1127     d->setPosition(pos);
       
  1128     if (m == MoveAnchor) {
       
  1129         d->anchor = pos;
       
  1130         d->adjusted_anchor = pos;
       
  1131     } else { // keep anchor
       
  1132         QTextCursor::MoveOperation op;
       
  1133         if (pos < d->anchor)
       
  1134             op = QTextCursor::Left;
       
  1135         else
       
  1136             op = QTextCursor::Right;
       
  1137         d->adjustCursor(op);
       
  1138     }
       
  1139     d->setX();
       
  1140 }
       
  1141 
       
  1142 /*!
       
  1143     Returns the absolute position of the cursor within the document.
       
  1144     The cursor is positioned between characters.
       
  1145 
       
  1146     \sa setPosition() movePosition() anchor()
       
  1147 */
       
  1148 int QTextCursor::position() const
       
  1149 {
       
  1150     if (!d || !d->priv)
       
  1151         return -1;
       
  1152     return d->position;
       
  1153 }
       
  1154 
       
  1155 /*!
       
  1156     Returns the anchor position; this is the same as position() unless
       
  1157     there is a selection in which case position() marks one end of the
       
  1158     selection and anchor() marks the other end. Just like the cursor
       
  1159     position, the anchor position is between characters.
       
  1160 
       
  1161     \sa position() setPosition() movePosition() selectionStart() selectionEnd()
       
  1162 */
       
  1163 int QTextCursor::anchor() const
       
  1164 {
       
  1165     if (!d || !d->priv)
       
  1166         return -1;
       
  1167     return d->anchor;
       
  1168 }
       
  1169 
       
  1170 /*!
       
  1171     \fn bool QTextCursor::movePosition(MoveOperation operation, MoveMode mode, int n)
       
  1172 
       
  1173     Moves the cursor by performing the given \a operation \a n times, using the specified
       
  1174     \a mode, and returns true if all operations were completed successfully; otherwise
       
  1175     returns false.
       
  1176 
       
  1177     For example, if this function is repeatedly used to seek to the end of the next
       
  1178     word, it will eventually fail when the end of the document is reached.
       
  1179 
       
  1180     By default, the move operation is performed once (\a n = 1).
       
  1181 
       
  1182     If \a mode is \c KeepAnchor, the cursor selects the text it moves
       
  1183     over. This is the same effect that the user achieves when they
       
  1184     hold down the Shift key and move the cursor with the cursor keys.
       
  1185 
       
  1186     \sa setVisualNavigation()
       
  1187 */
       
  1188 bool QTextCursor::movePosition(MoveOperation op, MoveMode mode, int n)
       
  1189 {
       
  1190     if (!d || !d->priv)
       
  1191         return false;
       
  1192     switch (op) {
       
  1193     case Start:
       
  1194     case StartOfLine:
       
  1195     case End:
       
  1196     case EndOfLine:
       
  1197         n = 1;
       
  1198         break;
       
  1199     default: break;
       
  1200     }
       
  1201 
       
  1202     int previousPosition = d->position;
       
  1203     for (; n > 0; --n) {
       
  1204         if (!d->movePosition(op, mode))
       
  1205             return false;
       
  1206     }
       
  1207 
       
  1208     if (d->visualNavigation && !d->block().isVisible()) {
       
  1209         QTextBlock b = d->block();
       
  1210         if (previousPosition < d->position) {
       
  1211             while (!b.next().isVisible())
       
  1212                 b = b.next();
       
  1213             d->setPosition(b.position() + b.length() - 1);
       
  1214         } else {
       
  1215             while (!b.previous().isVisible())
       
  1216                 b = b.previous();
       
  1217             d->setPosition(b.position());
       
  1218         }
       
  1219         if (mode == QTextCursor::MoveAnchor)
       
  1220             d->anchor = d->position;
       
  1221         while (d->movePosition(op, mode)
       
  1222                && !d->block().isVisible())
       
  1223             ;
       
  1224 
       
  1225     }
       
  1226     return true;
       
  1227 }
       
  1228 
       
  1229 /*!
       
  1230   \since 4.4
       
  1231 
       
  1232   Returns true if the cursor does visual navigation; otherwise
       
  1233   returns false.
       
  1234 
       
  1235   Visual navigation means skipping over hidden text pragraphs. The
       
  1236   default is false.
       
  1237 
       
  1238   \sa setVisualNavigation(), movePosition()
       
  1239  */
       
  1240 bool QTextCursor::visualNavigation() const
       
  1241 {
       
  1242     return d ? d->visualNavigation : false;
       
  1243 }
       
  1244 
       
  1245 /*!
       
  1246   \since 4.4
       
  1247 
       
  1248   Sets visual navigation to \a b.
       
  1249 
       
  1250   Visual navigation means skipping over hidden text pragraphs. The
       
  1251   default is false.
       
  1252 
       
  1253   \sa visualNavigation(), movePosition()
       
  1254  */
       
  1255 void QTextCursor::setVisualNavigation(bool b)
       
  1256 {
       
  1257     if (d)
       
  1258         d->visualNavigation = b;
       
  1259 }
       
  1260 
       
  1261 /*!
       
  1262     Inserts \a text at the current position, using the current
       
  1263     character format.
       
  1264 
       
  1265     If there is a selection, the selection is deleted and replaced by
       
  1266     \a text, for example:
       
  1267     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 0
       
  1268     This clears any existing selection, selects the word at the cursor
       
  1269     (i.e. from position() forward), and replaces the selection with
       
  1270     the phrase "Hello World".
       
  1271 
       
  1272     Any ASCII linefeed characters (\\n) in the inserted text are transformed
       
  1273     into unicode block separators, corresponding to insertBlock() calls.
       
  1274 
       
  1275     \sa charFormat() hasSelection()
       
  1276 */
       
  1277 void QTextCursor::insertText(const QString &text)
       
  1278 {
       
  1279     QTextCharFormat fmt = charFormat();
       
  1280     fmt.clearProperty(QTextFormat::ObjectType);
       
  1281     insertText(text, fmt);
       
  1282 }
       
  1283 
       
  1284 /*!
       
  1285     \fn void QTextCursor::insertText(const QString &text, const QTextCharFormat &format)
       
  1286     \overload
       
  1287 
       
  1288     Inserts \a text at the current position with the given \a format.
       
  1289 */
       
  1290 void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format)
       
  1291 {
       
  1292     if (!d || !d->priv)
       
  1293         return;
       
  1294 
       
  1295     Q_ASSERT(_format.isValid());
       
  1296 
       
  1297     QTextCharFormat format = _format;
       
  1298     format.clearProperty(QTextFormat::ObjectIndex);
       
  1299 
       
  1300     bool hasEditBlock = false;
       
  1301 
       
  1302     if (d->anchor != d->position) {
       
  1303         hasEditBlock = true;
       
  1304         d->priv->beginEditBlock();
       
  1305         d->remove();
       
  1306     }
       
  1307 
       
  1308     if (!text.isEmpty()) {
       
  1309         QTextFormatCollection *formats = d->priv->formatCollection();
       
  1310         int formatIdx = formats->indexForFormat(format);
       
  1311         Q_ASSERT(formats->format(formatIdx).isCharFormat());
       
  1312 
       
  1313         QTextBlockFormat blockFmt = blockFormat();
       
  1314 
       
  1315 
       
  1316         int textStart = d->priv->text.length();
       
  1317         int blockStart = 0;
       
  1318         d->priv->text += text;
       
  1319         int textEnd = d->priv->text.length();
       
  1320 
       
  1321         for (int i = 0; i < text.length(); ++i) {
       
  1322             QChar ch = text.at(i);
       
  1323 
       
  1324             const int blockEnd = i;
       
  1325 
       
  1326             if (ch == QLatin1Char('\r')
       
  1327                 && (i + 1) < text.length()
       
  1328                 && text.at(i + 1) == QLatin1Char('\n')) {
       
  1329                 ++i;
       
  1330                 ch = text.at(i);
       
  1331             }
       
  1332 
       
  1333             if (ch == QLatin1Char('\n')
       
  1334                 || ch == QChar::ParagraphSeparator
       
  1335                 || ch == QTextBeginningOfFrame
       
  1336                 || ch == QTextEndOfFrame
       
  1337                 || ch == QLatin1Char('\r')) {
       
  1338 
       
  1339                 if (!hasEditBlock) {
       
  1340                     hasEditBlock = true;
       
  1341                     d->priv->beginEditBlock();
       
  1342                 }
       
  1343 
       
  1344                 if (blockEnd > blockStart)
       
  1345                     d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx);
       
  1346 
       
  1347                 d->insertBlock(blockFmt, format);
       
  1348                 blockStart = i + 1;
       
  1349             }
       
  1350         }
       
  1351         if (textStart + blockStart < textEnd)
       
  1352             d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx);
       
  1353     }
       
  1354     if (hasEditBlock)
       
  1355         d->priv->endEditBlock();
       
  1356     d->setX();
       
  1357 }
       
  1358 
       
  1359 /*!
       
  1360     If there is no selected text, deletes the character \e at the
       
  1361     current cursor position; otherwise deletes the selected text.
       
  1362 
       
  1363     \sa deletePreviousChar() hasSelection() clearSelection()
       
  1364 */
       
  1365 void QTextCursor::deleteChar()
       
  1366 {
       
  1367     if (!d || !d->priv)
       
  1368         return;
       
  1369 
       
  1370     if (d->position != d->anchor) {
       
  1371         removeSelectedText();
       
  1372         return;
       
  1373     }
       
  1374 
       
  1375     if (!d->canDelete(d->position))
       
  1376         return;
       
  1377     d->adjusted_anchor = d->anchor =
       
  1378                          d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters);
       
  1379     d->remove();
       
  1380     d->setX();
       
  1381 }
       
  1382 
       
  1383 /*!
       
  1384     If there is no selected text, deletes the character \e before the
       
  1385     current cursor position; otherwise deletes the selected text.
       
  1386 
       
  1387     \sa deleteChar() hasSelection() clearSelection()
       
  1388 */
       
  1389 void QTextCursor::deletePreviousChar()
       
  1390 {
       
  1391     if (!d || !d->priv)
       
  1392         return;
       
  1393     
       
  1394     if (d->position != d->anchor) {
       
  1395         removeSelectedText();
       
  1396         return;
       
  1397     }
       
  1398     
       
  1399     if (d->anchor < 1 || !d->canDelete(d->anchor-1))
       
  1400         return;
       
  1401     d->anchor--;
       
  1402     
       
  1403     QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
       
  1404     const QTextFragmentData * const frag = fragIt.value();
       
  1405     int fpos = fragIt.position();
       
  1406     QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition);
       
  1407     if (d->anchor > fpos && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) {
       
  1408         // second half of a surrogate, check if we have the first half as well,
       
  1409         // if yes delete both at once
       
  1410         uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition);
       
  1411         if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00)
       
  1412             --d->anchor;
       
  1413     }
       
  1414     
       
  1415     d->adjusted_anchor = d->anchor;
       
  1416     d->remove();
       
  1417     d->setX();
       
  1418 }
       
  1419 
       
  1420 /*!
       
  1421     Selects text in the document according to the given \a selection.
       
  1422 */
       
  1423 void QTextCursor::select(SelectionType selection)
       
  1424 {
       
  1425     if (!d || !d->priv)
       
  1426         return;
       
  1427 
       
  1428     clearSelection();
       
  1429 
       
  1430     const QTextBlock block = d->block();
       
  1431 
       
  1432     switch (selection) {
       
  1433         case LineUnderCursor:
       
  1434             movePosition(StartOfLine);
       
  1435             movePosition(EndOfLine, KeepAnchor);
       
  1436             break;
       
  1437         case WordUnderCursor:
       
  1438             movePosition(StartOfWord);
       
  1439             movePosition(EndOfWord, KeepAnchor);
       
  1440             break;
       
  1441         case BlockUnderCursor:
       
  1442             if (block.length() == 1) // no content
       
  1443                 break;
       
  1444             movePosition(StartOfBlock);
       
  1445             // also select the paragraph separator
       
  1446             if (movePosition(PreviousBlock)) {
       
  1447                 movePosition(EndOfBlock);
       
  1448                 movePosition(NextBlock, KeepAnchor);
       
  1449             }
       
  1450             movePosition(EndOfBlock, KeepAnchor);
       
  1451             break;
       
  1452         case Document:
       
  1453             movePosition(Start);
       
  1454             movePosition(End, KeepAnchor);
       
  1455             break;
       
  1456     }
       
  1457 }
       
  1458 
       
  1459 /*!
       
  1460     Returns true if the cursor contains a selection; otherwise returns false.
       
  1461 */
       
  1462 bool QTextCursor::hasSelection() const
       
  1463 {
       
  1464     return !!d && d->position != d->anchor;
       
  1465 }
       
  1466 
       
  1467 
       
  1468 /*!
       
  1469     Returns true if the cursor contains a selection that is not simply a
       
  1470     range from selectionStart() to selectionEnd(); otherwise returns false.
       
  1471 
       
  1472     Complex selections are ones that span at least two cells in a table;
       
  1473     their extent is specified by selectedTableCells().
       
  1474 */
       
  1475 bool QTextCursor::hasComplexSelection() const
       
  1476 {
       
  1477     if (!d)
       
  1478         return false;
       
  1479 
       
  1480     return d->complexSelectionTable() != 0;
       
  1481 }
       
  1482 
       
  1483 /*!
       
  1484     If the selection spans over table cells, \a firstRow is populated
       
  1485     with the number of the first row in the selection, \a firstColumn
       
  1486     with the number of the first column in the selection, and \a
       
  1487     numRows and \a numColumns with the number of rows and columns in
       
  1488     the selection. If the selection does not span any table cells the
       
  1489     results are harmless but undefined.
       
  1490 */
       
  1491 void QTextCursor::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
       
  1492 {
       
  1493     *firstRow = -1;
       
  1494     *firstColumn = -1;
       
  1495     *numRows = -1;
       
  1496     *numColumns = -1;
       
  1497 
       
  1498     if (!d || d->position == d->anchor)
       
  1499         return;
       
  1500 
       
  1501     d->selectedTableCells(firstRow, numRows, firstColumn, numColumns);
       
  1502 }
       
  1503 
       
  1504 
       
  1505 /*!
       
  1506     Clears the current selection by setting the anchor to the cursor position.
       
  1507 
       
  1508     Note that it does \bold{not} delete the text of the selection.
       
  1509 
       
  1510     \sa removeSelectedText() hasSelection()
       
  1511 */
       
  1512 void QTextCursor::clearSelection()
       
  1513 {
       
  1514     if (!d)
       
  1515         return;
       
  1516     d->adjusted_anchor = d->anchor = d->position;
       
  1517     d->currentCharFormat = -1;
       
  1518 }
       
  1519 
       
  1520 /*!
       
  1521     If there is a selection, its content is deleted; otherwise does
       
  1522     nothing.
       
  1523 
       
  1524     \sa hasSelection()
       
  1525 */
       
  1526 void QTextCursor::removeSelectedText()
       
  1527 {
       
  1528     if (!d || !d->priv || d->position == d->anchor)
       
  1529         return;
       
  1530 
       
  1531     d->priv->beginEditBlock();
       
  1532     d->remove();
       
  1533     d->priv->endEditBlock();
       
  1534     d->setX();
       
  1535 }
       
  1536 
       
  1537 /*!
       
  1538     Returns the start of the selection or position() if the
       
  1539     cursor doesn't have a selection.
       
  1540 
       
  1541     \sa selectionEnd() position() anchor()
       
  1542 */
       
  1543 int QTextCursor::selectionStart() const
       
  1544 {
       
  1545     if (!d || !d->priv)
       
  1546         return -1;
       
  1547     return qMin(d->position, d->adjusted_anchor);
       
  1548 }
       
  1549 
       
  1550 /*!
       
  1551     Returns the end of the selection or position() if the cursor
       
  1552     doesn't have a selection.
       
  1553 
       
  1554     \sa selectionStart() position() anchor()
       
  1555 */
       
  1556 int QTextCursor::selectionEnd() const
       
  1557 {
       
  1558     if (!d || !d->priv)
       
  1559         return -1;
       
  1560     return qMax(d->position, d->adjusted_anchor);
       
  1561 }
       
  1562 
       
  1563 static void getText(QString &text, QTextDocumentPrivate *priv, const QString &docText, int pos, int end)
       
  1564 {
       
  1565     while (pos < end) {
       
  1566         QTextDocumentPrivate::FragmentIterator fragIt = priv->find(pos);
       
  1567         const QTextFragmentData * const frag = fragIt.value();
       
  1568 
       
  1569         const int offsetInFragment = qMax(0, pos - fragIt.position());
       
  1570         const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
       
  1571 
       
  1572         text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
       
  1573         pos += len;
       
  1574     }
       
  1575 }
       
  1576 
       
  1577 /*!
       
  1578     Returns the current selection's text (which may be empty). This
       
  1579     only returns the text, with no rich text formatting information.
       
  1580     If you want a document fragment (i.e. formatted rich text) use
       
  1581     selection() instead.
       
  1582 
       
  1583     \note If the selection obtained from an editor spans a line break,
       
  1584     the text will contain a Unicode U+2029 paragraph separator character
       
  1585     instead of a newline \c{\n} character. Use QString::replace() to
       
  1586     replace these characters with newlines.
       
  1587 */
       
  1588 QString QTextCursor::selectedText() const
       
  1589 {
       
  1590     if (!d || !d->priv || d->position == d->anchor)
       
  1591         return QString();
       
  1592 
       
  1593     const QString docText = d->priv->buffer();
       
  1594     QString text;
       
  1595 
       
  1596     QTextTable *table = d->complexSelectionTable();
       
  1597     if (table) {
       
  1598         int row_start, col_start, num_rows, num_cols;
       
  1599         selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
       
  1600 
       
  1601         Q_ASSERT(row_start != -1);
       
  1602         for (int r = row_start; r < row_start + num_rows; ++r) {
       
  1603             for (int c = col_start; c < col_start + num_cols; ++c) {
       
  1604                 QTextTableCell cell = table->cellAt(r, c);
       
  1605                 int rspan = cell.rowSpan();
       
  1606                 int cspan = cell.columnSpan();
       
  1607                 if (rspan != 1) {
       
  1608                     int cr = cell.row();
       
  1609                     if (cr != r)
       
  1610                         continue;
       
  1611                 }
       
  1612                 if (cspan != 1) {
       
  1613                     int cc = cell.column();
       
  1614                     if (cc != c)
       
  1615                         continue;
       
  1616                 }
       
  1617 
       
  1618                 getText(text, d->priv, docText, cell.firstPosition(), cell.lastPosition());
       
  1619             }
       
  1620         }
       
  1621     } else {
       
  1622         getText(text, d->priv, docText, selectionStart(), selectionEnd());
       
  1623     }
       
  1624 
       
  1625     return text;
       
  1626 }
       
  1627 
       
  1628 /*!
       
  1629     Returns the current selection (which may be empty) with all its
       
  1630     formatting information. If you just want the selected text (i.e.
       
  1631     plain text) use selectedText() instead.
       
  1632 
       
  1633     \note Unlike QTextDocumentFragment::toPlainText(),
       
  1634     selectedText() may include special unicode characters such as
       
  1635     QChar::ParagraphSeparator.
       
  1636 
       
  1637     \sa QTextDocumentFragment::toPlainText()
       
  1638 */
       
  1639 QTextDocumentFragment QTextCursor::selection() const
       
  1640 {
       
  1641     return QTextDocumentFragment(*this);
       
  1642 }
       
  1643 
       
  1644 /*!
       
  1645     Returns the block that contains the cursor.
       
  1646 */
       
  1647 QTextBlock QTextCursor::block() const
       
  1648 {
       
  1649     if (!d || !d->priv)
       
  1650         return QTextBlock();
       
  1651     return d->block();
       
  1652 }
       
  1653 
       
  1654 /*!
       
  1655     Returns the block format of the block the cursor is in.
       
  1656 
       
  1657     \sa setBlockFormat() charFormat()
       
  1658  */
       
  1659 QTextBlockFormat QTextCursor::blockFormat() const
       
  1660 {
       
  1661     if (!d || !d->priv)
       
  1662         return QTextBlockFormat();
       
  1663 
       
  1664     return d->block().blockFormat();
       
  1665 }
       
  1666 
       
  1667 /*!
       
  1668     Sets the block format of the current block (or all blocks that
       
  1669     are contained in the selection) to \a format.
       
  1670 
       
  1671     \sa blockFormat(), mergeBlockFormat()
       
  1672 */
       
  1673 void QTextCursor::setBlockFormat(const QTextBlockFormat &format)
       
  1674 {
       
  1675     if (!d || !d->priv)
       
  1676         return;
       
  1677 
       
  1678     d->setBlockFormat(format, QTextDocumentPrivate::SetFormat);
       
  1679 }
       
  1680 
       
  1681 /*!
       
  1682     Modifies the block format of the current block (or all blocks that
       
  1683     are contained in the selection) with the block format specified by
       
  1684     \a modifier.
       
  1685 
       
  1686     \sa setBlockFormat(), blockFormat()
       
  1687 */
       
  1688 void QTextCursor::mergeBlockFormat(const QTextBlockFormat &modifier)
       
  1689 {
       
  1690     if (!d || !d->priv)
       
  1691         return;
       
  1692 
       
  1693     d->setBlockFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1694 }
       
  1695 
       
  1696 /*!
       
  1697     Returns the block character format of the block the cursor is in.
       
  1698 
       
  1699     The block char format is the format used when inserting text at the
       
  1700     beginning of an empty block.
       
  1701 
       
  1702     \sa setBlockCharFormat()
       
  1703  */
       
  1704 QTextCharFormat QTextCursor::blockCharFormat() const
       
  1705 {
       
  1706     if (!d || !d->priv)
       
  1707         return QTextCharFormat();
       
  1708 
       
  1709     return d->block().charFormat();
       
  1710 }
       
  1711 
       
  1712 /*!
       
  1713     Sets the block char format of the current block (or all blocks that
       
  1714     are contained in the selection) to \a format.
       
  1715 
       
  1716     \sa blockCharFormat()
       
  1717 */
       
  1718 void QTextCursor::setBlockCharFormat(const QTextCharFormat &format)
       
  1719 {
       
  1720     if (!d || !d->priv)
       
  1721         return;
       
  1722 
       
  1723     d->setBlockCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
       
  1724 }
       
  1725 
       
  1726 /*!
       
  1727     Modifies the block char format of the current block (or all blocks that
       
  1728     are contained in the selection) with the block format specified by
       
  1729     \a modifier.
       
  1730 
       
  1731     \sa setBlockCharFormat()
       
  1732 */
       
  1733 void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier)
       
  1734 {
       
  1735     if (!d || !d->priv)
       
  1736         return;
       
  1737 
       
  1738     d->setBlockCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1739 }
       
  1740 
       
  1741 /*!
       
  1742     Returns the format of the character immediately before the cursor position(). If the cursor is
       
  1743     positioned at the beginning of a text block that is not empty then the format of the character
       
  1744     immediately after the cursor is returned.
       
  1745 
       
  1746     \sa insertText(), blockFormat()
       
  1747  */
       
  1748 QTextCharFormat QTextCursor::charFormat() const
       
  1749 {
       
  1750     if (!d || !d->priv)
       
  1751         return QTextCharFormat();
       
  1752 
       
  1753     int idx = d->currentCharFormat;
       
  1754     if (idx == -1) {
       
  1755         QTextBlock block = d->block();
       
  1756 
       
  1757         int pos;
       
  1758         if (d->position == block.position()
       
  1759             && block.length() > 1)
       
  1760             pos = d->position;
       
  1761         else
       
  1762             pos = d->position - 1;
       
  1763 
       
  1764         if (pos == -1) {
       
  1765             idx = d->priv->blockCharFormatIndex(d->priv->blockMap().firstNode());
       
  1766         } else {
       
  1767             Q_ASSERT(pos >= 0 && pos < d->priv->length());
       
  1768 
       
  1769             QTextDocumentPrivate::FragmentIterator it = d->priv->find(pos);
       
  1770             Q_ASSERT(!it.atEnd());
       
  1771             idx = it.value()->format;
       
  1772         }
       
  1773     }
       
  1774 
       
  1775     QTextCharFormat cfmt = d->priv->formatCollection()->charFormat(idx);
       
  1776     cfmt.clearProperty(QTextFormat::ObjectIndex);
       
  1777 
       
  1778     Q_ASSERT(cfmt.isValid());
       
  1779     return cfmt;
       
  1780 }
       
  1781 
       
  1782 /*!
       
  1783     Sets the cursor's current character format to the given \a
       
  1784     format. If the cursor has a selection, the given \a format is
       
  1785     applied to the current selection.
       
  1786 
       
  1787     \sa hasSelection(), mergeCharFormat()
       
  1788 */
       
  1789 void QTextCursor::setCharFormat(const QTextCharFormat &format)
       
  1790 {
       
  1791     if (!d || !d->priv)
       
  1792         return;
       
  1793     if (d->position == d->anchor) {
       
  1794         d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
       
  1795         return;
       
  1796     }
       
  1797     d->setCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
       
  1798 }
       
  1799 
       
  1800 /*!
       
  1801     Merges the cursor's current character format with the properties
       
  1802     described by format \a modifier. If the cursor has a selection,
       
  1803     this function applies all the properties set in \a modifier to all
       
  1804     the character formats that are part of the selection.
       
  1805 
       
  1806     \sa hasSelection(), setCharFormat()
       
  1807 */
       
  1808 void QTextCursor::mergeCharFormat(const QTextCharFormat &modifier)
       
  1809 {
       
  1810     if (!d || !d->priv)
       
  1811         return;
       
  1812     if (d->position == d->anchor) {
       
  1813         QTextCharFormat format = charFormat();
       
  1814         format.merge(modifier);
       
  1815         d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
       
  1816         return;
       
  1817     }
       
  1818 
       
  1819     d->setCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
       
  1820 }
       
  1821 
       
  1822 /*!
       
  1823     Returns true if the cursor is at the start of a block; otherwise
       
  1824     returns false.
       
  1825 
       
  1826     \sa atBlockEnd(), atStart()
       
  1827 */
       
  1828 bool QTextCursor::atBlockStart() const
       
  1829 {
       
  1830     if (!d || !d->priv)
       
  1831         return false;
       
  1832 
       
  1833     return d->position == d->block().position();
       
  1834 }
       
  1835 
       
  1836 /*!
       
  1837     Returns true if the cursor is at the end of a block; otherwise
       
  1838     returns false.
       
  1839 
       
  1840     \sa atBlockStart(), atEnd()
       
  1841 */
       
  1842 bool QTextCursor::atBlockEnd() const
       
  1843 {
       
  1844     if (!d || !d->priv)
       
  1845         return false;
       
  1846 
       
  1847     return d->position == d->block().position() + d->block().length() - 1;
       
  1848 }
       
  1849 
       
  1850 /*!
       
  1851     Returns true if the cursor is at the start of the document;
       
  1852     otherwise returns false.
       
  1853 
       
  1854     \sa atBlockStart(), atEnd()
       
  1855 */
       
  1856 bool QTextCursor::atStart() const
       
  1857 {
       
  1858     if (!d || !d->priv)
       
  1859         return false;
       
  1860 
       
  1861     return d->position == 0;
       
  1862 }
       
  1863 
       
  1864 /*!
       
  1865     \since 4.6
       
  1866 
       
  1867     Returns true if the cursor is at the end of the document;
       
  1868     otherwise returns false.
       
  1869 
       
  1870     \sa atStart(), atBlockEnd()
       
  1871 */
       
  1872 bool QTextCursor::atEnd() const
       
  1873 {
       
  1874     if (!d || !d->priv)
       
  1875         return false;
       
  1876 
       
  1877     return d->position == d->priv->length() - 1;
       
  1878 }
       
  1879 
       
  1880 /*!
       
  1881     Inserts a new empty block at the cursor position() with the
       
  1882     current blockFormat() and charFormat().
       
  1883 
       
  1884     \sa setBlockFormat()
       
  1885 */
       
  1886 void QTextCursor::insertBlock()
       
  1887 {
       
  1888     insertBlock(blockFormat());
       
  1889 }
       
  1890 
       
  1891 /*!
       
  1892     \overload
       
  1893 
       
  1894     Inserts a new empty block at the cursor position() with block
       
  1895     format \a format and the current charFormat() as block char format.
       
  1896 
       
  1897     \sa setBlockFormat()
       
  1898 */
       
  1899 void QTextCursor::insertBlock(const QTextBlockFormat &format)
       
  1900 {
       
  1901     QTextCharFormat charFmt = charFormat();
       
  1902     charFmt.clearProperty(QTextFormat::ObjectType);
       
  1903     insertBlock(format, charFmt);
       
  1904 }
       
  1905 
       
  1906 /*!
       
  1907     \fn void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
       
  1908     \overload
       
  1909 
       
  1910     Inserts a new empty block at the cursor position() with block
       
  1911     format \a format and \a charFormat as block char format.
       
  1912 
       
  1913     \sa setBlockFormat()
       
  1914 */
       
  1915 void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &_charFormat)
       
  1916 {
       
  1917     if (!d || !d->priv)
       
  1918         return;
       
  1919 
       
  1920     QTextCharFormat charFormat = _charFormat;
       
  1921     charFormat.clearProperty(QTextFormat::ObjectIndex);
       
  1922 
       
  1923     d->priv->beginEditBlock();
       
  1924     d->remove();
       
  1925     d->insertBlock(format, charFormat);
       
  1926     d->priv->endEditBlock();
       
  1927     d->setX();
       
  1928 }
       
  1929 
       
  1930 /*!
       
  1931     Inserts a new block at the current position and makes it the first
       
  1932     list item of a newly created list with the given \a format. Returns
       
  1933     the created list.
       
  1934 
       
  1935     \sa currentList() createList() insertBlock()
       
  1936  */
       
  1937 QTextList *QTextCursor::insertList(const QTextListFormat &format)
       
  1938 {
       
  1939     insertBlock();
       
  1940     return createList(format);
       
  1941 }
       
  1942 
       
  1943 /*!
       
  1944     \overload
       
  1945 
       
  1946     Inserts a new block at the current position and makes it the first
       
  1947     list item of a newly created list with the given \a style. Returns
       
  1948     the created list.
       
  1949 
       
  1950     \sa currentList(), createList(), insertBlock()
       
  1951  */
       
  1952 QTextList *QTextCursor::insertList(QTextListFormat::Style style)
       
  1953 {
       
  1954     insertBlock();
       
  1955     return createList(style);
       
  1956 }
       
  1957 
       
  1958 /*!
       
  1959     Creates and returns a new list with the given \a format, and makes the
       
  1960     current paragraph the cursor is in the first list item.
       
  1961 
       
  1962     \sa insertList() currentList()
       
  1963  */
       
  1964 QTextList *QTextCursor::createList(const QTextListFormat &format)
       
  1965 {
       
  1966     if (!d || !d->priv)
       
  1967         return 0;
       
  1968 
       
  1969     QTextList *list = static_cast<QTextList *>(d->priv->createObject(format));
       
  1970     QTextBlockFormat modifier;
       
  1971     modifier.setObjectIndex(list->objectIndex());
       
  1972     mergeBlockFormat(modifier);
       
  1973     return list;
       
  1974 }
       
  1975 
       
  1976 /*!
       
  1977     \overload
       
  1978 
       
  1979     Creates and returns a new list with the given \a style, making the
       
  1980     cursor's current paragraph the first list item.
       
  1981 
       
  1982     The style to be used is defined by the QTextListFormat::Style enum.
       
  1983 
       
  1984     \sa insertList() currentList()
       
  1985  */
       
  1986 QTextList *QTextCursor::createList(QTextListFormat::Style style)
       
  1987 {
       
  1988     QTextListFormat fmt;
       
  1989     fmt.setStyle(style);
       
  1990     return createList(fmt);
       
  1991 }
       
  1992 
       
  1993 /*!
       
  1994     Returns the current list if the cursor position() is inside a
       
  1995     block that is part of a list; otherwise returns 0.
       
  1996 
       
  1997     \sa insertList() createList()
       
  1998  */
       
  1999 QTextList *QTextCursor::currentList() const
       
  2000 {
       
  2001     if (!d || !d->priv)
       
  2002         return 0;
       
  2003 
       
  2004     QTextBlockFormat b = blockFormat();
       
  2005     QTextObject *o = d->priv->objectForFormat(b);
       
  2006     return qobject_cast<QTextList *>(o);
       
  2007 }
       
  2008 
       
  2009 /*!
       
  2010     \fn QTextTable *QTextCursor::insertTable(int rows, int columns)
       
  2011 
       
  2012     \overload
       
  2013 
       
  2014     Creates a new table with the given number of \a rows and \a columns,
       
  2015     inserts it at the current cursor position() in the document, and returns
       
  2016     the table object. The cursor is moved to the beginning of the first cell.
       
  2017 
       
  2018     There must be at least one row and one column in the table.
       
  2019 
       
  2020     \sa currentTable()
       
  2021  */
       
  2022 QTextTable *QTextCursor::insertTable(int rows, int cols)
       
  2023 {
       
  2024     return insertTable(rows, cols, QTextTableFormat());
       
  2025 }
       
  2026 
       
  2027 /*!
       
  2028     \fn QTextTable *QTextCursor::insertTable(int rows, int columns, const QTextTableFormat &format)
       
  2029 
       
  2030     Creates a new table with the given number of \a rows and \a columns
       
  2031     in the specified \a format, inserts it at the current cursor position()
       
  2032     in the document, and returns the table object. The cursor is moved to
       
  2033     the beginning of the first cell.
       
  2034 
       
  2035     There must be at least one row and one column in the table.
       
  2036 
       
  2037     \sa currentTable()
       
  2038 */
       
  2039 QTextTable *QTextCursor::insertTable(int rows, int cols, const QTextTableFormat &format)
       
  2040 {
       
  2041     if(!d || !d->priv || rows == 0 || cols == 0)
       
  2042         return 0;
       
  2043 
       
  2044     int pos = d->position;
       
  2045     QTextTable *t = QTextTablePrivate::createTable(d->priv, d->position, rows, cols, format);
       
  2046     d->setPosition(pos+1);
       
  2047     // ##### what should we do if we have a selection?
       
  2048     d->anchor = d->position;
       
  2049     d->adjusted_anchor = d->anchor;
       
  2050     return t;
       
  2051 }
       
  2052 
       
  2053 /*!
       
  2054     Returns a pointer to the current table if the cursor position()
       
  2055     is inside a block that is part of a table; otherwise returns 0.
       
  2056 
       
  2057     \sa insertTable()
       
  2058 */
       
  2059 QTextTable *QTextCursor::currentTable() const
       
  2060 {
       
  2061     if(!d || !d->priv)
       
  2062         return 0;
       
  2063 
       
  2064     QTextFrame *frame = d->priv->frameAt(d->position);
       
  2065     while (frame) {
       
  2066         QTextTable *table = qobject_cast<QTextTable *>(frame);
       
  2067         if (table)
       
  2068             return table;
       
  2069         frame = frame->parentFrame();
       
  2070     }
       
  2071     return 0;
       
  2072 }
       
  2073 
       
  2074 /*!
       
  2075     Inserts a frame with the given \a format at the current cursor position(),
       
  2076     moves the cursor position() inside the frame, and returns the frame.
       
  2077 
       
  2078     If the cursor holds a selection, the whole selection is moved inside the
       
  2079     frame.
       
  2080 
       
  2081     \sa hasSelection()
       
  2082 */
       
  2083 QTextFrame *QTextCursor::insertFrame(const QTextFrameFormat &format)
       
  2084 {
       
  2085     if (!d || !d->priv)
       
  2086         return 0;
       
  2087 
       
  2088     return d->priv->insertFrame(selectionStart(), selectionEnd(), format);
       
  2089 }
       
  2090 
       
  2091 /*!
       
  2092     Returns a pointer to the current frame. Returns 0 if the cursor is invalid.
       
  2093 
       
  2094     \sa insertFrame()
       
  2095 */
       
  2096 QTextFrame *QTextCursor::currentFrame() const
       
  2097 {
       
  2098     if(!d || !d->priv)
       
  2099         return 0;
       
  2100 
       
  2101     return d->priv->frameAt(d->position);
       
  2102 }
       
  2103 
       
  2104 
       
  2105 /*!
       
  2106     Inserts the text \a fragment at the current position().
       
  2107 */
       
  2108 void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
       
  2109 {
       
  2110     if (!d || !d->priv || fragment.isEmpty())
       
  2111         return;
       
  2112 
       
  2113     d->priv->beginEditBlock();
       
  2114     d->remove();
       
  2115     fragment.d->insert(*this);
       
  2116     d->priv->endEditBlock();
       
  2117 
       
  2118     if (fragment.d && fragment.d->doc)
       
  2119         d->priv->mergeCachedResources(fragment.d->doc->docHandle());
       
  2120 }
       
  2121 
       
  2122 /*!
       
  2123     \since 4.2
       
  2124     Inserts the text \a html at the current position(). The text is interpreted as
       
  2125     HTML.
       
  2126 
       
  2127     \note When using this function with a style sheet, the style sheet will
       
  2128     only apply to the current block in the document. In order to apply a style
       
  2129     sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
       
  2130     instead.
       
  2131 */
       
  2132 
       
  2133 #ifndef QT_NO_TEXTHTMLPARSER
       
  2134 
       
  2135 void QTextCursor::insertHtml(const QString &html)
       
  2136 {
       
  2137     if (!d || !d->priv)
       
  2138         return;
       
  2139     QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html, d->priv->document());
       
  2140     insertFragment(fragment);
       
  2141 }
       
  2142 
       
  2143 #endif // QT_NO_TEXTHTMLPARSER
       
  2144 
       
  2145 /*!
       
  2146     \overload
       
  2147     \since 4.2
       
  2148 
       
  2149     Inserts the image defined by the given \a format at the cursor's current position
       
  2150     with the specified \a alignment.
       
  2151 
       
  2152     \sa position()
       
  2153 */
       
  2154 void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
       
  2155 {
       
  2156     if (!d || !d->priv)
       
  2157         return;
       
  2158 
       
  2159     QTextFrameFormat ffmt;
       
  2160     ffmt.setPosition(alignment);
       
  2161     QTextObject *obj = d->priv->createObject(ffmt);
       
  2162 
       
  2163     QTextImageFormat fmt = format;
       
  2164     fmt.setObjectIndex(obj->objectIndex());
       
  2165 
       
  2166     d->priv->beginEditBlock();
       
  2167     d->remove();
       
  2168     const int idx = d->priv->formatCollection()->indexForFormat(fmt);
       
  2169     d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
       
  2170     d->priv->endEditBlock();
       
  2171 }
       
  2172 
       
  2173 /*!
       
  2174     Inserts the image defined by \a format at the current position().
       
  2175 */
       
  2176 void QTextCursor::insertImage(const QTextImageFormat &format)
       
  2177 {
       
  2178     insertText(QString(QChar::ObjectReplacementCharacter), format);
       
  2179 }
       
  2180 
       
  2181 /*!
       
  2182     \overload
       
  2183 
       
  2184     Convenience method for inserting the image with the given \a name at the
       
  2185     current position().
       
  2186 
       
  2187     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 1
       
  2188 */
       
  2189 void QTextCursor::insertImage(const QString &name)
       
  2190 {
       
  2191     QTextImageFormat format;
       
  2192     format.setName(name);
       
  2193     insertImage(format);
       
  2194 }
       
  2195 
       
  2196 /*!
       
  2197     \since 4.5
       
  2198     \overload
       
  2199 
       
  2200     Convenience function for inserting the given \a image with an optional
       
  2201     \a name at the current position().
       
  2202 */
       
  2203 void QTextCursor::insertImage(const QImage &image, const QString &name)
       
  2204 {
       
  2205     if (image.isNull()) {
       
  2206         qWarning("QTextCursor::insertImage: attempt to add an invalid image");
       
  2207         return;
       
  2208     }
       
  2209     QString imageName = name;
       
  2210     if (name.isEmpty())
       
  2211         imageName = QString::number(image.serialNumber());
       
  2212     d->priv->document()->addResource(QTextDocument::ImageResource, QUrl(imageName), image);
       
  2213     QTextImageFormat format;
       
  2214     format.setName(imageName);
       
  2215     insertImage(format);
       
  2216 }
       
  2217 
       
  2218 /*!
       
  2219     \fn bool QTextCursor::operator!=(const QTextCursor &other) const
       
  2220 
       
  2221     Returns true if the \a other cursor is at a different position in
       
  2222     the document as this cursor; otherwise returns false.
       
  2223 */
       
  2224 bool QTextCursor::operator!=(const QTextCursor &rhs) const
       
  2225 {
       
  2226     return !operator==(rhs);
       
  2227 }
       
  2228 
       
  2229 /*!
       
  2230     \fn bool QTextCursor::operator<(const QTextCursor &other) const
       
  2231 
       
  2232     Returns true if the \a other cursor is positioned later in the
       
  2233     document than this cursor; otherwise returns false.
       
  2234 */
       
  2235 bool QTextCursor::operator<(const QTextCursor &rhs) const
       
  2236 {
       
  2237     if (!d)
       
  2238         return !!rhs.d;
       
  2239 
       
  2240     if (!rhs.d)
       
  2241         return false;
       
  2242 
       
  2243     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<", "cannot compare cursors attached to different documents");
       
  2244 
       
  2245     return d->position < rhs.d->position;
       
  2246 }
       
  2247 
       
  2248 /*!
       
  2249     \fn bool QTextCursor::operator<=(const QTextCursor &other) const
       
  2250 
       
  2251     Returns true if the \a other cursor is positioned later or at the
       
  2252     same position in the document as this cursor; otherwise returns
       
  2253     false.
       
  2254 */
       
  2255 bool QTextCursor::operator<=(const QTextCursor &rhs) const
       
  2256 {
       
  2257     if (!d)
       
  2258         return true;
       
  2259 
       
  2260     if (!rhs.d)
       
  2261         return false;
       
  2262 
       
  2263     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<=", "cannot compare cursors attached to different documents");
       
  2264 
       
  2265     return d->position <= rhs.d->position;
       
  2266 }
       
  2267 
       
  2268 /*!
       
  2269     \fn bool QTextCursor::operator==(const QTextCursor &other) const
       
  2270 
       
  2271     Returns true if the \a other cursor is at the same position in the
       
  2272     document as this cursor; otherwise returns false.
       
  2273 */
       
  2274 bool QTextCursor::operator==(const QTextCursor &rhs) const
       
  2275 {
       
  2276     if (!d)
       
  2277         return !rhs.d;
       
  2278 
       
  2279     if (!rhs.d)
       
  2280         return false;
       
  2281 
       
  2282     return d->position == rhs.d->position && d->priv == rhs.d->priv;
       
  2283 }
       
  2284 
       
  2285 /*!
       
  2286     \fn bool QTextCursor::operator>=(const QTextCursor &other) const
       
  2287 
       
  2288     Returns true if the \a other cursor is positioned earlier or at the
       
  2289     same position in the document as this cursor; otherwise returns
       
  2290     false.
       
  2291 */
       
  2292 bool QTextCursor::operator>=(const QTextCursor &rhs) const
       
  2293 {
       
  2294     if (!d)
       
  2295         return false;
       
  2296 
       
  2297     if (!rhs.d)
       
  2298         return true;
       
  2299 
       
  2300     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>=", "cannot compare cursors attached to different documents");
       
  2301 
       
  2302     return d->position >= rhs.d->position;
       
  2303 }
       
  2304 
       
  2305 /*!
       
  2306     \fn bool QTextCursor::operator>(const QTextCursor &other) const
       
  2307 
       
  2308     Returns true if the \a other cursor is positioned earlier in the
       
  2309     document than this cursor; otherwise returns false.
       
  2310 */
       
  2311 bool QTextCursor::operator>(const QTextCursor &rhs) const
       
  2312 {
       
  2313     if (!d)
       
  2314         return false;
       
  2315 
       
  2316     if (!rhs.d)
       
  2317         return true;
       
  2318 
       
  2319     Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>", "cannot compare cursors attached to different documents");
       
  2320 
       
  2321     return d->position > rhs.d->position;
       
  2322 }
       
  2323 
       
  2324 /*!
       
  2325     Indicates the start of a block of editing operations on the
       
  2326     document that should appear as a single operation from an
       
  2327     undo/redo point of view.
       
  2328 
       
  2329     For example:
       
  2330 
       
  2331     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 2
       
  2332 
       
  2333     The call to undo() will cause both insertions to be undone,
       
  2334     causing both "World" and "Hello" to be removed.
       
  2335 
       
  2336     It is possible to nest calls to beginEditBlock and endEditBlock. The
       
  2337     top-most pair will determine the scope of the undo/redo operation.
       
  2338 
       
  2339     \sa endEditBlock()
       
  2340  */
       
  2341 void QTextCursor::beginEditBlock()
       
  2342 {
       
  2343     if (!d || !d->priv)
       
  2344         return;
       
  2345 
       
  2346     d->priv->beginEditBlock();
       
  2347 }
       
  2348 
       
  2349 /*!
       
  2350     Like beginEditBlock() indicates the start of a block of editing operations
       
  2351     that should appear as a single operation for undo/redo. However unlike
       
  2352     beginEditBlock() it does not start a new block but reverses the previous call to
       
  2353     endEditBlock() and therefore makes following operations part of the previous edit block created.
       
  2354 
       
  2355     For example:
       
  2356 
       
  2357     \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 3
       
  2358 
       
  2359     The call to undo() will cause all three insertions to be undone.
       
  2360 
       
  2361     \sa beginEditBlock(), endEditBlock()
       
  2362  */
       
  2363 void QTextCursor::joinPreviousEditBlock()
       
  2364 {
       
  2365     if (!d || !d->priv)
       
  2366         return;
       
  2367 
       
  2368     d->priv->joinPreviousEditBlock();
       
  2369 }
       
  2370 
       
  2371 /*!
       
  2372     Indicates the end of a block of editing operations on the document
       
  2373     that should appear as a single operation from an undo/redo point
       
  2374     of view.
       
  2375 
       
  2376     \sa beginEditBlock()
       
  2377  */
       
  2378 
       
  2379 void QTextCursor::endEditBlock()
       
  2380 {
       
  2381     if (!d || !d->priv)
       
  2382         return;
       
  2383 
       
  2384     d->priv->endEditBlock();
       
  2385 }
       
  2386 
       
  2387 /*!
       
  2388     Returns true if this cursor and \a other are copies of each other, i.e.
       
  2389     one of them was created as a copy of the other and neither has moved since.
       
  2390     This is much stricter than equality.
       
  2391 
       
  2392     \sa operator=() operator==()
       
  2393 */
       
  2394 bool QTextCursor::isCopyOf(const QTextCursor &other) const
       
  2395 {
       
  2396     return d == other.d;
       
  2397 }
       
  2398 
       
  2399 /*!
       
  2400     \since 4.2
       
  2401     Returns the number of the block the cursor is in, or 0 if the cursor is invalid.
       
  2402 
       
  2403     Note that this function only makes sense in documents without complex objects such
       
  2404     as tables or frames.
       
  2405 */
       
  2406 int QTextCursor::blockNumber() const
       
  2407 {
       
  2408     if (!d || !d->priv)
       
  2409         return 0;
       
  2410 
       
  2411     return d->block().blockNumber();
       
  2412 }
       
  2413 
       
  2414 /*!
       
  2415     \since 4.2
       
  2416     Returns the position of the cursor within its containing line.
       
  2417 */
       
  2418 int QTextCursor::columnNumber() const
       
  2419 {
       
  2420     if (!d || !d->priv)
       
  2421         return 0;
       
  2422 
       
  2423     QTextBlock block = d->block();
       
  2424     if (!block.isValid())
       
  2425         return 0;
       
  2426 
       
  2427     const QTextLayout *layout = d->blockLayout(block);
       
  2428 
       
  2429     const int relativePos = d->position - block.position();
       
  2430 
       
  2431     if (layout->lineCount() == 0)
       
  2432         return relativePos;
       
  2433 
       
  2434     QTextLine line = layout->lineForTextPosition(relativePos);
       
  2435     if (!line.isValid())
       
  2436         return 0;
       
  2437     return relativePos - line.textStart();
       
  2438 }
       
  2439 
       
  2440 /*!
       
  2441     \since 4.5
       
  2442     Returns the document this cursor is associated with.
       
  2443 */
       
  2444 QTextDocument *QTextCursor::document() const
       
  2445 {
       
  2446     if (d->priv)
       
  2447         return d->priv->document();
       
  2448     return 0; // document went away
       
  2449 }
       
  2450 
       
  2451 QT_END_NAMESPACE