|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsCOMPtr.h" |
|
7 #include "nsPIListBoxObject.h" |
|
8 #include "nsBoxObject.h" |
|
9 #include "nsIFrame.h" |
|
10 #include "nsBindingManager.h" |
|
11 #include "nsIDOMElement.h" |
|
12 #include "nsIDOMNodeList.h" |
|
13 #include "nsGkAtoms.h" |
|
14 #include "nsIScrollableFrame.h" |
|
15 #include "nsListBoxBodyFrame.h" |
|
16 #include "ChildIterator.h" |
|
17 |
|
18 class nsListBoxObject : public nsPIListBoxObject, public nsBoxObject |
|
19 { |
|
20 public: |
|
21 NS_DECL_ISUPPORTS_INHERITED |
|
22 NS_DECL_NSILISTBOXOBJECT |
|
23 |
|
24 // nsPIListBoxObject |
|
25 virtual nsListBoxBodyFrame* GetListBoxBody(bool aFlush) MOZ_OVERRIDE; |
|
26 |
|
27 nsListBoxObject(); |
|
28 |
|
29 // nsPIBoxObject |
|
30 virtual void Clear() MOZ_OVERRIDE; |
|
31 virtual void ClearCachedValues() MOZ_OVERRIDE; |
|
32 |
|
33 protected: |
|
34 nsListBoxBodyFrame *mListBoxBody; |
|
35 }; |
|
36 |
|
37 NS_IMPL_ISUPPORTS_INHERITED(nsListBoxObject, nsBoxObject, nsIListBoxObject, |
|
38 nsPIListBoxObject) |
|
39 |
|
40 nsListBoxObject::nsListBoxObject() |
|
41 : mListBoxBody(nullptr) |
|
42 { |
|
43 } |
|
44 |
|
45 ////////////////////////////////////////////////////////////////////////// |
|
46 //// nsIListBoxObject |
|
47 |
|
48 NS_IMETHODIMP |
|
49 nsListBoxObject::GetRowCount(int32_t *aResult) |
|
50 { |
|
51 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
52 if (body) |
|
53 return body->GetRowCount(aResult); |
|
54 return NS_OK; |
|
55 } |
|
56 |
|
57 NS_IMETHODIMP |
|
58 nsListBoxObject::GetNumberOfVisibleRows(int32_t *aResult) |
|
59 { |
|
60 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
61 if (body) |
|
62 return body->GetNumberOfVisibleRows(aResult); |
|
63 return NS_OK; |
|
64 } |
|
65 |
|
66 NS_IMETHODIMP |
|
67 nsListBoxObject::GetIndexOfFirstVisibleRow(int32_t *aResult) |
|
68 { |
|
69 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
70 if (body) |
|
71 return body->GetIndexOfFirstVisibleRow(aResult); |
|
72 return NS_OK; |
|
73 } |
|
74 |
|
75 NS_IMETHODIMP nsListBoxObject::EnsureIndexIsVisible(int32_t aRowIndex) |
|
76 { |
|
77 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
78 if (body) |
|
79 return body->EnsureIndexIsVisible(aRowIndex); |
|
80 return NS_OK; |
|
81 } |
|
82 |
|
83 NS_IMETHODIMP |
|
84 nsListBoxObject::ScrollToIndex(int32_t aRowIndex) |
|
85 { |
|
86 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
87 if (body) |
|
88 return body->ScrollToIndex(aRowIndex); |
|
89 return NS_OK; |
|
90 } |
|
91 |
|
92 NS_IMETHODIMP |
|
93 nsListBoxObject::ScrollByLines(int32_t aNumLines) |
|
94 { |
|
95 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
96 if (body) |
|
97 return body->ScrollByLines(aNumLines); |
|
98 return NS_OK; |
|
99 } |
|
100 |
|
101 NS_IMETHODIMP |
|
102 nsListBoxObject::GetItemAtIndex(int32_t index, nsIDOMElement **_retval) |
|
103 { |
|
104 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
105 if (body) |
|
106 return body->GetItemAtIndex(index, _retval); |
|
107 return NS_OK; |
|
108 } |
|
109 |
|
110 NS_IMETHODIMP |
|
111 nsListBoxObject::GetIndexOfItem(nsIDOMElement* aElement, int32_t *aResult) |
|
112 { |
|
113 *aResult = 0; |
|
114 |
|
115 nsListBoxBodyFrame* body = GetListBoxBody(true); |
|
116 if (body) |
|
117 return body->GetIndexOfItem(aElement, aResult); |
|
118 return NS_OK; |
|
119 } |
|
120 |
|
121 ////////////////////// |
|
122 |
|
123 static nsIContent* |
|
124 FindBodyContent(nsIContent* aParent) |
|
125 { |
|
126 if (aParent->Tag() == nsGkAtoms::listboxbody) { |
|
127 return aParent; |
|
128 } |
|
129 |
|
130 mozilla::dom::FlattenedChildIterator iter(aParent); |
|
131 for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) { |
|
132 nsIContent* result = FindBodyContent(child); |
|
133 if (result) { |
|
134 return result; |
|
135 } |
|
136 } |
|
137 |
|
138 return nullptr; |
|
139 } |
|
140 |
|
141 nsListBoxBodyFrame* |
|
142 nsListBoxObject::GetListBoxBody(bool aFlush) |
|
143 { |
|
144 if (mListBoxBody) { |
|
145 return mListBoxBody; |
|
146 } |
|
147 |
|
148 nsIPresShell* shell = GetPresShell(false); |
|
149 if (!shell) { |
|
150 return nullptr; |
|
151 } |
|
152 |
|
153 nsIFrame* frame = aFlush ? |
|
154 GetFrame(false) /* does Flush_Frames */ : |
|
155 mContent->GetPrimaryFrame(); |
|
156 if (!frame) |
|
157 return nullptr; |
|
158 |
|
159 // Iterate over our content model children looking for the body. |
|
160 nsCOMPtr<nsIContent> content = FindBodyContent(frame->GetContent()); |
|
161 |
|
162 if (!content) |
|
163 return nullptr; |
|
164 |
|
165 // this frame will be a nsGFXScrollFrame |
|
166 frame = content->GetPrimaryFrame(); |
|
167 if (!frame) |
|
168 return nullptr; |
|
169 nsIScrollableFrame* scrollFrame = do_QueryFrame(frame); |
|
170 if (!scrollFrame) |
|
171 return nullptr; |
|
172 |
|
173 // this frame will be the one we want |
|
174 nsIFrame* yeahBaby = scrollFrame->GetScrolledFrame(); |
|
175 if (!yeahBaby) |
|
176 return nullptr; |
|
177 |
|
178 // It's a frame. Refcounts are irrelevant. |
|
179 nsListBoxBodyFrame* listBoxBody = do_QueryFrame(yeahBaby); |
|
180 NS_ENSURE_TRUE(listBoxBody && |
|
181 listBoxBody->SetBoxObject(this), |
|
182 nullptr); |
|
183 mListBoxBody = listBoxBody; |
|
184 return mListBoxBody; |
|
185 } |
|
186 |
|
187 void |
|
188 nsListBoxObject::Clear() |
|
189 { |
|
190 ClearCachedValues(); |
|
191 |
|
192 nsBoxObject::Clear(); |
|
193 } |
|
194 |
|
195 void |
|
196 nsListBoxObject::ClearCachedValues() |
|
197 { |
|
198 mListBoxBody = nullptr; |
|
199 } |
|
200 |
|
201 // Creation Routine /////////////////////////////////////////////////////////////////////// |
|
202 |
|
203 nsresult |
|
204 NS_NewListBoxObject(nsIBoxObject** aResult) |
|
205 { |
|
206 *aResult = new nsListBoxObject; |
|
207 if (!*aResult) |
|
208 return NS_ERROR_OUT_OF_MEMORY; |
|
209 NS_ADDREF(*aResult); |
|
210 return NS_OK; |
|
211 } |