Bug 2716, 2792, 1190, 1750: Wired up selected, defaultSelected, and selectedIndex.

This commit is contained in:
pollmann%netscape.com 1999-01-30 01:02:28 +00:00
Родитель 916de0e58b
Коммит d3346aaad9
5 изменённых файлов: 477 добавлений и 90 удалений

Просмотреть файл

@ -31,11 +31,21 @@
#include "nsIForm.h"
#include "nsIDOMText.h"
// Notify/query select frame for selected state
#include "nsIFormControlFrame.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIFrame.h"
#include "nsIDOMHTMLSelectElement.h"
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID);
static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID);
class nsHTMLOptionElement : public nsIDOMHTMLOptionElement,
public nsIScriptObjectOwner,
@ -89,6 +99,9 @@ public:
protected:
nsGenericHTMLContainerElement mInner;
nsIForm* mForm;
// Return the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame);
};
nsresult
@ -180,21 +193,53 @@ nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
return result;
}
NS_IMETHODIMP
nsHTMLOptionElement::GetSelected(PRBool *aSelected)
NS_IMETHODIMP
nsHTMLOptionElement::GetSelected(PRBool* aValue)
{
nsHTMLValue val;
nsresult rv = mInner.GetHTMLAttribute(nsHTMLAtoms::selected, val);
*aSelected = NS_CONTENT_ATTR_NOT_THERE != rv;
return NS_OK;
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
PRInt32 index;
if (NS_OK == GetIndex(&index)) {
nsString value;
value.Append(index, 10); // Save the index in base 10
formControlFrame->GetProperty(nsHTMLAtoms::selected, value);
if (value == "1")
*aValue = PR_TRUE;
else
*aValue = PR_FALSE;
}
NS_RELEASE(formControlFrame);
}
return NS_OK;
}
NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, defaultselected)
//NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, defaultselected)
NS_IMPL_INT_ATTR(nsHTMLOptionElement, Index, index)
NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled)
NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Label, label)
NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Value, value)
NS_IMETHODIMP
nsHTMLOptionElement::GetDefaultSelected(PRBool* aDefaultSelected)
{
nsHTMLValue val;
nsresult rv = mInner.GetHTMLAttribute(nsHTMLAtoms::selected, val);
*aDefaultSelected = (NS_CONTENT_ATTR_NOT_THERE != rv);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLOptionElement::SetDefaultSelected(PRBool aDefaultSelected)
{
nsHTMLValue empty(eHTMLUnit_Empty);
if (aDefaultSelected) {
return mInner.SetHTMLAttribute(nsHTMLAtoms::selected, empty, PR_TRUE);
} else {
mInner.UnsetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::selected, PR_TRUE);
return NS_OK;
}
}
NS_IMETHODIMP
nsHTMLOptionElement::StringToAttribute(nsIAtom* aAttribute,
const nsString& aValue,
@ -273,3 +318,44 @@ nsHTMLOptionElement::GetStyleHintForAttributeChange(
nsGenericHTMLElement::SetStyleHintForCommonAttributes(this, aAttribute, aHint);
return NS_OK;
}
// Options don't have frames, so get the select frame.
nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame)
{
// Get the containing element.
nsresult res = NS_NOINTERFACE;
nsIDOMNode* parentNode = nsnull;
nsresult gotParent = this->GetParentNode(&parentNode);
if (NS_OK == gotParent) {
nsIDOMHTMLSelectElement* selectElement = nsnull;
// XXX Optgroups: if this is not NS_OK then we need to GetParentNode again.
nsresult isSelect = parentNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&selectElement);
if (NS_OK == isSelect) {
nsIContent* selectContent = nsnull;
nsresult gotContent = selectElement->QueryInterface(kIContentIID, (void**)&selectContent);
if (NS_OK == gotContent) {
nsIDocument* doc = nsnull;
// Get the document
if (NS_OK == GetDocument(doc)) {
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
if (nsnull != presShell) {
nsIFrame *frame = nsnull;
presShell->GetPrimaryFrameFor(selectContent, frame);
if (nsnull != frame) {
res = frame->QueryInterface(kIFormControlFrameIID, (void**)&aIFormControlFrame);
}
NS_RELEASE(presShell);
}
NS_RELEASE(doc);
}
NS_RELEASE(selectContent);
}
NS_RELEASE(selectElement);
}
NS_RELEASE(parentNode);
}
return res;
}

