1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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) {
272 position = c_position.firstPosition();
273 if (position < adjusted_anchor)
274 adjusted_anchor = c_anchor.lastPosition();
276 adjusted_anchor = c_anchor.firstPosition();
278 currentCharFormat = -1;
281 void QTextCursorPrivate::aboutToRemoveCell(int from, int to)
283 Q_ASSERT(from <= to);
284 if (position == anchor)
287 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
290 QTextTableCell removedCellFrom = t->cellAt(from);
291 QTextTableCell removedCellEnd = t->cellAt(to);
292 if (! removedCellFrom.isValid() || !removedCellEnd.isValid())
295 int curFrom = position;
296 int curTo = adjusted_anchor;
298 qSwap(curFrom, curTo);
300 QTextTableCell cellStart = t->cellAt(curFrom);
301 QTextTableCell cellEnd = t->cellAt(curTo);
303 if (cellStart.row() >= removedCellFrom.row() && cellEnd.row() <= removedCellEnd.row()
304 && cellStart.column() >= removedCellFrom.column()
305 && cellEnd.column() <= removedCellEnd.column()) { // selection is completely removed
306 // find a new position, as close as possible to where we were.
308 if (removedCellFrom.row() == 0 && removedCellEnd.row() == t->rows()-1) // removed n columns
309 cell = t->cellAt(cellStart.row(), removedCellEnd.column()+1);
310 else if (removedCellFrom.column() == 0 && removedCellEnd.column() == t->columns()-1) // removed n rows
311 cell = t->cellAt(removedCellEnd.row() + 1, cellStart.column());
315 newPosition = cell.firstPosition();
317 newPosition = t->lastPosition()+1;
319 setPosition(newPosition);
320 anchor = newPosition;
321 adjusted_anchor = newPosition;
324 else if (cellStart.row() >= removedCellFrom.row() && cellStart.row() <= removedCellEnd.row()
325 && cellEnd.row() > removedCellEnd.row()) {
326 int newPosition = t->cellAt(removedCellEnd.row() + 1, cellStart.column()).firstPosition();
327 if (position < anchor)
328 position = newPosition;
330 anchor = adjusted_anchor = newPosition;
332 else if (cellStart.column() >= removedCellFrom.column() && cellStart.column() <= removedCellEnd.column()
333 && cellEnd.column() > removedCellEnd.column()) {
334 int newPosition = t->cellAt(cellStart.row(), removedCellEnd.column()+1).firstPosition();
335 if (position < anchor)
336 position = newPosition;
338 anchor = adjusted_anchor = newPosition;
342 bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode)
344 currentCharFormat = -1;
346 QTextBlock blockIt = block();
347 bool visualMovement = priv->defaultCursorMoveStyle == Qt::VisualMoveStyle;
349 if (!blockIt.isValid())
352 if (blockIt.textDirection() == Qt::RightToLeft) {
353 if (op == QTextCursor::WordLeft)
354 op = QTextCursor::NextWord;
355 else if (op == QTextCursor::WordRight)
356 op = QTextCursor::PreviousWord;
358 if (!visualMovement) {
359 if (op == QTextCursor::Left)
360 op = QTextCursor::NextCharacter;
361 else if (op == QTextCursor::Right)
362 op = QTextCursor::PreviousCharacter;
366 const QTextLayout *layout = blockLayout(blockIt);
367 int relativePos = position - blockIt.position();
369 if (!priv->isInEditBlock())
370 line = layout->lineForTextPosition(relativePos);
372 Q_ASSERT(priv->frameAt(position) == priv->frameAt(adjusted_anchor));
374 int newPosition = position;
376 if (mode == QTextCursor::KeepAnchor && complexSelectionTable() != 0) {
377 if ((op >= QTextCursor::EndOfLine && op <= QTextCursor::NextWord)
378 || (op >= QTextCursor::Right && op <= QTextCursor::WordRight)) {
379 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
380 Q_ASSERT(t); // as we have already made sure we have a complex selection
381 QTextTableCell cell_pos = t->cellAt(position);
382 if (cell_pos.column() + cell_pos.columnSpan() != t->columns())
383 op = QTextCursor::NextCell;
387 if (x == -1 && !priv->isInEditBlock() && (op == QTextCursor::Up || op == QTextCursor::Down))
391 case QTextCursor::NoMove:
394 case QTextCursor::Start:
397 case QTextCursor::StartOfLine: {
398 newPosition = blockIt.position();
400 newPosition += line.textStart();
404 case QTextCursor::StartOfBlock: {
405 newPosition = blockIt.position();
408 case QTextCursor::PreviousBlock: {
409 if (blockIt == priv->blocksBegin())
411 blockIt = blockIt.previous();
413 newPosition = blockIt.position();
416 case QTextCursor::PreviousCharacter:
417 if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
418 newPosition = qMin(position, adjusted_anchor);
420 newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
422 case QTextCursor::Left:
423 if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
424 newPosition = visualMovement ? qMax(position, adjusted_anchor)
425 : qMin(position, adjusted_anchor);
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 (newPosition >= priv->length())
499 newPosition = priv->length() - 1;
500 if (line.lineNumber() < layout->lineCount() - 1) {
501 const QString text = blockIt.text();
502 // ###### this relies on spaces being the cause for linebreaks.
503 // this doesn't work with japanese
504 if (text.at(line.textStart() + line.textLength() - 1).isSpace())
509 case QTextCursor::EndOfWord: {
510 QTextEngine *engine = layout->engine();
511 engine->attributes();
512 const int len = blockIt.length() - 1;
513 if (relativePos >= len)
515 if (engine->atWordSeparator(relativePos)) {
517 while (relativePos < len && engine->atWordSeparator(relativePos))
520 while (relativePos < len && !engine->atSpace(relativePos) && !engine->atWordSeparator(relativePos))
523 newPosition = blockIt.position() + relativePos;
526 case QTextCursor::EndOfBlock:
527 if (blockIt.length() >= 1)
528 // position right before the block separator
529 newPosition = blockIt.position() + blockIt.length() - 1;
531 case QTextCursor::NextBlock: {
532 blockIt = blockIt.next();
533 if (!blockIt.isValid())
536 newPosition = blockIt.position();
539 case QTextCursor::NextCharacter:
540 if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
541 newPosition = qMax(position, adjusted_anchor);
543 newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
545 case QTextCursor::Right:
546 if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
547 newPosition = visualMovement ? qMin(position, adjusted_anchor)
548 : qMax(position, adjusted_anchor);
550 newPosition = visualMovement ? priv->rightCursorPosition(position)
551 : priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
553 case QTextCursor::NextWord:
554 case QTextCursor::WordRight:
555 newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords);
558 case QTextCursor::Down: {
559 int i = line.lineNumber() + 1;
561 if (i >= layout->lineCount()) {
562 int blockPosition = blockIt.position() + blockIt.length() - 1;
563 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(blockPosition));
565 QTextTableCell cell = table->cellAt(blockPosition);
566 if (cell.lastPosition() == blockPosition) {
567 int row = cell.row() + cell.rowSpan();
568 if (row < table->rows()) {
569 blockPosition = table->cellAt(row, cell.column()).firstPosition();
571 // move to line below the table
572 blockPosition = table->lastPosition() + 1;
574 blockIt = priv->blocksFind(blockPosition);
576 blockIt = blockIt.next();
579 blockIt = blockIt.next();
582 if (blockIt == priv->blocksEnd())
584 layout = blockLayout(blockIt);
587 if (layout->lineCount()) {
588 QTextLine line = layout->lineAt(i);
589 newPosition = line.xToCursor(x) + blockIt.position();
591 newPosition = blockIt.position();
596 case QTextCursor::NextCell: // fall through
597 case QTextCursor::PreviousCell: // fall through
598 case QTextCursor::NextRow: // fall through
599 case QTextCursor::PreviousRow: {
600 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
604 QTextTableCell cell = table->cellAt(position);
605 Q_ASSERT(cell.isValid());
606 int column = cell.column();
607 int row = cell.row();
608 const int currentRow = row;
609 if (op == QTextCursor::NextCell || op == QTextCursor::NextRow) {
611 column += cell.columnSpan();
612 if (column >= table->columns()) {
616 cell = table->cellAt(row, column);
617 // note we also continue while we have not reached a cell thats not merged with one above us
618 } while (cell.isValid()
619 && ((op == QTextCursor::NextRow && currentRow == cell.row())
620 || cell.row() < row));
622 else if (op == QTextCursor::PreviousCell || op == QTextCursor::PreviousRow) {
626 column = table->columns()-1;
629 cell = table->cellAt(row, column);
630 // note we also continue while we have not reached a cell thats not merged with one above us
631 } while (cell.isValid()
632 && ((op == QTextCursor::PreviousRow && currentRow == cell.row())
633 || cell.row() < row));
636 newPosition = cell.firstPosition();
641 if (mode == QTextCursor::KeepAnchor) {
642 QTextTable *table = qobject_cast<QTextTable *>(priv->frameAt(position));
643 if (table && ((op >= QTextCursor::PreviousBlock && op <= QTextCursor::WordLeft)
644 || (op >= QTextCursor::NextBlock && op <= QTextCursor::WordRight))) {
645 int oldColumn = table->cellAt(position).column();
647 const QTextTableCell otherCell = table->cellAt(newPosition);
648 if (!otherCell.isValid())
651 int newColumn = otherCell.column();
652 if ((oldColumn > newColumn && op >= QTextCursor::End)
653 || (oldColumn < newColumn && op <= QTextCursor::WordLeft))
658 const bool moved = setPosition(newPosition);
660 if (mode == QTextCursor::MoveAnchor) {
662 adjusted_anchor = position;
673 QTextTable *QTextCursorPrivate::complexSelectionTable() const
675 if (position == anchor)
678 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
680 QTextTableCell cell_pos = t->cellAt(position);
681 QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
683 Q_ASSERT(cell_anchor.isValid());
685 if (cell_pos == cell_anchor)
691 void QTextCursorPrivate::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
698 if (position == anchor)
701 QTextTable *t = qobject_cast<QTextTable *>(priv->frameAt(position));
705 QTextTableCell cell_pos = t->cellAt(position);
706 QTextTableCell cell_anchor = t->cellAt(adjusted_anchor);
708 Q_ASSERT(cell_anchor.isValid());
710 if (cell_pos == cell_anchor)
713 *firstRow = qMin(cell_pos.row(), cell_anchor.row());
714 *firstColumn = qMin(cell_pos.column(), cell_anchor.column());
715 *numRows = qMax(cell_pos.row() + cell_pos.rowSpan(), cell_anchor.row() + cell_anchor.rowSpan()) - *firstRow;
716 *numColumns = qMax(cell_pos.column() + cell_pos.columnSpan(), cell_anchor.column() + cell_anchor.columnSpan()) - *firstColumn;
719 static void setBlockCharFormatHelper(QTextDocumentPrivate *priv, int pos1, int pos2,
720 const QTextCharFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
722 QTextBlock it = priv->blocksFind(pos1);
723 QTextBlock end = priv->blocksFind(pos2);
727 for (; it != end; it = it.next()) {
728 priv->setCharFormat(it.position() - 1, 1, format, changeMode);
732 void QTextCursorPrivate::setBlockCharFormat(const QTextCharFormat &_format,
733 QTextDocumentPrivate::FormatChangeMode changeMode)
735 priv->beginEditBlock();
737 QTextCharFormat format = _format;
738 format.clearProperty(QTextFormat::ObjectIndex);
740 QTextTable *table = complexSelectionTable();
742 int row_start, col_start, num_rows, num_cols;
743 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
745 Q_ASSERT(row_start != -1);
746 for (int r = row_start; r < row_start + num_rows; ++r) {
747 for (int c = col_start; c < col_start + num_cols; ++c) {
748 QTextTableCell cell = table->cellAt(r, c);
749 int rspan = cell.rowSpan();
750 int cspan = cell.columnSpan();
757 int cc = cell.column();
762 int pos1 = cell.firstPosition();
763 int pos2 = cell.lastPosition();
764 setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
769 int pos2 = adjusted_anchor;
771 pos1 = adjusted_anchor;
775 setBlockCharFormatHelper(priv, pos1, pos2, format, changeMode);
777 priv->endEditBlock();
781 void QTextCursorPrivate::setBlockFormat(const QTextBlockFormat &format, QTextDocumentPrivate::FormatChangeMode changeMode)
783 QTextTable *table = complexSelectionTable();
785 priv->beginEditBlock();
786 int row_start, col_start, num_rows, num_cols;
787 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
789 Q_ASSERT(row_start != -1);
790 for (int r = row_start; r < row_start + num_rows; ++r) {
791 for (int c = col_start; c < col_start + num_cols; ++c) {
792 QTextTableCell cell = table->cellAt(r, c);
793 int rspan = cell.rowSpan();
794 int cspan = cell.columnSpan();
801 int cc = cell.column();
806 int pos1 = cell.firstPosition();
807 int pos2 = cell.lastPosition();
808 priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
811 priv->endEditBlock();
814 int pos2 = adjusted_anchor;
816 pos1 = adjusted_anchor;
820 priv->setBlockFormat(priv->blocksFind(pos1), priv->blocksFind(pos2), format, changeMode);
824 void QTextCursorPrivate::setCharFormat(const QTextCharFormat &_format, QTextDocumentPrivate::FormatChangeMode changeMode)
826 Q_ASSERT(position != anchor);
828 QTextCharFormat format = _format;
829 format.clearProperty(QTextFormat::ObjectIndex);
831 QTextTable *table = complexSelectionTable();
833 priv->beginEditBlock();
834 int row_start, col_start, num_rows, num_cols;
835 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
837 Q_ASSERT(row_start != -1);
838 for (int r = row_start; r < row_start + num_rows; ++r) {
839 for (int c = col_start; c < col_start + num_cols; ++c) {
840 QTextTableCell cell = table->cellAt(r, c);
841 int rspan = cell.rowSpan();
842 int cspan = cell.columnSpan();
849 int cc = cell.column();
854 int pos1 = cell.firstPosition();
855 int pos2 = cell.lastPosition();
856 priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
859 priv->endEditBlock();
862 int pos2 = adjusted_anchor;
864 pos1 = adjusted_anchor;
868 priv->setCharFormat(pos1, pos2-pos1, format, changeMode);
873 QTextLayout *QTextCursorPrivate::blockLayout(QTextBlock &block) const{
874 QTextLayout *tl = block.layout();
875 if (!tl->lineCount() && priv->layout())
876 priv->layout()->blockBoundingRect(block);
885 \brief The QTextCursor class offers an API to access and modify QTextDocuments.
887 \ingroup richtext-processing
890 Text cursors are objects that are used to access and modify the
891 contents and underlying structure of text documents via a
892 programming interface that mimics the behavior of a cursor in a
893 text editor. QTextCursor contains information about both the
894 cursor's position within a QTextDocument and any selection that it
897 QTextCursor is modeled on the way a text cursor behaves in a text
898 editor, providing a programmatic means of performing standard
899 actions through the user interface. A document can be thought of
900 as a single string of characters. The cursor's current position()
901 then is always either \e between two consecutive characters in the
902 string, or else \e before the very first character or \e after the
903 very last character in the string. Documents can also contain
904 tables, lists, images, and other objects in addition to text but,
905 from the developer's point of view, the document can be treated as
906 one long string. Some portions of that string can be considered
907 to lie within particular blocks (e.g. paragraphs), or within a
908 table's cell, or a list's item, or other structural elements. When
909 we refer to "current character" we mean the character immediately
910 \e before the cursor position() in the document. Similarly, the
911 "current block" is the block that contains the cursor position().
913 A QTextCursor also has an anchor() position. The text that is
914 between the anchor() and the position() is the selection. If
915 anchor() == position() there is no selection.
917 The cursor position can be changed programmatically using
918 setPosition() and movePosition(); the latter can also be used to
919 select text. For selections see selectionStart(), selectionEnd(),
920 hasSelection(), clearSelection(), and removeSelectedText().
922 If the position() is at the start of a block atBlockStart()
923 returns true; and if it is at the end of a block atBlockEnd() returns
924 true. The format of the current character is returned by
925 charFormat(), and the format of the current block is returned by
928 Formatting can be applied to the current text document using the
929 setCharFormat(), mergeCharFormat(), setBlockFormat() and
930 mergeBlockFormat() functions. The 'set' functions will replace the
931 cursor's current character or block format, while the 'merge'
932 functions add the given format properties to the cursor's current
933 format. If the cursor has a selection the given format is applied
934 to the current selection. Note that when only parts of a block is
935 selected the block format is applied to the entire block. The text
936 at the current character position can be turned into a list using
939 Deletions can be achieved using deleteChar(),
940 deletePreviousChar(), and removeSelectedText().
942 Text strings can be inserted into the document with the insertText()
943 function, blocks (representing new paragraphs) can be inserted with
946 Existing fragments of text can be inserted with insertFragment() but,
947 if you want to insert pieces of text in various formats, it is usually
948 still easier to use insertText() and supply a character format.
950 Various types of higher-level structure can also be inserted into the
951 document with the cursor:
954 \li Lists are ordered sequences of block elements that are decorated with
955 bullet points or symbols. These are inserted in a specified format
957 \li Tables are inserted with the insertTable() function, and can be
958 given an optional format. These contain an array of cells that can
959 be traversed using the cursor.
960 \li Inline images are inserted with insertImage(). The image to be
961 used can be specified in an image format, or by name.
962 \li Frames are inserted by calling insertFrame() with a specified format.
965 Actions can be grouped (i.e. treated as a single action for
966 undo/redo) using beginEditBlock() and endEditBlock().
968 Cursor movements are limited to valid cursor positions. In Latin
969 writing this is between any two consecutive characters in the
970 text, before the first character, or after the last character. In
971 some other writing systems cursor movements are limited to
972 "clusters" (e.g. a syllable in Devanagari, or a base letter plus
973 diacritics). Functions such as movePosition() and deleteChar()
974 limit cursor movement to these valid positions.
976 \sa {Rich Text Processing}
981 \enum QTextCursor::MoveOperation
983 \value NoMove Keep the cursor where it is
985 \value Start Move to the start of the document.
986 \value StartOfLine Move to the start of the current line.
987 \value StartOfBlock Move to the start of the current block.
988 \value StartOfWord Move to the start of the current word.
989 \value PreviousBlock Move to the start of the previous block.
990 \value PreviousCharacter Move to the previous character.
991 \value PreviousWord Move to the beginning of the previous word.
992 \value Up Move up one line.
993 \value Left Move left one character.
994 \value WordLeft Move left one word.
996 \value End Move to the end of the document.
997 \value EndOfLine Move to the end of the current line.
998 \value EndOfWord Move to the end of the current word.
999 \value EndOfBlock Move to the end of the current block.
1000 \value NextBlock Move to the beginning of the next block.
1001 \value NextCharacter Move to the next character.
1002 \value NextWord Move to the next word.
1003 \value Down Move down one line.
1004 \value Right Move right one character.
1005 \value WordRight Move right one word.
1007 \value NextCell Move to the beginning of the next table cell inside the
1008 current table. If the current cell is the last cell in the row, the
1009 cursor will move to the first cell in the next row.
1010 \value PreviousCell Move to the beginning of the previous table cell
1011 inside the current table. If the current cell is the first cell in
1012 the row, the cursor will move to the last cell in the previous row.
1013 \value NextRow Move to the first new cell of the next row in the current
1015 \value PreviousRow Move to the last cell of the previous row in the
1022 \enum QTextCursor::MoveMode
1024 \value MoveAnchor Moves the anchor to the same position as the cursor itself.
1025 \value KeepAnchor Keeps the anchor where it is.
1027 If the anchor() is kept where it is and the position() is moved,
1028 the text in between will be selected.
1032 \enum QTextCursor::SelectionType
1034 This enum describes the types of selection that can be applied with the
1037 \value Document Selects the entire document.
1038 \value BlockUnderCursor Selects the block of text under the cursor.
1039 \value LineUnderCursor Selects the line of text under the cursor.
1040 \value WordUnderCursor Selects the word under the cursor. If the cursor
1041 is not positioned within a string of selectable characters, no
1046 Constructs a null cursor.
1048 QTextCursor::QTextCursor()
1054 Constructs a cursor pointing to the beginning of the \a document.
1056 QTextCursor::QTextCursor(QTextDocument *document)
1057 : d(new QTextCursorPrivate(document->docHandle()))
1062 Constructs a cursor pointing to the beginning of the \a frame.
1064 QTextCursor::QTextCursor(QTextFrame *frame)
1065 : d(new QTextCursorPrivate(frame->document()->docHandle()))
1067 d->adjusted_anchor = d->anchor = d->position = frame->firstPosition();
1072 Constructs a cursor pointing to the beginning of the \a block.
1074 QTextCursor::QTextCursor(const QTextBlock &block)
1075 : d(new QTextCursorPrivate(block.docHandle()))
1077 d->adjusted_anchor = d->anchor = d->position = block.position();
1084 QTextCursor::QTextCursor(QTextDocumentPrivate *p, int pos)
1085 : d(new QTextCursorPrivate(p))
1087 d->adjusted_anchor = d->anchor = d->position = pos;
1095 QTextCursor::QTextCursor(QTextCursorPrivate *d)
1102 Constructs a new cursor that is a copy of \a cursor.
1104 QTextCursor::QTextCursor(const QTextCursor &cursor)
1110 Makes a copy of \a cursor and assigns it to this QTextCursor. Note
1111 that QTextCursor is an \l{Implicitly Shared Classes}{implicitly
1115 QTextCursor &QTextCursor::operator=(const QTextCursor &cursor)
1122 Destroys the QTextCursor.
1124 QTextCursor::~QTextCursor()
1129 Returns true if the cursor is null; otherwise returns false. A null
1130 cursor is created by the default constructor.
1132 bool QTextCursor::isNull() const
1134 return !d || !d->priv;
1138 Moves the cursor to the absolute position in the document specified by
1139 \a pos using a \c MoveMode specified by \a m. The cursor is positioned
1142 \sa position(), movePosition(), anchor()
1144 void QTextCursor::setPosition(int pos, MoveMode m)
1149 if (pos < 0 || pos >= d->priv->length()) {
1150 qWarning("QTextCursor::setPosition: Position '%d' out of range", pos);
1154 d->setPosition(pos);
1155 if (m == MoveAnchor) {
1157 d->adjusted_anchor = pos;
1158 } else { // keep anchor
1159 QTextCursor::MoveOperation op;
1160 if (pos < d->anchor)
1161 op = QTextCursor::Left;
1163 op = QTextCursor::Right;
1164 d->adjustCursor(op);
1170 Returns the absolute position of the cursor within the document.
1171 The cursor is positioned between characters.
1173 \sa setPosition(), movePosition(), anchor(), positionInBlock()
1175 int QTextCursor::position() const
1184 Returns the relative position of the cursor within the block.
1185 The cursor is positioned between characters.
1187 This is equivalent to \c{ position() - block().position()}.
1191 int QTextCursor::positionInBlock() const
1195 return d->position - d->block().position();
1199 Returns the anchor position; this is the same as position() unless
1200 there is a selection in which case position() marks one end of the
1201 selection and anchor() marks the other end. Just like the cursor
1202 position, the anchor position is between characters.
1204 \sa position(), setPosition(), movePosition(), selectionStart(), selectionEnd()
1206 int QTextCursor::anchor() const
1214 \fn bool QTextCursor::movePosition(MoveOperation operation, MoveMode mode, int n)
1216 Moves the cursor by performing the given \a operation \a n times, using the specified
1217 \a mode, and returns true if all operations were completed successfully; otherwise
1220 For example, if this function is repeatedly used to seek to the end of the next
1221 word, it will eventually fail when the end of the document is reached.
1223 By default, the move operation is performed once (\a n = 1).
1225 If \a mode is \c KeepAnchor, the cursor selects the text it moves
1226 over. This is the same effect that the user achieves when they
1227 hold down the Shift key and move the cursor with the cursor keys.
1229 \sa setVisualNavigation()
1231 bool QTextCursor::movePosition(MoveOperation op, MoveMode mode, int n)
1245 int previousPosition = d->position;
1246 for (; n > 0; --n) {
1247 if (!d->movePosition(op, mode))
1251 if (d->visualNavigation && !d->block().isVisible()) {
1252 QTextBlock b = d->block();
1253 if (previousPosition < d->position) {
1254 while (!b.next().isVisible())
1256 d->setPosition(b.position() + b.length() - 1);
1258 while (!b.previous().isVisible())
1260 d->setPosition(b.position());
1262 if (mode == QTextCursor::MoveAnchor)
1263 d->anchor = d->position;
1264 while (d->movePosition(op, mode)
1265 && !d->block().isVisible())
1275 Returns true if the cursor does visual navigation; otherwise
1278 Visual navigation means skipping over hidden text pragraphs. The
1281 \sa setVisualNavigation(), movePosition()
1283 bool QTextCursor::visualNavigation() const
1285 return d ? d->visualNavigation : false;
1291 Sets visual navigation to \a b.
1293 Visual navigation means skipping over hidden text pragraphs. The
1296 \sa visualNavigation(), movePosition()
1298 void QTextCursor::setVisualNavigation(bool b)
1301 d->visualNavigation = b;
1308 Sets the visual x position for vertical cursor movements to \a x.
1310 The vertical movement x position is cleared automatically when the cursor moves horizontally, and kept
1311 unchanged when the cursor moves vertically. The mechanism allows the cursor to move up and down on a
1312 visually straight line with proportional fonts, and to gently "jump" over short lines.
1314 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1315 cursor moves up or down.
1317 \sa verticalMovementX()
1319 void QTextCursor::setVerticalMovementX(int x)
1327 Returns the visual x position for vertical cursor movements.
1329 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1330 cursor moves up or down.
1332 \sa setVerticalMovementX()
1334 int QTextCursor::verticalMovementX() const
1336 return d ? d->x : -1;
1342 Returns whether the cursor should keep its current position when text gets inserted at the position of the
1345 The default is false;
1347 \sa setKeepPositionOnInsert()
1349 bool QTextCursor::keepPositionOnInsert() const
1351 return d ? d->keepPositionOnInsert : false;
1357 Defines whether the cursor should keep its current position when text gets inserted at the current position of the
1360 If \a b is true, the cursor keeps its current position when text gets inserted at the positing of the cursor.
1361 If \a b is false, the cursor moves along with the inserted text.
1363 The default is false.
1365 Note that a cursor always moves when text is inserted before the current position of the cursor, and it
1366 always keeps its position when text is inserted after the current position of the cursor.
1368 \sa keepPositionOnInsert()
1370 void QTextCursor::setKeepPositionOnInsert(bool b)
1373 d->keepPositionOnInsert = b;
1379 Inserts \a text at the current position, using the current
1382 If there is a selection, the selection is deleted and replaced by
1383 \a text, for example:
1384 \snippet code/src_gui_text_qtextcursor.cpp 0
1385 This clears any existing selection, selects the word at the cursor
1386 (i.e. from position() forward), and replaces the selection with
1387 the phrase "Hello World".
1389 Any ASCII linefeed characters (\\n) in the inserted text are transformed
1390 into unicode block separators, corresponding to insertBlock() calls.
1392 \sa charFormat(), hasSelection()
1394 void QTextCursor::insertText(const QString &text)
1396 QTextCharFormat fmt = charFormat();
1397 fmt.clearProperty(QTextFormat::ObjectType);
1398 insertText(text, fmt);
1402 \fn void QTextCursor::insertText(const QString &text, const QTextCharFormat &format)
1405 Inserts \a text at the current position with the given \a format.
1407 void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format)
1412 Q_ASSERT(_format.isValid());
1414 QTextCharFormat format = _format;
1415 format.clearProperty(QTextFormat::ObjectIndex);
1417 bool hasEditBlock = false;
1419 if (d->anchor != d->position) {
1420 hasEditBlock = true;
1421 d->priv->beginEditBlock();
1425 if (!text.isEmpty()) {
1426 QTextFormatCollection *formats = d->priv->formatCollection();
1427 int formatIdx = formats->indexForFormat(format);
1428 Q_ASSERT(formats->format(formatIdx).isCharFormat());
1430 QTextBlockFormat blockFmt = blockFormat();
1433 int textStart = d->priv->text.length();
1435 d->priv->text += text;
1436 int textEnd = d->priv->text.length();
1438 for (int i = 0; i < text.length(); ++i) {
1439 QChar ch = text.at(i);
1441 const int blockEnd = i;
1443 if (ch == QLatin1Char('\r')
1444 && (i + 1) < text.length()
1445 && text.at(i + 1) == QLatin1Char('\n')) {
1450 if (ch == QLatin1Char('\n')
1451 || ch == QChar::ParagraphSeparator
1452 || ch == QTextBeginningOfFrame
1453 || ch == QTextEndOfFrame
1454 || ch == QLatin1Char('\r')) {
1456 if (!hasEditBlock) {
1457 hasEditBlock = true;
1458 d->priv->beginEditBlock();
1461 if (blockEnd > blockStart)
1462 d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx);
1464 d->insertBlock(blockFmt, format);
1468 if (textStart + blockStart < textEnd)
1469 d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx);
1472 d->priv->endEditBlock();
1477 If there is no selected text, deletes the character \e at the
1478 current cursor position; otherwise deletes the selected text.
1480 \sa deletePreviousChar(), hasSelection(), clearSelection()
1482 void QTextCursor::deleteChar()
1487 if (d->position != d->anchor) {
1488 removeSelectedText();
1492 if (!d->canDelete(d->position))
1494 d->adjusted_anchor = d->anchor =
1495 d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters);
1501 If there is no selected text, deletes the character \e before the
1502 current cursor position; otherwise deletes the selected text.
1504 \sa deleteChar(), hasSelection(), clearSelection()
1506 void QTextCursor::deletePreviousChar()
1511 if (d->position != d->anchor) {
1512 removeSelectedText();
1516 if (d->anchor < 1 || !d->canDelete(d->anchor-1))
1520 QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
1521 const QTextFragmentData * const frag = fragIt.value();
1522 int fpos = fragIt.position();
1523 QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition);
1524 if (d->anchor > fpos && uc.isLowSurrogate()) {
1525 // second half of a surrogate, check if we have the first half as well,
1526 // if yes delete both at once
1527 uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition);
1528 if (uc.isHighSurrogate())
1532 d->adjusted_anchor = d->anchor;
1538 Selects text in the document according to the given \a selection.
1540 void QTextCursor::select(SelectionType selection)
1547 const QTextBlock block = d->block();
1549 switch (selection) {
1550 case LineUnderCursor:
1551 movePosition(StartOfLine);
1552 movePosition(EndOfLine, KeepAnchor);
1554 case WordUnderCursor:
1555 movePosition(StartOfWord);
1556 movePosition(EndOfWord, KeepAnchor);
1558 case BlockUnderCursor:
1559 if (block.length() == 1) // no content
1561 movePosition(StartOfBlock);
1562 // also select the paragraph separator
1563 if (movePosition(PreviousBlock)) {
1564 movePosition(EndOfBlock);
1565 movePosition(NextBlock, KeepAnchor);
1567 movePosition(EndOfBlock, KeepAnchor);
1570 movePosition(Start);
1571 movePosition(End, KeepAnchor);
1577 Returns true if the cursor contains a selection; otherwise returns false.
1579 bool QTextCursor::hasSelection() const
1581 return !!d && d->position != d->anchor;
1586 Returns true if the cursor contains a selection that is not simply a
1587 range from selectionStart() to selectionEnd(); otherwise returns false.
1589 Complex selections are ones that span at least two cells in a table;
1590 their extent is specified by selectedTableCells().
1592 bool QTextCursor::hasComplexSelection() const
1597 return d->complexSelectionTable() != 0;
1601 If the selection spans over table cells, \a firstRow is populated
1602 with the number of the first row in the selection, \a firstColumn
1603 with the number of the first column in the selection, and \a
1604 numRows and \a numColumns with the number of rows and columns in
1605 the selection. If the selection does not span any table cells the
1606 results are harmless but undefined.
1608 void QTextCursor::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
1615 if (!d || d->position == d->anchor)
1618 d->selectedTableCells(firstRow, numRows, firstColumn, numColumns);
1623 Clears the current selection by setting the anchor to the cursor position.
1625 Note that it does \b{not} delete the text of the selection.
1627 \sa removeSelectedText(), hasSelection()
1629 void QTextCursor::clearSelection()
1633 d->adjusted_anchor = d->anchor = d->position;
1634 d->currentCharFormat = -1;
1638 If there is a selection, its content is deleted; otherwise does
1643 void QTextCursor::removeSelectedText()
1645 if (!d || !d->priv || d->position == d->anchor)
1648 d->priv->beginEditBlock();
1650 d->priv->endEditBlock();
1655 Returns the start of the selection or position() if the
1656 cursor doesn't have a selection.
1658 \sa selectionEnd(), position(), anchor()
1660 int QTextCursor::selectionStart() const
1664 return qMin(d->position, d->adjusted_anchor);
1668 Returns the end of the selection or position() if the cursor
1669 doesn't have a selection.
1671 \sa selectionStart(), position(), anchor()
1673 int QTextCursor::selectionEnd() const
1677 return qMax(d->position, d->adjusted_anchor);
1680 static void getText(QString &text, QTextDocumentPrivate *priv, const QString &docText, int pos, int end)
1683 QTextDocumentPrivate::FragmentIterator fragIt = priv->find(pos);
1684 const QTextFragmentData * const frag = fragIt.value();
1686 const int offsetInFragment = qMax(0, pos - fragIt.position());
1687 const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
1689 text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
1695 Returns the current selection's text (which may be empty). This
1696 only returns the text, with no rich text formatting information.
1697 If you want a document fragment (i.e. formatted rich text) use
1698 selection() instead.
1700 \note If the selection obtained from an editor spans a line break,
1701 the text will contain a Unicode U+2029 paragraph separator character
1702 instead of a newline \c{\n} character. Use QString::replace() to
1703 replace these characters with newlines.
1705 QString QTextCursor::selectedText() const
1707 if (!d || !d->priv || d->position == d->anchor)
1710 const QString docText = d->priv->buffer();
1713 QTextTable *table = d->complexSelectionTable();
1715 int row_start, col_start, num_rows, num_cols;
1716 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
1718 Q_ASSERT(row_start != -1);
1719 for (int r = row_start; r < row_start + num_rows; ++r) {
1720 for (int c = col_start; c < col_start + num_cols; ++c) {
1721 QTextTableCell cell = table->cellAt(r, c);
1722 int rspan = cell.rowSpan();
1723 int cspan = cell.columnSpan();
1725 int cr = cell.row();
1730 int cc = cell.column();
1735 getText(text, d->priv, docText, cell.firstPosition(), cell.lastPosition());
1739 getText(text, d->priv, docText, selectionStart(), selectionEnd());
1746 Returns the current selection (which may be empty) with all its
1747 formatting information. If you just want the selected text (i.e.
1748 plain text) use selectedText() instead.
1750 \note Unlike QTextDocumentFragment::toPlainText(),
1751 selectedText() may include special unicode characters such as
1752 QChar::ParagraphSeparator.
1754 \sa QTextDocumentFragment::toPlainText()
1756 QTextDocumentFragment QTextCursor::selection() const
1758 return QTextDocumentFragment(*this);
1762 Returns the block that contains the cursor.
1764 QTextBlock QTextCursor::block() const
1767 return QTextBlock();
1772 Returns the block format of the block the cursor is in.
1774 \sa setBlockFormat(), charFormat()
1776 QTextBlockFormat QTextCursor::blockFormat() const
1779 return QTextBlockFormat();
1781 return d->block().blockFormat();
1785 Sets the block format of the current block (or all blocks that
1786 are contained in the selection) to \a format.
1788 \sa blockFormat(), mergeBlockFormat()
1790 void QTextCursor::setBlockFormat(const QTextBlockFormat &format)
1795 d->setBlockFormat(format, QTextDocumentPrivate::SetFormat);
1799 Modifies the block format of the current block (or all blocks that
1800 are contained in the selection) with the block format specified by
1803 \sa setBlockFormat(), blockFormat()
1805 void QTextCursor::mergeBlockFormat(const QTextBlockFormat &modifier)
1810 d->setBlockFormat(modifier, QTextDocumentPrivate::MergeFormat);
1814 Returns the block character format of the block the cursor is in.
1816 The block char format is the format used when inserting text at the
1817 beginning of an empty block.
1819 \sa setBlockCharFormat()
1821 QTextCharFormat QTextCursor::blockCharFormat() const
1824 return QTextCharFormat();
1826 return d->block().charFormat();
1830 Sets the block char format of the current block (or all blocks that
1831 are contained in the selection) to \a format.
1833 \sa blockCharFormat()
1835 void QTextCursor::setBlockCharFormat(const QTextCharFormat &format)
1840 d->setBlockCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1844 Modifies the block char format of the current block (or all blocks that
1845 are contained in the selection) with the block format specified by
1848 \sa setBlockCharFormat()
1850 void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier)
1855 d->setBlockCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1859 Returns the format of the character immediately before the cursor
1860 position(). If the cursor is positioned at the beginning of a text
1861 block that is not empty then the format of the character
1862 immediately after the cursor is returned.
1864 \sa insertText(), blockFormat()
1866 QTextCharFormat QTextCursor::charFormat() const
1869 return QTextCharFormat();
1871 int idx = d->currentCharFormat;
1873 QTextBlock block = d->block();
1876 if (d->position == block.position()
1877 && block.length() > 1)
1880 pos = d->position - 1;
1883 idx = d->priv->blockCharFormatIndex(d->priv->blockMap().firstNode());
1885 Q_ASSERT(pos >= 0 && pos < d->priv->length());
1887 QTextDocumentPrivate::FragmentIterator it = d->priv->find(pos);
1888 Q_ASSERT(!it.atEnd());
1889 idx = it.value()->format;
1893 QTextCharFormat cfmt = d->priv->formatCollection()->charFormat(idx);
1894 cfmt.clearProperty(QTextFormat::ObjectIndex);
1896 Q_ASSERT(cfmt.isValid());
1901 Sets the cursor's current character format to the given \a
1902 format. If the cursor has a selection, the given \a format is
1903 applied to the current selection.
1905 \sa hasSelection(), mergeCharFormat()
1907 void QTextCursor::setCharFormat(const QTextCharFormat &format)
1911 if (d->position == d->anchor) {
1912 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1915 d->setCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1919 Merges the cursor's current character format with the properties
1920 described by format \a modifier. If the cursor has a selection,
1921 this function applies all the properties set in \a modifier to all
1922 the character formats that are part of the selection.
1924 \sa hasSelection(), setCharFormat()
1926 void QTextCursor::mergeCharFormat(const QTextCharFormat &modifier)
1930 if (d->position == d->anchor) {
1931 QTextCharFormat format = charFormat();
1932 format.merge(modifier);
1933 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1937 d->setCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1941 Returns true if the cursor is at the start of a block; otherwise
1944 \sa atBlockEnd(), atStart()
1946 bool QTextCursor::atBlockStart() const
1951 return d->position == d->block().position();
1955 Returns true if the cursor is at the end of a block; otherwise
1958 \sa atBlockStart(), atEnd()
1960 bool QTextCursor::atBlockEnd() const
1965 return d->position == d->block().position() + d->block().length() - 1;
1969 Returns true if the cursor is at the start of the document;
1970 otherwise returns false.
1972 \sa atBlockStart(), atEnd()
1974 bool QTextCursor::atStart() const
1979 return d->position == 0;
1985 Returns true if the cursor is at the end of the document;
1986 otherwise returns false.
1988 \sa atStart(), atBlockEnd()
1990 bool QTextCursor::atEnd() const
1995 return d->position == d->priv->length() - 1;
1999 Inserts a new empty block at the cursor position() with the
2000 current blockFormat() and charFormat().
2002 \sa setBlockFormat()
2004 void QTextCursor::insertBlock()
2006 insertBlock(blockFormat());
2012 Inserts a new empty block at the cursor position() with block
2013 format \a format and the current charFormat() as block char format.
2015 \sa setBlockFormat()
2017 void QTextCursor::insertBlock(const QTextBlockFormat &format)
2019 QTextCharFormat charFmt = charFormat();
2020 charFmt.clearProperty(QTextFormat::ObjectType);
2021 insertBlock(format, charFmt);
2025 \fn void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
2028 Inserts a new empty block at the cursor position() with block
2029 format \a format and \a charFormat as block char format.
2031 \sa setBlockFormat()
2033 void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &_charFormat)
2038 QTextCharFormat charFormat = _charFormat;
2039 charFormat.clearProperty(QTextFormat::ObjectIndex);
2041 d->priv->beginEditBlock();
2043 d->insertBlock(format, charFormat);
2044 d->priv->endEditBlock();
2049 Inserts a new block at the current position and makes it the first
2050 list item of a newly created list with the given \a format. Returns
2053 \sa currentList(), createList(), insertBlock()
2055 QTextList *QTextCursor::insertList(const QTextListFormat &format)
2058 return createList(format);
2064 Inserts a new block at the current position and makes it the first
2065 list item of a newly created list with the given \a style. Returns
2068 \sa currentList(), createList(), insertBlock()
2070 QTextList *QTextCursor::insertList(QTextListFormat::Style style)
2073 return createList(style);
2077 Creates and returns a new list with the given \a format, and makes the
2078 current paragraph the cursor is in the first list item.
2080 \sa insertList(), currentList()
2082 QTextList *QTextCursor::createList(const QTextListFormat &format)
2087 QTextList *list = static_cast<QTextList *>(d->priv->createObject(format));
2088 QTextBlockFormat modifier;
2089 modifier.setObjectIndex(list->objectIndex());
2090 mergeBlockFormat(modifier);
2097 Creates and returns a new list with the given \a style, making the
2098 cursor's current paragraph the first list item.
2100 The style to be used is defined by the QTextListFormat::Style enum.
2102 \sa insertList(), currentList()
2104 QTextList *QTextCursor::createList(QTextListFormat::Style style)
2106 QTextListFormat fmt;
2107 fmt.setStyle(style);
2108 return createList(fmt);
2112 Returns the current list if the cursor position() is inside a
2113 block that is part of a list; otherwise returns 0.
2115 \sa insertList(), createList()
2117 QTextList *QTextCursor::currentList() const
2122 QTextBlockFormat b = blockFormat();
2123 QTextObject *o = d->priv->objectForFormat(b);
2124 return qobject_cast<QTextList *>(o);
2128 \fn QTextTable *QTextCursor::insertTable(int rows, int columns)
2132 Creates a new table with the given number of \a rows and \a columns,
2133 inserts it at the current cursor position() in the document, and returns
2134 the table object. The cursor is moved to the beginning of the first cell.
2136 There must be at least one row and one column in the table.
2140 QTextTable *QTextCursor::insertTable(int rows, int cols)
2142 return insertTable(rows, cols, QTextTableFormat());
2146 \fn QTextTable *QTextCursor::insertTable(int rows, int columns, const QTextTableFormat &format)
2148 Creates a new table with the given number of \a rows and \a columns
2149 in the specified \a format, inserts it at the current cursor position()
2150 in the document, and returns the table object. The cursor is moved to
2151 the beginning of the first cell.
2153 There must be at least one row and one column in the table.
2157 QTextTable *QTextCursor::insertTable(int rows, int cols, const QTextTableFormat &format)
2159 if(!d || !d->priv || rows == 0 || cols == 0)
2162 int pos = d->position;
2163 QTextTable *t = QTextTablePrivate::createTable(d->priv, d->position, rows, cols, format);
2164 d->setPosition(pos+1);
2165 // ##### what should we do if we have a selection?
2166 d->anchor = d->position;
2167 d->adjusted_anchor = d->anchor;
2172 Returns a pointer to the current table if the cursor position()
2173 is inside a block that is part of a table; otherwise returns 0.
2177 QTextTable *QTextCursor::currentTable() const
2182 QTextFrame *frame = d->priv->frameAt(d->position);
2184 QTextTable *table = qobject_cast<QTextTable *>(frame);
2187 frame = frame->parentFrame();
2193 Inserts a frame with the given \a format at the current cursor position(),
2194 moves the cursor position() inside the frame, and returns the frame.
2196 If the cursor holds a selection, the whole selection is moved inside the
2201 QTextFrame *QTextCursor::insertFrame(const QTextFrameFormat &format)
2206 return d->priv->insertFrame(selectionStart(), selectionEnd(), format);
2210 Returns a pointer to the current frame. Returns 0 if the cursor is invalid.
2214 QTextFrame *QTextCursor::currentFrame() const
2219 return d->priv->frameAt(d->position);
2224 Inserts the text \a fragment at the current position().
2226 void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
2228 if (!d || !d->priv || fragment.isEmpty())
2231 d->priv->beginEditBlock();
2233 fragment.d->insert(*this);
2234 d->priv->endEditBlock();
2236 if (fragment.d && fragment.d->doc)
2237 d->priv->mergeCachedResources(fragment.d->doc->docHandle());
2242 Inserts the text \a html at the current position(). The text is interpreted as
2245 \note When using this function with a style sheet, the style sheet will
2246 only apply to the current block in the document. In order to apply a style
2247 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2251 #ifndef QT_NO_TEXTHTMLPARSER
2253 void QTextCursor::insertHtml(const QString &html)
2257 QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html, d->priv->document());
2258 insertFragment(fragment);
2261 #endif // QT_NO_TEXTHTMLPARSER
2267 Inserts the image defined by the given \a format at the cursor's current position
2268 with the specified \a alignment.
2272 void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
2277 QTextFrameFormat ffmt;
2278 ffmt.setPosition(alignment);
2279 QTextObject *obj = d->priv->createObject(ffmt);
2281 QTextImageFormat fmt = format;
2282 fmt.setObjectIndex(obj->objectIndex());
2284 d->priv->beginEditBlock();
2286 const int idx = d->priv->formatCollection()->indexForFormat(fmt);
2287 d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
2288 d->priv->endEditBlock();
2292 Inserts the image defined by \a format at the current position().
2294 void QTextCursor::insertImage(const QTextImageFormat &format)
2296 insertText(QString(QChar::ObjectReplacementCharacter), format);
2302 Convenience method for inserting the image with the given \a name at the
2305 \snippet code/src_gui_text_qtextcursor.cpp 1
2307 void QTextCursor::insertImage(const QString &name)
2309 QTextImageFormat format;
2310 format.setName(name);
2311 insertImage(format);
2318 Convenience function for inserting the given \a image with an optional
2319 \a name at the current position().
2321 void QTextCursor::insertImage(const QImage &image, const QString &name)
2323 if (image.isNull()) {
2324 qWarning("QTextCursor::insertImage: attempt to add an invalid image");
2327 QString imageName = name;
2329 imageName = QString::number(image.cacheKey());
2330 d->priv->document()->addResource(QTextDocument::ImageResource, QUrl(imageName), image);
2331 QTextImageFormat format;
2332 format.setName(imageName);
2333 insertImage(format);
2337 \fn bool QTextCursor::operator!=(const QTextCursor &other) const
2339 Returns true if the \a other cursor is at a different position in
2340 the document as this cursor; otherwise returns false.
2342 bool QTextCursor::operator!=(const QTextCursor &rhs) const
2344 return !operator==(rhs);
2348 \fn bool QTextCursor::operator<(const QTextCursor &other) const
2350 Returns true if the \a other cursor is positioned later in the
2351 document than this cursor; otherwise returns false.
2353 bool QTextCursor::operator<(const QTextCursor &rhs) const
2361 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<", "cannot compare cursors attached to different documents");
2363 return d->position < rhs.d->position;
2367 \fn bool QTextCursor::operator<=(const QTextCursor &other) const
2369 Returns true if the \a other cursor is positioned later or at the
2370 same position in the document as this cursor; otherwise returns
2373 bool QTextCursor::operator<=(const QTextCursor &rhs) const
2381 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<=", "cannot compare cursors attached to different documents");
2383 return d->position <= rhs.d->position;
2387 \fn bool QTextCursor::operator==(const QTextCursor &other) const
2389 Returns true if the \a other cursor is at the same position in the
2390 document as this cursor; otherwise returns false.
2392 bool QTextCursor::operator==(const QTextCursor &rhs) const
2400 return d->position == rhs.d->position && d->priv == rhs.d->priv;
2404 \fn bool QTextCursor::operator>=(const QTextCursor &other) const
2406 Returns true if the \a other cursor is positioned earlier or at the
2407 same position in the document as this cursor; otherwise returns
2410 bool QTextCursor::operator>=(const QTextCursor &rhs) const
2418 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>=", "cannot compare cursors attached to different documents");
2420 return d->position >= rhs.d->position;
2424 \fn bool QTextCursor::operator>(const QTextCursor &other) const
2426 Returns true if the \a other cursor is positioned earlier in the
2427 document than this cursor; otherwise returns false.
2429 bool QTextCursor::operator>(const QTextCursor &rhs) const
2437 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>", "cannot compare cursors attached to different documents");
2439 return d->position > rhs.d->position;
2443 Indicates the start of a block of editing operations on the
2444 document that should appear as a single operation from an
2445 undo/redo point of view.
2449 \snippet code/src_gui_text_qtextcursor.cpp 2
2451 The call to undo() will cause both insertions to be undone,
2452 causing both "World" and "Hello" to be removed.
2454 It is possible to nest calls to beginEditBlock and endEditBlock. The
2455 top-most pair will determine the scope of the undo/redo operation.
2459 void QTextCursor::beginEditBlock()
2464 if (d->priv->editBlock == 0) // we are the initial edit block, store current cursor position for undo
2465 d->priv->editBlockCursorPosition = d->position;
2467 d->priv->beginEditBlock();
2471 Like beginEditBlock() indicates the start of a block of editing operations
2472 that should appear as a single operation for undo/redo. However unlike
2473 beginEditBlock() it does not start a new block but reverses the previous call to
2474 endEditBlock() and therefore makes following operations part of the previous edit block created.
2478 \snippet code/src_gui_text_qtextcursor.cpp 3
2480 The call to undo() will cause all three insertions to be undone.
2482 \sa beginEditBlock(), endEditBlock()
2484 void QTextCursor::joinPreviousEditBlock()
2489 d->priv->joinPreviousEditBlock();
2493 Indicates the end of a block of editing operations on the document
2494 that should appear as a single operation from an undo/redo point
2497 \sa beginEditBlock()
2500 void QTextCursor::endEditBlock()
2505 d->priv->endEditBlock();
2509 Returns true if this cursor and \a other are copies of each other, i.e.
2510 one of them was created as a copy of the other and neither has moved since.
2511 This is much stricter than equality.
2513 \sa operator=(), operator==()
2515 bool QTextCursor::isCopyOf(const QTextCursor &other) const
2517 return d == other.d;
2522 Returns the number of the block the cursor is in, or 0 if the cursor is invalid.
2524 Note that this function only makes sense in documents without complex objects such
2525 as tables or frames.
2527 int QTextCursor::blockNumber() const
2532 return d->block().blockNumber();
2538 Returns the position of the cursor within its containing line.
2540 Note that this is the column number relative to a wrapped line,
2541 not relative to the block (i.e. the paragraph).
2543 You probably want to call positionInBlock() instead.
2545 \sa positionInBlock()
2547 int QTextCursor::columnNumber() const
2552 QTextBlock block = d->block();
2553 if (!block.isValid())
2556 const QTextLayout *layout = d->blockLayout(block);
2558 const int relativePos = d->position - block.position();
2560 if (layout->lineCount() == 0)
2563 QTextLine line = layout->lineForTextPosition(relativePos);
2564 if (!line.isValid())
2566 return relativePos - line.textStart();
2571 Returns the document this cursor is associated with.
2573 QTextDocument *QTextCursor::document() const
2576 return d->priv->document();
2577 return 0; // document went away
2581 \enum Qt::CursorMoveStyle
2583 This enum describes the movement style available to text cursors. The options
2586 \value LogicalMoveStyle Within a left-to-right text block, decrease cursor
2587 position when pressing left arrow key, increase cursor position when pressing
2588 the right arrow key. If the text block is right-to-left, the opposite behavior
2590 \value VisualMoveStyle Pressing the left arrow key will always cause the cursor
2591 to move left, regardless of the text's writing direction. Pressing the right
2592 arrow key will always cause the cursor to move right.