From cf9cdb1bd0ee5888092d7945e58e4be3cd92f977 Mon Sep 17 00:00:00 2001 From: "kin%netscape.com" Date: Wed, 26 May 1999 21:16:25 +0000 Subject: [PATCH] Added support for nsITransactionListener. Cleaned up includes in header files. git-svn-id: svn://10.0.0.236/trunk@32713 18797224-902f-48f8-a5cc-f745e15eee43 --- .../txmgr/public/nsITransactionListener.h | 154 +++++- .../editor/txmgr/src/nsTransactionItem.cpp | 127 +++-- mozilla/editor/txmgr/src/nsTransactionItem.h | 17 +- .../editor/txmgr/src/nsTransactionManager.cpp | 523 +++++++++++++++++- .../editor/txmgr/src/nsTransactionManager.h | 27 +- .../txmgr/src/nsTransactionManagerFactory.cpp | 5 + .../editor/txmgr/src/nsTransactionStack.cpp | 2 + mozilla/editor/txmgr/src/nsTransactionStack.h | 1 - mozilla/editor/txmgr/tests/TestTXMgr.cpp | 4 +- 9 files changed, 744 insertions(+), 116 deletions(-) diff --git a/mozilla/editor/txmgr/public/nsITransactionListener.h b/mozilla/editor/txmgr/public/nsITransactionListener.h index 278fdd2127a..725ad8c03ce 100644 --- a/mozilla/editor/txmgr/public/nsITransactionListener.h +++ b/mozilla/editor/txmgr/public/nsITransactionListener.h @@ -20,9 +20,8 @@ #define nsITransactionListener_h__ #include "nsISupports.h" -#include "nsITransaction.h" -#include "nsITransactionManager.h" +class nsITransaction; class nsITransactionManager; /* @@ -45,37 +44,154 @@ public: static const nsIID& GetIID() { static nsIID iid = NS_ITRANSACTIONLISTENER_IID; return iid; } /** - * Called when a transaction manager is doing a transaction. - * @param aContinue if true, transaction manager continues normal processing. - * if false, transaction manager discontinues processing. + * Called before a transaction manager calls a transaction's + * Do() method. * @param aManager the transaction manager doing the transaction. * @param aTransaction the transaction being done. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. */ - virtual nsresult Do(PRBool *aContinue, - nsITransactionManager *aManager, + NS_IMETHOD WillDo(nsITransactionManager *aManager, + nsITransaction *aTransaction) = 0; + + /** + * Called after a transaction manager calls the Do() method of + * a transaction. + * @param aManager the transaction manager that did the transaction. + * @param aTransaction the transaction that was done. + * @param aDoResult the nsresult returned after doing the transaction. + * @result error status returned by the listener. + */ + NS_IMETHOD DidDo(nsITransactionManager *aManager, + nsITransaction *aTransaction, + nsresult aDoResult) = 0; + + /** + * Called before a transaction manager calls the Undo() method of + * a transaction. + * @param aManager the transaction manager undoing the transaction. + * @param aTransaction the transaction being undone. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. + */ + NS_IMETHOD WillUndo(nsITransactionManager *aManager, nsITransaction *aTransaction) = 0; /** - * Called when a transaction manager is undoing a transaction. - * @param aContinue if true, transaction manager continues normal processing. - * if false, transaction manager discontinues processing. + * Called after a transaction manager calls the Undo() method of + * a transaction. * @param aManager the transaction manager undoing the transaction. * @param aTransaction the transaction being undone. + * @param aUndoResult the nsresult returned after undoing the transaction. + * @result error status returned by the listener. */ - virtual nsresult Undo(PRBool *aContinue, - nsITransactionManager *aManager, - nsITransaction *aTransaction) = 0; + NS_IMETHOD DidUndo(nsITransactionManager *aManager, + nsITransaction *aTransaction, + nsresult aUndoResult) = 0; /** - * Called when a transaction manager is redoing a transaction. - * @param aContinue if true, transaction manager continues normal processing. - * if false, transaction manager discontinues processing. + * Called before a transaction manager calls the Redo() method of + * a transaction. * @param aManager the transaction manager redoing the transaction. * @param aTransaction the transaction being redone. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. */ - virtual nsresult Redo(PRBool *aContinue, - nsITransactionManager *aManager, - nsITransaction *aTransaction) = 0; + NS_IMETHOD WillRedo(nsITransactionManager *aManager, + nsITransaction *aTransaction) = 0; + + /** + * Called after a transaction manager calls the Redo() method of + * a transaction. + * @param aManager the transaction manager redoing the transaction. + * @param aTransaction the transaction being redone. + * @param aRedoResult the nsresult returned after redoing the transaction. + * @result error status returned by the listener. + */ + NS_IMETHOD DidRedo(nsITransactionManager *aManager, + nsITransaction *aTransaction, + nsresult aRedoResult) = 0; + + /** + * Called before a transaction manager begins a batch. + * @param aManager the transaction manager beginning a batch. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. + */ + NS_IMETHOD WillBeginBatch(nsITransactionManager *aManager) = 0; + + /** + * Called after a transaction manager begins a batch. + * @param aManager the transaction manager that began a batch. + * @param aResult the nsresult returned after beginning a batch. + * @result error status returned by the listener. + */ + NS_IMETHOD DidBeginBatch(nsITransactionManager *aManager, + nsresult aResult) = 0; + + /** + * Called before a transaction manager ends a batch. + * @param aManager the transaction manager ending a batch. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. + */ + NS_IMETHOD WillEndBatch(nsITransactionManager *aManager) = 0; + + /** + * Called after a transaction manager ends a batch. + * @param aManager the transaction manager ending a batch. + * @param aResult the nsresult returned after ending a batch. + * @result error status returned by the listener. + */ + NS_IMETHOD DidEndBatch(nsITransactionManager *aManager, + nsresult aResult) = 0; + + /** + * Called before a transaction manager tries to merge + * a transaction, that was just executed, with the + * transaction at the top of the undo stack. + * @param aManager the transaction manager ending a batch. + * @param aTopTransaction the transaction at the top of the undo stack. + * @param aTransactionToMerge the transaction to merge. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. + */ + NS_IMETHOD WillMerge(nsITransactionManager *aManager, + nsITransaction *aTopTransaction, + nsITransaction *aTransactionToMerge) = 0; + + /** + * Called after a transaction manager tries to merge + * a transaction, that was just executed, with the + * transaction at the top of the undo stack. + * @param aManager the transaction manager ending a batch. + * @param aTopTransaction the transaction at the top of the undo stack. + * @param aTransactionToMerge the transaction to merge. + * @param aDidMerge true if transaction was merged, else false. + * @param aMergeResult the nsresult returned after the merge attempt. + * @result error status returned by the listener. NS_OK + * should be used to indicate no error, proceed with normal control + * flow. NS_COMFALSE can be returned by the listener to + * indicate no error, interrupt normal control flow. + */ + NS_IMETHOD DidMerge(nsITransactionManager *aManager, + nsITransaction *aTopTransaction, + nsITransaction *aTransactionToMerge, + PRBool aDidMerge, + nsresult aMergeResult) = 0; + /* XXX: We should probably add pruning notification methods. */ }; diff --git a/mozilla/editor/txmgr/src/nsTransactionItem.cpp b/mozilla/editor/txmgr/src/nsTransactionItem.cpp index 791c257eb75..c01081c41b8 100644 --- a/mozilla/editor/txmgr/src/nsTransactionItem.cpp +++ b/mozilla/editor/txmgr/src/nsTransactionItem.cpp @@ -16,13 +16,13 @@ * Reserved. */ +#include "nsITransaction.h" +#include "nsITransactionManager.h" +#include "nsTransactionStack.h" +#include "nsTransactionManager.h" #include "nsTransactionItem.h" #include "nsCOMPtr.h" -#ifdef NS_DEBUG -//#define NOISY -#endif - nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction) : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0) { @@ -104,28 +104,22 @@ nsTransactionItem::Do() } nsresult -nsTransactionItem::Undo() +nsTransactionItem::Undo(nsTransactionManager *aTxMgr) { - nsresult result = UndoChildren(); + nsresult result = UndoChildren(aTxMgr); if (NS_FAILED(result)) { - RecoverFromUndoError(); + RecoverFromUndoError(aTxMgr); return result; } if (!mTransaction) return NS_OK; -#ifdef NOISY - nsAutoString redoString; - mTransaction->GetRedoString(&redoString); - printf("undoing %s\n", redoString); -#endif - result = mTransaction->Undo(); if (NS_FAILED(result)) { - RecoverFromUndoError(); + RecoverFromUndoError(aTxMgr); return result; } @@ -133,10 +127,10 @@ nsTransactionItem::Undo() } nsresult -nsTransactionItem::UndoChildren() +nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr) { nsTransactionItem *item; - nsresult result; + nsresult result = NS_OK; PRInt32 sz = 0; if (mUndoStack) { @@ -159,61 +153,65 @@ nsTransactionItem::UndoChildren() return result; } -#ifdef NOISY - nsAutoString redoString; - item->GetRedoString(&redoString); - printf("undoing %s\n", redoString); -#endif + nsITransaction *t = 0; - result = item->Undo(); + result = item->GetTransaction(&t); if (NS_FAILED(result)) { return result; } - result = mUndoStack->Pop(&item); + result = aTxMgr->WillUndoNotify(t); if (NS_FAILED(result)) { return result; } - result = mRedoStack->Push(item); + if (result == NS_COMFALSE) { + return NS_OK; + } - if (NS_FAILED(result)) { - /* XXX: If we got an error here, I doubt we can recover! - * XXX: Should we just push the item back on the undo stack? - */ - return result; + result = item->Undo(aTxMgr); + + if (NS_SUCCEEDED(result)) { + result = mUndoStack->Pop(&item); + + if (NS_SUCCEEDED(result)) { + result = mRedoStack->Push(item); + + /* XXX: If we got an error here, I doubt we can recover! + * XXX: Should we just push the item back on the undo stack? + */ + } + } + + nsresult result2 = aTxMgr->DidUndoNotify(t, result); + + if (NS_SUCCEEDED(result)) { + result = result2; } } } - return NS_OK; + return result; } nsresult -nsTransactionItem::Redo() +nsTransactionItem::Redo(nsTransactionManager *aTxMgr) { nsresult result; if (mTransaction) { - -#ifdef NOISY - nsAutoString undoString; - mTransaction->GetUndoString(&undoString); - printf("redoing %s\n", undoString); -#endif - result = mTransaction->Redo(); if (NS_FAILED(result)) return result; } - result = RedoChildren(); + result = RedoChildren(aTxMgr); if (NS_FAILED(result)) { - RecoverFromRedoError(); + RecoverFromRedoError(aTxMgr); return result; } @@ -221,10 +219,10 @@ nsTransactionItem::Redo() } nsresult -nsTransactionItem::RedoChildren() +nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr) { nsTransactionItem *item; - nsresult result; + nsresult result = NS_OK; PRInt32 sz = 0; if (!mRedoStack) @@ -244,34 +242,45 @@ nsTransactionItem::RedoChildren() return result; } -#ifdef NOISY - nsAutoString undoString; - item->GetUndoString(&undoString); - printf("redoing %s\n", undoString); -#endif + nsITransaction *t = 0; - result = item->Redo(); + result = item->GetTransaction(&t); if (NS_FAILED(result)) { return result; } - result = mRedoStack->Pop(&item); + result = aTxMgr->WillRedoNotify(t); if (NS_FAILED(result)) { return result; } - result = mUndoStack->Push(item); + if (result == NS_COMFALSE) { + return NS_OK; + } - if (NS_FAILED(result)) { - // XXX: If we got an error here, I doubt we can recover! - // XXX: Should we just push the item back on the redo stack? - return result; + result = item->Redo(aTxMgr); + + if (NS_SUCCEEDED(result)) { + result = mRedoStack->Pop(&item); + + if (NS_SUCCEEDED(result)) { + result = mUndoStack->Push(item); + + // XXX: If we got an error here, I doubt we can recover! + // XXX: Should we just push the item back on the redo stack? + } + } + + nsresult result2 = aTxMgr->DidUndoNotify(t, result); + + if (NS_SUCCEEDED(result)) { + result = result2; } } - return NS_OK; + return result; } nsresult @@ -325,18 +334,18 @@ nsTransactionItem::Write(nsIOutputStream *aOutputStream) } nsresult -nsTransactionItem::RecoverFromUndoError(void) +nsTransactionItem::RecoverFromUndoError(nsTransactionManager *aTxMgr) { // // If this method gets called, we never got to the point where we // successfully called Undo() for the transaction item itself. // Just redo any children that successfully called undo! // - return RedoChildren(); + return RedoChildren(aTxMgr); } nsresult -nsTransactionItem::RecoverFromRedoError(void) +nsTransactionItem::RecoverFromRedoError(nsTransactionManager *aTxMgr) { // // If this method gets called, we already successfully called Redo() @@ -346,7 +355,7 @@ nsTransactionItem::RecoverFromRedoError(void) nsresult result; - result = UndoChildren(); + result = UndoChildren(aTxMgr); if (NS_FAILED(result)) { return result; diff --git a/mozilla/editor/txmgr/src/nsTransactionItem.h b/mozilla/editor/txmgr/src/nsTransactionItem.h index 1275c4b0936..4b799feb0d8 100644 --- a/mozilla/editor/txmgr/src/nsTransactionItem.h +++ b/mozilla/editor/txmgr/src/nsTransactionItem.h @@ -19,11 +19,10 @@ #ifndef nsTransactionItem_h__ #define nsTransactionItem_h__ -#include "nsITransaction.h" -#include "nsTransactionStack.h" - +class nsITransaction; class nsTransactionStack; class nsTransactionRedoStack; +class nsTransactionManager; class nsTransactionItem { @@ -41,17 +40,17 @@ public: virtual nsresult GetNumberOfChildren(PRInt32 *aNumChildren); virtual nsresult Do(void); - virtual nsresult Undo(void); - virtual nsresult Redo(void); + virtual nsresult Undo(nsTransactionManager *aTxMgr); + virtual nsresult Redo(nsTransactionManager *aTxMgr); virtual nsresult Write(nsIOutputStream *aOutputStream); private: - virtual nsresult UndoChildren(); - virtual nsresult RedoChildren(); + virtual nsresult UndoChildren(nsTransactionManager *aTxMgr); + virtual nsresult RedoChildren(nsTransactionManager *aTxMgr); - virtual nsresult RecoverFromUndoError(); - virtual nsresult RecoverFromRedoError(); + virtual nsresult RecoverFromUndoError(nsTransactionManager *aTxMgr); + virtual nsresult RecoverFromRedoError(nsTransactionManager *aTxMgr); virtual nsresult GetNumberOfUndoItems(PRInt32 *aNumItems); virtual nsresult GetNumberOfRedoItems(PRInt32 *aNumItems); diff --git a/mozilla/editor/txmgr/src/nsTransactionManager.cpp b/mozilla/editor/txmgr/src/nsTransactionManager.cpp index 5d1c5b99975..89c7ba4fc90 100644 --- a/mozilla/editor/txmgr/src/nsTransactionManager.cpp +++ b/mozilla/editor/txmgr/src/nsTransactionManager.cpp @@ -16,7 +16,15 @@ * Reserved. */ +#include "nsITransaction.h" +#include "nsITransactionManager.h" +#include "nsITransactionListener.h" + +#include "nsTransactionItem.h" +#include "nsTransactionStack.h" +#include "nsVoidArray.h" #include "nsTransactionManager.h" + #include "nsCOMPtr.h" #define LOCK_TX_MANAGER(mgr) @@ -25,20 +33,28 @@ static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kITransactionManagerIID, NS_ITRANSACTIONMANAGER_IID); -#ifdef NS_DEBUG -static PRBool gNoisy = PR_FALSE; -#else -static const PRBool gNoisy = PR_FALSE; -#endif - nsTransactionManager::nsTransactionManager(PRInt32 aMaxTransactionCount) - : mMaxTransactionCount(aMaxTransactionCount) + : mMaxTransactionCount(aMaxTransactionCount), mListeners(0) { mRefCnt = 0; } nsTransactionManager::~nsTransactionManager() { + if (mListeners) + { + PRInt32 i; + nsITransactionListener *listener; + + for (i = 0; i < mListeners->Count(); i++) + { + listener = (nsITransactionListener *)mListeners->ElementAt(i); + NS_IF_RELEASE(listener); + } + + delete mListeners; + mListeners = 0; + } } #ifdef DEBUG_TXMGR_REFCNT @@ -95,15 +111,33 @@ nsTransactionManager::Do(nsITransaction *aTransaction) LOCK_TX_MANAGER(this); - result = BeginTransaction(aTransaction); + result = WillDoNotify(aTransaction); if (NS_FAILED(result)) { UNLOCK_TX_MANAGER(this); return result; } + if (result == NS_COMFALSE) { + UNLOCK_TX_MANAGER(this); + return NS_OK; + } + + result = BeginTransaction(aTransaction); + + if (NS_FAILED(result)) { + DidDoNotify(aTransaction, result); + UNLOCK_TX_MANAGER(this); + return result; + } + result = EndTransaction(); + nsresult result2 = DidDoNotify(aTransaction, result); + + if (NS_SUCCEEDED(result)) + result = result2; + UNLOCK_TX_MANAGER(this); return result; @@ -148,13 +182,41 @@ nsTransactionManager::Undo() return NS_OK; } - result = tx->Undo(); + nsITransaction *t = 0; + + result = tx->GetTransaction(&t); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + result = WillUndoNotify(t); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + if (result == NS_COMFALSE) { + UNLOCK_TX_MANAGER(this); + return NS_OK; + } + + result = tx->Undo(this); if (NS_SUCCEEDED(result)) { result = mUndoStack.Pop(&tx); - result = mRedoStack.Push(tx); + + if (NS_SUCCEEDED(result)) + result = mRedoStack.Push(tx); } + nsresult result2 = DidUndoNotify(t, result); + + if (NS_SUCCEEDED(result)) + result = result2; + UNLOCK_TX_MANAGER(this); return result; @@ -199,13 +261,41 @@ nsTransactionManager::Redo() return NS_OK; } - result = tx->Redo(); + nsITransaction *t = 0; + + result = tx->GetTransaction(&t); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + result = WillRedoNotify(t); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + if (result == NS_COMFALSE) { + UNLOCK_TX_MANAGER(this); + return NS_OK; + } + + result = tx->Redo(this); if (NS_SUCCEEDED(result)) { result = mRedoStack.Pop(&tx); - result = mUndoStack.Push(tx); + + if (NS_SUCCEEDED(result)) + result = mUndoStack.Push(tx); } + nsresult result2 = DidRedoNotify(t, result); + + if (NS_SUCCEEDED(result)) + result = result2; + UNLOCK_TX_MANAGER(this); return result; @@ -235,7 +325,6 @@ nsTransactionManager::Clear() nsresult nsTransactionManager::BeginBatch() { - if (gNoisy) { printf("Begin Batch\n"); } nsresult result; // We can batch independent transactions together by simply pushing @@ -245,8 +334,25 @@ nsTransactionManager::BeginBatch() LOCK_TX_MANAGER(this); + result = WillBeginBatchNotify(); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + if (result == NS_COMFALSE) { + UNLOCK_TX_MANAGER(this); + return NS_OK; + } + result = BeginTransaction(0); + nsresult result2 = DidBeginBatchNotify(result); + + if (NS_SUCCEEDED(result)) + result = result2; + UNLOCK_TX_MANAGER(this); return result; @@ -255,7 +361,6 @@ nsTransactionManager::BeginBatch() nsresult nsTransactionManager::EndBatch() { - if (gNoisy) { printf("End Batch\n"); } nsTransactionItem *tx = 0; nsITransaction *ti = 0; nsresult result; @@ -288,8 +393,25 @@ nsTransactionManager::EndBatch() return NS_ERROR_FAILURE; } + result = WillEndBatchNotify(); + + if (NS_FAILED(result)) { + UNLOCK_TX_MANAGER(this); + return result; + } + + if (result == NS_COMFALSE) { + UNLOCK_TX_MANAGER(this); + return NS_OK; + } + result = EndTransaction(); + nsresult result2 = DidEndBatchNotify(result); + + if (NS_SUCCEEDED(result)) + result = result2; + UNLOCK_TX_MANAGER(this); return result; @@ -495,15 +617,53 @@ nsTransactionManager::Write(nsIOutputStream *aOutputStream) nsresult nsTransactionManager::AddListener(nsITransactionListener *aListener) { - // XXX: Need to add listener support. - return NS_ERROR_NOT_IMPLEMENTED; + if (!aListener) + return NS_ERROR_NULL_POINTER; + + LOCK_TX_MANAGER(this); + + if (!mListeners) { + mListeners = new nsVoidArray(); + + if (!mListeners) { + UNLOCK_TX_MANAGER(this); + return NS_ERROR_OUT_OF_MEMORY; + } + } + + if (!mListeners->AppendElement((void *)aListener)) { + UNLOCK_TX_MANAGER(this); + return NS_ERROR_FAILURE; + } + + NS_ADDREF(aListener); + + UNLOCK_TX_MANAGER(this); + + return NS_OK; } nsresult nsTransactionManager::RemoveListener(nsITransactionListener *aListener) { - // XXX: Need to add listener support. - return NS_ERROR_NOT_IMPLEMENTED; + if (!aListener) + return NS_ERROR_NULL_POINTER; + + if (!mListeners) + return NS_ERROR_FAILURE; + + if (!mListeners->RemoveElement((void *)aListener)) + return NS_ERROR_FAILURE; + + NS_IF_RELEASE(aListener); + + if (mListeners->Count() < 1) + { + delete mListeners; + mListeners = 0; + } + + return NS_OK; } nsresult @@ -530,6 +690,309 @@ nsTransactionManager::ClearRedoStack() return result; } +nsresult +nsTransactionManager::WillDoNotify(nsITransaction *aTransaction) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillDo(this, aTransaction); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidDoNotify(nsITransaction *aTransaction, nsresult aDoResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidDo(this, aTransaction, aDoResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + +nsresult +nsTransactionManager::WillUndoNotify(nsITransaction *aTransaction) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillUndo(this, aTransaction); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidUndoNotify(nsITransaction *aTransaction, nsresult aUndoResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidUndo(this, aTransaction, aUndoResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + +nsresult +nsTransactionManager::WillRedoNotify(nsITransaction *aTransaction) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillRedo(this, aTransaction); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidRedoNotify(nsITransaction *aTransaction, nsresult aRedoResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidRedo(this, aTransaction, aRedoResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + +nsresult +nsTransactionManager::WillBeginBatchNotify() +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillBeginBatch(this); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidBeginBatchNotify(nsresult aResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidBeginBatch(this, aResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + +nsresult +nsTransactionManager::WillEndBatchNotify() +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillEndBatch(this); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidEndBatchNotify(nsresult aResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidEndBatch(this, aResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + +nsresult +nsTransactionManager::WillMergeNotify(nsITransaction *aTop, nsITransaction *aTransaction) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->WillMerge(this, aTop, aTransaction); + + if (NS_FAILED(result) || result == NS_COMFALSE) + break; + } + + return result; +} + +nsresult +nsTransactionManager::DidMergeNotify(nsITransaction *aTop, + nsITransaction *aTransaction, + PRBool aDidMerge, + nsresult aMergeResult) +{ + if (!mListeners) + return NS_OK; + + nsresult result = NS_OK; + PRInt32 i, lcount = mListeners->Count(); + + for (i = 0; i < lcount; i++) + { + nsITransactionListener *listener = (nsITransactionListener *)mListeners->ElementAt(i); + + if (!listener) + return NS_ERROR_FAILURE; + + result = listener->DidMerge(this, aTop, aTransaction, aDidMerge, aMergeResult); + + if (NS_FAILED(result)) + break; + } + + return result; +} + nsresult nsTransactionManager::BeginTransaction(nsITransaction *aTransaction) { @@ -655,15 +1118,27 @@ nsTransactionManager::EndTransaction() result = top->GetTransaction(&topTransaction); if (topTransaction) { - result = topTransaction->Merge(&didMerge, tint); - if (NS_FAILED(result)) { - // XXX: What do we do if this fails? - } + result = WillMergeNotify(topTransaction, tint); - if (didMerge) { - delete tx; + if (NS_FAILED(result)) return result; + + if (result != NS_COMFALSE) { + result = topTransaction->Merge(&didMerge, tint); + + if (NS_FAILED(result)) { + // XXX: What do we do if this fails? + } + + nsresult result2 = DidMergeNotify(topTransaction, tint, didMerge, result); + + // XXX: What do we do if this fails? + + if (didMerge) { + delete tx; + return result; + } } } } diff --git a/mozilla/editor/txmgr/src/nsTransactionManager.h b/mozilla/editor/txmgr/src/nsTransactionManager.h index 15202343024..72545519427 100644 --- a/mozilla/editor/txmgr/src/nsTransactionManager.h +++ b/mozilla/editor/txmgr/src/nsTransactionManager.h @@ -19,8 +19,13 @@ #ifndef nsTransactionManager_h__ #define nsTransactionManager_h__ -#include "nsITransactionManager.h" -#include "nsTransactionStack.h" +class nsITransaction; +class nsITransactionManager; +class nsITransactionListener; +class nsTransactionItem; +class nsTransactionStack; +class nsTransactionRedoStack; +class nsVoidArray; /** implementation of a transaction manager object. * @@ -33,6 +38,7 @@ private: nsTransactionStack mDoStack; nsTransactionStack mUndoStack; nsTransactionRedoStack mRedoStack; + nsVoidArray *mListeners; public: @@ -67,6 +73,23 @@ public: virtual nsresult ClearUndoStack(void); virtual nsresult ClearRedoStack(void); + virtual nsresult WillDoNotify(nsITransaction *aTransaction); + virtual nsresult DidDoNotify(nsITransaction *aTransaction, nsresult aDoResult); + virtual nsresult WillUndoNotify(nsITransaction *aTransaction); + virtual nsresult DidUndoNotify(nsITransaction *aTransaction, nsresult aUndoResult); + virtual nsresult WillRedoNotify(nsITransaction *aTransaction); + virtual nsresult DidRedoNotify(nsITransaction *aTransaction, nsresult aRedoResult); + virtual nsresult WillBeginBatchNotify(); + virtual nsresult DidBeginBatchNotify(nsresult aResult); + virtual nsresult WillEndBatchNotify(); + virtual nsresult DidEndBatchNotify(nsresult aResult); + virtual nsresult WillMergeNotify(nsITransaction *aTop, + nsITransaction *aTransaction); + virtual nsresult DidMergeNotify(nsITransaction *aTop, + nsITransaction *aTransaction, + PRBool aDidMerge, + nsresult aMergeResult); + private: /* nsTransactionManager specific private methods. */ diff --git a/mozilla/editor/txmgr/src/nsTransactionManagerFactory.cpp b/mozilla/editor/txmgr/src/nsTransactionManagerFactory.cpp index 943a41850b0..795d44412cd 100644 --- a/mozilla/editor/txmgr/src/nsTransactionManagerFactory.cpp +++ b/mozilla/editor/txmgr/src/nsTransactionManagerFactory.cpp @@ -23,7 +23,12 @@ #include "nsIServiceManager.h" #include "nsTransactionManagerCID.h" + +#include "nsITransactionManager.h" +#include "nsTransactionItem.h" +#include "nsTransactionStack.h" #include "nsTransactionManager.h" + #include "nsCOMPtr.h" static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); diff --git a/mozilla/editor/txmgr/src/nsTransactionStack.cpp b/mozilla/editor/txmgr/src/nsTransactionStack.cpp index 8daf1386b87..d4f11bbd8bc 100644 --- a/mozilla/editor/txmgr/src/nsTransactionStack.cpp +++ b/mozilla/editor/txmgr/src/nsTransactionStack.cpp @@ -16,6 +16,8 @@ * Reserved. */ +#include "nsITransaction.h" +#include "nsTransactionItem.h" #include "nsTransactionStack.h" #include "nsCOMPtr.h" diff --git a/mozilla/editor/txmgr/src/nsTransactionStack.h b/mozilla/editor/txmgr/src/nsTransactionStack.h index 2134e42c5a3..28418f6a3d8 100644 --- a/mozilla/editor/txmgr/src/nsTransactionStack.h +++ b/mozilla/editor/txmgr/src/nsTransactionStack.h @@ -19,7 +19,6 @@ #ifndef nsTransactionStack_h__ #define nsTransactionStack_h__ -#include "nsTransactionItem.h" #include "nsDeque.h" class nsTransactionItem; diff --git a/mozilla/editor/txmgr/tests/TestTXMgr.cpp b/mozilla/editor/txmgr/tests/TestTXMgr.cpp index acf2c0197c6..a3dc5cbbaa8 100644 --- a/mozilla/editor/txmgr/tests/TestTXMgr.cpp +++ b/mozilla/editor/txmgr/tests/TestTXMgr.cpp @@ -1120,7 +1120,7 @@ quick_test(TestTransactionFactory *factory) result = mgr->AddListener(0); if (NS_FAILED(result) - && result != NS_ERROR_NOT_IMPLEMENTED) { + && result != NS_ERROR_NULL_POINTER) { printf("ERROR: AddListener() returned unexpected error. (%d)\n", result); return result; } @@ -1138,7 +1138,7 @@ quick_test(TestTransactionFactory *factory) result = mgr->RemoveListener(0); if (NS_FAILED(result) - && result != NS_ERROR_NOT_IMPLEMENTED) { + && result != NS_ERROR_NULL_POINTER) { printf("ERROR: RemoveListener() returned unexpected error. (%d)\n", result); return result; }