📄 qtextdocument_p.cpp
字号:
// qDebug("merging block with next"); int n = blocks.next(b); Q_ASSERT((int)blocks.position(n) == pos + 1); blocks.setSize(b, blocks.size(b) + blocks.size(n) - 1); b = n; } *blockFormat = blocks.fragment(b)->format; QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(blocks.fragment(b)->format)); if (group) group->blockRemoved(QTextBlock(this, b)); QTextFrame *frame = qobject_cast<QTextFrame *>(objectForFormat(fragments.fragment(x)->format)); if (frame) { frame->d_func()->fragmentRemoved(text.at(fragments.fragment(x)->stringPosition), x); framesDirty = true; } blocks.erase_single(b); const int w = fragments.erase_single(x); adjustDocumentChangesAndCursors(pos, -1, op); return w;}#if !defined(QT_NO_DEBUG)static bool isAncestorFrame(QTextFrame *possibleAncestor, QTextFrame *child){ while (child) { if (child == possibleAncestor) return true; child = child->parentFrame(); } return false;}#endifvoid QTextDocumentPrivate::remove(int pos, int length, QTextUndoCommand::Operation op){ Q_ASSERT(pos >= 0 && pos+length <= fragments.length()); Q_ASSERT(blocks.length() == fragments.length());#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()); Q_ASSERT(startAndEndInSameFrame || endIsEndOfChildFrame || startIsStartOfFrameAndEndIsEndOfFrameWithCommonParent);#endif beginEditBlock(); split(pos); split(pos+length); 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); QTextFragmentData *X = fragments.fragment(x); QTextUndoCommand c = { QTextUndoCommand::Removed, true, op, X->format, X->stringPosition, key, { X->size } }; 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); } else {// qDebug("remove_block at %d", key); Q_ASSERT(X->size == 1 && isValidBlockSeparator(text.at(X->stringPosition))); b = blocks.previous(b); c.command = blocks.size(b) == 1 ? QTextUndoCommand::BlockDeleted : QTextUndoCommand::BlockRemoved; w = remove_block(key, &c.blockFormat, QTextUndoCommand::BlockAdded, op); } appendUndoItem(c); x = n; } if (w) unite(w); Q_ASSERT(blocks.length() == fragments.length()); endEditBlock();}void QTextDocumentPrivate::setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode){ Q_ASSERT(newFormat.isValid()); beginEditBlock(); int newFormatIdx = -1; 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 { 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 { fragment->format = newFormatIdx; } QTextUndoCommand c = { QTextUndoCommand::CharFormatChanged, true, QTextUndoCommand::MoveCursor, oldFormat, 0, pos, { length } }; 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::setBlockFormat(const QTextBlock &from, const QTextBlock &to, const QTextBlockFormat &newFormat, FormatChangeMode mode){ beginEditBlock(); 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 } }; 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();}bool QTextDocumentPrivate::split(int pos){ uint x = fragments.findNode(pos); if (x) { int k = fragments.position(x);// qDebug("found fragment with key %d, size_left=%d, size=%d to split at %d",// k, (*it)->size_left, (*it)->size, pos); if (k != pos) { Q_ASSERT(k <= pos); // need to resize the first fragment and add a new one QTextFragmentData *X = fragments.fragment(x); int oldsize = X->size; fragments.setSize(x, pos-k); uint n = fragments.insert_single(pos, oldsize-(pos-k)); X = fragments.fragment(x); QTextFragmentData *N = fragments.fragment(n); N->stringPosition = X->stringPosition + pos-k; N->format = X->format; return true; } } return false;}bool QTextDocumentPrivate::unite(uint f){ uint n = fragments.next(f); if (!n) return false; QTextFragmentData *ff = fragments.fragment(f); QTextFragmentData *nf = fragments.fragment(n); if (nf->format == ff->format && (ff->stringPosition + (int)ff->size == nf->stringPosition)) { if (isValidBlockSeparator(text.at(ff->stringPosition)) || isValidBlockSeparator(text.at(nf->stringPosition))) return false; fragments.setSize(f, ff->size + nf->size); fragments.erase_single(n); return true; } return false;}void 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; undoEnabled = false; beginEditBlock(); while (1) { if (undo) --undoState; QTextUndoCommand &c = undoStack[undoState]; 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); if (c.command == QTextUndoCommand::BlockRemoved) c.command = QTextUndoCommand::BlockInserted; else c.command = QTextUndoCommand::BlockAdded; break; case QTextUndoCommand::CharFormatChanged: { 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: { 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: { 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: if (undo) c.custom->undo(); else c.custom->redo(); break; default: Q_ASSERT(false); } if (undo) { if (undoState == 0 || !undoStack[undoState-1].block) break; } else { ++undoState; if (undoState == undoStack.size() || !undoStack[undoState-1].block) break; } } undoEnabled = true; endEditBlock(); Q_Q(QTextDocument); emit q->undoAvailable(isUndoAvailable()); emit q->redoAvailable(isRedoAvailable());}/*! Appends a custom undo \a item to the undo stack.*/void QTextDocumentPrivate::appendUndoItem(QAbstractUndoItem *item){ if (!undoEnabled) { delete item; return; } QTextUndoCommand c; c.command = QTextUndoCommand::Custom; c.block = editBlock != 0; c.operation = QTextUndoCommand::MoveCursor; c.format = 0; c.strPos = 0; c.pos = 0; c.blockFormat = 0; c.custom = item; appendUndoItem(c);}void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c){ Q_Q(QTextDocument); PMDEBUG("appendUndoItem, command=%d enabled=%d", c.command, undoEnabled); if (!undoEnabled) return; if (undoState < undoStack.size()) truncateUndoStack(); if (!undoStack.isEmpty() && modified) { QTextUndoCommand &last = undoStack[undoState - 1]; if (last.tryMerge(c)) return; } undoStack.append(c); undoState++; emit q->undoAvailable(true); emit q->redoAvailable(false);}void QTextDocumentPrivate::truncateUndoStack() { if (undoState == undoStack.size()) return; for (int i = undoState; i < undoStack.size(); ++i) { QTextUndoCommand c = undoStack[i]; if (c.command & QTextUndoCommand::Removed) { // ########// QTextFragment *f = c.fragment_list;// while (f) {// QTextFragment *n = f->right;// delete f;// f = n;// } } else if (c.command & QTextUndoCommand::Custom) { delete c.custom; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -