From da2627ead4787f098a4c1f1075a6eb9c9dcae65c Mon Sep 17 00:00:00 2001 From: "jkeiser%netscape.com" Date: Thu, 7 Mar 2002 20:53:40 +0000 Subject: [PATCH] Move radio buttons to content (bug 108308). r=rods@netscape.com, sr=jst@netscape.com, a=asa@mozilla.org git-svn-id: svn://10.0.0.236/trunk@116076 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/html/content/public/MANIFEST | 2 + .../content/html/content/public/Makefile.in | 3 + .../content/html/content/public/makefile.win | 2 + mozilla/content/html/content/public/nsIForm.h | 148 ++-- .../content/public/nsIRadioControlElement.h | 113 +++ .../html/content/public/nsIRadioVisitor.h | 96 +++ .../html/content/src/nsGenericHTMLElement.cpp | 14 +- .../html/content/src/nsGenericHTMLElement.h | 2 - .../html/content/src/nsHTMLFormElement.cpp | 169 +++- .../html/content/src/nsHTMLInputElement.cpp | 756 ++++++++++++++---- mozilla/layout/forms/nsFormControlFrame.cpp | 25 +- .../forms/nsGfxCheckboxControlFrame.cpp | 107 +-- .../layout/forms/nsGfxCheckboxControlFrame.h | 18 - .../layout/forms/nsGfxRadioControlFrame.cpp | 179 +---- mozilla/layout/forms/nsGfxRadioControlFrame.h | 21 +- mozilla/layout/forms/nsIRadioControlFrame.h | 26 +- .../html/forms/public/nsIRadioControlFrame.h | 26 +- mozilla/layout/html/forms/src/Makefile.in | 1 - mozilla/layout/html/forms/src/makefile.win | 3 +- .../html/forms/src/nsFormControlFrame.cpp | 25 +- mozilla/layout/html/forms/src/nsFormFrame.cpp | 275 ------- mozilla/layout/html/forms/src/nsFormFrame.h | 23 - .../forms/src/nsGfxCheckboxControlFrame.cpp | 107 +-- .../forms/src/nsGfxCheckboxControlFrame.h | 18 - .../html/forms/src/nsGfxRadioControlFrame.cpp | 179 +---- .../html/forms/src/nsGfxRadioControlFrame.h | 21 +- 26 files changed, 1122 insertions(+), 1237 deletions(-) create mode 100644 mozilla/content/html/content/public/nsIRadioControlElement.h create mode 100644 mozilla/content/html/content/public/nsIRadioVisitor.h diff --git a/mozilla/content/html/content/public/MANIFEST b/mozilla/content/html/content/public/MANIFEST index a763d0e78cc..1c7665e5d8d 100644 --- a/mozilla/content/html/content/public/MANIFEST +++ b/mozilla/content/html/content/public/MANIFEST @@ -6,5 +6,7 @@ nsIFormControl.h nsIFormSubmission.h nsILink.h nsIOptionElement.h +nsIRadioControlElement.h +nsIRadioVisitor.h nsIScriptElement.h nsITextControlElement.h diff --git a/mozilla/content/html/content/public/Makefile.in b/mozilla/content/html/content/public/Makefile.in index 418a4eafde4..095b3219dff 100644 --- a/mozilla/content/html/content/public/Makefile.in +++ b/mozilla/content/html/content/public/Makefile.in @@ -38,6 +38,9 @@ EXPORTS = \ nsIForm.h \ nsILink.h \ nsIOptionElement.h \ + nsIRadioControlElement.h \ + nsIRadioVisitor.h \ + nsIScriptElement.h \ nsITextControlElement.h \ nsIScriptElement.h \ nsIFormSubmission.h \ diff --git a/mozilla/content/html/content/public/makefile.win b/mozilla/content/html/content/public/makefile.win index 19c256fcd77..f8b3dc35fe8 100644 --- a/mozilla/content/html/content/public/makefile.win +++ b/mozilla/content/html/content/public/makefile.win @@ -30,6 +30,8 @@ EXPORTS= \ nsIForm.h \ nsILink.h \ nsIOptionElement.h \ + nsIRadioControlElement.h \ + nsIRadioVisitor.h \ nsIScriptElement.h \ nsITextControlElement.h \ nsIFormSubmission.h \ diff --git a/mozilla/content/html/content/public/nsIForm.h b/mozilla/content/html/content/public/nsIForm.h index 549167d7983..c647ab62026 100644 --- a/mozilla/content/html/content/public/nsIForm.h +++ b/mozilla/content/html/content/public/nsIForm.h @@ -43,6 +43,8 @@ class nsIFormControl; class nsISizeOfHandler; +class nsIDOMHTMLInputElement; +class nsIRadioVisitor; #define NS_FORM_METHOD_GET 0 @@ -69,91 +71,129 @@ public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFORM_IID) /** - * Add an element to end of this form's list of elements - * @param aElement the element to add - * @return NS_OK if the element was successfully added - */ + * Add an element to end of this form's list of elements + * + * @param aElement the element to add + * @return NS_OK if the element was successfully added + */ NS_IMETHOD AddElement(nsIFormControl* aElement) = 0; /** - * Add an element to the lookup table mainted by the form. - * We can't fold this method into AddElement() because when - * AddElement() is called, the form control has no - * attributes. The name or id attributes of the form control - * are used as a key into the table. - */ + * Add an element to the lookup table mainted by the form. + * + * We can't fold this method into AddElement() because when + * AddElement() is called, the form control has no + * attributes. The name or id attributes of the form control + * are used as a key into the table. + */ NS_IMETHOD AddElementToTable(nsIFormControl* aElement, const nsAReadableString& aName) = 0; /** - * Get the element at a specified index position - * @param aIndex the index - * @param aElement the element at that index - * @return NS_OK if there was an element at that position, -1 otherwise - */ + * Get the element at a specified index position + * + * @param aIndex the index + * @param aElement the element at that index + * @return NS_OK if there was an element at that position, -1 otherwise + */ NS_IMETHOD GetElementAt(PRInt32 aIndex, nsIFormControl** aElement) const = 0; /** - * Get the number of elements in this form - * @param aCount the number of elements - * @return NS_OK if there was an element at that position, -1 otherwise - */ + * Get the number of elements in this form + * + * @param aCount the number of elements + * @return NS_OK if there was an element at that position, -1 otherwise + */ NS_IMETHOD GetElementCount(PRUint32* aCount) const = 0; /** - * Remove an element from this form's list of elements - * @param aElement the element to remove - * @return NS_OK if the element was successfully removed. - */ + * Remove an element from this form's list of elements + * + * @param aElement the element to remove + * @return NS_OK if the element was successfully removed. + */ NS_IMETHOD RemoveElement(nsIFormControl* aElement) = 0; /** - * Remove an element from the lookup table mainted by the form. - * We can't fold this method into RemoveElement() because when - * RemoveElement() is called it doesn't know if the element is - * removed because the id attribute has changed, or bacause the - * name attribute has changed. - * - * @param aElement the element to remove - * @param aName the name or id of the element to remove - * @return NS_OK if the element was successfully removed. - */ + * Remove an element from the lookup table mainted by the form. + * We can't fold this method into RemoveElement() because when + * RemoveElement() is called it doesn't know if the element is + * removed because the id attribute has changed, or bacause the + * name attribute has changed. + * + * @param aElement the element to remove + * @param aName the name or id of the element to remove + * @return NS_OK if the element was successfully removed. + */ NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement, const nsAReadableString& aName) = 0; /** - * Resolve a name in the scope of the form object, this means find - * form controls in this form with the correct value in the name - * attribute. - * - * @param aElement the element to remove - * @param aName the name or id of the element to remove - * @return NS_OK if the element was successfully removed. - */ + * Resolve a name in the scope of the form object, this means find + * form controls in this form with the correct value in the name + * attribute. + * + * @param aElement the element to remove + * @param aName the name or id of the element to remove + * @return NS_OK if the element was successfully removed. + */ NS_IMETHOD ResolveName(const nsAReadableString& aName, nsISupports **aResult) = 0; /** - * Get the index of the given control within this form. - */ + * Get the index of the given control within this form. + */ NS_IMETHOD IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex) = 0; /** - * This is a flag set on the form by nsHTMLContentSink::DemoteForm() - * to let form controls know that children of the form are being moved - * around needlessly (which is what DemoteForm() does). - * - * Form controls query this so that they can avoid changing their form when - * the inevitable SetParent() occurs. This prevents problems with indexing - * in DemoteForm() itself as well as other problems that arise from form - * controls setting their form to null, even temporarily. - */ + * This is a flag set on the form by nsHTMLContentSink::DemoteForm() + * to let form controls know that children of the form are being moved + * around needlessly (which is what DemoteForm() does). + * + * Form controls query this so that they can avoid changing their form when + * the inevitable SetParent() occurs. This prevents problems with indexing + * in DemoteForm() itself as well as other problems that arise from form + * controls setting their form to null, even temporarily. + * + * @param aDemotingForm whether the current form is being demoted. + */ NS_IMETHOD SetDemotingForm(PRBool aDemotingForm) = 0; /** - * Test whether this form is currently being demoted - */ + * Test whether this form is currently being demoted + * + * @param aDemotingForm a boolean to hold whether the current form is being + * demoted. + */ NS_IMETHOD IsDemotingForm(PRBool* aDemotingForm) = 0; + + /** + * Set the currently selected radio button in a group + * + * @param aName the radio group to set the button in + * @param aRadio the radio button to be returned + */ + NS_IMETHOD SetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement* aRadio) = 0; + + /** + * Get the currently selected radio button in a group + * + * @param aName the radio group to get the radio button in + * @param aRadio the radio button to be returned + */ + NS_IMETHOD GetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement** aRadio) = 0; + + /** + * Walk over the radios in a group and call Visit() on the visitor. + * + * @param aName the radio group to walk + * @param aVisitor the visitor to call Visit() on + */ + NS_IMETHOD WalkRadioGroup(const nsAString& aName, + nsIRadioVisitor* aVisitor) = 0; + }; #endif /* nsIForm_h___ */ diff --git a/mozilla/content/html/content/public/nsIRadioControlElement.h b/mozilla/content/html/content/public/nsIRadioControlElement.h new file mode 100644 index 00000000000..288b2ee546a --- /dev/null +++ b/mozilla/content/html/content/public/nsIRadioControlElement.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * John B. Keiser + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsIRadioControlElement_h___ +#define nsIRadioControlElement_h___ + +#include "nsISupports.h" +class nsAString; +class nsIForm; + +// IID for the nsIRadioControl interface +#define NS_IRADIOCONTROLELEMENT_IID \ +{ 0x647dff84, 0x1dd2, 0x11b2, \ + { 0x95, 0xcf, 0xe5, 0x01, 0xa8, 0x54, 0xa6, 0x40 } } + +/** + * This interface is used for the text control frame to store its value away + * into the content. + */ +class nsIRadioControlElement : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRADIOCONTROLELEMENT_IID) + + /** + * Set the radio button checked, but don't do any extra checks and don't + * trigger "value changed". This is for experts only. Do not try this + * at home. Well, OK, try it at home, but not late at night. + */ + NS_IMETHOD RadioSetChecked() = 0; + + /** + * Let this radio button know that the radio group's "checked" property has + * been changed by JavaScript or by the user + * + * @param aCheckedChanged whether the checked property has been changed. + * @param aOnlyOnThisRadioButton set to TRUE to only set the property only on + * the radio button in question; otherwise it will set the property on + * all other radio buttons in its group just to be sure they are + * consistent. + */ + NS_IMETHOD SetCheckedChangedInternal(PRBool aCheckedChanged) = 0; + + /** + * Let an entire radio group know that it's "checked" property has been + * changed by JS or by the user (calls SetCheckedChangedInternal multiple + * times via a visitor) + * + * @param aCheckedChanged whether the checked property has been changed. + */ + NS_IMETHOD SetCheckedChanged(PRBool aCheckedChanged) = 0; + + /** + * Find out whether this radio group's "checked" property has been changed by + * JavaScript or by the user + * + * @param aCheckedChanged out param, whether the checked property has been + * changed. + */ + NS_IMETHOD GetCheckedChanged(PRBool* aCheckedChanged) = 0; + + /** + * Let this radio button know that state has been changed such that it has + * been added to a group. + */ + NS_IMETHOD AddedToRadioGroup() = 0; + + /** + * Let this radio button know that state has been changed such that it has + * been *removed* from a group (and tell it which group). + * @param aForm the form it was removed from + * @param aName the name of the group it was removed from (nsnull to detect + * using GetName()) + */ + NS_IMETHOD RemovedFromRadioGroup(nsIForm* aForm, nsAString* aName) = 0; +}; + +#endif // nsIRadioControlElement_h___ diff --git a/mozilla/content/html/content/public/nsIRadioVisitor.h b/mozilla/content/html/content/public/nsIRadioVisitor.h new file mode 100644 index 00000000000..daf33c8163e --- /dev/null +++ b/mozilla/content/html/content/public/nsIRadioVisitor.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * John B. Keiser + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsIRadioVisitor_h___ +#define nsIRadioVisitor_h___ + +#include "nsISupports.h" +class nsIFormControl; + +// IID for the nsIRadioControl interface +#define NS_IRADIOVISITOR_IID \ +{ 0xd3494bd2, 0x1dd1, 0x11b2, \ + { 0xbe, 0x86, 0xb5, 0x08, 0xc8, 0x71, 0xd7, 0xc5 } } + +/** + * This interface is used for the text control frame to store its value away + * into the content. + */ +class nsIRadioVisitor : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRADIOVISITOR_IID) + + /** + * Visit a node in the tree. This is meant to be called on all radios in a + * group, sequentially. (Each radio group implementor may define + * sequentially in their own way, it just has to be the same every time.) + * Currently all radio groups are ordered in the order they appear in the + * document. Radio group implementors should honor the aStop parameter and + * stop iterating over form controls when Visit() returns true there. + * + * @param aRadio the radio button in question (must be nsnull and QI'able to + * nsIRadioControlElement) + * @param aStop whether or not to stop iterating (out-param) + */ + NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop) = 0; +}; + +/** + * This visitor sets CheckedChanged on all elements it finds. + * + * @param aVisitor the visitor (out param) + * @param aCheckedChanged the value of CheckedChanged to set on all elements + */ +extern NS_METHOD NS_GetRadioSetCheckedChangedVisitor(PRBool aCheckedChanged, + nsIRadioVisitor** aVisitor); + +/** + * This visitor will take the boolean you're pointing at and put + * aCheckedChanged into it. If the visitor is never called, aCheckedChanged + * will of course not change. + * + * @param aVisitor the visitor (out param) + * @param aCheckedChanged the boolean to put CheckedChanged into + * @param aExcludeElement the element + */ +extern NS_METHOD NS_GetRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged, + nsIFormControl* aExcludeElement, + nsIRadioVisitor** aVisitor); + +#endif // nsIRadioVisitor_h___ diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp index e407a7c13cd..288dc8648bf 100644 --- a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp +++ b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp @@ -4081,12 +4081,6 @@ nsGenericHTMLContainerFormElement::SetForm(nsIDOMHTMLFormElement* aForm, return NS_OK; } -NS_IMETHODIMP -nsGenericHTMLContainerFormElement::Init() -{ - return NS_OK; -} - NS_IMETHODIMP nsGenericHTMLContainerFormElement::GetForm(nsIDOMHTMLFormElement** aForm) { @@ -4329,12 +4323,6 @@ nsGenericHTMLLeafFormElement::SetForm(nsIDOMHTMLFormElement* aForm, return NS_OK; } -NS_IMETHODIMP -nsGenericHTMLLeafFormElement::Init() -{ - return NS_OK; -} - NS_IMETHODIMP nsGenericHTMLLeafFormElement::GetForm(nsIDOMHTMLFormElement** aForm) { @@ -4731,6 +4719,8 @@ nsGenericHTMLElement::GetHostnameFromHrefString(const nsAReadableString& aHref, if (NS_FAILED(rv)) return rv; + CopyASCIItoUCS2(host, aHostname); + aHostname.Assign(NS_ConvertUTF8toUCS2(host)); return NS_OK; } diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.h b/mozilla/content/html/content/src/nsGenericHTMLElement.h index 14dff5d36f5..9ce15966891 100644 --- a/mozilla/content/html/content/src/nsGenericHTMLElement.h +++ b/mozilla/content/html/content/src/nsGenericHTMLElement.h @@ -589,7 +589,6 @@ public: NS_IMETHOD GetForm(nsIDOMHTMLFormElement** aForm); NS_IMETHOD SetForm(nsIDOMHTMLFormElement* aForm, PRBool aRemoveFromForm = PR_TRUE); - NS_IMETHOD Init(); NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState) { return NS_OK; @@ -639,7 +638,6 @@ public: NS_IMETHOD GetForm(nsIDOMHTMLFormElement** aForm); NS_IMETHOD SetForm(nsIDOMHTMLFormElement* aForm, PRBool aRemoveFromForm = PR_TRUE); - NS_IMETHOD Init(); NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState) { return NS_OK; diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp index 6400b63f45c..06c693f6e05 100644 --- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp @@ -61,6 +61,7 @@ #include "nsDOMError.h" #include "nsContentUtils.h" #include "nsHashtable.h" +#include "nsDoubleHashtable.h" #include "nsContentList.h" #include "nsGUIEvent.h" @@ -75,6 +76,10 @@ #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" +// radio buttons +#include "nsIDOMHTMLInputElement.h" +#include "nsIRadioControlElement.h" +#include "nsIRadioVisitor.h" static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16; @@ -88,9 +93,15 @@ class nsHTMLFormElement : public nsGenericHTMLContainerElement, public nsIForm { public: - nsHTMLFormElement(); + nsHTMLFormElement() : + mGeneratingSubmit(PR_FALSE), + mGeneratingReset(PR_FALSE), + mDemotingForm(PR_FALSE) { }; + virtual ~nsHTMLFormElement(); + virtual nsresult Init(nsINodeInfo* aNodeInfo); + // nsISupports NS_DECL_ISUPPORTS_INHERITED @@ -119,10 +130,15 @@ public: NS_IMETHOD RemoveElementFromTable(nsIFormControl* aElement, const nsAReadableString& aName); NS_IMETHOD ResolveName(const nsAReadableString& aName, - nsISupports **aReturn); + nsISupports** aReturn); NS_IMETHOD IndexOfControl(nsIFormControl* aControl, PRInt32* aIndex); NS_IMETHOD SetDemotingForm(PRBool aDemotingForm); NS_IMETHOD IsDemotingForm(PRBool* aDemotingForm); + NS_IMETHOD SetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement* aRadio); + NS_IMETHOD GetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement** aRadio); + NS_IMETHOD WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor); #ifdef DEBUG NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const; @@ -138,6 +154,7 @@ public: NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus); + protected: nsresult DoSubmitOrReset(nsIPresContext* aPresContext, nsEvent* aEvent, @@ -196,6 +213,7 @@ protected: // Data members // nsFormControlList *mControls; + nsDoubleHashtableStringSupports mSelectedRadioButtons; PRPackedBool mGeneratingSubmit; PRPackedBool mGeneratingReset; PRPackedBool mDemotingForm; @@ -335,14 +353,22 @@ NS_NewHTMLFormElement(nsIHTMLContent** aInstancePtrResult, } -nsHTMLFormElement::nsHTMLFormElement(): - mGeneratingSubmit(PR_FALSE), - mGeneratingReset(PR_FALSE), - mDemotingForm(PR_FALSE) +nsresult +nsHTMLFormElement::Init(nsINodeInfo *aNodeInfo) { - mControls = new nsFormControlList(this); + nsresult rv = nsGenericHTMLElement::Init(aNodeInfo); + NS_ENSURE_SUCCESS(rv, rv); - NS_IF_ADDREF(mControls); + mControls = new nsFormControlList(this); + if (!mControls) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(mControls); + + rv = mSelectedRadioButtons.Init(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; } nsHTMLFormElement::~nsHTMLFormElement() @@ -990,6 +1016,17 @@ nsHTMLFormElement::AddElement(nsIFormControl* aChild) } } + // + // Notify the radio button it's been added to a group + // + PRInt32 type; + aChild->GetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + nsCOMPtr radio = do_QueryInterface(aChild); + nsresult rv = radio->AddedToRadioGroup(); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; } @@ -1016,6 +1053,17 @@ nsHTMLFormElement::RemoveElement(nsIFormControl* aChild) mControls->mNotInElements->Remove(&key); } + // + // Remove it from the radio group if it's a radio button + // + PRInt32 type; + aChild->GetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + nsCOMPtr radio = do_QueryInterface(aChild); + nsresult rv = radio->RemovedFromRadioGroup(this, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; } @@ -1083,8 +1131,111 @@ nsHTMLFormElement::IsDemotingForm(PRBool* aDemotingForm) return NS_OK; } -//---------------------------------------------------------------------- +NS_IMETHODIMP +nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement* aRadio) +{ + return mSelectedRadioButtons.Put(aName, (nsISupports*)aRadio); +} +NS_IMETHODIMP +nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName, + nsIDOMHTMLInputElement** aRadio) +{ + *aRadio = (nsIDOMHTMLInputElement*)mSelectedRadioButtons.Get(aName).get(); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLFormElement::WalkRadioGroup(const nsAString& aName, + nsIRadioVisitor* aVisitor) +{ + nsresult rv = NS_OK; + + PRBool stopIterating = PR_FALSE; + + if (aName.IsEmpty()) { + // + // XXX If the name is empty, it's not stored in the control list. There + // *must* be a more efficient way to do this. + // + nsCOMPtr control; + PRUint32 len = 0; + GetElementCount(&len); + for (PRUint32 i=0; iGetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + nsCOMPtr elem(do_QueryInterface(control)); + if (elem) { + // + // XXX This is a particularly frivolous string copy just to determine + // if the string is empty or not + // + nsAutoString name; + elem->GetName(name); + if (name.IsEmpty()) { + aVisitor->Visit(control, &stopIterating); + if (stopIterating) { + break; + } + } + } + } + } + } else { + // + // Get the control / list of controls from the form using form["name"] + // + nsCOMPtr item; + rv = ResolveName(aName, getter_AddRefs(item)); + + if (item) { + // + // If it's just a lone radio button, then select it. + // + nsCOMPtr formControl(do_QueryInterface(item)); + if (formControl) { + PRInt32 type; + formControl->GetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + aVisitor->Visit(formControl, &stopIterating); + } + } else { + // + // If it's a list, we have to find the first non-disabled one and + // select it. + // + nsCOMPtr nodeList(do_QueryInterface(item)); + if (nodeList) { + PRUint32 length = 0; + nodeList->GetLength(&length); + for (PRUint32 i=0; i node; + nodeList->Item(i, getter_AddRefs(node)); + nsCOMPtr formControl(do_QueryInterface(node)); + if (formControl) { + PRInt32 type; + formControl->GetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + aVisitor->Visit(formControl, &stopIterating); + if (stopIterating) { + break; + } + } + } + } + } + } + } + } + + return rv; +} + + +//---------------------------------------------------------------------- // nsFormControlList implementation, this could go away if there were // a lightweight collection implementation somewhere diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp index 5d69d74bab8..cc98af9e675 100644 --- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp @@ -40,6 +40,9 @@ #include "nsIDOMHTMLInputElement.h" #include "nsIDOMNSHTMLInputElement.h" #include "nsITextControlElement.h" +#include "nsIRadioControlElement.h" +#include "nsIRadioVisitor.h" + #include "nsIControllers.h" #include "nsIEditorController.h" #include "nsIFocusController.h" @@ -61,6 +64,7 @@ #include "nsIForm.h" #include "nsIFormSubmission.h" #include "nsIGfxTextControlFrame.h" +#include "nsIRadioControlFrame.h" #include "nsIDocument.h" #include "nsIPresShell.h" #include "nsIFormControlFrame.h" @@ -80,7 +84,6 @@ #include "nsIDOMNodeList.h" #include "nsIDOMHTMLCollection.h" #include "nsICheckboxControlFrame.h" -#include "nsIRadioControlFrame.h" #include "nsIFormManager.h" #include "nsIImageControlFrame.h" #include "nsLinebreakConverter.h" //to strip out carriage returns @@ -125,7 +128,8 @@ typedef nsIGfxTextControlFrame2 textControlPlace; class nsHTMLInputElement : public nsGenericHTMLLeafFormElement, public nsIDOMHTMLInputElement, public nsIDOMNSHTMLInputElement, - public nsITextControlElement + public nsITextControlElement, + public nsIRadioControlElement { public: nsHTMLInputElement(); @@ -150,6 +154,8 @@ public: NS_DECL_NSIDOMNSHTMLINPUTELEMENT // Overriden nsIFormControl methods + NS_IMETHOD SetForm(nsIDOMHTMLFormElement* aForm, + PRBool aRemoveFromForm = PR_TRUE); NS_IMETHOD GetType(PRInt32* aType); NS_IMETHOD Reset(); NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission, @@ -179,21 +185,12 @@ public: NS_IMETHOD SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAReadableString& aValue, PRBool aNotify) { + BeforeSetAttr(aNameSpaceID, aName, &aValue, aNotify); + nsresult rv = nsGenericHTMLLeafFormElement::SetAttr(aNameSpaceID, aName, aValue, aNotify); - if (aName == nsHTMLAtoms::value - && !GET_BOOLBIT(mBitField, BF_VALUE_CHANGED) - && (mType == NS_FORM_INPUT_TEXT - || mType == NS_FORM_INPUT_PASSWORD - || mType == NS_FORM_INPUT_FILE - || mType == NS_FORM_INPUT_HIDDEN)) { - Reset(); - } - if (aName == nsHTMLAtoms::checked - && !GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED) - && (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO)) { - Reset(); - } + + AfterSetAttr(aNameSpaceID, aName, &aValue, aNotify); return rv; } NS_IMETHOD SetAttr(nsINodeInfo* aNodeInfo, const nsAReadableString& aValue, @@ -204,17 +201,13 @@ public: NS_IMETHOD UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify) { + BeforeSetAttr(aNameSpaceID, aAttribute, nsnull, aNotify); + nsresult rv = nsGenericHTMLLeafElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify); - if (aAttribute == nsHTMLAtoms::value - && !GET_BOOLBIT(mBitField, BF_VALUE_CHANGED)) { - Reset(); - } - if (aAttribute == nsHTMLAtoms::checked - && !GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED)) { - Reset(); - } + + AfterSetAttr(aNameSpaceID, aAttribute, nsnull, aNotify); return rv; } @@ -222,6 +215,14 @@ public: NS_IMETHOD SetValueGuaranteed(const nsAString& aValue, nsIGfxTextControlFrame2* aFrame); NS_IMETHOD SetValueChanged(PRBool aValueChanged); + // nsIRadioControlElement + NS_IMETHOD RadioSetChecked(); + NS_IMETHOD SetCheckedChanged(PRBool aCheckedChanged); + NS_IMETHOD SetCheckedChangedInternal(PRBool aCheckedChanged); + NS_IMETHOD GetCheckedChanged(PRBool* aCheckedChanged); + NS_IMETHOD AddedToRadioGroup(); + NS_IMETHOD RemovedFromRadioGroup(nsIForm* aForm, nsAString* aName); + protected: // Helper method void SetPresStateChecked(nsIHTMLContent * aHTMLContent, PRBool aValue); @@ -237,6 +238,17 @@ protected: const nsAReadableString& aEventType); #endif + /** + * Called when an attribute is about to be changed + */ + void BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAReadableString* aValue, PRBool aNotify); + /** + * Called when an attribute has just been changed + */ + void AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAReadableString* aValue, PRBool aNotify); + void SelectAll(nsIPresContext* aPresContext); PRBool IsImage() const { @@ -249,6 +261,10 @@ protected: void FireOnChange(); + nsresult VisitGroup(nsIRadioVisitor* aVisitor); + + nsresult SetCheckedInternal(PRBool aValue); + static nsresult GetContentType(const char* aPathName, char** aContentType); nsCOMPtr mControllers; @@ -259,6 +275,34 @@ protected: char* mValue; }; +// +// Visitor declarations +// + +/** + * This visitor sets CheckedChanged on all elements it finds. + * + * @param aCheckedChanged the value of CheckedChanged to set on all elements + * @param aVisitor the visitor (out param) + */ +NS_METHOD NS_GetRadioSetCheckedChangedVisitor(PRBool aCheckedChanged, + nsIRadioVisitor** aVisitor); + +/** + * This visitor will take the boolean you're pointing at and put + * aCheckedChanged into it. If the visitor is never called, aCheckedChanged + * will of course not change. + * + * @param aCheckedChanged the boolean to put CheckedChanged into + * @param aExcludeElement an element to exclude--i.e. don't get checked changed + * on this element + * @param aVisitor the visitor (out param) + */ +NS_METHOD NS_GetRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged, + nsIFormControl* aExcludeElement, + nsIRadioVisitor** aVisitor); + + // // construction, destruction // @@ -320,6 +364,7 @@ NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLInputElement, NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLInputElement) NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLInputElement) NS_INTERFACE_MAP_ENTRY(nsITextControlElement) + NS_INTERFACE_MAP_ENTRY(nsIRadioControlElement) NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLInputElement) NS_HTML_CONTENT_INTERFACE_MAP_END @@ -355,6 +400,57 @@ nsHTMLInputElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) } +void +nsHTMLInputElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAReadableString* aValue, + PRBool aNotify) +{ + if (aName == nsHTMLAtoms::name && + mType == NS_FORM_INPUT_RADIO) { + // XXX Because we are not doing anything that assumes the radio button has + // actually had its name changed at this point, we can get away with + // calling this before the name has changed (and gain in performance by not + // grabbing the old name every time the name is changed). + RemovedFromRadioGroup(mForm, nsnull); + } +} + +void +nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAReadableString* aValue, + PRBool aNotify) +{ + // + // When name changes, radio moves to a different group + // (type changes are handled in the form itself currently) + // + if (aName == nsHTMLAtoms::name && + mType == NS_FORM_INPUT_RADIO) { + AddedToRadioGroup(); + } + + // + // Some elements have to change their value when the value and checked + // attributes change (but they only do so when ValueChanged() and + // CheckedChanged() are false--i.e. the value has not been changed by the + // user or by JS) + // + if (aName == nsHTMLAtoms::value && + !GET_BOOLBIT(mBitField, BF_VALUE_CHANGED) && + (mType == NS_FORM_INPUT_TEXT || + mType == NS_FORM_INPUT_PASSWORD || + mType == NS_FORM_INPUT_FILE || + mType == NS_FORM_INPUT_HIDDEN)) { + Reset(); + } + if (aName == nsHTMLAtoms::checked && + !GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED) && + (mType == NS_FORM_INPUT_CHECKBOX || + mType == NS_FORM_INPUT_RADIO)) { + Reset(); + } +} + NS_IMETHODIMP nsHTMLInputElement::GetForm(nsIDOMHTMLFormElement** aForm) { @@ -377,7 +473,7 @@ nsHTMLInputElement::SetDefaultValue(const nsAReadableString& aDefaultValue) NS_IMETHODIMP nsHTMLInputElement::GetDefaultChecked(PRBool* aDefaultChecked) { - nsHTMLValue val; + nsHTMLValue val; nsresult rv; rv = GetHTMLAttribute(nsHTMLAtoms::checked, val); @@ -591,42 +687,7 @@ nsHTMLInputElement::SetValueChanged(PRBool aValueChanged) NS_IMETHODIMP nsHTMLInputElement::GetChecked(PRBool* aChecked) { - PRInt32 type; - GetType(&type); - if (type == NS_FORM_INPUT_RADIO) { - nsAutoString value(NS_LITERAL_STRING("0")); - - // No need to flush here, if there's no frame created for this input - // yet, we know our own checked state. - nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE); - - if (formControlFrame) { - formControlFrame->GetProperty(nsHTMLAtoms::checked, value); - } - else { - // Retrieve the presentation state instead. - nsCOMPtr presState; - GetPrimaryPresState(this, getter_AddRefs(presState)); - - // Obtain the value property from the presentation state. - if (presState) { - presState->GetStateProperty(NS_LITERAL_STRING("checked"), value); - } - } - - if (value.Equals(NS_LITERAL_STRING("1"))) { - *aChecked = PR_TRUE; - } else { - *aChecked = PR_FALSE; - } - } else { - if (!GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED)) { - GetDefaultChecked(aChecked); - } else { - *aChecked = GET_BOOLBIT(mBitField, BF_CHECKED); - } - } - + *aChecked = GET_BOOLBIT(mBitField, BF_CHECKED); return NS_OK; } @@ -644,15 +705,143 @@ nsHTMLInputElement::SetPresStateChecked(nsIHTMLContent * aHTMLContent, } } -NS_IMETHODIMP -nsHTMLInputElement::SetChecked(PRBool aValue) +NS_IMETHODIMP +nsHTMLInputElement::SetCheckedChanged(PRBool aCheckedChanged) { - SET_BOOLBIT(mBitField, BF_CHECKED_CHANGED, PR_TRUE); + if (mType == NS_FORM_INPUT_RADIO) { + if (GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED) != aCheckedChanged) { + nsCOMPtr visitor; + NS_GetRadioSetCheckedChangedVisitor(aCheckedChanged, + getter_AddRefs(visitor)); + VisitGroup(visitor); + } + } else { + SetCheckedChangedInternal(aCheckedChanged); + } + return NS_OK; +} +NS_IMETHODIMP +nsHTMLInputElement::SetCheckedChangedInternal(PRBool aCheckedChanged) +{ + SET_BOOLBIT(mBitField, BF_CHECKED_CHANGED, aCheckedChanged); + return NS_OK; +} + + +NS_IMETHODIMP +nsHTMLInputElement::GetCheckedChanged(PRBool* aCheckedChanged) +{ + *aCheckedChanged = GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED); + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLInputElement::SetChecked(PRBool aChecked) +{ + nsresult rv = NS_OK; + + // + // If the user or JS attempts to set checked, whether it actually changes the + // value or not, we say the value was changed so that defaultValue don't + // affect it no more. + // + SetCheckedChanged(PR_TRUE); + + // + // Don't do anything if we're not changing whether it's checked (it would + // screw up state actually, especially when you are setting radio button to + // false) + // + PRBool checked = PR_FALSE; + GetChecked(&checked); + if (checked == aChecked) { + return NS_OK; + } + + // + // Set checked + // + PRInt32 type; + GetType(&type); + if (type == NS_FORM_INPUT_RADIO) { + // + // For radio button, we need to do some extra fun stuff + // + if (aChecked) { + rv = RadioSetChecked(); + } else { + rv = SetCheckedInternal(PR_FALSE); + if (mForm) { + nsAutoString name; + GetName(name); + mForm->SetCurrentRadioButton(name, nsnull); + } + } + } else { + rv = SetCheckedInternal(aChecked); + } + + return rv; +} + +NS_IMETHODIMP +nsHTMLInputElement::RadioSetChecked() +{ + nsresult rv = NS_OK; + + // + // Find the selected radio button so we can deselect it + // + nsCOMPtr currentlySelected; + nsAutoString name; + if (mForm) { + // This is only initialized in if (mForm) for use in later if (mForm)s + GetName(name); + mForm->GetCurrentRadioButton(name, getter_AddRefs(currentlySelected)); + } + + // + // Deselect the currently selected radio button + // + if (currentlySelected) { + rv = NS_STATIC_CAST(nsHTMLInputElement*, + NS_STATIC_CAST(nsIDOMHTMLInputElement*, currentlySelected) + )->SetCheckedInternal(PR_FALSE); + } + + // + // Actually select this one + // + if (NS_SUCCEEDED(rv)) { + rv = SetCheckedInternal(PR_TRUE); + } + + // + // Let the form know that we are now the One True Radio Button + // + if (mForm && NS_SUCCEEDED(rv)) { + rv = mForm->SetCurrentRadioButton(name, NS_STATIC_CAST(nsIDOMHTMLInputElement*, this)); + } + + return rv; +} + +NS_IMETHODIMP +nsHTMLInputElement::SetForm(nsIDOMHTMLFormElement* aForm, + PRBool aRemoveFromForm) +{ + return nsGenericHTMLLeafFormElement::SetForm(aForm, aRemoveFromForm); +} + + +nsresult +nsHTMLInputElement::SetCheckedInternal(PRBool aChecked) +{ // // Set the value // - SET_BOOLBIT(mBitField, BF_CHECKED, aValue); + SET_BOOLBIT(mBitField, BF_CHECKED, aChecked); // // Notify the frame @@ -660,10 +849,11 @@ nsHTMLInputElement::SetChecked(PRBool aValue) // No need to flush here since if there's no frame for this input at // this point we don't care about creating one, once it's created // the frame will do the right thing. + // PRInt32 type; GetType(&type); - nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE); + nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE); if (formControlFrame) { nsCOMPtr presContext; GetPresContext(this, getter_AddRefs(presContext)); @@ -672,63 +862,21 @@ nsHTMLInputElement::SetChecked(PRBool aValue) nsICheckboxControlFrame* checkboxFrame = nsnull; CallQueryInterface(formControlFrame, &checkboxFrame); if (checkboxFrame) { - checkboxFrame->OnChecked(presContext, aValue); + checkboxFrame->OnChecked(presContext, aChecked); } + // These are frames. You don't refcount frames. Silly wabbit. } else if (type == NS_FORM_INPUT_RADIO) { - // the value is being toggled - nsAutoString val; val.AssignWithConversion(aValue ? "1" : "0"); - - formControlFrame->SetProperty(presContext, nsHTMLAtoms::checked, val); - } - } - else if (type == NS_FORM_INPUT_RADIO) { - SetPresStateChecked(this, aValue); - - nsAutoString name; - GetName(name); - - nsCOMPtr formElement; - if (NS_SUCCEEDED(GetForm(getter_AddRefs(formElement))) && formElement) { - nsCOMPtr controls; - - nsresult rv = formElement->GetElements(getter_AddRefs(controls)); - - if (controls) { - PRUint32 numControls; - - controls->GetLength(&numControls); - - for (PRUint32 i = 0; i < numControls; i++) { - nsCOMPtr elementNode; - - controls->Item(i, getter_AddRefs(elementNode)); - - if (elementNode) { - nsCOMPtr - inputElement(do_QueryInterface(elementNode)); - - if (inputElement && inputElement.get() != - NS_STATIC_CAST(nsIDOMHTMLInputElement *, this)) { - nsAutoString childName; - - rv = inputElement->GetName(childName); - - if (NS_SUCCEEDED(rv)) { - if (name == childName) { - nsCOMPtr - htmlContent(do_QueryInterface(inputElement)); - - SetPresStateChecked(htmlContent, PR_FALSE); - } - } - } - } - } + nsIRadioControlFrame* radioFrame = nsnull; + CallQueryInterface(formControlFrame, &radioFrame); + if (radioFrame) { + radioFrame->OnChecked(presContext, aChecked); } + // You don't refcount frames. } } + // special attr for XBL form controls else if (type == NS_FORM_INPUT_CHECKBOX) { - if (GET_BOOLBIT(mBitField, BF_CHECKED)) + if (aChecked) SetAttr(kNameSpaceID_None, nsHTMLAtoms::inputCheckedPseudo, NS_LITERAL_STRING(""), PR_TRUE); else @@ -1152,12 +1300,15 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext, // Start by remember the original value and for radio buttons we // must get the currently selected radiobtn. So we go get the // content instead of the frame - PRBool orginalCheckedValue = PR_FALSE; + // + PRBool originalCheckedValue = PR_FALSE; PRBool checkWasSet = PR_FALSE; - nsCOMPtr selectedRadiobtn; + + nsCOMPtr selectedRadioButton; + if (!(aFlags & NS_EVENT_FLAG_CAPTURE) && aEvent->message == NS_MOUSE_LEFT_CLICK) { - GetChecked(&orginalCheckedValue); + GetChecked(&originalCheckedValue); checkWasSet = PR_TRUE; switch(type) { case NS_FORM_INPUT_CHECKBOX: @@ -1168,30 +1319,32 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext, FireOnChange(); // Fire an event to notify accessibility #ifdef ACCESSIBILITY - FireEventForAccessibility( aPresContext, NS_LITERAL_STRING("CheckboxStateChange")); + FireEventForAccessibility(aPresContext, + NS_LITERAL_STRING("CheckboxStateChange")); #endif } break; case NS_FORM_INPUT_RADIO: { - // Get the currently selected button from the radio group - // we get access to that via the nsIRadioControlFrame interface - // because the current grouping is kept in the frame. - if (formControlFrame) { - nsIRadioControlFrame * rb = nsnull; - CallQueryInterface(formControlFrame, &rb); - - if (rb) { - rb->GetRadioGroupSelectedContent(getter_AddRefs(selectedRadiobtn)); - } + if (mForm) { + nsAutoString name; + GetName(name); + mForm->GetCurrentRadioButton(name, + getter_AddRefs(selectedRadioButton)); + } + + PRBool checked; + GetChecked(&checked); + if (!checked) { + SetChecked(PR_TRUE); + FireOnChange(); } - SetChecked(PR_TRUE); - FireOnChange(); // Fire an event to notify accessibility #ifdef ACCESSIBILITY - if ( selectedRadiobtn != this ) { - FireEventForAccessibility( aPresContext, NS_LITERAL_STRING("RadioStateChange")); + if (selectedRadioButton != this) { + FireEventForAccessibility(aPresContext, + NS_LITERAL_STRING("RadioStateChange")); } #endif } @@ -1228,13 +1381,10 @@ nsHTMLInputElement::HandleDOMEvent(nsIPresContext* aPresContext, // if it was cancelled and a radio button, then set the old // selected btn to TRUE. if it is a checkbox then set it to its // original value - if (selectedRadiobtn) { - nsCOMPtr inputElement(do_QueryInterface(selectedRadiobtn)); - if (inputElement) { - inputElement->SetChecked(PR_TRUE); - } - } else { - SetChecked(orginalCheckedValue); + if (selectedRadioButton) { + selectedRadioButton->SetChecked(PR_TRUE); + } else if (type == NS_FORM_INPUT_CHECKBOX) { + SetChecked(originalCheckedValue); } } @@ -1600,12 +1750,9 @@ nsHTMLInputElement::GetAttributeMappingFunction(nsMapRuleToAttributesFunc& aMapR NS_IMETHODIMP nsHTMLInputElement::GetType(PRInt32* aType) { - if (aType) { - *aType = mType; - return NS_OK; - } else { - return NS_FORM_NOTOK; - } + NS_ASSERTION(aType, "aType must not be null!"); + *aType = mType; + return NS_OK; } #ifdef DEBUG @@ -1828,7 +1975,7 @@ nsHTMLInputElement::Reset() PRBool resetVal; GetDefaultChecked(&resetVal); rv = SetChecked(resetVal); - SET_BOOLBIT(mBitField, BF_CHECKED_CHANGED, PR_FALSE); + SetCheckedChanged(PR_FALSE); break; } case NS_FORM_INPUT_HIDDEN: @@ -2082,26 +2229,47 @@ nsHTMLInputElement::SaveState(nsIPresContext* aPresContext, GetType(&type); switch (type) { + case NS_FORM_INPUT_CHECKBOX: + case NS_FORM_INPUT_RADIO: + { + PRBool checked = PR_FALSE; + GetChecked(&checked); + rv = GetPrimaryPresState(this, aState); + if (*aState) { + if (checked) { + rv = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), + NS_LITERAL_STRING("t")); + } else { + rv = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), + NS_LITERAL_STRING("f")); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "checked save failed!"); + } + break; + } + // Never save passwords in session history case NS_FORM_INPUT_PASSWORD: break; case NS_FORM_INPUT_TEXT: case NS_FORM_INPUT_FILE: - nsresult rv = GetPrimaryPresState(this, aState); - if (*aState) { - nsString value; - GetValue(value); - // XXX Should use nsAutoString above but ConvertStringLineBreaks - // requires mOwnsBuffer! - rv = nsLinebreakConverter::ConvertStringLineBreaks( - value, - nsLinebreakConverter::eLinebreakPlatform, - nsLinebreakConverter::eLinebreakContent); - NS_ASSERTION(NS_SUCCEEDED(rv), "Converting linebreaks failed!"); - rv = (*aState)->SetStateProperty(NS_LITERAL_STRING("value"), value); - NS_ASSERTION(NS_SUCCEEDED(rv), "value save failed!"); + { + nsresult rv = GetPrimaryPresState(this, aState); + if (*aState) { + nsString value; + GetValue(value); + // XXX Should use nsAutoString above but ConvertStringLineBreaks + // requires mOwnsBuffer! + rv = nsLinebreakConverter::ConvertStringLineBreaks( + value, + nsLinebreakConverter::eLinebreakPlatform, + nsLinebreakConverter::eLinebreakContent); + NS_ASSERTION(NS_SUCCEEDED(rv), "Converting linebreaks failed!"); + rv = (*aState)->SetStateProperty(NS_LITERAL_STRING("value"), value); + NS_ASSERTION(NS_SUCCEEDED(rv), "value save failed!"); + } + break; } - break; } return rv; @@ -2117,17 +2285,271 @@ nsHTMLInputElement::RestoreState(nsIPresContext* aPresContext, GetType(&type); switch (type) { + case NS_FORM_INPUT_CHECKBOX: + case NS_FORM_INPUT_RADIO: + { + nsAutoString checked; + rv = aState->GetStateProperty(NS_LITERAL_STRING("checked"), checked); + // We assume that we are the only ones who saved the state. Thus we + // know the exact value that would have been saved. + if (checked.Equals(NS_LITERAL_STRING("t"))) { + SetChecked(PR_TRUE); + } else { + SetChecked(PR_FALSE); + } + + break; + } + // Never save passwords in session history case NS_FORM_INPUT_PASSWORD: break; case NS_FORM_INPUT_TEXT: case NS_FORM_INPUT_FILE: - nsAutoString value; - rv = aState->GetStateProperty(NS_LITERAL_STRING("value"), value); - NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!"); - SetValue(value); - break; + { + nsAutoString value; + rv = aState->GetStateProperty(NS_LITERAL_STRING("value"), value); + NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!"); + SetValue(value); + break; + } } return rv; } + + +/* + * Radio group stuff + */ + +NS_IMETHODIMP +nsHTMLInputElement::AddedToRadioGroup() +{ + // + // Currently the only time radio groups really happen is in forms + // + if (!mForm) { + return NS_OK; + } + + // + // If the input element is checked, and we add it to the group, it will + // deselect whatever is currently selected in that group + // + PRBool checked; + GetChecked(&checked); + if (checked) { + // + // If it is checked, call "RadioSetChecked" to perform the selection/ + // deselection ritual. This has the side effect of repainting the + // radio button, but as adding a checked radio button into the group + // should not be that common an occurrence, I think we can live with + // that. + // + RadioSetChecked(); + } + + // + // For integrity purposes, we have to ensure that "checkedChanged" is + // the same for this new element as for all the others in the group + // + PRBool checkedChanged = PR_FALSE; + nsCOMPtr visitor; + nsresult rv = NS_GetRadioGetCheckedChangedVisitor(&checkedChanged, this, + getter_AddRefs(visitor)); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoString name; + GetName(name); + rv = mForm->WalkRadioGroup(name, visitor); + SetCheckedChangedInternal(checkedChanged); + + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLInputElement::RemovedFromRadioGroup(nsIForm* aForm, nsAString* aName) +{ + // + // Currently radio groups only happen in forms + // + if (!aForm) { + return NS_OK; + } + + // + // If this button was checked, we need to notify the group that there is no + // longer a selected radio button + // + PRBool checked = PR_FALSE; + GetChecked(&checked); + + if (checked) { + if (aName) { + aForm->SetCurrentRadioButton(*aName, (nsIDOMHTMLInputElement*)nsnull); + } else { + nsAutoString name; + GetName(name); + aForm->SetCurrentRadioButton(name, (nsIDOMHTMLInputElement*)nsnull); + } + } + + return NS_OK; +} + +nsresult +nsHTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor) +{ + nsresult rv; + if (mForm) { + nsAutoString name; + GetName(name); + rv = mForm->WalkRadioGroup(name, aVisitor); + } else { + PRBool stop = PR_FALSE; + rv = aVisitor->Visit(this, &stop); + } + return rv; +} + + +// +// Visitor classes +// +// +// CLASS nsRadioVisitor +// +// (this is the superclass of the others) +// +class nsRadioVisitor : public nsIRadioVisitor { +public: + nsRadioVisitor() { NS_INIT_ISUPPORTS(); } + virtual ~nsRadioVisitor() { }; + + NS_DECL_ISUPPORTS + + NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop) = 0; +}; + +NS_IMPL_ADDREF(nsRadioVisitor) +NS_IMPL_RELEASE(nsRadioVisitor) + +NS_INTERFACE_MAP_BEGIN(nsRadioVisitor) + NS_INTERFACE_MAP_ENTRY(nsIRadioVisitor) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + + +// +// CLASS nsRadioSetCheckedChangedVisitor +// +class nsRadioSetCheckedChangedVisitor : public nsRadioVisitor { +public: + nsRadioSetCheckedChangedVisitor(PRBool aCheckedChanged) : + nsRadioVisitor(), mCheckedChanged(aCheckedChanged) + { } + + virtual ~nsRadioSetCheckedChangedVisitor() { } + + NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop) + { + nsCOMPtr radio(do_QueryInterface(aRadio)); + NS_ASSERTION(radio, "Visit() passed a null button (or non-radio)!"); + radio->SetCheckedChangedInternal(mCheckedChanged); + *aStop = PR_TRUE; + return NS_OK; + } + +protected: + PRPackedBool mCheckedChanged; +}; + +// +// CLASS nsRadioGetCheckedChangedVisitor +// +class nsRadioGetCheckedChangedVisitor : public nsRadioVisitor { +public: + nsRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged, + nsIFormControl* aExcludeElement) : + nsRadioVisitor(), + mCheckedChanged(aCheckedChanged), + mExcludeElement(aExcludeElement) + { } + + virtual ~nsRadioGetCheckedChangedVisitor() { } + + NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop) + { + if (aRadio == mExcludeElement) { + return NS_OK; + } + nsCOMPtr radio(do_QueryInterface(aRadio)); + NS_ASSERTION(radio, "Visit() passed a null button (or non-radio)!"); + radio->GetCheckedChanged(mCheckedChanged); + *aStop = PR_TRUE; + return NS_OK; + } + +protected: + PRBool* mCheckedChanged; + nsIFormControl* mExcludeElement; +}; + +NS_METHOD +NS_GetRadioSetCheckedChangedVisitor(PRBool aCheckedChanged, + nsIRadioVisitor** aVisitor) +{ + // + // These are static so that we don't have to keep creating new visitors for + // such an ordinary process all the time. There are only two possibilities + // for this visitor: set to true, and set to false. + // + static nsIRadioVisitor* visitorTrue = nsnull; + static nsIRadioVisitor* visitorFalse = nsnull; + + // + // Get the visitor that sets them to true + // + if (aCheckedChanged) { + if (!visitorTrue) { + visitorTrue = new nsRadioSetCheckedChangedVisitor(PR_TRUE); + if (!visitorTrue) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(visitorTrue); + } + *aVisitor = visitorTrue; + } + + // + // Get the visitor that sets them to false + // + if (!aCheckedChanged) { + if (!visitorFalse) { + visitorFalse = new nsRadioSetCheckedChangedVisitor(PR_FALSE); + if (!visitorFalse) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(visitorFalse); + } + *aVisitor = visitorFalse; + } + + NS_ADDREF(*aVisitor); + return NS_OK; +} + +NS_METHOD +NS_GetRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged, + nsIFormControl* aExcludeElement, + nsIRadioVisitor** aVisitor) +{ + *aVisitor = new nsRadioGetCheckedChangedVisitor(aCheckedChanged, + aExcludeElement); + if (!*aVisitor) { + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ADDREF(*aVisitor); + + return NS_OK; +} diff --git a/mozilla/layout/forms/nsFormControlFrame.cpp b/mozilla/layout/forms/nsFormControlFrame.cpp index 7f81fc68097..464ae0dce12 100644 --- a/mozilla/layout/forms/nsFormControlFrame.cpp +++ b/mozilla/layout/forms/nsFormControlFrame.cpp @@ -129,8 +129,6 @@ nsFormControlFrame::~nsFormControlFrame() { if (mFormFrame) { mFormFrame->RemoveFormControlFrame(*this); - // This method only removes from radio lists if we are a radio input - mFormFrame->RemoveRadioControlFrame(this); mFormFrame = nsnull; } } @@ -857,11 +855,11 @@ nsFormControlFrame::GetFont(nsIPresContext* aPresContext, nsresult nsFormControlFrame::GetDefaultCheckState(PRBool *aState) -{ nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { +{ + nsresult res = NS_OK; + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->GetDefaultChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -870,10 +868,9 @@ nsresult nsFormControlFrame::SetDefaultCheckState(PRBool aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->SetDefaultChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -882,10 +879,9 @@ nsresult nsFormControlFrame::GetCurrentCheckState(PRBool *aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->GetChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -894,10 +890,9 @@ nsresult nsFormControlFrame::SetCurrentCheckState(PRBool aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { inputElement->SetChecked(aState); - NS_RELEASE(inputElement); } return res; } diff --git a/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp b/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp index 65ef96ad97e..a0de56439aa 100644 --- a/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp +++ b/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp @@ -275,127 +275,26 @@ nsGfxCheckboxControlFrame::GetCheckboxState ( ) return retval; } -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::SetCheckboxState (nsIPresContext* aPresContext, - PRBool aValue ) -{ - nsCOMPtr elem(do_QueryInterface(mContent)); - elem->SetChecked(aValue); -} - -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::GetCheckboxControlFrameState ( - nsAWritableString& aValue ) -{ - CheckStateToString(GetCheckboxState(), aValue); -} - - -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::SetCheckboxControlFrameState ( - nsIPresContext* aPresContext, - const nsAReadableString& aValue ) -{ - PRBool state = StringToCheckState(aValue); - SetCheckboxState(aPresContext, state); -} - - -//------------------------------------------------------------ -// -// CheckStateToString -// -// Converts from a CheckState to a string -// -void -nsGfxCheckboxControlFrame::CheckStateToString ( - PRBool inState, - nsAWritableString& outStateAsString ) -{ - if (inState) { - outStateAsString.Assign(NS_STRING_TRUE); - } else { - outStateAsString.Assign(NS_STRING_FALSE); - } -} // CheckStateToString - - -//------------------------------------------------------------ -// -// StringToCheckState -// -// Converts from a string to a CheckState enum -// -PRBool -nsGfxCheckboxControlFrame::StringToCheckState ( const nsAReadableString & aStateAsString ) -{ - return aStateAsString.Equals(NS_STRING_TRUE); -} // StringToCheckState - - //---------------------------------------------------------------------- // nsIStatefulFrame //---------------------------------------------------------------------- NS_IMETHODIMP nsGfxCheckboxControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** aState) { - NS_ENSURE_ARG_POINTER(aState); - - // Don't save state before we are initialized - if (!mDidInit) { - return NS_OK; - } - - PRBool stateCheck = GetCheckboxState(); - PRBool defaultStateBool = PR_FALSE; - nsresult res = GetDefaultCheckState(&defaultStateBool); - - // Compare to default value, and only save if needed (Bug 62713) - if (!(NS_CONTENT_ATTR_HAS_VALUE == res && - ((stateCheck && defaultStateBool) || - (!stateCheck && !defaultStateBool)))) { - - // Get the value string - nsAutoString stateString; - CheckStateToString(stateCheck, stateString); - - // Construct a pres state and store value in it. - res = NS_NewPresState(aState); - NS_ENSURE_SUCCESS(res, res); - res = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), stateString); - } - - return res; + return nsFormControlHelper::SaveContentState(this, aPresContext, aState); } NS_IMETHODIMP nsGfxCheckboxControlFrame::RestoreState(nsIPresContext* aPresContext, nsIPresState* aState) { - NS_ENSURE_ARG_POINTER(aState); - - if (!mDidInit) { - mPresContext = aPresContext; - InitializeControl(aPresContext); - mDidInit = PR_TRUE; - } - - // Set the value to the stored state. - nsAutoString stateString; - nsresult res = aState->GetStateProperty(NS_LITERAL_STRING("checked"), stateString); - NS_ENSURE_SUCCESS(res, res); - - SetCheckboxControlFrameState(aPresContext, stateString); - return NS_OK; + return nsFormControlHelper::RestoreContentState(this, aPresContext, aState); } //------------------------------------------------------------ // Extra Debug Methods //------------------------------------------------------------ #ifdef DEBUG_rodsXXX -NS_IMETHODIMP +NS_IMETHODIMP nsGfxCheckboxControlFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/forms/nsGfxCheckboxControlFrame.h b/mozilla/layout/forms/nsGfxCheckboxControlFrame.h index 69bf5e41f69..16549d7ddd0 100644 --- a/mozilla/layout/forms/nsGfxCheckboxControlFrame.h +++ b/mozilla/layout/forms/nsGfxCheckboxControlFrame.h @@ -103,27 +103,9 @@ public: nsReflowStatus& aStatus); #endif - NS_IMETHOD GetChecked(PRBool* aIsChecked) { - *aIsChecked = GetCheckboxState(); return NS_OK; - } - NS_IMETHOD SetChecked(nsIPresContext* aPresContext, PRBool aIsChecked) { - SetCheckboxState(aPresContext, aIsChecked); return NS_OK; - } - protected: - // native/gfx implementations need to implement needs. PRBool GetCheckboxState(); - void SetCheckboxState(nsIPresContext* aPresContext, PRBool aValue); - - // Utility methods for implementing SetProperty/GetProperty - void SetCheckboxControlFrameState(nsIPresContext* aPresContext, - const nsAReadableString& aValue); - void GetCheckboxControlFrameState(nsAWritableString& aValue); - - // utility routine for converting from DOM values to internal enum - void CheckStateToString(PRBool inState, nsAWritableString& outStateAsString) ; - PRBool StringToCheckState(const nsAReadableString & aStateAsString) ; protected: diff --git a/mozilla/layout/forms/nsGfxRadioControlFrame.cpp b/mozilla/layout/forms/nsGfxRadioControlFrame.cpp index b1f8e5e217a..5e0f9b7d33e 100644 --- a/mozilla/layout/forms/nsGfxRadioControlFrame.cpp +++ b/mozilla/layout/forms/nsGfxRadioControlFrame.cpp @@ -74,7 +74,6 @@ NS_NewGfxRadioControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) nsGfxRadioControlFrame::nsGfxRadioControlFrame() { // Initialize GFX-rendered state - mChecked = PR_FALSE; mRadioButtonFaceStyle = nsnull; } @@ -155,79 +154,6 @@ nsGfxRadioControlFrame::SetAdditionalStyleContext(PRInt32 aIndex, return NS_OK; } -//-------------------------------------------------------------- -NS_IMETHODIMP nsGfxRadioControlFrame::SetProperty(nsIPresContext* aPresContext, nsIAtom* aName, const nsAReadableString& aValue) -{ - if (nsHTMLAtoms::checked == aName) { - PRBool state = (aValue.Equals(NS_STRING_TRUE)) ? PR_TRUE : PR_FALSE; - - - // if there is no form than the radiobtn is an orphan - if (mFormFrame) { - // if this failed then it didn't have a named radio group - if (NS_FAILED(mFormFrame->OnRadioChecked(aPresContext, *this, state))) { - // The line below is commented out to duplicate NavQuirks behavior - //SetRadioState(aPresContext, state); - } - } else { - SetRadioState(aPresContext, state); - } - } - else { - return nsFormControlFrame::SetProperty(aPresContext, aName, aValue); - } - - return NS_OK; -} - -//-------------------------------------------------------------- -NS_IMETHODIMP nsGfxRadioControlFrame::GetProperty(nsIAtom* aName, nsAWritableString& aValue) -{ - // Return the value of the property from the widget it is not null. - // If is null, assume the widget is GFX-rendered and return a member variable instead. - - if (nsHTMLAtoms::checked == aName) { - nsFormControlHelper::GetBoolString(GetRadioState(), aValue); - } else { - return nsFormControlFrame::GetProperty(aName, aValue); - } - - return NS_OK; -} - -//-------------------------------------------------------------- -PRBool -nsGfxRadioControlFrame::GetChecked() -{ - PRBool checked = PR_FALSE; - GetCurrentCheckState(&checked); - return(checked); -} - -//-------------------------------------------------------------- -PRBool -nsGfxRadioControlFrame::GetDefaultChecked() -{ - PRBool checked = PR_FALSE; - GetDefaultCheckState(&checked); - return(checked); -} - -//-------------------------------------------------------------- -void -nsGfxRadioControlFrame::SetChecked(nsIPresContext* aPresContext, PRBool aValue, PRBool aSetInitialValue) -{ - if (aSetInitialValue) { - if (aValue) { - mContent->SetAttr(kNameSpaceID_HTML, nsHTMLAtoms::checked, NS_LITERAL_STRING("1"), PR_FALSE); // XXX should be "empty" value - } else { - mContent->SetAttr(kNameSpaceID_HTML, nsHTMLAtoms::checked, NS_LITERAL_STRING("0"), PR_FALSE); - } - } - - SetRadioState(aPresContext, aValue); -} - //-------------------------------------------------------------- NS_IMETHODIMP nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) @@ -238,15 +164,6 @@ nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioBu } //-------------------------------------------------------------- -NS_IMETHODIMP -nsGfxRadioControlFrame::GetRadioGroupSelectedContent(nsIContent ** aRadioBtn) -{ - NS_ENSURE_ARG_POINTER(aRadioBtn); - nsFormFrame::GetRadioGroupSelectedContent(this, aRadioBtn); - return NS_OK; -} - - NS_IMETHODIMP nsGfxRadioControlFrame::HandleEvent(nsIPresContext* aPresContext, nsGUIEvent* aEvent, @@ -271,8 +188,8 @@ nsGfxRadioControlFrame::PaintRadioButton(nsIPresContext* aPresContext, PRBool checked = PR_TRUE; GetCurrentCheckState(&checked); // Get check state from the content model - if (PR_TRUE == checked) { - // Paint the button for the radio button using CSS background rendering code + if (checked) { + // Paint the button for the radio button using CSS background rendering code if (nsnull != mRadioButtonFaceStyle) { const nsStyleBackground* myColor = (const nsStyleBackground*) mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Background); @@ -332,80 +249,22 @@ nsGfxRadioControlFrame::Paint(nsIPresContext* aPresContext, //-------------------------------------------------------------- -PRBool nsGfxRadioControlFrame::GetRadioState() +NS_IMETHODIMP +nsGfxRadioControlFrame::OnChecked(nsIPresContext* aPresContext, + PRBool aChecked) { - return mChecked; -} - -//-------------------------------------------------------------- -void nsGfxRadioControlFrame::SetRadioState(nsIPresContext* aPresContext, PRBool aValue) -{ - mChecked = aValue; nsFormControlHelper::ForceDrawFrame(aPresContext, this); -} - -void -nsGfxRadioControlFrame::InitializeControl(nsIPresContext* aPresContext) -{ - nsFormControlFrame::InitializeControl(aPresContext); - - // Only reset on init if this is the primary shell - // Temporary workaround until radio state is in content - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - if (!presShell) return; - - nsCOMPtr doc; - presShell->GetDocument(getter_AddRefs(doc)); - if (!doc) return; - - nsCOMPtr primaryPresShell; - doc->GetShellAt(0, getter_AddRefs(primaryPresShell)); - if (!primaryPresShell) return; - - if (presShell.get() == primaryPresShell.get()) { - // set the widget to the initial state - // XXX We can't use reset because radio buttons fire onChange - // from content (much to our dismay) - PRBool checked = PR_FALSE; - nsresult rv = GetDefaultCheckState(&checked); - if (NS_CONTENT_ATTR_HAS_VALUE == rv) { - SetRadioState(aPresContext, checked); - } - } + return NS_OK; } //---------------------------------------------------------------------- // nsIStatefulFrame //---------------------------------------------------------------------- NS_IMETHODIMP -nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** aState) +nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, + nsIPresState** aState) { - NS_ENSURE_ARG_POINTER(aState); - - // Don't save state before we are initialized - if (!mDidInit) { - return NS_OK; - } - - nsresult res = NS_OK; - PRBool stateBool = GetRadioState(); - PRBool defaultStateBool = GetDefaultChecked(); - - // Compare to default value, and only save if needed (Bug 62713) - if (stateBool != defaultStateBool) { - - // Get the value string - nsAutoString stateString; - nsFormControlHelper::GetBoolString(stateBool, stateString); - - // Construct a pres state and store value in it. - res = NS_NewPresState(aState); - NS_ENSURE_SUCCESS(res, res); - res = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), stateString); - } - - return res; + return nsFormControlHelper::SaveContentState(this, aPresContext, aState); } @@ -414,25 +273,7 @@ nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** a NS_IMETHODIMP nsGfxRadioControlFrame::RestoreState(nsIPresContext* aPresContext, nsIPresState* aState) { - NS_ENSURE_ARG_POINTER(aState); - - if (!mDidInit) { - mPresContext = aPresContext; - InitializeControl(aPresContext); - mDidInit = PR_TRUE; - } - - mIsRestored = PR_TRUE; - nsAutoString stateString; - nsresult res = aState->GetStateProperty(NS_LITERAL_STRING("checked"), stateString); - NS_ENSURE_SUCCESS(res, res); - - res = SetProperty(aPresContext, nsHTMLAtoms::checked, stateString); - NS_ENSURE_SUCCESS(res, res); - - mRestoredChecked = mChecked; - - return NS_OK; + return nsFormControlHelper::RestoreContentState(this, aPresContext, aState); } diff --git a/mozilla/layout/forms/nsGfxRadioControlFrame.h b/mozilla/layout/forms/nsGfxRadioControlFrame.h index 7408966ee70..372fbc5d6a6 100644 --- a/mozilla/layout/forms/nsGfxRadioControlFrame.h +++ b/mozilla/layout/forms/nsGfxRadioControlFrame.h @@ -65,19 +65,10 @@ public: //nsIRadioControlFrame methods NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext); - NS_IMETHOD GetRadioGroupSelectedContent(nsIContent ** aRadioBtn); #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); #endif - - virtual PRBool GetChecked(); - virtual PRBool GetDefaultChecked(); - virtual PRBool GetRestoredChecked() { return mRestoredChecked;} - virtual PRBool IsRestored() { return mIsRestored;} - - virtual void SetChecked(nsIPresContext* aPresContext, PRBool aValue, PRBool aSetInitialValue); - - void InitializeControl(nsIPresContext* aPresContext); + NS_IMETHOD OnChecked(nsIPresContext* aPresContext, PRBool aChecked); NS_IMETHOD GetAdditionalStyleContext(PRInt32 aIndex, nsIStyleContext** aStyleContext) const; @@ -103,9 +94,7 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - // nsIFormControlFrame - NS_IMETHOD SetProperty(nsIPresContext* aPresContext, nsIAtom* aName, const nsAReadableString& aValue); - NS_IMETHOD GetProperty(nsIAtom* aName, nsAWritableString& aValue); + // nsIFormControlFrame NS_IMETHOD OnContentReset(); //nsIStatefulFrame @@ -122,14 +111,8 @@ public: protected: - virtual PRBool GetRadioState(); - virtual void SetRadioState(nsIPresContext* aPresContext, PRBool aValue); - //GFX-rendered state variables - PRBool mChecked; nsIStyleContext* mRadioButtonFaceStyle; - PRBool mRestoredChecked; - PRBool mIsRestored; private: NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } diff --git a/mozilla/layout/forms/nsIRadioControlFrame.h b/mozilla/layout/forms/nsIRadioControlFrame.h index 955fbb1806b..3da9d8674e1 100644 --- a/mozilla/layout/forms/nsIRadioControlFrame.h +++ b/mozilla/layout/forms/nsIRadioControlFrame.h @@ -50,7 +50,7 @@ class nsIStyleContext; /** * nsIRadioControlFrame is the common interface radio buttons. - * @see nsFromControlFrame and its base classes for more info + * @see nsFormControlFrame and its base classes for more info */ class nsIRadioControlFrame : public nsISupports { @@ -59,30 +59,14 @@ public: /** * Sets the Pseudo Style Contexts for the Radio button - * */ NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) = 0; - /** - * When a user clicks on a radiobutton the value needs to be set after the onmouseup - * and before the onclick event is processed via script. The EVM always lets script - * get first crack at the processing, and script can cancel further processing of - * the event by return null. - * - * This means the radiobutton needs to have it's new value set before it goes to script - * to process the onclick and then if script cancels the event it needs to be set back. - * In Nav and IE there is a flash of it being set and then unset - * - * We have added this extra method to the radiobutton so nsHTMLInputElement can get - * the content of the currently selected radiobutton for that radio group - * - * That way if it is cancelled then the original radiobutton can be set back - */ - - NS_IMETHOD GetRadioGroupSelectedContent(nsIContent ** aRadioBtn) = 0; - - + /** + * Called by content when the radio button's state changes + */ + NS_IMETHOD OnChecked(nsIPresContext* aPresContext, PRBool aChecked) = 0; }; #endif diff --git a/mozilla/layout/html/forms/public/nsIRadioControlFrame.h b/mozilla/layout/html/forms/public/nsIRadioControlFrame.h index 955fbb1806b..3da9d8674e1 100644 --- a/mozilla/layout/html/forms/public/nsIRadioControlFrame.h +++ b/mozilla/layout/html/forms/public/nsIRadioControlFrame.h @@ -50,7 +50,7 @@ class nsIStyleContext; /** * nsIRadioControlFrame is the common interface radio buttons. - * @see nsFromControlFrame and its base classes for more info + * @see nsFormControlFrame and its base classes for more info */ class nsIRadioControlFrame : public nsISupports { @@ -59,30 +59,14 @@ public: /** * Sets the Pseudo Style Contexts for the Radio button - * */ NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) = 0; - /** - * When a user clicks on a radiobutton the value needs to be set after the onmouseup - * and before the onclick event is processed via script. The EVM always lets script - * get first crack at the processing, and script can cancel further processing of - * the event by return null. - * - * This means the radiobutton needs to have it's new value set before it goes to script - * to process the onclick and then if script cancels the event it needs to be set back. - * In Nav and IE there is a flash of it being set and then unset - * - * We have added this extra method to the radiobutton so nsHTMLInputElement can get - * the content of the currently selected radiobutton for that radio group - * - * That way if it is cancelled then the original radiobutton can be set back - */ - - NS_IMETHOD GetRadioGroupSelectedContent(nsIContent ** aRadioBtn) = 0; - - + /** + * Called by content when the radio button's state changes + */ + NS_IMETHOD OnChecked(nsIPresContext* aPresContext, PRBool aChecked) = 0; }; #endif diff --git a/mozilla/layout/html/forms/src/Makefile.in b/mozilla/layout/html/forms/src/Makefile.in index 79ca31d3c81..a3a5b98e798 100644 --- a/mozilla/layout/html/forms/src/Makefile.in +++ b/mozilla/layout/html/forms/src/Makefile.in @@ -72,7 +72,6 @@ CPPSRCS = \ nsLabelFrame.cpp \ nsLegendFrame.cpp \ nsListControlFrame.cpp \ - nsRadioControlGroup.cpp \ nsIsIndexFrame.cpp \ $(NULL) diff --git a/mozilla/layout/html/forms/src/makefile.win b/mozilla/layout/html/forms/src/makefile.win index f08d31d9e79..389b5ccd502 100644 --- a/mozilla/layout/html/forms/src/makefile.win +++ b/mozilla/layout/html/forms/src/makefile.win @@ -68,8 +68,7 @@ CPP_OBJS= \ .\$(OBJDIR)\nsGfxButtonControlFrame.obj \ .\$(OBJDIR)\nsGfxCheckboxControlFrame.obj \ .\$(OBJDIR)\nsGfxRadioControlFrame.obj \ - .\$(OBJDIR)\nsIsIndexFrame.obj \ - .\$(OBJDIR)\nsRadioControlGroup.obj + .\$(OBJDIR)\nsIsIndexFrame.obj LINCS= -I..\..\base\src \ diff --git a/mozilla/layout/html/forms/src/nsFormControlFrame.cpp b/mozilla/layout/html/forms/src/nsFormControlFrame.cpp index 7f81fc68097..464ae0dce12 100644 --- a/mozilla/layout/html/forms/src/nsFormControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsFormControlFrame.cpp @@ -129,8 +129,6 @@ nsFormControlFrame::~nsFormControlFrame() { if (mFormFrame) { mFormFrame->RemoveFormControlFrame(*this); - // This method only removes from radio lists if we are a radio input - mFormFrame->RemoveRadioControlFrame(this); mFormFrame = nsnull; } } @@ -857,11 +855,11 @@ nsFormControlFrame::GetFont(nsIPresContext* aPresContext, nsresult nsFormControlFrame::GetDefaultCheckState(PRBool *aState) -{ nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { +{ + nsresult res = NS_OK; + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->GetDefaultChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -870,10 +868,9 @@ nsresult nsFormControlFrame::SetDefaultCheckState(PRBool aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->SetDefaultChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -882,10 +879,9 @@ nsresult nsFormControlFrame::GetCurrentCheckState(PRBool *aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { res = inputElement->GetChecked(aState); - NS_RELEASE(inputElement); } return res; } @@ -894,10 +890,9 @@ nsresult nsFormControlFrame::SetCurrentCheckState(PRBool aState) { nsresult res = NS_OK; - nsIDOMHTMLInputElement* inputElement; - if (NS_OK == mContent->QueryInterface(NS_GET_IID(nsIDOMHTMLInputElement), (void**)&inputElement)) { + nsCOMPtr inputElement = do_QueryInterface(mContent); + if (inputElement) { inputElement->SetChecked(aState); - NS_RELEASE(inputElement); } return res; } diff --git a/mozilla/layout/html/forms/src/nsFormFrame.cpp b/mozilla/layout/html/forms/src/nsFormFrame.cpp index 53bbbe42e01..a87fc32fa30 100644 --- a/mozilla/layout/html/forms/src/nsFormFrame.cpp +++ b/mozilla/layout/html/forms/src/nsFormFrame.cpp @@ -54,7 +54,6 @@ #include "nsIFormControlFrame.h" #include "nsFormControlFrame.h" #include "nsFileControlFrame.h" -#include "nsRadioControlGroup.h" #include "nsIForm.h" #include "nsIFormControl.h" @@ -78,7 +77,6 @@ #include "nsIDocument.h" #include "nsILinkHandler.h" -#include "nsGfxRadioControlFrame.h" #include "nsIDOMHTMLFormElement.h" #include "nsIDOMNSHTMLFormElement.h" #include "nsDOMError.h" @@ -125,7 +123,6 @@ nsFormFrame::nsFormFrame() nsFormFrame::~nsFormFrame() { - RemoveRadioGroups(); PRInt32 numControls = mFormControls.Count(); PRInt32 i; @@ -135,16 +132,6 @@ nsFormFrame::~nsFormFrame() } } -void nsFormFrame::RemoveRadioGroups() -{ - int numRadioGroups = mRadioGroups.Count(); - for (int i = 0; i < numRadioGroups; i++) { - nsRadioControlGroup* radioGroup = (nsRadioControlGroup *) mRadioGroups.ElementAt(i); - delete radioGroup; - } - mRadioGroups.Clear(); -} - void nsFormFrame::AddFormControlFrame(nsIPresContext* aPresContext, nsIFrame& aFrame) { // Make sure we have a form control @@ -190,132 +177,6 @@ void nsFormFrame::RemoveFormControlFrame(nsIFormControlFrame& aFrame) mFormControls.RemoveElement(&aFrame); } -NS_IMETHODIMP -nsFormFrame::RemoveFrame(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame) -{ - nsIFormControlFrame* fcFrame = nsnull; - nsresult result = aOldFrame->QueryInterface(NS_GET_IID(nsIFormControlFrame), (void**)&fcFrame); - if ((NS_OK == result) || (nsnull != fcFrame)) { - PRInt32 type; - fcFrame->GetType(&type); - if (NS_FORM_INPUT_RADIO == type) { - nsRadioControlGroup * group; - nsAutoString name; - nsresult rv = GetRadioInfo(fcFrame, name, group); - if (NS_SUCCEEDED(rv) && nsnull != group) { - DoDefaultSelection(aPresContext, group, (nsGfxRadioControlFrame*)fcFrame); - } - } - } - - return nsBlockFrame::RemoveFrame(aPresContext, aPresShell, aListName, aOldFrame); -} - -nsresult nsFormFrame::GetRadioInfo(nsIFormControlFrame* aFrame, - nsString& aName, - nsRadioControlGroup *& aGroup) -{ - aGroup = nsnull; - aName.SetLength(0); - aFrame->GetName(&aName); - PRBool hasName = aName.Length() > 0; - - // radio group processing - if (hasName) { - int numGroups = mRadioGroups.Count(); - nsRadioControlGroup* group; - for (int j = 0; j < numGroups; j++) { - group = (nsRadioControlGroup *) mRadioGroups.ElementAt(j); - nsString groupName; - group->GetName(groupName); - if (groupName.Equals(aName)) { - aGroup = group; - return NS_OK; - } - } - } - return NS_ERROR_FAILURE; -} - -void nsFormFrame::DoDefaultSelection(nsIPresContext* aPresContext, - nsRadioControlGroup * aGroup, - nsGfxRadioControlFrame * aRadioToIgnore) -{ -#if 0 - // We do not want to do the default selection when printing - // The code below ends up calling into the content, which then sets - // the state on the "primary" frame the frame being displayed - // this causes it to be "reset" to the default selection, - // then when we go to get the current state of the UI it has been reset back - // and then the printed state has the wrong value also - nsCOMPtr printContext = do_QueryInterface(aPresContext); - if (printContext) { - return; - } - // If in standard mode, then a radio group MUST default - // to the first item in the group (it must be selected) - nsCompatibility mode; - nsFormControlHelper::GetFormCompatibilityMode(aPresContext, mode); - if (eCompatibility_Standard == mode) { - // first find out if any have a default selection - PRInt32 i; - PRInt32 numItems = aGroup->GetNumRadios(); - PRBool oneIsDefSelected = PR_FALSE; - for (i=0;iGetRadioAt(i); - nsCOMPtr content; - radioBtn->GetContent(getter_AddRefs(content)); - if (content) { - nsCOMPtr input(do_QueryInterface(content)); - if (input) { - PRBool initiallyChecked = PR_FALSE; - if (radioBtn->IsRestored()) { - initiallyChecked = radioBtn->GetRestoredChecked(); - } else { - initiallyChecked = radioBtn->GetDefaultChecked(); - } - - PRBool currentValue = radioBtn->GetChecked(); - if (currentValue != initiallyChecked ) { - input->SetChecked(initiallyChecked); - //radioBtn->SetChecked(aPresContext, initSelected, PR_FALSE); - } - if (initiallyChecked) { - oneIsDefSelected = PR_TRUE; - } - } - } - } - - // if there isn't a default selcted radio then - // select the firdst one in the group. - // if aRadioToIgnore is not null then it is being deleted - // so don't select that item, select the next one if there is one. - if (!oneIsDefSelected && numItems > 0) { - nsGfxRadioControlFrame * radioBtn = (nsGfxRadioControlFrame*) aGroup->GetRadioAt(0); - if (aRadioToIgnore != nsnull && aRadioToIgnore == radioBtn) { - if (numItems == 1) { - return; - } - radioBtn = (nsGfxRadioControlFrame*) aGroup->GetRadioAt(1); - } - nsCOMPtr content; - radioBtn->GetContent(getter_AddRefs(content)); - if (content) { - nsCOMPtr input(do_QueryInterface(content)); - if (input) { - input->SetChecked(PR_TRUE); - } - } - } - } -#endif -} - - void nsFormFrame::AddFormControlFrame(nsIPresContext* aPresContext, nsIFormControlFrame& aFrame) { PRInt32 type; @@ -360,145 +221,9 @@ void nsFormFrame::AddFormControlFrame(nsIPresContext* aPresContext, nsIFormContr } } mFormControls.InsertElementAt(&aFrame, i); - - // determine which radio buttons belong to which radio groups, unnamed radio - // buttons don't go into any group since they can't be submitted. Determine - // which controls are capable of form submission. - - if (NS_FORM_INPUT_RADIO == type) { - nsGfxRadioControlFrame* radioFrame = (nsGfxRadioControlFrame*)&aFrame; - // gets the name of the radio group and the group - nsRadioControlGroup * group; - nsAutoString name; - rv = GetRadioInfo(&aFrame, name, group); - if (NS_SUCCEEDED(rv) && nsnull != group) { - group->AddRadio(radioFrame); - } else { - group = new nsRadioControlGroup(name); - mRadioGroups.AppendElement(group); - group->AddRadio(radioFrame); - } - // allow only one checked radio button - PRBool initiallyChecked = PR_FALSE; - if (radioFrame->IsRestored()) { - initiallyChecked = radioFrame->GetRestoredChecked(); - } else { - initiallyChecked = radioFrame->GetDefaultChecked(); - } - if (initiallyChecked) { - if (nsnull == group->GetCheckedRadio()) { - group->SetCheckedRadio(radioFrame); - } else { - radioFrame->SetChecked(aPresContext, PR_FALSE, PR_FALSE); - } - } - DoDefaultSelection(aPresContext, group); - } -} - -void nsFormFrame::RemoveRadioControlFrame(nsIFormControlFrame * aFrame) -{ - PRInt32 type; - aFrame->GetType(&type); - - // radio group processing - if (NS_FORM_INPUT_RADIO == type) { - nsGfxRadioControlFrame* radioFrame = (nsGfxRadioControlFrame*)aFrame; - // gets the name of the radio group and the group - nsRadioControlGroup * group; - nsAutoString name; - nsresult rv = GetRadioInfo(aFrame, name, group); - if (NS_SUCCEEDED(rv) && nsnull != group) { - group->RemoveRadio(radioFrame); - } - } } -//-------------------------------------------------------- -// Return the content of the currently selected item in -// the radio group of the incoming radiobutton. -//-------------------------------------------------------- -nsresult -nsFormFrame::GetRadioGroupSelectedContent(nsGfxRadioControlFrame* aControl, - nsIContent ** aRadiobtn) -{ - NS_ASSERTION(aControl, "nsGfxRadioControlFrame can't be null"); - - // first get correct interface - nsIFormControlFrame* fcFrame = nsnull; - nsresult result = aControl->QueryInterface(NS_GET_IID(nsIFormControlFrame), (void**)&fcFrame); - if (NS_SUCCEEDED(result)) { - // get the form frame for the radio btn - nsFormFrame * formFrame = ((nsFormControlFrame *)aControl)->GetFormFrame(); - if (formFrame != nsnull) { - // now get the radio group by name - nsAutoString groupName; - nsRadioControlGroup * group = nsnull; - result = formFrame->GetRadioInfo(fcFrame, groupName, group); - if (NS_SUCCEEDED(result) && nsnull != group) { - // get the currently checked radio button - nsGfxRadioControlFrame* currentCheckBtn = group->GetCheckedRadio(); - if (currentCheckBtn != nsnull) { - currentCheckBtn->GetContent(aRadiobtn); - } - } - } - } - return NS_OK; -} - -//-------------------------------------------------------- -// returns NS_ERROR_FAILURE if the radiobtn doesn't have a group -// returns NS_OK is it did have a radio group -//-------------------------------------------------------- -nsresult -nsFormFrame::OnRadioChecked(nsIPresContext* aPresContext, - nsGfxRadioControlFrame& aControl, - PRBool aNewCheckedVal) -{ - // first get correct interface - nsIFormControlFrame* fcFrame = nsnull; - nsresult result = aControl.QueryInterface(NS_GET_IID(nsIFormControlFrame), (void**)&fcFrame); - if (NS_SUCCEEDED(result)) { - // now get the radio group by name - nsAutoString groupName; - nsRadioControlGroup * group = nsnull; - result = GetRadioInfo(fcFrame, groupName, group); - if (NS_SUCCEEDED(result) && nsnull != group) { - // get the currently checked radio button - nsGfxRadioControlFrame* currentCheckBtn = group->GetCheckedRadio(); - // is the new checked btn different than the current button? - if (&aControl != currentCheckBtn) { - // if the new button is being set to false - // then don't do anything - if (aNewCheckedVal) { - // the current btn could be null - if (currentCheckBtn != nsnull) { - currentCheckBtn->SetChecked(aPresContext, !aNewCheckedVal, PR_FALSE); - } - aControl.SetChecked(aPresContext, aNewCheckedVal, PR_FALSE); - group->SetCheckedRadio(&aControl); - } - } else { - // here we are setting the same radio button - // as the one that is currently checked - // - if (currentCheckBtn != nsnull) { - currentCheckBtn->SetChecked(aPresContext, aNewCheckedVal, PR_FALSE); - // So if we are setting the current btn to be 0 or off - // then we must set a default selction - if (!aNewCheckedVal) { - DoDefaultSelection(aPresContext, group, currentCheckBtn); - } - } - } - } - } - return NS_OK; -} - - nsresult NS_NewFormFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, PRUint32 aFlags) { diff --git a/mozilla/layout/html/forms/src/nsFormFrame.h b/mozilla/layout/html/forms/src/nsFormFrame.h index 7bb3c9af3b8..6a84918ad2d 100644 --- a/mozilla/layout/html/forms/src/nsFormFrame.h +++ b/mozilla/layout/html/forms/src/nsFormFrame.h @@ -48,14 +48,12 @@ class nsIFrame; class nsIPresContext; struct nsHTMLReflowState; class nsFormControlFrame; -class nsGfxRadioControlFrame; class nsIFormControlFrame; class nsIDOMHTMLFormElement; class nsIDocument; class nsIPresContext; class nsFormFrame; class nsIUnicodeEncoder; -class nsRadioControlGroup; class nsFormFrame : public nsBlockFrame { @@ -65,24 +63,11 @@ public: NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); - NS_IMETHOD RemoveFrame(nsIPresContext* aPresContext, - nsIPresShell& aPresShell, - nsIAtom* aListName, - nsIFrame* aOldFrame); - // other methods - //-------------------------------------------------------- - // returns NS_ERROR_FAILURE if the radiobtn doesn't have a group - // returns NS_OK is it did have a radio group - //-------------------------------------------------------- - nsresult OnRadioChecked(nsIPresContext* aPresContext, nsGfxRadioControlFrame& aRadio, PRBool aChecked = PR_TRUE); - void AddFormControlFrame(nsIPresContext* aPresContext, nsIFormControlFrame& aFrame); static void AddFormControlFrame(nsIPresContext* aPresContext, nsIFrame& aFrame); void RemoveFormControlFrame(nsIFormControlFrame& aFrame); - void RemoveRadioControlFrame(nsIFormControlFrame * aFrame); - nsresult GetRadioInfo(nsIFormControlFrame* aFrame, nsString& aName, nsRadioControlGroup *& aGroup); // static helper functions for nsIFormControls @@ -96,8 +81,6 @@ public: nsIContent* aContent = 0); static void StyleChangeReflow(nsIPresContext* aPresContext, nsIFrame* aFrame); - static nsresult GetRadioGroupSelectedContent(nsGfxRadioControlFrame* aControl, - nsIContent ** aRadiobtn); void SetFlags(PRUint32 aFlags) { mState &= ~NS_BLOCK_FLAGS_MASK; mState |= aFlags; @@ -109,14 +92,8 @@ public: protected: NS_IMETHOD_(nsrefcnt) AddRef(void); NS_IMETHOD_(nsrefcnt) Release(void); - void RemoveRadioGroups(); - - void DoDefaultSelection(nsIPresContext* aPresContext, - nsRadioControlGroup * aGroup, - nsGfxRadioControlFrame * aRadioToIgnore = nsnull); nsVoidArray mFormControls; - nsVoidArray mRadioGroups; static PRBool gInitPasswordManager; }; diff --git a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp index 65ef96ad97e..a0de56439aa 100644 --- a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp @@ -275,127 +275,26 @@ nsGfxCheckboxControlFrame::GetCheckboxState ( ) return retval; } -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::SetCheckboxState (nsIPresContext* aPresContext, - PRBool aValue ) -{ - nsCOMPtr elem(do_QueryInterface(mContent)); - elem->SetChecked(aValue); -} - -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::GetCheckboxControlFrameState ( - nsAWritableString& aValue ) -{ - CheckStateToString(GetCheckboxState(), aValue); -} - - -//------------------------------------------------------------ -void -nsGfxCheckboxControlFrame::SetCheckboxControlFrameState ( - nsIPresContext* aPresContext, - const nsAReadableString& aValue ) -{ - PRBool state = StringToCheckState(aValue); - SetCheckboxState(aPresContext, state); -} - - -//------------------------------------------------------------ -// -// CheckStateToString -// -// Converts from a CheckState to a string -// -void -nsGfxCheckboxControlFrame::CheckStateToString ( - PRBool inState, - nsAWritableString& outStateAsString ) -{ - if (inState) { - outStateAsString.Assign(NS_STRING_TRUE); - } else { - outStateAsString.Assign(NS_STRING_FALSE); - } -} // CheckStateToString - - -//------------------------------------------------------------ -// -// StringToCheckState -// -// Converts from a string to a CheckState enum -// -PRBool -nsGfxCheckboxControlFrame::StringToCheckState ( const nsAReadableString & aStateAsString ) -{ - return aStateAsString.Equals(NS_STRING_TRUE); -} // StringToCheckState - - //---------------------------------------------------------------------- // nsIStatefulFrame //---------------------------------------------------------------------- NS_IMETHODIMP nsGfxCheckboxControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** aState) { - NS_ENSURE_ARG_POINTER(aState); - - // Don't save state before we are initialized - if (!mDidInit) { - return NS_OK; - } - - PRBool stateCheck = GetCheckboxState(); - PRBool defaultStateBool = PR_FALSE; - nsresult res = GetDefaultCheckState(&defaultStateBool); - - // Compare to default value, and only save if needed (Bug 62713) - if (!(NS_CONTENT_ATTR_HAS_VALUE == res && - ((stateCheck && defaultStateBool) || - (!stateCheck && !defaultStateBool)))) { - - // Get the value string - nsAutoString stateString; - CheckStateToString(stateCheck, stateString); - - // Construct a pres state and store value in it. - res = NS_NewPresState(aState); - NS_ENSURE_SUCCESS(res, res); - res = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), stateString); - } - - return res; + return nsFormControlHelper::SaveContentState(this, aPresContext, aState); } NS_IMETHODIMP nsGfxCheckboxControlFrame::RestoreState(nsIPresContext* aPresContext, nsIPresState* aState) { - NS_ENSURE_ARG_POINTER(aState); - - if (!mDidInit) { - mPresContext = aPresContext; - InitializeControl(aPresContext); - mDidInit = PR_TRUE; - } - - // Set the value to the stored state. - nsAutoString stateString; - nsresult res = aState->GetStateProperty(NS_LITERAL_STRING("checked"), stateString); - NS_ENSURE_SUCCESS(res, res); - - SetCheckboxControlFrameState(aPresContext, stateString); - return NS_OK; + return nsFormControlHelper::RestoreContentState(this, aPresContext, aState); } //------------------------------------------------------------ // Extra Debug Methods //------------------------------------------------------------ #ifdef DEBUG_rodsXXX -NS_IMETHODIMP +NS_IMETHODIMP nsGfxCheckboxControlFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, diff --git a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h index 69bf5e41f69..16549d7ddd0 100644 --- a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h +++ b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h @@ -103,27 +103,9 @@ public: nsReflowStatus& aStatus); #endif - NS_IMETHOD GetChecked(PRBool* aIsChecked) { - *aIsChecked = GetCheckboxState(); return NS_OK; - } - NS_IMETHOD SetChecked(nsIPresContext* aPresContext, PRBool aIsChecked) { - SetCheckboxState(aPresContext, aIsChecked); return NS_OK; - } - protected: - // native/gfx implementations need to implement needs. PRBool GetCheckboxState(); - void SetCheckboxState(nsIPresContext* aPresContext, PRBool aValue); - - // Utility methods for implementing SetProperty/GetProperty - void SetCheckboxControlFrameState(nsIPresContext* aPresContext, - const nsAReadableString& aValue); - void GetCheckboxControlFrameState(nsAWritableString& aValue); - - // utility routine for converting from DOM values to internal enum - void CheckStateToString(PRBool inState, nsAWritableString& outStateAsString) ; - PRBool StringToCheckState(const nsAReadableString & aStateAsString) ; protected: diff --git a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp index b1f8e5e217a..5e0f9b7d33e 100644 --- a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp @@ -74,7 +74,6 @@ NS_NewGfxRadioControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame) nsGfxRadioControlFrame::nsGfxRadioControlFrame() { // Initialize GFX-rendered state - mChecked = PR_FALSE; mRadioButtonFaceStyle = nsnull; } @@ -155,79 +154,6 @@ nsGfxRadioControlFrame::SetAdditionalStyleContext(PRInt32 aIndex, return NS_OK; } -//-------------------------------------------------------------- -NS_IMETHODIMP nsGfxRadioControlFrame::SetProperty(nsIPresContext* aPresContext, nsIAtom* aName, const nsAReadableString& aValue) -{ - if (nsHTMLAtoms::checked == aName) { - PRBool state = (aValue.Equals(NS_STRING_TRUE)) ? PR_TRUE : PR_FALSE; - - - // if there is no form than the radiobtn is an orphan - if (mFormFrame) { - // if this failed then it didn't have a named radio group - if (NS_FAILED(mFormFrame->OnRadioChecked(aPresContext, *this, state))) { - // The line below is commented out to duplicate NavQuirks behavior - //SetRadioState(aPresContext, state); - } - } else { - SetRadioState(aPresContext, state); - } - } - else { - return nsFormControlFrame::SetProperty(aPresContext, aName, aValue); - } - - return NS_OK; -} - -//-------------------------------------------------------------- -NS_IMETHODIMP nsGfxRadioControlFrame::GetProperty(nsIAtom* aName, nsAWritableString& aValue) -{ - // Return the value of the property from the widget it is not null. - // If is null, assume the widget is GFX-rendered and return a member variable instead. - - if (nsHTMLAtoms::checked == aName) { - nsFormControlHelper::GetBoolString(GetRadioState(), aValue); - } else { - return nsFormControlFrame::GetProperty(aName, aValue); - } - - return NS_OK; -} - -//-------------------------------------------------------------- -PRBool -nsGfxRadioControlFrame::GetChecked() -{ - PRBool checked = PR_FALSE; - GetCurrentCheckState(&checked); - return(checked); -} - -//-------------------------------------------------------------- -PRBool -nsGfxRadioControlFrame::GetDefaultChecked() -{ - PRBool checked = PR_FALSE; - GetDefaultCheckState(&checked); - return(checked); -} - -//-------------------------------------------------------------- -void -nsGfxRadioControlFrame::SetChecked(nsIPresContext* aPresContext, PRBool aValue, PRBool aSetInitialValue) -{ - if (aSetInitialValue) { - if (aValue) { - mContent->SetAttr(kNameSpaceID_HTML, nsHTMLAtoms::checked, NS_LITERAL_STRING("1"), PR_FALSE); // XXX should be "empty" value - } else { - mContent->SetAttr(kNameSpaceID_HTML, nsHTMLAtoms::checked, NS_LITERAL_STRING("0"), PR_FALSE); - } - } - - SetRadioState(aPresContext, aValue); -} - //-------------------------------------------------------------- NS_IMETHODIMP nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) @@ -238,15 +164,6 @@ nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioBu } //-------------------------------------------------------------- -NS_IMETHODIMP -nsGfxRadioControlFrame::GetRadioGroupSelectedContent(nsIContent ** aRadioBtn) -{ - NS_ENSURE_ARG_POINTER(aRadioBtn); - nsFormFrame::GetRadioGroupSelectedContent(this, aRadioBtn); - return NS_OK; -} - - NS_IMETHODIMP nsGfxRadioControlFrame::HandleEvent(nsIPresContext* aPresContext, nsGUIEvent* aEvent, @@ -271,8 +188,8 @@ nsGfxRadioControlFrame::PaintRadioButton(nsIPresContext* aPresContext, PRBool checked = PR_TRUE; GetCurrentCheckState(&checked); // Get check state from the content model - if (PR_TRUE == checked) { - // Paint the button for the radio button using CSS background rendering code + if (checked) { + // Paint the button for the radio button using CSS background rendering code if (nsnull != mRadioButtonFaceStyle) { const nsStyleBackground* myColor = (const nsStyleBackground*) mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Background); @@ -332,80 +249,22 @@ nsGfxRadioControlFrame::Paint(nsIPresContext* aPresContext, //-------------------------------------------------------------- -PRBool nsGfxRadioControlFrame::GetRadioState() +NS_IMETHODIMP +nsGfxRadioControlFrame::OnChecked(nsIPresContext* aPresContext, + PRBool aChecked) { - return mChecked; -} - -//-------------------------------------------------------------- -void nsGfxRadioControlFrame::SetRadioState(nsIPresContext* aPresContext, PRBool aValue) -{ - mChecked = aValue; nsFormControlHelper::ForceDrawFrame(aPresContext, this); -} - -void -nsGfxRadioControlFrame::InitializeControl(nsIPresContext* aPresContext) -{ - nsFormControlFrame::InitializeControl(aPresContext); - - // Only reset on init if this is the primary shell - // Temporary workaround until radio state is in content - nsCOMPtr presShell; - aPresContext->GetShell(getter_AddRefs(presShell)); - if (!presShell) return; - - nsCOMPtr doc; - presShell->GetDocument(getter_AddRefs(doc)); - if (!doc) return; - - nsCOMPtr primaryPresShell; - doc->GetShellAt(0, getter_AddRefs(primaryPresShell)); - if (!primaryPresShell) return; - - if (presShell.get() == primaryPresShell.get()) { - // set the widget to the initial state - // XXX We can't use reset because radio buttons fire onChange - // from content (much to our dismay) - PRBool checked = PR_FALSE; - nsresult rv = GetDefaultCheckState(&checked); - if (NS_CONTENT_ATTR_HAS_VALUE == rv) { - SetRadioState(aPresContext, checked); - } - } + return NS_OK; } //---------------------------------------------------------------------- // nsIStatefulFrame //---------------------------------------------------------------------- NS_IMETHODIMP -nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** aState) +nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, + nsIPresState** aState) { - NS_ENSURE_ARG_POINTER(aState); - - // Don't save state before we are initialized - if (!mDidInit) { - return NS_OK; - } - - nsresult res = NS_OK; - PRBool stateBool = GetRadioState(); - PRBool defaultStateBool = GetDefaultChecked(); - - // Compare to default value, and only save if needed (Bug 62713) - if (stateBool != defaultStateBool) { - - // Get the value string - nsAutoString stateString; - nsFormControlHelper::GetBoolString(stateBool, stateString); - - // Construct a pres state and store value in it. - res = NS_NewPresState(aState); - NS_ENSURE_SUCCESS(res, res); - res = (*aState)->SetStateProperty(NS_LITERAL_STRING("checked"), stateString); - } - - return res; + return nsFormControlHelper::SaveContentState(this, aPresContext, aState); } @@ -414,25 +273,7 @@ nsGfxRadioControlFrame::SaveState(nsIPresContext* aPresContext, nsIPresState** a NS_IMETHODIMP nsGfxRadioControlFrame::RestoreState(nsIPresContext* aPresContext, nsIPresState* aState) { - NS_ENSURE_ARG_POINTER(aState); - - if (!mDidInit) { - mPresContext = aPresContext; - InitializeControl(aPresContext); - mDidInit = PR_TRUE; - } - - mIsRestored = PR_TRUE; - nsAutoString stateString; - nsresult res = aState->GetStateProperty(NS_LITERAL_STRING("checked"), stateString); - NS_ENSURE_SUCCESS(res, res); - - res = SetProperty(aPresContext, nsHTMLAtoms::checked, stateString); - NS_ENSURE_SUCCESS(res, res); - - mRestoredChecked = mChecked; - - return NS_OK; + return nsFormControlHelper::RestoreContentState(this, aPresContext, aState); } diff --git a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h index 7408966ee70..372fbc5d6a6 100644 --- a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h +++ b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h @@ -65,19 +65,10 @@ public: //nsIRadioControlFrame methods NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr); NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext); - NS_IMETHOD GetRadioGroupSelectedContent(nsIContent ** aRadioBtn); #ifdef ACCESSIBILITY NS_IMETHOD GetAccessible(nsIAccessible** aAccessible); #endif - - virtual PRBool GetChecked(); - virtual PRBool GetDefaultChecked(); - virtual PRBool GetRestoredChecked() { return mRestoredChecked;} - virtual PRBool IsRestored() { return mIsRestored;} - - virtual void SetChecked(nsIPresContext* aPresContext, PRBool aValue, PRBool aSetInitialValue); - - void InitializeControl(nsIPresContext* aPresContext); + NS_IMETHOD OnChecked(nsIPresContext* aPresContext, PRBool aChecked); NS_IMETHOD GetAdditionalStyleContext(PRInt32 aIndex, nsIStyleContext** aStyleContext) const; @@ -103,9 +94,7 @@ public: nsIRenderingContext& aRenderingContext, const nsRect& aDirtyRect); - // nsIFormControlFrame - NS_IMETHOD SetProperty(nsIPresContext* aPresContext, nsIAtom* aName, const nsAReadableString& aValue); - NS_IMETHOD GetProperty(nsIAtom* aName, nsAWritableString& aValue); + // nsIFormControlFrame NS_IMETHOD OnContentReset(); //nsIStatefulFrame @@ -122,14 +111,8 @@ public: protected: - virtual PRBool GetRadioState(); - virtual void SetRadioState(nsIPresContext* aPresContext, PRBool aValue); - //GFX-rendered state variables - PRBool mChecked; nsIStyleContext* mRadioButtonFaceStyle; - PRBool mRestoredChecked; - PRBool mIsRestored; private: NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }