1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsTreeContentView.h"
9 #include "nsITreeSelection.h"
10 #include "ChildIterator.h"
12 #include "nsTreeBodyFrame.h"
13 #include "mozilla/dom/DOMRect.h"
14 #include "mozilla/dom/BindingUtils.h"
15 #include "mozilla/dom/Element.h"
16 #include "mozilla/dom/ToJSValue.h"
17 #include "mozilla/dom/XULTreeElement.h"
18 #include "mozilla/dom/XULTreeElementBinding.h"
20 namespace mozilla::dom
{
22 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULTreeElement
, nsXULElement
)
23 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeElement
, nsXULElement
, mView
)
25 JSObject
* XULTreeElement::WrapNode(JSContext
* aCx
,
26 JS::Handle
<JSObject
*> aGivenProto
) {
27 return XULTreeElement_Binding::Wrap(aCx
, this, aGivenProto
);
30 void XULTreeElement::UnbindFromTree(UnbindContext
& aContext
) {
31 // Drop the view's ref to us.
33 nsCOMPtr
<nsITreeSelection
> sel
;
34 mView
->GetSelection(getter_AddRefs(sel
));
36 sel
->SetTree(nullptr);
38 mView
->SetTree(nullptr); // Break the circular ref between the view and us.
42 nsXULElement::UnbindFromTree(aContext
);
45 void XULTreeElement::DestroyContent() {
46 // Drop the view's ref to us.
48 nsCOMPtr
<nsITreeSelection
> sel
;
49 mView
->GetSelection(getter_AddRefs(sel
));
51 sel
->SetTree(nullptr);
53 mView
->SetTree(nullptr); // Break the circular ref between the view and us.
57 nsXULElement::DestroyContent();
60 static nsIContent
* FindBodyElement(nsIContent
* aParent
) {
61 mozilla::dom::FlattenedChildIterator
iter(aParent
);
62 for (nsIContent
* content
= iter
.GetNextChild(); content
;
63 content
= iter
.GetNextChild()) {
64 mozilla::dom::NodeInfo
* ni
= content
->NodeInfo();
65 if (ni
->Equals(nsGkAtoms::treechildren
, kNameSpaceID_XUL
)) {
67 } else if (ni
->Equals(nsGkAtoms::tree
, kNameSpaceID_XUL
)) {
68 // There are nesting tree elements. Only the innermost should
69 // find the treechilren.
71 } else if (content
->IsElement() &&
72 !ni
->Equals(nsGkAtoms::_template
, kNameSpaceID_XUL
)) {
73 nsIContent
* result
= FindBodyElement(content
);
74 if (result
) return result
;
81 nsTreeBodyFrame
* XULTreeElement::GetTreeBodyFrame(FlushType aFlushType
) {
82 MOZ_ASSERT(aFlushType
== FlushType::Frames
||
83 aFlushType
== FlushType::Layout
|| aFlushType
== FlushType::None
);
84 nsCOMPtr
<nsIContent
> kungFuDeathGrip
= this; // keep a reference
86 // Make sure our frames are up to date, and layout as needed. We
87 // have to do this before checking for our cached mTreeBody, since
88 // it might go away on style flush, and in any case if aFlushLayout
89 // is true we need to make sure to flush no matter what.
90 if (aFlushType
!= FlushType::None
) {
91 if (RefPtr
<Document
> doc
= GetComposedDoc()) {
92 doc
->FlushPendingNotifications(aFlushType
);
97 // Have one cached already.
101 if (nsCOMPtr
<nsIContent
> tree
= FindBodyElement(this)) {
102 mTreeBody
= do_QueryFrame(tree
->GetPrimaryFrame());
108 already_AddRefed
<nsITreeView
> XULTreeElement::GetView(FlushType aFlushType
) {
110 if (!GetTreeBodyFrame(aFlushType
)) {
115 nsCOMPtr
<nsITreeView
> view
;
116 // Our new frame needs to initialise itself
117 mTreeBody
->GetView(getter_AddRefs(view
));
118 return view
.forget();
122 // No tree builder, create a tree content view.
123 if (NS_FAILED(NS_NewTreeContentView(getter_AddRefs(mView
)))) {
127 // Initialise the frame and view
128 mTreeBody
->SetView(mView
);
131 return do_AddRef(mView
);
134 void XULTreeElement::SetView(nsITreeView
* aView
, CallerType aCallerType
,
136 if (aCallerType
!= CallerType::System
) {
137 // Don't trust views coming from random places.
138 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
143 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
145 body
->SetView(aView
);
149 bool XULTreeElement::Focused() {
150 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
152 return body
->GetFocused();
157 void XULTreeElement::SetFocused(bool aFocused
) {
158 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
160 body
->SetFocused(aFocused
);
164 already_AddRefed
<Element
> XULTreeElement::GetTreeBody() {
165 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
167 nsCOMPtr
<Element
> element
;
168 body
->GetTreeBody(getter_AddRefs(element
));
169 return element
.forget();
175 already_AddRefed
<nsTreeColumns
> XULTreeElement::GetColumns(
176 FlushType aFlushType
) {
177 if (nsTreeBodyFrame
* body
= GetTreeBodyFrame(aFlushType
)) {
178 return body
->Columns();
183 int32_t XULTreeElement::RowHeight() {
184 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
186 return body
->RowHeight();
191 int32_t XULTreeElement::RowWidth() {
192 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
194 return body
->RowWidth();
199 int32_t XULTreeElement::GetFirstVisibleRow() {
200 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
202 return body
->FirstVisibleRow();
207 int32_t XULTreeElement::GetLastVisibleRow() {
208 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
210 return body
->LastVisibleRow();
215 int32_t XULTreeElement::HorizontalPosition() {
216 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
218 return body
->GetHorizontalPosition();
223 int32_t XULTreeElement::GetPageLength() {
224 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
226 return body
->PageLength();
231 void XULTreeElement::EnsureRowIsVisible(int32_t aRow
) {
232 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
234 body
->EnsureRowIsVisible(aRow
);
238 void XULTreeElement::EnsureCellIsVisible(int32_t aRow
, nsTreeColumn
* aCol
,
240 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
242 nsresult rv
= body
->EnsureCellIsVisible(aRow
, aCol
);
249 void XULTreeElement::ScrollToRow(int32_t aRow
) {
250 nsTreeBodyFrame
* body
= GetTreeBodyFrame(FlushType::Layout
);
255 body
->ScrollToRow(aRow
);
258 void XULTreeElement::ScrollByLines(int32_t aNumLines
) {
259 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
263 body
->ScrollByLines(aNumLines
);
266 void XULTreeElement::ScrollByPages(int32_t aNumPages
) {
267 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
269 body
->ScrollByPages(aNumPages
);
273 void XULTreeElement::Invalidate() {
274 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
280 void XULTreeElement::InvalidateColumn(nsTreeColumn
* aCol
) {
281 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
283 body
->InvalidateColumn(aCol
);
287 void XULTreeElement::InvalidateRow(int32_t aIndex
) {
288 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
290 body
->InvalidateRow(aIndex
);
294 void XULTreeElement::InvalidateCell(int32_t aRow
, nsTreeColumn
* aCol
) {
295 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
297 body
->InvalidateCell(aRow
, aCol
);
301 void XULTreeElement::InvalidateRange(int32_t aStart
, int32_t aEnd
) {
302 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
304 body
->InvalidateRange(aStart
, aEnd
);
308 int32_t XULTreeElement::GetRowAt(int32_t x
, int32_t y
) {
309 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
313 return body
->GetRowAt(x
, y
);
316 void XULTreeElement::GetCellAt(int32_t aX
, int32_t aY
, TreeCellInfo
& aRetVal
,
319 aRetVal
.mCol
= nullptr;
321 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
323 nsAutoCString element
;
324 body
->GetCellAt(aX
, aY
, &aRetVal
.mRow
, getter_AddRefs(aRetVal
.mCol
),
326 CopyUTF8toUTF16(element
, aRetVal
.mChildElt
);
330 nsIntRect
XULTreeElement::GetCoordsForCellItem(int32_t aRow
, nsTreeColumn
* aCol
,
331 const nsAString
& aElement
,
336 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
337 NS_ConvertUTF16toUTF8
element(aElement
);
339 rv
= body
->GetCoordsForCellItem(aRow
, aCol
, element
, &rect
.x
, &rect
.y
,
340 &rect
.width
, &rect
.height
);
346 already_AddRefed
<DOMRect
> XULTreeElement::GetCoordsForCellItem(
347 int32_t aRow
, nsTreeColumn
& aCol
, const nsAString
& aElement
,
350 nsIntRect rect
= GetCoordsForCellItem(aRow
, &aCol
, aElement
, rv
);
353 RefPtr
<DOMRect
> domRect
= new DOMRect(ToSupports(OwnerDoc()), rect
.x
, rect
.y
,
354 rect
.width
, rect
.height
);
355 return domRect
.forget();
358 bool XULTreeElement::IsCellCropped(int32_t aRow
, nsTreeColumn
* aCol
,
360 bool cropped
= false;
362 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
364 aRv
= body
->IsCellCropped(aRow
, aCol
, &cropped
);
370 void XULTreeElement::RowCountChanged(int32_t aIndex
, int32_t aDelta
) {
371 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
373 body
->RowCountChanged(aIndex
, aDelta
);
377 void XULTreeElement::BeginUpdateBatch() {
378 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
380 body
->BeginUpdateBatch();
384 void XULTreeElement::EndUpdateBatch() {
385 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
387 body
->EndUpdateBatch();
391 void XULTreeElement::ClearStyleAndImageCaches() {
392 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
394 body
->ClearStyleAndImageCaches();
398 void XULTreeElement::RemoveImageCacheEntry(int32_t aRowIndex
,
401 if (NS_WARN_IF(aRowIndex
< 0)) {
402 aRv
.Throw(NS_ERROR_INVALID_ARG
);
405 nsTreeBodyFrame
* body
= GetTreeBodyFrame();
407 body
->RemoveImageCacheEntry(aRowIndex
, &aCol
);
411 } // namespace mozilla::dom