Source code

Revision control

Other Tools

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/. */
6
7
#include "nsCOMPtr.h"
8
#include "nsTreeContentView.h"
9
#include "nsITreeSelection.h"
10
#include "ChildIterator.h"
11
#include "nsError.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"
19
20
namespace mozilla {
21
namespace dom {
22
23
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(XULTreeElement, nsXULElement)
24
NS_IMPL_CYCLE_COLLECTION_INHERITED(XULTreeElement, nsXULElement, mView)
25
26
JSObject* XULTreeElement::WrapNode(JSContext* aCx,
27
JS::Handle<JSObject*> aGivenProto) {
28
return XULTreeElement_Binding::Wrap(aCx, this, aGivenProto);
29
}
30
31
void XULTreeElement::UnbindFromTree(bool aNullParent) {
32
// Drop the view's ref to us.
33
if (mView) {
34
nsCOMPtr<nsITreeSelection> sel;
35
mView->GetSelection(getter_AddRefs(sel));
36
if (sel) {
37
sel->SetTree(nullptr);
38
}
39
mView->SetTree(nullptr); // Break the circular ref between the view and us.
40
}
41
mView = nullptr;
42
43
nsXULElement::UnbindFromTree(aNullParent);
44
}
45
46
void XULTreeElement::DestroyContent() {
47
// Drop the view's ref to us.
48
if (mView) {
49
nsCOMPtr<nsITreeSelection> sel;
50
mView->GetSelection(getter_AddRefs(sel));
51
if (sel) {
52
sel->SetTree(nullptr);
53
}
54
mView->SetTree(nullptr); // Break the circular ref between the view and us.
55
}
56
mView = nullptr;
57
58
nsXULElement::DestroyContent();
59
}
60
61
static nsIContent* FindBodyElement(nsIContent* aParent) {
62
mozilla::dom::FlattenedChildIterator iter(aParent);
63
for (nsIContent* content = iter.GetNextChild(); content;
64
content = iter.GetNextChild()) {
65
mozilla::dom::NodeInfo* ni = content->NodeInfo();
66
if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
67
return content;
68
} else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
69
// There are nesting tree elements. Only the innermost should
70
// find the treechilren.
71
return nullptr;
72
} else if (content->IsElement() &&
73
!ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
74
nsIContent* result = FindBodyElement(content);
75
if (result) return result;
76
}
77
}
78
79
return nullptr;
80
}
81
82
nsTreeBodyFrame* XULTreeElement::GetTreeBodyFrame(FlushType aFlushType) {
83
MOZ_ASSERT(aFlushType == FlushType::Frames ||
84
aFlushType == FlushType::Layout || aFlushType == FlushType::None);
85
nsCOMPtr<nsIContent> kungFuDeathGrip = this; // keep a reference
86
RefPtr<Document> doc = GetUncomposedDoc();
87
88
// Make sure our frames are up to date, and layout as needed. We
89
// have to do this before checking for our cached mTreeBody, since
90
// it might go away on style flush, and in any case if aFlushLayout
91
// is true we need to make sure to flush no matter what.
92
// XXXbz except that flushing style when we were not asked to flush
93
// layout here breaks things. See bug 585123.
94
if (aFlushType == FlushType::Layout && doc) {
95
doc->FlushPendingNotifications(FlushType::Layout);
96
}
97
98
if (mTreeBody) {
99
// Have one cached already.
100
return mTreeBody;
101
}
102
103
if (aFlushType == FlushType::Frames && doc) {
104
doc->FlushPendingNotifications(FlushType::Frames);
105
}
106
107
if (nsCOMPtr<nsIContent> tree = FindBodyElement(this)) {
108
mTreeBody = do_QueryFrame(tree->GetPrimaryFrame());
109
}
110
111
return mTreeBody;
112
}
113
114
already_AddRefed<nsITreeView> XULTreeElement::GetView() {
115
if (!mTreeBody) {
116
if (!GetTreeBodyFrame()) {
117
return nullptr;
118
}
119
120
if (mView) {
121
nsCOMPtr<nsITreeView> view;
122
// Our new frame needs to initialise itself
123
mTreeBody->GetView(getter_AddRefs(view));
124
return view.forget();
125
}
126
}
127
if (!mView) {
128
// No tree builder, create a tree content view.
129
if (NS_FAILED(NS_NewTreeContentView(getter_AddRefs(mView)))) {
130
return nullptr;
131
}
132
133
// Initialise the frame and view
134
mTreeBody->SetView(mView);
135
}
136
137
return do_AddRef(mView);
138
}
139
140
void XULTreeElement::SetView(nsITreeView* aView, CallerType aCallerType,
141
ErrorResult& aRv) {
142
if (aCallerType != CallerType::System) {
143
// Don't trust views coming from random places.
144
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
145
return;
146
}
147
148
mView = aView;
149
nsTreeBodyFrame* body = GetTreeBodyFrame();
150
if (body) {
151
body->SetView(aView);
152
}
153
}
154
155
bool XULTreeElement::Focused() {
156
nsTreeBodyFrame* body = GetTreeBodyFrame();
157
if (body) {
158
return body->GetFocused();
159
}
160
return false;
161
}
162
163
void XULTreeElement::SetFocused(bool aFocused) {
164
nsTreeBodyFrame* body = GetTreeBodyFrame();
165
if (body) {
166
body->SetFocused(aFocused);
167
}
168
}
169
170
already_AddRefed<Element> XULTreeElement::GetTreeBody() {
171
nsTreeBodyFrame* body = GetTreeBodyFrame();
172
if (body) {
173
nsCOMPtr<Element> element;
174
body->GetTreeBody(getter_AddRefs(element));
175
return element.forget();
176
}
177
178
return nullptr;
179
}
180
181
already_AddRefed<nsTreeColumns> XULTreeElement::GetColumns() {
182
nsTreeBodyFrame* body = GetTreeBodyFrame();
183
if (body) {
184
return body->Columns();
185
}
186
return nullptr;
187
}
188
189
int32_t XULTreeElement::RowHeight() {
190
nsTreeBodyFrame* body = GetTreeBodyFrame();
191
if (body) {
192
return body->RowHeight();
193
}
194
return 0;
195
}
196
197
int32_t XULTreeElement::RowWidth() {
198
nsTreeBodyFrame* body = GetTreeBodyFrame();
199
if (body) {
200
return body->RowWidth();
201
}
202
return 0;
203
}
204
205
int32_t XULTreeElement::GetFirstVisibleRow() {
206
nsTreeBodyFrame* body = GetTreeBodyFrame();
207
if (body) {
208
return body->FirstVisibleRow();
209
}
210
return 0;
211
}
212
213
int32_t XULTreeElement::GetLastVisibleRow() {
214
nsTreeBodyFrame* body = GetTreeBodyFrame();
215
if (body) {
216
return body->LastVisibleRow();
217
}
218
return 0;
219
}
220
221
int32_t XULTreeElement::HorizontalPosition() {
222
nsTreeBodyFrame* body = GetTreeBodyFrame();
223
if (body) {
224
return body->GetHorizontalPosition();
225
}
226
return 0;
227
}
228
229
int32_t XULTreeElement::GetPageLength() {
230
nsTreeBodyFrame* body = GetTreeBodyFrame();
231
if (body) {
232
return body->PageLength();
233
}
234
return 0;
235
}
236
237
void XULTreeElement::EnsureRowIsVisible(int32_t aRow) {
238
nsTreeBodyFrame* body = GetTreeBodyFrame();
239
if (body) {
240
body->EnsureRowIsVisible(aRow);
241
}
242
}
243
244
void XULTreeElement::EnsureCellIsVisible(int32_t aRow, nsTreeColumn* aCol,
245
ErrorResult& aRv) {
246
nsTreeBodyFrame* body = GetTreeBodyFrame();
247
if (body) {
248
nsresult rv = body->EnsureCellIsVisible(aRow, aCol);
249
if (NS_FAILED(rv)) {
250
aRv.Throw(rv);
251
}
252
}
253
}
254
255
void XULTreeElement::ScrollToRow(int32_t aRow) {
256
nsTreeBodyFrame* body = GetTreeBodyFrame(FlushType::Layout);
257
if (!body) {
258
return;
259
}
260
261
body->ScrollToRow(aRow);
262
}
263
264
void XULTreeElement::ScrollByLines(int32_t aNumLines) {
265
nsTreeBodyFrame* body = GetTreeBodyFrame();
266
if (!body) {
267
return;
268
}
269
body->ScrollByLines(aNumLines);
270
}
271
272
void XULTreeElement::ScrollByPages(int32_t aNumPages) {
273
nsTreeBodyFrame* body = GetTreeBodyFrame();
274
if (body) {
275
body->ScrollByPages(aNumPages);
276
}
277
}
278
279
void XULTreeElement::Invalidate() {
280
nsTreeBodyFrame* body = GetTreeBodyFrame();
281
if (body) {
282
body->Invalidate();
283
}
284
}
285
286
void XULTreeElement::InvalidateColumn(nsTreeColumn* aCol) {
287
nsTreeBodyFrame* body = GetTreeBodyFrame();
288
if (body) {
289
body->InvalidateColumn(aCol);
290
}
291
}
292
293
void XULTreeElement::InvalidateRow(int32_t aIndex) {
294
nsTreeBodyFrame* body = GetTreeBodyFrame();
295
if (body) {
296
body->InvalidateRow(aIndex);
297
}
298
}
299
300
void XULTreeElement::InvalidateCell(int32_t aRow, nsTreeColumn* aCol) {
301
nsTreeBodyFrame* body = GetTreeBodyFrame();
302
if (body) {
303
body->InvalidateCell(aRow, aCol);
304
}
305
}
306
307
void XULTreeElement::InvalidateRange(int32_t aStart, int32_t aEnd) {
308
nsTreeBodyFrame* body = GetTreeBodyFrame();
309
if (body) {
310
body->InvalidateRange(aStart, aEnd);
311
}
312
}
313
314
int32_t XULTreeElement::GetRowAt(int32_t x, int32_t y) {
315
nsTreeBodyFrame* body = GetTreeBodyFrame();
316
if (!body) {
317
return 0;
318
}
319
return body->GetRowAt(x, y);
320
}
321
322
void XULTreeElement::GetCellAt(int32_t aX, int32_t aY, TreeCellInfo& aRetVal,
323
ErrorResult& aRv) {
324
aRetVal.mRow = 0;
325
aRetVal.mCol = nullptr;
326
327
nsTreeBodyFrame* body = GetTreeBodyFrame();
328
if (body) {
329
nsAutoCString element;
330
body->GetCellAt(aX, aY, &aRetVal.mRow, getter_AddRefs(aRetVal.mCol),
331
element);
332
CopyUTF8toUTF16(element, aRetVal.mChildElt);
333
}
334
}
335
336
nsIntRect XULTreeElement::GetCoordsForCellItem(int32_t aRow, nsTreeColumn* aCol,
337
const nsAString& aElement,
338
nsresult& rv) {
339
rv = NS_OK;
340
nsIntRect rect;
341
342
nsTreeBodyFrame* body = GetTreeBodyFrame();
343
NS_ConvertUTF16toUTF8 element(aElement);
344
if (body) {
345
rv = body->GetCoordsForCellItem(aRow, aCol, element, &rect.x, &rect.y,
346
&rect.width, &rect.height);
347
}
348
349
return rect;
350
}
351
352
already_AddRefed<DOMRect> XULTreeElement::GetCoordsForCellItem(
353
int32_t aRow, nsTreeColumn& aCol, const nsAString& aElement,
354
ErrorResult& aRv) {
355
nsresult rv;
356
nsIntRect rect = GetCoordsForCellItem(aRow, &aCol, aElement, rv);
357
aRv = rv;
358
359
RefPtr<DOMRect> domRect =
360
new DOMRect(this, rect.x, rect.y, rect.width, rect.height);
361
return domRect.forget();
362
}
363
364
bool XULTreeElement::IsCellCropped(int32_t aRow, nsTreeColumn* aCol,
365
ErrorResult& aRv) {
366
bool cropped = false;
367
368
nsTreeBodyFrame* body = GetTreeBodyFrame();
369
if (body) {
370
aRv = body->IsCellCropped(aRow, aCol, &cropped);
371
}
372
373
return cropped;
374
}
375
376
void XULTreeElement::RowCountChanged(int32_t aIndex, int32_t aDelta) {
377
nsTreeBodyFrame* body = GetTreeBodyFrame();
378
if (body) {
379
body->RowCountChanged(aIndex, aDelta);
380
}
381
}
382
383
void XULTreeElement::BeginUpdateBatch() {
384
nsTreeBodyFrame* body = GetTreeBodyFrame();
385
if (body) {
386
body->BeginUpdateBatch();
387
}
388
}
389
390
void XULTreeElement::EndUpdateBatch() {
391
nsTreeBodyFrame* body = GetTreeBodyFrame();
392
if (body) {
393
body->EndUpdateBatch();
394
}
395
}
396
397
void XULTreeElement::ClearStyleAndImageCaches() {
398
nsTreeBodyFrame* body = GetTreeBodyFrame();
399
if (body) {
400
body->ClearStyleAndImageCaches();
401
}
402
}
403
404
void XULTreeElement::RemoveImageCacheEntry(int32_t aRowIndex,
405
nsTreeColumn& aCol,
406
ErrorResult& aRv) {
407
if (NS_WARN_IF(aRowIndex < 0)) {
408
aRv.Throw(NS_ERROR_INVALID_ARG);
409
return;
410
}
411
nsTreeBodyFrame* body = GetTreeBodyFrame();
412
if (body) {
413
body->RemoveImageCacheEntry(aRowIndex, &aCol);
414
}
415
}
416
417
} // namespace dom
418
} // namespace mozilla