diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index 65b598acac13..a38dd5d6a093 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -126,7 +126,7 @@ nsComboboxControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } else if (aIID.Equals(kIDOMMouseListenerIID)) { *aInstancePtr = (void*)(nsIDOMMouseListener*) this; - NS_ADDREF_THIS(); + NS_ADDREF_THIS(); return NS_OK; } else if (aIID.Equals(nsCOMTypeInfo::GetIID())) { *aInstancePtr = (void*)(nsIDOMFocusListener*)this; @@ -134,8 +134,10 @@ nsComboboxControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) return NS_OK; } else if (aIID.Equals(kIAnonymousContentCreatorIID)) { *aInstancePtr = (void*)(nsIAnonymousContentCreator*) this; - NS_ADDREF_THIS(); return NS_OK; + } else if (aIID.Equals(nsCOMTypeInfo::GetIID())) { + *aInstancePtr = (void *)((nsISelectControlFrame*)this); + return NS_OK; } return nsAreaFrame::QueryInterface(aIID, aInstancePtr); @@ -314,18 +316,6 @@ nsComboboxControlFrame::ScrollIntoView(nsIPresContext* aPresContext) } } -// Toggle dropdown list. - -void -nsComboboxControlFrame::ToggleList(nsIPresContext* aPresContext) -{ - if (PR_TRUE == mDroppedDown) { - ShowList(aPresContext, PR_FALSE); - } else { - ShowList(aPresContext, PR_TRUE); - } -} - void nsComboboxControlFrame::ShowPopup(PRBool aShowPopup) @@ -508,11 +498,7 @@ nsComboboxControlFrame::PositionDropdown(nsIPresContext& aPresContext, nscoord screenHeightInPixels = 0; if (NS_SUCCEEDED(GetScreenHeight(aPresContext, screenHeightInPixels))) { - nsRect absoluteRect; - - // Get the height of the dropdown list in pixels. - nsRect dropdownRect; - dropdownFrame->GetRect(dropdownRect); + // Get the height of the dropdown list in pixels. float t2p; aPresContext.GetTwipsToPixels(&t2p); nscoord absoluteDropDownHeight = NSTwipsToIntPixels(dropdownRect.height, t2p); @@ -691,8 +677,8 @@ nsComboboxControlFrame::Reflow(nsIPresContext& aPresContext, buttonFrame->GetRect(buttonRect); if ((oldDisplayRect == displayRect) && (oldButtonRect == buttonRect)) { // Reposition the popup. - nsRect absoluteTwips; - nsRect absolutePixels; + //nsRect absoluteTwips; + //nsRect absolutePixels; //GetAbsoluteFramePosition(aPresContext, displayFrame, absoluteTwips, absolutePixels); //PositionDropdown(aPresContext, displayRect.height, absoluteTwips, absolutePixels); return rv; @@ -907,7 +893,7 @@ nsComboboxControlFrame::ReResolveStyleContext(nsIPresContext* aPresContext, nsresult nsComboboxControlFrame::MouseDown(nsIDOMEvent* aMouseEvent) { - if (nsFormFrame::GetDisabled(this)) { + /*if (nsFormFrame::GetDisabled(this)) { return NS_OK; } nsRect absoluteTwips; @@ -920,12 +906,40 @@ nsComboboxControlFrame::MouseDown(nsIDOMEvent* aMouseEvent) PositionDropdown(*mPresContext, displayRect.height, absoluteTwips, absolutePixels); ToggleList(mPresContext); + mIgnoreMouseUp = PR_TRUE; +*/ return NS_OK; } //---------------------------------------------------------------------- // nsIComboboxControlFrame //---------------------------------------------------------------------- +NS_IMETHODIMP +nsComboboxControlFrame::ShowDropDown(PRBool aDoDropDown) +{ + if (nsFormFrame::GetDisabled(this)) { + return NS_OK; + } + + if (!mDroppedDown && aDoDropDown) { + nsRect absoluteTwips; + nsRect absolutePixels; + nsIFrame * displayFrame = GetDisplayFrame(*mPresContext); + nsRect displayRect; + // Get the current sizes of the combo box child frames + displayFrame->GetRect(displayRect); + GetAbsoluteFramePosition(*mPresContext, displayFrame, absoluteTwips, absolutePixels); + PositionDropdown(*mPresContext, displayRect.height, absoluteTwips, absolutePixels); + + ToggleList(mPresContext); + return NS_OK; + } else if (mDroppedDown && !aDoDropDown) { + ToggleList(mPresContext); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} NS_IMETHODIMP nsComboboxControlFrame::SetDropDown(nsIFrame* aDropDownFrame) @@ -951,9 +965,60 @@ nsComboboxControlFrame::GetDropDown(nsIFrame** aDropDownFrame) return NS_OK; } +NS_IMETHODIMP +nsComboboxControlFrame::ListWasSelected(nsIPresContext* aPresContext) +{ + if (aPresContext == nsnull) { + aPresContext = mPresContext; + } + ShowList(aPresContext, PR_FALSE); + mListControlFrame->CaptureMouseEvents(PR_FALSE); -void -nsComboboxControlFrame::SelectionChanged() + PRInt32 index; + mListControlFrame->GetSelectedIndex(&index); + + UpdateSelection(PR_TRUE, PR_FALSE, index); + + return NS_OK; +} +// Toggle dropdown list. + +NS_IMETHODIMP +nsComboboxControlFrame::ToggleList(nsIPresContext* aPresContext) +{ + if (PR_TRUE == mDroppedDown) { + ShowList(aPresContext, PR_FALSE); + } else { + ShowList(aPresContext, PR_TRUE); + } + return NS_OK; +} + + +NS_IMETHODIMP +nsComboboxControlFrame::UpdateSelection(PRBool aDoDispatchEvent, PRBool aForceUpdate, PRInt32 aNewIndex) +{ + if (nsnull != mListControlFrame) { + // Check to see if the selection changed + if (mSelectedIndex != aNewIndex || aForceUpdate) { + nsAutoString newTextStr; + mListControlFrame->GetSelectedItem(newTextStr); + //XXX:TODO look at the ordinal position of the selected content in the listbox to tell + // if the selection has changed, rather than looking at the text string. + // There may be more than one item in the dropdown list with the same label. + if (newTextStr != mTextStr) { + mTextStr = newTextStr; + SelectionChanged(aDoDispatchEvent); + } + } + mSelectedIndex = aNewIndex; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsComboboxControlFrame::SelectionChanged(PRBool aDoDispatchEvent) { if (nsnull != mDisplayContent) { mDisplayContent->SetAttribute(kNameSpaceID_None, nsHTMLAtoms::value, mTextStr, PR_TRUE); @@ -974,25 +1039,60 @@ nsComboboxControlFrame::SelectionChanged() } } - // Dispatch the NS_FORM_CHANGE event - nsEventStatus status = nsEventStatus_eIgnore; - nsGUIEvent event; - event.eventStructType = NS_GUI_EVENT; - event.widget = nsnull; - event.message = NS_FORM_CHANGE; + if (aDoDispatchEvent) { + // Dispatch the NS_FORM_CHANGE event + nsEventStatus status = nsEventStatus_eIgnore; + nsGUIEvent event; + event.eventStructType = NS_GUI_EVENT; + event.widget = nsnull; + event.message = NS_FORM_CHANGE; - // Have the content handle the event. - mContent->HandleDOMEvent(*mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); - // Now have the frame handle the event - nsIFrame* frame = nsnull; - nsIFrame* dropdownFrame = GetDropdownFrame(); - nsresult result = dropdownFrame->QueryInterface(kIFrameIID, (void**)&frame); - if ((NS_SUCCEEDED(result)) && (nsnull != frame)) { - frame->HandleEvent(*mPresContext, &event, status); + // Have the content handle the event. + mContent->HandleDOMEvent(*mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); + // Now have the frame handle the event + nsIFrame* frame = nsnull; + nsIFrame* dropdownFrame = GetDropdownFrame(); + nsresult result = dropdownFrame->QueryInterface(kIFrameIID, (void**)&frame); + if ((NS_SUCCEEDED(result)) && (nsnull != frame)) { + frame->HandleEvent(*mPresContext, &event, status); + } } - + return NS_OK; } + +//---------------------------------------------------------------------- +// nsISelectControlFrame +//---------------------------------------------------------------------- + +NS_IMETHODIMP +nsComboboxControlFrame::AddOption(PRInt32 index) +{ + nsISelectControlFrame* listFrame = nsnull; + nsIFrame* dropdownFrame = GetDropdownFrame(); + nsresult rv = dropdownFrame->QueryInterface(nsCOMTypeInfo::GetIID(), + (void**)&listFrame); + if (NS_SUCCEEDED(rv) && nsnull != listFrame) { + return listFrame->AddOption(index); + } + return rv; +} + + +NS_IMETHODIMP +nsComboboxControlFrame::RemoveOption(PRInt32 index) +{ + nsISelectControlFrame* listFrame = nsnull; + nsIFrame* dropdownFrame = GetDropdownFrame(); + nsresult rv = dropdownFrame->QueryInterface(nsCOMTypeInfo::GetIID(), + (void**)&listFrame); + if (NS_SUCCEEDED(rv) && nsnull != listFrame) { + return listFrame->RemoveOption(index); + } + return rv; +} + + NS_IMETHODIMP nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, @@ -1009,30 +1109,6 @@ nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, } -NS_IMETHODIMP -nsComboboxControlFrame::ListWasSelected(nsIPresContext* aPresContext) -{ - ShowList(aPresContext, PR_FALSE); - mListControlFrame->CaptureMouseEvents(PR_FALSE); - - if (nsnull != mListControlFrame) { - PRInt32 index; - mListControlFrame->GetSelectedIndex(&index); - // Check to see if the selection changed - if (mSelectedIndex != index) { - mListControlFrame->GetSelectedItem(mTextStr); - mSelectedIndex = index; - //XXX:TODO look at the ordinal position of the selected content in the listbox to tell - // if the selection has changed, rather than looking at the text string. - // There may be more than one item in the dropdown list with the same label. - SelectionChanged(); - } - } - - return NS_OK; -} - - nsresult nsComboboxControlFrame::RequiresWidget(PRBool& aRequiresWidget) { diff --git a/layout/forms/nsComboboxControlFrame.h b/layout/forms/nsComboboxControlFrame.h index 608056dd84d6..d7672a19eeee 100644 --- a/layout/forms/nsComboboxControlFrame.h +++ b/layout/forms/nsComboboxControlFrame.h @@ -27,6 +27,7 @@ #include "nsIDOMFocusListener.h" #include "nsVoidArray.h" #include "nsIAnonymousContentCreator.h" +#include "nsISelectControlFrame.h" class nsButtonControlFrame; class nsTextControlFrame; @@ -47,7 +48,8 @@ class nsComboboxControlFrame : public nsAreaFrame, public nsIComboboxControlFrame, public nsIDOMMouseListener, public nsIDOMFocusListener, - public nsIAnonymousContentCreator + public nsIAnonymousContentCreator, + public nsISelectControlFrame { public: @@ -123,22 +125,33 @@ public: nscoord aCharWidth) const; virtual nsresult RequiresWidget(PRBool &aRequiresWidget); + NS_IMETHOD SelectionChanged(PRBool aDoDispatchEvent);// Called when the selection has changed. + // If the the same item in the list is selected + // it is NOT called. + // nsIFormMouseListener virtual void MouseClicked(nsIPresContext* aPresContext); //nsIComboboxControlFrame + NS_IMETHOD IsDroppedDown(PRBool * aDoDropDown) { *aDoDropDown = mDroppedDown; return NS_OK; } + NS_IMETHOD ShowDropDown(PRBool aDoDropDown); NS_IMETHOD GetDropDown(nsIFrame** aDropDownFrame); NS_IMETHOD SetDropDown(nsIFrame* aDropDownFrame); NS_IMETHOD ListWasSelected(nsIPresContext* aPresContext); + NS_IMETHOD UpdateSelection(PRBool aDoDispatchEvent, PRBool aForceUpdate, PRInt32 aNewIndex); + + // nsISelectControlFrame + NS_IMETHOD AddOption(PRInt32 index); + NS_IMETHOD RemoveOption(PRInt32 index); //nsIDOMEventListener virtual nsresult MouseDown(nsIDOMEvent* aMouseEvent); - virtual nsresult MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; } - virtual nsresult MouseClick(nsIDOMEvent* aMouseEvent) { printf("mouse clock\n"); return NS_OK; }; + virtual nsresult MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; } virtual nsresult MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; } - virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; } - virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; } - virtual nsresult HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } + virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } //nsIDOMFocusListener virtual nsresult Focus(nsIDOMEvent* aEvent); @@ -167,7 +180,6 @@ protected: nsIFrame *aFrame, nsRect& aAbsoluteTwipsRect, nsRect& aAbsolutePixelRect); - void ToggleList(nsIPresContext* aPresContext); void ShowPopup(PRBool aShowPopup); void ShowList(nsIPresContext* aPresContext, PRBool aShowList); void SetChildFrameSize(nsIFrame* aFrame, nscoord aWidth, nscoord aHeight); @@ -176,10 +188,8 @@ protected: nsIFrame* GetButtonFrame(nsIPresContext& aPresContext); nsIFrame* GetDisplayFrame(nsIPresContext& aPresContext); nsIFrame* GetDropdownFrame(); + NS_IMETHOD ToggleList(nsIPresContext* aPresContext); - // Called when the selection has changed. If the the same item in the list is selected - // it is NOT called. - void SelectionChanged(); nsFrameList mPopupFrames; // additional named child list nsIPresContext* mPresContext; // XXX: Remove the need to cache the pres context. diff --git a/layout/forms/nsIComboboxControlFrame.h b/layout/forms/nsIComboboxControlFrame.h index 74c097c162c9..b1fa59f062d5 100644 --- a/layout/forms/nsIComboboxControlFrame.h +++ b/layout/forms/nsIComboboxControlFrame.h @@ -44,6 +44,18 @@ class nsIComboboxControlFrame : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMBOBOXCONTROLFRAME_IID) + /** + * Indicates whether the list is dropped down + * + */ + NS_IMETHOD IsDroppedDown(PRBool * aDoDropDown) = 0; + + /** + * Shows or hides the drop down + * + */ + NS_IMETHOD ShowDropDown(PRBool aDoDropDown) = 0; + /** * Gets the Drop Down List * @@ -62,6 +74,15 @@ public: */ NS_IMETHOD ListWasSelected(nsIPresContext* aPresContext) = 0; + /** + * Asks the Combobox to update the display frame + * aDoDispatchEvent - indicates whether an event should be dispatched to the DOM + * aForceUpdate - indicates whether the indexx and the text value should both be + * whether the index has changed or not. + * + */ + NS_IMETHOD UpdateSelection(PRBool aDoDispatchEvent, PRBool aForceUpdate, PRInt32 aNewIndex) = 0; + }; diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 5030518c4df6..0abea03067bb 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -36,6 +36,14 @@ #include "nsWidgetsCID.h" #include "nsIReflowCommand.h" #include "nsIPresShell.h" +#include "nsHTMLParts.h" + +#include "nsIDOMEventReceiver.h" +#include "nsIEventStateManager.h" +#include "nsIDOMUIEvent.h" + +static NS_DEFINE_IID(kIDOMMouseListenerIID, NS_IDOMMOUSELISTENER_IID); +static NS_DEFINE_IID(kIDOMMouseMotionListenerIID, NS_IDOMMOUSEMOTIONLISTENER_IID); // Constants const nscoord kMaxDropDownRows = 20; // This matches the setting for 4.x browsers @@ -69,15 +77,19 @@ NS_NewListControlFrame(nsIFrame** aNewFrame) //--------------------------------------------------------- nsListControlFrame::nsListControlFrame() { - mHitFrame = nsnull; - mSelectedIndex = kNothingSelected; - mComboboxFrame = nsnull; - mFormFrame = nsnull; - mDisplayed = PR_FALSE; - mButtonDown = PR_FALSE; - mLastFrame = nsnull; - mMaxWidth = 0; - mMaxHeight = 0; + mHitFrame = nsnull; + mSelectedIndex = kNothingSelected; + mComboboxFrame = nsnull; + mFormFrame = nsnull; + mDisplayed = PR_FALSE; + mButtonDown = PR_FALSE; + mLastFrame = nsnull; + mMaxWidth = 0; + mMaxHeight = 0; + mPresContext = nsnull; + mEndExtendedIndex = kNothingSelected; + mStartExtendedIndex = kNothingSelected; + mIgnoreMouseUp = PR_FALSE; mIsCapturingMouseEvents = PR_FALSE; } @@ -86,6 +98,7 @@ nsListControlFrame::~nsListControlFrame() { mComboboxFrame = nsnull; mFormFrame = nsnull; + NS_IF_RELEASE(mPresContext); } //--------------------------------------------------------- @@ -107,136 +120,23 @@ nsListControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) *aInstancePtr = (void *)((nsIListControlFrame*)this); return NS_OK; } - - return nsScrollFrame::QueryInterface(aIID, aInstancePtr); -} - - -//--------------------------------------------------------- -NS_IMETHODIMP -nsListControlFrame::GetFrameForPoint(const nsPoint& aPoint, nsIFrame** aFrame) -{ - // Save the result of GetFrameForPointUsing in the mHitFrame member variable. - // mHitFrame is used later in the HandleLikeListEvent to determine what was clicked on. - // XXX: This is kludgy, but there doesn't seem to be a way to get what was just clicked - // on in the HandleEvent. The GetFrameForPointUsing is always called before the HandleEvent. - // - nsresult rv; - mHitFrame = nsnull; - nsIFrame *childFrame; - FirstChild(nsnull, &childFrame); - rv = GetFrameForPointUsing(aPoint, nsnull, aFrame); - if (NS_SUCCEEDED(rv)) { - if (*aFrame != this) { - *aFrame = GetSelectableFrame(*aFrame); - if (nsnull == *aFrame) { - mHitFrame = this; - } else { - mHitFrame = *aFrame; - } - *aFrame = this; - } + if (aIID.Equals(nsCOMTypeInfo::GetIID())) { + *aInstancePtr = (void *)((nsISelectControlFrame*)this); return NS_OK; } - *aFrame = this; - return NS_ERROR_FAILURE; - -} - -//--------------------------------------------------------- -nsresult -nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, - nsIAtom* aList, - nsIFrame** aFrame) -{ - nsIFrame* kid = nsnull; - nsRect kidRect; - nsPoint tmp; - nsRect offset(0, 0, 0, 0); - *aFrame = nsnull; - nsIFrame* firstKid = nsnull; - - // Get the scrolled offset from the view. - // - // XXX:Hack. This should not be necessary. It is only required because we interpose on the - // normal event flow by redirecting to the listbox using the SetVFlags(NS_DONT_CHECK_CHILDREN). - // What we should really do is have a manager which the option items report there events to. - // The listbox frame would be the manager for the option items. KMM. - // - // - // This is needed because: - // The scrolled view is below the nsListControlFrame's ScrollingView in - // the view hierarchy. This presents a problem for event translation when the events - // are re-directed with the nsView::SetVFlags(NS_DONT_CHECK_CHILDREN). Since - // the handling of the view event is short-circuited at the nsListControlFrame's - // scrolling view level mouse click events do not have the scolled offset added to them. - // The view containing the offset is below the nsListControlFrame's scrolling - // view, so the short-circuiting of the event processing provided by nsView:SetVFlags(NS_DONT_CHECK_CHILDREN) - // prevents the scrolled view's offset from ever being added to the event's offset. - // When nsListControlFrame::GetFrameForPoint is invoked the nsPoint passed in does not include the scrolled view offset, - // so the frame returned will always be wrong when the listbox is scrolled. - // As a hack we adjust for missing view offset by adding code to the nsListControlFrame::GetFrameForPoint which first - // gets the ScrollableView associated with the nsListControlFrame and asks for it's GetScrollPosition offsets. These are - // added to the point that is passed in so the correct frame is returned from nsListControlFrame::GetFrameForPoint. - - tmp.MoveTo(aPoint.x, aPoint.y); - nsIView *view = nsnull; - GetView(&view); - if (nsnull != view) { - nscoord offsetx; - nscoord offsety; - nsIScrollableView* scrollableView; - if (NS_SUCCEEDED(view->QueryInterface(nsCOMTypeInfo::GetIID(),(void **)&scrollableView))) { - scrollableView->GetScrollPosition(offsetx, offsety); - tmp.x += offsetx; - tmp.y += offsety; - // Note: scrollableView is not ref counted - } - } - - // Remove the top border from the offset. - nsMargin border; - tmp.y -= mBorderOffsetY; - - mContentFrame->FirstChild(aList, &kid); - while (nsnull != kid) { - kid->GetRect(kidRect); - if (kidRect.Contains(tmp)) { - tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); - - nsIContent * content; - kid->GetContent(&content); - nsCOMPtr optEle; - if (content && NS_SUCCEEDED(content->QueryInterface(nsCOMTypeInfo::GetIID(),(void**) getter_AddRefs(optEle)))) { - *aFrame = kid; - NS_RELEASE(content); - return NS_OK; - } - NS_RELEASE(content); - return kid->GetFrameForPoint(tmp, aFrame); - } - kid->GetNextSibling(&kid); + if (aIID.Equals(kIDOMMouseListenerIID)) { + *aInstancePtr = (void*)(nsIDOMMouseListener*) this; + NS_ADDREF_THIS(); + return NS_OK; } - - mContentFrame->FirstChild(aList, &kid); - while (nsnull != kid) { - nsFrameState state; - kid->GetFrameState(&state); - if (NS_FRAME_OUTSIDE_CHILDREN & state) { - kid->GetRect(kidRect); - tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); - if (NS_OK == kid->GetFrameForPoint(tmp, aFrame)) { - return NS_OK; - } - } - kid->GetNextSibling(&kid); + if (aIID.Equals(kIDOMMouseMotionListenerIID)) { + *aInstancePtr = (void*)(nsIDOMMouseMotionListener*) this; + NS_ADDREF_THIS(); + return NS_OK; } - *aFrame = this; - return NS_ERROR_FAILURE; - + return nsScrollFrame::QueryInterface(aIID, aInstancePtr); } - //--------------------------------------------------------- // Reflow is overriden to constrain the listbox height to the number of rows and columns // specified. @@ -326,7 +226,7 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, dc->GetScrollBarDimensions(sbWidth, sbHeight); // Convert to nscoord's by rounding nscoord scrollbarWidth = NSToCoordRound(sbWidth); - nscoord scrollbarHeight = NSToCoordRound(sbHeight); + //nscoord scrollbarHeight = NSToCoordRound(sbHeight); // Subtract out the scrollbar width scrolledAreaWidth -= scrollbarWidth; @@ -566,13 +466,14 @@ nsListControlFrame::DisplaySelected(nsIContent* aContent) // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager supports selected states. KMM - nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); + nsIAtom * selectedAtom = NS_NewAtom(kMozSelected); if (PR_TRUE == mDisplayed) { aContent->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_TRUE); ForceRedraw(); } else { aContent->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_FALSE); } + NS_RELEASE(selectedAtom); } //--------------------------------------------------------- @@ -583,50 +484,87 @@ nsListControlFrame::DisplayDeselected(nsIContent* aContent) // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager is functional. KMM - nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); - + nsIAtom * selectedAtom = NS_NewAtom(kMozSelected); if (PR_TRUE == mDisplayed) { aContent->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_TRUE); ForceRedraw(); } else { aContent->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_FALSE); } + NS_RELEASE(selectedAtom); } +//--------------------------------------------------------- +// Starts at the passed in content object and walks up the +// parent heierarchy looking for the nsIDOMHTMLOptionElement +//--------------------------------------------------------- +nsIContent * +nsListControlFrame::GetOptionFromContent(nsIContent *aContent) +{ + nsIContent * content = aContent; + NS_ADDREF(content); + while (nsnull != content) { + if (IsOptionElement(content)) { + return content; + } + nsIContent * node = content; + node->GetParent(content); // this add refs + NS_RELEASE(node); + } + return nsnull; +} + +//--------------------------------------------------------- +// Finds the index of the hit frame's content in the list +// of option elements +//--------------------------------------------------------- +PRInt32 +nsListControlFrame::GetSelectedIndexFromContent(nsIContent *aContent) +{ + // Search the list of option elements looking for a match + // between the hit frame's content and the content of an option element + + // get the collection of option items + nsIDOMHTMLCollection* options = GetOptions(mContent); + if (nsnull != options) { + PRUint32 numOptions; + options->GetLength(&numOptions); + + PRUint32 inx; + for (inx = 0; inx < numOptions; inx++) { + nsIContent* option = nsnull; + option = GetOptionAsContent(options, inx); + if (nsnull != option) { + if (option == aContent) { + NS_RELEASE(option); + NS_RELEASE(options); + return inx; + } + NS_RELEASE(option); + } + } + NS_RELEASE(options); + } + return kNothingSelected; +} + +//--------------------------------------------------------- +// Finds the index of the hit frame's content in the list +// of option elements //--------------------------------------------------------- PRInt32 nsListControlFrame::GetSelectedIndexFromFrame(nsIFrame *aHitFrame) { - PRInt32 index = kNothingSelected; + PRInt32 index = kNothingSelected; // Get the content of the frame that was selected nsIContent* selectedContent = nsnull; NS_ASSERTION(aHitFrame, "No frame for html element\n"); if (aHitFrame) { aHitFrame->GetContent(&selectedContent); - - // Search the list of option elements looking for a match - - PRInt32 length = 0; - GetNumberOfOptions(&length); - nsIDOMHTMLCollection* options = GetOptions(mContent); - if (nsnull != options) { - PRUint32 numOptions; - options->GetLength(&numOptions); - for (PRUint32 optionX = 0; optionX < numOptions; optionX++) { - nsIContent* option = nsnull; - option = GetOptionAsContent(options, optionX); - if (nsnull != option) { - if (option == selectedContent) { - index = optionX; - break; - } - NS_RELEASE(option); - } - } - NS_RELEASE(options); - } + index = GetSelectedIndexFromContent(selectedContent); + NS_RELEASE(selectedContent); } return index; } @@ -640,8 +578,8 @@ nsListControlFrame::ClearSelection() GetNumberOfOptions(&length); for (PRInt32 i = 0; i < length; i++) { if (i != mSelectedIndex) { - SetFrameSelected(i, PR_FALSE); - } + SetContentSelected(i, PR_FALSE); + } } } @@ -671,9 +609,9 @@ nsListControlFrame::ExtendedSelection(PRInt32 aStartIndex, PRInt32 aEndIndex, PR } if (startInverting && ((i != mStartExtendedIndex && aDoInvert) || !aDoInvert)) { if (aDoInvert) { - SetFrameSelected(i, !IsFrameSelected(i)); + SetContentSelected(i, !IsContentSelectedByIndex(i)); } else { - SetFrameSelected(i, aSetValue); + SetContentSelected(i, aSetValue); } } if (i == endInx) { @@ -686,23 +624,17 @@ nsListControlFrame::ExtendedSelection(PRInt32 aStartIndex, PRInt32 aEndIndex, PR void nsListControlFrame::SingleSelection() { - if (nsnull != mHitFrame) { - // Store previous selection - PRInt32 oldSelectedIndex = mSelectedIndex; - // Get Current selection - PRInt32 newSelectedIndex = (PRInt32)GetSelectedIndexFromFrame(mHitFrame); - if (newSelectedIndex != kNothingSelected) { - if (oldSelectedIndex != newSelectedIndex) { - // Deselect the previous selection if there is one - if (oldSelectedIndex != kNothingSelected) { - SetFrameSelected(oldSelectedIndex, PR_FALSE); - } - // Display the new selection - SetFrameSelected(newSelectedIndex, PR_TRUE); - mSelectedIndex = newSelectedIndex; - } else { - // Selecting the currently selected item so do nothing. + // Get Current selection + if (mSelectedIndex != kNothingSelected) { + if (mOldSelectedIndex != mSelectedIndex) { + // Deselect the previous selection if there is one + if (mOldSelectedIndex != kNothingSelected) { + SetContentSelected(mOldSelectedIndex, PR_FALSE); } + // Display the new selection + SetContentSelected(mSelectedIndex, PR_TRUE); + } else { + // Selecting the currently selected item so do nothing. } } } @@ -711,69 +643,71 @@ nsListControlFrame::SingleSelection() void nsListControlFrame::MultipleSelection(PRBool aIsShift, PRBool aIsControl) { - if (nsnull != mHitFrame) { - mSelectedIndex = (PRInt32)GetSelectedIndexFromFrame(mHitFrame); if (kNothingSelected != mSelectedIndex) { - if ((aIsShift) || (mButtonDown && (!aIsControl))) { - // Shift is held down - SetFrameSelected(mSelectedIndex, PR_TRUE); - if (mEndExtendedIndex == kNothingSelected) { - mEndExtendedIndex = mSelectedIndex; - ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); - } else { - if (mStartExtendedIndex < mEndExtendedIndex) { - if (mSelectedIndex < mStartExtendedIndex) { - ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } - } else if (mStartExtendedIndex > mEndExtendedIndex) { - if (mSelectedIndex > mStartExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } + if ((aIsShift) || (mButtonDown && (!aIsControl))) { + // Shift is held down + SetContentSelected(mSelectedIndex, PR_TRUE); + if (mEndExtendedIndex == kNothingSelected) { + mEndExtendedIndex = mSelectedIndex; + ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); + } else { + if (mStartExtendedIndex < mEndExtendedIndex) { + if (mSelectedIndex < mStartExtendedIndex) { + ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; + } + } else if (mStartExtendedIndex > mEndExtendedIndex) { + if (mSelectedIndex > mStartExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; } } - } else if (aIsControl) { - // Control is held down - if (IsFrameSelected(mSelectedIndex)) { - SetFrameSelected(mSelectedIndex, PR_FALSE); - } else { - SetFrameSelected(mSelectedIndex, PR_TRUE); - } - - } else { - // Neither control nor shift is held down - SetFrameSelected(mSelectedIndex, PR_TRUE); - mStartExtendedIndex = mSelectedIndex; - mEndExtendedIndex = kNothingSelected; - ClearSelection(); } - } - } + } else if (aIsControl) { + // Control is held down + if (IsContentSelectedByIndex(mSelectedIndex)) { + SetContentSelected(mSelectedIndex, PR_FALSE); + } else { + SetContentSelected(mSelectedIndex, PR_TRUE); + } + + } else { + // Neither control nor shift is held down + SetContentSelected(mSelectedIndex, PR_TRUE); + mStartExtendedIndex = mSelectedIndex; + mEndExtendedIndex = kNothingSelected; + ClearSelection(); + } + } + } //--------------------------------------------------------- void -nsListControlFrame::HandleListSelection(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus) +nsListControlFrame::HandleListSelection(nsIDOMEvent* aEvent) { + PRBool multipleSelections = PR_FALSE; GetMultiple(&multipleSelections); if (multipleSelections) { - MultipleSelection(((nsMouseEvent *)aEvent)->isShift, ((nsMouseEvent *)aEvent)->isControl); + nsCOMPtr uiEvent = do_QueryInterface(aEvent); + PRBool isShift; + PRBool isControl; + uiEvent->GetCtrlKey(&isControl); + uiEvent->GetShiftKey(&isShift); + MultipleSelection(isShift, isControl); } else { SingleSelection(); } @@ -802,39 +736,9 @@ nsListControlFrame::HasSameContent(nsIFrame* aFrame1, nsIFrame* aFrame2) return(result); } - -//--------------------------------------------------------- -nsresult -nsListControlFrame::HandleLikeListEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus) -{ - if (nsnull != mHitFrame) { - - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { - HandleListSelection(aPresContext, aEvent, aEventStatus); - mButtonDown = PR_TRUE; - CaptureMouseEvents(PR_TRUE); - mLastFrame = mHitFrame; - } else if (aEvent->message == NS_MOUSE_MOVE) { - if ((PR_TRUE == mButtonDown) && (! HasSameContent(mLastFrame, mHitFrame))) { - HandleListSelection(aPresContext, aEvent, aEventStatus); - mLastFrame = mHitFrame; - } - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { - mButtonDown = PR_FALSE; - CaptureMouseEvents(PR_FALSE); - } - - } - - aEventStatus = nsEventStatus_eConsumeNoDefault; - return NS_OK; -} - //--------------------------------------------------------- NS_IMETHODIMP -nsListControlFrame :: CaptureMouseEvents(PRBool aGrabMouseEvents) +nsListControlFrame::CaptureMouseEvents(PRBool aGrabMouseEvents) { // get its view @@ -904,77 +808,6 @@ nsListControlFrame::IsAncestor(nsIView* aAncestor, nsIView* aChild) } -//--------------------------------------------------------- -nsresult -nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus) -{ - if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { - if (nsnull == mHitFrame) { - // Button down without hitting a frame in the drop down list. - - // May need to give the scrollbars a chance at the event. - // The drop down list's scrollbar view will be a descendant - // of the drop down list's view. So check to see if the view - // that associated with event's widget is a descendant. - // If so, then we do not pop the drop down list back up. - nsIView* eventView = GetViewFor(aEvent->widget); - nsIView* view=nsnull; - GetView(&view); - if (PR_TRUE == IsAncestor(view, eventView)) { - return NS_OK; - } - // Roll the drop-down list back up. - mComboboxFrame->ListWasSelected(&aPresContext); - return NS_OK; - } - } - - // Mouse Move behavior is as follows: - // When the DropDown occurs, if an item is selected it displayed as being selected. - // It may or may not be currently visible, when the mouse is moved across any item - // in the the list it is displayed as the currently selected item. - // (Selection doesn't actually occur until the mouse is released, or clicked and released) - if (aEvent->message == NS_MOUSE_MOVE) { - - // If the DropDown is currently has a selected item - // then clear the selected item - - if (nsnull != mHitFrame) { - PRInt32 oldSelectedIndex = mSelectedIndex; - PRInt32 newSelectedIndex = GetSelectedIndexFromFrame(mHitFrame); - if (kNothingSelected != newSelectedIndex) { - if (oldSelectedIndex != newSelectedIndex) { - if (oldSelectedIndex != kNothingSelected) { - SetFrameSelected(oldSelectedIndex, PR_FALSE); - } - SetFrameSelected(newSelectedIndex, PR_TRUE); - mSelectedIndex = newSelectedIndex; - } - } - } - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { - // Start by finding the newly "hit" content from the hit frame - if (nsnull != mHitFrame) { - PRInt32 index = GetSelectedIndexFromFrame(mHitFrame); - if (kNothingSelected != index) { - SetFrameSelected(index, PR_TRUE); - mSelectedIndex = index; - } - - if (mComboboxFrame) { - mComboboxFrame->ListWasSelected(&aPresContext); - } - } - - } - - aEventStatus = nsEventStatus_eConsumeNoDefault; - return NS_OK; -} - - //--------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::HandleEvent(nsIPresContext& aPresContext, @@ -1006,7 +839,7 @@ nsListControlFrame::HandleEvent(nsIPresContext& aPresContext, printf("Mouse in ListFrame [%d]\n", aEvent->message); }*/ - if (nsEventStatus_eConsumeNoDefault == aEventStatus) { + /*if (nsEventStatus_eConsumeNoDefault == aEventStatus) { return NS_OK; } @@ -1023,12 +856,7 @@ nsListControlFrame::HandleEvent(nsIPresContext& aPresContext, HandleLikeDropDownListEvent(aPresContext, aEvent, aEventStatus); } else { HandleLikeListEvent(aPresContext, aEvent, aEventStatus); - } - - if (aEvent->message == NS_KEY_PRESS) { - int x = 0; - x++; - } + }*/ return NS_OK; } @@ -1066,6 +894,8 @@ nsListControlFrame::Init(nsIPresContext& aPresContext, nsIStyleContext* aContext, nsIFrame* aPrevInFlow) { + mPresContext = &aPresContext; + NS_ADDREF(mPresContext); nsresult result = nsScrollFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); // Initialize the current selected and not selected state's for @@ -1077,7 +907,16 @@ nsListControlFrame::Init(nsIPresContext& aPresContext, if (!mIsInitializedFromContent) { Reset(); } - + + // get the reciever interface from the browser button's content node + nsCOMPtr reciever(do_QueryInterface(mContent)); + + // we shouldn't have to unregister this listener because when + // our frame goes away all these content node go away as well + // because our frame is the only one who references them. + reciever->AddEventListenerByIID((nsIDOMMouseListener *)this, kIDOMMouseListenerIID); + reciever->AddEventListenerByIID((nsIDOMMouseMotionListener *)this, kIDOMMouseMotionListenerIID); + return result; } @@ -1102,13 +941,17 @@ nsListControlFrame::GetHorizontalInsidePadding(nsIPresContext& aPresContext, } +//--------------------------------------------------------- +// Returns whether the nsIDOMHTMLSelectElement supports +// mulitple selection //--------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetMultiple(PRBool* aMultiple, nsIDOMHTMLSelectElement* aSelect) { if (!aSelect) { nsIDOMHTMLSelectElement* selectElement = nsnull; - nsresult result = mContent->QueryInterface(nsCOMTypeInfo::GetIID(),(void**)&selectElement); + nsresult result = mContent->QueryInterface(nsCOMTypeInfo::GetIID(), + (void**)&selectElement); if (NS_SUCCEEDED(result) && selectElement) { result = selectElement->GetMultiple(aMultiple); NS_RELEASE(selectElement); @@ -1120,12 +963,16 @@ nsListControlFrame::GetMultiple(PRBool* aMultiple, nsIDOMHTMLSelectElement* aSel } +//--------------------------------------------------------- +// for a given piece of content it returns nsIDOMHTMLSelectElement object +// or null //--------------------------------------------------------- nsIDOMHTMLSelectElement* nsListControlFrame::GetSelect(nsIContent * aContent) { nsIDOMHTMLSelectElement* selectElement = nsnull; - nsresult result = aContent->QueryInterface(nsCOMTypeInfo::GetIID(),(void**)&selectElement); + nsresult result = aContent->QueryInterface(nsCOMTypeInfo::GetIID(), + (void**)&selectElement); if (NS_SUCCEEDED(result) && selectElement) { return selectElement; } else { @@ -1134,14 +981,16 @@ nsListControlFrame::GetSelect(nsIContent * aContent) } +//--------------------------------------------------------- +// Returns the nsIContent object in the collection +// for a given index //--------------------------------------------------------- nsIContent* -nsListControlFrame::GetOptionAsContent(nsIDOMHTMLCollection* aCollection,PRUint32 aIndex) +nsListControlFrame::GetOptionAsContent(nsIDOMHTMLCollection* aCollection, PRUint32 aIndex) { - nsIContent *content = nsnull; + nsIContent * content = nsnull; nsIDOMHTMLOptionElement* optionElement = GetOption(*aCollection, aIndex); if (nsnull != optionElement) { - content = nsnull; optionElement->QueryInterface(nsCOMTypeInfo::GetIID(),(void**) &content); NS_RELEASE(optionElement); } @@ -1149,6 +998,9 @@ nsListControlFrame::GetOptionAsContent(nsIDOMHTMLCollection* aCollection,PRUint3 return content; } +//--------------------------------------------------------- +// for a given index it returns the nsIContent object +// from the select //--------------------------------------------------------- nsIContent* nsListControlFrame::GetOptionContent(PRUint32 aIndex) @@ -1164,47 +1016,8 @@ nsListControlFrame::GetOptionContent(PRUint32 aIndex) } //--------------------------------------------------------- -PRBool -nsListControlFrame::IsContentSelected(nsIContent* aContent) -{ - nsString value; - nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); - nsresult result = aContent->GetAttribute(kNameSpaceID_None, selectedAtom, value); - - if (NS_CONTENT_ATTR_NOT_THERE == result) { - return(PR_FALSE); - } - else { - return(PR_TRUE); - } -} - - -//--------------------------------------------------------- -PRBool -nsListControlFrame::IsFrameSelected(PRUint32 aIndex) -{ - nsIContent* content = GetOptionContent(aIndex); - NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); - PRBool result = IsContentSelected(content); - NS_RELEASE(content); - return result; -} - -//--------------------------------------------------------- -void -nsListControlFrame::SetFrameSelected(PRUint32 aIndex, PRBool aSelected) -{ - nsIContent* content = GetOptionContent(aIndex); - NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); - if (aSelected) { - DisplaySelected(content); - } else { - DisplayDeselected(content); - } - NS_IF_RELEASE(content); -} - +// This returns the collection for nsIDOMHTMLSelectElement or +// the nsIContent object is the select is null //--------------------------------------------------------- nsIDOMHTMLCollection* nsListControlFrame::GetOptions(nsIContent * aContent, nsIDOMHTMLSelectElement* aSelect) @@ -1225,6 +1038,9 @@ nsListControlFrame::GetOptions(nsIContent * aContent, nsIDOMHTMLSelectElement* a } } +//--------------------------------------------------------- +// Returns the nsIDOMHTMLOptionElement for a given index +// in the select's collection //--------------------------------------------------------- nsIDOMHTMLOptionElement* nsListControlFrame::GetOption(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex) @@ -1233,7 +1049,7 @@ nsListControlFrame::GetOption(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex if (NS_SUCCEEDED(aCollection.Item(aIndex, &node))) { if (nsnull != node) { nsIDOMHTMLOptionElement* option = nsnull; - node->QueryInterface(nsCOMTypeInfo::GetIID(),(void**)&option); + node->QueryInterface(nsCOMTypeInfo::GetIID(), (void**)&option); NS_RELEASE(node); return option; } @@ -1242,9 +1058,15 @@ nsListControlFrame::GetOption(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex } +//--------------------------------------------------------- +// For a given index in the collection it sets the aValue +// parameter with the "value" ATTRIBUTE from the DOM element +// This method return PR_TRUE if successful //--------------------------------------------------------- PRBool -nsListControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex, nsString& aValue) +nsListControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection, + PRUint32 aIndex, + nsString& aValue) { PRBool status = PR_FALSE; nsIDOMHTMLOptionElement* option = GetOption(aCollection, aIndex); @@ -1263,6 +1085,59 @@ nsListControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection, PRUint32 a return status; } +//--------------------------------------------------------- +// For a given piece of content, it determines whether the +// content (an option) is selected or not +// return PR_TRUE if it is, PR_FALSE if it is NOT +//--------------------------------------------------------- +PRBool +nsListControlFrame::IsContentSelected(nsIContent* aContent) +{ + nsString value; + nsIAtom * selectedAtom = NS_NewAtom(kMozSelected); + nsresult result = aContent->GetAttribute(kNameSpaceID_None, selectedAtom, value); + NS_RELEASE(selectedAtom); + + return (NS_CONTENT_ATTR_NOT_THERE == result ? PR_FALSE : PR_TRUE); +} + + +//--------------------------------------------------------- +// For a given index is return whether the content is selected +//--------------------------------------------------------- +PRBool +nsListControlFrame::IsContentSelectedByIndex(PRUint32 aIndex) +{ + nsIContent* content = GetOptionContent(aIndex); + NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); + + PRBool result = IsContentSelected(content); + NS_RELEASE(content); + return result; +} + +//--------------------------------------------------------- +// gets the content (an option) by index and then set it as +// being selected or not selected +//--------------------------------------------------------- +void +nsListControlFrame::SetContentSelected(PRUint32 aIndex, PRBool aSelected) +{ + if (aIndex == kNothingSelected) { + return; + } + nsIContent* content = GetOptionContent(aIndex); + NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); + if (aSelected) { + DisplaySelected(content); + } else { + DisplayDeselected(content); + } + NS_IF_RELEASE(content); +} + +//--------------------------------------------------------- +// Deselects all the content items in the select //--------------------------------------------------------- nsresult nsListControlFrame::Deselect() @@ -1271,7 +1146,7 @@ nsListControlFrame::Deselect() PRInt32 max = 0; GetNumberOfOptions(&max); for (i=0;iGetLength(&numOptions); Deselect(); - for (PRUint32 i = 0; i < numOptions; i++) { + PRUint32 i; + for (i = 0; i < numOptions; i++) { nsIDOMHTMLOptionElement* option = GetOption(*options, i); if (option) { PRBool selected = PR_FALSE; option->GetDefaultSelected(&selected); if (selected) { mSelectedIndex = i; - SetFrameSelected(i, PR_TRUE); + SetContentSelected(i, PR_TRUE); } NS_RELEASE(option); } @@ -1397,7 +1276,7 @@ nsListControlFrame::GetNumberOfSelections() GetNumberOfOptions(&length); PRInt32 i = 0; for (i = 0; i < length; i++) { - if (IsFrameSelected(i)) { + if (IsContentSelectedByIndex(i)) { count++; } } @@ -1440,7 +1319,7 @@ nsListControlFrame::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, PRInt32 length = 0; GetNumberOfOptions(&length); for (int i = 0; i < length; i++) { - if (PR_TRUE == IsFrameSelected(i)) { + if (PR_TRUE == IsContentSelectedByIndex(i)) { nsAutoString value; GetOptionValue(*options, i, value); aNames[aNumValues] = name; @@ -1489,6 +1368,10 @@ nsListControlFrame::SetComboboxFrame(nsIFrame* aComboboxFrame) } +//--------------------------------------------------------- +// Gets the text of the currently selected item +// if the there are zero items then an empty string is returned +// if there is nothing selected, then the 0th item's text is returned //--------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetSelectedItem(nsString & aStr) @@ -1496,15 +1379,25 @@ nsListControlFrame::GetSelectedItem(nsString & aStr) aStr = ""; nsresult rv = NS_ERROR_FAILURE; nsIDOMHTMLCollection* options = GetOptions(mContent); + if (nsnull != options) { - nsIDOMHTMLOptionElement* optionElement = GetOption(*options, mSelectedIndex); - if (nsnull != optionElement) { - nsAutoString text; - if (NS_CONTENT_ATTR_HAS_VALUE == optionElement->GetText(text)) { - aStr = text; - rv = NS_OK; + PRUint32 numOptions; + options->GetLength(&numOptions); + + if (numOptions == 0) { + rv = NS_OK; + } else { + PRInt32 selectedIndex = (mSelectedIndex == kNothingSelected ? 0 : mSelectedIndex); + + nsIDOMHTMLOptionElement* optionElement = GetOption(*options, selectedIndex); + if (nsnull != optionElement) { + nsAutoString text; + if (NS_CONTENT_ATTR_HAS_VALUE == optionElement->GetText(text)) { + aStr = text; + rv = NS_OK; + } + NS_RELEASE(optionElement); } - NS_RELEASE(optionElement); } NS_RELEASE(options); } @@ -1520,6 +1413,33 @@ nsListControlFrame::GetSelectedIndex(PRInt32 * aIndex) return NS_OK; } +//--------------------------------------------------------- +NS_IMETHODIMP +nsListControlFrame::GetSelectedIndexFromDOM(PRInt32 * aIndex) +{ + // figure out which item is selected by looking at which + // option are selected + *aIndex = kNothingSelected; + nsIDOMHTMLCollection* options = GetOptions(mContent); + if (options) { + PRUint32 numOptions; + options->GetLength(&numOptions); + + PRUint32 inx; + for (inx = 0; inx < numOptions && (*aIndex == kNothingSelected); inx++) { + nsIContent* content = GetOptionAsContent(options, inx); + if (nsnull != content) { + if (IsContentSelected(content)) { + *aIndex = (PRInt32)inx; + } + NS_RELEASE(content); + } + } + NS_RELEASE(options); + } + return NS_ERROR_FAILURE; +} + //--------------------------------------------------------- PRBool nsListControlFrame::IsInDropDownMode() @@ -1563,16 +1483,61 @@ nsListControlFrame::ToggleSelected(PRInt32 aIndex) GetMultiple(&multiple); if (PR_TRUE == multiple) { - SetFrameSelected(aIndex, PR_TRUE); + SetContentSelected(aIndex, PR_TRUE); } else { - if (mSelectedIndex != kNothingSelected) { - SetFrameSelected(mSelectedIndex, PR_FALSE); - } - SetFrameSelected(aIndex, PR_TRUE); + SetContentSelected(mSelectedIndex, PR_FALSE); + SetContentSelected(aIndex, PR_TRUE); mSelectedIndex = aIndex; } } +//---------------------------------------------------------------------- +// nsISelectControlFrame +//---------------------------------------------------------------------- +NS_IMETHODIMP +nsListControlFrame::AddOption(PRInt32 aIndex) +{ + PRInt32 numOptions; + GetNumberOfOptions(&numOptions); + + PRInt32 selectedIndex; + GetSelectedIndexFromDOM(&selectedIndex); // comes from the DOM + + if (1 == numOptions || mSelectedIndex == kNothingSelected || selectedIndex != mSelectedIndex) { + mSelectedIndex = selectedIndex; + if (nsnull != mComboboxFrame) { + mComboboxFrame->UpdateSelection(PR_FALSE, PR_TRUE, selectedIndex); // don't dispatch event + } + } else { + mSelectedIndex = selectedIndex; + } + return NS_OK; +} + + +NS_IMETHODIMP +nsListControlFrame::RemoveOption(PRInt32 aIndex) +{ + PRInt32 numOptions; + GetNumberOfOptions(&numOptions); + + PRInt32 selectedIndex; + GetSelectedIndexFromDOM(&selectedIndex); // comes from the DOM + + if (aIndex == mSelectedIndex) { + ToggleSelected(selectedIndex); // sets mSelectedIndex + } else { + mSelectedIndex = selectedIndex; + } + if (nsnull != mComboboxFrame) { + mComboboxFrame->UpdateSelection(PR_FALSE, PR_TRUE, selectedIndex); // don't dispatch event + } + + return NS_OK; +} +//---------------------------------------------------------------------- +// End nsISelectControlFrame +//---------------------------------------------------------------------- //--------------------------------------------------------- NS_IMETHODIMP @@ -1587,7 +1552,12 @@ nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) return NS_ERROR_INVALID_ARG; // Couldn't convert to integer } else { // Select the specified item in the list box. - ToggleSelected(selectedIndex); + if (mSelectedIndex != selectedIndex) { + ToggleSelected(selectedIndex);// sets mSelectedIndex + if (nsnull != mComboboxFrame) { + mComboboxFrame->UpdateSelection(PR_FALSE, PR_TRUE, selectedIndex); // don't dispatch event + } + } } } @@ -1604,13 +1574,18 @@ nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) PRBool selected = PR_FALSE; PRInt32 index = aValue.ToInteger(&error, 10); // Get index from aValue if (error == 0) - selected = IsFrameSelected(index); + selected = IsContentSelectedByIndex(index); nsFormControlHelper::GetBoolString(selected, aValue); // For selectedIndex, get the value from the widget } else if (nsHTMLAtoms::selectedindex == aName) { - aValue.Append(mSelectedIndex, 10); + // figures out the first selected item from the content + PRInt32 selectedIndex; + GetSelectedIndexFromDOM(&selectedIndex); + aValue.Append(selectedIndex, 10); + //aValue.Append(mSelectedIndex, 10); + } return NS_OK; @@ -1779,4 +1754,120 @@ nsListControlFrame::SetSuggestedSize(nscoord aWidth, nscoord aHeight) return NS_OK; } +//---------------------------------------------------------------------- +// nsIDOMMouseListener +//---------------------------------------------------------------------- +nsresult +nsListControlFrame::MouseUp(nsIDOMEvent* aMouseEvent) +{ + //if (nsEventStatus_eConsumeNoDefault == aEventStatus) { + // return NS_OK; + //} + + if (nsFormFrame::GetDisabled(this)) { + return NS_OK; + } + + const nsStyleDisplay* disp = (const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) { + return NS_OK; + } + + if (IsInDropDownMode() == PR_TRUE) { + if (NS_SUCCEEDED(GetIndexFromDOMEvent(aMouseEvent))) { + if (kNothingSelected != mSelectedIndex) { + SetContentSelected(mSelectedIndex, PR_TRUE); + } + if (mComboboxFrame) { + mComboboxFrame->ListWasSelected(mPresContext); + } + } + } else { + mButtonDown = PR_FALSE; + CaptureMouseEvents(PR_FALSE); + } + + return NS_OK; +} + + +//---------------------------------------------------------------------- +// Sets the mSelectedIndex and mOldSelectedIndex from figuring out what +// item was selected using content +// Returns NS_OK if it successfully found the selection +//---------------------------------------------------------------------- +nsresult +nsListControlFrame::GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent) +{ + nsresult rv = NS_ERROR_FAILURE; + nsIEventStateManager *stateManager; + if (NS_OK == mPresContext->GetEventStateManager(&stateManager)) { + nsIContent * content; + stateManager->GetEventTargetContent(&content); + + nsIContent * optionContent = GetOptionFromContent(content); + NS_RELEASE(content); + if (nsnull != optionContent) { + mOldSelectedIndex = mSelectedIndex; + mSelectedIndex = GetSelectedIndexFromContent(optionContent); + NS_RELEASE(optionContent); + rv = NS_OK; + } + NS_RELEASE(stateManager); + } + + return rv; +} + +//---------------------------------------------------------------------- +nsresult +nsListControlFrame::MouseDown(nsIDOMEvent* aMouseEvent) +{ + if (nsFormFrame::GetDisabled(this)) { + return NS_OK; + } + + if (NS_SUCCEEDED(GetIndexFromDOMEvent(aMouseEvent))) { + if (IsInDropDownMode() == PR_TRUE) { + // Do nothing + } else { + // Handle Like List + mButtonDown = PR_TRUE; + CaptureMouseEvents(PR_TRUE); + HandleListSelection(aMouseEvent); + } + } else { + if (mComboboxFrame) { + PRBool isDroppedDown; + mComboboxFrame->IsDroppedDown(&isDroppedDown); + mComboboxFrame->ShowDropDown(!isDroppedDown); + if (isDroppedDown) { + CaptureMouseEvents(PR_FALSE); + } + } + } + return NS_OK; +} + +//---------------------------------------------------------------------- +// nsIDOMMouseMotionListener +//---------------------------------------------------------------------- +nsresult +nsListControlFrame::MouseMove(nsIDOMEvent* aMouseEvent) +{ + if (NS_SUCCEEDED(GetIndexFromDOMEvent(aMouseEvent))) { + if (IsInDropDownMode() == PR_TRUE) { + if (kNothingSelected != mSelectedIndex) { + if (mOldSelectedIndex != mSelectedIndex) { + if (mOldSelectedIndex != kNothingSelected) { + SetContentSelected(mOldSelectedIndex, PR_FALSE); + } + SetContentSelected(mSelectedIndex, PR_TRUE); + } + } + } + } + return NS_OK; +} + diff --git a/layout/html/forms/src/nsListControlFrame.h b/layout/html/forms/src/nsListControlFrame.h index 5f65cd74e512..e2104df2bf48 100644 --- a/layout/html/forms/src/nsListControlFrame.h +++ b/layout/html/forms/src/nsListControlFrame.h @@ -22,12 +22,16 @@ #include "nsScrollFrame.h" #include "nsIFormControlFrame.h" #include "nsIListControlFrame.h" +#include "nsISelectControlFrame.h" +#include "nsIDOMMouseListener.h" +#include "nsIDOMMouseMotionListener.h" class nsIDOMHTMLSelectElement; class nsIDOMHTMLCollection; class nsIDOMHTMLOptionElement; class nsIComboboxControlFrame; class nsIViewManager; +class nsIPresContext; /** * Frame-based listbox. @@ -35,7 +39,10 @@ class nsIViewManager; class nsListControlFrame : public nsScrollFrame, public nsIFormControlFrame, - public nsIListControlFrame + public nsIListControlFrame, + public nsIDOMMouseListener, + public nsIDOMMouseMotionListener, + public nsISelectControlFrame { public: friend nsresult NS_NewListControlFrame(nsIFrame** aNewFrame); @@ -44,8 +51,6 @@ public: NS_DECL_ISUPPORTS // nsIFrame - NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint, nsIFrame** aFrame); - NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus); @@ -99,13 +104,31 @@ public: // nsIListControlFrame NS_IMETHOD SetComboboxFrame(nsIFrame* aComboboxFrame); + NS_IMETHOD GetSelectedIndex(PRInt32* aIndex); NS_IMETHOD GetSelectedItem(nsString & aStr); - NS_IMETHOD GetSelectedIndex(PRInt32* aIndex); NS_IMETHOD CaptureMouseEvents(PRBool aGrabMouseEvents); NS_IMETHOD GetMaximumSize(nsSize &aSize); NS_IMETHOD SetSuggestedSize(nscoord aWidth, nscoord aHeight); NS_IMETHOD GetNumberOfOptions(PRInt32* aNumOptions); + // nsISelectControlFrame + NS_IMETHOD AddOption(PRInt32 index); + NS_IMETHOD RemoveOption(PRInt32 index); + + //nsIDOMEventListener + virtual nsresult MouseDown(nsIDOMEvent* aMouseEvent);//{ printf("-MouseDown\n"); return NS_OK; }; + virtual nsresult MouseUp(nsIDOMEvent* aMouseEvent);// { printf("-MouseUp\n"); return NS_OK; }; + virtual nsresult MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; } + virtual nsresult HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } + + //nsIDOMEventMotionListener + virtual nsresult MouseMove(nsIDOMEvent* aMouseEvent); + virtual nsresult DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; } + + // Static Methods static nsIDOMHTMLSelectElement* GetSelect(nsIContent * aContent); static nsIDOMHTMLCollection* GetOptions(nsIContent * aContent, nsIDOMHTMLSelectElement* aSelect = nsnull); @@ -114,6 +137,7 @@ public: static PRBool GetOptionValue(nsIDOMHTMLCollection& aCollecton, PRUint32 aIndex, nsString& aValue); protected: + NS_IMETHOD GetSelectedIndexFromDOM(PRInt32* aIndex); // from DOM nsListControlFrame(); virtual ~nsListControlFrame(); @@ -128,16 +152,16 @@ protected: // Utility methods nsresult GetSizeAttribute(PRInt32 *aSize); PRInt32 GetNumberOfSelections(); + nsIContent* GetOptionFromContent(nsIContent *aContent); + nsresult GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent); + PRInt32 GetSelectedIndexFromContent(nsIContent *aContent); nsIContent* GetOptionContent(PRUint32 aIndex); PRBool IsContentSelected(nsIContent* aContent); - PRBool IsFrameSelected(PRUint32 aIndex); - void SetFrameSelected(PRUint32 aIndex, PRBool aSelected); + PRBool IsContentSelectedByIndex(PRUint32 aIndex); + void SetContentSelected(PRUint32 aIndex, PRBool aSelected); void GetViewOffset(nsIViewManager* aManager, nsIView* aView, nsPoint& aPoint); nsresult Deselect(); nsIFrame *GetOptionFromChild(nsIFrame* aParentFrame); - nsresult GetFrameForPointUsing(const nsPoint& aPoint, - nsIAtom* aList, - nsIFrame** aFrame); PRBool IsAncestor(nsIView* aAncestor, nsIView* aChild); nsIView* GetViewFor(nsIWidget* aWidget); nsresult SyncViewWithFrame(); @@ -156,22 +180,15 @@ protected: void ClearSelection(); void ExtendedSelection(PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aDoInvert, PRBool aSetValue); - nsresult HandleLikeDropDownListEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus); PRBool HasSameContent(nsIFrame* aFrame1, nsIFrame* aFrame2); - void HandleListSelection(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus); - nsresult HandleLikeListEvent(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsEventStatus& aEventStatus); + void HandleListSelection(nsIDOMEvent * aDOMEvent); PRInt32 GetSelectedIndexFromFrame(nsIFrame *aHitFrame); // Data Members nscoord mBorderOffsetY; nsFormFrame* mFormFrame; PRInt32 mSelectedIndex; + PRInt32 mOldSelectedIndex; PRInt32 mStartExtendedIndex; PRInt32 mEndExtendedIndex; nsIFrame* mHitFrame; @@ -184,6 +201,9 @@ protected: nscoord mMaxWidth; nscoord mMaxHeight; PRBool mIsCapturingMouseEvents; + PRBool mIgnoreMouseUp; + + nsIPresContext* mPresContext; // XXX: Remove the need to cache the pres context. // XXX temprary only until full system mouse capture works PRBool mIsScrollbarVisible;