Major rework of how items are added, removed and selected (while being added and removed) with script
Now all the changes are performed, but no reflows are issued until the timer fires, which would be after the script is done executing. The selection that take place during the script execution are also cached and done afterward. Bug 53165 r=pollmann sr=attinasi a=asa git-svn-id: svn://10.0.0.236/trunk@96675 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<count;i++) {
|
||||
PRInt32 inx = (PRInt32)mInxArray[i];
|
||||
if (inx > 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<nsITimer> 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<nsIPresShell> 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<nsIDOMHTMLCollection> options = getter_AddRefs(GetOptions(mContent));
|
||||
if (options) {
|
||||
PRUint32 length = 0;
|
||||
options->GetLength(&length);
|
||||
PRUint32 i;
|
||||
for (i=0;i<length;i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
if (NS_SUCCEEDED(options->Item(i, getter_AddRefs(node)))) {
|
||||
nsCOMPtr<nsIContent> 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<nsIPresShell> 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<nsIDOMHTMLOptionElement> 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<nsIContent> 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<nsISupports> 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<nsISelectElement> 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<nsIDOMHTMLCollection> options = getter_AddRefs(GetOptions(mContent));
|
||||
if (options) {
|
||||
nsCOMPtr<nsIDOMHTMLOptionElement> 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<nsISupportsPRInt32> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<count;i++) {
|
||||
PRInt32 inx = (PRInt32)mInxArray[i];
|
||||
if (inx > 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<nsITimer> 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<nsIPresShell> 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<nsIDOMHTMLCollection> options = getter_AddRefs(GetOptions(mContent));
|
||||
if (options) {
|
||||
PRUint32 length = 0;
|
||||
options->GetLength(&length);
|
||||
PRUint32 i;
|
||||
for (i=0;i<length;i++) {
|
||||
nsCOMPtr<nsIDOMNode> node;
|
||||
if (NS_SUCCEEDED(options->Item(i, getter_AddRefs(node)))) {
|
||||
nsCOMPtr<nsIContent> 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<nsIPresShell> 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<nsIDOMHTMLOptionElement> 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<nsIContent> 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<nsISupports> 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<nsISelectElement> 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<nsIDOMHTMLCollection> options = getter_AddRefs(GetOptions(mContent));
|
||||
if (options) {
|
||||
nsCOMPtr<nsIDOMHTMLOptionElement> 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<nsISupportsPRInt32> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user