1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qtextcursor.h"
43 #include "qtextcursor_p.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"
53 #include <qtextlayout.h>
65 QTextCursorPrivate::QTextCursorPrivate(QTextDocumentPrivate *p)
66 : priv(p), x(0), position(0), anchor(0), adjusted_anchor(0),
67 currentCharFormat(-1), visualNavigation(false), keepPositionOnInsert(false),
70 priv->addCursor(this);
73 QTextCursorPrivate::QTextCursorPrivate(const QTextCursorPrivate &rhs)
76 position = rhs.position;
78 adjusted_anchor = rhs.adjusted_anchor;
81 currentCharFormat = rhs.currentCharFormat;
82 visualNavigation = rhs.visualNavigation;
83 keepPositionOnInsert = rhs.keepPositionOnInsert;
84 changed = rhs.changed;
85 priv->addCursor(this);
88 QTextCursorPrivate::~QTextCursorPrivate()
91 priv->removeCursor(this);
94 QTextCursorPrivate::AdjustResult QTextCursorPrivate::adjustPosition(int positionOfChange, int charsAddedOrRemoved, QTextUndoCommand::Operation op)
96 QTextCursorPrivate::AdjustResult result = QTextCursorPrivate::CursorMoved;
97 // not(!) <= , so that inserting text adjusts the cursor correctly
98 if (position < positionOfChange
99 || (position == positionOfChange
100 && (op == QTextUndoCommand::KeepCursor
101 || keepPositionOnInsert)
104 result = CursorUnchanged;
106 if (charsAddedOrRemoved < 0 && position < positionOfChange - charsAddedOrRemoved)
107 position = positionOfChange;
109 position += charsAddedOrRemoved;
111 currentCharFormat = -1;
114 if (anchor >= positionOfChange
115 && (anchor != positionOfChange || op != QTextUndoCommand::KeepCursor)) {
116 if (charsAddedOrRemoved < 0 && anchor < positionOfChange - charsAddedOrRemoved)
117 anchor = positionOfChange;
119 anchor += charsAddedOrRemoved;
122 if (adjusted_anchor >= positionOfChange
123 && (adjusted_anchor != positionOfChange || op != QTextUndoCommand::KeepCursor)) {
124 if (charsAddedOrRemoved < 0 && adjusted_anchor < positionOfChange - charsAddedOrRemoved)
125 adjusted_anchor = positionOfChange;
127 adjusted_anchor += charsAddedOrRemoved;
133 void QTextCursorPrivate::setX()
135 if (priv->isInEditBlock()) {
136 x = -1; // mark dirty
140 QTextBlock block = this->block();
141 const QTextLayout *layout = blockLayout(block);
142 int pos = position - block.position();
144 QTextLine line = layout->lineForTextPosition(pos);
146 x = line.cursorToX(pos);
148 x = -1; // delayed init. Makes movePosition() call setX later on again.
151 void QTextCursorPrivate::remove()
153 if (anchor == position)
155 currentCharFormat = -1;
157 int pos2 = adjusted_anchor;
158 QTextUndoCommand::Operation op = QTextUndoCommand::KeepCursor;
160 pos1 = adjusted_anchor;
162 op = QTextUndoCommand::MoveCursor;
165 // deleting inside table? -> delete only content
166 QTextTable *table = complexSelectionTable();
168 priv->beginEditBlock();
169 int startRow, startCol, numRows, numCols;
170 selectedTableCells(&startRow, &numRows, &startCol, &numCols);
171 clearCells(table, startRow, startCol, numRows, numCols, op);
172 adjusted_anchor = anchor = position;
173 priv->endEditBlock();
175 priv->remove(pos1, pos2-pos1, op);
176 adjusted_anchor = anchor = position;
182 void QTextCursorPrivate::clearCells(QTextTable *table, int startRow, int startCol, int numRows, int numCols, QTextUndoCommand::Operation op)
184 priv->beginEditBlock();
186 for (int row = startRow; row < startRow + numRows; ++row)
187 for (int col = startCol; col < startCol + numCols; ++col) {
188 QTextTableCell cell = table->cellAt(row, col);
189 const int startPos = cell.firstPosition();
190 const int endPos = cell.lastPosition();
191 Q_ASSERT(startPos <= endPos);
192 priv->remove(startPos, endPos - startPos, op);
195 priv->endEditBlock();
198 bool QTextCursorPrivate::canDelete(int pos) const
200 QTextDocumentPrivate::FragmentIterator fit = priv->find(pos);
201 QTextCharFormat fmt = priv->formatCollection()->charFormat((*fit)->format);
202 return (fmt.objectIndex() == -1 || fmt.objectType() == QTextFormat::ImageObject);
205 void QTextCursorPrivate::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
207 QTextFormatCollection *formats = priv->formatCollection();
208 int idx = formats->indexForFormat(format);
209 Q_ASSERT(formats->format(idx).isBlockFormat());
211 priv->insertBlock(position, idx, formats->indexForFormat(charFormat));
212 currentCharFormat = -1;
215 void QTextCursorPrivate::adjustCursor(QTextCursor::MoveOperation m)
217 adjusted_anchor = anchor;
218 if (position == anchor)
221 QTextFrame *f_position = priv->frameAt(position);
222 QTextFrame *f_anchor = priv->frameAt(adjusted_anchor);
224 if (f_position != f_anchor) {
225 // find common parent frame
226 QList<QTextFrame *> positionChain;
227 QList<QTextFrame *> anchorChain;
228 QTextFrame *f = f_position;
230 positionChain.prepend(f);
231 f = f->parentFrame();
235 anchorChain.prepend(f);
236 f = f->parentFrame();
238 Q_ASSERT(positionChain.at(0) == anchorChain.at(0));
240 int l = qMin(positionChain.size(), anchorChain.size());
242 if (positionChain.at(i) != anchorChain.at(i))
246 if (m <= QTextCursor::WordLeft) {
247 if (i < positionChain.size())
248 position = positionChain.at(i)->firstPosition() - 1;
250 if (i < positionChain.size())
251 position = positionChain.at(i)->lastPosition() + 1;
253 if (position < adjusted_anchor) {
254 if (i < anchorChain.size())
255 adjusted_anchor = anchorChain.at(i)->lastPosition() + 1;
257 if (i < anchorChain.size())
258 adjusted_anchor = anchorChain.at(i)->firstPosition() - 1;
261 f_position = positionChain.at(i-1);
264 // same frame, either need to adjust to cell boundaries or return
265 QTextTable *table = qobject_cast<QTextTable *>(f_position);
269 QTextTableCell c_position = table->cellAt(position);
270 QTextTableCell c_anchor = table->cellAt(adjusted_anchor);
271 if (c_position != c_anchor) {
273 int col_position = c_position.column();
274 int col_anchor = c_anchor.column();
275 if (col_position == col_anchor) {
276 before = c_position.row() < c_anchor.row();
278 before = col_position < col_anchor;
281 // adjust to cell boundaries
282 if (m <= QTextCursor::WordLeft) {
283 position = c_position.firstPosition();
287 position = c_position.lastPosition();
291 if (position < adjusted_anchor)
292 adjusted_anchor = c_anchor.lastPosition();
294 adjusted_anchor = c_anchor.firstPosition();
296 currentCharFormat = -1;
299 void QTextCursorPrivate::aboutToRemoveCell(int from, int to)
301 Q_ASSERT(from <= to);
302 if (position == anchor)
305 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
308 QTextTableCell removedCellFrom = t->cellAt(from);
309 QTextTableCell removedCellEnd = t->cellAt(to);
310 if (! removedCellFrom.isValid() || !removedCellEnd.isValid())
313 int curFrom = position;
314 int curTo = adjusted_anchor;
316 qSwap(curFrom, curTo);
318 QTextTableCell cellStart = t->cellAt(curFrom);
319 QTextTableCell cellEnd = t->cellAt(curTo);
321 if (cellStart.row() >= removedCellFrom.row() && cellEnd.row() <= removedCellEnd.row()
322 && cellStart.column() >= removedCellFrom.column()
323 && cellEnd.column() <= removedCellEnd.column()) { // selection is completely removed
324 // find a new position, as close as possible to where we were.
326 if (removedCellFrom.row() == 0 && removedCellEnd.row() == t->rows()-1) // removed n columns
327 cell = t->cellAt(cellStart.row(), removedCellEnd.column()+1);
328 else if (removedCellFrom.column() == 0 && removedCellEnd.column() == t->columns()-1) // removed n rows
329 cell = t->cellAt(removedCellEnd.row() + 1, cellStart.column());
333 newPosition = cell.firstPosition();
335 newPosition = t->lastPosition()+1;
337 setPosition(newPosition);
338 anchor = newPosition;
339 adjusted_anchor = newPosition;
342 else if (cellStart.row() >= removedCellFrom.row() && cellStart.row() <= removedCellEnd.row()
343 && cellEnd.row() > removedCellEnd.row()) {
344 int newPosition = t->cellAt(removedCellEnd.row() + 1, cellStart.column()).firstPosition();
345 if (position < anchor)
346 position = newPosition;
348 anchor = adjusted_anchor = newPosition;
350 else if (cellStart.column() >= removedCellFrom.column() && cellStart.column() <= removedCellEnd.column()
351 && cellEnd.column() > removedCellEnd.column()) {
352 int newPosition = t->cellAt(cellStart.row(), removedCellEnd.column()+1).firstPosition();
353 if (position < anchor)
354 position = newPosition;
356 anchor = adjusted_anchor = newPosition;
360 bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
362 currentCharFormat = -1;
364 QTextBlock blockIt = block();
365 bool visualMovement = priv->defaultCursorMoveStyle == Qt::VisualMoveStyle;
367 if (!blockIt.isValid())
370 if (blockIt.textDirection() == Qt::RightToLeft) {
371 if (op == QTextCursor::WordLeft)
372 op = QTextCursor::NextWord;
373 else if (op == QTextCursor::WordRight)
374 op = QTextCursor::PreviousWord;
376 if (!visualMovement) {
377 if (op == QTextCursor::Left)
378 op = QTextCursor::NextCharacter;
379 else if (op == QTextCursor::Right)
380 op = QTextCursor::PreviousCharacter;
384 const QTextLayout *layout = blockLayout(blockIt);
385 int relativePos = position - blockIt.position();
387 if (!priv->isInEditBlock())
388 line = layout->lineForTextPosition(relativePos);
390 Q_ASSERT(priv->frameAt(position) == priv->frameAt(adjusted_anchor));
392 int newPosition = position;
394 if (x == -1 && !priv->isInEditBlock() && (op == QTextCursor::Up || op == QTextCursor::Down))
398 case QTextCursor::NoMove:
401 case QTextCursor::Start:
404 case QTextCursor::StartOfLine: {
405 newPosition = blockIt.position();
407 newPosition += line.textStart();
411 case QTextCursor::StartOfBlock: {
412 newPosition = blockIt.position();
415 case QTextCursor::PreviousBlock: {
416 if (blockIt == priv->blocksBegin())
418 blockIt = blockIt.previous();
420 newPosition = blockIt.position();
423 case QTextCursor::PreviousCharacter:
424 newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
426 case QTextCursor::Left:
427 newPosition = visualMovement ? priv->leftCursorPosition(position)
428 : priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
430 case QTextCursor::StartOfWord: {
431 if (relativePos == 0)
434 // skip if already at word start
435 QTextEngine *engine = layout->engine();
436 engine->attributes();
437 if ((relativePos == blockIt.length() - 1)
438 && (engine->atSpace(relativePos - 1) || engine->atWordSeparator(relativePos - 1)))
441 if (relativePos < blockIt.length()-1)
446 case QTextCursor::PreviousWord:
447 case QTextCursor::WordLeft:
448 newPosition = priv->previousCursorPosition(position, QTextLayout::SkipWords);
450 case QTextCursor::Up: {
451 int i = line.lineNumber() - 1;
453 if (blockIt == priv->blocksBegin())
455 int blockPosition = blockIt.position();
456 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(blockPosition));
458 QTextTableCell cell = table->cellAt(blockPosition);
459 if (cell.firstPosition() == blockPosition) {
460 int row = cell.row() - 1;
462 blockPosition = table->cellAt(row, cell.column()).lastPosition();
464 // move to line above the table
465 blockPosition = table->firstPosition() - 1;
467 blockIt = priv->blocksFind(blockPosition);
469 blockIt = blockIt.previous();
472 blockIt = blockIt.previous();
474 layout = blockLayout(blockIt);
475 i = layout->lineCount()-1;
477 if (layout->lineCount()) {
478 QTextLine line = layout->lineAt(i);
479 newPosition = line.xToCursor(x) + blockIt.position();
481 newPosition = blockIt.position();
487 case QTextCursor::End:
488 newPosition = priv->length() - 1;
490 case QTextCursor::EndOfLine: {
491 if (!line.isValid() || line.textLength() == 0) {
492 if (blockIt.length() >= 1)
493 // position right before the block separator
494 newPosition = blockIt.position() + blockIt.length() - 1;
497 newPosition = blockIt.position() + line.textStart() + line.textLength();
498 if (line.lineNumber() < layout->lineCount() - 1) {
499 const QString text = blockIt.text();
500 // ###### this relies on spaces being the cause for linebreaks.
501 // this doesn't work with japanese
502 if (text.at(line.textStart() + line.textLength() - 1).isSpace())
507 case QTextCursor::EndOfWord: {
508 QTextEngine *engine = layout->engine();
509 engine->attributes();
510 const int len = blockIt.length() - 1;
511 if (relativePos >= len)
513 if (engine->atWordSeparator(relativePos)) {
515 while (relativePos < len && engine->atWordSeparator(relativePos))
518 while (relativePos < len && !engine->atSpace(relativePos) && !engine->atWordSeparator(relativePos))
521 newPosition = blockIt.position() + relativePos;
524 case QTextCursor::EndOfBlock:
525 if (blockIt.length() >= 1)
526 // position right before the block separator
527 newPosition = blockIt.position() + blockIt.length() - 1;
529 case QTextCursor::NextBlock: {
530 blockIt = blockIt.next();
531 if (!blockIt.isValid())
534 newPosition = blockIt.position();
537 case QTextCursor::NextCharacter:
538 newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
540 case QTextCursor::Right:
541 newPosition = visualMovement ? priv->rightCursorPosition(position)
542 : priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
544 case QTextCursor::NextWord:
545 case QTextCursor::WordRight:
546 newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords);
549 case QTextCursor::Down: {
550 int i = line.lineNumber() + 1;
552 if (i >= layout->lineCount()) {
553 int blockPosition = blockIt.position() + blockIt.length() - 1;
554 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(blockPosition));
556 QTextTableCell cell = table->cellAt(blockPosition);
557 if (cell.lastPosition() == blockPosition) {
558 int row = cell.row() + cell.rowSpan();
559 if (row < table->rows()) {
560 blockPosition = table->cellAt(row, cell.column()).firstPosition();
562 // move to line below the table
563 blockPosition = table->lastPosition() + 1;
565 blockIt = priv->blocksFind(blockPosition);
567 blockIt = blockIt.next();
570 blockIt = blockIt.next();
573 if (blockIt == priv->blocksEnd())
575 layout = blockLayout(blockIt);
578 if (layout->lineCount()) {
579 QTextLine line = layout->lineAt(i);
580 newPosition = line.xToCursor(x) + blockIt.position();
582 newPosition = blockIt.position();
587 case QTextCursor::NextCell: // fall through
588 case QTextCursor::PreviousCell: // fall through
589 case QTextCursor::NextRow: // fall through
590 case QTextCursor::PreviousRow: {
591 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
595 QTextTableCell cell = table->cellAt(position);
596 Q_ASSERT(cell.isValid());
597 int column = cell.column();
598 int row = cell.row();
599 const int currentRow = row;
600 if (op == QTextCursor::NextCell || op == QTextCursor::NextRow) {
602 column += cell.columnSpan();
603 if (column >= table->columns()) {
607 cell = table->cellAt(row, column);
608 // note we also continue while we have not reached a cell thats not merged with one above us
609 } while (cell.isValid()
610 && ((op == QTextCursor::NextRow && currentRow == cell.row())
611 || cell.row() < row));
613 else if (op == QTextCursor::PreviousCell || op == QTextCursor::PreviousRow) {
617 column = table->columns()-1;
620 cell = table->cellAt(row, column);
621 // note we also continue while we have not reached a cell thats not merged with one above us
622 } while (cell.isValid()
623 && ((op == QTextCursor::PreviousRow && currentRow == cell.row())
624 || cell.row() < row));
627 newPosition = cell.firstPosition();
632 if (mode == QTextCursor::KeepAnchor) {
633 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
634 if (table && ((op >= QTextCursor::PreviousBlock && op <= QTextCursor::WordLeft)
635 || (op >= QTextCursor::NextBlock && op <= QTextCursor::WordRight))) {
636 int oldColumn = table->cellAt(position).column();
638 const QTextTableCell otherCell = table->cellAt(newPosition);
639 if (!otherCell.isValid())
642 int newColumn = otherCell.column();
643 if ((oldColumn > newColumn && op >= QTextCursor::End)
644 || (oldColumn < newColumn && op <= QTextCursor::WordLeft))
649 const bool moved = setPosition(newPosition);
651 if (mode == QTextCursor::MoveAnchor) {
653 adjusted_anchor = position;
664 QTextTable *QTextCursorPrivate::complexSelectionTable() const
666 if (position == anchor)
669 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
671 QTextTableCell cell_pos = t->cellAt(position);
672 QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
674 Q_ASSERT(cell_anchor.isValid());
676 if (cell_pos == cell_anchor)
682 void QTextCursorPrivate::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
689 if (position == anchor)
692 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
696 QTextTableCell cell_pos = t->cellAt(position);
697 QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
699 Q_ASSERT(cell_anchor.isValid());
701 if (cell_pos == cell_anchor)
704 *firstRow = qMin(cell_pos.row(), cell_anchor.row());
705 *firstColumn = qMin(cell_pos.column(), cell_anchor.column());
706 *numRows = qMax(cell_pos.row() + cell_pos.rowSpan(), cell_anchor.row() + cell_anchor.rowSpan()) - *firstRow;
707 *numColumns = qMax(cell_pos.column() + cell_pos.columnSpan(), cell_anchor.column() + cell_anchor.columnSpan()) - *firstColumn;
710 static void setBlockCharFormatHelper(QTextDocumentPrivate *priv, int pos1, int pos2,
711 const QTextCharFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
713 QTextBlock it = priv->blocksFind(pos1);
714 QTextBlock end = priv->blocksFind(pos2);
718 for (; it != end; it = it.next()) {
719 priv->setCharFormat(it.position() - 1, 1, format, changeMode);
723 void QTextCursorPrivate::setBlockCharFormat(const QTextCharFormat &_format,
724 QTextDocumentPrivate::FormatChangeMode changeMode)
726 priv->beginEditBlock();
728 QTextCharFormat format = _format;
729 format.clearProperty(QTextFormat::ObjectIndex);
731 QTextTable *table = complexSelectionTable();
733 int row_start, col_start, num_rows, num_cols;
734 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
736 Q_ASSERT(row_start != -1);
737 for (int r = row_start; r < row_start + num_rows; ++r) {
738 for (int c = col_start; c < col_start + num_cols; ++c) {
739 QTextTableCell cell = table->cellAt(r, c);
740 int rspan = cell.rowSpan();
741 int cspan = cell.columnSpan();
748 int cc = cell.column();
753 int pos1 = cell.firstPosition();
754 int pos2 = cell.lastPosition();
755 setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
760 int pos2 = adjusted_anchor;
762 pos1 = adjusted_anchor;
766 setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
768 priv->endEditBlock();
772 void QTextCursorPrivate::setBlockFormat(const QTextBlockFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
774 QTextTable *table = complexSelectionTable();
776 priv->beginEditBlock();
777 int row_start, col_start, num_rows, num_cols;
778 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
780 Q_ASSERT(row_start != -1);
781 for (int r = row_start; r < row_start + num_rows; ++r) {
782 for (int c = col_start; c < col_start + num_cols; ++c) {
783 QTextTableCell cell = table->cellAt(r, c);
784 int rspan = cell.rowSpan();
785 int cspan = cell.columnSpan();
792 int cc = cell.column();
797 int pos1 = cell.firstPosition();
798 int pos2 = cell.lastPosition();
799 priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
802 priv->endEditBlock();
805 int pos2 = adjusted_anchor;
807 pos1 = adjusted_anchor;
811 priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
815 void QTextCursorPrivate::setCharFormat(const QTextCharFormat &_format, QTextDocumentPrivate::FormatChangeMode changeMode)
817 Q_ASSERT(position != anchor);
819 QTextCharFormat format = _format;
820 format.clearProperty(QTextFormat::ObjectIndex);
822 QTextTable *table = complexSelectionTable();
824 priv->beginEditBlock();
825 int row_start, col_start, num_rows, num_cols;
826 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
828 Q_ASSERT(row_start != -1);
829 for (int r = row_start; r < row_start + num_rows; ++r) {
830 for (int c = col_start; c < col_start + num_cols; ++c) {
831 QTextTableCell cell = table->cellAt(r, c);
832 int rspan = cell.rowSpan();
833 int cspan = cell.columnSpan();
840 int cc = cell.column();
845 int pos1 = cell.firstPosition();
846 int pos2 = cell.lastPosition();
847 priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
850 priv->endEditBlock();
853 int pos2 = adjusted_anchor;
855 pos1 = adjusted_anchor;
859 priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
864 QTextLayout *QTextCursorPrivate::blockLayout(QTextBlock &block) const{
865 QTextLayout *tl = block.layout();
866 if (!tl->lineCount() && priv->layout())
867 priv->layout()->blockBoundingRect(block);
875 \brief The QTextCursor class offers an API to access and modify QTextDocuments.
877 \ingroup richtext-processing
880 Text cursors are objects that are used to access and modify the
881 contents and underlying structure of text documents via a
882 programming interface that mimics the behavior of a cursor in a
883 text editor. QTextCursor contains information about both the
884 cursor's position within a QTextDocument and any selection that it
887 QTextCursor is modeled on the way a text cursor behaves in a text
888 editor, providing a programmatic means of performing standard
889 actions through the user interface. A document can be thought of
890 as a single string of characters. The cursor's current position()
891 then is always either \e between two consecutive characters in the
892 string, or else \e before the very first character or \e after the
893 very last character in the string. Documents can also contain
894 tables, lists, images, and other objects in addition to text but,
895 from the developer's point of view, the document can be treated as
896 one long string. Some portions of that string can be considered
897 to lie within particular blocks (e.g. paragraphs), or within a
898 table's cell, or a list's item, or other structural elements. When
899 we refer to "current character" we mean the character immediately
900 \e before the cursor position() in the document. Similarly, the
901 "current block" is the block that contains the cursor position().
903 A QTextCursor also has an anchor() position. The text that is
904 between the anchor() and the position() is the selection. If
905 anchor() == position() there is no selection.
907 The cursor position can be changed programmatically using
908 setPosition() and movePosition(); the latter can also be used to
909 select text. For selections see selectionStart(), selectionEnd(),
910 hasSelection(), clearSelection(), and removeSelectedText().
912 If the position() is at the start of a block atBlockStart()
913 returns true; and if it is at the end of a block atBlockEnd() returns
914 true. The format of the current character is returned by
915 charFormat(), and the format of the current block is returned by
918 Formatting can be applied to the current text document using the
919 setCharFormat(), mergeCharFormat(), setBlockFormat() and
920 mergeBlockFormat() functions. The 'set' functions will replace the
921 cursor's current character or block format, while the 'merge'
922 functions add the given format properties to the cursor's current
923 format. If the cursor has a selection the given format is applied
924 to the current selection. Note that when only parts of a block is
925 selected the block format is applied to the entire block. The text
926 at the current character position can be turned into a list using
929 Deletions can be achieved using deleteChar(),
930 deletePreviousChar(), and removeSelectedText().
932 Text strings can be inserted into the document with the insertText()
933 function, blocks (representing new paragraphs) can be inserted with
936 Existing fragments of text can be inserted with insertFragment() but,
937 if you want to insert pieces of text in various formats, it is usually
938 still easier to use insertText() and supply a character format.
940 Various types of higher-level structure can also be inserted into the
941 document with the cursor:
944 \i Lists are ordered sequences of block elements that are decorated with
945 bullet points or symbols. These are inserted in a specified format
947 \i Tables are inserted with the insertTable() function, and can be
948 given an optional format. These contain an array of cells that can
949 be traversed using the cursor.
950 \i Inline images are inserted with insertImage(). The image to be
951 used can be specified in an image format, or by name.
952 \i Frames are inserted by calling insertFrame() with a specified format.
955 Actions can be grouped (i.e. treated as a single action for
956 undo/redo) using beginEditBlock() and endEditBlock().
958 Cursor movements are limited to valid cursor positions. In Latin
959 writing this is between any two consecutive characters in the
960 text, before the first character, or after the last character. In
961 some other writing systems cursor movements are limited to
962 "clusters" (e.g. a syllable in Devanagari, or a base letter plus
963 diacritics). Functions such as movePosition() and deleteChar()
964 limit cursor movement to these valid positions.
966 \sa \link richtext.html Rich Text Processing\endlink
971 \enum QTextCursor::MoveOperation
973 \value NoMove Keep the cursor where it is
975 \value Start Move to the start of the document.
976 \value StartOfLine Move to the start of the current line.
977 \value StartOfBlock Move to the start of the current block.
978 \value StartOfWord Move to the start of the current word.
979 \value PreviousBlock Move to the start of the previous block.
980 \value PreviousCharacter Move to the previous character.
981 \value PreviousWord Move to the beginning of the previous word.
982 \value Up Move up one line.
983 \value Left Move left one character.
984 \value WordLeft Move left one word.
986 \value End Move to the end of the document.
987 \value EndOfLine Move to the end of the current line.
988 \value EndOfWord Move to the end of the current word.
989 \value EndOfBlock Move to the end of the current block.
990 \value NextBlock Move to the beginning of the next block.
991 \value NextCharacter Move to the next character.
992 \value NextWord Move to the next word.
993 \value Down Move down one line.
994 \value Right Move right one character.
995 \value WordRight Move right one word.
997 \value NextCell Move to the beginning of the next table cell inside the
998 current table. If the current cell is the last cell in the row, the
999 cursor will move to the first cell in the next row.
1000 \value PreviousCell Move to the beginning of the previous table cell
1001 inside the current table. If the current cell is the first cell in
1002 the row, the cursor will move to the last cell in the previous row.
1003 \value NextRow Move to the first new cell of the next row in the current
1005 \value PreviousRow Move to the last cell of the previous row in the
1012 \enum QTextCursor::MoveMode
1014 \value MoveAnchor Moves the anchor to the same position as the cursor itself.
1015 \value KeepAnchor Keeps the anchor where it is.
1017 If the anchor() is kept where it is and the position() is moved,
1018 the text in between will be selected.
1022 \enum QTextCursor::SelectionType
1024 This enum describes the types of selection that can be applied with the
1027 \value Document Selects the entire document.
1028 \value BlockUnderCursor Selects the block of text under the cursor.
1029 \value LineUnderCursor Selects the line of text under the cursor.
1030 \value WordUnderCursor Selects the word under the cursor. If the cursor
1031 is not positioned within a string of selectable characters, no
1036 Constructs a null cursor.
1038 QTextCursor::QTextCursor()
1044 Constructs a cursor pointing to the beginning of the \a document.
1046 QTextCursor::QTextCursor(QTextDocument *document)
1047 : d(new QTextCursorPrivate(document->docHandle()))
1052 Constructs a cursor pointing to the beginning of the \a frame.
1054 QTextCursor::QTextCursor(QTextFrame *frame)
1055 : d(new QTextCursorPrivate(frame->document()->docHandle()))
1057 d->adjusted_anchor = d->anchor = d->position = frame->firstPosition();
1062 Constructs a cursor pointing to the beginning of the \a block.
1064 QTextCursor::QTextCursor(const QTextBlock &block)
1065 : d(new QTextCursorPrivate(block.docHandle()))
1067 d->adjusted_anchor = d->anchor = d->position = block.position();
1074 QTextCursor::QTextCursor(QTextDocumentPrivate *p, int pos)
1075 : d(new QTextCursorPrivate(p))
1077 d->adjusted_anchor = d->anchor = d->position = pos;
1085 QTextCursor::QTextCursor(QTextCursorPrivate *d)
1092 Constructs a new cursor that is a copy of \a cursor.
1094 QTextCursor::QTextCursor(const QTextCursor &cursor)
1100 Makes a copy of \a cursor and assigns it to this QTextCursor. Note
1101 that QTextCursor is an \l{Implicitly Shared Classes}{implicitly
1105 QTextCursor &QTextCursor::operator=(const QTextCursor &cursor)
1112 Destroys the QTextCursor.
1114 QTextCursor::~QTextCursor()
1119 Returns true if the cursor is null; otherwise returns false. A null
1120 cursor is created by the default constructor.
1122 bool QTextCursor::isNull() const
1124 return !d || !d->priv;
1128 Moves the cursor to the absolute position in the document specified by
1129 \a pos using a \c MoveMode specified by \a m. The cursor is positioned
1132 \sa position() movePosition() anchor()
1134 void QTextCursor::setPosition(int pos, MoveMode m)
1139 if (pos < 0 || pos >= d->priv->length()) {
1140 qWarning("QTextCursor::setPosition: Position '%d' out of range", pos);
1144 d->setPosition(pos);
1145 if (m == MoveAnchor) {
1147 d->adjusted_anchor = pos;
1148 } else { // keep anchor
1149 QTextCursor::MoveOperation op;
1150 if (pos < d->anchor)
1151 op = QTextCursor::Left;
1153 op = QTextCursor::Right;
1154 d->adjustCursor(op);
1160 Returns the absolute position of the cursor within the document.
1161 The cursor is positioned between characters.
1163 \sa setPosition() movePosition() anchor() positionInBlock()
1165 int QTextCursor::position() const
1174 Returns the relative position of the cursor within the block.
1175 The cursor is positioned between characters.
1177 This is equivalent to \c{ position() - block().position()}.
1181 int QTextCursor::positionInBlock() const
1185 return d->position - d->block().position();
1189 Returns the anchor position; this is the same as position() unless
1190 there is a selection in which case position() marks one end of the
1191 selection and anchor() marks the other end. Just like the cursor
1192 position, the anchor position is between characters.
1194 \sa position() setPosition() movePosition() selectionStart() selectionEnd()
1196 int QTextCursor::anchor() const
1204 \fn bool QTextCursor::movePosition(MoveOperation operation, MoveMode mode, int n)
1206 Moves the cursor by performing the given \a operation \a n times, using the specified
1207 \a mode, and returns true if all operations were completed successfully; otherwise
1210 For example, if this function is repeatedly used to seek to the end of the next
1211 word, it will eventually fail when the end of the document is reached.
1213 By default, the move operation is performed once (\a n = 1).
1215 If \a mode is \c KeepAnchor, the cursor selects the text it moves
1216 over. This is the same effect that the user achieves when they
1217 hold down the Shift key and move the cursor with the cursor keys.
1219 \sa setVisualNavigation()
1221 bool QTextCursor::movePosition(MoveOperation op, MoveMode mode, int n)
1235 int previousPosition = d->position;
1236 for (; n > 0; --n) {
1237 if (!d->movePosition(op, mode))
1241 if (d->visualNavigation && !d->block().isVisible()) {
1242 QTextBlock b = d->block();
1243 if (previousPosition < d->position) {
1244 while (!b.next().isVisible())
1246 d->setPosition(b.position() + b.length() - 1);
1248 while (!b.previous().isVisible())
1250 d->setPosition(b.position());
1252 if (mode == QTextCursor::MoveAnchor)
1253 d->anchor = d->position;
1254 while (d->movePosition(op, mode)
1255 && !d->block().isVisible())
1265 Returns true if the cursor does visual navigation; otherwise
1268 Visual navigation means skipping over hidden text pragraphs. The
1271 \sa setVisualNavigation(), movePosition()
1273 bool QTextCursor::visualNavigation() const
1275 return d ? d->visualNavigation : false;
1281 Sets visual navigation to \a b.
1283 Visual navigation means skipping over hidden text pragraphs. The
1286 \sa visualNavigation(), movePosition()
1288 void QTextCursor::setVisualNavigation(bool b)
1291 d->visualNavigation = b;
1298 Sets the visual x position for vertical cursor movements to \a x.
1300 The vertical movement x position is cleared automatically when the cursor moves horizontally, and kept
1301 unchanged when the cursor moves vertically. The mechanism allows the cursor to move up and down on a
1302 visually straight line with proportional fonts, and to gently "jump" over short lines.
1304 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1305 cursor moves up or down.
1307 \sa verticalMovementX()
1309 void QTextCursor::setVerticalMovementX(int x)
1317 Returns the visual x position for vertical cursor movements.
1319 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1320 cursor moves up or down.
1322 \sa setVerticalMovementX()
1324 int QTextCursor::verticalMovementX() const
1326 return d ? d->x : -1;
1332 Returns whether the cursor should keep its current position when text gets inserted at the position of the
1335 The default is false;
1337 \sa setKeepPositionOnInsert()
1339 bool QTextCursor::keepPositionOnInsert() const
1341 return d ? d->keepPositionOnInsert : false;
1347 Defines whether the cursor should keep its current position when text gets inserted at the current position of the
1350 If \a b is true, the cursor keeps its current position when text gets inserted at the positing of the cursor.
1351 If \a b is false, the cursor moves along with the inserted text.
1353 The default is false.
1355 Note that a cursor always moves when text is inserted before the current position of the cursor, and it
1356 always keeps its position when text is inserted after the current position of the cursor.
1358 \sa keepPositionOnInsert()
1360 void QTextCursor::setKeepPositionOnInsert(bool b)
1363 d->keepPositionOnInsert = b;
1369 Inserts \a text at the current position, using the current
1372 If there is a selection, the selection is deleted and replaced by
1373 \a text, for example:
1374 \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 0
1375 This clears any existing selection, selects the word at the cursor
1376 (i.e. from position() forward), and replaces the selection with
1377 the phrase "Hello World".
1379 Any ASCII linefeed characters (\\n) in the inserted text are transformed
1380 into unicode block separators, corresponding to insertBlock() calls.
1382 \sa charFormat() hasSelection()
1384 void QTextCursor::insertText(const QString &text)
1386 QTextCharFormat fmt = charFormat();
1387 fmt.clearProperty(QTextFormat::ObjectType);
1388 insertText(text, fmt);
1392 \fn void QTextCursor::insertText(const QString &text, const QTextCharFormat &format)
1395 Inserts \a text at the current position with the given \a format.
1397 void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format)
1402 Q_ASSERT(_format.isValid());
1404 QTextCharFormat format = _format;
1405 format.clearProperty(QTextFormat::ObjectIndex);
1407 bool hasEditBlock = false;
1409 if (d->anchor != d->position) {
1410 hasEditBlock = true;
1411 d->priv->beginEditBlock();
1415 if (!text.isEmpty()) {
1416 QTextFormatCollection *formats = d->priv->formatCollection();
1417 int formatIdx = formats->indexForFormat(format);
1418 Q_ASSERT(formats->format(formatIdx).isCharFormat());
1420 QTextBlockFormat blockFmt = blockFormat();
1423 int textStart = d->priv->text.length();
1425 d->priv->text += text;
1426 int textEnd = d->priv->text.length();
1428 for (int i = 0; i < text.length(); ++i) {
1429 QChar ch = text.at(i);
1431 const int blockEnd = i;
1433 if (ch == QLatin1Char('\r')
1434 && (i + 1) < text.length()
1435 && text.at(i + 1) == QLatin1Char('\n')) {
1440 if (ch == QLatin1Char('\n')
1441 || ch == QChar::ParagraphSeparator
1442 || ch == QTextBeginningOfFrame
1443 || ch == QTextEndOfFrame
1444 || ch == QLatin1Char('\r')) {
1446 if (!hasEditBlock) {
1447 hasEditBlock = true;
1448 d->priv->beginEditBlock();
1451 if (blockEnd > blockStart)
1452 d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx);
1454 d->insertBlock(blockFmt, format);
1458 if (textStart + blockStart < textEnd)
1459 d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx);
1462 d->priv->endEditBlock();
1467 If there is no selected text, deletes the character \e at the
1468 current cursor position; otherwise deletes the selected text.
1470 \sa deletePreviousChar() hasSelection() clearSelection()
1472 void QTextCursor::deleteChar()
1477 if (d->position != d->anchor) {
1478 removeSelectedText();
1482 if (!d->canDelete(d->position))
1484 d->adjusted_anchor = d->anchor =
1485 d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters);
1491 If there is no selected text, deletes the character \e before the
1492 current cursor position; otherwise deletes the selected text.
1494 \sa deleteChar() hasSelection() clearSelection()
1496 void QTextCursor::deletePreviousChar()
1501 if (d->position != d->anchor) {
1502 removeSelectedText();
1506 if (d->anchor < 1 || !d->canDelete(d->anchor-1))
1510 QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
1511 const QTextFragmentData * const frag = fragIt.value();
1512 int fpos = fragIt.position();
1513 QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition);
1514 if (d->anchor > fpos && uc.isLowSurrogate()) {
1515 // second half of a surrogate, check if we have the first half as well,
1516 // if yes delete both at once
1517 uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition);
1518 if (uc.isHighSurrogate())
1522 d->adjusted_anchor = d->anchor;
1528 Selects text in the document according to the given \a selection.
1530 void QTextCursor::select(SelectionType selection)
1537 const QTextBlock block = d->block();
1539 switch (selection) {
1540 case LineUnderCursor:
1541 movePosition(StartOfLine);
1542 movePosition(EndOfLine, KeepAnchor);
1544 case WordUnderCursor:
1545 movePosition(StartOfWord);
1546 movePosition(EndOfWord, KeepAnchor);
1548 case BlockUnderCursor:
1549 if (block.length() == 1) // no content
1551 movePosition(StartOfBlock);
1552 // also select the paragraph separator
1553 if (movePosition(PreviousBlock)) {
1554 movePosition(EndOfBlock);
1555 movePosition(NextBlock, KeepAnchor);
1557 movePosition(EndOfBlock, KeepAnchor);
1560 movePosition(Start);
1561 movePosition(End, KeepAnchor);
1567 Returns true if the cursor contains a selection; otherwise returns false.
1569 bool QTextCursor::hasSelection() const
1571 return !!d && d->position != d->anchor;
1576 Returns true if the cursor contains a selection that is not simply a
1577 range from selectionStart() to selectionEnd(); otherwise returns false.
1579 Complex selections are ones that span at least two cells in a table;
1580 their extent is specified by selectedTableCells().
1582 bool QTextCursor::hasComplexSelection() const
1587 return d->complexSelectionTable() != 0;
1591 If the selection spans over table cells, \a firstRow is populated
1592 with the number of the first row in the selection, \a firstColumn
1593 with the number of the first column in the selection, and \a
1594 numRows and \a numColumns with the number of rows and columns in
1595 the selection. If the selection does not span any table cells the
1596 results are harmless but undefined.
1598 void QTextCursor::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
1605 if (!d || d->position == d->anchor)
1608 d->selectedTableCells(firstRow, numRows, firstColumn, numColumns);
1613 Clears the current selection by setting the anchor to the cursor position.
1615 Note that it does \bold{not} delete the text of the selection.
1617 \sa removeSelectedText() hasSelection()
1619 void QTextCursor::clearSelection()
1623 d->adjusted_anchor = d->anchor = d->position;
1624 d->currentCharFormat = -1;
1628 If there is a selection, its content is deleted; otherwise does
1633 void QTextCursor::removeSelectedText()
1635 if (!d || !d->priv || d->position == d->anchor)
1638 d->priv->beginEditBlock();
1640 d->priv->endEditBlock();
1645 Returns the start of the selection or position() if the
1646 cursor doesn't have a selection.
1648 \sa selectionEnd() position() anchor()
1650 int QTextCursor::selectionStart() const
1654 return qMin(d->position, d->adjusted_anchor);
1658 Returns the end of the selection or position() if the cursor
1659 doesn't have a selection.
1661 \sa selectionStart() position() anchor()
1663 int QTextCursor::selectionEnd() const
1667 return qMax(d->position, d->adjusted_anchor);
1670 static void getText(QString &text, QTextDocumentPrivate *priv, const QString &docText, int pos, int end)
1673 QTextDocumentPrivate::FragmentIterator fragIt = priv->find(pos);
1674 const QTextFragmentData * const frag = fragIt.value();
1676 const int offsetInFragment = qMax(0, pos - fragIt.position());
1677 const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
1679 text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
1685 Returns the current selection's text (which may be empty). This
1686 only returns the text, with no rich text formatting information.
1687 If you want a document fragment (i.e. formatted rich text) use
1688 selection() instead.
1690 \note If the selection obtained from an editor spans a line break,
1691 the text will contain a Unicode U+2029 paragraph separator character
1692 instead of a newline \c{\n} character. Use QString::replace() to
1693 replace these characters with newlines.
1695 QString QTextCursor::selectedText() const
1697 if (!d || !d->priv || d->position == d->anchor)
1700 const QString docText = d->priv->buffer();
1703 QTextTable *table = d->complexSelectionTable();
1705 int row_start, col_start, num_rows, num_cols;
1706 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
1708 Q_ASSERT(row_start != -1);
1709 for (int r = row_start; r < row_start + num_rows; ++r) {
1710 for (int c = col_start; c < col_start + num_cols; ++c) {
1711 QTextTableCell cell = table->cellAt(r, c);
1712 int rspan = cell.rowSpan();
1713 int cspan = cell.columnSpan();
1715 int cr = cell.row();
1720 int cc = cell.column();
1725 getText(text, d->priv, docText, cell.firstPosition(), cell.lastPosition());
1729 getText(text, d->priv, docText, selectionStart(), selectionEnd());
1736 Returns the current selection (which may be empty) with all its
1737 formatting information. If you just want the selected text (i.e.
1738 plain text) use selectedText() instead.
1740 \note Unlike QTextDocumentFragment::toPlainText(),
1741 selectedText() may include special unicode characters such as
1742 QChar::ParagraphSeparator.
1744 \sa QTextDocumentFragment::toPlainText()
1746 QTextDocumentFragment QTextCursor::selection() const
1748 return QTextDocumentFragment(*this);
1752 Returns the block that contains the cursor.
1754 QTextBlock QTextCursor::block() const
1757 return QTextBlock();
1762 Returns the block format of the block the cursor is in.
1764 \sa setBlockFormat() charFormat()
1766 QTextBlockFormat QTextCursor::blockFormat() const
1769 return QTextBlockFormat();
1771 return d->block().blockFormat();
1775 Sets the block format of the current block (or all blocks that
1776 are contained in the selection) to \a format.
1778 \sa blockFormat(), mergeBlockFormat()
1780 void QTextCursor::setBlockFormat(const QTextBlockFormat &format)
1785 d->setBlockFormat(format, QTextDocumentPrivate::SetFormat);
1789 Modifies the block format of the current block (or all blocks that
1790 are contained in the selection) with the block format specified by
1793 \sa setBlockFormat(), blockFormat()
1795 void QTextCursor::mergeBlockFormat(const QTextBlockFormat &modifier)
1800 d->setBlockFormat(modifier, QTextDocumentPrivate::MergeFormat);
1804 Returns the block character format of the block the cursor is in.
1806 The block char format is the format used when inserting text at the
1807 beginning of an empty block.
1809 \sa setBlockCharFormat()
1811 QTextCharFormat QTextCursor::blockCharFormat() const
1814 return QTextCharFormat();
1816 return d->block().charFormat();
1820 Sets the block char format of the current block (or all blocks that
1821 are contained in the selection) to \a format.
1823 \sa blockCharFormat()
1825 void QTextCursor::setBlockCharFormat(const QTextCharFormat &format)
1830 d->setBlockCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1834 Modifies the block char format of the current block (or all blocks that
1835 are contained in the selection) with the block format specified by
1838 \sa setBlockCharFormat()
1840 void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier)
1845 d->setBlockCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1849 Returns the format of the character immediately before the cursor
1850 position(). If the cursor is positioned at the beginning of a text
1851 block that is not empty then the format of the character
1852 immediately after the cursor is returned.
1854 \sa insertText(), blockFormat()
1856 QTextCharFormat QTextCursor::charFormat() const
1859 return QTextCharFormat();
1861 int idx = d->currentCharFormat;
1863 QTextBlock block = d->block();
1866 if (d->position == block.position()
1867 && block.length() > 1)
1870 pos = d->position - 1;
1873 idx = d->priv->blockCharFormatIndex(d->priv->blockMap().firstNode());
1875 Q_ASSERT(pos >= 0 && pos < d->priv->length());
1877 QTextDocumentPrivate::FragmentIterator it = d->priv->find(pos);
1878 Q_ASSERT(!it.atEnd());
1879 idx = it.value()->format;
1883 QTextCharFormat cfmt = d->priv->formatCollection()->charFormat(idx);
1884 cfmt.clearProperty(QTextFormat::ObjectIndex);
1886 Q_ASSERT(cfmt.isValid());
1891 Sets the cursor's current character format to the given \a
1892 format. If the cursor has a selection, the given \a format is
1893 applied to the current selection.
1895 \sa hasSelection(), mergeCharFormat()
1897 void QTextCursor::setCharFormat(const QTextCharFormat &format)
1901 if (d->position == d->anchor) {
1902 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1905 d->setCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1909 Merges the cursor's current character format with the properties
1910 described by format \a modifier. If the cursor has a selection,
1911 this function applies all the properties set in \a modifier to all
1912 the character formats that are part of the selection.
1914 \sa hasSelection(), setCharFormat()
1916 void QTextCursor::mergeCharFormat(const QTextCharFormat &modifier)
1920 if (d->position == d->anchor) {
1921 QTextCharFormat format = charFormat();
1922 format.merge(modifier);
1923 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1927 d->setCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1931 Returns true if the cursor is at the start of a block; otherwise
1934 \sa atBlockEnd(), atStart()
1936 bool QTextCursor::atBlockStart() const
1941 return d->position == d->block().position();
1945 Returns true if the cursor is at the end of a block; otherwise
1948 \sa atBlockStart(), atEnd()
1950 bool QTextCursor::atBlockEnd() const
1955 return d->position == d->block().position() + d->block().length() - 1;
1959 Returns true if the cursor is at the start of the document;
1960 otherwise returns false.
1962 \sa atBlockStart(), atEnd()
1964 bool QTextCursor::atStart() const
1969 return d->position == 0;
1975 Returns true if the cursor is at the end of the document;
1976 otherwise returns false.
1978 \sa atStart(), atBlockEnd()
1980 bool QTextCursor::atEnd() const
1985 return d->position == d->priv->length() - 1;
1989 Inserts a new empty block at the cursor position() with the
1990 current blockFormat() and charFormat().
1992 \sa setBlockFormat()
1994 void QTextCursor::insertBlock()
1996 insertBlock(blockFormat());
2002 Inserts a new empty block at the cursor position() with block
2003 format \a format and the current charFormat() as block char format.
2005 \sa setBlockFormat()
2007 void QTextCursor::insertBlock(const QTextBlockFormat &format)
2009 QTextCharFormat charFmt = charFormat();
2010 charFmt.clearProperty(QTextFormat::ObjectType);
2011 insertBlock(format, charFmt);
2015 \fn void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
2018 Inserts a new empty block at the cursor position() with block
2019 format \a format and \a charFormat as block char format.
2021 \sa setBlockFormat()
2023 void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &_charFormat)
2028 QTextCharFormat charFormat = _charFormat;
2029 charFormat.clearProperty(QTextFormat::ObjectIndex);
2031 d->priv->beginEditBlock();
2033 d->insertBlock(format, charFormat);
2034 d->priv->endEditBlock();
2039 Inserts a new block at the current position and makes it the first
2040 list item of a newly created list with the given \a format. Returns
2043 \sa currentList() createList() insertBlock()
2045 QTextList *QTextCursor::insertList(const QTextListFormat &format)
2048 return createList(format);
2054 Inserts a new block at the current position and makes it the first
2055 list item of a newly created list with the given \a style. Returns
2058 \sa currentList(), createList(), insertBlock()
2060 QTextList *QTextCursor::insertList(QTextListFormat::Style style)
2063 return createList(style);
2067 Creates and returns a new list with the given \a format, and makes the
2068 current paragraph the cursor is in the first list item.
2070 \sa insertList() currentList()
2072 QTextList *QTextCursor::createList(const QTextListFormat &format)
2077 QTextList *list = static_cast<QTextList *>(d->priv->createObject(format));
2078 QTextBlockFormat modifier;
2079 modifier.setObjectIndex(list->objectIndex());
2080 mergeBlockFormat(modifier);
2087 Creates and returns a new list with the given \a style, making the
2088 cursor's current paragraph the first list item.
2090 The style to be used is defined by the QTextListFormat::Style enum.
2092 \sa insertList() currentList()
2094 QTextList *QTextCursor::createList(QTextListFormat::Style style)
2096 QTextListFormat fmt;
2097 fmt.setStyle(style);
2098 return createList(fmt);
2102 Returns the current list if the cursor position() is inside a
2103 block that is part of a list; otherwise returns 0.
2105 \sa insertList() createList()
2107 QTextList *QTextCursor::currentList() const
2112 QTextBlockFormat b = blockFormat();
2113 QTextObject *o = d->priv->objectForFormat(b);
2114 return qobject_cast<QTextList *>(o);
2118 \fn QTextTable *QTextCursor::insertTable(int rows, int columns)
2122 Creates a new table with the given number of \a rows and \a columns,
2123 inserts it at the current cursor position() in the document, and returns
2124 the table object. The cursor is moved to the beginning of the first cell.
2126 There must be at least one row and one column in the table.
2130 QTextTable *QTextCursor::insertTable(int rows, int cols)
2132 return insertTable(rows, cols, QTextTableFormat());
2136 \fn QTextTable *QTextCursor::insertTable(int rows, int columns, const QTextTableFormat &format)
2138 Creates a new table with the given number of \a rows and \a columns
2139 in the specified \a format, inserts it at the current cursor position()
2140 in the document, and returns the table object. The cursor is moved to
2141 the beginning of the first cell.
2143 There must be at least one row and one column in the table.
2147 QTextTable *QTextCursor::insertTable(int rows, int cols, const QTextTableFormat &format)
2149 if(!d || !d->priv || rows == 0 || cols == 0)
2152 int pos = d->position;
2153 QTextTable *t = QTextTablePrivate::createTable(d->priv, d->position, rows, cols, format);
2154 d->setPosition(pos+1);
2155 // ##### what should we do if we have a selection?
2156 d->anchor = d->position;
2157 d->adjusted_anchor = d->anchor;
2162 Returns a pointer to the current table if the cursor position()
2163 is inside a block that is part of a table; otherwise returns 0.
2167 QTextTable *QTextCursor::currentTable() const
2172 QTextFrame *frame = d->priv->frameAt(d->position);
2174 QTextTable *table = qobject_cast<QTextTable *>(frame);
2177 frame = frame->parentFrame();
2183 Inserts a frame with the given \a format at the current cursor position(),
2184 moves the cursor position() inside the frame, and returns the frame.
2186 If the cursor holds a selection, the whole selection is moved inside the
2191 QTextFrame *QTextCursor::insertFrame(const QTextFrameFormat &format)
2196 return d->priv->insertFrame(selectionStart(), selectionEnd(), format);
2200 Returns a pointer to the current frame. Returns 0 if the cursor is invalid.
2204 QTextFrame *QTextCursor::currentFrame() const
2209 return d->priv->frameAt(d->position);
2214 Inserts the text \a fragment at the current position().
2216 void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
2218 if (!d || !d->priv || fragment.isEmpty())
2221 d->priv->beginEditBlock();
2223 fragment.d->insert(*this);
2224 d->priv->endEditBlock();
2226 if (fragment.d && fragment.d->doc)
2227 d->priv->mergeCachedResources(fragment.d->doc->docHandle());
2232 Inserts the text \a html at the current position(). The text is interpreted as
2235 \note When using this function with a style sheet, the style sheet will
2236 only apply to the current block in the document. In order to apply a style
2237 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2241 #ifndef QT_NO_TEXTHTMLPARSER
2243 void QTextCursor::insertHtml(const QString &html)
2247 QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html, d->priv->document());
2248 insertFragment(fragment);
2251 #endif // QT_NO_TEXTHTMLPARSER
2257 Inserts the image defined by the given \a format at the cursor's current position
2258 with the specified \a alignment.
2262 void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
2267 QTextFrameFormat ffmt;
2268 ffmt.setPosition(alignment);
2269 QTextObject *obj = d->priv->createObject(ffmt);
2271 QTextImageFormat fmt = format;
2272 fmt.setObjectIndex(obj->objectIndex());
2274 d->priv->beginEditBlock();
2276 const int idx = d->priv->formatCollection()->indexForFormat(fmt);
2277 d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
2278 d->priv->endEditBlock();
2282 Inserts the image defined by \a format at the current position().
2284 void QTextCursor::insertImage(const QTextImageFormat &format)
2286 insertText(QString(QChar::ObjectReplacementCharacter), format);
2292 Convenience method for inserting the image with the given \a name at the
2295 \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 1
2297 void QTextCursor::insertImage(const QString &name)
2299 QTextImageFormat format;
2300 format.setName(name);
2301 insertImage(format);
2308 Convenience function for inserting the given \a image with an optional
2309 \a name at the current position().
2311 void QTextCursor::insertImage(const QImage &image, const QString &name)
2313 if (image.isNull()) {
2314 qWarning("QTextCursor::insertImage: attempt to add an invalid image");
2317 QString imageName = name;
2319 imageName = QString::number(image.serialNumber());
2320 d->priv->document()->addResource(QTextDocument::ImageResource, QUrl(imageName), image);
2321 QTextImageFormat format;
2322 format.setName(imageName);
2323 insertImage(format);
2327 \fn bool QTextCursor::operator!=(const QTextCursor &other) const
2329 Returns true if the \a other cursor is at a different position in
2330 the document as this cursor; otherwise returns false.
2332 bool QTextCursor::operator!=(const QTextCursor &rhs) const
2334 return !operator==(rhs);
2338 \fn bool QTextCursor::operator<(const QTextCursor &other) const
2340 Returns true if the \a other cursor is positioned later in the
2341 document than this cursor; otherwise returns false.
2343 bool QTextCursor::operator<(const QTextCursor &rhs) const
2351 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<", "cannot compare cursors attached to different documents");
2353 return d->position < rhs.d->position;
2357 \fn bool QTextCursor::operator<=(const QTextCursor &other) const
2359 Returns true if the \a other cursor is positioned later or at the
2360 same position in the document as this cursor; otherwise returns
2363 bool QTextCursor::operator<=(const QTextCursor &rhs) const
2371 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<=", "cannot compare cursors attached to different documents");
2373 return d->position <= rhs.d->position;
2377 \fn bool QTextCursor::operator==(const QTextCursor &other) const
2379 Returns true if the \a other cursor is at the same position in the
2380 document as this cursor; otherwise returns false.
2382 bool QTextCursor::operator==(const QTextCursor &rhs) const
2390 return d->position == rhs.d->position && d->priv == rhs.d->priv;
2394 \fn bool QTextCursor::operator>=(const QTextCursor &other) const
2396 Returns true if the \a other cursor is positioned earlier or at the
2397 same position in the document as this cursor; otherwise returns
2400 bool QTextCursor::operator>=(const QTextCursor &rhs) const
2408 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>=", "cannot compare cursors attached to different documents");
2410 return d->position >= rhs.d->position;
2414 \fn bool QTextCursor::operator>(const QTextCursor &other) const
2416 Returns true if the \a other cursor is positioned earlier in the
2417 document than this cursor; otherwise returns false.
2419 bool QTextCursor::operator>(const QTextCursor &rhs) const
2427 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>", "cannot compare cursors attached to different documents");
2429 return d->position > rhs.d->position;
2433 Indicates the start of a block of editing operations on the
2434 document that should appear as a single operation from an
2435 undo/redo point of view.
2439 \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 2
2441 The call to undo() will cause both insertions to be undone,
2442 causing both "World" and "Hello" to be removed.
2444 It is possible to nest calls to beginEditBlock and endEditBlock. The
2445 top-most pair will determine the scope of the undo/redo operation.
2449 void QTextCursor::beginEditBlock()
2454 if (d->priv->editBlock == 0) // we are the initial edit block, store current cursor position for undo
2455 d->priv->editBlockCursorPosition = d->position;
2457 d->priv->beginEditBlock();
2461 Like beginEditBlock() indicates the start of a block of editing operations
2462 that should appear as a single operation for undo/redo. However unlike
2463 beginEditBlock() it does not start a new block but reverses the previous call to
2464 endEditBlock() and therefore makes following operations part of the previous edit block created.
2468 \snippet doc/src/snippets/code/src_gui_text_qtextcursor.cpp 3
2470 The call to undo() will cause all three insertions to be undone.
2472 \sa beginEditBlock(), endEditBlock()
2474 void QTextCursor::joinPreviousEditBlock()
2479 d->priv->joinPreviousEditBlock();
2483 Indicates the end of a block of editing operations on the document
2484 that should appear as a single operation from an undo/redo point
2487 \sa beginEditBlock()
2490 void QTextCursor::endEditBlock()
2495 d->priv->endEditBlock();
2499 Returns true if this cursor and \a other are copies of each other, i.e.
2500 one of them was created as a copy of the other and neither has moved since.
2501 This is much stricter than equality.
2503 \sa operator=() operator==()
2505 bool QTextCursor::isCopyOf(const QTextCursor &other) const
2507 return d == other.d;
2512 Returns the number of the block the cursor is in, or 0 if the cursor is invalid.
2514 Note that this function only makes sense in documents without complex objects such
2515 as tables or frames.
2517 int QTextCursor::blockNumber() const
2522 return d->block().blockNumber();
2528 Returns the position of the cursor within its containing line.
2530 Note that this is the column number relative to a wrapped line,
2531 not relative to the block (i.e. the paragraph).
2533 You probably want to call positionInBlock() instead.
2535 \sa positionInBlock()
2537 int QTextCursor::columnNumber() const
2542 QTextBlock block = d->block();
2543 if (!block.isValid())
2546 const QTextLayout *layout = d->blockLayout(block);
2548 const int relativePos = d->position - block.position();
2550 if (layout->lineCount() == 0)
2553 QTextLine line = layout->lineForTextPosition(relativePos);
2554 if (!line.isValid())
2556 return relativePos - line.textStart();
2561 Returns the document this cursor is associated with.
2563 QTextDocument *QTextCursor::document() const
2566 return d->priv->document();
2567 return 0; // document went away
2571 \enum Qt::CursorMoveStyle
2573 This enum describes the movement style available to text cursors. The options
2576 \value LogicalMoveStyle Within a left-to-right text block, decrease cursor
2577 position when pressing left arrow key, increase cursor position when pressing
2578 the right arrow key. If the text block is right-to-left, the opposite behavior
2580 \value VisualMoveStyle Pressing the left arrow key will always cause the cursor
2581 to move left, regardless of the text's writing direction. Pressing the right
2582 arrow key will always cause the cursor to move right.