Просмотреть файл

@ -35,11 +35,18 @@
#include "nsIHTMLAttributes.h"
#include "nsIDOMHTMLOptionElement.h"
// Notify/query select frame for selectedIndex
#include "nsIFormControlFrame.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIFrame.h"
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID);
static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID);
class nsHTMLSelectElement;
@ -137,6 +144,9 @@ protected:
nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient
nsIForm* mForm;
nsOptionList* mOptions;
// Return the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame);
};
@ -304,7 +314,42 @@ nsHTMLSelectElement::GetLength(PRUint32* aLength)
}
}
NS_IMPL_INT_ATTR(nsHTMLSelectElement, SelectedIndex, selectedindex)
//NS_IMPL_INT_ATTR(nsHTMLSelectElement, SelectedIndex, selectedindex)
NS_IMETHODIMP
nsHTMLSelectElement::GetSelectedIndex(PRInt32* aValue)
{
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
nsString value;
formControlFrame->GetProperty(nsHTMLAtoms::selectedindex, value);
NS_RELEASE(formControlFrame);
if (value.Length() > 0) {
PRInt32 retval = 0;
PRInt32 error = 0;
retval = value.ToInteger(&error, 10); // Convert to integer, base 10
if (!error) {
*aValue = retval;
return NS_OK;
}
}
}
*aValue = -1; // If no selectedIndex was to be had, make it -1 (none selected)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLSelectElement::SetSelectedIndex(PRInt32 aValue)
{
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
nsString value;
value.Append(aValue, 10);
formControlFrame->SetProperty(nsHTMLAtoms::selectedindex, value);
NS_RELEASE(formControlFrame);
}
return NS_OK;
}
NS_IMPL_STRING_ATTR(nsHTMLSelectElement, Value, value)
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Disabled, disabled)
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Multiple, multiple)
@ -659,3 +704,26 @@ nsHTMLSelectElement::GetStyleHintForAttributeChange(
nsGenericHTMLElement::SetStyleHintForCommonAttributes(this, aAttribute, aHint);
return NS_OK;
}
nsresult
nsHTMLSelectElement::GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame)
{
nsIDocument* doc = nsnull;
nsresult res = NS_NOINTERFACE;
// Get the document
if (NS_OK == GetDocument(doc)) {
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
if (nsnull != presShell) {
nsIFrame *frame = nsnull;
presShell->GetPrimaryFrameFor(this, frame);
if (nsnull != frame) {
res = frame->QueryInterface(kIFormControlFrameIID, (void**)&aFormControlFrame);
}
NS_RELEASE(presShell);
}
NS_RELEASE(doc);
}
return res;
}

Просмотреть файл

