From 32d1e793b2eb140f63eb0589f81dabe8f46be515 Mon Sep 17 00:00:00 2001 From: "sfraser%netscape.com" Date: Wed, 16 Feb 2000 01:41:59 +0000 Subject: [PATCH] Fix command updating for GFX text widgets. for bug 18395. r=pinkerton git-svn-id: svn://10.0.0.236/trunk@61009 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/forms/src/nsGfxTextControlFrame.cpp | 264 ++++++++++++++---- .../html/forms/src/nsGfxTextControlFrame.h | 71 +++-- 2 files changed, 263 insertions(+), 72 deletions(-) diff --git a/mozilla/layout/html/forms/src/nsGfxTextControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxTextControlFrame.cpp index d2529976b78..3f7b66da0fa 100644 --- a/mozilla/layout/html/forms/src/nsGfxTextControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsGfxTextControlFrame.cpp @@ -43,8 +43,10 @@ #include "nsIFrameManager.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLTextAreaElement.h" +#include "nsIDOMWindow.h" #include "nsIScrollbar.h" #include "nsIScrollableFrame.h" +#include "nsIScriptGlobalObject.h" #include "nsCSSRendering.h" #include "nsIDeviceContext.h" @@ -68,6 +70,7 @@ #include "nsIEditorIMESupport.h" #include "nsIDocumentEncoder.h" #include "nsIEditorMailSupport.h" +#include "nsITransactionManager.h" #include "nsEditorCID.h" #include "nsIDOMNode.h" #include "nsIDOMElement.h" @@ -330,6 +333,8 @@ nsGfxTextControlFrame::nsGfxTextControlFrame() mFrameConstructor(nsnull), mDisplayFrame(nsnull), mDidSetFocus(PR_FALSE), + mGotSelectionState(PR_FALSE), + mSelectionWasCollapsed(PR_FALSE), mPassThroughMouseEvents(eUninitialized) { #ifdef DEBUG @@ -404,16 +409,25 @@ nsGfxTextControlFrame::~nsGfxTextControlFrame() if (mEditor) { // remove selection listener - nsCOMPtrselection; + nsCOMPtr selection; result = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { - nsCOMPtrselListener; - selListener = do_QueryInterface(mEventListener); - if (selListener) { + nsCOMPtr selListener = do_QueryInterface(mEventListener); + if (selListener) selection->RemoveSelectionListener(selListener); - } } + + // remove the txnListener + nsCOMPtr txnMgr; + result = mEditor->GetTransactionManager(getter_AddRefs(txnMgr)); + if (NS_SUCCEEDED(result) && txnMgr) + { + nsCOMPtr txnListener = do_QueryInterface(mEventListener); + if (txnListener) + txnMgr->RemoveListener(txnListener); + } + // remove all other listeners from embedded document nsCOMPtrdomDoc; result = mEditor->GetDocument(getter_AddRefs(domDoc)); @@ -616,8 +630,7 @@ NS_METHOD nsGfxTextControlFrame::HandleEvent(nsIPresContext* aPresContext, break; case NS_FORM_SELECTED: - nsAutoString commandString("selection-changed"); - return UpdateTextControlCommands(commandString); + return UpdateTextControlCommands(nsAutoString("select")); break; } return NS_OK; @@ -2744,18 +2757,32 @@ nsGfxTextControlFrame::InstallEventListeners() if (NS_FAILED(result)) { return result; } // add the selection listener - nsCOMPtrselection; if (mEditor && mEventListener) { + nsCOMPtrselection; result = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_FAILED(result)) { return result; } if (!selection) { return NS_ERROR_NULL_POINTER; } nsCOMPtr selectionListener = do_QueryInterface(mEventListener); if (!selectionListener) { return NS_ERROR_NO_INTERFACE; } - selection->AddSelectionListener(selectionListener); + result = selection->AddSelectionListener(selectionListener); if (NS_FAILED(result)) { return result; } } + + // add the transation listener + if (mEditor && mEventListener) + { + nsCOMPtr txMgr; + result = mEditor->GetTransactionManager(getter_AddRefs(txMgr)); + if (NS_FAILED(result)) return result; + if (!txMgr) { return NS_ERROR_NULL_POINTER; } + nsCOMPtr txnListener = do_QueryInterface(mEventListener); + if (!txnListener) { return NS_ERROR_NO_INTERFACE; } + result = txMgr->AddListener(txnListener); + if (NS_FAILED(result)) { return result; } + } + return result; } @@ -3073,51 +3100,62 @@ nsGfxTextControlFrame::InternalContentChanged() // Dispatch the change event nsEventStatus status = nsEventStatus_eIgnore; - nsGUIEvent event; - event.eventStructType = NS_GUI_EVENT; - event.widget = nsnull; - event.message = NS_FORM_INPUT; - event.flags = NS_EVENT_FLAG_INIT; + nsGUIEvent theEvent; + theEvent.eventStructType = NS_GUI_EVENT; + theEvent.widget = nsnull; + theEvent.message = NS_FORM_INPUT; + theEvent.flags = NS_EVENT_FLAG_INIT; // Have the content handle the event, propogating it according to normal DOM rules. - nsresult result = mContent->HandleDOMEvent(mFramePresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - - // update commands via controllers interface, if present - nsAutoString commandString("furby"); - result = UpdateTextControlCommands(commandString); - - return result; + return mContent->HandleDOMEvent(mFramePresContext, &theEvent, nsnull, NS_EVENT_FLAG_INIT, &status); } nsresult nsGfxTextControlFrame::UpdateTextControlCommands(const nsString& aCommand) { - nsresult result; + nsresult rv = NS_OK; - nsCOMPtr controllers; - nsCOMPtr textInputDOMElement = do_QueryInterface(mContent); - if (textInputDOMElement) { - result = textInputDOMElement->GetControllers(getter_AddRefs(controllers)); - } - else - { - nsCOMPtr textAreaDOMElement = do_QueryInterface(mContent); - if (textAreaDOMElement) { - result = textAreaDOMElement->GetControllers(getter_AddRefs(controllers)); - } - } - if (NS_FAILED(result)) { return result; } - if (controllers) - { - nsCOMPtr commandDispatcher; - result = controllers->GetCommandDispatcher(getter_AddRefs(commandDispatcher)); - if (NS_FAILED(result)) { return result; } - if (commandDispatcher) + if (mEditor) + { + if (aCommand == nsAutoString("select")) // optimize select updates { - result = commandDispatcher->UpdateCommands(aCommand); + nsCOMPtr domSelection; + rv = mEditor->GetSelection(getter_AddRefs(domSelection)); + if (NS_FAILED(rv)) return rv; + if (!domSelection) return NS_ERROR_UNEXPECTED; + + PRBool selectionCollapsed; + domSelection->GetIsCollapsed(&selectionCollapsed); + if (mGotSelectionState && mSelectionWasCollapsed == selectionCollapsed) + { + return NS_OK; // no update necessary + } + else + { + mGotSelectionState = PR_TRUE; + mSelectionWasCollapsed = selectionCollapsed; + } } } - return result; + nsCOMPtr content; + rv = GetContent(getter_AddRefs(content)); + if (NS_FAILED(rv)) return rv; + if (!content) return NS_ERROR_FAILURE; + + nsCOMPtr doc; + rv = content->GetDocument(*getter_AddRefs(doc)); + if (NS_FAILED(rv)) return rv; + if (!doc) return NS_ERROR_FAILURE; + + nsCOMPtr scriptGlobalObject; + rv = doc->GetScriptGlobalObject(getter_AddRefs(scriptGlobalObject)); + if (NS_FAILED(rv)) return rv; + if (!scriptGlobalObject) return NS_ERROR_FAILURE; + + nsCOMPtr domWindow = do_QueryInterface(scriptGlobalObject); + if (!domWindow) return NS_ERROR_FAILURE; + + return domWindow->UpdateCommands(aCommand); } @@ -3321,6 +3359,10 @@ EnderFrameLoadingInfo::EnderFrameLoadingInfo(const nsSize& aSize) NS_IMPL_ISUPPORTS(EnderFrameLoadingInfo,kISupportsIID); +#ifdef XP_MAC +#pragma mark - +#endif + /******************************************************************************* * nsEnderDocumentObserver ******************************************************************************/ @@ -3494,6 +3536,9 @@ NS_IMETHODIMP nsEnderDocumentObserver::DocumentWillBeDestroyed(nsIDocument *aDoc return NS_OK; } +#ifdef XP_MAC +#pragma mark - +#endif /******************************************************************************* @@ -3516,14 +3561,11 @@ NS_IMPL_RELEASE(nsEnderEventListener) nsEnderEventListener::nsEnderEventListener() +: mView(nsnull) +, mSkipFocusDispatch(PR_FALSE) // needed for when mouse down set focus on native widgets +, mFirstDoOfFirstUndo(PR_TRUE) { NS_INIT_REFCNT(); - mView = nsnull; - - // needed for when mouse down set focus on native widgets - mSkipFocusDispatch = PR_FALSE; - - // other fields are objects that initialize themselves } nsEnderEventListener::~nsEnderEventListener() @@ -3585,6 +3627,11 @@ nsEnderEventListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsITransactionListener))) { + *aInstancePtr = (void*)(nsITransactionListener*)this; + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(NS_GET_IID(nsIEnderEventListener))) { *aInstancePtr = (void*)(nsIEnderEventListener*)this; NS_ADDREF_THIS(); @@ -4235,7 +4282,118 @@ nsEnderEventListener::TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset) return NS_OK; } +NS_IMETHODIMP nsEnderEventListener::WillDo(nsITransactionManager *aManager, + nsITransaction *aTransaction, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} +NS_IMETHODIMP nsEnderEventListener::DidDo(nsITransactionManager *aManager, + nsITransaction *aTransaction, nsresult aDoResult) +{ + // we only need to update if the undo count is now 1 + nsGfxTextControlFrame *gfxFrame = mFrame.Reference(); + PRBool mustUpdate = PR_FALSE; + + if (gfxFrame) + { + PRInt32 undoCount; + aManager->GetNumberOfUndoItems(&undoCount); + if (undoCount == 1) + { + if (mFirstDoOfFirstUndo) + gfxFrame->UpdateTextControlCommands(nsAutoString("undo")); + + mFirstDoOfFirstUndo = PR_FALSE; + } + } + + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::WillUndo(nsITransactionManager *aManager, + nsITransaction *aTransaction, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::DidUndo(nsITransactionManager *aManager, + nsITransaction *aTransaction, nsresult aUndoResult) +{ + nsGfxTextControlFrame *gfxFrame = mFrame.Reference(); + if (gfxFrame) + { + PRInt32 undoCount; + aManager->GetNumberOfUndoItems(&undoCount); + if (undoCount == 0) + mFirstDoOfFirstUndo = PR_TRUE; // reset the state for the next do + + gfxFrame->UpdateTextControlCommands(nsAutoString("undo")); + } + + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::WillRedo(nsITransactionManager *aManager, + nsITransaction *aTransaction, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::DidRedo(nsITransactionManager *aManager, + nsITransaction *aTransaction, nsresult aRedoResult) +{ + nsGfxTextControlFrame *gfxFrame = mFrame.Reference(); + if (gfxFrame) + { + gfxFrame->UpdateTextControlCommands(nsAutoString("undo")); + } + + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::WillBeginBatch(nsITransactionManager *aManager, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::DidBeginBatch(nsITransactionManager *aManager, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::WillEndBatch(nsITransactionManager *aManager, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::DidEndBatch(nsITransactionManager *aManager, nsresult aResult) +{ + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::WillMerge(nsITransactionManager *aManager, + nsITransaction *aTopTransaction, nsITransaction *aTransactionToMerge, PRBool *aInterrupt) +{ + *aInterrupt = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP nsEnderEventListener::DidMerge(nsITransactionManager *aManager, + nsITransaction *aTopTransaction, nsITransaction *aTransactionToMerge, + PRBool aDidMerge, nsresult aMergeResult) +{ + return NS_OK; +} + +#ifdef XP_MAC +#pragma mark - +#endif /******************************************************************************* * nsEnderFocusListenerForDisplayContent @@ -4306,6 +4464,9 @@ nsEnderFocusListenerForDisplayContent::SetFrame(nsGfxTextControlFrame *aFrame) return NS_OK; } +#ifdef XP_MAC +#pragma mark - +#endif /******************************************************************************* * EnderTempObserver @@ -4421,8 +4582,9 @@ EnderTempObserver::SetFrame(nsGfxTextControlFrame *aFrame) } - - +#ifdef XP_MAC +#pragma mark - +#endif /******************************************************************************* * nsEnderListenerForContent diff --git a/mozilla/layout/html/forms/src/nsGfxTextControlFrame.h b/mozilla/layout/html/forms/src/nsGfxTextControlFrame.h index 7f6068fb3fa..b59c1cfa568 100644 --- a/mozilla/layout/html/forms/src/nsGfxTextControlFrame.h +++ b/mozilla/layout/html/forms/src/nsGfxTextControlFrame.h @@ -35,6 +35,7 @@ #include "nsIDOMDragListener.h" #include "nsIDOMFocusListener.h" #include "nsIDOMSelectionListener.h" +#include "nsITransactionListener.h" #include "nsIDOMDocument.h" #include "nsIPresContext.h" #include "nsIContent.h" @@ -221,7 +222,8 @@ class nsEnderEventListener : public nsIEnderEventListener, public nsIDOMKeyListener, public nsIDOMMouseListener, public nsIDOMFocusListener, - public nsIDOMSelectionListener + public nsIDOMSelectionListener, + public nsITransactionListener { public: @@ -274,6 +276,25 @@ public: NS_IMETHOD TableCellNotification(nsIDOMNode* aNode, PRInt32 aOffset); /*END interfaces from nsIDOMSelectionListener*/ + /** nsITransactionListener interfaces + */ + + NS_IMETHOD WillDo(nsITransactionManager *aManager, nsITransaction *aTransaction, PRBool *aInterrupt); + NS_IMETHOD DidDo(nsITransactionManager *aManager, nsITransaction *aTransaction, nsresult aDoResult); + NS_IMETHOD WillUndo(nsITransactionManager *aManager, nsITransaction *aTransaction, PRBool *aInterrupt); + NS_IMETHOD DidUndo(nsITransactionManager *aManager, nsITransaction *aTransaction, nsresult aUndoResult); + NS_IMETHOD WillRedo(nsITransactionManager *aManager, nsITransaction *aTransaction, PRBool *aInterrupt); + NS_IMETHOD DidRedo(nsITransactionManager *aManager, nsITransaction *aTransaction, nsresult aRedoResult); + NS_IMETHOD WillBeginBatch(nsITransactionManager *aManager, PRBool *aInterrupt); + NS_IMETHOD DidBeginBatch(nsITransactionManager *aManager, nsresult aResult); + NS_IMETHOD WillEndBatch(nsITransactionManager *aManager, PRBool *aInterrupt); + NS_IMETHOD DidEndBatch(nsITransactionManager *aManager, nsresult aResult); + NS_IMETHOD WillMerge(nsITransactionManager *aManager, nsITransaction *aTopTransaction, + nsITransaction *aTransactionToMerge, PRBool *aInterrupt); + NS_IMETHOD DidMerge(nsITransactionManager *aManager, nsITransaction *aTopTransaction, + nsITransaction *aTransactionToMerge, + PRBool aDidMerge, nsresult aMergeResult); + friend nsresult NS_NewEnderEventListener(nsIEnderEventListener ** aInstancePtrResult); protected: @@ -300,6 +321,9 @@ protected: // of event processing. See the KeyUp handler // for places where this is a problem, and see // nsCWeakReference.h for notes on use. + + PRPackedBool mFirstDoOfFirstUndo; + }; @@ -521,6 +545,9 @@ public: // nsEnderEventListener::Focus PRBool DidSetFocus() { return mDidSetFocus; } + /** Call the controller for this control to update commands */ + nsresult UpdateTextControlCommands(const nsString& aCommand); + /* ============= nsIGfxTextControlFrame ================= */ NS_IMETHOD GetEditor(nsIEditor **aEditor); NS_IMETHOD GetWebShell(nsIWebShell **aWebShell); @@ -632,9 +659,6 @@ protected: nsIAtom** aListName) const; NS_IMETHOD Destroy(nsIPresContext *aPresContext); - /** Call the controller for this control to update commands */ - nsresult UpdateTextControlCommands(const nsString& aCommand); - public: void SetShouldSetFocus() { mDidSetFocus = PR_FALSE; }; void SetFrameConstructor(nsCSSFrameConstructor *aConstructor) @@ -642,33 +666,38 @@ public: nsresult GetFirstFrameWithIID(nsIPresContext *aPresContext, const nsIID& aIID, nsIFrame *aRootFrame, void **aResultFrame); protected: - nsCOMPtr mWebShell; - PRBool mCreatingViewer; - EnderTempObserver* mTempObserver; - nsEnderDocumentObserver *mDocObserver; - PRBool mNotifyOnInput; // init false, + nsCOMPtr mWebShell; + EnderTempObserver* mTempObserver; + nsEnderDocumentObserver* mDocObserver; + + PRPackedBool mCreatingViewer; + PRPackedBool mNotifyOnInput; // init false, // when true this frame propogates notifications whenever the edited content is changed - PRBool mIsProcessing; - PRBool mNeedsStyleInit; - nsIPresContext *mFramePresContext; // not ref counted - nsString* mCachedState; // this is used for caching changed between frame creation + PRPackedBool mIsProcessing; + PRPackedBool mNeedsStyleInit; + PRPackedBool mDidSetFocus; // init false, + + PRPackedBool mGotSelectionState; + PRPackedBool mSelectionWasCollapsed; + + nsIPresContext* mFramePresContext; // not ref counted + nsString* mCachedState; // this is used for caching changed between frame creation // and full initialization - nsCWeakReferent mWeakReferent; // so this obj can be used as a weak ptr + nsCWeakReferent mWeakReferent; // so this obj can be used as a weak ptr // listeners nsCOMPtr mEventListener; // ref counted nsEnderFocusListenerForDisplayContent *mFocusListenerForDisplayContent; // ref counted - nsEnderListenerForContent *mListenerForContent; // ref counted + nsEnderListenerForContent* mListenerForContent; // ref counted - nsCSSFrameConstructor *mFrameConstructor; - nsIFrame *mDisplayFrame; - nsCOMPtr mDisplayContent; + nsCSSFrameConstructor* mFrameConstructor; + nsIFrame* mDisplayFrame; + nsCOMPtr mDisplayContent; // editing state - nsCOMPtr mEditor; // ref counted - nsCOMPtr mDoc; // ref counted + nsCOMPtr mEditor; // ref counted + nsCOMPtr mDoc; // ref counted - PRBool mDidSetFocus; // init false, // the PassThroughState is used to manage a tiny state machine so // only the proper messages get passed through