nsresult nsTransactionManager::EndTransaction() { nsCOMPtr<nsITransaction> tint; nsRefPtr<nsTransactionItem> tx; nsresult result = NS_OK; // No need for LOCK/UNLOCK_TX_MANAGER() calls since the calling routine // should have done this already! result = mDoStack.Pop(getter_AddRefs(tx)); if (NS_FAILED(result) || !tx) return result; result = tx->GetTransaction(getter_AddRefs(tint)); if (NS_FAILED(result)) { // XXX: What do we do with the transaction item at this point? return result; } if (!tint) { PRInt32 nc = 0; // If we get here, the transaction must be a dummy batch transaction // created by BeginBatch(). If it contains no children, get rid of it! tx->GetNumberOfChildren(&nc); if (!nc) { return result; } } // Check if the transaction is transient. If it is, there's nothing // more to do, just return. PRBool isTransient = PR_FALSE; if (tint) result = tint->GetIsTransient(&isTransient); if (NS_FAILED(result) || isTransient || !mMaxTransactionCount) { // XXX: Should we be clearing the redo stack if the transaction // is transient and there is nothing on the do stack? return result; } nsRefPtr<nsTransactionItem> top; // 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. result = mDoStack.Peek(getter_AddRefs(top)); if (top) { result = top->AddChild(tx); // XXX: What do we do if this fails? return result; } // The transaction succeeded, so clear the redo stack. result = ClearRedoStack(); if (NS_FAILED(result)) { // XXX: What do we do if this fails? } // Check if we can coalesce this transaction with the one at the top // of the undo stack. top = 0; result = mUndoStack.Peek(getter_AddRefs(top)); if (tint && top) { PRBool didMerge = PR_FALSE; nsCOMPtr<nsITransaction> topTransaction; result = top->GetTransaction(getter_AddRefs(topTransaction)); if (topTransaction) { PRBool doInterrupt = PR_FALSE; result = WillMergeNotify(topTransaction, tint, &doInterrupt); NS_ENSURE_SUCCESS(result, result); if (!doInterrupt) { result = topTransaction->Merge(tint, &didMerge); nsresult result2 = DidMergeNotify(topTransaction, tint, didMerge, result); if (NS_SUCCEEDED(result)) result = result2; if (NS_FAILED(result)) { // XXX: What do we do if this fails? } if (didMerge) { return result; } } } } // 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! PRInt32 sz = 0; result = mUndoStack.GetSize(&sz); if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) { nsRefPtr<nsTransactionItem> overflow; result = mUndoStack.PopBottom(getter_AddRefs(overflow)); // XXX: What do we do in the case where this fails? } // Push the transaction on the undo stack: result = mUndoStack.Push(tx); if (NS_FAILED(result)) { // XXX: What do we do in the case where a clear fails? // Remove the transaction from the stack, and release it? } return result; }
nsresult nsTransactionManager::EndTransaction() { nsresult result = NS_OK; nsRefPtr<nsTransactionItem> tx = mDoStack.Pop(); if (!tx) return NS_ERROR_FAILURE; nsCOMPtr<nsITransaction> tint = tx->GetTransaction(); if (!tint) { PRInt32 nc = 0; // If we get here, the transaction must be a dummy batch transaction // created by BeginBatch(). If it contains no children, get rid of it! tx->GetNumberOfChildren(&nc); if (!nc) { return result; } } // Check if the transaction is transient. If it is, there's nothing // more to do, just return. bool isTransient = false; if (tint) result = tint->GetIsTransient(&isTransient); if (NS_FAILED(result) || isTransient || !mMaxTransactionCount) { // XXX: Should we be clearing the redo stack if the transaction // is transient and there is nothing on the do stack? return result; } // 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. nsRefPtr<nsTransactionItem> top = mDoStack.Peek(); if (top) { result = top->AddChild(tx); // XXX: What do we do if this fails? return result; } // The transaction succeeded, so clear the redo stack. result = ClearRedoStack(); if (NS_FAILED(result)) { // XXX: What do we do if this fails? } // Check if we can coalesce this transaction with the one at the top // of the undo stack. top = mUndoStack.Peek(); if (tint && top) { bool didMerge = false; nsCOMPtr<nsITransaction> topTransaction = top->GetTransaction(); if (topTransaction) { bool doInterrupt = false; result = WillMergeNotify(topTransaction, tint, &doInterrupt); NS_ENSURE_SUCCESS(result, result); if (!doInterrupt) { result = topTransaction->Merge(tint, &didMerge); nsresult result2 = DidMergeNotify(topTransaction, tint, didMerge, result); if (NS_SUCCEEDED(result)) result = result2; if (NS_FAILED(result)) { // XXX: What do we do if this fails? } if (didMerge) { return result; } } } } // 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! PRInt32 sz = mUndoStack.GetSize(); if (mMaxTransactionCount > 0 && sz >= mMaxTransactionCount) { nsRefPtr<nsTransactionItem> overflow = mUndoStack.PopBottom(); } // Push the transaction on the undo stack: mUndoStack.Push(tx); return NS_OK; }