@ -31,11 +31,21 @@
#include "nsIForm.h"
#include "nsIDOMText.h"
// Notify/query select frame for selected state
#include "nsIFormControlFrame.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIFrame.h"
#include "nsIDOMHTMLSelectElement.h"
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID);
static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID);
class nsHTMLOptionElement : public nsIDOMHTMLOptionElement,
public nsIScriptObjectOwner,
@ -89,6 +99,9 @@ public:
protected:
nsGenericHTMLContainerElement mInner;
nsIForm* mForm;
// Return the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame);
};
nsresult
@ -180,21 +193,53 @@ nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
return result;
}
NS_IMETHODIMP
nsHTMLOptionElement::GetSelected(PRBool *aSelected)
NS_IMETHODIMP
nsHTMLOptionElement::GetSelected(PRBool* aValue)
{
nsHTMLValue val;
nsresult rv = mInner.GetHTMLAttribute(nsHTMLAtoms::selected, val);
*aSelected = NS_CONTENT_ATTR_NOT_THERE != rv;
return NS_OK;
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
PRInt32 index;
if (NS_OK == GetIndex(&index)) {
nsString value;
value.Append(index, 10); // Save the index in base 10
formControlFrame->GetProperty(nsHTMLAtoms::selected, value);
if (value == "1")
*aValue = PR_TRUE;
else
*aValue = PR_FALSE;
}
NS_RELEASE(formControlFrame);
}
return NS_OK;
}
NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, defaultselected)
//NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, DefaultSelected, defaultselected)
NS_IMPL_INT_ATTR(nsHTMLOptionElement, Index, index)
NS_IMPL_BOOL_ATTR(nsHTMLOptionElement, Disabled, disabled)
NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Label, label)
NS_IMPL_STRING_ATTR(nsHTMLOptionElement, Value, value)
NS_IMETHODIMP
nsHTMLOptionElement::GetDefaultSelected(PRBool* aDefaultSelected)
{
nsHTMLValue val;
nsresult rv = mInner.GetHTMLAttribute(nsHTMLAtoms::selected, val);
*aDefaultSelected = (NS_CONTENT_ATTR_NOT_THERE != rv);
return NS_OK;
}
NS_IMETHODIMP
nsHTMLOptionElement::SetDefaultSelected(PRBool aDefaultSelected)
{
nsHTMLValue empty(eHTMLUnit_Empty);
if (aDefaultSelected) {
return mInner.SetHTMLAttribute(nsHTMLAtoms::selected, empty, PR_TRUE);
} else {
mInner.UnsetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::selected, PR_TRUE);
return NS_OK;
}
}
NS_IMETHODIMP
nsHTMLOptionElement::StringToAttribute(nsIAtom* aAttribute,
const nsString& aValue,
@ -273,3 +318,44 @@ nsHTMLOptionElement::GetStyleHintForAttributeChange(
nsGenericHTMLElement::SetStyleHintForCommonAttributes(this, aAttribute, aHint);
return NS_OK;
}
// Options don't have frames, so get the select frame.
nsresult nsHTMLOptionElement::GetPrimaryFrame(nsIFormControlFrame *&aIFormControlFrame)
{
// Get the containing element.
nsresult res = NS_NOINTERFACE;
nsIDOMNode* parentNode = nsnull;
nsresult gotParent = this->GetParentNode(&parentNode);
if (NS_OK == gotParent) {
nsIDOMHTMLSelectElement* selectElement = nsnull;
// XXX Optgroups: if this is not NS_OK then we need to GetParentNode again.
nsresult isSelect = parentNode->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&selectElement);
if (NS_OK == isSelect) {
nsIContent* selectContent = nsnull;
nsresult gotContent = selectElement->QueryInterface(kIContentIID, (void**)&selectContent);
if (NS_OK == gotContent) {
nsIDocument* doc = nsnull;
// Get the document
if (NS_OK == GetDocument(doc)) {
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
if (nsnull != presShell) {
nsIFrame *frame = nsnull;
presShell->GetPrimaryFrameFor(selectContent, frame);
if (nsnull != frame) {
res = frame->QueryInterface(kIFormControlFrameIID, (void**)&aIFormControlFrame);
}
NS_RELEASE(presShell);
}
NS_RELEASE(doc);
}
NS_RELEASE(selectContent);
}
NS_RELEASE(selectElement);
}
NS_RELEASE(parentNode);
}
return res;
}

Просмотреть файл

