bool QTextDocumentPrivate::ensureMaximumBlockCount() { if (maximumBlockCount <= 0) return false; if (blocks.numNodes() <= maximumBlockCount) return false; beginEditBlock(); const int blocksToRemove = blocks.numNodes() - maximumBlockCount; QTextCursor cursor(this, 0); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, blocksToRemove); unreachableCharacterCount += cursor.selectionEnd() - cursor.selectionStart(); // preserve the char format of the paragraph that is to become the new first one QTextCharFormat charFmt = cursor.blockCharFormat(); cursor.removeSelectedText(); cursor.setBlockCharFormat(charFmt); endEditBlock(); compressPieceTable(); return true; }
QTextFrame *QTextDocumentPrivate::insertFrame(int start, int end, const QTextFrameFormat &format) { Q_ASSERT(start >= 0 && start < length()); Q_ASSERT(end >= 0 && end < length()); Q_ASSERT(start <= end || end == -1); if (start != end && frameAt(start) != frameAt(end)) return 0; beginEditBlock(); QTextFrame *frame = qobject_cast<QTextFrame *>(createObject(format)); Q_ASSERT(frame); // #### using the default block and char format below might be wrong int idx = formats.indexForFormat(QTextBlockFormat()); QTextCharFormat cfmt; cfmt.setObjectIndex(frame->objectIndex()); int charIdx = formats.indexForFormat(cfmt); insertBlock(QTextBeginningOfFrame, start, idx, charIdx, QTextUndoCommand::MoveCursor); insertBlock(QTextEndOfFrame, ++end, idx, charIdx, QTextUndoCommand::KeepCursor); frame->d_func()->fragment_start = find(start).n; frame->d_func()->fragment_end = find(end).n; insert_frame(frame); endEditBlock(); return frame; }
void Text4Edit( const QString& _text, Ui::TextEditEx& _edit, const Text2DocHtmlMode _htmlMode, const bool _convertLinks, const bool _breakDocument, const Text2HtmlUriCallback _uriCallback, const Emoji::EmojiSizePx _emojiSize, const QTextCharFormat::VerticalAlignment _aligment) { _edit.blockSignals(true); _edit.document()->blockSignals(true); _edit.setUpdatesEnabled(false); Text2DocConverter converter; converter.MakeUniqueResources(true); auto cursor = _edit.textCursor(); cursor.beginEditBlock(); converter.Convert(_text, cursor, _htmlMode, _convertLinks, _breakDocument, _uriCallback, _emojiSize, _aligment); cursor.endEditBlock(); _edit.mergeResources(converter.GetResources()); _edit.setUpdatesEnabled(true); _edit.document()->blockSignals(false); _edit.blockSignals(false); emit (_edit.document()->contentsChanged()); }
void QTextDocumentPrivate::setBlockFormat(const QTextBlock &from, const QTextBlock &to, const QTextBlockFormat &newFormat, FormatChangeMode mode) { beginEditBlock(); Q_ASSERT(mode != SetFormatAndPreserveObjectIndices); // only implemented for setCharFormat Q_ASSERT(newFormat.isValid()); int newFormatIdx = -1; if (mode == SetFormat) newFormatIdx = formats.indexForFormat(newFormat); QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(newFormat)); QTextBlock it = from; QTextBlock end = to; if (end.isValid()) end = end.next(); for (; it != end; it = it.next()) { int oldFormat = block(it)->format; QTextBlockFormat format = formats.blockFormat(oldFormat); QTextBlockGroup *oldGroup = qobject_cast<QTextBlockGroup *>(objectForFormat(format)); if (mode == MergeFormat) { format.merge(newFormat); newFormatIdx = formats.indexForFormat(format); group = qobject_cast<QTextBlockGroup *>(objectForFormat(format)); } block(it)->format = newFormatIdx; block(it)->invalidate(); QTextUndoCommand c = { QTextUndoCommand::BlockFormatChanged, true, QTextUndoCommand::MoveCursor, oldFormat, 0, it.position(), { 1 }, 0 }; appendUndoItem(c); if (group != oldGroup) { if (oldGroup) oldGroup->blockRemoved(it); if (group) group->blockInserted(it); } else if (group) { group->blockFormatChanged(it); } } documentChange(from.position(), to.position() + to.length() - from.position()); endEditBlock(); }
void QTextDocumentPrivate::removeFrame(QTextFrame *frame) { QTextFrame *parent = frame->d_func()->parentFrame; if (!parent) return; int start = frame->firstPosition(); int end = frame->lastPosition(); Q_ASSERT(end >= start); beginEditBlock(); // remove already removes the frames from the tree remove(end, 1); remove(start-1, 1); endEditBlock(); }
void CImgFilterPluginHelperBase::changedClip(const OFX::InstanceChangedArgs &args, const std::string &clipName) { if (clipName == kOfxImageEffectSimpleSourceClipName && _srcClip && _srcClip->isConnected() && args.reason == OFX::eChangeUserEdit) { beginEditBlock("changedClip"); if (_defaultUnpremult && !_premultChanged->getValue()) { switch (_srcClip->getPreMultiplication()) { case OFX::eImageOpaque: _premult->setValue(false); break; case OFX::eImagePreMultiplied: _premult->setValue(true); break; case OFX::eImageUnPreMultiplied: _premult->setValue(false); break; } } if (_processR) { switch (_srcClip->getPixelComponents()) { case OFX::ePixelComponentAlpha: _processR->setValue(false); _processG->setValue(false); _processB->setValue(false); _processA->setValue(true); break; case OFX::ePixelComponentRGBA: case OFX::ePixelComponentRGB: // Alpha is not processed by default on RGBA images _processR->setValue(true); _processG->setValue(true); _processB->setValue(true); _processA->setValue(_defaultProcessAlphaOnRGBA); break; default: break; } } endEditBlock(); } }
int QTextDocumentPrivate::insertBlock(const QChar &blockSeparator, int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation op) { Q_ASSERT(formats.format(blockFormat).isBlockFormat()); Q_ASSERT(formats.format(charFormat).isCharFormat()); Q_ASSERT(pos >= 0 && (pos < fragments.length() || (pos == 0 && fragments.length() == 0))); Q_ASSERT(isValidBlockSeparator(blockSeparator)); beginEditBlock(); int strPos = text.length(); text.append(blockSeparator); const int fragment = insert_block(pos, strPos, charFormat, blockFormat, op, QTextUndoCommand::BlockRemoved); Q_ASSERT(blocks.length() == fragments.length()); int b = blocks.findNode(pos); QTextBlockData *B = blocks.fragment(b); QTextUndoCommand c = { QTextUndoCommand::BlockInserted, true, op, charFormat, strPos, pos, { blockFormat }, B->revision }; appendUndoItem(c); Q_ASSERT(undoState == undoStack.size()); // update revision numbers of the modified blocks. Close to the // truth, but we may want to special case breaking a block before // the first or behind the last character B->revision = undoState; b = blocks.next(b); if (b) { B = blocks.fragment(b); B->revision = undoState; } if (formats.charFormat(charFormat).objectIndex() == -1) needsEnsureMaximumBlockCount = true; endEditBlock(); return fragment; }
void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) { beginEditBlock(); int objectIndex = obj->objectIndex(); int oldFormatIndex = formats.objectFormatIndex(objectIndex); formats.setObjectFormatIndex(objectIndex, format); QTextBlockGroup *b = qobject_cast<QTextBlockGroup *>(obj); if (b) { b->d_func()->markBlocksDirty(); } QTextFrame *f = qobject_cast<QTextFrame *>(obj); if (f) documentChange(f->firstPosition(), f->lastPosition() - f->firstPosition()); QTextUndoCommand c = { QTextUndoCommand::GroupFormatChange, true, QTextUndoCommand::MoveCursor, oldFormatIndex, 0, 0, { obj->d_func()->objectIndex }, 0 }; appendUndoItem(c); endEditBlock(); }
void Text::selectText(const QString &txt, const int index) { regenerate(); if (!doc) { return; } auto cursor = doc->find(txt, index); if (!cursor.isNull()) { cursor.beginEditBlock(); cursor.setPosition(index); cursor.setPosition(index + txt.size(), QTextCursor::KeepAnchor); cursor.endEditBlock(); QTextCharFormat format; format.setBackground(QBrush(QColor("#ff7626"))); cursor.mergeCharFormat(format); regenerate(); update(); } }
void QTextDocumentPrivate::insert(int pos, int strPos, int strLength, int format) { if (strLength <= 0) return; Q_ASSERT(pos >= 0 && pos < fragments.length()); Q_ASSERT(formats.format(format).isCharFormat()); insert_string(pos, strPos, strLength, format, QTextUndoCommand::MoveCursor); beginEditBlock(); int b = blocks.findNode(pos); QTextBlockData *B = blocks.fragment(b); QTextUndoCommand c = { QTextUndoCommand::Inserted, true, QTextUndoCommand::MoveCursor, format, strPos, pos, { strLength }, B->revision }; appendUndoItem(c); B->revision = undoState; Q_ASSERT(undoState == undoStack.size()); endEditBlock(); }
int QTextDocumentPrivate::undoRedo(bool undo) { PMDEBUG("%s, undoState=%d, undoStack size=%d", undo ? "undo:" : "redo:", undoState, undoStack.size()); if (!undoEnabled || (undo && undoState == 0) || (!undo && undoState == undoStack.size())) return -1; undoEnabled = false; beginEditBlock(); while (1) { if (undo) --undoState; QTextUndoCommand &c = undoStack[undoState]; int resetBlockRevision = c.pos; switch(c.command) { case QTextUndoCommand::Inserted: remove(c.pos, c.length, (QTextUndoCommand::Operation)c.operation); PMDEBUG(" erase: from %d, length %d", c.pos, c.length); c.command = QTextUndoCommand::Removed; break; case QTextUndoCommand::Removed: PMDEBUG(" insert: format %d (from %d, length %d, strpos=%d)", c.format, c.pos, c.length, c.strPos); insert_string(c.pos, c.strPos, c.length, c.format, (QTextUndoCommand::Operation)c.operation); c.command = QTextUndoCommand::Inserted; break; case QTextUndoCommand::BlockInserted: case QTextUndoCommand::BlockAdded: remove_block(c.pos, &c.blockFormat, c.command, (QTextUndoCommand::Operation)c.operation); PMDEBUG(" blockremove: from %d", c.pos); if (c.command == QTextUndoCommand::BlockInserted) c.command = QTextUndoCommand::BlockRemoved; else c.command = QTextUndoCommand::BlockDeleted; break; case QTextUndoCommand::BlockRemoved: case QTextUndoCommand::BlockDeleted: PMDEBUG(" blockinsert: charformat %d blockformat %d (pos %d, strpos=%d)", c.format, c.blockFormat, c.pos, c.strPos); insert_block(c.pos, c.strPos, c.format, c.blockFormat, (QTextUndoCommand::Operation)c.operation, c.command); resetBlockRevision += 1; if (c.command == QTextUndoCommand::BlockRemoved) c.command = QTextUndoCommand::BlockInserted; else c.command = QTextUndoCommand::BlockAdded; break; case QTextUndoCommand::CharFormatChanged: { resetBlockRevision = -1; // ## TODO PMDEBUG(" charFormat: format %d (from %d, length %d)", c.format, c.pos, c.length); FragmentIterator it = find(c.pos); Q_ASSERT(!it.atEnd()); int oldFormat = it.value()->format; setCharFormat(c.pos, c.length, formats.charFormat(c.format)); c.format = oldFormat; break; } case QTextUndoCommand::BlockFormatChanged: { resetBlockRevision = -1; // ## TODO PMDEBUG(" blockformat: format %d pos %d", c.format, c.pos); QTextBlock it = blocksFind(c.pos); Q_ASSERT(it.isValid()); int oldFormat = block(it)->format; block(it)->format = c.format; QTextBlockGroup *oldGroup = qobject_cast<QTextBlockGroup *>(objectForFormat(formats.blockFormat(oldFormat))); QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(formats.blockFormat(c.format))); c.format = oldFormat; if (group != oldGroup) { if (oldGroup) oldGroup->blockRemoved(it); if (group) group->blockInserted(it); } else if (group) { group->blockFormatChanged(it); } documentChange(it.position(), it.length()); break; } case QTextUndoCommand::GroupFormatChange: { resetBlockRevision = -1; // ## TODO PMDEBUG(" group format change"); QTextObject *object = objectForIndex(c.objectIndex); int oldFormat = formats.objectFormatIndex(c.objectIndex); changeObjectFormat(object, c.format); c.format = oldFormat; break; } case QTextUndoCommand::Custom: resetBlockRevision = -1; // ## TODO if (undo) c.custom->undo(); else c.custom->redo(); break; default: Q_ASSERT(false); } if (resetBlockRevision >= 0) { int b = blocks.findNode(resetBlockRevision); QTextBlockData *B = blocks.fragment(b); B->revision = c.revision; } if (undo) { if (undoState == 0 || !undoStack[undoState-1].block) break; } else { ++undoState; if (undoState == undoStack.size() || !undoStack[undoState-1].block) break; } } undoEnabled = true; int editPos = -1; if (docChangeFrom >= 0) { editPos = qMin(docChangeFrom + docChangeLength, length() - 1); } endEditBlock(); emitUndoAvailable(isUndoAvailable()); emitRedoAvailable(isRedoAvailable()); return editPos; }
void QTextDocumentPrivate::setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode) { beginEditBlock(); Q_ASSERT(newFormat.isValid()); int newFormatIdx = -1; if (mode == SetFormatAndPreserveObjectIndices) { QTextCharFormat cleanFormat = newFormat; cleanFormat.clearProperty(QTextFormat::ObjectIndex); newFormatIdx = formats.indexForFormat(cleanFormat); } else if (mode == SetFormat) { newFormatIdx = formats.indexForFormat(newFormat); } if (pos == -1) { if (mode == MergeFormat) { QTextFormat format = formats.format(initialBlockCharFormatIndex); format.merge(newFormat); initialBlockCharFormatIndex = formats.indexForFormat(format); } else if (mode == SetFormatAndPreserveObjectIndices && formats.format(initialBlockCharFormatIndex).objectIndex() != -1) { QTextCharFormat f = newFormat; f.setObjectIndex(formats.format(initialBlockCharFormatIndex).objectIndex()); initialBlockCharFormatIndex = formats.indexForFormat(f); } else { initialBlockCharFormatIndex = newFormatIdx; } ++pos; --length; } const int startPos = pos; const int endPos = pos + length; split(startPos); split(endPos); while (pos < endPos) { FragmentMap::Iterator it = fragments.find(pos); Q_ASSERT(!it.atEnd()); QTextFragmentData *fragment = it.value(); Q_ASSERT(formats.format(fragment->format).type() == QTextFormat::CharFormat); int offset = pos - it.position(); int length = qMin(endPos - pos, int(fragment->size - offset)); int oldFormat = fragment->format; if (mode == MergeFormat) { QTextFormat format = formats.format(fragment->format); format.merge(newFormat); fragment->format = formats.indexForFormat(format); } else if (mode == SetFormatAndPreserveObjectIndices && formats.format(oldFormat).objectIndex() != -1) { QTextCharFormat f = newFormat; f.setObjectIndex(formats.format(oldFormat).objectIndex()); fragment->format = formats.indexForFormat(f); } else { fragment->format = newFormatIdx; } QTextUndoCommand c = { QTextUndoCommand::CharFormatChanged, true, QTextUndoCommand::MoveCursor, oldFormat, 0, pos, { length }, 0 }; appendUndoItem(c); pos += length; Q_ASSERT(pos == (int)(it.position() + fragment->size) || pos >= endPos); } int n = fragments.findNode(startPos - 1); if (n) unite(n); n = fragments.findNode(endPos); if (n) unite(n); QTextBlock blockIt = blocksFind(startPos); QTextBlock endIt = blocksFind(endPos); if (endIt.isValid()) endIt = endIt.next(); for (; blockIt.isValid() && blockIt != endIt; blockIt = blockIt.next()) QTextDocumentPrivate::block(blockIt)->invalidate(); documentChange(startPos, length); endEditBlock(); }
void QTextDocumentPrivate::move(int pos, int to, int length, QTextUndoCommand::Operation op) { Q_ASSERT(to <= fragments.length() && to <= pos); Q_ASSERT(pos >= 0 && pos+length <= fragments.length()); Q_ASSERT(blocks.length() == fragments.length()); if (pos == to) return; const bool needsInsert = to != -1; #if !defined(QT_NO_DEBUG) const bool startAndEndInSameFrame = (frameAt(pos) == frameAt(pos + length - 1)); const bool endIsEndOfChildFrame = (isAncestorFrame(frameAt(pos), frameAt(pos + length - 1)) && text.at(find(pos + length - 1)->stringPosition) == QTextEndOfFrame); const bool startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent = (text.at(find(pos)->stringPosition) == QTextBeginningOfFrame && text.at(find(pos + length - 1)->stringPosition) == QTextEndOfFrame && frameAt(pos)->parentFrame() == frameAt(pos + length - 1)->parentFrame()); const bool isFirstTableCell = (qobject_cast<QTextTable *>(frameAt(pos + length - 1)) && frameAt(pos + length - 1)->parentFrame() == frameAt(pos)); Q_ASSERT(startAndEndInSameFrame || endIsEndOfChildFrame || startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent || isFirstTableCell); #endif beginEditBlock(); split(pos); split(pos+length); uint dst = needsInsert ? fragments.findNode(to) : 0; uint dstKey = needsInsert ? fragments.position(dst) : 0; uint x = fragments.findNode(pos); uint end = fragments.findNode(pos+length); uint w = 0; while (x != end) { uint n = fragments.next(x); uint key = fragments.position(x); uint b = blocks.findNode(key+1); QTextBlockData *B = blocks.fragment(b); int blockRevision = B->revision; QTextFragmentData *X = fragments.fragment(x); QTextUndoCommand c = { QTextUndoCommand::Removed, true, op, X->format, X->stringPosition, key, { X->size }, blockRevision }; QTextUndoCommand cInsert = { QTextUndoCommand::Inserted, true, op, X->format, X->stringPosition, dstKey, { X->size }, blockRevision }; if (key+1 != blocks.position(b)) { // qDebug("remove_string from %d length %d", key, X->size); Q_ASSERT(noBlockInString(text.mid(X->stringPosition, X->size))); w = remove_string(key, X->size, op); if (needsInsert) { insert_string(dstKey, X->stringPosition, X->size, X->format, op); dstKey += X->size; } } else { // qDebug("remove_block at %d", key); Q_ASSERT(X->size == 1 && isValidBlockSeparator(text.at(X->stringPosition))); b = blocks.previous(b); B = 0; c.command = blocks.size(b) == 1 ? QTextUndoCommand::BlockDeleted : QTextUndoCommand::BlockRemoved; w = remove_block(key, &c.blockFormat, QTextUndoCommand::BlockAdded, op); if (needsInsert) { insert_block(dstKey++, X->stringPosition, X->format, c.blockFormat, op, QTextUndoCommand::BlockRemoved); cInsert.command = blocks.size(b) == 1 ? QTextUndoCommand::BlockAdded : QTextUndoCommand::BlockInserted; cInsert.blockFormat = c.blockFormat; } } appendUndoItem(c); if (B) B->revision = undoState; x = n; if (needsInsert) appendUndoItem(cInsert); } if (w) unite(w); Q_ASSERT(blocks.length() == fragments.length()); endEditBlock(); }