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 "QtGui/qtextcursor.h"
56#include "QtGui/qtextdocument.h"
57#include "QtGui/qtextlayout.h"
58#include "QtGui/qtextobject.h"
59#include "QtGui/qtextoption.h"
60
61#include "QtCore/qlist.h"
62#include "QtCore/qmap.h"
63#include "QtCore/qset.h"
64#include "QtCore/qstring.h"
65#include "QtCore/qurl.h"
66#include "QtCore/qvariant.h"
67
68#include "private/qcssparser_p.h"
69#include "private/qfragmentmap_p.h"
70#include "private/qobject_p.h"
71#include "private/qtextformat_p.h"
72
73// #define QT_QMAP_DEBUG
74
75#ifdef QT_QMAP_DEBUG
76#include <iostream>
77#endif
78
79QT_BEGIN_NAMESPACE
80
81class QTextFormatCollection;
82class QTextFormat;
83class QTextBlockFormat;
84class QTextCursorPrivate;
85class QAbstractTextDocumentLayout;
86class QTextDocument;
87class QTextFrame;
88
89#define QTextBeginningOfFrame QChar(u'\xfdd0')
90#define QTextEndOfFrame QChar(u'\xfdd1')
91
92class QTextFragmentData : public QFragment<>
93{
94public:
95 inline void initialize() {}
96 inline void invalidate() const {}
97 inline void free() {}
98 int stringPosition;
99 int format;
100};
101
102class QTextBlockData : public QFragment<3>
103{
104public:
105 inline void initialize()
106 { layout = nullptr; userData = nullptr; userState = -1; revision = 0; hidden = 0; }
107 void invalidate() const;
108 inline void free()
109 { delete layout; layout = nullptr; delete userData; userData = nullptr; }
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 signed int revision : 31;
117 mutable uint hidden : 1;
118};
119
120
121class QAbstractUndoItem;
122
123class QTextUndoCommand
124{
125public:
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};
161Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
162
163class Q_GUI_EXPORT QTextDocumentPrivate : public QObjectPrivate
164{
165 Q_DECLARE_PUBLIC(QTextDocument)
166public:
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(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
261private:
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
279public:
280 void documentChange(int from, int length);
281
282 inline void addCursor(QTextCursorPrivate *c) { cursors.insert(c); }
283 inline void removeCursor(QTextCursorPrivate *c) { cursors.remove(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 static inline const QTextDocumentPrivate *get(const QTextDocument *document)
301 {
302 return document->d_func();
303 }
304
305 static inline QTextDocumentPrivate *get(QTextDocument *document)
306 {
307 return document->d_func();
308 }
309
310 static inline QTextDocumentPrivate *get(QTextBlock &block)
311 {
312 return block.p;
313 }
314
315 static inline const QTextDocumentPrivate *get(const QTextBlock &block)
316 {
317 return block.p;
318 }
319
320 static inline QTextDocumentPrivate *get(QTextObject *object)
321 {
322 return get(object->document());
323 }
324
325 static inline const QTextDocumentPrivate *get(const QTextObject *object)
326 {
327 return get(object->document());
328 }
329
330private:
331 QTextDocumentPrivate(const QTextDocumentPrivate& m);
332 QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m);
333
334 void appendUndoItem(const QTextUndoCommand &c);
335
336 void contentsChanged();
337
338 void compressPieceTable();
339
340 QString text;
341 uint unreachableCharacterCount;
342
343 QList<QTextUndoCommand> undoStack;
344 bool undoEnabled;
345 int undoState;
346 int revision;
347 // position in undo stack of the last setModified(false) call
348 int modifiedState;
349 bool modified;
350
351 int editBlock;
352 int editBlockCursorPosition;
353 int docChangeFrom;
354 int docChangeOldLength;
355 int docChangeLength;
356 bool framesDirty;
357
358 QTextFormatCollection formats;
359 mutable QTextFrame *rtFrame;
360 QAbstractTextDocumentLayout *lout;
361 FragmentMap fragments;
362 BlockMap blocks;
363 int initialBlockCharFormatIndex;
364
365 QSet<QTextCursorPrivate *> cursors;
366 QMap<int, QTextObject *> objects;
367 QMap<QUrl, QVariant> resources;
368 QMap<QUrl, QVariant> cachedResources;
369 QString defaultStyleSheet;
370
371 int lastBlockCount;
372
373public:
374 bool inContentsChange;
375 QTextOption defaultTextOption;
376 Qt::CursorMoveStyle defaultCursorMoveStyle;
377#ifndef QT_NO_CSSPARSER
378 QCss::StyleSheet parsedDefaultStyleSheet;
379#endif
380 int maximumBlockCount;
381 uint needsEnsureMaximumBlockCount : 1;
382 uint blockCursorAdjustment : 1;
383 QSizeF pageSize;
384 QString title;
385 QString url;
386 qreal indentWidth;
387 qreal documentMargin;
388 QUrl baseUrl;
389
390 void mergeCachedResources(const QTextDocumentPrivate *priv);
391
392 friend struct QTextHtmlParserNode;
393 friend class QTextHtmlExporter;
394 friend class QTextCursor;
395};
396
397class QTextTable;
398class QTextHtmlExporter
399{
400public:
401 QTextHtmlExporter(const QTextDocument *_doc);
402
403 enum ExportMode {
404 ExportEntireDocument,
405 ExportFragment
406 };
407
408 QString toHtml(ExportMode mode = ExportEntireDocument);
409
410private:
411 enum StyleMode { EmitStyleTag, OmitStyleTag };
412 enum FrameType { TextFrame, TableFrame, RootFrame };
413
414 void emitFrame(const QTextFrame::Iterator &frameIt);
415 void emitTextFrame(const QTextFrame *frame);
416 void emitBlock(const QTextBlock &block);
417 void emitTable(const QTextTable *table);
418 void emitFragment(const QTextFragment &fragment);
419
420 void emitBlockAttributes(const QTextBlock &block);
421 bool emitCharFormatStyle(const QTextCharFormat &format);
422 void emitTextLength(const char *attribute, const QTextLength &length);
423 void emitAlignment(Qt::Alignment alignment);
424 void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag);
425 void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right);
426 void emitAttribute(const char *attribute, const QString &value);
427 void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType);
428 void emitBorderStyle(QTextFrameFormat::BorderStyle style);
429 void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
430
431 void emitFontFamily(const QStringList &families);
432
433 void emitBackgroundAttribute(const QTextFormat &format);
434 QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
435
436 QString html;
437 QTextCharFormat defaultCharFormat;
438 const QTextDocument *doc;
439 bool fragmentMarkers;
440};
441
442QT_END_NAMESPACE
443
444#endif // QTEXTDOCUMENT_P_H
445