/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
nsresult TransactionManager::Undo() { // It's possible to be called Undo() again while the transaction manager is // executing a transaction's DoTransaction() method. If this happens, // the Undo() request is ignored, and we return NS_ERROR_FAILURE. This // may occur if a mutation event listener calls document.execCommand("undo"). if (NS_WARN_IF(!mDoStack.IsEmpty())) { return NS_ERROR_FAILURE;
}
// Peek at the top of the undo stack. Don't remove the transaction // until it has successfully completed.
RefPtr<TransactionItem> transactionItem = mUndoStack.Peek(); if (!transactionItem) { // Bail if there's nothing on the stack. return NS_OK;
}
nsresult TransactionManager::Redo() { // It's possible to be called Redo() again while the transaction manager is // executing a transaction's DoTransaction() method. If this happens, // the Redo() request is ignored, and we return NS_ERROR_FAILURE. This // may occur if a mutation event listener calls document.execCommand("redo"). if (NS_WARN_IF(!mDoStack.IsEmpty())) { return NS_ERROR_FAILURE;
}
// Peek at the top of the redo stack. Don't remove the transaction // until it has successfully completed.
RefPtr<TransactionItem> transactionItem = mRedoStack.Peek(); if (!transactionItem) { // Bail if there's nothing on the stack. return NS_OK;
}
nsresult TransactionManager::BeginBatchInternal(nsISupports* aData) { // We can batch independent transactions together by simply pushing // a dummy transaction item on the do stack. This dummy transaction item // will be popped off the do stack, and then pushed on the undo stack // in EndBatch().
nsresult rv = BeginTransaction(nullptr, aData);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "TransactionManager::BeginTransaction() failed"); return rv;
}
nsresult TransactionManager::EndBatchInternal(bool aAllowEmpty) { // XXX: Need to add some mechanism to detect the case where the transaction // at the top of the do stack isn't the dummy transaction, so we can // throw an error!! This can happen if someone calls EndBatch() within // the DoTransaction() method of a transaction. // // For now, we can detect this case by checking the value of the // dummy transaction's mTransaction field. If it is our dummy // transaction, it should be nullptr. This may not be true in the // future when we allow users to execute a transaction when beginning // a batch!!!!
RefPtr<TransactionItem> transactionItem = mDoStack.Peek(); if (NS_WARN_IF(!transactionItem)) { return NS_ERROR_FAILURE;
}
nsCOMPtr<nsITransaction> transaction = transactionItem->GetTransaction(); if (NS_WARN_IF(transaction)) { return NS_ERROR_FAILURE;
}
bool TransactionManager::EnableUndoRedo(int32_t aMaxTransactionCount) { // It is illegal to call EnableUndoRedo() while the transaction manager is // executing a transaction's DoTransaction() method because the undo and redo // stacks might get pruned. If this happens, the EnableUndoRedo() request is // ignored, and we return false. if (NS_WARN_IF(!mDoStack.IsEmpty())) { returnfalse;
}
// If aMaxTransactionCount is 0, it means to disable undo/redo. if (!aMaxTransactionCount) {
mUndoStack.Clear();
mRedoStack.Clear();
mMaxTransactionCount = 0; returntrue;
}
// If aMaxTransactionCount is less than zero, the user wants unlimited // levels of undo! No need to prune the undo or redo stacks. if (aMaxTransactionCount < 0) {
mMaxTransactionCount = -1; returntrue;
}
// If new max transaction count is greater than or equal to current max // transaction count, we don't need to remove any transactions. if (mMaxTransactionCount >= 0 &&
mMaxTransactionCount <= aMaxTransactionCount) {
mMaxTransactionCount = aMaxTransactionCount; returntrue;
}
// If aMaxTransactionCount is greater than the number of transactions that // currently exist on the undo and redo stack, there is no need to prune the // undo or redo stacks.
size_t numUndoItems = NumberOfUndoItems();
size_t numRedoItems = NumberOfRedoItems();
size_t total = numUndoItems + numRedoItems;
size_t newMaxTransactionCount = static_cast<size_t>(aMaxTransactionCount); if (newMaxTransactionCount > total) {
mMaxTransactionCount = aMaxTransactionCount; returntrue;
}
// Try getting rid of some transactions on the undo stack! Start at // the bottom of the stack and pop towards the top. for (; numUndoItems && (numRedoItems + numUndoItems) > newMaxTransactionCount;
numUndoItems--) {
RefPtr<TransactionItem> transactionItem = mUndoStack.PopBottom();
MOZ_ASSERT(transactionItem);
}
// If necessary, get rid of some transactions on the redo stack! Start at // the bottom of the stack and pop towards the top. for (; numRedoItems && (numRedoItems + numUndoItems) > newMaxTransactionCount;
numRedoItems--) {
RefPtr<TransactionItem> transactionItem = mRedoStack.PopBottom();
MOZ_ASSERT(transactionItem);
}
// Transfer data from the transactions that is going to be // merged to the transaction that it is being merged with.
nsCOMArray<nsISupports>& lastData = lastUndo->GetData();
nsCOMArray<nsISupports>& previousData = previousUndo->GetData(); if (!previousData.AppendObjects(lastData)) {
NS_WARNING("nsISupports::AppendObjects() failed"); return NS_ERROR_FAILURE;
}
lastData.Clear(); return rv;
}
nsresult TransactionManager::RemoveTopUndo() { if (mUndoStack.IsEmpty()) { return NS_OK;
}
nsresult TransactionManager::BeginTransaction(nsITransaction* aTransaction,
nsISupports* aData) { // XXX: POSSIBLE OPTIMIZATION // We could use a factory that pre-allocates/recycles transaction items.
RefPtr<TransactionItem> transactionItem = new TransactionItem(aTransaction);
if (aData) {
nsCOMArray<nsISupports>& data = transactionItem->GetData();
data.AppendObject(aData);
}
nsCOMPtr<nsITransaction> transaction = transactionItem->GetTransaction(); if (!transaction && !aAllowEmpty) { // If we get here, the transaction must be a dummy batch transaction // created by BeginBatch(). If it contains no children, get rid of it! if (!transactionItem->NumberOfChildren()) { return NS_OK;
}
}
// Check if the transaction is transient. If it is, there's nothing // more to do, just return. if (transaction) { bool isTransient = false;
nsresult rv = transaction->GetIsTransient(&isTransient); if (NS_FAILED(rv)) {
NS_WARNING("nsITransaction::GetIsTransient() failed"); return rv;
} // XXX: Should we be clearing the redo stack if the transaction // is transient and there is nothing on the do stack? if (isTransient) { return NS_OK;
}
}
if (!mMaxTransactionCount) { return NS_OK;
}
// Check if there is a transaction on the do stack. If there is, // the current transaction is a "sub" transaction, and should // be added to the transaction at the top of the do stack.
RefPtr<TransactionItem> topTransactionItem = mDoStack.Peek(); if (topTransactionItem) { // XXX: What do we do if this fails?
nsresult rv = topTransactionItem->AddChild(*transactionItem);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "TransactionItem::AddChild() failed"); return rv;
}
// The transaction succeeded, so clear the redo stack.
mRedoStack.Clear();
// Check if we can coalesce this transaction with the one at the top // of the undo stack.
topTransactionItem = mUndoStack.Peek(); if (transaction && topTransactionItem) { bool didMerge = false;
nsCOMPtr<nsITransaction> topTransaction =
topTransactionItem->GetTransaction(); if (topTransaction) {
nsresult rv = topTransaction->Merge(transaction, &didMerge); if (didMerge) { return rv;
}
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsITransaction::Merge() failed, but ignored");
}
}
// Check to see if we've hit the max level of undo. If so, // pop the bottom transaction off the undo stack and release it!
int32_t sz = mUndoStack.GetSize(); if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) {
RefPtr<TransactionItem> overflow = mUndoStack.PopBottom();
}
// Push the transaction on the undo stack:
mUndoStack.Push(transactionItem.forget()); return NS_OK;
}
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.