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