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