4#include <private/qtools_p.h>
24#define PMDEBUG if(0) qDebug
27#if !defined(Q_CC_DIAB)
28# define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
29 QTextUndoCommand c = { a1, a2, 0, 0, quint8(a3), a4, quint32(a5), quint32(a6), { int(a7) }, quint32(a8) }
31# define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
32 QTextUndoCommand c = { a1, a2, 0, 0, a3, a4, a5, a6 }; c.blockFormat = a7; c.revision = a8
147 : wasUndoAvailable(
false),
148 wasRedoAvailable(
false),
149 docChangeOldLength(0),
153 initialBlockCharFormatIndex(-1),
158 editBlockCursorPosition = -1;
182 unreachableCharacterCount = 0;
190 bool undoState = undoEnabled;
194 undoEnabled = undoState;
198 qRegisterMetaType<QTextDocument *>();
206 curs->setPosition(0);
207 curs->currentCharFormat = -1;
209 curs->adjusted_anchor = 0;
217 while (objectIt != objects.
end()) {
218 if (*objectIt != rtFrame) {
220 objectIt = objects.
erase(objectIt);
232 unreachableCharacterCount = 0;
239 cachedResources.
clear();
243 cursors = oldCursors;
251 cursors = oldCursors;
259 curs->priv =
nullptr;
271 const bool firstLayout = !lout;
279 emit q->documentLayoutChanged();
298 X->stringPosition = strPos;
310 frame->d_func()->fragmentAdded(text.
at(strPos),
x);
314 adjustDocumentChangesAndCursors(
pos,
length, op);
323 X->stringPosition = strPos;
337 if (
key != block_pos) {
339 int oldSize = blocks.
size(
n);
341 size += oldSize - (block_pos-
key);
345 B->format = blockFormat;
352 docChangeOldLength--;
358 frame->d_func()->fragmentAdded(text.
at(strPos),
x);
362 adjustDocumentChangesAndCursors(
pos, 1, op);
376 int strPos = text.
size();
377 text.
append(blockSeparator);
380 bool atBlockEnd =
true;
381 bool atBlockStart =
true;
397 op, charFormat, strPos,
pos, blockFormat,
404 B->revision = (atBlockEnd && !atBlockStart)? oldRevision : revision;
408 B->revision = atBlockStart ? oldRevision : revision;
411 if (
formats.charFormat(charFormat).objectIndex() == -1)
440 B->revision = revision;
453 int strPos = text.
size();
482 unreachableCharacterCount +=
length;
484 adjustDocumentChangesAndCursors(
pos, -
int(
length), op);
531 adjustDocumentChangesAndCursors(
pos, -1, op);
536#if !defined(QT_NO_DEBUG)
540 if (
child == possibleAncestor)
557 const bool needsInsert = to != -1;
559#if !defined(QT_NO_DEBUG)
565 const bool startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent
570 const bool isFirstTableCell = (qobject_cast<QTextTable *>(
frameAt(
pos +
length - 1))
573 Q_ASSERT(startAndEndInSameFrame || endIsEndOfChildFrame || startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent || isFirstTableCell);
592 int blockRevision =
B->revision;
596 op,
X->format,
X->stringPosition,
key,
X->size_array[0],
599 op,
X->format,
X->stringPosition, dstKey,
X->size_array[0],
605 w = remove_string(
key,
X->size_array[0], op);
608 insert_string(dstKey,
X->stringPosition,
X->size_array[0],
X->format, op);
609 dstKey +=
X->size_array[0];
622 cInsert.blockFormat =
c.blockFormat;
627 B->revision = revision;
651 curs->changed =
true;
663 int newFormatIdx = -1;
667 newFormatIdx =
formats.indexForFormat(cleanFormat);
669 newFormatIdx =
formats.indexForFormat(newFormat);
676 initialBlockCharFormatIndex =
formats.indexForFormat(
format);
678 &&
formats.format(initialBlockCharFormatIndex).objectIndex() != -1) {
681 initialBlockCharFormatIndex =
formats.indexForFormat(
f);
683 initialBlockCharFormatIndex = newFormatIdx;
690 const int startPos =
pos;
696 while (
pos < endPos) {
706 int oldFormat = fragment->
format;
713 &&
formats.format(oldFormat).objectIndex() != -1) {
718 fragment->
format = newFormatIdx;
729 int n = fragments.
findNode(startPos - 1);
740 endIt = endIt.
next();
741 for (; blockIt.
isValid() && blockIt != endIt; blockIt = blockIt.
next())
758 int newFormatIdx = -1;
760 newFormatIdx =
formats.indexForFormat(newFormat);
782 0,
it.position(), 1, 0);
785 if (
group != oldGroup) {
801bool QTextDocumentPrivate::split(
int pos)
817 N->stringPosition =
X->stringPosition +
pos-k;
818 N->format =
X->format;
825bool QTextDocumentPrivate::unite(
uint f)
849 PMDEBUG(
"%s, undoState=%d, undoStack size=%d",
undo ?
"undo:" :
"redo:", undoState, int(undoStack.
size()));
850 if (!undoEnabled || (
undo && undoState == 0) || (!
undo && undoState == undoStack.
size()))
861 int resetBlockRevision =
c.pos;
866 PMDEBUG(
" erase: from %d, length %d",
c.pos,
c.length);
872 PMDEBUG(
" insert: format %d (from %d, length %d, strpos=%d)",
c.format,
c.pos,
c.length,
c.strPos);
875 if (editPos != (
int)
c.pos)
878 editLength +=
c.length;
883 PMDEBUG(
" blockremove: from %d",
c.pos);
893 PMDEBUG(
" blockinsert: charformat %d blockformat %d (pos %d, strpos=%d)",
c.format,
c.blockFormat,
c.pos,
c.strPos);
895 resetBlockRevision += 1;
900 if (editPos != (
int)
c.pos)
906 resetBlockRevision = -1;
907 PMDEBUG(
" charFormat: format %d (from %d, length %d)",
c.format,
c.pos,
c.length);
911 int oldFormat =
it.value()->format;
913 c.format = oldFormat;
914 if (editPos != (
int)
c.pos)
917 editLength +=
c.length;
921 resetBlockRevision = -1;
922 PMDEBUG(
" blockformat: format %d pos %d",
c.format,
c.pos);
930 c.format = oldFormat;
931 if (
group != oldGroup) {
944 resetBlockRevision = -1;
945 PMDEBUG(
" group format change");
947 int oldFormat =
formats.objectFormatIndex(
c.objectIndex);
949 c.format = oldFormat;
958 resetBlockRevision = -1;
969 if (resetBlockRevision >= 0) {
970 int b = blocks.
findNode(resetBlockRevision);
972 B->revision =
c.revision;
980 && undoState < undoStack.
size()
990 int newCursorPos = -1;
993 newCursorPos = editPos + editLength;
994 else if (docChangeFrom >= 0)
995 newCursorPos=
qMin(docChangeFrom + docChangeLength,
length() - 1);
1001 return newCursorPos;
1016 c.block_part = editBlock != 0;
1030 PMDEBUG(
"appendUndoItem, command=%d enabled=%d",
c.command, undoEnabled);
1033 if (undoState < undoStack.
size())
1036 if (editBlock != 0 && editBlockCursorPosition >= 0) {
1037 if (
c.pos != (
quint32) editBlockCursorPosition) {
1040 0, 0, editBlockCursorPosition, 0, 0);
1043 editBlockCursorPosition = -1;
1048 if (!undoStack.
isEmpty() && modified) {
1049 const int lastIdx = undoState - 1;
1056 if (undoStack[lastIdx].tryMerge(
c))
1060 if (modifiedState > undoState)
1074 bool undoCommandsAvailable = undoState != 0;
1075 bool redoCommandsAvailable = undoState != undoStack.
size();
1077 for (
int i = 0;
i < undoState; ++
i) {
1082 undoStack.
remove(0, undoState);
1087 && redoCommandsAvailable) {
1088 for (
int i = undoState;
i < undoStack.
size(); ++
i) {
1093 undoStack.
resize(undoState);
1098 for (
int i = 0;
i < undoStack.
size(); ++
i) {
1105 if (emitSignals && undoCommandsAvailable)
1107 if (emitSignals && redoCommandsAvailable)
1114 if (available != wasUndoAvailable) {
1116 emit q->undoAvailable(available);
1117 wasUndoAvailable = available;
1123 if (available != wasRedoAvailable) {
1125 emit q->redoAvailable(available);
1126 wasRedoAvailable = available;
1141 modifiedState = modified ? -1 : undoState;
1144 compressPieceTable();
1151 if (undoEnabled && undoState)
1152 undoStack[undoState - 1].block_end =
false;
1161 if (undoEnabled && undoState > 0) {
1162 const bool wasBlocking = !undoStack.
at(undoState - 1).
block_end;
1164 undoStack[undoState - 1].block_end =
true;
1170 editBlockCursorPosition = -1;
1183 scan_frames(docChangeFrom, docChangeOldLength, docChangeLength);
1185 if (lout && docChangeFrom >= 0) {
1188 emit q->contentsChange(docChangeFrom, docChangeOldLength, docChangeLength);
1190 lout->
documentChanged(docChangeFrom, docChangeOldLength, docChangeLength);
1208 if (curs->changed) {
1209 curs->changed =
false;
1218 if (blocks.
numNodes() != lastBlockCount) {
1219 lastBlockCount = blocks.
numNodes();
1220 emit q->blockCountChanged(lastBlockCount);
1223 if (!undoEnabled && unreachableCharacterCount)
1224 compressPieceTable();
1230 if (docChangeFrom < 0) {
1231 docChangeFrom = from;
1232 docChangeOldLength =
length;
1233 docChangeLength =
length;
1237 int end =
qMax(from +
length, docChangeFrom + docChangeLength);
1239 docChangeFrom =
start;
1240 docChangeOldLength += diff;
1241 docChangeLength += diff;
1261 curs->changed =
true;
1267 if (docChangeFrom < 0) {
1268 docChangeFrom = from;
1269 if (addedOrRemoved > 0) {
1270 docChangeOldLength = 0;
1271 docChangeLength = addedOrRemoved;
1273 docChangeOldLength = -addedOrRemoved;
1274 docChangeLength = 0;
1282 int added =
qMax(0, addedOrRemoved);
1283 int removed =
qMax(0, -addedOrRemoved);
1286 if (from + removed < docChangeFrom)
1287 diff = docChangeFrom - from - removed;
1288 else if (from > docChangeFrom + docChangeLength)
1289 diff = from - (docChangeFrom + docChangeLength);
1291 int overlap_start =
qMax(from, docChangeFrom);
1292 int overlap_end =
qMin(from + removed, docChangeFrom + docChangeLength);
1293 int removedInside =
qMax(0, overlap_end - overlap_start);
1294 removed -= removedInside;
1297 docChangeFrom =
qMin(docChangeFrom, from);
1298 docChangeOldLength += removed + diff;
1299 docChangeLength += added - removedInside + diff;
1313 ::memcpy(
data, text_unicode +
f->stringPosition,
f->size_array[0] *
sizeof(
QChar));
1314 data +=
f->size_array[0];
1325 return initialBlockCharFormatIndex;
1327 return fragments.
find(
pos - 1)->format;
1374 int objectIndex =
obj->objectIndex();
1375 int oldFormatIndex =
formats.objectFormatIndex(objectIndex);
1380 b->d_func()->markBlocksDirty();
1387 0, 0,
obj->d_func()->objectIndex, 0);
1398 int last = children.
size() - 1;
1399 while (
first <= last) {
1400 int mid = (
first + last) / 2;
1402 if (
pos >
c->lastPosition())
1404 else if (pos < c->firstPosition())
1444void QTextDocumentPrivate::clearFrame(
QTextFrame *
f)
1446 for (
int i = 0;
i <
f->d_func()->childFrames.size(); ++
i)
1447 clearFrame(
f->d_func()->childFrames.at(
i));
1448 f->d_func()->childFrames.clear();
1449 f->d_func()->parentFrame =
nullptr;
1452void QTextDocumentPrivate::scan_frames(
int pos,
int charsRemoved,
int charsAdded)
1475 frame->d_func()->parentFrame =
f;
1476 f->d_func()->childFrames.append(
frame);
1482 f =
frame->d_func()->parentFrame;
1487 frame->d_func()->parentFrame =
f;
1488 f->d_func()->childFrames.append(
frame);
1494 framesDirty =
false;
1497void QTextDocumentPrivate::insert_frame(
QTextFrame *
f)
1499 int start =
f->firstPosition();
1500 int end =
f->lastPosition();
1506 for (
int i = 0;
i <
parent->d_func()->childFrames.size(); ++
i) {
1508 if (start < c->firstPosition() &&
end >
c->lastPosition()) {
1509 parent->d_func()->childFrames.removeAt(
i);
1510 f->d_func()->childFrames.append(
c);
1511 c->d_func()->parentFrame =
f;
1517 for (;
i <
parent->d_func()->childFrames.size(); ++
i) {
1519 if (
c->firstPosition() >
end)
1522 parent->d_func()->childFrames.insert(
i,
f);
1523 f->d_func()->parentFrame =
parent;
1544 int charIdx =
formats.indexForFormat(cfmt);
1552 insert_frame(
frame);
1580 if (objectIndex < 0)
1609 objects[
obj->d_func()->objectIndex] =
obj;
1617 const int objIdx =
object->d_func()->objectIndex;
1622void QTextDocumentPrivate::contentsChanged()
1628 bool m = undoEnabled ? (modifiedState != undoState) : true;
1629 if (modified !=
m) {
1631 emit q->modificationChanged(modified);
1634 emit q->contentsChanged();
1637void QTextDocumentPrivate::compressPieceTable()
1642 const uint garbageCollectionThreshold = 96 * 1024;
1646 bool compressTable = unreachableCharacterCount *
sizeof(
QChar) > garbageCollectionThreshold
1657 memcpy(newTextPtr, text.
constData() +
it->stringPosition,
it->size_array[0] *
sizeof(
QChar));
1658 it->stringPosition = newLen;
1659 newTextPtr +=
it->size_array[0];
1660 newLen +=
it->size_array[0];
1667 unreachableCharacterCount = 0;
1678 modifiedState = undoState;
1682 emit q->modificationChanged(modified);
1698 unreachableCharacterCount +=
cursor.selectionEnd() -
cursor.selectionStart();
1702 cursor.removeSelectedText();
1703 cursor.setBlockCharFormat(charFmt);
1707 compressPieceTable();
1717 curs->aboutToRemoveCell(from, to);
virtual void documentChanged(int from, int charsRemoved, int charsAdded)=0
This function is called whenever the contents of the document change.
@ ObjectReplacementCharacter
uint position(uint node, uint field=0) const
uint insert_single(int key, uint length)
void setSize(uint node, int new_size, uint field=0)
uint previous(uint n) const
Iterator find(int k, uint field=0)
uint erase_single(uint f)
Fragment * fragment(uint index)
uint findNode(int k, uint field=0) const
uint size(uint node, uint field=0) const
int length(uint field=0) const
qsizetype size() const noexcept
bool isEmpty() const noexcept
const_reference at(qsizetype i) const noexcept
void remove(qsizetype i, qsizetype n=1)
void resize(qsizetype size)
void append(parameter_type t)
T value(const Key &key, const T &defaultValue=T()) const
iterator erase(const_iterator it)
size_type remove(const Key &key)
bool remove(const T &value)
iterator insert(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
void clear()
Clears the contents of the string and makes it null.
const QChar * constData() const
Returns a pointer to the data stored in the QString.
qsizetype size() const
Returns the number of characters in this string.
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
qsizetype capacity() const
Returns the maximum number of characters that can be stored in the string without forcing a reallocat...
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
QChar * data()
Returns a pointer to the data stored in the QString.
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString & append(QChar c)
void squeeze()
Releases any memory not required to store the character data.
const QChar * unicode() const
Returns a Unicode representation of the string.
void resize(qsizetype size)
Sets the size of the string to size characters.
bool isValid() const
Returns true if this block format is valid; otherwise returns false.
virtual void blockRemoved(const QTextBlock &block)
Removes the given block from the group; the block itself is not deleted, it simply isn't a member of ...
int length() const
Returns the length of the block in characters.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
int position() const
Returns the index of the block's first character within the document.
bool isValid() const
Returns true if this character format is valid; otherwise returns false.
\reentrant \inmodule QtGui
QTextObject * objectForIndex(int objectIndex) const
QAbstractTextDocumentLayout * layout() const
void documentChange(int from, int length)
int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation=QTextUndoCommand::MoveCursor)
QTextFrame * frameAt(int pos) const
void remove(int pos, int length, QTextUndoCommand::Operation=QTextUndoCommand::MoveCursor)
int rightCursorPosition(int position) const
QTextFrame * insertFrame(int start, int end, const QTextFrameFormat &format)
void appendUndoItem(QAbstractUndoItem *)
Appends a custom undo item to the undo stack.
QTextFrame * rootFrame() const
void removeCursor(QTextCursorPrivate *c)
int blockCharFormatIndex(int node) const
int nextCursorPosition(int position, QTextLayout::CursorMode mode) const
void emitUndoAvailable(bool available)
QTextDocument * document()
static const QTextBlockData * block(const QTextBlock &it)
void deleteObject(QTextObject *object)
bool ensureMaximumBlockCount()
QTextObject * createObject(const QTextFormat &newFormat, int objectIndex=-1)
void changeObjectFormat(QTextObject *group, int format)
void move(int from, int to, int length, QTextUndoCommand::Operation=QTextUndoCommand::MoveCursor)
void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals=false)
void enableUndoRedo(bool enable)
FragmentIterator begin() const
void removeFrame(QTextFrame *frame)
FragmentMap::ConstIterator FragmentIterator
void setLayout(QAbstractTextDocumentLayout *layout)
@ SetFormatAndPreserveObjectIndices
void setBlockFormat(const QTextBlock &from, const QTextBlock &to, const QTextBlockFormat &newFormat, FormatChangeMode mode=SetFormat)
FragmentIterator find(int pos) const
bool isUndoAvailable() const
Qt::CursorMoveStyle defaultCursorMoveStyle
void joinPreviousEditBlock()
QTextObject * objectForFormat(int formatIndex) const
void insert(int pos, const QString &text, int format)
uint blockCursorAdjustment
int leftCursorPosition(int position) const
QTextOption defaultTextOption
FragmentIterator end() const
void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode=SetFormat)
uint needsEnsureMaximumBlockCount
QTextBlock blocksFind(int pos) const
QString plainText() const
void aboutToRemoveCell(int cursorFrom, int cursorEnd)
This method is called from QTextTable when it is about to remove a table-cell to allow cursors to upd...
bool isRedoAvailable() const
int previousCursorPosition(int position, QTextLayout::CursorMode mode) const
void emitRedoAvailable(bool available)
void addCursor(QTextCursorPrivate *c)
\reentrant \inmodule QtGui
Stacks
\value UndoStack The undo stack.
virtual QTextObject * createObject(const QTextFormat &f)
Creates and returns a new document object (a QTextObject), based on the given format.
int objectIndex() const
Returns the index of the format object, or -1 if the format object is invalid.
void setObjectIndex(int object)
Sets the format object's object index.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
void merge(const QTextFormat &other)
Merges the other format with this format; where there are conflicts the other format takes precedence...
void setMargin(qreal margin)
Sets the frame's margin in pixels.
QTextFrame * parentFrame() const
Returns the frame's parent frame.
QTextEngine * engine() const
CursorMode
\value SkipCharacters \value SkipWords
int objectIndex() const
Returns the object index of this object.
QTextFormat format() const
Returns the text object's format.
void setWrapMode(WrapMode wrap)
Sets the option's text wrap mode to the given mode.
@ WrapAtWordBoundaryOrAnywhere
void setTabStopDistance(qreal tabStopDistance)
QAbstractUndoItem * custom
bool tryMerge(const QTextUndoCommand &other)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLdouble GLdouble GLdouble GLdouble q
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define QStringLiteral(str)
#define QTextBeginningOfFrame
static bool isValidBlockSeparator(QChar ch)
static bool isAncestorFrame(QTextFrame *possibleAncestor, QTextFrame *child)
static bool noBlockInString(QStringView str)
#define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8)
static QTextFrame * findChildFrame(QTextFrame *f, int pos)
QVideoFrameFormat::PixelFormat fmt