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
#ifndef QTEXTDOCUMENT_P_H
43
#define QTEXTDOCUMENT_P_H
44
45
//
46
//  W A R N I N G
47
//  -------------
48
//
49
// This file is not part of the Qt API.  It exists purely as an
50
// implementation detail.  This header file may change from version to
51
// version without notice, or even be removed.
52
//
53
// We mean it.
54
//
55
56
#include "QtCore/qglobal.h"
57
#include "QtCore/qstring.h"
58
#include "QtCore/qvector.h"
59
#include "QtCore/qlist.h"
60
#include "private/qobject_p.h"
61
#include "private/qfragmentmap_p.h"
62
#include "QtGui/qtextlayout.h"
63
#include "QtGui/qtextoption.h"
64
#include "private/qtextformat_p.h"
65
#include "QtGui/qtextdocument.h"
66
#include "QtGui/qtextobject.h"
67
#include "QtGui/qtextcursor.h"
68
#include "QtCore/qmap.h"
69
#include "QtCore/qvariant.h"
70
#include "QtCore/qurl.h"
71
#include "private/qcssparser_p.h"
72
73
// #define QT_QMAP_DEBUG
74
75
#ifdef QT_QMAP_DEBUG
76
#include <iostream>
77
#endif
78
79
QT_BEGIN_NAMESPACE
80
81
class QTextFormatCollection;
82
class QTextFormat;
83
class QTextBlockFormat;
84
class QTextCursorPrivate;
85
class QAbstractTextDocumentLayout;
86
class QTextDocument;
87
class QTextFrame;
88
89
#define QTextBeginningOfFrame QChar(0xfdd0)
90
#define QTextEndOfFrame QChar(0xfdd1)
91
92
class QTextFragmentData : public QFragment<>
93
{
94
public:
95
    inline void initialize() {}
96
    inline void invalidate() const {}
97
    inline void free() {}
98
    int stringPosition;
99
    int format;
100
};
101
102
class QTextBlockData : public QFragment<3>
103
{
104
public:
105
    inline void initialize()
106
        { layout = 0; userData = 0; userState = -1; revision = 0; hidden = 0; }
107
    void invalidate() const;
108
    inline void free()
109
    { delete layout; layout = 0; delete userData; userData = 0; }
110
111
    mutable int format;
112
    // ##### probably store a QTextEngine * here!
113
    mutable QTextLayout *layout;
114
    mutable QTextBlockUserData *userData;
115
    mutable int userState;
116
    mutable int revision : 31;
117
    mutable uint hidden : 1;
118
};
119
120
121
class QAbstractUndoItem;
122
123
class QTextUndoCommand
124
{
125
public:
126
    enum Command {
127
        Inserted = 0,
128
        Removed = 1,
129
        CharFormatChanged = 2,
130
        BlockFormatChanged = 3,
131
        BlockInserted = 4,
132
        BlockRemoved = 5,
133
        BlockAdded = 6,
134
        BlockDeleted = 7,
135
        GroupFormatChange = 8,
136
        CursorMoved = 9,
137
        Custom = 256
138
    };
139
    enum Operation {
140
        KeepCursor = 0,
141
        MoveCursor = 1
142
    };
143
    quint16 command;
144
    uint block_part : 1; // all commands that are part of an undo block (including the first and the last one) have this set to 1
145
    uint block_end : 1; // the last command in an undo block has this set to 1.
146
    uint block_padding : 6; // padding since block used to be a quint8
147
    quint8 operation;
148
    int format;
149
    quint32 strPos;
150
    quint32 pos;
151
    union {
152
        int blockFormat;
153
        quint32 length;
154
        QAbstractUndoItem *custom;
155
        int objectIndex;
156
    };
157
    quint32 revision;
158
159
    bool tryMerge(const QTextUndoCommand &other);
160
};
161
Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
162
163
class Q_AUTOTEST_EXPORT QTextDocumentPrivate : public QObjectPrivate
164
{
165
    Q_DECLARE_PUBLIC(QTextDocument)
166
public:
167
    typedef QFragmentMap<QTextFragmentData> FragmentMap;
168
    typedef FragmentMap::ConstIterator FragmentIterator;
169
    typedef QFragmentMap<QTextBlockData> BlockMap;
170
171
    QTextDocumentPrivate();
172
    ~QTextDocumentPrivate();
173
174
    void init();
175
    void clear();
176
177
    void setLayout(QAbstractTextDocumentLayout *layout);
178
179
    void insert(int pos, const QString &text, int format);
180
    void insert(int pos, int strPos, int strLength, int format);
181
    int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
182
    int insertBlock(const QChar &blockSeparator, int pos, int blockFormat, int charFormat,
183
                     QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor);
184
185
    void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
186
    void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
187
188
    void aboutToRemoveCell(int cursorFrom, int cursorEnd);
189
190
    QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format);
