Stop trying to observe content changes for the selected option, instead rely on getting a combobox reflow if it changed. b=297389 r+sr=roc a=asa

This commit is contained in:
mats.palmgren%bredband.net 2005-06-21 00:00:14 +00:00
parent 83e97bb062
commit 293246508e
6 changed files with 41 additions and 168 deletions

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Mats Palmgren <mats.palmgren@bredband.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -110,18 +111,6 @@ public:
NS_IMETHOD SetSelectedInternal(PRBool aValue, PRBool aNotify);
// nsIContent
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)
{
return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
}
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify);
virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
PRBool aNotify);
virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify);
virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify);
virtual PRInt32 IntrinsicState() const;
protected:
@ -139,11 +128,6 @@ protected:
*/
void GetSelect(nsIDOMHTMLSelectElement **aSelectElement) const;
/**
* Notify the frame that the option text or value or label has changed.
*/
void NotifyTextChanged();
PRPackedBool mIsInitialized;
PRPackedBool mIsSelected;
};
@ -407,9 +391,6 @@ nsHTMLOptionElement::SetText(const nsAString& aText)
rv = domText->SetData(aText);
if (NS_SUCCEEDED(rv)) {
// If we used an existing node, the notification will not happen (the
// notification typically happens in AppendChildTo).
NotifyTextChanged();
usedExistingTextNode = PR_TRUE;
}
@ -430,70 +411,6 @@ nsHTMLOptionElement::SetText(const nsAString& aText)
return rv;
}
void
nsHTMLOptionElement::NotifyTextChanged()
{
// No need to flush here, if there's no frame yet we don't need to
// force it to be created just to update the selection in it.
nsIFormControlFrame* fcFrame = GetSelectFrame();
if (fcFrame) {
nsISelectControlFrame* selectFrame = nsnull;
CallQueryInterface(fcFrame, &selectFrame);
if (selectFrame) {
selectFrame->OnOptionTextChanged(this);
}
}
}
nsresult
nsHTMLOptionElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify)
{
nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
aValue, aNotify);
if (NS_SUCCEEDED(rv) && aNotify && aName == nsHTMLAtoms::label &&
aNameSpaceID == kNameSpaceID_None) {
// XXX Why does this only happen to the combobox? and what about
// when the text gets set and label is blank?
NotifyTextChanged();
}
return rv;
}
//
// Override nsIContent children changing methods so we can detect when our text
// is changing
//
nsresult
nsHTMLOptionElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
PRBool aNotify)
{
nsresult rv = nsGenericHTMLElement::InsertChildAt(aKid, aIndex, aNotify);
NotifyTextChanged();
return rv;
}
nsresult
nsHTMLOptionElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
{
nsresult rv = nsGenericHTMLElement::AppendChildTo(aKid, aNotify);
NotifyTextChanged();
return rv;
}
nsresult
nsHTMLOptionElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
{
nsresult rv = nsGenericHTMLElement::RemoveChildAt(aIndex, aNotify);
NotifyTextChanged();
return rv;
}
PRInt32
nsHTMLOptionElement::IntrinsicState() const
{

View File

@ -99,17 +99,13 @@ static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
class RedisplayTextEvent : public PLEvent
{
public:
RedisplayTextEvent(nsComboboxControlFrame* aComboboxControlFrame,
const nsAString& aTextToDisplay);
RedisplayTextEvent(nsComboboxControlFrame* aComboboxControlFrame);
void HandleEvent()
{
NS_STATIC_CAST(nsComboboxControlFrame*, owner) ->
HandleRedisplayTextEvent(mTextToDisplay);
HandleRedisplayTextEvent();
}
private:
nsString mTextToDisplay;
};
PR_STATIC_CALLBACK(void*)
@ -132,9 +128,7 @@ DestroyRedisplayTextPLEvent(PLEvent* aEvent)
delete event;
}
RedisplayTextEvent::RedisplayTextEvent(nsComboboxControlFrame* aComboboxControlFrame,
const nsAString& aTextToDisplay)
: mTextToDisplay(aTextToDisplay)
RedisplayTextEvent::RedisplayTextEvent(nsComboboxControlFrame* aComboboxControlFrame)
{
PL_InitEvent(this, aComboboxControlFrame,
::HandleRedisplayTextPLEvent,
@ -453,23 +447,6 @@ nsComboboxControlFrame::Init(nsPresContext* aPresContext,
return nsAreaFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
}
// Initialize the text string in the combobox using either the current
// selection in the list box or the first item item in the list box.
void
nsComboboxControlFrame::InitTextStr()
{
nsAutoString textToDisplay;
PRInt32 selectedIndex;
mListControlFrame->GetSelectedIndex(&selectedIndex);
if (selectedIndex != -1) {
mListControlFrame->GetOptionText(selectedIndex, textToDisplay);
}
mDisplayedIndex = selectedIndex;
ActuallyDisplayText(textToDisplay, PR_FALSE);
}
//--------------------------------------------------------------
void
nsComboboxControlFrame::InitializeControl(nsPresContext* aPresContext)
@ -1238,6 +1215,17 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
return nsAreaFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
}
// Make sure the displayed text is the same as the selected option, bug 297389.
PRInt32 selectedIndex;
nsAutoString selectedOptionText;
mListControlFrame->GetSelectedIndex(&selectedIndex);
if (selectedIndex != -1) {
mListControlFrame->GetOptionText(selectedIndex, selectedOptionText);
}
if (mDisplayedOptionText != selectedOptionText) {
RedisplayText(selectedIndex);
}
// We should cache this instead getting it everytime
// the default size of the of scrollbar
// that will be the default width of the dropdown button
@ -1783,29 +1771,27 @@ nsresult
nsComboboxControlFrame::RedisplayText(PRInt32 aIndex)
{
// Get the text to display
nsAutoString textToDisplay;
if (aIndex != -1) {
mListControlFrame->GetOptionText(aIndex, textToDisplay);
mListControlFrame->GetOptionText(aIndex, mDisplayedOptionText);
} else {
mDisplayedOptionText.Truncate();
}
mDisplayedIndex = aIndex;
#ifdef DO_REFLOW_DEBUG
char * str = ToNewCString(textToDisplay);
REFLOW_DEBUG_MSG2("RedisplayText %s\n", str);
delete [] str;
#endif
REFLOW_DEBUG_MSG2("RedisplayText \"%s\"\n",
NS_LossyConvertUCS2toASCII(mDisplayedOptionText).get());
// Send reflow command because the new text maybe larger
nsresult rv = NS_OK;
if (mDisplayContent && mEventQueueService) {
// Don't call ActuallyDisplayText(aText,PR_TRUE) directly here since that
// Don't call ActuallyDisplayText(PR_TRUE) directly here since that
// could cause recursive frame construction. See bug 283117 and the comment in
// HandleRedisplayTextEvent() below.
nsCOMPtr<nsIEventQueue> eventQueue;
rv = mEventQueueService->GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
getter_AddRefs(eventQueue));
if (eventQueue) {
RedisplayTextEvent* event = new RedisplayTextEvent(this, textToDisplay);
RedisplayTextEvent* event = new RedisplayTextEvent(this);
if (event) {
// Revoke outstanding events to avoid out-of-order events which could mean
// displaying the wrong text.
@ -1830,7 +1816,7 @@ nsComboboxControlFrame::RedisplayText(PRInt32 aIndex)
}
void
nsComboboxControlFrame::HandleRedisplayTextEvent(const nsAString& aText)
nsComboboxControlFrame::HandleRedisplayTextEvent()
{
// First, make sure that the content model is up to date and we've
// constructed the frames for all our content in the right places.
@ -1848,26 +1834,24 @@ nsComboboxControlFrame::HandleRedisplayTextEvent(const nsAString& aText)
mInRedisplayText = PR_TRUE;
mRedisplayTextEventPosted = PR_FALSE;
ActuallyDisplayText(aText, PR_TRUE);
ActuallyDisplayText(PR_TRUE);
mDisplayFrame->AddStateBits(NS_FRAME_IS_DIRTY);
ReflowDirtyChild(GetPresContext()->PresShell(), mDisplayFrame);
mInRedisplayText = PR_FALSE;
}
nsresult
nsComboboxControlFrame::ActuallyDisplayText(const nsAString& aText, PRBool aNotify)
void
nsComboboxControlFrame::ActuallyDisplayText(PRBool aNotify)
{
if (aText.IsEmpty()) {
if (mDisplayedOptionText.IsEmpty()) {
// Have to use a non-breaking space for line-height calculations
// to be right
static const PRUnichar space = 0xA0;
mDisplayContent->SetText(&space, 1, aNotify);
} else {
mDisplayContent->SetText(aText, aNotify);
mDisplayContent->SetText(mDisplayedOptionText, aNotify);
}
return NS_OK;
}
NS_IMETHODIMP
@ -2112,7 +2096,9 @@ nsComboboxControlFrame::CreateAnonymousContent(nsPresContext* aPresContext,
if (labelContent) {
// set the value of the text node
mDisplayContent.swap(labelContent);
mDisplayContent->SetText(NS_LITERAL_STRING("X"), PR_TRUE);
mDisplayedIndex = -1;
mDisplayedOptionText.Truncate();
ActuallyDisplayText(PR_FALSE);
nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
@ -2286,7 +2272,6 @@ nsComboboxControlFrame::SetInitialChildList(nsPresContext* aPresContext,
mPopupFrames.SetFrames(aChildList);
} else {
rv = nsAreaFrame::SetInitialChildList(aPresContext, aListName, aChildList);
InitTextStr();
for (nsIFrame * child = aChildList; child;
child = child->GetNextSibling()) {
@ -2499,22 +2484,6 @@ void nsComboboxControlFrame::FireValueChangeEvent()
}
}
NS_IMETHODIMP
nsComboboxControlFrame::OnOptionTextChanged(nsIDOMHTMLOptionElement* option)
{
RedisplaySelectedText();
if (mDroppedDown) {
nsCOMPtr<nsISelectControlFrame> selectFrame
= do_QueryInterface(mListControlFrame);
if (selectFrame) {
selectFrame->OnOptionTextChanged(option);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsComboboxControlFrame::OnContentReset()
{

View File

@ -183,7 +183,6 @@ public:
NS_IMETHOD OnOptionSelected(nsPresContext* aPresContext,
PRInt32 aIndex,
PRBool aSelected);
NS_IMETHOD OnOptionTextChanged(nsIDOMHTMLOptionElement* option);
NS_IMETHOD GetDummyFrame(nsIFrame** aFrame);
NS_IMETHOD SetDummyFrame(nsIFrame* aFrame);
NS_IMETHOD OnSetSelectedIndex(PRInt32 aOldIndex, PRInt32 aNewIndex);
@ -242,12 +241,11 @@ protected:
void ShowPopup(PRBool aShowPopup);
void ShowList(nsPresContext* aPresContext, PRBool aShowList);
void SetChildFrameSize(nsIFrame* aFrame, nscoord aWidth, nscoord aHeight);
void InitTextStr();
void CheckFireOnChange();
void FireValueChangeEvent();
nsresult RedisplayText(PRInt32 aIndex);
void HandleRedisplayTextEvent(const nsAString& aText);
nsresult ActuallyDisplayText(const nsAString& aText, PRBool aNotify);
void HandleRedisplayTextEvent();
void ActuallyDisplayText(PRBool aNotify);
nsresult GetPrimaryComboFrame(nsPresContext* aPresContext, nsIContent* aContent, nsIFrame** aFrame);
NS_IMETHOD ToggleList(nsPresContext* aPresContext);
@ -291,6 +289,7 @@ protected:
PRInt32 mRecentSelectedIndex;
PRInt32 mDisplayedIndex;
nsString mDisplayedOptionText;
// make someone to listen to the button. If its programmatically pressed by someone like Accessibility
// then open or close the combo box.

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mats Palmgren <mats.palmgren@bredband.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -41,10 +42,10 @@
#include "nsISupports.h"
// IID for the nsISelectControlFrame class
#define NS_ISELECTCONTROLFRAME_IID \
{ 0x62a3bc8e, 0x1312, 0x42f3, \
{ 0x96, 0x7c, 0x37, 0x0f, 0x16, 0x9a, 0xd3, 0xbf } }
// 62a3bc8e-1312-42f3-967c-370f169ad3bf
// 264dc2f5-1cca-47dd-9ebc-699c430be00a
#define NS_ISELECTCONTROLFRAME_IID \
{ 0x264dc2f5, 0x1cca, 0x47dd, \
{ 0x9e, 0xbc, 0x69, 0x9c, 0x43, 0x0b, 0xe0, 0x0a } }
class nsIDOMHTMLOptionElement;
@ -86,13 +87,6 @@ public:
PRInt32 aIndex,
PRBool aSelected) = 0;
/**
* Notify the frame when an option's text changes
* (We don't pass in the index because it would be expensive for
* the option to figure that out)
*/
NS_IMETHOD OnOptionTextChanged(nsIDOMHTMLOptionElement* option) = 0;
/**
* For the content model to tell if there's a dummy frame or not
*/

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Mats Palmgren <mats.palmgren@bredband.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -1727,13 +1728,6 @@ nsListControlFrame::OnOptionSelected(nsPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
nsListControlFrame::OnOptionTextChanged(nsIDOMHTMLOptionElement* option)
{
return NS_OK;
}
//---------------------------------------------------------
PRIntn
nsListControlFrame::GetSkipSides() const

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mats Palmgren <mats.palmgren@bredband.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -182,7 +183,6 @@ public:
NS_IMETHOD OnOptionSelected(nsPresContext* aPresContext,
PRInt32 aIndex,
PRBool aSelected);
NS_IMETHOD OnOptionTextChanged(nsIDOMHTMLOptionElement* option);
NS_IMETHOD GetDummyFrame(nsIFrame** aFrame);
NS_IMETHOD SetDummyFrame(nsIFrame* aFrame);
NS_IMETHOD OnSetSelectedIndex(PRInt32 aOldIndex, PRInt32 aNewIndex);