/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * Mats Palmgren * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nscore.h" #include "nsCOMPtr.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" #include "nsListControlFrame.h" #include "nsFormControlFrame.h" // for COMPARE macro #include "nsGkAtoms.h" #include "nsIFormControl.h" #include "nsIDeviceContext.h" #include "nsIDocument.h" #include "nsIDOMHTMLCollection.h" #include "nsIDOMHTMLOptionsCollection.h" #include "nsIDOMNSHTMLOptionCollectn.h" #include "nsIDOMHTMLSelectElement.h" #include "nsIDOMHTMLOptionElement.h" #include "nsComboboxControlFrame.h" #include "nsIViewManager.h" #include "nsIDOMHTMLOptGroupElement.h" #include "nsWidgetsCID.h" #include "nsIPresShell.h" #include "nsHTMLParts.h" #include "nsIDOMEventTarget.h" #include "nsEventDispatcher.h" #include "nsIEventStateManager.h" #include "nsIEventListenerManager.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMMouseEvent.h" #include "nsIPrivateDOMEvent.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIComponentManager.h" #include "nsILookAndFeel.h" #include "nsIFontMetrics.h" #include "nsIScrollableFrame.h" #include "nsIDOMEventTarget.h" #include "nsIDOMNSEvent.h" #include "nsGUIEvent.h" #include "nsIServiceManager.h" #include "nsINodeInfo.h" #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" #endif #include "nsISelectElement.h" #include "nsIPrivateDOMEvent.h" #include "nsCSSRendering.h" #include "nsITheme.h" #include "nsIDOMMouseListener.h" #include "nsIDOMMouseMotionListener.h" #include "nsIDOMKeyListener.h" #include "nsLayoutUtils.h" #include "nsDisplayList.h" // Constants const nscoord kMaxDropDownRows = 20; // This matches the setting for 4.x browsers const PRInt32 kNothingSelected = -1; // Static members nsListControlFrame * nsListControlFrame::mFocused = nsnull; nsString * nsListControlFrame::sIncrementalString = nsnull; // Using for incremental typing navigation #define INCREMENTAL_SEARCH_KEYPRESS_TIME 1000 // XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose: // nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml // need to find a good place to put them together. // if someone changes one, please also change the other. DOMTimeStamp nsListControlFrame::gLastKeyTime = 0; /****************************************************************************** * nsListEventListener * This class is responsible for propagating events to the nsListControlFrame. * Frames are not refcounted so they can't be used as event listeners. *****************************************************************************/ class nsListEventListener : public nsIDOMKeyListener, public nsIDOMMouseListener, public nsIDOMMouseMotionListener { public: nsListEventListener(nsListControlFrame *aFrame) : mFrame(aFrame) { } void SetFrame(nsListControlFrame *aFrame) { mFrame = aFrame; } NS_DECL_ISUPPORTS // nsIDOMEventListener NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); // nsIDOMKeyListener NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent); NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent); NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent); // nsIDOMMouseListener NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent); NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent); // nsIDOMMouseMotionListener NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent); NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent); private: nsListControlFrame *mFrame; }; //--------------------------------------------------------- nsIFrame* NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { nsListControlFrame* it = new (aPresShell) nsListControlFrame(aPresShell, aPresShell->GetDocument(), aContext); if (it) { it->AddStateBits(NS_FRAME_INDEPENDENT_SELECTION); } return it; } NS_IMPL_FRAMEARENA_HELPERS(nsListControlFrame) //--------------------------------------------------------- nsListControlFrame::nsListControlFrame( nsIPresShell* aShell, nsIDocument* aDocument, nsStyleContext* aContext) : nsHTMLScrollFrame(aShell, aContext, PR_FALSE), mMightNeedSecondPass(PR_FALSE), mHasPendingInterruptAtStartOfReflow(PR_FALSE), mLastDropdownComputedHeight(NS_UNCONSTRAINEDSIZE) { mComboboxFrame = nsnull; mChangesSinceDragStart = PR_FALSE; mButtonDown = PR_FALSE; mIsAllContentHere = PR_FALSE; mIsAllFramesHere = PR_FALSE; mHasBeenInitialized = PR_FALSE; mNeedToReset = PR_TRUE; mPostChildrenLoadedReset = PR_FALSE; mControlSelectMode = PR_FALSE; } //--------------------------------------------------------- nsListControlFrame::~nsListControlFrame() { mComboboxFrame = nsnull; } // for Bug 47302 (remove this comment later) void nsListControlFrame::DestroyFrom(nsIFrame* aDestructRoot) { // get the receiver interface from the browser button's content node ENSURE_TRUE(mContent); // Clear the frame pointer on our event listener, just in case the // event listener can outlive the frame. mEventListener->SetFrame(nsnull); mContent->RemoveEventListenerByIID(static_cast (mEventListener), NS_GET_IID(nsIDOMMouseListener)); mContent->RemoveEventListenerByIID(static_cast (mEventListener), NS_GET_IID(nsIDOMMouseMotionListener)); mContent->RemoveEventListenerByIID(static_cast (mEventListener), NS_GET_IID(nsIDOMKeyListener)); nsFormControlFrame::RegUnRegAccessKey(static_cast(this), PR_FALSE); nsHTMLScrollFrame::DestroyFrom(aDestructRoot); } NS_IMETHODIMP nsListControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { // We allow visibility:hidden . So if the mouse goes over an option just before // he leaves the box and clicks, that's what the