michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsPIListBoxObject.h" michael@0: #include "nsBoxObject.h" michael@0: #include "nsIFrame.h" michael@0: #include "nsBindingManager.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDOMNodeList.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsListBoxBodyFrame.h" michael@0: #include "ChildIterator.h" michael@0: michael@0: class nsListBoxObject : public nsPIListBoxObject, public nsBoxObject michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSILISTBOXOBJECT michael@0: michael@0: // nsPIListBoxObject michael@0: virtual nsListBoxBodyFrame* GetListBoxBody(bool aFlush) MOZ_OVERRIDE; michael@0: michael@0: nsListBoxObject(); michael@0: michael@0: // nsPIBoxObject michael@0: virtual void Clear() MOZ_OVERRIDE; michael@0: virtual void ClearCachedValues() MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: nsListBoxBodyFrame *mListBoxBody; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(nsListBoxObject, nsBoxObject, nsIListBoxObject, michael@0: nsPIListBoxObject) michael@0: michael@0: nsListBoxObject::nsListBoxObject() michael@0: : mListBoxBody(nullptr) michael@0: { michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////// michael@0: //// nsIListBoxObject michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::GetRowCount(int32_t *aResult) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->GetRowCount(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::GetNumberOfVisibleRows(int32_t *aResult) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->GetNumberOfVisibleRows(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::GetIndexOfFirstVisibleRow(int32_t *aResult) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->GetIndexOfFirstVisibleRow(aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsListBoxObject::EnsureIndexIsVisible(int32_t aRowIndex) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->EnsureIndexIsVisible(aRowIndex); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::ScrollToIndex(int32_t aRowIndex) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->ScrollToIndex(aRowIndex); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::ScrollByLines(int32_t aNumLines) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->ScrollByLines(aNumLines); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::GetItemAtIndex(int32_t index, nsIDOMElement **_retval) michael@0: { michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->GetItemAtIndex(index, _retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsListBoxObject::GetIndexOfItem(nsIDOMElement* aElement, int32_t *aResult) michael@0: { michael@0: *aResult = 0; michael@0: michael@0: nsListBoxBodyFrame* body = GetListBoxBody(true); michael@0: if (body) michael@0: return body->GetIndexOfItem(aElement, aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: ////////////////////// michael@0: michael@0: static nsIContent* michael@0: FindBodyContent(nsIContent* aParent) michael@0: { michael@0: if (aParent->Tag() == nsGkAtoms::listboxbody) { michael@0: return aParent; michael@0: } michael@0: michael@0: mozilla::dom::FlattenedChildIterator iter(aParent); michael@0: for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { michael@0: nsIContent* result = FindBodyContent(child); michael@0: if (result) { michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: nsListBoxBodyFrame* michael@0: nsListBoxObject::GetListBoxBody(bool aFlush) michael@0: { michael@0: if (mListBoxBody) { michael@0: return mListBoxBody; michael@0: } michael@0: michael@0: nsIPresShell* shell = GetPresShell(false); michael@0: if (!shell) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsIFrame* frame = aFlush ? michael@0: GetFrame(false) /* does Flush_Frames */ : michael@0: mContent->GetPrimaryFrame(); michael@0: if (!frame) michael@0: return nullptr; michael@0: michael@0: // Iterate over our content model children looking for the body. michael@0: nsCOMPtr content = FindBodyContent(frame->GetContent()); michael@0: michael@0: if (!content) michael@0: return nullptr; michael@0: michael@0: // this frame will be a nsGFXScrollFrame michael@0: frame = content->GetPrimaryFrame(); michael@0: if (!frame) michael@0: return nullptr; michael@0: nsIScrollableFrame* scrollFrame = do_QueryFrame(frame); michael@0: if (!scrollFrame) michael@0: return nullptr; michael@0: michael@0: // this frame will be the one we want michael@0: nsIFrame* yeahBaby = scrollFrame->GetScrolledFrame(); michael@0: if (!yeahBaby) michael@0: return nullptr; michael@0: michael@0: // It's a frame. Refcounts are irrelevant. michael@0: nsListBoxBodyFrame* listBoxBody = do_QueryFrame(yeahBaby); michael@0: NS_ENSURE_TRUE(listBoxBody && michael@0: listBoxBody->SetBoxObject(this), michael@0: nullptr); michael@0: mListBoxBody = listBoxBody; michael@0: return mListBoxBody; michael@0: } michael@0: michael@0: void michael@0: nsListBoxObject::Clear() michael@0: { michael@0: ClearCachedValues(); michael@0: michael@0: nsBoxObject::Clear(); michael@0: } michael@0: michael@0: void michael@0: nsListBoxObject::ClearCachedValues() michael@0: { michael@0: mListBoxBody = nullptr; michael@0: } michael@0: michael@0: // Creation Routine /////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: NS_NewListBoxObject(nsIBoxObject** aResult) michael@0: { michael@0: *aResult = new nsListBoxObject; michael@0: if (!*aResult) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: }