@ -35,11 +35,18 @@
#include "nsIHTMLAttributes.h"
#include "nsIDOMHTMLOptionElement.h"
// Notify/query select frame for selectedIndex
#include "nsIFormControlFrame.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
#include "nsIFrame.h"
static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID);
static NS_DEFINE_IID(kIDOMHTMLFormElementIID, NS_IDOMHTMLFORMELEMENT_IID);
static NS_DEFINE_IID(kIFormControlIID, NS_IFORMCONTROL_IID);
static NS_DEFINE_IID(kIFormIID, NS_IFORM_IID);
static NS_DEFINE_IID(kIFormControlFrameIID, NS_IFORMCONTROLFRAME_IID);
class nsHTMLSelectElement;
@ -137,6 +144,9 @@ protected:
nsIWidget* mWidget; // XXX this needs to go away when FindFrameWithContent is efficient
nsIForm* mForm;
nsOptionList* mOptions;
// Return the primary frame associated with this content
nsresult GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame);
};
@ -304,7 +314,42 @@ nsHTMLSelectElement::GetLength(PRUint32* aLength)
}
}
NS_IMPL_INT_ATTR(nsHTMLSelectElement, SelectedIndex, selectedindex)
//NS_IMPL_INT_ATTR(nsHTMLSelectElement, SelectedIndex, selectedindex)
NS_IMETHODIMP
nsHTMLSelectElement::GetSelectedIndex(PRInt32* aValue)
{
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
nsString value;
formControlFrame->GetProperty(nsHTMLAtoms::selectedindex, value);
NS_RELEASE(formControlFrame);
if (value.Length() > 0) {
PRInt32 retval = 0;
PRInt32 error = 0;
retval = value.ToInteger(&error, 10); // Convert to integer, base 10
if (!error) {
*aValue = retval;
return NS_OK;
}
}
}
*aValue = -1; // If no selectedIndex was to be had, make it -1 (none selected)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLSelectElement::SetSelectedIndex(PRInt32 aValue)
{
nsIFormControlFrame* formControlFrame = nsnull;
if (NS_OK == GetPrimaryFrame(formControlFrame)) {
nsString value;
value.Append(aValue, 10);
formControlFrame->SetProperty(nsHTMLAtoms::selectedindex, value);
NS_RELEASE(formControlFrame);
}
return NS_OK;
}
NS_IMPL_STRING_ATTR(nsHTMLSelectElement, Value, value)
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Disabled, disabled)
NS_IMPL_BOOL_ATTR(nsHTMLSelectElement, Multiple, multiple)
@ -659,3 +704,26 @@ nsHTMLSelectElement::GetStyleHintForAttributeChange(
nsGenericHTMLElement::SetStyleHintForCommonAttributes(this, aAttribute, aHint);
return NS_OK;
}
nsresult
nsHTMLSelectElement::GetPrimaryFrame(nsIFormControlFrame *&aFormControlFrame)
{
nsIDocument* doc = nsnull;
nsresult res = NS_NOINTERFACE;
// Get the document
if (NS_OK == GetDocument(doc)) {
// Get presentation shell 0
nsIPresShell* presShell = doc->GetShellAt(0);
if (nsnull != presShell) {
nsIFrame *frame = nsnull;
presShell->GetPrimaryFrameFor(this, frame);
if (nsnull != frame) {
res = frame->QueryInterface(kIFormControlFrameIID, (void**)&aFormControlFrame);
}
NS_RELEASE(presShell);
}
NS_RELEASE(doc);
}
return res;
}

Просмотреть файл

