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