/* x y / / \ y --> a x / \ / a b b */ void QFragmentMapData::rotateRight(uint x) { uint y = X.left; uint p = X.parent; PMDEBUG(" rotateRight on x=%d (y=%d, p=%d)", x, y, p); if (y) { X.left = Y.right; if (Y.right) F(Y.right).parent = x; Y.right = x; Y.parent = p; } else { X.left = 0; } if (!p) { Q_ASSERT(head->root == x); head->root = y; } else if (x == P.right) P.right = y; else P.left = y; X.parent = y; X.size_left -= Y.size_left + Y.size; X.weight_left -= Y.weight_left + 1; inorder(); check(); }
void QFragmentMapData::rebalance(uint x) { X.color = Red; PMDEBUG(" -> rebalance x=%d", x); inorder(); while (X.parent && F(X.parent).color == Red) { uint p = X.parent; uint pp = P.parent; Q_ASSERT(pp); if (p == PP.left) { uint y = PP.right; if (y && Y.color == Red) { P.color = Black; Y.color = Black; PP.color = Red; x = pp; } else { if (x == P.right) { x = p; rotateLeft(x); p = X.parent; pp = P.parent; } P.color = Black; if (pp) { PP.color = Red; rotateRight(pp); } } } else { uint y = PP.left; if (y && Y.color == Red) { P.color = Black; Y.color = Black; PP.color = Red; x = pp; } else { if (x == P.left) { x = p; rotateRight(x); p = X.parent; pp = P.parent; } P.color = Black; if (pp) { PP.color = Red; rotateLeft(pp); } } } } F(root()).color = Black; check(); }
void QFragmentMapData::freeFragment(uint i) { PMDEBUG("===> freeFragment at %d", i); #ifndef QT_NO_DEBUG Q_ASSERT(F(i).parent != 0xdeadbeef); if (head->freelist < head->allocated) { Q_ASSERT(F(head->freelist).parent == 0xdeadbeef); } F(i).parent = 0xdeadbeef; #endif F(i).right = head->freelist; head->freelist = i; --head->node_count; }
void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) { 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; } if (modifiedState > undoState) modifiedState = -1; undoStack.append(c); undoState++; emitUndoAvailable(true); emitRedoAvailable(false); emit document()->undoCommandAdded(); }
uint QFragmentMapData::createFragment() { Q_ASSERT(head->freelist <= head->allocated); uint freePos = head->freelist; if (freePos == head->allocated) { // need to create some free space uint needed = qAllocMore((freePos+1)*fragmentSize, 0); Q_ASSERT(needed/fragmentSize > head->allocated); fragments = (char *)realloc(fragments, needed); head->allocated = needed/fragmentSize; F(freePos).right = 0; #ifndef QT_NO_DEBUG for (uint i = freePos; i < head->allocated; ++i) F(i).parent = 0xdeadbeef; #endif } uint nextPos = F(freePos).right; if (!nextPos) { nextPos = freePos+1; if (nextPos < head->allocated) F(nextPos).right = 0; } head->freelist = nextPos; #ifndef QT_NO_DEBUG Q_ASSERT(F(freePos).parent == 0xdeadbeef); F(freePos).parent = 0; if (nextPos < head->allocated) { Q_ASSERT(F(nextPos).parent == 0xdeadbeef); } #endif ++head->node_count; PMDEBUG("===> createFragment at %d", freePos); return freePos; }
uint QFragmentMapData::insert_single(int key, uint length) { Q_ASSERT(!findNode(key) || (int)this->position(findNode(key)) == key); uint z = createFragment(); Z.size = length; Z.left = 0; Z.right = 0; Z.size_left = 0; Z.weight_left = 0; PMDEBUG("inserting with key %d", key); uint y = 0; uint x = root(); Q_ASSERT(!x || X.parent == 0); uint s = key; // inorder(); bool right = false; while (x) { y = x; // PMDEBUG("x=%p: x->size_left=%d, key=%d, s=%d", x, x->size_left, x->key(), s); if (s <= X.size_left) { x = X.left; right = false; } else { s -= X.size_left + X.size; x = X.right; right = true; } } // if (y) // PMDEBUG(" y=%p: y->size_left=%d, y->key=%d s=%d", y, y->size_left, y ? y->key() : -1, s); Z.parent = y; if (!y) { head->root = z; } else if (!right) { // PMDEBUG("inserting left"); Y.left = z; Y.size_left = Z.size; Y.weight_left = 1; } else { // PMDEBUG("inserting right"); Y.right = z; } while (y && Y.parent) { uint p = Y.parent; if (P.left == y) { P.size_left += Z.size; P.weight_left += 1; } y = p; } // PMDEBUG("before rebalance"); // inorder(); rebalance(z); inorder(); PMDEBUG("end insert\n"); return z; }
uint QFragmentMapData::erase_single(uint z) { uint w = previous(z); uint y = z; uint x; uint p; if (!Y.left) { x = Y.right; } else if (!Y.right) { x = Y.left; } else { y = Y.right; while (Y.left) y = Y.left; x = Y.right; } PMDEBUG("removeAndRebalance on %d (x=%d, y=%d)", z, x, y); inorder(); if (y != z) { F(Z.left).parent = y; Y.left = Z.left; Y.size_left = Z.size_left; Y.weight_left = Z.weight_left; if (y != Z.right) { /* z y / \ / \ a b a b / / ... --> ... / / y x / \ 0 x */ p = Y.parent; if (x) X.parent = p; P.left = x; Y.right = Z.right; F(Z.right).parent = y; uint n = p; while (n != y) { N.size_left -= Y.size; N.weight_left -= 1; n = N.parent; } } else { /* z y / \ / \ a y --> a x / \ 0 x */ p = y; } uint zp = Z.parent; if (!zp) { Q_ASSERT(head->root == z); head->root = y; } else if (F(zp).left == z) { F(zp).left = y; F(zp).size_left -= Z.size; F(zp).weight_left -= 1; } else { F(zp).right = y; } Y.parent = zp; // Swap the colors uint c = Y.color; Y.color = Z.color; Z.color = c; y = z; } else { /* p p p p / / \ \ z --> x z --> x | | x x */ p = Z.parent; if (x) X.parent = p; if (!p) { Q_ASSERT(head->root == z); head->root = x; } else if (P.left == z) { P.left = x; P.size_left -= Z.size; P.weight_left -= 1; } else { P.right = x; } } uint n = z; while (N.parent) { uint p = N.parent; if (P.left == n) { PMDEBUG("reducing size_left of %d by %d", N.parent, Z.size); P.size_left -= Z.size; P.weight_left -= 1; } n = p; } freeFragment(z); PMDEBUG("after removal"); inorder(); check(); if (Y.color != Red) { while (X.parent && (x == 0 || X.color == Black)) { if (x == P.left) { uint w = P.right; if (W.color == Red) { W.color = Black; P.color = Red; rotateLeft(p); w = P.right; } if ((W.left == 0 || F(W.left).color == Black) && (W.right == 0 || F(W.right).color == Black)) { W.color = Red; x = p; p = X.parent; } else { if (W.right == 0 || F(W.right).color == Black) { if (W.left) F(W.left).color = Black; W.color = Red; rotateRight(P.right); w = P.right; } W.color = P.color; P.color = Black; if (W.right) F(W.right).color = Black; rotateLeft(p); break; } } else { uint w = P.left; if (W.color == Red) { W.color = Black; P.color = Red; rotateRight(p); w = P.left; } if ((W.right == 0 || F(W.right).color == Black) && (W.left == 0 || F(W.left).color == Black)) { W.color = Red; x = p; p = X.parent; } else { if (W.left == 0 || F(W.left).color == Black) { if (W.right) F(W.right).color = Black; W.color = Red; rotateLeft(P.left); w = P.left; } W.color = P.color; P.color = Black; if (W.left) F(W.left).color = Black; rotateRight(p); break; } } } if (x) X.color = Black; } PMDEBUG("after rebalance"); inorder(); check(); return w; }
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; }