1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2015 The Qt Company Ltd. 4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further 15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free 20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 22 ** following information to ensure the GNU Lesser General Public License 23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 25 ** 26 ** As a special exception, The Qt Company gives you certain additional 27 ** rights. These rights are described in The Qt Company LGPL Exception 28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 29 ** 30 ** GNU General Public License Usage 31 ** Alternatively, this file may be used under the terms of the GNU 32 ** General Public License version 3.0 as published by the Free Software 33 ** Foundation and appearing in the file LICENSE.GPL included in the 34 ** packaging of this file. Please review the following information to 35 ** ensure the GNU General Public License version 3.0 requirements will be 36 ** met: http://www.gnu.org/copyleft/gpl.html. 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: initialize()95 inline void initialize() {} invalidate()96 inline void invalidate() const {} free()97 inline void free() {} 98 int stringPosition; 99 int format; 100 }; 101 102 class QTextBlockData : public QFragment<3> 103 { 104 public: initialize()105 inline void initialize() 106 { layout = 0; userData = 0; userState = -1; revision = 0; hidden = 0; } 107 void invalidate() const; free()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); undo()203 inline void undo() { undoRedo(true); } redo()204 inline void redo() { undoRedo(false); } 205 void appendUndoItem(QAbstractUndoItem *); beginEditBlock()206 inline void beginEditBlock() { if (0 == editBlock++) ++revision; } 207 void joinPreviousEditBlock(); 208 void endEditBlock(); 209 void finishEdit(); isInEditBlock()210 inline bool isInEditBlock() const { return editBlock; } 211 void enableUndoRedo(bool enable); isUndoRedoEnabled()212 inline bool isUndoRedoEnabled() const { return undoEnabled; } 213 isUndoAvailable()214 inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; } isRedoAvailable()215 inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); } 216 availableUndoSteps()217 inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; } availableRedoSteps()218 inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; } 219 buffer()220 inline QString buffer() const { return text; } 221 QString plainText() const; length()222 inline int length() const { return fragments.length(); } 223 formatCollection()224 inline QTextFormatCollection *formatCollection() { return &formats; } formatCollection()225 inline const QTextFormatCollection *formatCollection() const { return &formats; } layout()226 inline QAbstractTextDocumentLayout *layout() const { return lout; } 227 find(int pos)228 inline FragmentIterator find(int pos) const { return fragments.find(pos); } begin()229 inline FragmentIterator begin() const { return fragments.begin(); } end()230 inline FragmentIterator end() const { return fragments.end(); } 231 blocksBegin()232 inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); } blocksEnd()233 inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); } blocksFind(int pos)234 inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); } 235 int blockCharFormatIndex(int node) const; 236 numBlocks()237 inline int numBlocks() const { return blocks.numNodes(); } 238 blockMap()239 const BlockMap &blockMap() const { return blocks; } fragmentMap()240 const FragmentMap &fragmentMap() const { return fragments; } blockMap()241 BlockMap &blockMap() { return blocks; } fragmentMap()242 FragmentMap &fragmentMap() { return fragments; } 243 block(const QTextBlock & it)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); isModified()254 inline bool isModified() const { return modified; } 255 defaultFont()256 inline QFont defaultFont() const { return formats.defaultFont(); } setDefaultFont(const QFont & f)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 addCursor(QTextCursorPrivate * c)282 inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); } removeCursor(QTextCursorPrivate * 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 document()295 QTextDocument *document() { return q_func(); } document()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 413