191
    void removeFrame(QTextFrame *frame);
192
193
    enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices };
194
195
    void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat);
196
    void setBlockFormat(const QTextBlock &from, const QTextBlock &to,
197
			const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat);
198
199
    void emitUndoAvailable(bool available);
200
    void emitRedoAvailable(bool available);
201
202
    int undoRedo(bool undo);
203
    inline void undo() { undoRedo(true); }
204
    inline void redo() { undoRedo(false); }
205
    void appendUndoItem(QAbstractUndoItem *);
206
    inline void beginEditBlock() { if (0 == editBlock++) ++revision; }
207
    void joinPreviousEditBlock();
208
    void endEditBlock();
209
    void finishEdit();
210
    inline bool isInEditBlock() const { return editBlock; }
211
    void enableUndoRedo(bool enable);
212
    inline bool isUndoRedoEnabled() const { return undoEnabled; }
213
214
    inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; }
215
    inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); }
216
217
    inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; }
218
    inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; }
219
220
    inline QString buffer() const { return text; }
221
    QString plainText() const;
222
    inline int length() const { return fragments.length(); }
223
224
    inline QTextFormatCollection *formatCollection() { return &formats; }
225
    inline const QTextFormatCollection *formatCollection() const { return &formats; }
226
    inline QAbstractTextDocumentLayout *layout() const { return lout; }
227
228
    inline FragmentIterator find(int pos) const { return fragments.find(pos); }
229
    inline FragmentIterator begin() const { return fragments.begin(); }
230
    inline FragmentIterator end() const { return fragments.end(); }
231
232
    inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); }
233
    inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); }
234
    inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); }
235
    int blockCharFormatIndex(int node) const;
236
237
    inline int numBlocks() const { return blocks.numNodes(); }
238
239
    const BlockMap &blockMap() const { return blocks; }
240
    const FragmentMap &fragmentMap() const { return fragments; }
241
    BlockMap &blockMap() { return blocks; }
242
    FragmentMap &fragmentMap() { return fragments; }
243
244
    static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); }
245
246
    int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
247
    int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
248
    int leftCursorPosition(int position) const;
249
    int rightCursorPosition(int position) const;
250
251
    void changeObjectFormat(QTextObject *group, int format);
252
253
    void setModified(bool m);
254
    inline bool isModified() const { return modified; }
255
256
    inline QFont defaultFont() const { return formats.defaultFont(); }
257
    inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
258
259
    void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
260
261
private:
262
    bool split(int pos);
263
    bool unite(uint f);
264
265
    void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
266
    int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command);
267
    int remove_string(int pos, uint length, QTextUndoCommand::Operation op);
268
    int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op);
269
270
    void insert_frame(QTextFrame *f);
271
    void scan_frames(int pos, int charsRemoved, int charsAdded);
272
    static void clearFrame(QTextFrame *f);
273
274
    void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op);
275
276
    bool wasUndoAvailable;
277
    bool wasRedoAvailable;
278
279
public:
280
    void documentChange(int from, int length);
281
282
    inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); }
283
    inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); }
284
285
    QTextFrame *frameAt(int pos) const;
286
    QTextFrame *rootFrame() const;
287
288
    QTextObject *objectForIndex(int objectIndex) const;
289
    QTextObject *objectForFormat(int formatIndex) const;
290
    QTextObject *objectForFormat(const QTextFormat &f) const;
