1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QTEXTDOCUMENT_P_H
41#define QTEXTDOCUMENT_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtGui/private/qtguiglobal_p.h>
55#include "QtCore/qstring.h"
56#include "QtCore/qvector.h"
57#include "QtCore/qlist.h"
58#include "private/qobject_p.h"
59#include "private/qfragmentmap_p.h"
60#include "QtGui/qtextlayout.h"
61#include "QtGui/qtextoption.h"
62#include "private/qtextformat_p.h"
63#include "QtGui/qtextdocument.h"
64#include "QtGui/qtextobject.h"
65#include "QtGui/qtextcursor.h"
66#include "QtCore/qmap.h"
67#include "QtCore/qvariant.h"
68#include "QtCore/qurl.h"
69#include "private/qcssparser_p.h"
70
71// #define QT_QMAP_DEBUG
72
73#ifdef QT_QMAP_DEBUG
74#include <iostream>
75#endif
76
77QT_BEGIN_NAMESPACE
78
79class QTextFormatCollection;
80class QTextFormat;
81class QTextBlockFormat;
82class QTextCursorPrivate;
83class QAbstractTextDocumentLayout;
84class QTextDocument;
85class QTextFrame;
86
87#define QTextBeginningOfFrame QChar(0xfdd0)
88#define QTextEndOfFrame QChar(0xfdd1)
89
90class QTextFragmentData : public QFragment<>
91{
92public:
93 inline void initialize() {}
94 inline void invalidate() const {}
95 inline void free() {}
96 int stringPosition;
97 int format;
98};
99
100class QTextBlockData : public QFragment<3>
101{
102public:
103 inline void initialize()
104 { layout = nullptr; userData = nullptr; userState = -1; revision = 0; hidden = 0; }
105 void invalidate() const;
106 inline void free()
107 { delete layout; layout = nullptr; delete userData; userData = nullptr; }
108
109 mutable int format;
110 // ##### probably store a QTextEngine * here!
111 mutable QTextLayout *layout;
112 mutable QTextBlockUserData *userData;
113 mutable int userState;
114 mutable int revision : 31;
115 mutable uint hidden : 1;
116};
117
118
119class QAbstractUndoItem;
120
121class QTextUndoCommand
122{
123public:
124 enum Command {
125 Inserted = 0,
126 Removed = 1,
127 CharFormatChanged = 2,
128 BlockFormatChanged = 3,
129 BlockInserted = 4,
130 BlockRemoved = 5,
131 BlockAdded = 6,
132 BlockDeleted = 7,
133 GroupFormatChange = 8,
134 CursorMoved = 9,
135 Custom = 256
136 };
137 enum Operation {
138 KeepCursor = 0,
139 MoveCursor = 1
140 };
141 quint16 command;
142 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
143 uint block_end : 1; // the last command in an undo block has this set to 1.
144 uint block_padding : 6; // padding since block used to be a quint8
145 quint8 operation;
146 int format;
147 quint32 strPos;
148 quint32 pos;
149 union {
150 int blockFormat;
151 quint32 length;
152 QAbstractUndoItem *custom;
153 int objectIndex;
154 };
155 quint32 revision;
156
157 bool tryMerge(const QTextUndoCommand &other);
158};
159Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
160
161class Q_GUI_EXPORT QTextDocumentPrivate : public QObjectPrivate
162{
163 Q_DECLARE_PUBLIC(QTextDocument)
164public:
165 typedef QFragmentMap<QTextFragmentData> FragmentMap;
166 typedef FragmentMap::ConstIterator FragmentIterator;
167 typedef QFragmentMap<QTextBlockData> BlockMap;
168
169 QTextDocumentPrivate();
170 ~QTextDocumentPrivate();
171
172 void init();
173 void clear();
174
175 void setLayout(QAbstractTextDocumentLayout *layout);
176
177 void insert(int pos, const QString &text, int format);
178 void insert(int pos, int strPos, int strLength, int format);
179 int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
180 int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat,
181 QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor);
182
183 void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
184 void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
185
186 void aboutToRemoveCell(int cursorFrom, int cursorEnd);
187
188 QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format);
189 void removeFrame(QTextFrame *frame);
190
191 enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices };
192
193 void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat);
194 void setBlockFormat(const QTextBlock &from, const QTextBlock &to,
195 const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat);
196
197 void emitUndoAvailable(bool available);
198 void emitRedoAvailable(bool available);
199
200 int undoRedo(bool undo);
201 inline void undo() { undoRedo(true); }
202 inline void redo() { undoRedo(false); }
203 void appendUndoItem(QAbstractUndoItem *);
204 inline void beginEditBlock() { if (0 == editBlock++) ++revision; }
205 void joinPreviousEditBlock();
206 void endEditBlock();
207 void finishEdit();
208 inline bool isInEditBlock() const { return editBlock; }
209 void enableUndoRedo(bool enable);
210 inline bool isUndoRedoEnabled() const { return undoEnabled; }
211
212 inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; }
213 inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); }
214
215 inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; }
216 inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; }
217
218 inline QString buffer() const { return text; }
219 QString plainText() const;
220 inline int length() const { return fragments.length(); }
221
222 inline QTextFormatCollection *formatCollection() { return &formats; }
223 inline const QTextFormatCollection *formatCollection() const { return &formats; }
224 inline QAbstractTextDocumentLayout *layout() const { return lout; }
225
226 inline FragmentIterator find(int pos) const { return fragments.find(pos); }
227 inline FragmentIterator begin() const { return fragments.begin(); }
228 inline FragmentIterator end() const { return fragments.end(); }
229
230 inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); }
231 inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); }
232 inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); }
233 int blockCharFormatIndex(int node) const;
234
235 inline int numBlocks() const { return blocks.numNodes(); }
236
237 const BlockMap &blockMap() const { return blocks; }
238 const FragmentMap &fragmentMap() const { return fragments; }
239 BlockMap &blockMap() { return blocks; }
240 FragmentMap &fragmentMap() { return fragments; }
241
242 static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); }
243
244 int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
245 int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
246 int leftCursorPosition(int position) const;
247 int rightCursorPosition(int position) const;
248
249 void changeObjectFormat(QTextObject *group, int format);
250
251 void setModified(bool m);
252 inline bool isModified() const { return modified; }
253
254 inline QFont defaultFont() const { return formats.defaultFont(); }
255 inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
256
257 void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
258
259private:
260 bool split(int pos);
261 bool unite(uint f);
262
263 void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
264 int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command);
265 int remove_string(int pos, uint length, QTextUndoCommand::Operation op);
266 int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op);
267
268 void insert_frame(QTextFrame *f);
269 void scan_frames(int pos, int charsRemoved, int charsAdded);
270 static void clearFrame(QTextFrame *f);
271
272 void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op);
273
274 bool wasUndoAvailable;
275 bool wasRedoAvailable;
276
277public:
278 void documentChange(int from, int length);
279
280 inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); }
281 inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); }
282
283 QTextFrame *frameAt(int pos) const;
284 QTextFrame *rootFrame() const;
285
286 QTextObject *objectForIndex(int objectIndex) const;
287 QTextObject *objectForFormat(int formatIndex) const;
288 QTextObject *objectForFormat(const QTextFormat &f) const;
289
290 QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1);
291 void deleteObject(QTextObject *object);
292
293 QTextDocument *document() { return q_func(); }
294 const QTextDocument *document() const { return q_func(); }
295
296 bool ensureMaximumBlockCount();
297
298private:
299 QTextDocumentPrivate(const QTextDocumentPrivate& m);
300 QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m);
301
302 void appendUndoItem(const QTextUndoCommand &c);
303
304 void contentsChanged();
305
306 void compressPieceTable();
307
308 QString text;
309 uint unreachableCharacterCount;
310
311 QVector<QTextUndoCommand> undoStack;
312 bool undoEnabled;
313 int undoState;
314 int revision;
315 // position in undo stack of the last setModified(false) call
316 int modifiedState;
317 bool modified;
318
319 int editBlock;
320 int editBlockCursorPosition;
321 int docChangeFrom;
322 int docChangeOldLength;
323 int docChangeLength;
324 bool framesDirty;
325
326 QTextFormatCollection formats;
327 mutable QTextFrame *rtFrame;
328 QAbstractTextDocumentLayout *lout;
329 FragmentMap fragments;
330 BlockMap blocks;
331 int initialBlockCharFormatIndex;
332
333 QList<QTextCursorPrivate *> cursors;
334 QMap<int, QTextObject *> objects;
335 QMap<QUrl, QVariant> resources;
336 QMap<QUrl, QVariant> cachedResources;
337 QString defaultStyleSheet;
338
339 int lastBlockCount;
340
341public:
342 bool inContentsChange;
343 QTextOption defaultTextOption;
344 Qt::CursorMoveStyle defaultCursorMoveStyle;
345#ifndef QT_NO_CSSPARSER
346 QCss::StyleSheet parsedDefaultStyleSheet;
347#endif
348 int maximumBlockCount;
349 uint needsEnsureMaximumBlockCount : 1;
350 uint blockCursorAdjustment : 1;
351 QSizeF pageSize;
352 QString title;
353 QString url;
354 qreal indentWidth;
355 qreal documentMargin;
356 QUrl baseUrl;
357
358 void mergeCachedResources(const QTextDocumentPrivate *priv);
359
360 friend struct QTextHtmlParserNode;
361 friend class QTextHtmlExporter;
362 friend class QTextCursor;
363};
364
365class QTextTable;
366class QTextHtmlExporter
367{
368public:
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
378private:
379 enum StyleMode { EmitStyleTag, OmitStyleTag };
380 enum FrameType { TextFrame, TableFrame, RootFrame };
381
382 void emitFrame(const 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 void emitFontFamily(const QStringList &families);
401
402 void emitBackgroundAttribute(const QTextFormat &format);
403 QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
404
405 QString html;
406 QTextCharFormat defaultCharFormat;
407 const QTextDocument *doc;
408 bool fragmentMarkers;
409};
410
411QT_END_NAMESPACE
412
413#endif // QTEXTDOCUMENT_P_H
414