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);
884 \brief The QTextCursor class offers an API to access and modify QTextDocuments.
886 \ingroup richtext-processing
889 Text cursors are objects that are used to access and modify the
890 contents and underlying structure of text documents via a
891 programming interface that mimics the behavior of a cursor in a
892 text editor. QTextCursor contains information about both the
893 cursor's position within a QTextDocument and any selection that it
896 QTextCursor is modeled on the way a text cursor behaves in a text
897 editor, providing a programmatic means of performing standard
898 actions through the user interface. A document can be thought of
899 as a single string of characters. The cursor's current position()
900 then is always either \e between two consecutive characters in the
901 string, or else \e before the very first character or \e after the
902 very last character in the string. Documents can also contain
903 tables, lists, images, and other objects in addition to text but,
904 from the developer's point of view, the document can be treated as
905 one long string. Some portions of that string can be considered
906 to lie within particular blocks (e.g. paragraphs), or within a
907 table's cell, or a list's item, or other structural elements. When
908 we refer to "current character" we mean the character immediately
909 \e before the cursor position() in the document. Similarly, the
910 "current block" is the block that contains the cursor position().
912 A QTextCursor also has an anchor() position. The text that is
913 between the anchor() and the position() is the selection. If
914 anchor() == position() there is no selection.
916 The cursor position can be changed programmatically using
917 setPosition() and movePosition(); the latter can also be used to
918 select text. For selections see selectionStart(), selectionEnd(),
919 hasSelection(), clearSelection(), and removeSelectedText().
921 If the position() is at the start of a block atBlockStart()
922 returns true; and if it is at the end of a block atBlockEnd() returns
923 true. The format of the current character is returned by
924 charFormat(), and the format of the current block is returned by
927 Formatting can be applied to the current text document using the
928 setCharFormat(), mergeCharFormat(), setBlockFormat() and
929 mergeBlockFormat() functions. The 'set' functions will replace the
930 cursor's current character or block format, while the 'merge'
931 functions add the given format properties to the cursor's current
932 format. If the cursor has a selection the given format is applied
933 to the current selection. Note that when only parts of a block is
934 selected the block format is applied to the entire block. The text
935 at the current character position can be turned into a list using
938 Deletions can be achieved using deleteChar(),
939 deletePreviousChar(), and removeSelectedText().
941 Text strings can be inserted into the document with the insertText()
942 function, blocks (representing new paragraphs) can be inserted with
945 Existing fragments of text can be inserted with insertFragment() but,
946 if you want to insert pieces of text in various formats, it is usually
947 still easier to use insertText() and supply a character format.
949 Various types of higher-level structure can also be inserted into the
950 document with the cursor:
953 \li Lists are ordered sequences of block elements that are decorated with
954 bullet points or symbols. These are inserted in a specified format
956 \li Tables are inserted with the insertTable() function, and can be
957 given an optional format. These contain an array of cells that can
958 be traversed using the cursor.
959 \li Inline images are inserted with insertImage(). The image to be
960 used can be specified in an image format, or by name.
961 \li Frames are inserted by calling insertFrame() with a specified format.
964 Actions can be grouped (i.e. treated as a single action for
965 undo/redo) using beginEditBlock() and endEditBlock().
967 Cursor movements are limited to valid cursor positions. In Latin
968 writing this is between any two consecutive characters in the
969 text, before the first character, or after the last character. In
970 some other writing systems cursor movements are limited to
971 "clusters" (e.g. a syllable in Devanagari, or a base letter plus
972 diacritics). Functions such as movePosition() and deleteChar()
973 limit cursor movement to these valid positions.
975 \sa {Rich Text Processing}
980 \enum QTextCursor::MoveOperation
982 \value NoMove Keep the cursor where it is
984 \value Start Move to the start of the document.
985 \value StartOfLine Move to the start of the current line.
986 \value StartOfBlock Move to the start of the current block.
987 \value StartOfWord Move to the start of the current word.
988 \value PreviousBlock Move to the start of the previous block.
989 \value PreviousCharacter Move to the previous character.
990 \value PreviousWord Move to the beginning of the previous word.
991 \value Up Move up one line.
992 \value Left Move left one character.
993 \value WordLeft Move left one word.
995 \value End Move to the end of the document.
996 \value EndOfLine Move to the end of the current line.
997 \value EndOfWord Move to the end of the current word.
998 \value EndOfBlock Move to the end of the current block.
999 \value NextBlock Move to the beginning of the next block.
1000 \value NextCharacter Move to the next character.
1001 \value NextWord Move to the next word.
1002 \value Down Move down one line.
1003 \value Right Move right one character.
1004 \value WordRight Move right one word.
1006 \value NextCell Move to the beginning of the next table cell inside the
1007 current table. If the current cell is the last cell in the row, the
1008 cursor will move to the first cell in the next row.
1009 \value PreviousCell Move to the beginning of the previous table cell
1010 inside the current table. If the current cell is the first cell in
1011 the row, the cursor will move to the last cell in the previous row.
1012 \value NextRow Move to the first new cell of the next row in the current
1014 \value PreviousRow Move to the last cell of the previous row in the
1021 \enum QTextCursor::MoveMode
1023 \value MoveAnchor Moves the anchor to the same position as the cursor itself.
1024 \value KeepAnchor Keeps the anchor where it is.
1026 If the anchor() is kept where it is and the position() is moved,
1027 the text in between will be selected.
1031 \enum QTextCursor::SelectionType
1033 This enum describes the types of selection that can be applied with the
1036 \value Document Selects the entire document.
1037 \value BlockUnderCursor Selects the block of text under the cursor.
1038 \value LineUnderCursor Selects the line of text under the cursor.
1039 \value WordUnderCursor Selects the word under the cursor. If the cursor
1040 is not positioned within a string of selectable characters, no
1045 Constructs a null cursor.
1047 QTextCursor::QTextCursor()
1053 Constructs a cursor pointing to the beginning of the \a document.
1055 QTextCursor::QTextCursor(QTextDocument *document)
1056 : d(new QTextCursorPrivate(document->docHandle()))
1061 Constructs a cursor pointing to the beginning of the \a frame.
1063 QTextCursor::QTextCursor(QTextFrame *frame)
1064 : d(new QTextCursorPrivate(frame->document()->docHandle()))
1066 d->adjusted_anchor = d->anchor = d->position = frame->firstPosition();
1071 Constructs a cursor pointing to the beginning of the \a block.
1073 QTextCursor::QTextCursor(const QTextBlock &block)
1074 : d(new QTextCursorPrivate(block.docHandle()))
1076 d->adjusted_anchor = d->anchor = d->position = block.position();
1083 QTextCursor::QTextCursor(QTextDocumentPrivate *p, int pos)
1084 : d(new QTextCursorPrivate(p))
1086 d->adjusted_anchor = d->anchor = d->position = pos;
1094 QTextCursor::QTextCursor(QTextCursorPrivate *d)
1101 Constructs a new cursor that is a copy of \a cursor.
1103 QTextCursor::QTextCursor(const QTextCursor &cursor)
1109 Makes a copy of \a cursor and assigns it to this QTextCursor. Note
1110 that QTextCursor is an \l{Implicitly Shared Classes}{implicitly
1114 QTextCursor &QTextCursor::operator=(const QTextCursor &cursor)
1121 Destroys the QTextCursor.
1123 QTextCursor::~QTextCursor()
1128 Returns true if the cursor is null; otherwise returns false. A null
1129 cursor is created by the default constructor.
1131 bool QTextCursor::isNull() const
1133 return !d || !d->priv;
1137 Moves the cursor to the absolute position in the document specified by
1138 \a pos using a \c MoveMode specified by \a m. The cursor is positioned
1141 \sa position(), movePosition(), anchor()
1143 void QTextCursor::setPosition(int pos, MoveMode m)
1148 if (pos < 0 || pos >= d->priv->length()) {
1149 qWarning("QTextCursor::setPosition: Position '%d' out of range", pos);
1153 d->setPosition(pos);
1154 if (m == MoveAnchor) {
1156 d->adjusted_anchor = pos;
1157 } else { // keep anchor
1158 QTextCursor::MoveOperation op;
1159 if (pos < d->anchor)
1160 op = QTextCursor::Left;
1162 op = QTextCursor::Right;
1163 d->adjustCursor(op);
1169 Returns the absolute position of the cursor within the document.
1170 The cursor is positioned between characters.
1172 \sa setPosition(), movePosition(), anchor(), positionInBlock()
1174 int QTextCursor::position() const
1183 Returns the relative position of the cursor within the block.
1184 The cursor is positioned between characters.
1186 This is equivalent to \c{ position() - block().position()}.
1190 int QTextCursor::positionInBlock() const
1194 return d->position - d->block().position();
1198 Returns the anchor position; this is the same as position() unless
1199 there is a selection in which case position() marks one end of the
1200 selection and anchor() marks the other end. Just like the cursor
1201 position, the anchor position is between characters.
1203 \sa position(), setPosition(), movePosition(), selectionStart(), selectionEnd()
1205 int QTextCursor::anchor() const
1213 \fn bool QTextCursor::movePosition(MoveOperation operation, MoveMode mode, int n)
1215 Moves the cursor by performing the given \a operation \a n times, using the specified
1216 \a mode, and returns true if all operations were completed successfully; otherwise
1219 For example, if this function is repeatedly used to seek to the end of the next
1220 word, it will eventually fail when the end of the document is reached.
1222 By default, the move operation is performed once (\a n = 1).
1224 If \a mode is \c KeepAnchor, the cursor selects the text it moves
1225 over. This is the same effect that the user achieves when they
1226 hold down the Shift key and move the cursor with the cursor keys.
1228 \sa setVisualNavigation()
1230 bool QTextCursor::movePosition(MoveOperation op, MoveMode mode, int n)
1244 int previousPosition = d->position;
1245 for (; n > 0; --n) {
1246 if (!d->movePosition(op, mode))
1250 if (d->visualNavigation && !d->block().isVisible()) {
1251 QTextBlock b = d->block();
1252 if (previousPosition < d->position) {
1253 while (!b.next().isVisible())
1255 d->setPosition(b.position() + b.length() - 1);
1257 while (!b.previous().isVisible())
1259 d->setPosition(b.position());
1261 if (mode == QTextCursor::MoveAnchor)
1262 d->anchor = d->position;
1263 while (d->movePosition(op, mode)
1264 && !d->block().isVisible())
1274 Returns true if the cursor does visual navigation; otherwise
1277 Visual navigation means skipping over hidden text pragraphs. The
1280 \sa setVisualNavigation(), movePosition()
1282 bool QTextCursor::visualNavigation() const
1284 return d ? d->visualNavigation : false;
1290 Sets visual navigation to \a b.
1292 Visual navigation means skipping over hidden text pragraphs. The
1295 \sa visualNavigation(), movePosition()
1297 void QTextCursor::setVisualNavigation(bool b)
1300 d->visualNavigation = b;
1307 Sets the visual x position for vertical cursor movements to \a x.
1309 The vertical movement x position is cleared automatically when the cursor moves horizontally, and kept
1310 unchanged when the cursor moves vertically. The mechanism allows the cursor to move up and down on a
1311 visually straight line with proportional fonts, and to gently "jump" over short lines.
1313 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1314 cursor moves up or down.
1316 \sa verticalMovementX()
1318 void QTextCursor::setVerticalMovementX(int x)
1326 Returns the visual x position for vertical cursor movements.
1328 A value of -1 indicates no predefined x position. It will then be set automatically the next time the
1329 cursor moves up or down.
1331 \sa setVerticalMovementX()
1333 int QTextCursor::verticalMovementX() const
1335 return d ? d->x : -1;
1341 Returns whether the cursor should keep its current position when text gets inserted at the position of the
1344 The default is false;
1346 \sa setKeepPositionOnInsert()
1348 bool QTextCursor::keepPositionOnInsert() const
1350 return d ? d->keepPositionOnInsert : false;
1356 Defines whether the cursor should keep its current position when text gets inserted at the current position of the
1359 If \a b is true, the cursor keeps its current position when text gets inserted at the positing of the cursor.
1360 If \a b is false, the cursor moves along with the inserted text.
1362 The default is false.
1364 Note that a cursor always moves when text is inserted before the current position of the cursor, and it
1365 always keeps its position when text is inserted after the current position of the cursor.
1367 \sa keepPositionOnInsert()
1369 void QTextCursor::setKeepPositionOnInsert(bool b)
1372 d->keepPositionOnInsert = b;
1378 Inserts \a text at the current position, using the current
1381 If there is a selection, the selection is deleted and replaced by
1382 \a text, for example:
1383 \snippet code/src_gui_text_qtextcursor.cpp 0
1384 This clears any existing selection, selects the word at the cursor
1385 (i.e. from position() forward), and replaces the selection with
1386 the phrase "Hello World".
1388 Any ASCII linefeed characters (\\n) in the inserted text are transformed
1389 into unicode block separators, corresponding to insertBlock() calls.
1391 \sa charFormat(), hasSelection()
1393 void QTextCursor::insertText(const QString &text)
1395 QTextCharFormat fmt = charFormat();
1396 fmt.clearProperty(QTextFormat::ObjectType);
1397 insertText(text, fmt);
1401 \fn void QTextCursor::insertText(const QString &text, const QTextCharFormat &format)
1404 Inserts \a text at the current position with the given \a format.
1406 void QTextCursor::insertText(const QString &text, const QTextCharFormat &_format)
1411 Q_ASSERT(_format.isValid());
1413 QTextCharFormat format = _format;
1414 format.clearProperty(QTextFormat::ObjectIndex);
1416 bool hasEditBlock = false;
1418 if (d->anchor != d->position) {
1419 hasEditBlock = true;
1420 d->priv->beginEditBlock();
1424 if (!text.isEmpty()) {
1425 QTextFormatCollection *formats = d->priv->formatCollection();
1426 int formatIdx = formats->indexForFormat(format);
1427 Q_ASSERT(formats->format(formatIdx).isCharFormat());
1429 QTextBlockFormat blockFmt = blockFormat();
1432 int textStart = d->priv->text.length();
1434 d->priv->text += text;
1435 int textEnd = d->priv->text.length();
1437 for (int i = 0; i < text.length(); ++i) {
1438 QChar ch = text.at(i);
1440 const int blockEnd = i;
1442 if (ch == QLatin1Char('\r')
1443 && (i + 1) < text.length()
1444 && text.at(i + 1) == QLatin1Char('\n')) {
1449 if (ch == QLatin1Char('\n')
1450 || ch == QChar::ParagraphSeparator
1451 || ch == QTextBeginningOfFrame
1452 || ch == QTextEndOfFrame
1453 || ch == QLatin1Char('\r')) {
1455 if (!hasEditBlock) {
1456 hasEditBlock = true;
1457 d->priv->beginEditBlock();
1460 if (blockEnd > blockStart)
1461 d->priv->insert(d->position, textStart + blockStart, blockEnd - blockStart, formatIdx);
1463 d->insertBlock(blockFmt, format);
1467 if (textStart + blockStart < textEnd)
1468 d->priv->insert(d->position, textStart + blockStart, textEnd - textStart - blockStart, formatIdx);
1471 d->priv->endEditBlock();
1476 If there is no selected text, deletes the character \e at the
1477 current cursor position; otherwise deletes the selected text.
1479 \sa deletePreviousChar(), hasSelection(), clearSelection()
1481 void QTextCursor::deleteChar()
1486 if (d->position != d->anchor) {
1487 removeSelectedText();
1491 if (!d->canDelete(d->position))
1493 d->adjusted_anchor = d->anchor =
1494 d->priv->nextCursorPosition(d->anchor, QTextLayout::SkipCharacters);
1500 If there is no selected text, deletes the character \e before the
1501 current cursor position; otherwise deletes the selected text.
1503 \sa deleteChar(), hasSelection(), clearSelection()
1505 void QTextCursor::deletePreviousChar()
1510 if (d->position != d->anchor) {
1511 removeSelectedText();
1515 if (d->anchor < 1 || !d->canDelete(d->anchor-1))
1519 QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
1520 const QTextFragmentData * const frag = fragIt.value();
1521 int fpos = fragIt.position();
1522 QChar uc = d->priv->buffer().at(d->anchor - fpos + frag->stringPosition);
1523 if (d->anchor > fpos && uc.isLowSurrogate()) {
1524 // second half of a surrogate, check if we have the first half as well,
1525 // if yes delete both at once
1526 uc = d->priv->buffer().at(d->anchor - 1 - fpos + frag->stringPosition);
1527 if (uc.isHighSurrogate())
1531 d->adjusted_anchor = d->anchor;
1537 Selects text in the document according to the given \a selection.
1539 void QTextCursor::select(SelectionType selection)
1546 const QTextBlock block = d->block();
1548 switch (selection) {
1549 case LineUnderCursor:
1550 movePosition(StartOfLine);
1551 movePosition(EndOfLine, KeepAnchor);
1553 case WordUnderCursor:
1554 movePosition(StartOfWord);
1555 movePosition(EndOfWord, KeepAnchor);
1557 case BlockUnderCursor:
1558 if (block.length() == 1) // no content
1560 movePosition(StartOfBlock);
1561 // also select the paragraph separator
1562 if (movePosition(PreviousBlock)) {
1563 movePosition(EndOfBlock);
1564 movePosition(NextBlock, KeepAnchor);
1566 movePosition(EndOfBlock, KeepAnchor);
1569 movePosition(Start);
1570 movePosition(End, KeepAnchor);
1576 Returns true if the cursor contains a selection; otherwise returns false.
1578 bool QTextCursor::hasSelection() const
1580 return !!d && d->position != d->anchor;
1585 Returns true if the cursor contains a selection that is not simply a
1586 range from selectionStart() to selectionEnd(); otherwise returns false.
1588 Complex selections are ones that span at least two cells in a table;
1589 their extent is specified by selectedTableCells().
1591 bool QTextCursor::hasComplexSelection() const
1596 return d->complexSelectionTable() != 0;
1600 If the selection spans over table cells, \a firstRow is populated
1601 with the number of the first row in the selection, \a firstColumn
1602 with the number of the first column in the selection, and \a
1603 numRows and \a numColumns with the number of rows and columns in
1604 the selection. If the selection does not span any table cells the
1605 results are harmless but undefined.
1607 void QTextCursor::selectedTableCells(int *firstRow, int *numRows, int *firstColumn, int *numColumns) const
1614 if (!d || d->position == d->anchor)
1617 d->selectedTableCells(firstRow, numRows, firstColumn, numColumns);
1622 Clears the current selection by setting the anchor to the cursor position.
1624 Note that it does \b{not} delete the text of the selection.
1626 \sa removeSelectedText(), hasSelection()
1628 void QTextCursor::clearSelection()
1632 d->adjusted_anchor = d->anchor = d->position;
1633 d->currentCharFormat = -1;
1637 If there is a selection, its content is deleted; otherwise does
1642 void QTextCursor::removeSelectedText()
1644 if (!d || !d->priv || d->position == d->anchor)
1647 d->priv->beginEditBlock();
1649 d->priv->endEditBlock();
1654 Returns the start of the selection or position() if the
1655 cursor doesn't have a selection.
1657 \sa selectionEnd(), position(), anchor()
1659 int QTextCursor::selectionStart() const
1663 return qMin(d->position, d->adjusted_anchor);
1667 Returns the end of the selection or position() if the cursor
1668 doesn't have a selection.
1670 \sa selectionStart(), position(), anchor()
1672 int QTextCursor::selectionEnd() const
1676 return qMax(d->position, d->adjusted_anchor);
1679 static void getText(QString &text, QTextDocumentPrivate *priv, const QString &docText, int pos, int end)
1682 QTextDocumentPrivate::FragmentIterator fragIt = priv->find(pos);
1683 const QTextFragmentData * const frag = fragIt.value();
1685 const int offsetInFragment = qMax(0, pos - fragIt.position());
1686 const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
1688 text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
1694 Returns the current selection's text (which may be empty). This
1695 only returns the text, with no rich text formatting information.
1696 If you want a document fragment (i.e. formatted rich text) use
1697 selection() instead.
1699 \note If the selection obtained from an editor spans a line break,
1700 the text will contain a Unicode U+2029 paragraph separator character
1701 instead of a newline \c{\n} character. Use QString::replace() to
1702 replace these characters with newlines.
1704 QString QTextCursor::selectedText() const
1706 if (!d || !d->priv || d->position == d->anchor)
1709 const QString docText = d->priv->buffer();
1712 QTextTable *table = d->complexSelectionTable();
1714 int row_start, col_start, num_rows, num_cols;
1715 selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
1717 Q_ASSERT(row_start != -1);
1718 for (int r = row_start; r < row_start + num_rows; ++r) {
1719 for (int c = col_start; c < col_start + num_cols; ++c) {
1720 QTextTableCell cell = table->cellAt(r, c);
1721 int rspan = cell.rowSpan();
1722 int cspan = cell.columnSpan();
1724 int cr = cell.row();
1729 int cc = cell.column();
1734 getText(text, d->priv, docText, cell.firstPosition(), cell.lastPosition());
1738 getText(text, d->priv, docText, selectionStart(), selectionEnd());
1745 Returns the current selection (which may be empty) with all its
1746 formatting information. If you just want the selected text (i.e.
1747 plain text) use selectedText() instead.
1749 \note Unlike QTextDocumentFragment::toPlainText(),
1750 selectedText() may include special unicode characters such as
1751 QChar::ParagraphSeparator.
1753 \sa QTextDocumentFragment::toPlainText()
1755 QTextDocumentFragment QTextCursor::selection() const
1757 return QTextDocumentFragment(*this);
1761 Returns the block that contains the cursor.
1763 QTextBlock QTextCursor::block() const
1766 return QTextBlock();
1771 Returns the block format of the block the cursor is in.
1773 \sa setBlockFormat(), charFormat()
1775 QTextBlockFormat QTextCursor::blockFormat() const
1778 return QTextBlockFormat();
1780 return d->block().blockFormat();
1784 Sets the block format of the current block (or all blocks that
1785 are contained in the selection) to \a format.
1787 \sa blockFormat(), mergeBlockFormat()
1789 void QTextCursor::setBlockFormat(const QTextBlockFormat &format)
1794 d->setBlockFormat(format, QTextDocumentPrivate::SetFormat);
1798 Modifies the block format of the current block (or all blocks that
1799 are contained in the selection) with the block format specified by
1802 \sa setBlockFormat(), blockFormat()
1804 void QTextCursor::mergeBlockFormat(const QTextBlockFormat &modifier)
1809 d->setBlockFormat(modifier, QTextDocumentPrivate::MergeFormat);
1813 Returns the block character format of the block the cursor is in.
1815 The block char format is the format used when inserting text at the
1816 beginning of an empty block.
1818 \sa setBlockCharFormat()
1820 QTextCharFormat QTextCursor::blockCharFormat() const
1823 return QTextCharFormat();
1825 return d->block().charFormat();
1829 Sets the block char format of the current block (or all blocks that
1830 are contained in the selection) to \a format.
1832 \sa blockCharFormat()
1834 void QTextCursor::setBlockCharFormat(const QTextCharFormat &format)
1839 d->setBlockCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1843 Modifies the block char format of the current block (or all blocks that
1844 are contained in the selection) with the block format specified by
1847 \sa setBlockCharFormat()
1849 void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier)
1854 d->setBlockCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1858 Returns the format of the character immediately before the cursor
1859 position(). If the cursor is positioned at the beginning of a text
1860 block that is not empty then the format of the character
1861 immediately after the cursor is returned.
1863 \sa insertText(), blockFormat()
1865 QTextCharFormat QTextCursor::charFormat() const
1868 return QTextCharFormat();
1870 int idx = d->currentCharFormat;
1872 QTextBlock block = d->block();
1875 if (d->position == block.position()
1876 && block.length() > 1)
1879 pos = d->position - 1;
1882 idx = d->priv->blockCharFormatIndex(d->priv->blockMap().firstNode());
1884 Q_ASSERT(pos >= 0 && pos < d->priv->length());
1886 QTextDocumentPrivate::FragmentIterator it = d->priv->find(pos);
1887 Q_ASSERT(!it.atEnd());
1888 idx = it.value()->format;
1892 QTextCharFormat cfmt = d->priv->formatCollection()->charFormat(idx);
1893 cfmt.clearProperty(QTextFormat::ObjectIndex);
1895 Q_ASSERT(cfmt.isValid());
1900 Sets the cursor's current character format to the given \a
1901 format. If the cursor has a selection, the given \a format is
1902 applied to the current selection.
1904 \sa hasSelection(), mergeCharFormat()
1906 void QTextCursor::setCharFormat(const QTextCharFormat &format)
1910 if (d->position == d->anchor) {
1911 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1914 d->setCharFormat(format, QTextDocumentPrivate::SetFormatAndPreserveObjectIndices);
1918 Merges the cursor's current character format with the properties
1919 described by format \a modifier. If the cursor has a selection,
1920 this function applies all the properties set in \a modifier to all
1921 the character formats that are part of the selection.
1923 \sa hasSelection(), setCharFormat()
1925 void QTextCursor::mergeCharFormat(const QTextCharFormat &modifier)
1929 if (d->position == d->anchor) {
1930 QTextCharFormat format = charFormat();
1931 format.merge(modifier);
1932 d->currentCharFormat = d->priv->formatCollection()->indexForFormat(format);
1936 d->setCharFormat(modifier, QTextDocumentPrivate::MergeFormat);
1940 Returns true if the cursor is at the start of a block; otherwise
1943 \sa atBlockEnd(), atStart()
1945 bool QTextCursor::atBlockStart() const
1950 return d->position == d->block().position();
1954 Returns true if the cursor is at the end of a block; otherwise
1957 \sa atBlockStart(), atEnd()
1959 bool QTextCursor::atBlockEnd() const
1964 return d->position == d->block().position() + d->block().length() - 1;
1968 Returns true if the cursor is at the start of the document;
1969 otherwise returns false.
1971 \sa atBlockStart(), atEnd()
1973 bool QTextCursor::atStart() const
1978 return d->position == 0;
1984 Returns true if the cursor is at the end of the document;
1985 otherwise returns false.
1987 \sa atStart(), atBlockEnd()
1989 bool QTextCursor::atEnd() const
1994 return d->position == d->priv->length() - 1;
1998 Inserts a new empty block at the cursor position() with the
1999 current blockFormat() and charFormat().
2001 \sa setBlockFormat()
2003 void QTextCursor::insertBlock()
2005 insertBlock(blockFormat());
2011 Inserts a new empty block at the cursor position() with block
2012 format \a format and the current charFormat() as block char format.
2014 \sa setBlockFormat()
2016 void QTextCursor::insertBlock(const QTextBlockFormat &format)
2018 QTextCharFormat charFmt = charFormat();
2019 charFmt.clearProperty(QTextFormat::ObjectType);
2020 insertBlock(format, charFmt);
2024 \fn void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &charFormat)
2027 Inserts a new empty block at the cursor position() with block
2028 format \a format and \a charFormat as block char format.
2030 \sa setBlockFormat()
2032 void QTextCursor::insertBlock(const QTextBlockFormat &format, const QTextCharFormat &_charFormat)
2037 QTextCharFormat charFormat = _charFormat;
2038 charFormat.clearProperty(QTextFormat::ObjectIndex);
2040 d->priv->beginEditBlock();
2042 d->insertBlock(format, charFormat);
2043 d->priv->endEditBlock();
2048 Inserts a new block at the current position and makes it the first
2049 list item of a newly created list with the given \a format. Returns
2052 \sa currentList(), createList(), insertBlock()
2054 QTextList *QTextCursor::insertList(const QTextListFormat &format)
2057 return createList(format);
2063 Inserts a new block at the current position and makes it the first
2064 list item of a newly created list with the given \a style. Returns
2067 \sa currentList(), createList(), insertBlock()
2069 QTextList *QTextCursor::insertList(QTextListFormat::Style style)
2072 return createList(style);
2076 Creates and returns a new list with the given \a format, and makes the
2077 current paragraph the cursor is in the first list item.
2079 \sa insertList(), currentList()
2081 QTextList *QTextCursor::createList(const QTextListFormat &format)
2086 QTextList *list = static_cast<QTextList *>(d->priv->createObject(format));
2087 QTextBlockFormat modifier;
2088 modifier.setObjectIndex(list->objectIndex());
2089 mergeBlockFormat(modifier);
2096 Creates and returns a new list with the given \a style, making the
2097 cursor's current paragraph the first list item.
2099 The style to be used is defined by the QTextListFormat::Style enum.
2101 \sa insertList(), currentList()
2103 QTextList *QTextCursor::createList(QTextListFormat::Style style)
2105 QTextListFormat fmt;
2106 fmt.setStyle(style);
2107 return createList(fmt);
2111 Returns the current list if the cursor position() is inside a
2112 block that is part of a list; otherwise returns 0.
2114 \sa insertList(), createList()
2116 QTextList *QTextCursor::currentList() const
2121 QTextBlockFormat b = blockFormat();
2122 QTextObject *o = d->priv->objectForFormat(b);
2123 return qobject_cast<QTextList *>(o);
2127 \fn QTextTable *QTextCursor::insertTable(int rows, int columns)
2131 Creates a new table with the given number of \a rows and \a columns,
2132 inserts it at the current cursor position() in the document, and returns
2133 the table object. The cursor is moved to the beginning of the first cell.
2135 There must be at least one row and one column in the table.
2139 QTextTable *QTextCursor::insertTable(int rows, int cols)
2141 return insertTable(rows, cols, QTextTableFormat());
2145 \fn QTextTable *QTextCursor::insertTable(int rows, int columns, const QTextTableFormat &format)
2147 Creates a new table with the given number of \a rows and \a columns
2148 in the specified \a format, inserts it at the current cursor position()
2149 in the document, and returns the table object. The cursor is moved to
2150 the beginning of the first cell.
2152 There must be at least one row and one column in the table.
2156 QTextTable *QTextCursor::insertTable(int rows, int cols, const QTextTableFormat &format)
2158 if(!d || !d->priv || rows == 0 || cols == 0)
2161 int pos = d->position;
2162 QTextTable *t = QTextTablePrivate::createTable(d->priv, d->position, rows, cols, format);
2163 d->setPosition(pos+1);
2164 // ##### what should we do if we have a selection?
2165 d->anchor = d->position;
2166 d->adjusted_anchor = d->anchor;
2171 Returns a pointer to the current table if the cursor position()
2172 is inside a block that is part of a table; otherwise returns 0.
2176 QTextTable *QTextCursor::currentTable() const
2181 QTextFrame *frame = d->priv->frameAt(d->position);
2183 QTextTable *table = qobject_cast<QTextTable *>(frame);
2186 frame = frame->parentFrame();
2192 Inserts a frame with the given \a format at the current cursor position(),
2193 moves the cursor position() inside the frame, and returns the frame.
2195 If the cursor holds a selection, the whole selection is moved inside the
2200 QTextFrame *QTextCursor::insertFrame(const QTextFrameFormat &format)
2205 return d->priv->insertFrame(selectionStart(), selectionEnd(), format);
2209 Returns a pointer to the current frame. Returns 0 if the cursor is invalid.
2213 QTextFrame *QTextCursor::currentFrame() const
2218 return d->priv->frameAt(d->position);
2223 Inserts the text \a fragment at the current position().
2225 void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
2227 if (!d || !d->priv || fragment.isEmpty())
2230 d->priv->beginEditBlock();
2232 fragment.d->insert(*this);
2233 d->priv->endEditBlock();
2235 if (fragment.d && fragment.d->doc)
2236 d->priv->mergeCachedResources(fragment.d->doc->docHandle());
2241 Inserts the text \a html at the current position(). The text is interpreted as
2244 \note When using this function with a style sheet, the style sheet will
2245 only apply to the current block in the document. In order to apply a style
2246 sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
2250 #ifndef QT_NO_TEXTHTMLPARSER
2252 void QTextCursor::insertHtml(const QString &html)
2256 QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html, d->priv->document());
2257 insertFragment(fragment);
2260 #endif // QT_NO_TEXTHTMLPARSER
2266 Inserts the image defined by the given \a format at the cursor's current position
2267 with the specified \a alignment.
2271 void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::Position alignment)
2276 QTextFrameFormat ffmt;
2277 ffmt.setPosition(alignment);
2278 QTextObject *obj = d->priv->createObject(ffmt);
2280 QTextImageFormat fmt = format;
2281 fmt.setObjectIndex(obj->objectIndex());
2283 d->priv->beginEditBlock();
2285 const int idx = d->priv->formatCollection()->indexForFormat(fmt);
2286 d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
2287 d->priv->endEditBlock();
2291 Inserts the image defined by \a format at the current position().
2293 void QTextCursor::insertImage(const QTextImageFormat &format)
2295 insertText(QString(QChar::ObjectReplacementCharacter), format);
2301 Convenience method for inserting the image with the given \a name at the
2304 \snippet code/src_gui_text_qtextcursor.cpp 1
2306 void QTextCursor::insertImage(const QString &name)
2308 QTextImageFormat format;
2309 format.setName(name);
2310 insertImage(format);
2317 Convenience function for inserting the given \a image with an optional
2318 \a name at the current position().
2320 void QTextCursor::insertImage(const QImage &image, const QString &name)
2322 if (image.isNull()) {
2323 qWarning("QTextCursor::insertImage: attempt to add an invalid image");
2326 QString imageName = name;
2328 imageName = QString::number(image.cacheKey());
2329 d->priv->document()->addResource(QTextDocument::ImageResource, QUrl(imageName), image);
2330 QTextImageFormat format;
2331 format.setName(imageName);
2332 insertImage(format);
2336 \fn bool QTextCursor::operator!=(const QTextCursor &other) const
2338 Returns true if the \a other cursor is at a different position in
2339 the document as this cursor; otherwise returns false.
2341 bool QTextCursor::operator!=(const QTextCursor &rhs) const
2343 return !operator==(rhs);
2347 \fn bool QTextCursor::operator<(const QTextCursor &other) const
2349 Returns true if the \a other cursor is positioned later in the
2350 document than this cursor; otherwise returns false.
2352 bool QTextCursor::operator<(const QTextCursor &rhs) const
2360 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<", "cannot compare cursors attached to different documents");
2362 return d->position < rhs.d->position;
2366 \fn bool QTextCursor::operator<=(const QTextCursor &other) const
2368 Returns true if the \a other cursor is positioned later or at the
2369 same position in the document as this cursor; otherwise returns
2372 bool QTextCursor::operator<=(const QTextCursor &rhs) const
2380 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator<=", "cannot compare cursors attached to different documents");
2382 return d->position <= rhs.d->position;
2386 \fn bool QTextCursor::operator==(const QTextCursor &other) const
2388 Returns true if the \a other cursor is at the same position in the
2389 document as this cursor; otherwise returns false.
2391 bool QTextCursor::operator==(const QTextCursor &rhs) const
2399 return d->position == rhs.d->position && d->priv == rhs.d->priv;
2403 \fn bool QTextCursor::operator>=(const QTextCursor &other) const
2405 Returns true if the \a other cursor is positioned earlier or at the
2406 same position in the document as this cursor; otherwise returns
2409 bool QTextCursor::operator>=(const QTextCursor &rhs) const
2417 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>=", "cannot compare cursors attached to different documents");
2419 return d->position >= rhs.d->position;
2423 \fn bool QTextCursor::operator>(const QTextCursor &other) const
2425 Returns true if the \a other cursor is positioned earlier in the
2426 document than this cursor; otherwise returns false.
2428 bool QTextCursor::operator>(const QTextCursor &rhs) const
2436 Q_ASSERT_X(d->priv == rhs.d->priv, "QTextCursor::operator>", "cannot compare cursors attached to different documents");
2438 return d->position > rhs.d->position;
2442 Indicates the start of a block of editing operations on the
2443 document that should appear as a single operation from an
2444 undo/redo point of view.
2448 \snippet code/src_gui_text_qtextcursor.cpp 2
2450 The call to undo() will cause both insertions to be undone,
2451 causing both "World" and "Hello" to be removed.
2453 It is possible to nest calls to beginEditBlock and endEditBlock. The
2454 top-most pair will determine the scope of the undo/redo operation.
2458 void QTextCursor::beginEditBlock()
2463 if (d->priv->editBlock == 0) // we are the initial edit block, store current cursor position for undo
2464 d->priv->editBlockCursorPosition = d->position;
2466 d->priv->beginEditBlock();
2470 Like beginEditBlock() indicates the start of a block of editing operations
2471 that should appear as a single operation for undo/redo. However unlike
2472 beginEditBlock() it does not start a new block but reverses the previous call to
2473 endEditBlock() and therefore makes following operations part of the previous edit block created.
2477 \snippet code/src_gui_text_qtextcursor.cpp 3
2479 The call to undo() will cause all three insertions to be undone.
2481 \sa beginEditBlock(), endEditBlock()
2483 void QTextCursor::joinPreviousEditBlock()
2488 d->priv->joinPreviousEditBlock();
2492 Indicates the end of a block of editing operations on the document
2493 that should appear as a single operation from an undo/redo point
2496 \sa beginEditBlock()
2499 void QTextCursor::endEditBlock()
2504 d->priv->endEditBlock();
2508 Returns true if this cursor and \a other are copies of each other, i.e.
2509 one of them was created as a copy of the other and neither has moved since.
2510 This is much stricter than equality.
2512 \sa operator=(), operator==()
2514 bool QTextCursor::isCopyOf(const QTextCursor &other) const
2516 return d == other.d;
2521 Returns the number of the block the cursor is in, or 0 if the cursor is invalid.
2523 Note that this function only makes sense in documents without complex objects such
2524 as tables or frames.
2526 int QTextCursor::blockNumber() const
2531 return d->block().blockNumber();
2537 Returns the position of the cursor within its containing line.
2539 Note that this is the column number relative to a wrapped line,
2540 not relative to the block (i.e. the paragraph).
2542 You probably want to call positionInBlock() instead.
2544 \sa positionInBlock()
2546 int QTextCursor::columnNumber() const
2551 QTextBlock block = d->block();
2552 if (!block.isValid())
2555 const QTextLayout *layout = d->blockLayout(block);
2557 const int relativePos = d->position - block.position();
2559 if (layout->lineCount() == 0)
2562 QTextLine line = layout->lineForTextPosition(relativePos);
2563 if (!line.isValid())
2565 return relativePos - line.textStart();
2570 Returns the document this cursor is associated with.
2572 QTextDocument *QTextCursor::document() const
2575 return d->priv->document();
2576 return 0; // document went away
2580 \enum Qt::CursorMoveStyle
2582 This enum describes the movement style available to text cursors. The options
2585 \value LogicalMoveStyle Within a left-to-right text block, decrease cursor
2586 position when pressing left arrow key, increase cursor position when pressing
2587 the right arrow key. If the text block is right-to-left, the opposite behavior
2589 \value VisualMoveStyle Pressing the left arrow key will always cause the cursor
2590 to move left, regardless of the text's writing direction. Pressing the right
2591 arrow key will always cause the cursor to move right.