/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsCOMPtr.h" #include "nsGfxTextControlFrame.h" #include "nsIContent.h" #include "prtypes.h" #include "nsIFrame.h" #include "nsISupports.h" #include "nsIAtom.h" #include "nsIPresContext.h" #include "nsIHTMLContent.h" #include "nsHTMLIIDs.h" #include "nsITextWidget.h" #include "nsITextAreaWidget.h" #include "nsWidgetsCID.h" #include "nsSize.h" #include "nsString.h" #include "nsHTMLAtoms.h" #include "nsIStyleContext.h" #include "nsFont.h" #include "nsDOMEvent.h" #include "nsIFormControl.h" #include "nsFormFrame.h" #include "nsIContent.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMHTMLTextAreaElement.h" #include "nsCSSRendering.h" #include "nsIDeviceContext.h" #include "nsIFontMetrics.h" #include "nsILookAndFeel.h" #include "nsIComponentManager.h" #include "nsIWebShell.h" #include "nsINameSpaceManager.h" #include "nsIPref.h" #include "nsIView.h" #include "nsIScrollableView.h" #include "nsIDocumentViewer.h" #include "nsViewsCID.h" #include "nsWidgetsCID.h" #include "nsIHTMLEditor.h" #include "nsIDocumentEncoder.h" #include "nsIEditorMailSupport.h" #include "nsEditorCID.h" #include "nsIDOMNode.h" #include "nsIDOMElement.h" #include "nsIDOMNodeList.h" #include "nsIDOMSelection.h" #include "nsIDOMCharacterData.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMEventReceiver.h" #include "nsIDOMUIEvent.h" #include "nsIPresShell.h" static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID); static NS_DEFINE_IID(kTextCID, NS_TEXTFIELD_CID); static NS_DEFINE_IID(kTextAreaCID, NS_TEXTAREA_CID); static NS_DEFINE_IID(kITextWidgetIID, NS_ITEXTWIDGET_IID); static NS_DEFINE_IID(kITextAreaWidgetIID, NS_ITEXTAREAWIDGET_IID); static NS_DEFINE_IID(kIDOMHTMLTextAreaElementIID, NS_IDOMHTMLTEXTAREAELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID); static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kIWebShellContainerIID, NS_IWEB_SHELL_CONTAINER_IID); static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID); static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID); static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); static NS_DEFINE_IID(kCViewCID, NS_VIEW_CID); static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID); static NS_DEFINE_IID(kIStreamObserverIID, NS_ISTREAMOBSERVER_IID); static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID); static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID); static NS_DEFINE_IID(kIDocumentViewerIID, NS_IDOCUMENT_VIEWER_IID); static NS_DEFINE_IID(kIDOMEventReceiverIID, NS_IDOMEVENTRECEIVER_IID); static NS_DEFINE_IID(kIDOMKeyListenerIID, NS_IDOMKEYLISTENER_IID); //static NS_DEFINE_IID(kIDOMMouseListenerIID, NS_IDOMMOUSELISTENER_IID); static NS_DEFINE_IID(kIDOMFocusListenerIID, NS_IDOMFOCUSLISTENER_IID); #ifndef NECKO // about:blank is broken in netlib #define EMPTY_DOCUMENT "resource:/res/html/empty_doc.html" #else // but works great in the new necko lib #define EMPTY_DOCUMENT "about:blank" #endif //#define NOISY const nscoord kSuggestedNotSet = -1; nsAutoString kTextControl_Wrap_Soft = "SOFT"; nsAutoString kTextControl_Wrap_Hard = "HARD"; nsAutoString kTextControl_Wrap_Off = "OFF"; /************************************** MODULE NOTES *********************************** 7/28/99 buster Mouse listeners are commented out. HTML does not define mouse event notifications for text fields, so I've disabled them. Just as well, there was no mapping of event coordinates in the mouse events yet. 7/28/99 buster There has been no testing of the single signon code that is/was in here. It was simply carried over as is from native text control frame. ****************************************************************************************/ extern nsresult NS_NewNativeTextControlFrame(nsIFrame** aNewFrame); nsresult NS_NewGfxTextControlFrame(nsIFrame** aNewFrame) { NS_PRECONDITION(aNewFrame, "null OUT ptr"); if (nsnull == aNewFrame) { return NS_ERROR_NULL_POINTER; } *aNewFrame = new nsGfxTextControlFrame; if (nsnull == aNewFrame) { return NS_ERROR_OUT_OF_MEMORY; } nsresult result = ((nsGfxTextControlFrame*)(*aNewFrame))->InitTextControl(); if (NS_FAILED(result)) { // can't properly initialized ender, probably it isn't installed //NS_RELEASE(*aNewFrame); // XXX: need to release allocated ender text frame! result = NS_NewNativeTextControlFrame(aNewFrame); } return result; } NS_IMETHODIMP nsGfxTextControlFrame::Init(nsIPresContext& aPresContext, nsIContent* aContent, nsIFrame* aParent, nsIStyleContext* aContext, nsIFrame* aPrevInFlow) { mFramePresContext = &aPresContext; return (nsTextControlFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow)); } NS_IMETHODIMP nsGfxTextControlFrame::InitTextControl() { nsresult result = NS_OK; mWebShell = nsnull; mCreatingViewer = PR_FALSE; // create the stream observer mTempObserver = new EnderTempObserver(); if (!mTempObserver) { return NS_ERROR_OUT_OF_MEMORY; } mTempObserver->SetFrame(this); NS_ADDREF(mTempObserver); // create the document observer mDocObserver = new nsEnderDocumentObserver(); if (!mDocObserver) { return NS_ERROR_OUT_OF_MEMORY; } mDocObserver->SetFrame(this); NS_ADDREF(mDocObserver); nsCOMPtr theEditor; result = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, nsIHTMLEditor::GetIID(), getter_AddRefs(theEditor)); if (NS_FAILED(result)) { return result; } if (!theEditor) { return NS_ERROR_OUT_OF_MEMORY; } mEditor = do_QueryInterface(theEditor); if (!mEditor) { return NS_ERROR_NO_INTERFACE; } // allocate mDummy here to self-check native text control impl. vs. ender text control impl. //NS_NewNativeTextControlFrame((nsIFrame **)&mDummyFrame); //DUMMY // mDummyInitialized = PR_TRUE; //DUMMY return NS_OK; } nsGfxTextControlFrame::nsGfxTextControlFrame() : mWebShell(0), mCreatingViewer(PR_FALSE), mTempObserver(0), mDocObserver(0), mDummyFrame(0), mNeedsStyleInit(PR_TRUE), mIsProcessing(PR_FALSE), mDummyInitialized(PR_FALSE) // DUMMY { } nsGfxTextControlFrame::~nsGfxTextControlFrame() { nsresult result; if (mTempObserver) { mTempObserver->SetFrame(nsnull); NS_RELEASE(mTempObserver); } if (mSelectionListener) { if (mEditor) { nsCOMPtrselection; result = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { nsCOMPtrlistener; listener = do_QueryInterface(mSelectionListener); if (mSelectionListener) { selection->RemoveSelectionListener(listener); } } if (mKeyListener || /*mMouseListener || */mFocusListener) { nsCOMPtrdomDoc; result = mEditor->GetDocument(getter_AddRefs(domDoc)); if (NS_SUCCEEDED(result) && domDoc) { nsCOMPtr er; result = domDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er)); if (NS_SUCCEEDED(result) && er) { if (mKeyListener) er->RemoveEventListenerByIID(mKeyListener, kIDOMKeyListenerIID); /*if (mMouseListener) er->RemoveEventListenerByIID(mMouseListener, kIDOMMouseListenerIID);*/ if (mFocusListener) er->RemoveEventListenerByIID(mFocusListener, kIDOMFocusListenerIID); } } } } } mEditor = 0; // editor must be destroyed before the webshell! if (nsnull != mWebShell) { mWebShell->Destroy(); NS_RELEASE(mWebShell); } if (mDocObserver) { nsCOMPtr doc = do_QueryInterface(mDoc); if (doc) { doc->RemoveObserver(mDocObserver); } mDocObserver->SetFrame(nsnull); NS_RELEASE(mDocObserver); } // this will be a leak -- NS_IF_RELEASE(mDummyFrame); } NS_METHOD nsGfxTextControlFrame::HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus) { if (nsEventStatus_eConsumeNoDefault == aEventStatus) { return NS_OK; } aEventStatus = nsEventStatus_eConsumeDoDefault; // this is the default switch (aEvent->message) { case NS_MOUSE_LEFT_CLICK: MouseClicked(&aPresContext); break; case NS_KEY_PRESS: if (NS_KEY_EVENT == aEvent->eventStructType) { nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent; if (NS_VK_RETURN == keyEvent->keyCode) { EnterPressed(aPresContext); aEventStatus = nsEventStatus_eConsumeNoDefault; } else if (NS_VK_SPACE == keyEvent->keyCode) { MouseClicked(&aPresContext); } } break; } return NS_OK; } void nsGfxTextControlFrame::EnterPressed(nsIPresContext& aPresContext) { if (mFormFrame && mFormFrame->CanSubmit(*this)) { nsIContent *formContent = nsnull; mFormFrame->GetContent(&formContent); if (nsnull != formContent) { nsEvent event; nsEventStatus status = nsEventStatus_eIgnore; event.eventStructType = NS_EVENT; event.message = NS_FORM_SUBMIT; formContent->HandleDOMEvent(aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); NS_RELEASE(formContent); } mFormFrame->OnSubmit(&aPresContext, this); } } nsWidgetInitData* nsGfxTextControlFrame::GetWidgetInitData(nsIPresContext& aPresContext) { return nsnull; } NS_IMETHODIMP nsGfxTextControlFrame::GetText(nsString* aText, PRBool aInitialValue) { nsresult result = NS_CONTENT_ATTR_NOT_THERE; PRInt32 type; GetType(&type); if ((NS_FORM_INPUT_TEXT == type) || (NS_FORM_INPUT_PASSWORD == type)) { if (PR_TRUE==aInitialValue) { result = nsFormControlHelper::GetInputElementValue(mContent, aText, aInitialValue); } else { if (PR_TRUE==IsInitialized()) { nsString format ("text/plain"); mEditor->OutputToString(*aText, format, 0); } else { result = nsFormControlHelper::GetInputElementValue(mContent, aText, aInitialValue); } } RemoveNewlines(*aText); } else { nsIDOMHTMLTextAreaElement* textArea = nsnull; result = mContent->QueryInterface(kIDOMHTMLTextAreaElementIID, (void**)&textArea); if ((NS_OK == result) && textArea) { if (PR_TRUE == aInitialValue) { result = textArea->GetDefaultValue(*aText); } else { result = textArea->GetValue(*aText); } NS_RELEASE(textArea); } } return result; } NS_IMETHODIMP nsGfxTextControlFrame::AttributeChanged(nsIPresContext* aPresContext, nsIContent* aChild, nsIAtom* aAttribute, PRInt32 aHint) { if (PR_FALSE==IsInitialized()) {return NS_ERROR_NOT_INITIALIZED;} nsresult result = NS_OK; if (nsHTMLAtoms::value == aAttribute) { nsString value; GetText(&value, PR_TRUE); // get the initial value from the content attribute mEditor->EnableUndo(PR_FALSE); // wipe out undo info SetTextControlFrameState(value); // set new text value mEditor->EnableUndo(PR_TRUE); // fire up a new txn stack if (aHint != NS_STYLE_HINT_REFLOW) nsFormFrame::StyleChangeReflow(aPresContext, this); } else if (nsHTMLAtoms::maxlength == aAttribute) { PRInt32 maxLength; nsresult rv = GetMaxLength(&maxLength); nsCOMPtr htmlEditor = do_QueryInterface(mEditor); if (htmlEditor) { if (NS_CONTENT_ATTR_NOT_THERE != rv) { // set the maxLength attribute htmlEditor->SetMaxTextLength(maxLength); // if maxLength>docLength, we need to truncate the doc content } else { // unset the maxLength attribute htmlEditor->SetMaxTextLength(-1); } } } else if (nsHTMLAtoms::readonly == aAttribute) { nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); nsresult rv = DoesAttributeExist(nsHTMLAtoms::readonly); PRUint32 flags; mEditor->GetFlags(&flags); if (NS_CONTENT_ATTR_NOT_THERE != rv) { // set readonly flags |= nsIHTMLEditor::eEditorReadonlyMask; presShell->SetCaretEnabled(PR_FALSE); } else { // unset readonly flags &= ~(nsIHTMLEditor::eEditorReadonlyMask); presShell->SetCaretEnabled(PR_TRUE); } mEditor->SetFlags(flags); } else if (nsHTMLAtoms::disabled == aAttribute) { nsCOMPtr presShell; aPresContext->GetShell(getter_AddRefs(presShell)); nsresult rv = DoesAttributeExist(nsHTMLAtoms::disabled); PRUint32 flags; mEditor->GetFlags(&flags); if (NS_CONTENT_ATTR_NOT_THERE != rv) { // set readonly flags |= nsIHTMLEditor::eEditorDisabledMask; presShell->SetCaretEnabled(PR_FALSE); nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); NS_ASSERTION(doc, "null document"); if (!doc) { return NS_ERROR_NULL_POINTER; } doc->SetDisplaySelection(PR_FALSE); } else { // unset readonly flags &= ~(nsIHTMLEditor::eEditorDisabledMask); presShell->SetCaretEnabled(PR_TRUE); nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); NS_ASSERTION(doc, "null document"); if (!doc) { return NS_ERROR_NULL_POINTER; } doc->SetDisplaySelection(PR_TRUE); } mEditor->SetFlags(flags); } else if (nsHTMLAtoms::size == aAttribute && aHint != NS_STYLE_HINT_REFLOW) { nsFormFrame::StyleChangeReflow(aPresContext, this); } // Allow the base class to handle common attributes supported // by all form elements... else { result = nsFormControlFrame::AttributeChanged(aPresContext, aChild, aAttribute, aHint); } // DUMMY if (mDummyFrame) { nsresult dummyResult = mDummyFrame->AttributeChanged(aPresContext, aChild, aAttribute, aHint); NS_ASSERTION((NS_SUCCEEDED(dummyResult)), "dummy frame attribute changed failed."); } // END DUMMY return result; } NS_IMETHODIMP nsGfxTextControlFrame::DoesAttributeExist(nsIAtom *aAtt) { nsresult result = NS_CONTENT_ATTR_NOT_THERE; nsIHTMLContent* content = nsnull; mContent->QueryInterface(kIHTMLContentIID, (void**) &content); if (nsnull != content) { nsHTMLValue value; result = content->GetHTMLAttribute(aAtt, value); NS_RELEASE(content); } return result; } void nsGfxTextControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight) { nsresult rv; // initialize the webshell, if it hasn't already been constructed // if the size is not 0 and there is a src, create the web shell if (aPresContext && (aWidth >= 0) && (aHeight >= 0)) { if (nsnull == mWebShell) { nsSize maxSize(aWidth, aHeight); rv = CreateWebShell(*aPresContext, maxSize); NS_ASSERTION(nsnull!=mWebShell, "null web shell after attempt to create."); } if (nsnull != mWebShell) { mCreatingViewer=PR_TRUE; nsAutoString url(EMPTY_DOCUMENT); rv = mWebShell->LoadURL(url.GetUnicode()); // URL string with a default nsnull value for post Data } } } PRBool nsGfxTextControlFrame::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, nsString* aValues, nsString* aNames) { if (!aValues || !aNames) { return PR_FALSE; } nsAutoString name; nsresult result = GetName(&name); if ((aMaxNumValues <= 0) || (NS_CONTENT_ATTR_NOT_THERE == result)) { return PR_FALSE; } aNames[0] = name; aNumValues = 1; GetText(&(aValues[0]), PR_FALSE); // XXX: error checking return PR_TRUE; } void nsGfxTextControlFrame::Reset() { nsAutoString value; nsresult valStatus = GetText(&value, PR_TRUE); NS_ASSERTION((NS_SUCCEEDED(valStatus)), "GetText failed"); if (NS_SUCCEEDED(valStatus)) { SetTextControlFrameState(value); } } NS_METHOD nsGfxTextControlFrame::Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer) { if (mWebShell) { if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { nsAutoString text(" "); nsRect rect(0, 0, mRect.width, mRect.height); PaintTextControl(aPresContext, aRenderingContext, aDirtyRect, text, mStyleContext, rect); } } return NS_OK; } void nsGfxTextControlFrame::PaintTextControlBackground(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer) { // we paint our own border, but everything else is painted by the mWebshell if (mWebShell) { if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { nsAutoString text(" "); nsRect rect(0, 0, mRect.width, mRect.height); PaintTextControl(aPresContext, aRenderingContext, aDirtyRect, text, mStyleContext, rect); } } } void nsGfxTextControlFrame::PaintTextControl(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsString& aText, nsIStyleContext* aStyleContext, nsRect& aRect) { // XXX: aText is currently unused! const nsStyleDisplay* disp = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display); if (disp->mVisible) { nsCompatibility mode; aPresContext.GetCompatibilityMode(&mode); const nsStyleSpacing* mySpacing = (const nsStyleSpacing*)aStyleContext->GetStyleData(eStyleStruct_Spacing); PRIntn skipSides = 0; nsRect rect(0, 0, mRect.width, mRect.height); if (eCompatibility_NavQuirks == mode) { nscoord borderTwips = 0; nsILookAndFeel * lookAndFeel; if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { PRInt32 tfBorder; lookAndFeel->GetMetric(nsILookAndFeel::eMetric_TextFieldBorder, tfBorder); NS_RELEASE(lookAndFeel); float p2t; aPresContext.GetScaledPixelsToTwips(&p2t); borderTwips = NSIntPixelsToTwips(tfBorder, p2t); } nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *mySpacing, aStyleContext, skipSides, nsnull, borderTwips, PR_TRUE); } else { const nsStyleColor* color = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *mySpacing, 0, 0); //PaintTextControl(aPresContext, aRenderingContext, text, mStyleContext, rect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, aDirtyRect, rect, *mySpacing, aStyleContext, skipSides); } } } //XXX: this needs to be fixed for HTML output void nsGfxTextControlFrame::GetTextControlFrameState(nsString& aValue) { aValue = ""; // initialize out param if (PR_TRUE==IsInitialized()) { nsString format ("text/plain"); PRUint32 flags = 0; if (PR_TRUE==IsPlainTextControl()) { flags |= nsIDocumentEncoder::OutputBodyOnly; // OutputNoDoctype if head info needed } nsString wrap; nsresult result = GetWrapProperty(wrap); if (NS_CONTENT_ATTR_NOT_THERE != result) { if (kTextControl_Wrap_Hard.EqualsIgnoreCase(wrap)) { flags |= nsIDocumentEncoder::OutputFormatted; } } mEditor->OutputToString(aValue, format, flags); } } void nsGfxTextControlFrame::SetTextControlFrameState(const nsString& aValue) { if (PR_TRUE==IsInitialized()) { nsAutoString currentValue; nsString format ("text/plain"); nsresult result = mEditor->OutputToString(currentValue, format, 0); if (PR_TRUE==IsSingleLineTextControl()) { RemoveNewlines(currentValue); } if (PR_FALSE==currentValue.Equals(aValue)) // this is necessary to avoid infinite recursion { nsCOMPtrselection; result = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_FAILED(result)) return; if (!selection) return; nsCOMPtrdomDoc; result = mEditor->GetDocument(getter_AddRefs(domDoc)); if (NS_FAILED(result)) return; if (!domDoc) return; nsCOMPtr bodyNode; nsAutoString bodyTag = "body"; result = GetFirstNodeOfType(bodyTag, domDoc, getter_AddRefs(bodyNode)); SelectAllTextContent(bodyNode, selection); nsCOMPtr htmlEditor = do_QueryInterface(mEditor); if (!htmlEditor) return; // get the flags, remove readonly and disabled, set the value, restore flags PRUint32 flags, savedFlags; mEditor->GetFlags(&savedFlags); flags = savedFlags; flags &= ~(nsIHTMLEditor::eEditorDisabledMask); flags &= ~(nsIHTMLEditor::eEditorReadonlyMask); mEditor->SetFlags(flags); htmlEditor->InsertText(aValue); mEditor->SetFlags(savedFlags); } } } NS_IMETHODIMP nsGfxTextControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) { if (PR_FALSE==mIsProcessing) { mIsProcessing = PR_TRUE; if (nsHTMLAtoms::value == aName) { mEditor->EnableUndo(PR_FALSE); // wipe out undo info SetTextControlFrameState(aValue); // set new text value mEditor->EnableUndo(PR_TRUE); // fire up a new txn stack } else { return Inherited::SetProperty(aName, aValue); } mIsProcessing = PR_FALSE; } return NS_OK; } NS_IMETHODIMP nsGfxTextControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) { // Return the value of the property from the widget it is not null. // If widget is null, assume the widget is GFX-rendered and return a member variable instead. if (nsHTMLAtoms::value == aName) { GetTextControlFrameState(aValue); } else { return Inherited::GetProperty(aName, aValue); } return NS_OK; } void nsGfxTextControlFrame::SetFocus(PRBool aOn, PRBool aRepaint) { if (mWebShell) { if (aOn) { nsresult result = NS_OK; nsIContentViewer *viewer = nsnull; mWebShell->GetContentViewer(&viewer); if (viewer) { nsIDocumentViewer* docv = nsnull; viewer->QueryInterface(kIDocumentViewerIID, (void**) &docv); if (nsnull != docv) { nsIPresContext* cx = nsnull; docv->GetPresContext(cx); if (nsnull != cx) { nsIPresShell *shell = nsnull; cx->GetShell(&shell); if (nsnull != shell) { nsIViewManager *vm = nsnull; shell->GetViewManager(&vm); if (nsnull != vm) { nsIView *rootview = nsnull; vm->GetRootView(rootview); if (rootview) { nsIWidget* widget; rootview->GetWidget(widget); if (widget) { result = widget->SetFocus(); NS_RELEASE(widget); } } NS_RELEASE(vm); } NS_RELEASE(shell); } NS_RELEASE(cx); } NS_RELEASE(docv); } NS_RELEASE(viewer); } } else { mWebShell->RemoveFocus(); } } } /* --------------------- Ender methods ---------------------- */ nsresult nsGfxTextControlFrame::CreateWebShell(nsIPresContext& aPresContext, const nsSize& aSize) { nsresult rv; rv = nsComponentManager::CreateInstance(kWebShellCID, nsnull, kIWebShellIID, (void**)&mWebShell); if (NS_OK != rv) { NS_ASSERTION(0, "could not create web widget"); return rv; } // pass along marginwidth, marginheight, scrolling so sub document can use it mWebShell->SetMarginWidth(0); mWebShell->SetMarginHeight(0); /* our parent must be a webshell. we need to get our prefs from our parent */ nsCOMPtr container; aPresContext.GetContainer(getter_AddRefs(container)); NS_ASSERTION(container, "bad container"); if (!container) return NS_ERROR_UNEXPECTED; nsCOMPtr outerShell = do_QueryInterface(container); NS_ASSERTION(outerShell, "parent must be a webshell"); if (!outerShell) return NS_ERROR_UNEXPECTED; nsIPref* outerPrefs = nsnull; // connect the prefs outerShell->GetPrefs(outerPrefs); NS_ASSERTION(outerPrefs, "no prefs"); if (!outerPrefs) return NS_ERROR_UNEXPECTED; mWebShell->SetPrefs(outerPrefs); NS_RELEASE(outerPrefs); float t2p; aPresContext.GetTwipsToPixels(&t2p); nsCOMPtr presShell; aPresContext.GetShell(getter_AddRefs(presShell)); // create, init, set the parent of the view nsIView* view; rv = nsComponentManager::CreateInstance(kCViewCID, nsnull, kIViewIID, (void **)&view); if (NS_OK != rv) { NS_ASSERTION(0, "Could not create view for nsHTMLFrame"); return rv; } nsIView* parView; nsPoint origin; GetOffsetFromView(origin, &parView); nsRect viewBounds(origin.x, origin.y, aSize.width, aSize.height); nsCOMPtr viewMan; presShell->GetViewManager(getter_AddRefs(viewMan)); rv = view->Init(viewMan, viewBounds, parView); viewMan->InsertChild(parView, view, 0); rv = view->CreateWidget(kCChildCID); SetView(view); // if the visibility is hidden, reflect that in the view const nsStyleDisplay* display; GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)display)); if (NS_STYLE_VISIBILITY_HIDDEN == display->mVisible) { view->SetVisibility(nsViewVisibility_kHide); } const nsStyleSpacing* spacing; GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); nsMargin border; spacing->CalcBorderFor(this, border); nsIWidget* widget; view->GetWidget(widget); nsRect webBounds(NSToCoordRound(border.left * t2p), NSToCoordRound(border.top * t2p), NSToCoordRound((aSize.width - border.right) * t2p), NSToCoordRound((aSize.height - border.bottom) * t2p)); mWebShell->Init(widget->GetNativeData(NS_NATIVE_WIDGET), webBounds.x, webBounds.y, webBounds.width, webBounds.height); NS_RELEASE(widget); mWebShell->SetObserver(mTempObserver); mWebShell->Show(); return NS_OK; } NS_IMETHODIMP nsGfxTextControlFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aMetrics, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("enter nsGfxTextControlFrame::Reflow: aMaxSize=%d,%d", aReflowState.availableWidth, aReflowState.availableHeight)); NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow"); // add ourself as an nsIFormControlFrame if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { nsFormFrame::AddFormControlFrame(aPresContext, *this); } // Figure out if we are doing Quirks or Standard nsCompatibility mode; aPresContext.GetCompatibilityMode(&mode); // calculate the the desired size for the text control // use the suggested size if it has been set nsresult rv = NS_OK; nsHTMLReflowState suggestedReflowState(aReflowState); if ((kSuggestedNotSet != mSuggestedWidth) || (kSuggestedNotSet != mSuggestedHeight)) { // Honor the suggested width and/or height. if (kSuggestedNotSet != mSuggestedWidth) { suggestedReflowState.mComputedWidth = mSuggestedWidth; aMetrics.width = mSuggestedWidth; } if (kSuggestedNotSet != mSuggestedHeight) { suggestedReflowState.mComputedHeight = mSuggestedHeight; aMetrics.height = mSuggestedHeight; } rv = NS_OK; if (!mDidInit) { PostCreateWidget(&aPresContext, aMetrics.width, aMetrics.height); mDidInit = PR_TRUE; } aMetrics.ascent = aMetrics.height; aMetrics.descent = 0; aStatus = NS_FRAME_COMPLETE; } else { // Quirks mode will NOT obey CSS border and padding // GetDesiredSize calculates the size without CSS borders // the nsLeafFrame::Reflow will add in the borders if (eCompatibility_NavQuirks == mode) { GetDesiredSize(&aPresContext, aReflowState, aMetrics); aStatus = NS_FRAME_COMPLETE; } else { nsresult rv = nsLeafFrame::Reflow(aPresContext, aMetrics, aReflowState, aStatus); } // Now resize the widget if there is one, in this case it is // the webshell for the editor if (!mDidInit) { PostCreateWidget(&aPresContext, aMetrics.width, aMetrics.height); mDidInit = PR_TRUE; } //rv = Inherited::Reflow(aPresContext, aMetrics, suggestedReflowState, aStatus); } #ifdef NOISY printf ("exit nsGfxTextControlFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height); #endif // resize the sub document within the defined rect // the sub-document will fit inside the border if (NS_SUCCEEDED(rv) && mWebShell) { // Get the size of the border // if in Quirks mode then it is a hard coded value from // the native look and feel // otherwise it comes from style nsMargin border; if (eCompatibility_NavQuirks == mode) { nsILookAndFeel * lookAndFeel; if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { float p2t; aPresContext.GetPixelsToTwips(&p2t); PRInt32 borderSize; lookAndFeel->GetMetric(nsILookAndFeel::eMetric_TextFieldBorder, borderSize); nscoord borderTwips = NSIntPixelsToTwips(borderSize, p2t); border.SizeTo(borderTwips, borderTwips, borderTwips, borderTwips); NS_RELEASE(lookAndFeel); } } else { // Get the CSS border const nsStyleSpacing* spacing; GetStyleData(eStyleStruct_Spacing, (const nsStyleStruct *&)spacing); spacing->CalcBorderPaddingFor(this, border); } float t2p; aPresContext.GetTwipsToPixels(&t2p); nsRect subBounds; // XXX: the point here is to make a single-line edit field as wide as it wants to be, // so it will scroll horizontally if the characters take up more space than the field subBounds.x = NSToCoordRound(border.left * t2p); subBounds.y = NSToCoordRound(border.top * t2p); subBounds.width = NSToCoordRound((aMetrics.width - (border.left + border.right)) * t2p); subBounds.height = NSToCoordRound((aMetrics.height - (border.top + border.bottom)) * t2p); mWebShell->SetBounds(subBounds.x, subBounds.y, subBounds.width, subBounds.height); #ifdef NOISY printf("webshell set to (%d, %d, %d %d)\n", border.left, border.top, (aMetrics.width - (border.left + border.right)), (aMetrics.height - (border.top + border.bottom))); #endif } NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsGfxTextControlFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height)); // DUMMY if (mDummyFrame) { if (!mDummyInitialized) { mDummyFrame->Init(aPresContext, mContent, mParent, mStyleContext, nsnull); mDummyInitialized = PR_TRUE; } nsHTMLReflowMetrics metrics = aMetrics; nsHTMLReflowState reflowState = suggestedReflowState; nsReflowStatus status = aStatus; nsresult dummyResult = mDummyFrame->Reflow(aPresContext, metrics, reflowState, status); NS_ASSERTION((NS_SUCCEEDED(dummyResult)), "dummy frame reflow failed."); if (aMetrics.width != metrics.width) { printf("CT: different widths\n"); NS_ASSERTION(0, "CT: different widths\n"); } if (aMetrics.height != metrics.height) { printf("CT: different heights\n"); NS_ASSERTION(0, "CT: different heights\n"); } } // END DUMMY return NS_OK; } nsresult nsGfxTextControlFrame::RequiresWidget(PRBool &aRequiresWidget) { aRequiresWidget = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsGfxTextControlFrame::GetPresShellFor(nsIWebShell* aWebShell, nsIPresShell** aPresShell) { if (!aWebShell || !aPresShell) { return NS_ERROR_NULL_POINTER; } nsresult result = NS_ERROR_NULL_POINTER; *aPresShell = nsnull; nsIContentViewer* cv = nsnull; aWebShell->GetContentViewer(&cv); if (nsnull != cv) { nsIDocumentViewer* docv = nsnull; cv->QueryInterface(kIDocumentViewerIID, (void**) &docv); if (nsnull != docv) { nsIPresContext* cx; docv->GetPresContext(cx); if (nsnull != cx) { result = cx->GetShell(aPresShell); NS_RELEASE(cx); } NS_RELEASE(docv); } NS_RELEASE(cv); } return result; } NS_IMETHODIMP nsGfxTextControlFrame::GetFirstNodeOfType(const nsString& aTag, nsIDOMDocument *aDOMDoc, nsIDOMNode **aNode) { if (!aDOMDoc || !aNode) { return NS_ERROR_NULL_POINTER; } *aNode=nsnull; nsCOMPtrnodeList; nsresult result = aDOMDoc->GetElementsByTagName(aTag, getter_AddRefs(nodeList)); if ((NS_SUCCEEDED(result)) && nodeList) { PRUint32 count; nodeList->GetLength(&count); result = nodeList->Item(0, aNode); if (!aNode) { result = NS_ERROR_NULL_POINTER; } } return result; } nsresult nsGfxTextControlFrame::GetFirstFrameForType(const nsString& aTag, nsIPresShell *aPresShell, nsIDOMDocument *aDOMDoc, nsIFrame **aResult) { if (!aPresShell || !aDOMDoc || !aResult) { return NS_ERROR_NULL_POINTER; } nsresult result; *aResult = nsnull; nsCOMPtrnode; result = GetFirstNodeOfType(aTag, aDOMDoc, getter_AddRefs(node)); if ((NS_SUCCEEDED(result)) && node) { nsCOMPtrcontent = do_QueryInterface(node); if (content) { result = aPresShell->GetPrimaryFrameFor(content, aResult); } } return result; } // XXX: this really should use a content iterator over the whole document // looking for the first and last editable text nodes nsresult nsGfxTextControlFrame::SelectAllTextContent(nsIDOMNode *aBodyNode, nsIDOMSelection *aSelection) { if (!aBodyNode || !aSelection) { return NS_ERROR_NULL_POINTER; } nsCOMPtrfirstChild, lastChild; nsresult result = aBodyNode->GetFirstChild(getter_AddRefs(firstChild)); if ((NS_SUCCEEDED(result)) && firstChild) { result = aBodyNode->GetLastChild(getter_AddRefs(lastChild)); if ((NS_SUCCEEDED(result)) && lastChild) { aSelection->Collapse(firstChild, 0); nsCOMPtrtext = do_QueryInterface(lastChild); if (text) { PRUint32 length; text->GetLength(&length); aSelection->Extend(lastChild, length); } } } return result; } // XXX: wouldn't it be nice to get this from the style context! PRBool nsGfxTextControlFrame::IsSingleLineTextControl() const { PRInt32 type; GetType(&type); if ((NS_FORM_INPUT_TEXT==type) || (NS_FORM_INPUT_PASSWORD==type)) { return PR_TRUE; } return PR_FALSE; } // XXX: wouldn't it be nice to get this from the style context! PRBool nsGfxTextControlFrame::IsPlainTextControl() const { // need to check HTML attribute of mContent and/or CSS. return PR_TRUE; } PRBool nsGfxTextControlFrame::IsPasswordTextControl() const { PRInt32 type; GetType(&type); if (NS_FORM_INPUT_PASSWORD==type) { return PR_TRUE; } return PR_FALSE; } // so we don't have to keep an extra flag around, just see if // we've allocated the key listener or not. PRBool nsGfxTextControlFrame::IsInitialized() const { return (PRBool)(nsnull!=mEditor.get() && nsnull!=mKeyListener.get()); } PRInt32 nsGfxTextControlFrame::GetWidthInCharacters() const { // see if there's a COL attribute, if so it wins nsCOMPtr content; nsresult result = mContent->QueryInterface(nsIHTMLContent::GetIID(), getter_AddRefs(content)); if (NS_SUCCEEDED(result) && content) { nsHTMLValue resultValue; result = content->GetHTMLAttribute(nsHTMLAtoms::cols, resultValue); if (NS_CONTENT_ATTR_NOT_THERE != result) { if (resultValue.GetUnit() == eHTMLUnit_Integer) { return (resultValue.GetIntValue()); } } } // otherwise, see if CSS has a width specified. If so, work backwards to get the // number of characters this width represents. // otherwise, the default is just returned. return GetDefaultColumnWidth(); } NS_IMETHODIMP nsGfxTextControlFrame::InstallEditor() { nsresult result = NS_ERROR_NULL_POINTER; if (mEditor) { nsCOMPtr presShell; result = GetPresShellFor(mWebShell, getter_AddRefs(presShell)); if (NS_FAILED(result)) { return result; } if (!presShell) { return NS_ERROR_NULL_POINTER; } // set the scrolling behavior if (PR_TRUE==IsSingleLineTextControl()) { nsCOMPtr vm; presShell->GetViewManager(getter_AddRefs(vm)); if (vm) { nsIScrollableView *sv=nsnull; vm->GetRootScrollableView(&sv); if (sv) { sv->SetScrollPreference(nsScrollPreference_kNeverScroll); // views are not refcounted } } } nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); NS_ASSERTION(doc, "null document"); if (!doc) { return NS_ERROR_NULL_POINTER; } mDoc = do_QueryInterface(doc); if (!mDoc) { return NS_ERROR_NULL_POINTER; } if (mDocObserver) { doc->AddObserver(mDocObserver); } PRUint32 editorFlags = 0; if (IsPlainTextControl()) editorFlags |= nsIHTMLEditor::eEditorPlaintextMask; if (IsSingleLineTextControl()) editorFlags |= nsIHTMLEditor::eEditorSingleLineMask; if (IsPasswordTextControl()) editorFlags |= nsIHTMLEditor::eEditorPasswordMask; // initialize the editor result = mEditor->Init(mDoc, presShell, editorFlags); // set data from the text control into the editor if (NS_SUCCEEDED(result)) { result = InitializeTextControl(presShell, mDoc); } // install our own event handlers before the editor's event handlers if (NS_SUCCEEDED(result)) { result = InstallEventListeners(); } // finish editor initialization, including event handler installation if (NS_SUCCEEDED(result)) { mEditor->PostCreate(); } } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InstallEventListeners() { nsresult result; // get the DOM event receiver nsCOMPtr er; result = mDoc->QueryInterface(kIDOMEventReceiverIID, getter_AddRefs(er)); if (!er) { result = NS_ERROR_NULL_POINTER; } nsCOMPtr eL; // we need to hook up our listeners before the editor is initialized result = NS_NewEnderKeyListener(getter_AddRefs(mKeyListener)); if (NS_SUCCEEDED(result) && mKeyListener) { eL = do_QueryInterface(mKeyListener); if (eL) { eL->SetFrame(this); eL->SetPresContext(mFramePresContext); } result = er->AddEventListenerByIID(mKeyListener, kIDOMKeyListenerIID); if (NS_FAILED(result)) { //we couldn't add the listener mKeyListener = do_QueryInterface(nsnull); // null out the listener, it's useless } } /* result = NS_NewEnderMouseListener(getter_AddRefs(mMouseListener)); if (NS_SUCCEEDED(result) && mMouseListener) { eL = do_QueryInterface(mMouseListener); if (eL) { eL->SetFrame(this); eL->SetPresContext(mFramePresContext); result = er->AddEventListenerByIID(mMouseListener, kIDOMMouseListenerIID); if (NS_FAILED(result)) { //we couldn't add the listener mMouseListener = do_QueryInterface(nsnull); // null out the listener, it's useless } } } */ result = NS_NewEnderFocusListener(getter_AddRefs(mFocusListener)); if (NS_SUCCEEDED(result) && mFocusListener) { eL = do_QueryInterface(mFocusListener); if (eL) { eL->SetFrame(this); eL->SetPresContext(mFramePresContext); result = er->AddEventListenerByIID(mFocusListener, kIDOMFocusListenerIID); if (NS_FAILED(result)) { //we couldn't add the listener mFocusListener = do_QueryInterface(nsnull); // null out the listener, it's useless } } } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InitializeTextControl(nsIPresShell *aPresShell, nsIDOMDocument *aDoc) { nsresult result; if (!aPresShell || !aDoc) { return NS_ERROR_NULL_POINTER; } /* needing a frame here is a hack. We can't remove this hack until we can * set presContext info before style resolution on the webshell */ nsIFrame *frame; result = aPresShell->GetRootFrame(&frame); if (NS_SUCCEEDED(result) && frame) { PRInt32 type; GetType(&type); nsCOMPtr htmlEditor = do_QueryInterface(mEditor); if (!htmlEditor) { return NS_ERROR_NO_INTERFACE; } nsCOMPtrpresContext; aPresShell->GetPresContext(getter_AddRefs(presContext)); NS_ASSERTION(presContext, "null presentation context"); if (!presContext) { return NS_ERROR_NULL_POINTER; } /* set all style that propogates from the text control to its content * into the presContext for the webshell. * what I would prefer to do is hand the webshell my own * pres context at creation, rather than having it create its own. */ nsFont font(presContext->GetDefaultFixedFontDeprecated()); GetFont(presContext, font); const nsStyleFont* controlFont; GetStyleData(eStyleStruct_Font, (const nsStyleStruct *&)controlFont); presContext->SetDefaultFont(font); presContext->SetDefaultFixedFont(font); const nsStyleColor* controlColor; GetStyleData(eStyleStruct_Color, (const nsStyleStruct *&)controlColor); presContext->SetDefaultColor(controlColor->mColor); presContext->SetDefaultBackgroundColor(controlColor->mBackgroundColor); presContext->SetDefaultBackgroundImageRepeat(controlColor->mBackgroundRepeat); presContext->SetDefaultBackgroundImageAttachment(controlColor->mBackgroundAttachment); presContext->SetDefaultBackgroundImageOffset(controlColor->mBackgroundXPosition, controlColor->mBackgroundYPosition); presContext->SetDefaultBackgroundImage(controlColor->mBackgroundImage); /* HACK: * since I don't yet have a hook for setting info on the pres context before style is * resolved, I need to call remap style on the root frame's style context. * The above code for setting presContext data should happen on a presContext that * I create and pass into the webshell, rather than having the webshell create its own */ nsIStyleContext* sc = nsnull; result = frame->GetStyleContext(&sc); if (NS_FAILED(result)) { return result; } if (nsnull==sc) { return NS_ERROR_NULL_POINTER; } sc->RemapStyle(presContext); // end HACK // now that the style context is initialized, initialize the content nsAutoString value; GetText(&value, PR_TRUE); mEditor->EnableUndo(PR_FALSE); PRInt32 maxLength; result = GetMaxLength(&maxLength); if (NS_CONTENT_ATTR_NOT_THERE != result) { htmlEditor->SetMaxTextLength(maxLength); } nsCOMPtr mailEditor = do_QueryInterface(mEditor); if (mailEditor) { PRBool wrapToContainerWidth = PR_TRUE; if (PR_TRUE==IsSingleLineTextControl()) { // no wrapping for single line text controls result = mailEditor->SetBodyWrapWidth(-1); wrapToContainerWidth = PR_FALSE; } else { // if WRAP="OFF", turn wrapping off in the editor nsString wrap; result = GetWrapProperty(wrap); if (NS_CONTENT_ATTR_NOT_THERE != result) { if (kTextControl_Wrap_Off.EqualsIgnoreCase(wrap)) { result = mailEditor->SetBodyWrapWidth(-1); wrapToContainerWidth = PR_FALSE; } if (kTextControl_Wrap_Hard.EqualsIgnoreCase(wrap)) { PRInt32 widthInCharacters = GetWidthInCharacters(); result = mailEditor->SetBodyWrapWidth(widthInCharacters); wrapToContainerWidth = PR_FALSE; } } } if (PR_TRUE==wrapToContainerWidth) { // if we didn't set wrapping explicitly, turn on default wrapping here result = mailEditor->SetBodyWrapWidth(0); } NS_ASSERTION((NS_SUCCEEDED(result)), "error setting body wrap width"); if (NS_FAILED(result)) { return result; } } nsCOMPtreditor = do_QueryInterface(mEditor); NS_ASSERTION(editor, "bad QI to nsIEditor from mEditor"); if (editor) { nsCOMPtrselection; result = editor->GetSelection(getter_AddRefs(selection)); if (NS_FAILED(result)) { return result; } if (!selection) { return NS_ERROR_NULL_POINTER; } nsCOMPtrbodyNode; nsAutoString bodyTag = "body"; result = GetFirstNodeOfType(bodyTag, aDoc, getter_AddRefs(bodyNode)); if (NS_SUCCEEDED(result) && bodyNode) { result = SelectAllTextContent(bodyNode, selection); if (NS_SUCCEEDED(result)) { if (0!=value.Length()) { result = htmlEditor->InsertText(value); if (NS_FAILED(result)) { return result; } // collapse selection to beginning of text nsCOMPtrfirstChild; result = bodyNode->GetFirstChild(getter_AddRefs(firstChild)); if (NS_FAILED(result)) { return result; } selection->Collapse(firstChild, 0); } } } } /* SetColors(*aPresContext); if (nsFormFrame::GetDisabled(this)) { mWidget->Enable(PR_FALSE); } */ // finish initializing editor mEditor->EnableUndo(PR_TRUE); // set readonly and disabled states if (mContent) { PRUint32 flags=0; if (IsPlainTextControl()) { flags |= nsIHTMLEditor::eEditorPlaintextMask; } if (IsSingleLineTextControl()) { flags |= nsIHTMLEditor::eEditorSingleLineMask; } if (IsPasswordTextControl()) { flags |= nsIHTMLEditor::eEditorPasswordMask; } nsCOMPtr content; result = mContent->QueryInterface(nsIContent::GetIID(), getter_AddRefs(content)); if (NS_SUCCEEDED(result) && content) { PRInt32 nameSpaceID; content->GetNameSpaceID(nameSpaceID); nsAutoString resultValue; result = content->GetAttribute(nameSpaceID, nsHTMLAtoms::readonly, resultValue); if (NS_CONTENT_ATTR_NOT_THERE != result) { flags |= nsIHTMLEditor::eEditorReadonlyMask; aPresShell->SetCaretEnabled(PR_FALSE); } result = content->GetAttribute(nameSpaceID, nsHTMLAtoms::disabled, resultValue); if (NS_CONTENT_ATTR_NOT_THERE != result) { flags |= nsIHTMLEditor::eEditorDisabledMask; aPresShell->SetCaretEnabled(PR_FALSE); nsCOMPtrdoc = do_QueryInterface(aDoc); if (doc) { doc->SetDisplaySelection(PR_FALSE); } } } mEditor->SetFlags(flags); // now add the selection listener nsCOMPtrselection; if (mEditor) { result = mEditor->GetSelection(getter_AddRefs(selection)); if (NS_SUCCEEDED(result) && selection) { result = NS_NewEnderSelectionListener(getter_AddRefs(mSelectionListener)); if (NS_SUCCEEDED(result) && mSelectionListener) { nsCOMPtr eL; eL = do_QueryInterface(mSelectionListener); if (eL) { eL->SetFrame(this); eL->SetPresContext(mFramePresContext); } selection->AddSelectionListener(mSelectionListener); if (NS_FAILED(result)) { //we couldn't add the listener mSelectionListener = do_QueryInterface(nsnull); // null out the listener, it's useless } } } } } } else { result = NS_ERROR_NULL_POINTER; } return result; } NS_IMETHODIMP nsGfxTextControlFrame::InternalContentChanged() { if (!IsInitialized()) { return NS_ERROR_NOT_INITIALIZED; } nsAutoString textValue; // XXX: need to check here if we're an HTML edit field or a text edit field nsString format ("text/plain"); mEditor->OutputToString(textValue, format, 0); if (IsSingleLineTextControl()) { RemoveNewlines(textValue); } SetTextControlFrameState(textValue); // set new text value return NS_OK; } void nsGfxTextControlFrame::RemoveNewlines(nsString &aString) { // strip CR/LF static const char badChars[] = {10, 13, 0}; aString.StripChars(badChars); } NS_IMETHODIMP nsGfxTextControlFrame::List(FILE* out, PRInt32 aIndent) const { IndentBy(out, aIndent); ListTag(out); nsIView* view; GetView(&view); if (nsnull != view) { fprintf(out, " [view=%p]", view); } fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height); if (0 != mState) { fprintf(out, " [state=%08x]", mState); } fputs("<\n", out); // Dump out frames contained in interior web-shell if (mWebShell) { nsCOMPtr viewer; mWebShell->GetContentViewer(getter_AddRefs(viewer)); if (viewer) { nsCOMPtr docv(do_QueryInterface(viewer)); if (docv) { nsCOMPtr cx; docv->GetPresContext(*getter_AddRefs(cx)); if (cx) { nsCOMPtr shell; cx->GetShell(getter_AddRefs(shell)); if (shell) { nsIFrame* rootFrame; shell->GetRootFrame(&rootFrame); if (rootFrame) { rootFrame->List(out, aIndent + 1); nsCOMPtr doc; docv->GetDocument(*getter_AddRefs(doc)); if (doc) { nsCOMPtr rootContent(getter_AddRefs(doc->GetRootContent())); if (rootContent) { rootContent->List(out, aIndent + 1); } } } } } } } } IndentBy(out, aIndent); fputs(">\n", out); return NS_OK; } /******************************************************************************* * EnderFrameLoadingInfo ******************************************************************************/ class EnderFrameLoadingInfo : public nsISupports { public: EnderFrameLoadingInfo(const nsSize& aSize); // nsISupports interface... NS_DECL_ISUPPORTS protected: virtual ~EnderFrameLoadingInfo() {} public: nsSize mFrameSize; }; EnderFrameLoadingInfo::EnderFrameLoadingInfo(const nsSize& aSize) { NS_INIT_REFCNT(); mFrameSize = aSize; } /* * Implementation of ISupports methods... */ NS_IMPL_ISUPPORTS(EnderFrameLoadingInfo,kISupportsIID); /******************************************************************************* * nsEnderDocumentObserver ******************************************************************************/ NS_IMPL_ADDREF(nsEnderDocumentObserver); NS_IMPL_RELEASE(nsEnderDocumentObserver); nsEnderDocumentObserver::nsEnderDocumentObserver() { NS_INIT_REFCNT(); } nsEnderDocumentObserver::~nsEnderDocumentObserver() { } nsresult nsEnderDocumentObserver::QueryInterface(const nsIID& aIID, void** aInstancePtr) { NS_PRECONDITION(nsnull != aInstancePtr, "null pointer"); if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIDocumentObserverIID)) { *aInstancePtr = (void*) ((nsIStreamObserver*)this); AddRef(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { *aInstancePtr = (void*) ((nsISupports*)((nsIDocumentObserver*)this)); AddRef(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsEnderDocumentObserver::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::BeginUpdate(nsIDocument *aDocument) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::EndUpdate(nsIDocument *aDocument) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::BeginLoad(nsIDocument *aDocument) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::EndLoad(nsIDocument *aDocument) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::EndReflow(nsIDocument *aDocument, nsIPresShell* aShell) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::ContentChanged(nsIDocument *aDocument, nsIContent* aContent, nsISupports* aSubContent) { nsresult result = NS_OK; if (mFrame) { result = mFrame->InternalContentChanged(); } return result; } NS_IMETHODIMP nsEnderDocumentObserver::ContentStatesChanged(nsIDocument* aDocument, nsIContent* aContent1, nsIContent* aContent2) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aHint) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer, PRInt32 aNewIndexInContainer) { nsresult result = NS_OK; if (mFrame) { result = mFrame->InternalContentChanged(); } return result; } NS_IMETHODIMP nsEnderDocumentObserver::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { nsresult result = NS_OK; if (mFrame) { result = mFrame->InternalContentChanged(); } return result; } NS_IMETHODIMP nsEnderDocumentObserver::ContentReplaced(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aOldChild, nsIContent* aNewChild, PRInt32 aIndexInContainer) { nsresult result = NS_OK; if (mFrame) { result = mFrame->InternalContentChanged(); } return result; } NS_IMETHODIMP nsEnderDocumentObserver::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { nsresult result = NS_OK; if (mFrame) { result = mFrame->InternalContentChanged(); } return result; } NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::StyleSheetDisabledStateChanged(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, PRBool aDisabled) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleChanged(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule, PRInt32 aHint) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::StyleRuleRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { return NS_OK; } NS_IMETHODIMP nsEnderDocumentObserver::DocumentWillBeDestroyed(nsIDocument *aDocument) { return NS_OK; } /******************************************************************************* * nsEnderKeyListener ******************************************************************************/ nsresult NS_NewEnderKeyListener(nsIDOMKeyListener ** aInstancePtr) { nsEnderKeyListener* it = new nsEnderKeyListener(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(kIDOMKeyListenerIID, (void **) aInstancePtr); } NS_IMPL_ADDREF(nsEnderKeyListener) NS_IMPL_RELEASE(nsEnderKeyListener) nsEnderKeyListener::nsEnderKeyListener() { NS_INIT_REFCNT(); } nsEnderKeyListener::~nsEnderKeyListener() { } NS_IMETHODIMP nsEnderKeyListener::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; if (mFrame) { mFrame->GetContent(getter_AddRefs(mContent)); } return NS_OK; } nsresult nsEnderKeyListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); if (aIID.Equals(kISupportsIID)) { nsIDOMKeyListener *tmp = this; nsISupports *tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventListenerIID)) { *aInstancePtr = (void*)(nsIDOMEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMKeyListenerIID)) { *aInstancePtr = (void*)(nsIDOMKeyListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(nsIEnderEventListener::GetIID())) { *aInstancePtr = (void*)(nsIEnderEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } nsresult nsEnderKeyListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } nsresult nsEnderKeyListener::KeyDown(nsIDOMEvent* aKeyEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aKeyEvent); if (!uiEvent) { //non-key event passed to keydown. bad things. return NS_OK; } if (mFrame && mContent) { // Dispatch the NS_FORM_CHANGE event nsEventStatus status = nsEventStatus_eIgnore; nsKeyEvent event; event.eventStructType = NS_KEY_EVENT; event.widget = nsnull; event.message = NS_KEY_DOWN; event.flags = NS_EVENT_FLAG_INIT; uiEvent->GetKeyCode(&(event.keyCode)); uiEvent->GetCharCode(&(event.charCode)); uiEvent->GetShiftKey(&(event.isShift)); uiEvent->GetCtrlKey(&(event.isControl)); uiEvent->GetAltKey(&(event.isAlt)); // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } nsresult nsEnderKeyListener::KeyUp(nsIDOMEvent* aKeyEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aKeyEvent); if (!uiEvent) { //non-key event passed to keydown. bad things. return NS_OK; } if (mFrame && mContent) { nsEventStatus status = nsEventStatus_eIgnore; nsKeyEvent event; event.eventStructType = NS_KEY_EVENT; event.widget = nsnull; event.message = NS_KEY_UP; event.flags = NS_EVENT_FLAG_INIT; uiEvent->GetKeyCode(&(event.keyCode)); uiEvent->GetCharCode(&(event.charCode)); uiEvent->GetShiftKey(&(event.isShift)); uiEvent->GetCtrlKey(&(event.isControl)); uiEvent->GetAltKey(&(event.isAlt)); // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } nsresult nsEnderKeyListener::KeyPress(nsIDOMEvent* aKeyEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aKeyEvent); if (!uiEvent) { //non-key event passed to keydown. bad things. return NS_OK; } if (mFrame && mContent) { nsEventStatus status = nsEventStatus_eIgnore; nsKeyEvent event; event.eventStructType = NS_KEY_EVENT; event.widget = nsnull; event.message = NS_KEY_PRESS; event.flags = NS_EVENT_FLAG_INIT; uiEvent->GetKeyCode(&(event.keyCode)); uiEvent->GetCharCode(&(event.charCode)); uiEvent->GetShiftKey(&(event.isShift)); uiEvent->GetCtrlKey(&(event.isControl)); uiEvent->GetAltKey(&(event.isAlt)); // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } /******************************************************************************* * nsEnderMouseListener ******************************************************************************/ /* nsresult NS_NewEnderMouseListener(nsIDOMMouseListener ** aInstancePtr) { nsEnderMouseListener* it = new nsEnderMouseListener(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(kIDOMMouseListenerIID, (void **) aInstancePtr); } NS_IMPL_ADDREF(nsEnderMouseListener) NS_IMPL_RELEASE(nsEnderMouseListener) nsEnderMouseListener::nsEnderMouseListener() { NS_INIT_REFCNT(); } nsEnderMouseListener::~nsEnderMouseListener() { } NS_IMETHODIMP nsEnderMouseListener::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; if (mFrame) { mFrame->GetContent(getter_AddRefs(mContent)); } return NS_OK; } nsresult nsEnderMouseListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); if (aIID.Equals(kISupportsIID)) { nsIDOMMouseListener *tmp = this; nsISupports *tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventListenerIID)) { *aInstancePtr = (void*)(nsIDOMEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMMouseListenerIID)) { *aInstancePtr = (void*)(nsIDOMMouseListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(nsIEnderEventListener::GetIID())) { *aInstancePtr = (void*)(nsIEnderEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } nsresult nsEnderMouseListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } nsresult nsEnderMouseListener::MouseDown(nsIDOMEvent* aEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aEvent); if (!uiEvent) { //non-key event passed in. bad things. return NS_OK; } if (mFrame && mContent) { // Dispatch the event nsEventStatus status = nsEventStatus_eIgnore; nsMouseEvent event; event.eventStructType = NS_MOUSE_EVENT; event.widget = nsnull; event.flags = NS_EVENT_FLAG_INIT; uiEvent->GetShiftKey(&(event.isShift)); uiEvent->GetCtrlKey(&(event.isControl)); uiEvent->GetAltKey(&(event.isAlt)); PRUint16 clickCount; uiEvent->GetClickcount(&clickCount); NS_ASSERTION(clickCount>0 && clickCount<3, "bad click count"); if (!(clickCount>0 && clickCount<3)) return NS_OK; event.clickCount = clickCount; PRUint16 button; uiEvent->GetButton(&button); switch(button) { case 1: //XXX: I can't believe there isn't a symbol for this! if (1==clickCount) event.message = NS_MOUSE_LEFT_BUTTON_DOWN; else if (2==clickCount) event.message = NS_MOUSE_LEFT_DOUBLECLICK; break; case 2: //XXX: I can't believe there isn't a symbol for this! if (1==clickCount) event.message = NS_MOUSE_MIDDLE_BUTTON_DOWN; else if (2==clickCount) event.message = NS_MOUSE_MIDDLE_DOUBLECLICK; break; case 3: //XXX: I can't believe there isn't a symbol for this! if (1==clickCount) event.message = NS_MOUSE_RIGHT_BUTTON_DOWN; else if (2==clickCount) event.message = NS_MOUSE_RIGHT_DOUBLECLICK; break; default: NS_ASSERTION(0, "bad button type"); return NS_OK; } // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } nsresult nsEnderMouseListener::MouseUp(nsIDOMEvent* aEvent) { //XXX write me! return NS_OK; } nsresult nsEnderMouseListener::MouseClick(nsIDOMEvent* aEvent) { //XXX write me! return NS_OK; } nsresult nsEnderMouseListener::MouseDblClick(nsIDOMEvent* aEvent) { //XXX write me! return NS_OK; } nsresult nsEnderMouseListener::MouseOver(nsIDOMEvent* aEvent) { //XXX write me! return NS_OK; } nsresult nsEnderMouseListener::MouseOut(nsIDOMEvent* aEvent) { //XXX write me! return NS_OK; } */ /******************************************************************************* * nsEnderFocusListener ******************************************************************************/ nsresult NS_NewEnderFocusListener(nsIDOMFocusListener ** aInstancePtr) { nsEnderFocusListener* it = new nsEnderFocusListener(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(kIDOMFocusListenerIID, (void **) aInstancePtr); } NS_IMPL_ADDREF(nsEnderFocusListener) NS_IMPL_RELEASE(nsEnderFocusListener) nsEnderFocusListener::nsEnderFocusListener() { NS_INIT_REFCNT(); } nsEnderFocusListener::~nsEnderFocusListener() { } NS_IMETHODIMP nsEnderFocusListener::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; if (mFrame) { mFrame->GetContent(getter_AddRefs(mContent)); } return NS_OK; } nsresult nsEnderFocusListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); if (aIID.Equals(kISupportsIID)) { nsIDOMFocusListener *tmp = this; nsISupports *tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventListenerIID)) { *aInstancePtr = (void*)(nsIDOMEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMFocusListenerIID)) { *aInstancePtr = (void*)(nsIDOMFocusListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(nsIEnderEventListener::GetIID())) { *aInstancePtr = (void*)(nsIEnderEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } nsresult nsEnderFocusListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } nsresult nsEnderFocusListener::Focus(nsIDOMEvent* aEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aEvent); if (!uiEvent) { return NS_OK; } if (mFrame && mContent) { mTextValue = ""; mFrame->GetText(&mTextValue, PR_FALSE); // Dispatch the event nsEventStatus status = nsEventStatus_eIgnore; nsGUIEvent event; event.eventStructType = NS_GUI_EVENT; event.widget = nsnull; event.message = NS_FOCUS_CONTENT; event.flags = NS_EVENT_FLAG_INIT; // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } nsresult nsEnderFocusListener::Blur(nsIDOMEvent* aEvent) { nsCOMPtruiEvent; uiEvent = do_QueryInterface(aEvent); if (!uiEvent) { return NS_OK; } if (mFrame && mContent) { nsString currentValue; mFrame->GetText(¤tValue, PR_FALSE); if (PR_FALSE==currentValue.Equals(mTextValue)) { // Dispatch the change event nsEventStatus status = nsEventStatus_eIgnore; nsGUIEvent event; event.eventStructType = NS_GUI_EVENT; event.widget = nsnull; event.message = NS_FORM_CHANGE; event.flags = NS_EVENT_FLAG_INIT; // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } // Dispatch the blur event nsEventStatus status = nsEventStatus_eIgnore; nsGUIEvent event; event.eventStructType = NS_GUI_EVENT; event.widget = nsnull; event.message = NS_BLUR_CONTENT; event.flags = NS_EVENT_FLAG_INIT; // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } /******************************************************************************* * nsEnderSelectionListener ******************************************************************************/ nsresult NS_NewEnderSelectionListener(nsIDOMSelectionListener ** aInstancePtr) { nsEnderSelectionListener* it = new nsEnderSelectionListener(); if (nsnull == it) { return NS_ERROR_OUT_OF_MEMORY; } return it->QueryInterface(nsIDOMSelectionListener::GetIID(), (void **) aInstancePtr); } NS_IMPL_ADDREF(nsEnderSelectionListener) NS_IMPL_RELEASE(nsEnderSelectionListener) nsEnderSelectionListener::nsEnderSelectionListener() { NS_INIT_REFCNT(); } nsEnderSelectionListener::~nsEnderSelectionListener() { } NS_IMETHODIMP nsEnderSelectionListener::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; if (mFrame) { mFrame->GetContent(getter_AddRefs(mContent)); } return NS_OK; } nsresult nsEnderSelectionListener::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kIDOMEventListenerIID, NS_IDOMEVENTLISTENER_IID); if (aIID.Equals(kISupportsIID)) { nsIDOMSelectionListener *tmp = this; nsISupports *tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventListenerIID)) { *aInstancePtr = (void*)(nsIDOMEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(nsIDOMSelectionListener::GetIID())) { *aInstancePtr = (void*)(nsIDOMSelectionListener*)this; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(nsIEnderEventListener::GetIID())) { *aInstancePtr = (void*)(nsIEnderEventListener*)this; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsEnderSelectionListener::NotifySelectionChanged() { if (mFrame && mContent) { // Dispatch the event nsEventStatus status = nsEventStatus_eIgnore; nsGUIEvent event; event.eventStructType = NS_GUI_EVENT; event.widget = nsnull; event.message = NS_FORM_SELECTED; event.flags = NS_EVENT_FLAG_INIT; // Have the content handle the event. mContent->HandleDOMEvent(*mContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); // Now have the frame handle the event mFrame->HandleEvent(*mContext, &event, status); } return NS_OK; } /******************************************************************************* * EnderTempObserver ******************************************************************************/ // XXX temp implementation NS_IMPL_ADDREF(EnderTempObserver); NS_IMPL_RELEASE(EnderTempObserver); EnderTempObserver::~EnderTempObserver() { } nsresult EnderTempObserver::QueryInterface(const nsIID& aIID, void** aInstancePtr) { NS_PRECONDITION(nsnull != aInstancePtr, "null pointer"); if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIStreamObserverIID)) { *aInstancePtr = (void*) ((nsIStreamObserver*)this); AddRef(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { *aInstancePtr = (void*) ((nsISupports*)((nsIDocumentObserver*)this)); AddRef(); return NS_OK; } return NS_NOINTERFACE; } #ifndef NECKO NS_IMETHODIMP EnderTempObserver::OnProgress(nsIURI* aURL, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK; } NS_IMETHODIMP EnderTempObserver::OnStatus(nsIURI* aURL, const PRUnichar* aMsg) { return NS_OK; } #endif NS_IMETHODIMP #ifdef NECKO EnderTempObserver::OnStartRequest(nsIChannel* channel, nsISupports *ctxt) #else EnderTempObserver::OnStartRequest(nsIURI* aURL, const char *aContentType) #endif { return NS_OK; } NS_IMETHODIMP #ifdef NECKO EnderTempObserver::OnStopRequest(nsIChannel* channel, nsISupports *ctxt, nsresult status, const PRUnichar *errorMsg) #else EnderTempObserver::OnStopRequest(nsIURI* aURL, nsresult status, const PRUnichar* aMsg) #endif { if (PR_TRUE==mFirstCall) { mFirstCall = PR_FALSE; if (mFrame) { mFrame->InstallEditor(); } } return NS_OK; } NS_IMETHODIMP EnderTempObserver::SetFrame(nsGfxTextControlFrame *aFrame) { mFrame = aFrame; return NS_OK; }