| 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 |