@ -117,9 +117,9 @@ public:
virtual void MouseClicked(nsIPresContext* aPresContext);
// nsIFormControLFrame
// nsIFormControLFrame
NS_IMETHOD SetProperty(nsIAtom* aName, const nsString& aValue);
NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue);
NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue);
protected:
PRUint32 mNumRows;
@ -138,6 +138,18 @@ protected:
PRBool mIsComboBox;
PRBool mOptionsAdded;
// Store the state of the options in a local array whether the widget is
// GFX-rendered or not. This is used to detect changes in MouseClicked
PRUint32 mNumOptions;
PRBool* mOptionSelected;
// Accessor methods for mOptionsSelected and mNumOptions
void GetOptionSelected(PRUint32 index, PRBool* aValue);
void SetOptionSelected(PRUint32 index, PRBool aValue);
// Free our locally cached option array
~nsSelectControlFrame();
};
nsresult
@ -156,6 +168,15 @@ nsSelectControlFrame::nsSelectControlFrame()
mIsComboBox = PR_FALSE;
mOptionsAdded = PR_FALSE;
mNumRows = 0;
mNumOptions = 0;
mOptionSelected = nsnull;
}
// XXX is this the right way to clean up?
nsSelectControlFrame::~nsSelectControlFrame()
{
if (mOptionSelected)
delete mOptionSelected;
}
nscoord
@ -487,6 +508,14 @@ nsSelectControlFrame::PostCreateWidget(nsIPresContext* aPresContext,
options->GetLength(&numOptions);
nsIDOMNode* node;
nsIDOMHTMLOptionElement* option;
// Initialize the locally cached numOptions and optionSelected array.
// The values of the optionsSelected array are filled in by Reset()
mNumOptions = numOptions;
if ((numOptions > 0) && (mOptionSelected == nsnull)) {
mOptionSelected = new PRBool[numOptions];
}
for (PRUint32 i = 0; i < numOptions; i++) {
options->Item(i, &node);
if (node) {
@ -535,6 +564,7 @@ nsSelectControlFrame::GetMaxNumValues()
nsIDOMHTMLCollection* options = GetOptions();
if (options) {
options->GetLength(&length);
NS_RELEASE(options);
}
return (PRInt32)length; // XXX fix return on GetMaxNumValues
} else {
@ -629,14 +659,17 @@ nsSelectControlFrame::Reset()
nsIDOMHTMLOptionElement* option = GetOption(*options, i);
if (option) {
PRBool selected = PR_FALSE;
option->GetSelected(&selected);
option->SetDefaultSelected(selected); // Hmmm, the meaning seems reversed here...
// Cache the state of each option locally
option->GetDefaultSelected(&selected);
SetOptionSelected(i, selected);
// Store the index of each option in the DOM
option->SetIndex(i);
if (selected) {
listWidget->SelectItem(i);
if (selectedIndex < 0) selectedIndex = i; // First selected index in multiple
if (!multiple) { // Optimization
break;
}
if (selectedIndex < 0)
selectedIndex = i;
}
NS_RELEASE(option);
}
@ -645,18 +678,10 @@ nsSelectControlFrame::Reset()
// if none were selected, select 1st one if we are a combo box
if (mIsComboBox && (numOptions > 0) && (selectedIndex < 0)) {
selectedIndex = 0;
listWidget->SelectItem(selectedIndex);
listWidget->SelectItem(0);
}
NS_RELEASE(listWidget);
NS_RELEASE(options);
// reflect the selectedIndex into the content model
if (selectedIndex >= 0) {
nsIDOMHTMLSelectElement* selectElement = GetSelect();
selectElement->SetSelectedIndex(selectedIndex);
NS_RELEASE(selectElement);
}
}
@ -906,96 +931,58 @@ nsSelectControlFrame::MouseClicked(nsIPresContext* aPresContext)
nsIListWidget* listWidget;
nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget);
if ((NS_OK == result) && listWidget) {
PRInt32 contentIndex;
PRInt32 viewIndex = listWidget->GetSelectedIndex();
NS_RELEASE(listWidget);
nsIDOMHTMLSelectElement* selectElement = GetSelect();
if (selectElement) {
selectElement->GetSelectedIndex(&contentIndex);
if (contentIndex != viewIndex) {
changed = PR_TRUE;
selectElement->SetSelectedIndex(viewIndex); // Keep content up to date w/ view
}
NS_RELEASE(selectElement);
PRBool wasSelected = PR_FALSE;
GetOptionSelected(viewIndex, &wasSelected);
if (wasSelected = PR_FALSE) {
changed = PR_TRUE;
}
}
} else {
// Get content model options
nsIDOMHTMLCollection* options = GetOptions();
if (!options) {
return;
}
PRUint32 numOptions;
options->GetLength(&numOptions);
// Get the selected option from the view
// Get the selected option from the widget
nsIListBox* listBox;
nsresult result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox);
if (!(NS_OK == result) || !listBox) {
return;
}
PRUint32 numSelected = listBox->GetSelectedCount();
PRInt32* selOptions;
PRInt32* selOptions = nsnull;
if (numSelected >= 0) {
selOptions = new PRInt32[numSelected];
listBox->GetSelectedIndices(selOptions, numSelected);
}
NS_RELEASE(listBox);
// Assume options are sorted in selOptions XXX sort them:pollmann
// XXX Assume options are sorted in selOptions
// Walk through the content option list and synchronize it with the view
PRUint32 selIndex = 0;
PRUint32 nextSel = 0;
if (numSelected > 0) {
if ((nsnull != selOptions) && (numSelected > 0)) {
nextSel = selOptions[selIndex];
}
PRInt32 selectedIndex = -1;
// Step through each option in content model
for (PRUint32 i=0; i < numOptions; i++) {
PRBool selected = PR_FALSE;
nsIDOMHTMLOptionElement* option = GetOption(*options, i);
if (option) {
option->GetDefaultSelected(&selected);
if (i == nextSel) { // If this option is selected in view
if (!selected) { // If not selected in content model
changed = 1;
option->SetDefaultSelected(PR_TRUE); // Meaning reversed: Update contend model
}
// Update selectedIndex to point at first selected option in content model
if (selectedIndex < 0) {
selectedIndex = i;
}
// Step through each option in local cache
for (PRUint32 i=0; i < mNumOptions; i++) {
PRBool selectedInLocalCache = PR_FALSE;
PRBool selectedInView = (i == nextSel);
GetOptionSelected(i, &selectedInLocalCache);
if (selectedInView != selectedInLocalCache) {
changed = 1;
SetOptionSelected(i, selectedInView);
if (selectedInView) {
// Get the next selected option in the view
selIndex++;
if (selIndex < numSelected) {
nextSel = selOptions[selIndex];
}
} else { //not selected in view
if (selected) {
changed = 1;
option->SetDefaultSelected(PR_FALSE); //Meaning reversed: Update content model
}
}
}
NS_RELEASE(option);
}
delete[] selOptions;
NS_RELEASE(options);
// reflect the selectedIndex into the content model
if (selectedIndex >= 0) {
nsIDOMHTMLSelectElement* selectElement = GetSelect();
selectElement->SetSelectedIndex(selectedIndex);
NS_RELEASE(selectElement);
}
}
if (changed) {
@ -1011,13 +998,105 @@ nsSelectControlFrame::MouseClicked(nsIPresContext* aPresContext)
}
}
// Get the selected state from the local cache (not widget)
void nsSelectControlFrame::GetOptionSelected(PRUint32 index, PRBool* aValue)
{
if (nsnull != mOptionSelected) {
if (mNumOptions >= index) {
*aValue = mOptionSelected[index];
return;
}
}
*aValue = PR_FALSE;
}
// Update the locally cached selection state (not widget)
void nsSelectControlFrame::SetOptionSelected(PRUint32 index, PRBool aValue)
{
if (nsnull != mOptionSelected) {
if (mNumOptions >= index) {
mOptionSelected[index] = aValue;
}
}
}
NS_IMETHODIMP nsSelectControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue)
{
if (nsHTMLAtoms::selected == aName) {
return NS_ERROR_INVALID_ARG; // Selected is readonly according to spec.
} else if (nsHTMLAtoms::selectedindex == aName) {
PRInt32 error = 0;
PRInt32 selectedIndex = aValue.ToInteger(&error, 10); // Get index from aValue
if (error) {
return NS_ERROR_INVALID_ARG; // Couldn't convert to integer
} else {
// Update local cache of selected values
for (PRUint32 i=0; i < mNumOptions; i++)
SetOptionSelected(i, PR_FALSE);
SetOptionSelected(selectedIndex, PR_TRUE);
// Update widget
nsIListWidget* listWidget;
nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget);
if ((NS_OK == result) && (nsnull != listWidget)) {
listWidget->Deselect();
listWidget->SelectItem(selectedIndex);
NS_RELEASE(listWidget);
}
}
} else {
return nsFormControlFrame::SetProperty(aName, aValue);
}
return NS_OK;
}
NS_IMETHODIMP nsSelectControlFrame::GetProperty(nsIAtom* aName, nsString& aValue)
{
// Get the selected value of option from local cache (optimization vs. widget)
if (nsHTMLAtoms::selected == aName) {
PRInt32 error = 0;
PRBool selected = PR_FALSE;
PRInt32 index = aValue.ToInteger(&error, 10); // Get index from aValue
if (error == 0)
GetOptionSelected(index, &selected);
if (selected) {
aValue = "1";
} else {
aValue = "0";
}
// For selectedIndex, get the value from the widget
} else if (nsHTMLAtoms::selectedindex == aName) {
PRInt32 selectedIndex = -1;
PRBool multiple;
GetMultiple(&multiple);
if (!multiple) {
nsIListWidget* listWidget;
nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget);
if ((NS_OK == result) && (nsnull != listWidget)) {
selectedIndex = listWidget->GetSelectedIndex();
NS_RELEASE(listWidget);
}
} else {
// Listboxes don't do GetSelectedIndex on windows. Use GetSelectedIndices
nsIListBox* listBox;
nsresult result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox);
if ((NS_OK == result) && (nsnull != listBox)) {
PRUint32 numSelected = listBox->GetSelectedCount();
PRInt32* selOptions = nsnull;
if (numSelected > 0) {
// Could we set numSelected to 1 here? (memory, speed optimization)
selOptions = new PRInt32[numSelected];
listBox->GetSelectedIndices(selOptions, numSelected);
selectedIndex = selOptions[0];
delete[] selOptions;
}
NS_RELEASE(listBox);
}
}
aValue.Append(selectedIndex, 10);
} else {
return nsFormControlFrame::GetProperty(aName, aValue);
}
return NS_OK;
}
}