diff --git a/mozilla/content/html/content/src/nsHTMLOptionElement.cpp b/mozilla/content/html/content/src/nsHTMLOptionElement.cpp
index d5343e25671..ceeabed20b8 100644
--- a/mozilla/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLOptionElement.cpp
@@ -227,7 +227,9 @@ nsHTMLOptionElement::GetSelected(PRBool* aValue)
*aValue = PR_FALSE;
nsIFormControlFrame* formControlFrame = nsnull;
- GetPrimaryFrame(formControlFrame);
+
+ // DO NOT flush pending reflows here
+ GetPrimaryFrame(formControlFrame, PR_FALSE);
if (formControlFrame) {
PRInt32 indx;
@@ -265,6 +267,7 @@ nsHTMLOptionElement::SetSelected(PRBool aValue)
{
nsIFormControlFrame* fcFrame = nsnull;
+ // DO NOT flush pending reflows here
nsresult result = GetPrimaryFrame(fcFrame, PR_FALSE);
if (NS_SUCCEEDED(result) && fcFrame) {
@@ -278,6 +281,7 @@ nsHTMLOptionElement::SetSelected(PRBool aValue)
GetIndex(&indx);
if (indx >= 0) {
+ // this will flush pending reflows
return selectFrame->SetOptionSelected(indx, aValue);
}
}
diff --git a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
index 5410802a0fe..5e29257c743 100644
--- a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
@@ -514,7 +514,7 @@ nsHTMLSelectElement::GetSelectedIndex(PRInt32* aValue)
{
nsIFormControlFrame* formControlFrame = nsnull;
- nsresult rv = GetPrimaryFrame(this, formControlFrame);
+ nsresult rv = GetPrimaryFrame(this, formControlFrame, PR_FALSE);
if (NS_SUCCEEDED(rv)) {
nsAutoString value;
@@ -637,7 +637,7 @@ nsHTMLSelectElement::SetSelectedIndex(PRInt32 aIndex)
{
nsIFormControlFrame* formControlFrame = nsnull;
- GetPrimaryFrame(this, formControlFrame);
+ GetPrimaryFrame(this, formControlFrame, PR_FALSE);
if (formControlFrame) {
nsAutoString value;
diff --git a/mozilla/layout/forms/nsComboboxControlFrame.cpp b/mozilla/layout/forms/nsComboboxControlFrame.cpp
index f1008bfe19c..4d5513310f9 100644
--- a/mozilla/layout/forms/nsComboboxControlFrame.cpp
+++ b/mozilla/layout/forms/nsComboboxControlFrame.cpp
@@ -2030,24 +2030,14 @@ nsComboboxControlFrame::DoneAddingContent(PRBool aIsDone)
NS_IMETHODIMP
nsComboboxControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
-#ifdef DO_REFLOW_DEBUG
- printf("**********\n*********AddOption: %d\n", aIndex);
+#ifdef DO_REFLOW_DEBUGXX
+ printf("*********AddOption: %d\n", aIndex);
#endif
- nsISelectControlFrame* listFrame = nsnull;
- nsresult rv = mDropdownFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),
- (void**)&listFrame);
- if (NS_SUCCEEDED(rv) && listFrame) {
- rv = listFrame->AddOption(aPresContext, aIndex);
- //PRInt32 index;
- //mListControlFrame->GetSelectedIndex(&index);
- //UpdateSelection(PR_FALSE, PR_TRUE, index);
- NS_RELEASE(listFrame);
+ nsresult rv = NS_ERROR_FAILURE;
+ if (mDropdownFrame) {
+ nsListControlFrame * lcf = NS_STATIC_CAST(nsListControlFrame*, mDropdownFrame);
+ rv = lcf->AddOption(aPresContext, aIndex);
}
- // If we added the first option, we might need to select it.
- // We should call MakeSureSomethingIsSelected here, but since it
- // it changes selection, which currently causes a reframe, and thus
- // deletes the frame out from under the caller, causing a crash. (Bug 17995)
- // XXX MakeSureSomethingIsSelected(aPresContext);
return rv;
}
@@ -2055,16 +2045,11 @@ nsComboboxControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
NS_IMETHODIMP
nsComboboxControlFrame::RemoveOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
- nsISelectControlFrame* listFrame = nsnull;
- nsresult rv = mDropdownFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),
- (void**)&listFrame);
- if (NS_SUCCEEDED(rv) && listFrame) {
- rv = listFrame->RemoveOption(aPresContext, aIndex);
- NS_RELEASE(listFrame);
+ nsresult rv = NS_ERROR_FAILURE;
+ if (mDropdownFrame != nsnull) {
+ nsListControlFrame * lcf = NS_STATIC_CAST(nsListControlFrame*, mDropdownFrame);
+ rv = lcf->RemoveOption(aPresContext, aIndex);
}
- // If we removed the selected option, nothing is selected any more.
- // Restore selection to option 0 if there are options left.
- MakeSureSomethingIsSelected(aPresContext);
return rv;
}
diff --git a/mozilla/layout/forms/nsComboboxControlFrame.h b/mozilla/layout/forms/nsComboboxControlFrame.h
index 0b2414106a6..0f28755755a 100644
--- a/mozilla/layout/forms/nsComboboxControlFrame.h
+++ b/mozilla/layout/forms/nsComboboxControlFrame.h
@@ -177,6 +177,7 @@ public:
NS_IMETHOD GetOptionSelected(PRInt32 aIndex, PRBool* aValue);
NS_IMETHOD DoneAddingContent(PRBool aIsDone);
NS_IMETHOD OptionDisabled(nsIContent * aContent);
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext); // Default to option 0
//nsIStatefulFrame
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
@@ -232,7 +233,6 @@ protected:
void InitTextStr(nsIPresContext* aPresContext, PRBool aUpdate);
nsresult GetPrimaryComboFrame(nsIPresContext* aPresContext, nsIContent* aContent, nsIFrame** aFrame);
NS_IMETHOD ToggleList(nsIPresContext* aPresContext);
- NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext); // Default to option 0
void ReflowCombobox(nsIPresContext * aPresContext,
const nsHTMLReflowState& aReflowState,
diff --git a/mozilla/layout/forms/nsISelectControlFrame.h b/mozilla/layout/forms/nsISelectControlFrame.h
index 55f2b25e7b1..0ea67706f16 100644
--- a/mozilla/layout/forms/nsISelectControlFrame.h
+++ b/mozilla/layout/forms/nsISelectControlFrame.h
@@ -72,6 +72,11 @@ public:
NS_IMETHOD OptionDisabled(nsIContent * aContent) = 0;
+ /**
+ * This only applies to Comboboxes, no-op for ListBoxes
+ */
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext) = 0;
+
};
#endif
diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp
index 37e3151a2f2..9a4edfb9ef0 100644
--- a/mozilla/layout/forms/nsListControlFrame.cpp
+++ b/mozilla/layout/forms/nsListControlFrame.cpp
@@ -62,7 +62,9 @@
#include "nsISelectElement.h"
#include "nsIPrivateDOMEvent.h"
-//static NS_DEFINE_IID(kBlockFrameCID, NS_BLOCK_FRAME_CID);
+// Timer Includes
+#include "nsITimer.h"
+#include "nsITimerCallback.h"
// Constants
const nscoord kMaxDropDownRows = 20; // This matches the setting for 4.x browsers
@@ -207,6 +209,160 @@ if (aReflowState.mComputedWidth != NS_UNCONSTRAINEDSIZE) { \
//-- Done with macros
//------------------------------------------------------
+//---------------------------------------------------
+//-- Update Timer Stuff
+//---------------------------------------------------
+class nsSelectUpdateTimer : public nsITimerCallback
+{
+public:
+
+ NS_DECL_ISUPPORTS
+
+ nsSelectUpdateTimer()
+ : mPresContext(nsnull), mDelay(0), mHasBeenNotified(PR_FALSE),
+ mItemsAdded(PR_FALSE), mItemsRemoved(PR_FALSE), mItemsInxSet(PR_FALSE),
+ mRemovedSelectedIndex(PR_FALSE)
+ {
+ NS_INIT_ISUPPORTS();
+ }
+
+ virtual ~nsSelectUpdateTimer();
+
+ NS_IMETHOD_(void) Notify(nsITimer *timer);
+
+ // Additional Methods
+ nsresult Start(nsIPresContext *aPresContext)
+ {
+ mPresContext = aPresContext;
+ //mHasBeenNotified = PR_FALSE;
+
+ if (!mTimer) {
+ nsresult result;
+ mTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
+
+ if (NS_FAILED(result))
+ return result;
+
+ }
+
+ if (mHasBeenNotified) {
+ mItemsAdded = PR_FALSE;
+ mItemsRemoved = PR_FALSE;
+ mItemsInxSet = PR_FALSE;
+ mHasBeenNotified = PR_FALSE;
+ mRemovedSelectedIndex = PR_FALSE;
+ mInxArray.Clear();
+ }
+
+ return mTimer->Init(this, mDelay);
+ }
+
+ void Init(nsListControlFrame *aList, PRUint32 aDelay) { mListControl = aList; mDelay = aDelay; }
+ void Stop() { if (mTimer) mTimer->Cancel(); }
+
+ void AdjustIndexes(PRBool aInserted, PRInt32 aInx)
+ {
+ // remove the index from the list
+ if (!aInserted) {
+ PRInt32 inx = (PRInt32)mInxArray.IndexOf((void*)aInx);
+ if (inx > -1) {
+ mInxArray.RemoveElementAt(inx);
+ }
+ }
+
+ PRInt32 count = mInxArray.Count();
+ for (PRInt32 i=0;i aInx) {
+ mInxArray.ReplaceElementAt((void*)(inx+(aInserted?1:-1)), i);
+ }
+ }
+ }
+
+ void ItemAdded(PRInt32 aInx, PRInt32 aNumItems)
+ {
+ mItemsAdded = PR_TRUE;
+ if (mInxArray.Count() > 0 && aInx <= aNumItems-1) {
+ AdjustIndexes(PR_TRUE, aInx);
+ }
+ }
+
+ void ItemRemoved(PRInt32 aInx, PRInt32 aNumItems)
+ {
+ mItemsRemoved = PR_TRUE;
+ if (mInxArray.Count() > 0 && aInx <= aNumItems) {
+ AdjustIndexes(PR_FALSE, aInx);
+ }
+ }
+
+ void ItemIndexSet(PRInt32 aInx)
+ {
+ mItemsInxSet = PR_TRUE;
+ mInxArray.AppendElement((void*)aInx);
+ }
+
+ PRPackedBool HasBeenNotified() { return mHasBeenNotified; }
+ void SetRemovedSelectedIndex() { mRemovedSelectedIndex = PR_TRUE; }
+ PRPackedBool RemovedSelectedIndex() { return mRemovedSelectedIndex; }
+
+private:
+ nsListControlFrame * mListControl;
+ nsCOMPtr mTimer;
+ nsIPresContext* mPresContext;
+ PRUint32 mDelay;
+ PRPackedBool mHasBeenNotified;
+
+ PRPackedBool mItemsAdded;
+ PRPackedBool mItemsRemoved;
+ PRPackedBool mItemsInxSet;
+ PRPackedBool mRemovedSelectedIndex;
+ nsVoidArray mInxArray;
+
+};
+
+NS_IMPL_ADDREF(nsSelectUpdateTimer)
+NS_IMPL_RELEASE(nsSelectUpdateTimer)
+NS_IMPL_QUERY_INTERFACE1(nsSelectUpdateTimer, nsITimerCallback)
+
+nsresult NS_NewUpdateTimer(nsSelectUpdateTimer **aResult)
+{
+ if (!aResult)
+ return NS_ERROR_NULL_POINTER;
+
+ *aResult = (nsSelectUpdateTimer*) new nsSelectUpdateTimer;
+
+ if (!aResult)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(*aResult);
+
+ return NS_OK;
+}
+
+// nsITimerCallback
+NS_IMETHODIMP_(void) nsSelectUpdateTimer::Notify(nsITimer *timer)
+{
+ if (mPresContext && mListControl && !mHasBeenNotified) {
+ mHasBeenNotified = PR_TRUE;
+ if (mItemsAdded || mItemsInxSet) {
+ mListControl->ResetList(mPresContext, &mInxArray);
+ } else {
+ mListControl->ItemsHaveBeenRemoved(mPresContext);
+ }
+ }
+}
+
+nsSelectUpdateTimer::~nsSelectUpdateTimer()
+{
+ if (mTimer) {
+ mTimer->Cancel();
+ }
+}
+
+//---------------------------------------------------
+//-- DONE: Update Timer Stuff
+//---------------------------------------------------
+
//---------------------------------------------------------
nsListControlFrame::nsListControlFrame()
@@ -225,9 +381,6 @@ nsListControlFrame::nsListControlFrame()
mDelayedIndexSetting = kNothingSelected;
mDelayedValueSetting = PR_FALSE;
- mSelectionCache = new nsVoidArray();
- mSelectionCacheLength = 0;
-
mIsAllContentHere = PR_FALSE;
mIsAllFramesHere = PR_FALSE;
mHasBeenInitialized = PR_FALSE;
@@ -245,6 +398,8 @@ nsListControlFrame::nsListControlFrame()
mOverrideReflowOpt = PR_FALSE;
mPassId = 0;
+ mUpdateTimer = nsnull;
+
REFLOW_COUNTER_INIT()
}
@@ -252,6 +407,10 @@ nsListControlFrame::nsListControlFrame()
nsListControlFrame::~nsListControlFrame()
{
REFLOW_COUNTER_DUMP("nsLCF");
+ if (mUpdateTimer != nsnull) {
+ StopUpdateTimer();
+ delete mUpdateTimer;
+ }
mComboboxFrame = nsnull;
if (mFormFrame) {
@@ -259,9 +418,6 @@ nsListControlFrame::~nsListControlFrame()
mFormFrame = nsnull;
}
NS_IF_RELEASE(mPresContext);
- if (mSelectionCache) {
- delete mSelectionCache;
- }
}
// for Bug 47302 (remove this comment later)
@@ -531,7 +687,7 @@ nsListControlFrame::Reflow(nsIPresContext* aPresContext,
}
if (mIsAllFramesHere && !mHasBeenInitialized) {
mHasBeenInitialized = PR_TRUE;
- Reset(aPresContext);
+ ResetList(aPresContext);
}
}
@@ -1068,41 +1224,16 @@ nsListControlFrame::ForceRedraw(nsIPresContext* aPresContext)
void
nsListControlFrame::DisplaySelected(nsIContent* aContent)
{
- //XXX: This is temporary. It simulates psuedo states by using a attribute selector on
- // -moz-option-selected in the ua.css style sheet. This will not be needed when
- // The event state manager supports selected states. KMM
- nsAutoString attr;
- nsresult rv = aContent->GetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, attr);
- if (rv != NS_CONTENT_ATTR_NOT_THERE)
- return;
-
- if (PR_TRUE == mIsAllFramesHere) {
- aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), PR_TRUE);
- //ForceRedraw();
- } else {
- aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), PR_FALSE);
- }
+ // ignore return value, not much we can do if it fails
+ aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), mIsAllFramesHere);
}
//---------------------------------------------------------
void
nsListControlFrame::DisplayDeselected(nsIContent* aContent)
{
- //XXX: This is temporary. It simulates psuedo states by using a attribute selector on
- // -moz-option-selected in the ua.css style sheet. This will not be needed when
- // The event state manager is functional. KMM
- nsAutoString attr;
- nsresult rv = aContent->GetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, attr);
- if (rv == NS_CONTENT_ATTR_NOT_THERE)
- return;
-
- if (PR_TRUE == mIsAllFramesHere) {
- aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, PR_TRUE);
- //ForceRedraw();
- } else {
- aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, PR_FALSE);
- }
-
+ // ignore return value, not much we can do if it fails
+ aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, mIsAllFramesHere);
}
@@ -1339,7 +1470,7 @@ nsListControlFrame::MultipleSelection(PRBool aIsShift, PRBool aIsControl)
ClearSelection();
}
}
-#ifdef DEBUG_rods
+#ifdef DEBUG_rodsX
printf("mSelectedIndex: %d\n", mSelectedIndex);
printf("mOldSelectedIndex: %d\n", mOldSelectedIndex);
printf("mStartExtendedIndex: %d\n", mStartExtendedIndex);
@@ -1555,7 +1686,7 @@ nsListControlFrame::SetInitialChildList(nsIPresContext* aPresContext,
// If all content and frames are here
// the reset/initialize
if (CheckIfAllFramesHere()) {
- Reset(aPresContext);
+ ResetList(aPresContext);
mHasBeenInitialized = PR_TRUE;
}
}*/
@@ -1801,7 +1932,7 @@ nsListControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection,
return status;
}
-
+static int cnt = 0;
//---------------------------------------------------------
// For a given piece of content, it determines whether the
// content (an option) is selected or not
@@ -1837,7 +1968,10 @@ nsListControlFrame::IsContentSelectedByIndex(PRInt32 aIndex)
// being selected or not selected
//---------------------------------------------------------
void
-nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
+nsListControlFrame::SetContentSelected(PRInt32 aIndex,
+ PRBool aSelected,
+ PRBool aDoScrollTo,
+ nsIPresShell * aPresShell)
{
if (aIndex == kNothingSelected) {
return;
@@ -1858,26 +1992,47 @@ nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
nsIContent* content = GetOptionContent(aIndex);
NS_ASSERTION(content != nsnull, "Content should not be null!");
- if (content != nsnull) {
- nsCOMPtr presShell;
- mPresContext->GetShell(getter_AddRefs(presShell));
- if (presShell) {
- nsIFrame * childframe;
- nsresult result = presShell->GetPrimaryFrameFor(content, &childframe);
- if (NS_SUCCEEDED(result) && childframe != nsnull) {
- if (aSelected) {
- DisplaySelected(content);
- // Now that it is selected scroll to it
- ScrollToFrame(content);
+ nsIPresShell* presShell;
+ if (aPresShell == nsnull) {
+ mPresContext->GetShell(&presShell);
+ } else {
+ presShell = aPresShell;
+ NS_ADDREF(presShell);
+ }
+ SetContentSelected(aIndex, content, aSelected, aDoScrollTo, presShell);
+ NS_RELEASE(content);
+ NS_RELEASE(presShell);
+}
+
+void
+nsListControlFrame::SetContentSelected(PRInt32 aIndex,
+ nsIContent * aContent,
+ PRBool aSelected,
+ PRBool aDoScrollTo,
+ nsIPresShell * aPresShell)
+{
+ if (aContent != nsnull) {
+ PRBool isSelected = IsContentSelected(aContent);
+ //if (aSelected != isSelected) {
+ if (aPresShell) {
+ nsIFrame * childframe;
+ nsresult result = aPresShell->GetPrimaryFrameFor(aContent, &childframe);
+ if (NS_SUCCEEDED(result) && childframe != nsnull) {
+ if (aSelected) {
+ DisplaySelected(aContent);
+ // Now that it is selected scroll to it
+ if (aDoScrollTo) {
+ ScrollToFrame(aContent);
+ }
+ } else {
+ DisplayDeselected(aContent);
+ }
} else {
- DisplayDeselected(content);
+ mDelayedIndexSetting = aIndex;
+ mDelayedValueSetting = aSelected;
}
- } else {
- mDelayedIndexSetting = aIndex;
- mDelayedValueSetting = aSelected;
}
- }
- NS_RELEASE(content);
+ //}
}
}
@@ -1888,6 +2043,9 @@ nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
nsresult
nsListControlFrame::Deselect()
{
+
+ /* This code works fine but it
+ * isn't quite as efficient as the code below
PRInt32 i;
PRInt32 max = 0;
if (NS_SUCCEEDED(GetNumberOfOptions(&max))) {
@@ -1895,6 +2053,24 @@ nsListControlFrame::Deselect()
SetContentSelected(i, PR_FALSE);
}
}
+ */
+
+ nsCOMPtr options = getter_AddRefs(GetOptions(mContent));
+ if (options) {
+ PRUint32 length = 0;
+ options->GetLength(&length);
+ PRUint32 i;
+ for (i=0;i node;
+ if (NS_SUCCEEDED(options->Item(i, getter_AddRefs(node)))) {
+ nsCOMPtr content(do_QueryInterface(node));
+ if (content && IsContentSelected(content)) {
+ DisplayDeselected(content);
+ }
+ }
+ }
+ }
+
mSelectedIndex = kNothingSelected;
return NS_OK;
@@ -1966,9 +2142,10 @@ nsListControlFrame::GetMaxNumValues()
// those values as determined by the original HTML
//---------------------------------------------------------
void
-nsListControlFrame::Reset(nsIPresContext* aPresContext)
+nsListControlFrame::ResetList(nsIPresContext* aPresContext, nsVoidArray * aInxList)
{
- REFLOW_DEBUG_MSG("LBX::Reset\n");
+
+ REFLOW_DEBUG_MSG("LBX::ResetList\n");
// if all the frames aren't here
// don't bother reseting
@@ -1995,12 +2172,16 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
PRBool multiple;
GetMultiple(&multiple);
- Deselect();
-
// Clear the cache and set the default selections
- // if we havn't been restored
- mSelectionCache->Clear();
- mSelectionCacheLength = 0;
+ // if we haven't been restored
+ nsCOMPtr presShell;
+ aPresContext->GetShell(getter_AddRefs(presShell));
+
+ // This code has been reworked to make it as efficient as possible.
+ // In the case, where it is a single select, we do not select any items
+ // while they are being reset, we wait until the end and set the selected
+ // item once. This also means that when it is a multiple select
+ // we set the selected item twice, but the cost at that point is very low.
PRUint32 i;
for (i = 0; i < numOptions; i++) {
nsCOMPtr option = getter_AddRefs(GetOption(*options, i));
@@ -2009,31 +2190,39 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
if (!hasBeenRestored) {
option->GetDefaultSelected(&selected);
}
+ if (aInxList) {
+ selected = aInxList->IndexOf((void*)i) > -1;
+ }
- mSelectionCache->AppendElement((void*)selected);
- mSelectionCacheLength++;
-
+ nsCOMPtr content(do_QueryInterface(option));
if (selected) {
- if (mSelectedIndex == kNothingSelected ||
- (mSelectedIndex != kNothingSelected && multiple)) {
- mSelectedIndex = i;
- SetContentSelected(i, PR_TRUE);
- if (multiple) {
- mStartExtendedIndex = i;
- if (mEndExtendedIndex == kNothingSelected) {
- mEndExtendedIndex = i;
- }
+ NS_ASSERTION(content, "There is no way this could be nsnull");
+
+ mSelectedIndex = i;
+
+ if (multiple) {
+ SetContentSelected(i, content, PR_TRUE, PR_FALSE, presShell);
+ mStartExtendedIndex = i;
+ if (mEndExtendedIndex == kNothingSelected) {
+ mEndExtendedIndex = i;
}
- } else {
- SetContentSelected(mSelectedIndex, PR_FALSE);
- mSelectionCache->ReplaceElementAt((void*)PR_FALSE, mSelectedIndex);
- mSelectedIndex = i;
- SetContentSelected(i, PR_TRUE);
}
+ } else if (IsContentSelected(content)){
+ SetContentSelected(i, content, PR_FALSE, PR_FALSE, presShell);
}
}
}
+ // To make the final adjustments
+ // set the selected item to true and scroll to it
+ PRUint32 indexToSelect;
+ if (multiple) {
+ indexToSelect = mStartExtendedIndex;
+ } else {
+ indexToSelect = mSelectedIndex;
+ }
+ SetContentSelected(indexToSelect, PR_TRUE, PR_TRUE, presShell);
+
// Ok, so we were restored, now set the last known selections from the restore state.
if (hasBeenRestored) {
nsCOMPtr supp;
@@ -2060,7 +2249,6 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
if (NS_SUCCEEDED(res)) {
mSelectedIndex = j;
SetContentSelected(j, PR_TRUE);// might want to use ToggleSelection
- mSelectionCache->ReplaceElementAt((void*)PR_TRUE, j);
if (multiple) {
mStartExtendedIndex = j;
if (mEndExtendedIndex == kNothingSelected) {
@@ -2376,7 +2564,7 @@ nsListControlFrame::DoneAddingContent(PRBool aIsDone)
// if all the frames are now present we can initalize
if (CheckIfAllFramesHere() && mPresContext) {
mHasBeenInitialized = PR_TRUE;
- Reset(mPresContext);
+ ResetList(mPresContext);
}
}
}
@@ -2387,10 +2575,15 @@ nsListControlFrame::DoneAddingContent(PRBool aIsDone)
NS_IMETHODIMP
nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
+ StopUpdateTimer();
+
#ifdef DO_REFLOW_DEBUG
printf("---- Id: %d nsLCF %p Added Option %d\n", mReflowId, this, aIndex);
#endif
+ PRInt32 numOptions;
+ GetNumberOfOptions(&numOptions);
+
if (!mIsAllContentHere) {
nsCOMPtr element(do_QueryInterface(mContent));
if (element) {
@@ -2399,8 +2592,6 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
mIsAllFramesHere = PR_FALSE;
mHasBeenInitialized = PR_FALSE;
} else {
- PRInt32 numOptions;
- GetNumberOfOptions(&numOptions);
mIsAllFramesHere = aIndex == numOptions-1;
}
}
@@ -2410,56 +2601,10 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
return NS_OK;
}
- PRInt32 oldSelection = mSelectedIndex;
-
- // Adding an option to the select can cause a change in selection
- // if the new option has it's selected attribute set.
- // this code checks to see if it does
- // if so then it resets the entire selection of listbox
- PRBool wasReset = PR_FALSE;
- nsCOMPtr options = getter_AddRefs(GetOptions(mContent));
- if (options) {
- nsCOMPtr option = getter_AddRefs(GetOption(*options, aIndex));
- if (option) {
- PRBool selected = PR_FALSE;
- option->GetDefaultSelected(&selected);
-
- mSelectionCache->InsertElementAt((void*)selected, aIndex);
- mSelectionCacheLength++;
-
- if (selected) {
- Reset(aPresContext); // this sets mSelectedIndex to the defaulted selection
- wasReset = PR_TRUE;
- }
-
-#ifdef DEBUG_rods
- {
- nsAutoString text;
- text.AssignWithConversion("No Value");
- nsresult rv = option->GetLabel(text);
- if (NS_CONTENT_ATTR_NOT_THERE == rv || 0 == text.Length()) {
- option->GetText(text);
- }
- printf("|||||this %p Index: %d [%s] CB: %p\n", this, aIndex, text.ToNewCString(), mComboboxFrame); //leaks
- }
-#endif
- }
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ mUpdateTimer->ItemAdded(aIndex, numOptions);
}
-
- if (!wasReset) {
- GetSelectedIndexFromDOM(&mSelectedIndex); // comes from the DOM
- }
-
- // if selection changed because of the new option being added
- // notify the combox if necessary
- if (mComboboxFrame != nsnull) {
- if (mSelectedIndex == kNothingSelected) {
- mComboboxFrame->MakeSureSomethingIsSelected(mPresContext);
- } else if (oldSelection != mSelectedIndex) {
- mComboboxFrame->UpdateSelection(PR_FALSE, PR_TRUE, mSelectedIndex); // don't dispatch event
- }
- }
-
return NS_OK;
}
@@ -2467,25 +2612,29 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
NS_IMETHODIMP
nsListControlFrame::RemoveOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
- PRInt32 numOptions;
- GetNumberOfOptions(&numOptions);
-
-// PRInt32 oldSelectedIndex = mSelectedIndex;
- GetSelectedIndexFromDOM(&mSelectedIndex); // comes from the DOM
-
- // Select the new selectedIndex
- // Don't need to deselect option as it is being removed anyway.
- if (mSelectedIndex >= 0) {
- SetContentSelected(mSelectedIndex, PR_TRUE);
+ StopUpdateTimer();
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ PRInt32 numOptions;
+ GetNumberOfOptions(&numOptions);
+ mUpdateTimer->ItemRemoved(aIndex, numOptions);
}
- mSelectionCache->RemoveElementAt(aIndex);
- mSelectionCacheLength--;
+ // Check to see which index is being removed
+ // if the current index is being removed, remember that
+ // if the index is less then the current index
+ // then decrement the current selected index
+ if (aIndex == mSelectedIndex) {
+ mUpdateTimer->SetRemovedSelectedIndex();
+ mSelectedIndex = kNothingSelected;
+
+ } if (aIndex < mSelectedIndex) {
+ mSelectedIndex--;
+ }
return NS_OK;
}
-#ifdef FIX_FOR_BUG_50376
//-------------------------------------------------------------------
nsresult nsListControlFrame::GetPresStateAndValueArray(nsISupportsArray ** aSuppArray)
{
@@ -2596,8 +2745,6 @@ nsresult nsListControlFrame::SetOptionIntoPresState(nsISupportsArray * aSuppArra
return res;
}
-#endif // FIX_FOR_BUG_50376
-
//---------------------------------------------------------
// Select the specified item in the listbox using control logic.
// If it a single selection listbox the previous selection will be
@@ -2605,11 +2752,9 @@ nsresult nsListControlFrame::SetOptionIntoPresState(nsISupportsArray * aSuppArra
NS_IMETHODIMP
nsListControlFrame::SetOptionSelected(PRInt32 aIndex, PRBool aValue)
{
-#ifdef FIX_FOR_BUG_50376
if (!mIsAllFramesHere && !mHasBeenInitialized) {
return SetSelectionInPresState(aIndex, aValue);
}
-#endif // FIX_FOR_BUG_50376
PRBool multiple;
nsresult rv = GetMultiple(&multiple);
@@ -2646,49 +2791,16 @@ nsListControlFrame::UpdateSelection(PRBool aDoDispatchEvent, PRBool aForceUpdate
nsresult rv = NS_OK;
PRBool changed = PR_FALSE;
- // Paranoia: check if cache is up to date with content
- PRInt32 length = 0;
- GetNumberOfOptions(&length);
- if (mSelectionCacheLength != length) {
- //NS_ASSERTION(0,"nsListControlFrame: Cache sync'd with content!\n");
- changed = PR_TRUE; // Assume the worst, there was a change.
+
+ PRBool isDroppedDown = PR_FALSE;
+ if (mComboboxFrame != nsnull) {
+ mComboboxFrame->IsDroppedDown(&isDroppedDown);
+ }
+ if (aDoDispatchEvent && !isDroppedDown) {
+ rv = SelectionChanged(aContent); // Dispatch event
}
- // Step through content looking for change in selection
- if (NS_SUCCEEDED(rv)) {
- if (!changed) {
- PRBool selected;
- // the content array of options is actually
- // out of sync with the array
- // so until bug 38825 is fixed.
- if (mSelectionCacheLength != length) { // this shouldn't happend
- for (PRInt32 i = 0; i < length; i++) {
- selected = IsContentSelectedByIndex(i);
- if (selected != (PRBool)mSelectionCache->ElementAt(i)) {
- mSelectionCache->ReplaceElementAt((void*)selected, i);
- changed = PR_TRUE;
- }
- }
- } else {
- mSelectionCache->Clear();
- for (PRInt32 i = 0; i < length; i++) {
- selected = IsContentSelectedByIndex(i);
- mSelectionCache->InsertElementAt((void*)selected, i);
- changed = PR_TRUE;
- }
- }
- }
-
- PRBool isDroppedDown = PR_FALSE;
- if (mComboboxFrame != nsnull) {
- mComboboxFrame->IsDroppedDown(&isDroppedDown);
- }
- if (changed && aDoDispatchEvent && !isDroppedDown) {
- rv = SelectionChanged(aContent); // Dispatch event
- }
- }
-
- if ((changed || aForceUpdate) && mComboboxFrame) {
+ if (aForceUpdate && mComboboxFrame) {
rv = mComboboxFrame->SelectionChanged(); // Update view
}
return rv;
@@ -2779,6 +2891,17 @@ nsListControlFrame::SetProperty(nsIPresContext* aPresContext, nsIAtom* aName,
if (NS_FAILED(GetMultiple(&multiple, selectElement))) {
multiple = PR_FALSE;
}
+ if (mUpdateTimer != nsnull) {
+ if (!mUpdateTimer->HasBeenNotified()) {
+ StopUpdateTimer();
+ ToggleSelected(selectedIndex); // sets mSelectedIndex
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ mUpdateTimer->ItemIndexSet(selectedIndex);
+ }
+ return NS_OK;
+ }
+ }
// if it is a multiple, select the new item
if (multiple) {
Deselect();
@@ -2991,7 +3114,7 @@ nsListControlFrame::AboutToRollup()
ResetSelectedItem();
} else {
if (IsInDropDownMode() == PR_TRUE) {
- mComboboxFrame->ListWasSelected(mPresContext, PR_TRUE, PR_TRUE);
+ mComboboxFrame->ListWasSelected(mPresContext, PR_FALSE, PR_TRUE);
}
}
}
@@ -3251,7 +3374,7 @@ nsListControlFrame::MouseUp(nsIDOMEvent* aMouseEvent)
SetContentSelected(mSelectedIndex, PR_TRUE);
}
if (mComboboxFrame) {
- mComboboxFrame->ListWasSelected(mPresContext, PR_FALSE, PR_TRUE);
+ mComboboxFrame->ListWasSelected(mPresContext, PR_TRUE, PR_TRUE);
}
mouseEvent->clickCount = 1;
} else {
@@ -3335,11 +3458,9 @@ nsListControlFrame::GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent,
if (optionContent) {
aOldIndex = aCurIndex;
aCurIndex = GetSelectedIndexFromContent(optionContent);
- //printf("--> Old: %d New: %d\n", aOldIndex, aCurIndex);
rv = NS_OK;
}
}
- //printf("--> bailing\n");
return rv;
}
@@ -4024,6 +4145,7 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
//----------------------------------------------------------------------
// nsIStatefulFrame
//----------------------------------------------------------------------
+//----------------------------------------------------------------------
NS_IMETHODIMP
nsListControlFrame::SaveStateInternal(nsIPresContext* aPresContext, nsIPresState** aState)
{
@@ -4062,18 +4184,7 @@ nsListControlFrame::SaveStateInternal(nsIPresContext* aPresContext, nsIPresState
PRInt32 j = 0;
for (i = 0; i < numOptions; i++) {
if (IsContentSelectedByIndex(i)) {
-#ifdef FIX_FOR_BUG_50376
res = SetOptionIntoPresState(value, i, j++);
-#else
- nsCOMPtr thisVal(do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID));
- NS_ENSURE_TRUE(thisVal, res);
-
- res = thisVal->SetData(i);
- NS_ENSURE_SUCCEEDED(res, res);
-
- PRBool okay = value->InsertElementAt((nsISupports *)thisVal, j++);
- NS_ENSURE_TRUE(okay, NS_ERROR_OUT_OF_MEMORY);
-#endif
}
}
@@ -4107,7 +4218,7 @@ nsListControlFrame::RestoreStateInternal(nsIPresContext* aPresContext,
mPresState = aState;
if (mHasBeenInitialized) { // Already called Reset, call again to update selection
- Reset(aPresContext);
+ ResetList(aPresContext);
}
return NS_OK;
}
@@ -4352,3 +4463,45 @@ nsListEventListener::DragMove(nsIDOMEvent* aMouseEvent)
return NS_OK;
}
+/*=============== Timer Related Code ======================*/
+nsresult
+nsListControlFrame::StartUpdateTimer(nsIPresContext * aPresContext)
+{
+
+ if (mUpdateTimer == nsnull) {
+ nsresult result = NS_NewUpdateTimer(&mUpdateTimer);
+ if (NS_FAILED(result))
+ return result;
+
+ mUpdateTimer->Init(this, 0); // delay "0"
+ }
+
+ if (mUpdateTimer != nsnull) {
+ return mUpdateTimer->Start(aPresContext);
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+inline void
+nsListControlFrame::StopUpdateTimer()
+{
+ if (mUpdateTimer != nsnull) {
+ mUpdateTimer->Stop();
+ }
+}
+
+void
+nsListControlFrame::ItemsHaveBeenRemoved(nsIPresContext * aPresContext)
+{
+ // Only adjust things if it is a combobox
+ // removing items on a listbox should effect anything
+ if (IsInDropDownMode()) {
+ // if items were removed ahead of the selected item the
+ // selected index is moved down
+ // if the selected item was removed then we should reset the list
+ if (mUpdateTimer->RemovedSelectedIndex()) {
+ ResetList(aPresContext);
+ }
+ }
+}
diff --git a/mozilla/layout/forms/nsListControlFrame.h b/mozilla/layout/forms/nsListControlFrame.h
index 2f8748fe687..d6a965775fd 100644
--- a/mozilla/layout/forms/nsListControlFrame.h
+++ b/mozilla/layout/forms/nsListControlFrame.h
@@ -55,6 +55,8 @@ class nsVoidArray;
class nsIScrollableView;
class nsListControlFrame;
+class nsSelectUpdateTimer;
+class nsVoidArray;
#define NS_ILIST_EVENT_LISTENER_IID \
{/* 45BC6821-6EFB-11d4-B1EE-000064657374*/ \
@@ -152,8 +154,6 @@ protected:
/**
* Frame-based listbox.
*/
-#define FIX_FOR_BUG_50376
-
class nsListControlFrame : public nsScrollFrame,
public nsIFormControlFrame,
@@ -165,6 +165,7 @@ class nsListControlFrame : public nsScrollFrame,
{
public:
friend nsresult NS_NewListControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);
+ friend class nsSelectUpdateTimer;
// nsISupports
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
@@ -220,7 +221,7 @@ public:
virtual void SetFocus(PRBool aOn = PR_TRUE, PRBool aRepaint = PR_FALSE);
virtual void ScrollIntoView(nsIPresContext* aPresContext);
virtual void MouseClicked(nsIPresContext* aPresContext);
- virtual void Reset(nsIPresContext* aPresContext);
+ virtual void Reset(nsIPresContext* aPresContext) { ResetList(aPresContext); }
virtual PRBool IsSuccessful(nsIFormControlFrame* aSubmitter);
virtual PRInt32 GetMaxNumValues();
virtual PRBool GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues,
@@ -264,6 +265,7 @@ public:
NS_IMETHOD GetOptionSelected(PRInt32 aIndex, PRBool* aValue);
NS_IMETHOD DoneAddingContent(PRBool aIsDone);
NS_IMETHOD OptionDisabled(nsIContent * aContent);
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext) { return NS_OK; }
//nsIStatefulFrame
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
@@ -311,7 +313,8 @@ protected:
void AdjustIndexForDisabledOpt(PRInt32 &anNewIndex, PRInt32 &anOldIndex,
PRBool &aDoSetNewIndex, PRBool &aWasDisabled,
PRInt32 aNumOptions, PRInt32 aDoAdjustInc, PRInt32 aDoAdjustIncNext);
-#ifdef FIX_FOR_BUG_50376
+ virtual void ResetList(nsIPresContext* aPresContext, nsVoidArray * aInxList = nsnull);
+
// PresState Helper Methods
nsresult GetPresStateAndValueArray(nsISupportsArray ** aSuppArray);
nsresult SetOptionIntoPresState(nsISupportsArray * aSuppArray,
@@ -320,7 +323,6 @@ protected:
nsresult SetSelectionInPresState(PRInt32 aIndex, PRBool aValue);
nsresult RemoveOptionFromPresState(nsISupportsArray * aSuppArray,
PRInt32 aIndex);
-#endif
nsListControlFrame();
virtual ~nsListControlFrame();
@@ -343,7 +345,15 @@ protected:
nsIContent* GetOptionContent(PRInt32 aIndex);
PRBool IsContentSelected(nsIContent* aContent);
PRBool IsContentSelectedByIndex(PRInt32 aIndex);
- void SetContentSelected(PRInt32 aIndex, PRBool aSelected);
+ void SetContentSelected(PRInt32 aIndex,
+ PRBool aSelected,
+ PRBool aDoScrollTo = PR_TRUE,
+ nsIPresShell * aPresShell = nsnull);
+ void SetContentSelected(PRInt32 aIndex,
+ nsIContent * aContent,
+ PRBool aSelected,
+ PRBool aDoScrollTo = PR_TRUE,
+ nsIPresShell * aPresShell = nsnull);
void GetViewOffset(nsIViewManager* aManager, nsIView* aView, nsPoint& aPoint);
nsresult Deselect();
nsIFrame *GetOptionFromChild(nsIFrame* aParentFrame);
@@ -373,6 +383,11 @@ protected:
void GetScrollableView(nsIScrollableView*& aScrollableView);
+ // Timer Methods
+ nsresult StartUpdateTimer(nsIPresContext * aPresContext);
+ void StopUpdateTimer();
+ void ItemsHaveBeenRemoved(nsIPresContext * aPresContext);
+
// onChange detection
nsresult SelectionChanged(nsIContent* aContent);
@@ -417,6 +432,9 @@ protected:
PRInt16 mPassId;
nsSize mCachedDesiredMaxSize;
+ // Update timer
+ nsSelectUpdateTimer * mUpdateTimer;
+
//Resize Reflow OpitmizationSize;
nsSize mCacheSize;
nsSize mCachedMaxElementSize;
diff --git a/mozilla/layout/html/forms/public/nsISelectControlFrame.h b/mozilla/layout/html/forms/public/nsISelectControlFrame.h
index 55f2b25e7b1..0ea67706f16 100644
--- a/mozilla/layout/html/forms/public/nsISelectControlFrame.h
+++ b/mozilla/layout/html/forms/public/nsISelectControlFrame.h
@@ -72,6 +72,11 @@ public:
NS_IMETHOD OptionDisabled(nsIContent * aContent) = 0;
+ /**
+ * This only applies to Comboboxes, no-op for ListBoxes
+ */
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext) = 0;
+
};
#endif
diff --git a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp
index f1008bfe19c..4d5513310f9 100644
--- a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp
+++ b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp
@@ -2030,24 +2030,14 @@ nsComboboxControlFrame::DoneAddingContent(PRBool aIsDone)
NS_IMETHODIMP
nsComboboxControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
-#ifdef DO_REFLOW_DEBUG
- printf("**********\n*********AddOption: %d\n", aIndex);
+#ifdef DO_REFLOW_DEBUGXX
+ printf("*********AddOption: %d\n", aIndex);
#endif
- nsISelectControlFrame* listFrame = nsnull;
- nsresult rv = mDropdownFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),
- (void**)&listFrame);
- if (NS_SUCCEEDED(rv) && listFrame) {
- rv = listFrame->AddOption(aPresContext, aIndex);
- //PRInt32 index;
- //mListControlFrame->GetSelectedIndex(&index);
- //UpdateSelection(PR_FALSE, PR_TRUE, index);
- NS_RELEASE(listFrame);
+ nsresult rv = NS_ERROR_FAILURE;
+ if (mDropdownFrame) {
+ nsListControlFrame * lcf = NS_STATIC_CAST(nsListControlFrame*, mDropdownFrame);
+ rv = lcf->AddOption(aPresContext, aIndex);
}
- // If we added the first option, we might need to select it.
- // We should call MakeSureSomethingIsSelected here, but since it
- // it changes selection, which currently causes a reframe, and thus
- // deletes the frame out from under the caller, causing a crash. (Bug 17995)
- // XXX MakeSureSomethingIsSelected(aPresContext);
return rv;
}
@@ -2055,16 +2045,11 @@ nsComboboxControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
NS_IMETHODIMP
nsComboboxControlFrame::RemoveOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
- nsISelectControlFrame* listFrame = nsnull;
- nsresult rv = mDropdownFrame->QueryInterface(NS_GET_IID(nsISelectControlFrame),
- (void**)&listFrame);
- if (NS_SUCCEEDED(rv) && listFrame) {
- rv = listFrame->RemoveOption(aPresContext, aIndex);
- NS_RELEASE(listFrame);
+ nsresult rv = NS_ERROR_FAILURE;
+ if (mDropdownFrame != nsnull) {
+ nsListControlFrame * lcf = NS_STATIC_CAST(nsListControlFrame*, mDropdownFrame);
+ rv = lcf->RemoveOption(aPresContext, aIndex);
}
- // If we removed the selected option, nothing is selected any more.
- // Restore selection to option 0 if there are options left.
- MakeSureSomethingIsSelected(aPresContext);
return rv;
}
diff --git a/mozilla/layout/html/forms/src/nsComboboxControlFrame.h b/mozilla/layout/html/forms/src/nsComboboxControlFrame.h
index 0b2414106a6..0f28755755a 100644
--- a/mozilla/layout/html/forms/src/nsComboboxControlFrame.h
+++ b/mozilla/layout/html/forms/src/nsComboboxControlFrame.h
@@ -177,6 +177,7 @@ public:
NS_IMETHOD GetOptionSelected(PRInt32 aIndex, PRBool* aValue);
NS_IMETHOD DoneAddingContent(PRBool aIsDone);
NS_IMETHOD OptionDisabled(nsIContent * aContent);
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext); // Default to option 0
//nsIStatefulFrame
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
@@ -232,7 +233,6 @@ protected:
void InitTextStr(nsIPresContext* aPresContext, PRBool aUpdate);
nsresult GetPrimaryComboFrame(nsIPresContext* aPresContext, nsIContent* aContent, nsIFrame** aFrame);
NS_IMETHOD ToggleList(nsIPresContext* aPresContext);
- NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext); // Default to option 0
void ReflowCombobox(nsIPresContext * aPresContext,
const nsHTMLReflowState& aReflowState,
diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp
index 37e3151a2f2..9a4edfb9ef0 100644
--- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp
+++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp
@@ -62,7 +62,9 @@
#include "nsISelectElement.h"
#include "nsIPrivateDOMEvent.h"
-//static NS_DEFINE_IID(kBlockFrameCID, NS_BLOCK_FRAME_CID);
+// Timer Includes
+#include "nsITimer.h"
+#include "nsITimerCallback.h"
// Constants
const nscoord kMaxDropDownRows = 20; // This matches the setting for 4.x browsers
@@ -207,6 +209,160 @@ if (aReflowState.mComputedWidth != NS_UNCONSTRAINEDSIZE) { \
//-- Done with macros
//------------------------------------------------------
+//---------------------------------------------------
+//-- Update Timer Stuff
+//---------------------------------------------------
+class nsSelectUpdateTimer : public nsITimerCallback
+{
+public:
+
+ NS_DECL_ISUPPORTS
+
+ nsSelectUpdateTimer()
+ : mPresContext(nsnull), mDelay(0), mHasBeenNotified(PR_FALSE),
+ mItemsAdded(PR_FALSE), mItemsRemoved(PR_FALSE), mItemsInxSet(PR_FALSE),
+ mRemovedSelectedIndex(PR_FALSE)
+ {
+ NS_INIT_ISUPPORTS();
+ }
+
+ virtual ~nsSelectUpdateTimer();
+
+ NS_IMETHOD_(void) Notify(nsITimer *timer);
+
+ // Additional Methods
+ nsresult Start(nsIPresContext *aPresContext)
+ {
+ mPresContext = aPresContext;
+ //mHasBeenNotified = PR_FALSE;
+
+ if (!mTimer) {
+ nsresult result;
+ mTimer = do_CreateInstance("@mozilla.org/timer;1", &result);
+
+ if (NS_FAILED(result))
+ return result;
+
+ }
+
+ if (mHasBeenNotified) {
+ mItemsAdded = PR_FALSE;
+ mItemsRemoved = PR_FALSE;
+ mItemsInxSet = PR_FALSE;
+ mHasBeenNotified = PR_FALSE;
+ mRemovedSelectedIndex = PR_FALSE;
+ mInxArray.Clear();
+ }
+
+ return mTimer->Init(this, mDelay);
+ }
+
+ void Init(nsListControlFrame *aList, PRUint32 aDelay) { mListControl = aList; mDelay = aDelay; }
+ void Stop() { if (mTimer) mTimer->Cancel(); }
+
+ void AdjustIndexes(PRBool aInserted, PRInt32 aInx)
+ {
+ // remove the index from the list
+ if (!aInserted) {
+ PRInt32 inx = (PRInt32)mInxArray.IndexOf((void*)aInx);
+ if (inx > -1) {
+ mInxArray.RemoveElementAt(inx);
+ }
+ }
+
+ PRInt32 count = mInxArray.Count();
+ for (PRInt32 i=0;i aInx) {
+ mInxArray.ReplaceElementAt((void*)(inx+(aInserted?1:-1)), i);
+ }
+ }
+ }
+
+ void ItemAdded(PRInt32 aInx, PRInt32 aNumItems)
+ {
+ mItemsAdded = PR_TRUE;
+ if (mInxArray.Count() > 0 && aInx <= aNumItems-1) {
+ AdjustIndexes(PR_TRUE, aInx);
+ }
+ }
+
+ void ItemRemoved(PRInt32 aInx, PRInt32 aNumItems)
+ {
+ mItemsRemoved = PR_TRUE;
+ if (mInxArray.Count() > 0 && aInx <= aNumItems) {
+ AdjustIndexes(PR_FALSE, aInx);
+ }
+ }
+
+ void ItemIndexSet(PRInt32 aInx)
+ {
+ mItemsInxSet = PR_TRUE;
+ mInxArray.AppendElement((void*)aInx);
+ }
+
+ PRPackedBool HasBeenNotified() { return mHasBeenNotified; }
+ void SetRemovedSelectedIndex() { mRemovedSelectedIndex = PR_TRUE; }
+ PRPackedBool RemovedSelectedIndex() { return mRemovedSelectedIndex; }
+
+private:
+ nsListControlFrame * mListControl;
+ nsCOMPtr mTimer;
+ nsIPresContext* mPresContext;
+ PRUint32 mDelay;
+ PRPackedBool mHasBeenNotified;
+
+ PRPackedBool mItemsAdded;
+ PRPackedBool mItemsRemoved;
+ PRPackedBool mItemsInxSet;
+ PRPackedBool mRemovedSelectedIndex;
+ nsVoidArray mInxArray;
+
+};
+
+NS_IMPL_ADDREF(nsSelectUpdateTimer)
+NS_IMPL_RELEASE(nsSelectUpdateTimer)
+NS_IMPL_QUERY_INTERFACE1(nsSelectUpdateTimer, nsITimerCallback)
+
+nsresult NS_NewUpdateTimer(nsSelectUpdateTimer **aResult)
+{
+ if (!aResult)
+ return NS_ERROR_NULL_POINTER;
+
+ *aResult = (nsSelectUpdateTimer*) new nsSelectUpdateTimer;
+
+ if (!aResult)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(*aResult);
+
+ return NS_OK;
+}
+
+// nsITimerCallback
+NS_IMETHODIMP_(void) nsSelectUpdateTimer::Notify(nsITimer *timer)
+{
+ if (mPresContext && mListControl && !mHasBeenNotified) {
+ mHasBeenNotified = PR_TRUE;
+ if (mItemsAdded || mItemsInxSet) {
+ mListControl->ResetList(mPresContext, &mInxArray);
+ } else {
+ mListControl->ItemsHaveBeenRemoved(mPresContext);
+ }
+ }
+}
+
+nsSelectUpdateTimer::~nsSelectUpdateTimer()
+{
+ if (mTimer) {
+ mTimer->Cancel();
+ }
+}
+
+//---------------------------------------------------
+//-- DONE: Update Timer Stuff
+//---------------------------------------------------
+
//---------------------------------------------------------
nsListControlFrame::nsListControlFrame()
@@ -225,9 +381,6 @@ nsListControlFrame::nsListControlFrame()
mDelayedIndexSetting = kNothingSelected;
mDelayedValueSetting = PR_FALSE;
- mSelectionCache = new nsVoidArray();
- mSelectionCacheLength = 0;
-
mIsAllContentHere = PR_FALSE;
mIsAllFramesHere = PR_FALSE;
mHasBeenInitialized = PR_FALSE;
@@ -245,6 +398,8 @@ nsListControlFrame::nsListControlFrame()
mOverrideReflowOpt = PR_FALSE;
mPassId = 0;
+ mUpdateTimer = nsnull;
+
REFLOW_COUNTER_INIT()
}
@@ -252,6 +407,10 @@ nsListControlFrame::nsListControlFrame()
nsListControlFrame::~nsListControlFrame()
{
REFLOW_COUNTER_DUMP("nsLCF");
+ if (mUpdateTimer != nsnull) {
+ StopUpdateTimer();
+ delete mUpdateTimer;
+ }
mComboboxFrame = nsnull;
if (mFormFrame) {
@@ -259,9 +418,6 @@ nsListControlFrame::~nsListControlFrame()
mFormFrame = nsnull;
}
NS_IF_RELEASE(mPresContext);
- if (mSelectionCache) {
- delete mSelectionCache;
- }
}
// for Bug 47302 (remove this comment later)
@@ -531,7 +687,7 @@ nsListControlFrame::Reflow(nsIPresContext* aPresContext,
}
if (mIsAllFramesHere && !mHasBeenInitialized) {
mHasBeenInitialized = PR_TRUE;
- Reset(aPresContext);
+ ResetList(aPresContext);
}
}
@@ -1068,41 +1224,16 @@ nsListControlFrame::ForceRedraw(nsIPresContext* aPresContext)
void
nsListControlFrame::DisplaySelected(nsIContent* aContent)
{
- //XXX: This is temporary. It simulates psuedo states by using a attribute selector on
- // -moz-option-selected in the ua.css style sheet. This will not be needed when
- // The event state manager supports selected states. KMM
- nsAutoString attr;
- nsresult rv = aContent->GetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, attr);
- if (rv != NS_CONTENT_ATTR_NOT_THERE)
- return;
-
- if (PR_TRUE == mIsAllFramesHere) {
- aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), PR_TRUE);
- //ForceRedraw();
- } else {
- aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), PR_FALSE);
- }
+ // ignore return value, not much we can do if it fails
+ aContent->SetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, nsAutoString(), mIsAllFramesHere);
}
//---------------------------------------------------------
void
nsListControlFrame::DisplayDeselected(nsIContent* aContent)
{
- //XXX: This is temporary. It simulates psuedo states by using a attribute selector on
- // -moz-option-selected in the ua.css style sheet. This will not be needed when
- // The event state manager is functional. KMM
- nsAutoString attr;
- nsresult rv = aContent->GetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, attr);
- if (rv == NS_CONTENT_ATTR_NOT_THERE)
- return;
-
- if (PR_TRUE == mIsAllFramesHere) {
- aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, PR_TRUE);
- //ForceRedraw();
- } else {
- aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, PR_FALSE);
- }
-
+ // ignore return value, not much we can do if it fails
+ aContent->UnsetAttribute(kNameSpaceID_None, nsLayoutAtoms::optionSelectedPseudo, mIsAllFramesHere);
}
@@ -1339,7 +1470,7 @@ nsListControlFrame::MultipleSelection(PRBool aIsShift, PRBool aIsControl)
ClearSelection();
}
}
-#ifdef DEBUG_rods
+#ifdef DEBUG_rodsX
printf("mSelectedIndex: %d\n", mSelectedIndex);
printf("mOldSelectedIndex: %d\n", mOldSelectedIndex);
printf("mStartExtendedIndex: %d\n", mStartExtendedIndex);
@@ -1555,7 +1686,7 @@ nsListControlFrame::SetInitialChildList(nsIPresContext* aPresContext,
// If all content and frames are here
// the reset/initialize
if (CheckIfAllFramesHere()) {
- Reset(aPresContext);
+ ResetList(aPresContext);
mHasBeenInitialized = PR_TRUE;
}
}*/
@@ -1801,7 +1932,7 @@ nsListControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection,
return status;
}
-
+static int cnt = 0;
//---------------------------------------------------------
// For a given piece of content, it determines whether the
// content (an option) is selected or not
@@ -1837,7 +1968,10 @@ nsListControlFrame::IsContentSelectedByIndex(PRInt32 aIndex)
// being selected or not selected
//---------------------------------------------------------
void
-nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
+nsListControlFrame::SetContentSelected(PRInt32 aIndex,
+ PRBool aSelected,
+ PRBool aDoScrollTo,
+ nsIPresShell * aPresShell)
{
if (aIndex == kNothingSelected) {
return;
@@ -1858,26 +1992,47 @@ nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
nsIContent* content = GetOptionContent(aIndex);
NS_ASSERTION(content != nsnull, "Content should not be null!");
- if (content != nsnull) {
- nsCOMPtr presShell;
- mPresContext->GetShell(getter_AddRefs(presShell));
- if (presShell) {
- nsIFrame * childframe;
- nsresult result = presShell->GetPrimaryFrameFor(content, &childframe);
- if (NS_SUCCEEDED(result) && childframe != nsnull) {
- if (aSelected) {
- DisplaySelected(content);
- // Now that it is selected scroll to it
- ScrollToFrame(content);
+ nsIPresShell* presShell;
+ if (aPresShell == nsnull) {
+ mPresContext->GetShell(&presShell);
+ } else {
+ presShell = aPresShell;
+ NS_ADDREF(presShell);
+ }
+ SetContentSelected(aIndex, content, aSelected, aDoScrollTo, presShell);
+ NS_RELEASE(content);
+ NS_RELEASE(presShell);
+}
+
+void
+nsListControlFrame::SetContentSelected(PRInt32 aIndex,
+ nsIContent * aContent,
+ PRBool aSelected,
+ PRBool aDoScrollTo,
+ nsIPresShell * aPresShell)
+{
+ if (aContent != nsnull) {
+ PRBool isSelected = IsContentSelected(aContent);
+ //if (aSelected != isSelected) {
+ if (aPresShell) {
+ nsIFrame * childframe;
+ nsresult result = aPresShell->GetPrimaryFrameFor(aContent, &childframe);
+ if (NS_SUCCEEDED(result) && childframe != nsnull) {
+ if (aSelected) {
+ DisplaySelected(aContent);
+ // Now that it is selected scroll to it
+ if (aDoScrollTo) {
+ ScrollToFrame(aContent);
+ }
+ } else {
+ DisplayDeselected(aContent);
+ }
} else {
- DisplayDeselected(content);
+ mDelayedIndexSetting = aIndex;
+ mDelayedValueSetting = aSelected;
}
- } else {
- mDelayedIndexSetting = aIndex;
- mDelayedValueSetting = aSelected;
}
- }
- NS_RELEASE(content);
+ //}
}
}
@@ -1888,6 +2043,9 @@ nsListControlFrame::SetContentSelected(PRInt32 aIndex, PRBool aSelected)
nsresult
nsListControlFrame::Deselect()
{
+
+ /* This code works fine but it
+ * isn't quite as efficient as the code below
PRInt32 i;
PRInt32 max = 0;
if (NS_SUCCEEDED(GetNumberOfOptions(&max))) {
@@ -1895,6 +2053,24 @@ nsListControlFrame::Deselect()
SetContentSelected(i, PR_FALSE);
}
}
+ */
+
+ nsCOMPtr options = getter_AddRefs(GetOptions(mContent));
+ if (options) {
+ PRUint32 length = 0;
+ options->GetLength(&length);
+ PRUint32 i;
+ for (i=0;i node;
+ if (NS_SUCCEEDED(options->Item(i, getter_AddRefs(node)))) {
+ nsCOMPtr content(do_QueryInterface(node));
+ if (content && IsContentSelected(content)) {
+ DisplayDeselected(content);
+ }
+ }
+ }
+ }
+
mSelectedIndex = kNothingSelected;
return NS_OK;
@@ -1966,9 +2142,10 @@ nsListControlFrame::GetMaxNumValues()
// those values as determined by the original HTML
//---------------------------------------------------------
void
-nsListControlFrame::Reset(nsIPresContext* aPresContext)
+nsListControlFrame::ResetList(nsIPresContext* aPresContext, nsVoidArray * aInxList)
{
- REFLOW_DEBUG_MSG("LBX::Reset\n");
+
+ REFLOW_DEBUG_MSG("LBX::ResetList\n");
// if all the frames aren't here
// don't bother reseting
@@ -1995,12 +2172,16 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
PRBool multiple;
GetMultiple(&multiple);
- Deselect();
-
// Clear the cache and set the default selections
- // if we havn't been restored
- mSelectionCache->Clear();
- mSelectionCacheLength = 0;
+ // if we haven't been restored
+ nsCOMPtr presShell;
+ aPresContext->GetShell(getter_AddRefs(presShell));
+
+ // This code has been reworked to make it as efficient as possible.
+ // In the case, where it is a single select, we do not select any items
+ // while they are being reset, we wait until the end and set the selected
+ // item once. This also means that when it is a multiple select
+ // we set the selected item twice, but the cost at that point is very low.
PRUint32 i;
for (i = 0; i < numOptions; i++) {
nsCOMPtr option = getter_AddRefs(GetOption(*options, i));
@@ -2009,31 +2190,39 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
if (!hasBeenRestored) {
option->GetDefaultSelected(&selected);
}
+ if (aInxList) {
+ selected = aInxList->IndexOf((void*)i) > -1;
+ }
- mSelectionCache->AppendElement((void*)selected);
- mSelectionCacheLength++;
-
+ nsCOMPtr content(do_QueryInterface(option));
if (selected) {
- if (mSelectedIndex == kNothingSelected ||
- (mSelectedIndex != kNothingSelected && multiple)) {
- mSelectedIndex = i;
- SetContentSelected(i, PR_TRUE);
- if (multiple) {
- mStartExtendedIndex = i;
- if (mEndExtendedIndex == kNothingSelected) {
- mEndExtendedIndex = i;
- }
+ NS_ASSERTION(content, "There is no way this could be nsnull");
+
+ mSelectedIndex = i;
+
+ if (multiple) {
+ SetContentSelected(i, content, PR_TRUE, PR_FALSE, presShell);
+ mStartExtendedIndex = i;
+ if (mEndExtendedIndex == kNothingSelected) {
+ mEndExtendedIndex = i;
}
- } else {
- SetContentSelected(mSelectedIndex, PR_FALSE);
- mSelectionCache->ReplaceElementAt((void*)PR_FALSE, mSelectedIndex);
- mSelectedIndex = i;
- SetContentSelected(i, PR_TRUE);
}
+ } else if (IsContentSelected(content)){
+ SetContentSelected(i, content, PR_FALSE, PR_FALSE, presShell);
}
}
}
+ // To make the final adjustments
+ // set the selected item to true and scroll to it
+ PRUint32 indexToSelect;
+ if (multiple) {
+ indexToSelect = mStartExtendedIndex;
+ } else {
+ indexToSelect = mSelectedIndex;
+ }
+ SetContentSelected(indexToSelect, PR_TRUE, PR_TRUE, presShell);
+
// Ok, so we were restored, now set the last known selections from the restore state.
if (hasBeenRestored) {
nsCOMPtr supp;
@@ -2060,7 +2249,6 @@ nsListControlFrame::Reset(nsIPresContext* aPresContext)
if (NS_SUCCEEDED(res)) {
mSelectedIndex = j;
SetContentSelected(j, PR_TRUE);// might want to use ToggleSelection
- mSelectionCache->ReplaceElementAt((void*)PR_TRUE, j);
if (multiple) {
mStartExtendedIndex = j;
if (mEndExtendedIndex == kNothingSelected) {
@@ -2376,7 +2564,7 @@ nsListControlFrame::DoneAddingContent(PRBool aIsDone)
// if all the frames are now present we can initalize
if (CheckIfAllFramesHere() && mPresContext) {
mHasBeenInitialized = PR_TRUE;
- Reset(mPresContext);
+ ResetList(mPresContext);
}
}
}
@@ -2387,10 +2575,15 @@ nsListControlFrame::DoneAddingContent(PRBool aIsDone)
NS_IMETHODIMP
nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
+ StopUpdateTimer();
+
#ifdef DO_REFLOW_DEBUG
printf("---- Id: %d nsLCF %p Added Option %d\n", mReflowId, this, aIndex);
#endif
+ PRInt32 numOptions;
+ GetNumberOfOptions(&numOptions);
+
if (!mIsAllContentHere) {
nsCOMPtr element(do_QueryInterface(mContent));
if (element) {
@@ -2399,8 +2592,6 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
mIsAllFramesHere = PR_FALSE;
mHasBeenInitialized = PR_FALSE;
} else {
- PRInt32 numOptions;
- GetNumberOfOptions(&numOptions);
mIsAllFramesHere = aIndex == numOptions-1;
}
}
@@ -2410,56 +2601,10 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
return NS_OK;
}
- PRInt32 oldSelection = mSelectedIndex;
-
- // Adding an option to the select can cause a change in selection
- // if the new option has it's selected attribute set.
- // this code checks to see if it does
- // if so then it resets the entire selection of listbox
- PRBool wasReset = PR_FALSE;
- nsCOMPtr options = getter_AddRefs(GetOptions(mContent));
- if (options) {
- nsCOMPtr option = getter_AddRefs(GetOption(*options, aIndex));
- if (option) {
- PRBool selected = PR_FALSE;
- option->GetDefaultSelected(&selected);
-
- mSelectionCache->InsertElementAt((void*)selected, aIndex);
- mSelectionCacheLength++;
-
- if (selected) {
- Reset(aPresContext); // this sets mSelectedIndex to the defaulted selection
- wasReset = PR_TRUE;
- }
-
-#ifdef DEBUG_rods
- {
- nsAutoString text;
- text.AssignWithConversion("No Value");
- nsresult rv = option->GetLabel(text);
- if (NS_CONTENT_ATTR_NOT_THERE == rv || 0 == text.Length()) {
- option->GetText(text);
- }
- printf("|||||this %p Index: %d [%s] CB: %p\n", this, aIndex, text.ToNewCString(), mComboboxFrame); //leaks
- }
-#endif
- }
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ mUpdateTimer->ItemAdded(aIndex, numOptions);
}
-
- if (!wasReset) {
- GetSelectedIndexFromDOM(&mSelectedIndex); // comes from the DOM
- }
-
- // if selection changed because of the new option being added
- // notify the combox if necessary
- if (mComboboxFrame != nsnull) {
- if (mSelectedIndex == kNothingSelected) {
- mComboboxFrame->MakeSureSomethingIsSelected(mPresContext);
- } else if (oldSelection != mSelectedIndex) {
- mComboboxFrame->UpdateSelection(PR_FALSE, PR_TRUE, mSelectedIndex); // don't dispatch event
- }
- }
-
return NS_OK;
}
@@ -2467,25 +2612,29 @@ nsListControlFrame::AddOption(nsIPresContext* aPresContext, PRInt32 aIndex)
NS_IMETHODIMP
nsListControlFrame::RemoveOption(nsIPresContext* aPresContext, PRInt32 aIndex)
{
- PRInt32 numOptions;
- GetNumberOfOptions(&numOptions);
-
-// PRInt32 oldSelectedIndex = mSelectedIndex;
- GetSelectedIndexFromDOM(&mSelectedIndex); // comes from the DOM
-
- // Select the new selectedIndex
- // Don't need to deselect option as it is being removed anyway.
- if (mSelectedIndex >= 0) {
- SetContentSelected(mSelectedIndex, PR_TRUE);
+ StopUpdateTimer();
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ PRInt32 numOptions;
+ GetNumberOfOptions(&numOptions);
+ mUpdateTimer->ItemRemoved(aIndex, numOptions);
}
- mSelectionCache->RemoveElementAt(aIndex);
- mSelectionCacheLength--;
+ // Check to see which index is being removed
+ // if the current index is being removed, remember that
+ // if the index is less then the current index
+ // then decrement the current selected index
+ if (aIndex == mSelectedIndex) {
+ mUpdateTimer->SetRemovedSelectedIndex();
+ mSelectedIndex = kNothingSelected;
+
+ } if (aIndex < mSelectedIndex) {
+ mSelectedIndex--;
+ }
return NS_OK;
}
-#ifdef FIX_FOR_BUG_50376
//-------------------------------------------------------------------
nsresult nsListControlFrame::GetPresStateAndValueArray(nsISupportsArray ** aSuppArray)
{
@@ -2596,8 +2745,6 @@ nsresult nsListControlFrame::SetOptionIntoPresState(nsISupportsArray * aSuppArra
return res;
}
-#endif // FIX_FOR_BUG_50376
-
//---------------------------------------------------------
// Select the specified item in the listbox using control logic.
// If it a single selection listbox the previous selection will be
@@ -2605,11 +2752,9 @@ nsresult nsListControlFrame::SetOptionIntoPresState(nsISupportsArray * aSuppArra
NS_IMETHODIMP
nsListControlFrame::SetOptionSelected(PRInt32 aIndex, PRBool aValue)
{
-#ifdef FIX_FOR_BUG_50376
if (!mIsAllFramesHere && !mHasBeenInitialized) {
return SetSelectionInPresState(aIndex, aValue);
}
-#endif // FIX_FOR_BUG_50376
PRBool multiple;
nsresult rv = GetMultiple(&multiple);
@@ -2646,49 +2791,16 @@ nsListControlFrame::UpdateSelection(PRBool aDoDispatchEvent, PRBool aForceUpdate
nsresult rv = NS_OK;
PRBool changed = PR_FALSE;
- // Paranoia: check if cache is up to date with content
- PRInt32 length = 0;
- GetNumberOfOptions(&length);
- if (mSelectionCacheLength != length) {
- //NS_ASSERTION(0,"nsListControlFrame: Cache sync'd with content!\n");
- changed = PR_TRUE; // Assume the worst, there was a change.
+
+ PRBool isDroppedDown = PR_FALSE;
+ if (mComboboxFrame != nsnull) {
+ mComboboxFrame->IsDroppedDown(&isDroppedDown);
+ }
+ if (aDoDispatchEvent && !isDroppedDown) {
+ rv = SelectionChanged(aContent); // Dispatch event
}
- // Step through content looking for change in selection
- if (NS_SUCCEEDED(rv)) {
- if (!changed) {
- PRBool selected;
- // the content array of options is actually
- // out of sync with the array
- // so until bug 38825 is fixed.
- if (mSelectionCacheLength != length) { // this shouldn't happend
- for (PRInt32 i = 0; i < length; i++) {
- selected = IsContentSelectedByIndex(i);
- if (selected != (PRBool)mSelectionCache->ElementAt(i)) {
- mSelectionCache->ReplaceElementAt((void*)selected, i);
- changed = PR_TRUE;
- }
- }
- } else {
- mSelectionCache->Clear();
- for (PRInt32 i = 0; i < length; i++) {
- selected = IsContentSelectedByIndex(i);
- mSelectionCache->InsertElementAt((void*)selected, i);
- changed = PR_TRUE;
- }
- }
- }
-
- PRBool isDroppedDown = PR_FALSE;
- if (mComboboxFrame != nsnull) {
- mComboboxFrame->IsDroppedDown(&isDroppedDown);
- }
- if (changed && aDoDispatchEvent && !isDroppedDown) {
- rv = SelectionChanged(aContent); // Dispatch event
- }
- }
-
- if ((changed || aForceUpdate) && mComboboxFrame) {
+ if (aForceUpdate && mComboboxFrame) {
rv = mComboboxFrame->SelectionChanged(); // Update view
}
return rv;
@@ -2779,6 +2891,17 @@ nsListControlFrame::SetProperty(nsIPresContext* aPresContext, nsIAtom* aName,
if (NS_FAILED(GetMultiple(&multiple, selectElement))) {
multiple = PR_FALSE;
}
+ if (mUpdateTimer != nsnull) {
+ if (!mUpdateTimer->HasBeenNotified()) {
+ StopUpdateTimer();
+ ToggleSelected(selectedIndex); // sets mSelectedIndex
+ nsresult rv = StartUpdateTimer(aPresContext);
+ if (NS_SUCCEEDED(rv) && mUpdateTimer != nsnull) {
+ mUpdateTimer->ItemIndexSet(selectedIndex);
+ }
+ return NS_OK;
+ }
+ }
// if it is a multiple, select the new item
if (multiple) {
Deselect();
@@ -2991,7 +3114,7 @@ nsListControlFrame::AboutToRollup()
ResetSelectedItem();
} else {
if (IsInDropDownMode() == PR_TRUE) {
- mComboboxFrame->ListWasSelected(mPresContext, PR_TRUE, PR_TRUE);
+ mComboboxFrame->ListWasSelected(mPresContext, PR_FALSE, PR_TRUE);
}
}
}
@@ -3251,7 +3374,7 @@ nsListControlFrame::MouseUp(nsIDOMEvent* aMouseEvent)
SetContentSelected(mSelectedIndex, PR_TRUE);
}
if (mComboboxFrame) {
- mComboboxFrame->ListWasSelected(mPresContext, PR_FALSE, PR_TRUE);
+ mComboboxFrame->ListWasSelected(mPresContext, PR_TRUE, PR_TRUE);
}
mouseEvent->clickCount = 1;
} else {
@@ -3335,11 +3458,9 @@ nsListControlFrame::GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent,
if (optionContent) {
aOldIndex = aCurIndex;
aCurIndex = GetSelectedIndexFromContent(optionContent);
- //printf("--> Old: %d New: %d\n", aOldIndex, aCurIndex);
rv = NS_OK;
}
}
- //printf("--> bailing\n");
return rv;
}
@@ -4024,6 +4145,7 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
//----------------------------------------------------------------------
// nsIStatefulFrame
//----------------------------------------------------------------------
+//----------------------------------------------------------------------
NS_IMETHODIMP
nsListControlFrame::SaveStateInternal(nsIPresContext* aPresContext, nsIPresState** aState)
{
@@ -4062,18 +4184,7 @@ nsListControlFrame::SaveStateInternal(nsIPresContext* aPresContext, nsIPresState
PRInt32 j = 0;
for (i = 0; i < numOptions; i++) {
if (IsContentSelectedByIndex(i)) {
-#ifdef FIX_FOR_BUG_50376
res = SetOptionIntoPresState(value, i, j++);
-#else
- nsCOMPtr thisVal(do_CreateInstance(NS_SUPPORTS_PRINT32_CONTRACTID));
- NS_ENSURE_TRUE(thisVal, res);
-
- res = thisVal->SetData(i);
- NS_ENSURE_SUCCEEDED(res, res);
-
- PRBool okay = value->InsertElementAt((nsISupports *)thisVal, j++);
- NS_ENSURE_TRUE(okay, NS_ERROR_OUT_OF_MEMORY);
-#endif
}
}
@@ -4107,7 +4218,7 @@ nsListControlFrame::RestoreStateInternal(nsIPresContext* aPresContext,
mPresState = aState;
if (mHasBeenInitialized) { // Already called Reset, call again to update selection
- Reset(aPresContext);
+ ResetList(aPresContext);
}
return NS_OK;
}
@@ -4352,3 +4463,45 @@ nsListEventListener::DragMove(nsIDOMEvent* aMouseEvent)
return NS_OK;
}
+/*=============== Timer Related Code ======================*/
+nsresult
+nsListControlFrame::StartUpdateTimer(nsIPresContext * aPresContext)
+{
+
+ if (mUpdateTimer == nsnull) {
+ nsresult result = NS_NewUpdateTimer(&mUpdateTimer);
+ if (NS_FAILED(result))
+ return result;
+
+ mUpdateTimer->Init(this, 0); // delay "0"
+ }
+
+ if (mUpdateTimer != nsnull) {
+ return mUpdateTimer->Start(aPresContext);
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+inline void
+nsListControlFrame::StopUpdateTimer()
+{
+ if (mUpdateTimer != nsnull) {
+ mUpdateTimer->Stop();
+ }
+}
+
+void
+nsListControlFrame::ItemsHaveBeenRemoved(nsIPresContext * aPresContext)
+{
+ // Only adjust things if it is a combobox
+ // removing items on a listbox should effect anything
+ if (IsInDropDownMode()) {
+ // if items were removed ahead of the selected item the
+ // selected index is moved down
+ // if the selected item was removed then we should reset the list
+ if (mUpdateTimer->RemovedSelectedIndex()) {
+ ResetList(aPresContext);
+ }
+ }
+}
diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.h b/mozilla/layout/html/forms/src/nsListControlFrame.h
index 2f8748fe687..d6a965775fd 100644
--- a/mozilla/layout/html/forms/src/nsListControlFrame.h
+++ b/mozilla/layout/html/forms/src/nsListControlFrame.h
@@ -55,6 +55,8 @@ class nsVoidArray;
class nsIScrollableView;
class nsListControlFrame;
+class nsSelectUpdateTimer;
+class nsVoidArray;
#define NS_ILIST_EVENT_LISTENER_IID \
{/* 45BC6821-6EFB-11d4-B1EE-000064657374*/ \
@@ -152,8 +154,6 @@ protected:
/**
* Frame-based listbox.
*/
-#define FIX_FOR_BUG_50376
-
class nsListControlFrame : public nsScrollFrame,
public nsIFormControlFrame,
@@ -165,6 +165,7 @@ class nsListControlFrame : public nsScrollFrame,
{
public:
friend nsresult NS_NewListControlFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame);
+ friend class nsSelectUpdateTimer;
// nsISupports
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
@@ -220,7 +221,7 @@ public:
virtual void SetFocus(PRBool aOn = PR_TRUE, PRBool aRepaint = PR_FALSE);
virtual void ScrollIntoView(nsIPresContext* aPresContext);
virtual void MouseClicked(nsIPresContext* aPresContext);
- virtual void Reset(nsIPresContext* aPresContext);
+ virtual void Reset(nsIPresContext* aPresContext) { ResetList(aPresContext); }
virtual PRBool IsSuccessful(nsIFormControlFrame* aSubmitter);
virtual PRInt32 GetMaxNumValues();
virtual PRBool GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues,
@@ -264,6 +265,7 @@ public:
NS_IMETHOD GetOptionSelected(PRInt32 aIndex, PRBool* aValue);
NS_IMETHOD DoneAddingContent(PRBool aIsDone);
NS_IMETHOD OptionDisabled(nsIContent * aContent);
+ NS_IMETHOD MakeSureSomethingIsSelected(nsIPresContext* aPresContext) { return NS_OK; }
//nsIStatefulFrame
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
@@ -311,7 +313,8 @@ protected:
void AdjustIndexForDisabledOpt(PRInt32 &anNewIndex, PRInt32 &anOldIndex,
PRBool &aDoSetNewIndex, PRBool &aWasDisabled,
PRInt32 aNumOptions, PRInt32 aDoAdjustInc, PRInt32 aDoAdjustIncNext);
-#ifdef FIX_FOR_BUG_50376
+ virtual void ResetList(nsIPresContext* aPresContext, nsVoidArray * aInxList = nsnull);
+
// PresState Helper Methods
nsresult GetPresStateAndValueArray(nsISupportsArray ** aSuppArray);
nsresult SetOptionIntoPresState(nsISupportsArray * aSuppArray,
@@ -320,7 +323,6 @@ protected:
nsresult SetSelectionInPresState(PRInt32 aIndex, PRBool aValue);
nsresult RemoveOptionFromPresState(nsISupportsArray * aSuppArray,
PRInt32 aIndex);
-#endif
nsListControlFrame();
virtual ~nsListControlFrame();
@@ -343,7 +345,15 @@ protected:
nsIContent* GetOptionContent(PRInt32 aIndex);
PRBool IsContentSelected(nsIContent* aContent);
PRBool IsContentSelectedByIndex(PRInt32 aIndex);
- void SetContentSelected(PRInt32 aIndex, PRBool aSelected);
+ void SetContentSelected(PRInt32 aIndex,
+ PRBool aSelected,
+ PRBool aDoScrollTo = PR_TRUE,
+ nsIPresShell * aPresShell = nsnull);
+ void SetContentSelected(PRInt32 aIndex,
+ nsIContent * aContent,
+ PRBool aSelected,
+ PRBool aDoScrollTo = PR_TRUE,
+ nsIPresShell * aPresShell = nsnull);
void GetViewOffset(nsIViewManager* aManager, nsIView* aView, nsPoint& aPoint);
nsresult Deselect();
nsIFrame *GetOptionFromChild(nsIFrame* aParentFrame);
@@ -373,6 +383,11 @@ protected:
void GetScrollableView(nsIScrollableView*& aScrollableView);
+ // Timer Methods
+ nsresult StartUpdateTimer(nsIPresContext * aPresContext);
+ void StopUpdateTimer();
+ void ItemsHaveBeenRemoved(nsIPresContext * aPresContext);
+
// onChange detection
nsresult SelectionChanged(nsIContent* aContent);
@@ -417,6 +432,9 @@ protected:
PRInt16 mPassId;
nsSize mCachedDesiredMaxSize;
+ // Update timer
+ nsSelectUpdateTimer * mUpdateTimer;
+
//Resize Reflow OpitmizationSize;
nsSize mCacheSize;
nsSize mCachedMaxElementSize;