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