291
292
    QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1);
293
    void deleteObject(QTextObject *object);
294
295
    QTextDocument *document() { return q_func(); }
296
    const QTextDocument *document() const { return q_func(); }
297
298
    bool ensureMaximumBlockCount();
299
300
private:
301
    QTextDocumentPrivate(const QTextDocumentPrivate& m);
302
    QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m);
303
304
    void appendUndoItem(const QTextUndoCommand &c);
305
306
    void contentsChanged();
307
308
    void compressPieceTable();
309
310
    QString text;
311
    uint unreachableCharacterCount;
312
313
    QVector<QTextUndoCommand> undoStack;
314
    bool undoEnabled;
315
    int undoState;
316
    int revision;
317
    // position in undo stack of the last setModified(false) call
318
    int modifiedState;
319
    bool modified;
320
321
    int editBlock;
322
    int editBlockCursorPosition;
323
    int docChangeFrom;
324
    int docChangeOldLength;
325
    int docChangeLength;
326
    bool framesDirty;
327
328
    QTextFormatCollection formats;
329
    mutable QTextFrame *rtFrame;
330
    QAbstractTextDocumentLayout *lout;
331
    FragmentMap fragments;
332
    BlockMap blocks;
333
    int initialBlockCharFormatIndex;
334
335
    QList<QTextCursorPrivate *> cursors;
336
    QMap<int, QTextObject *> objects;
337
    QMap<QUrl, QVariant> resources;
338
    QMap<QUrl, QVariant> cachedResources;
339
    QString defaultStyleSheet;
340
341
    int lastBlockCount;
342
343
public:
344
    QTextOption defaultTextOption;
345
    Qt::CursorMoveStyle defaultCursorMoveStyle;
346
#ifndef QT_NO_CSSPARSER
347
    QCss::StyleSheet parsedDefaultStyleSheet;
348
#endif
349
    int maximumBlockCount;
350
    uint needsEnsureMaximumBlockCount : 1;
351
    uint inContentsChange : 1;
352
    uint blockCursorAdjustment : 1;
353
    QSizeF pageSize;
354
    QString title;
355
    QString url;
356
    qreal indentWidth;
357
    qreal documentMargin;
358
359
    void mergeCachedResources(const QTextDocumentPrivate *priv);
360
361
    friend class QTextHtmlExporter;
362
    friend class QTextCursor;
363
};
364
365
class QTextTable;
366
class QTextHtmlExporter
367
{
368
public:
369
    QTextHtmlExporter(const QTextDocument *_doc);
370
371
    enum ExportMode {
372
        ExportEntireDocument,
373
        ExportFragment
374
    };
375
376
    QString toHtml(const QByteArray &encoding, ExportMode mode = ExportEntireDocument);
377
378
private:
379
    enum StyleMode { EmitStyleTag, OmitStyleTag };
380
    enum FrameType { TextFrame, TableFrame, RootFrame };
381
382
    void emitFrame(QTextFrame::Iterator frameIt);
383
    void emitTextFrame(const QTextFrame *frame);
384
    void emitBlock(const QTextBlock &block);
385
    void emitTable(const QTextTable *table);
386
    void emitFragment(const QTextFragment &fragment);
387
388
    void emitBlockAttributes(const QTextBlock &block);
389
    bool emitCharFormatStyle(const QTextCharFormat &format);
390
    void emitTextLength(const char *attribute, const QTextLength &length);
391
    void emitAlignment(Qt::Alignment alignment);
392
    void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag);
393
    void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right);
394
    void emitAttribute(const char *attribute, const QString &value);
395
    void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType);
396
    void emitBorderStyle(QTextFrameFormat::BorderStyle style);
397
    void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
398
399
    void emitFontFamily(const QString &family);
400
401
    void emitBackgroundAttribute(const QTextFormat &format);
402
    QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
403
404
    QString html;
405
    QTextCharFormat defaultCharFormat;
406
    const QTextDocument *doc;
407
    bool fragmentMarkers;
408
};
409
410
QT_END_NAMESPACE
411
412
#endif // QTEXTDOCUMENT_P_H