1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Dave Hyatt <hyatt@mozilla.org> (Original Author)
24 : * Brian Ryner <bryner@brianryner.com>
25 : * Nate Nielsen <nielsen@memberwebs.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "nsTreeBoxObject.h"
42 : #include "nsCOMPtr.h"
43 : #include "nsIDOMXULElement.h"
44 : #include "nsIXULTemplateBuilder.h"
45 : #include "nsTreeContentView.h"
46 : #include "nsITreeSelection.h"
47 : #include "nsChildIterator.h"
48 : #include "nsContentUtils.h"
49 : #include "nsDOMError.h"
50 : #include "nsTreeBodyFrame.h"
51 :
52 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsTreeBoxObject, mView)
53 :
54 4 : NS_IMPL_ADDREF_INHERITED(nsTreeBoxObject, nsBoxObject)
55 4 : NS_IMPL_RELEASE_INHERITED(nsTreeBoxObject, nsBoxObject)
56 :
57 9 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsTreeBoxObject)
58 7 : NS_INTERFACE_MAP_ENTRY(nsITreeBoxObject)
59 7 : NS_INTERFACE_MAP_END_INHERITING(nsBoxObject)
60 :
61 : void
62 0 : nsTreeBoxObject::Clear()
63 : {
64 0 : ClearCachedValues();
65 :
66 : // Drop the view's ref to us.
67 0 : if (mView) {
68 0 : nsCOMPtr<nsITreeSelection> sel;
69 0 : mView->GetSelection(getter_AddRefs(sel));
70 0 : if (sel)
71 0 : sel->SetTree(nsnull);
72 0 : mView->SetTree(nsnull); // Break the circular ref between the view and us.
73 : }
74 0 : mView = nsnull;
75 :
76 0 : nsBoxObject::Clear();
77 0 : }
78 :
79 :
80 1 : nsTreeBoxObject::nsTreeBoxObject()
81 1 : : mTreeBody(nsnull)
82 : {
83 1 : }
84 :
85 2 : nsTreeBoxObject::~nsTreeBoxObject()
86 : {
87 : /* destructor code */
88 4 : }
89 :
90 :
91 0 : static void FindBodyElement(nsIContent* aParent, nsIContent** aResult)
92 : {
93 0 : *aResult = nsnull;
94 0 : ChildIterator iter, last;
95 0 : for (ChildIterator::Init(aParent, &iter, &last); iter != last; ++iter) {
96 0 : nsCOMPtr<nsIContent> content = *iter;
97 :
98 0 : nsINodeInfo *ni = content->NodeInfo();
99 0 : if (ni->Equals(nsGkAtoms::treechildren, kNameSpaceID_XUL)) {
100 0 : *aResult = content;
101 0 : NS_ADDREF(*aResult);
102 : break;
103 0 : } else if (ni->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
104 : // There are nesting tree elements. Only the innermost should
105 : // find the treechilren.
106 : break;
107 0 : } else if (content->IsElement() &&
108 0 : !ni->Equals(nsGkAtoms::_template, kNameSpaceID_XUL)) {
109 0 : FindBodyElement(content, aResult);
110 0 : if (*aResult)
111 : break;
112 : }
113 : }
114 0 : }
115 :
116 : nsTreeBodyFrame*
117 0 : nsTreeBoxObject::GetTreeBody(bool aFlushLayout)
118 : {
119 : // Make sure our frames are up to date, and layout as needed. We
120 : // have to do this before checking for our cached mTreeBody, since
121 : // it might go away on style flush, and in any case if aFlushLayout
122 : // is true we need to make sure to flush no matter what.
123 : // XXXbz except that flushing style when we were not asked to flush
124 : // layout here breaks things. See bug 585123.
125 : nsIFrame* frame;
126 0 : if (aFlushLayout) {
127 0 : frame = GetFrame(aFlushLayout);
128 0 : if (!frame)
129 0 : return nsnull;
130 : }
131 :
132 0 : if (mTreeBody) {
133 : // Have one cached already.
134 0 : return mTreeBody;
135 : }
136 :
137 0 : if (!aFlushLayout) {
138 0 : frame = GetFrame(aFlushLayout);
139 0 : if (!frame)
140 0 : return nsnull;
141 : }
142 :
143 : // Iterate over our content model children looking for the body.
144 0 : nsCOMPtr<nsIContent> content;
145 0 : FindBodyElement(frame->GetContent(), getter_AddRefs(content));
146 0 : if (!content)
147 0 : return nsnull;
148 :
149 0 : frame = content->GetPrimaryFrame();
150 0 : if (!frame)
151 0 : return nsnull;
152 :
153 : // Make sure that the treebodyframe has a pointer to |this|.
154 0 : nsTreeBodyFrame *treeBody = do_QueryFrame(frame);
155 0 : NS_ENSURE_TRUE(treeBody && treeBody->GetTreeBoxObject() == this, nsnull);
156 :
157 0 : mTreeBody = treeBody;
158 0 : return mTreeBody;
159 : }
160 :
161 0 : NS_IMETHODIMP nsTreeBoxObject::GetView(nsITreeView * *aView)
162 : {
163 0 : if (!mTreeBody) {
164 0 : if (!GetTreeBody()) {
165 : // Don't return an uninitialised view
166 0 : *aView = nsnull;
167 0 : return NS_OK;
168 : }
169 :
170 0 : if (mView)
171 : // Our new frame needs to initialise itself
172 0 : return mTreeBody->GetView(aView);
173 : }
174 0 : if (!mView) {
175 0 : nsCOMPtr<nsIDOMXULElement> xulele = do_QueryInterface(mContent);
176 0 : if (xulele) {
177 : // See if there is a XUL tree builder associated with the element
178 0 : nsCOMPtr<nsIXULTemplateBuilder> builder;
179 0 : xulele->GetBuilder(getter_AddRefs(builder));
180 0 : mView = do_QueryInterface(builder);
181 :
182 0 : if (!mView) {
183 : // No tree builder, create a tree content view.
184 0 : nsresult rv = NS_NewTreeContentView(getter_AddRefs(mView));
185 0 : NS_ENSURE_SUCCESS(rv, rv);
186 : }
187 :
188 : // Initialise the frame and view
189 0 : mTreeBody->SetView(mView);
190 : }
191 : }
192 0 : NS_IF_ADDREF(*aView = mView);
193 0 : return NS_OK;
194 : }
195 :
196 : static bool
197 0 : CanTrustView(nsISupports* aValue)
198 : {
199 : // Untrusted content is only allowed to specify known-good views
200 0 : if (nsContentUtils::IsCallerTrustedForWrite())
201 0 : return true;
202 0 : nsCOMPtr<nsINativeTreeView> nativeTreeView = do_QueryInterface(aValue);
203 0 : if (!nativeTreeView || NS_FAILED(nativeTreeView->EnsureNative())) {
204 : // XXX ERRMSG need a good error here for developers
205 0 : return false;
206 : }
207 0 : return true;
208 : }
209 :
210 0 : NS_IMETHODIMP nsTreeBoxObject::SetView(nsITreeView * aView)
211 : {
212 0 : if (!CanTrustView(aView))
213 0 : return NS_ERROR_DOM_SECURITY_ERR;
214 :
215 0 : mView = aView;
216 0 : nsTreeBodyFrame* body = GetTreeBody();
217 0 : if (body)
218 0 : body->SetView(aView);
219 :
220 0 : return NS_OK;
221 : }
222 :
223 0 : NS_IMETHODIMP nsTreeBoxObject::GetFocused(bool* aFocused)
224 : {
225 0 : *aFocused = false;
226 0 : nsTreeBodyFrame* body = GetTreeBody();
227 0 : if (body)
228 0 : return body->GetFocused(aFocused);
229 0 : return NS_OK;
230 : }
231 :
232 0 : NS_IMETHODIMP nsTreeBoxObject::SetFocused(bool aFocused)
233 : {
234 0 : nsTreeBodyFrame* body = GetTreeBody();
235 0 : if (body)
236 0 : return body->SetFocused(aFocused);
237 0 : return NS_OK;
238 : }
239 :
240 0 : NS_IMETHODIMP nsTreeBoxObject::GetTreeBody(nsIDOMElement** aElement)
241 : {
242 0 : *aElement = nsnull;
243 0 : nsTreeBodyFrame* body = GetTreeBody();
244 0 : if (body)
245 0 : return body->GetTreeBody(aElement);
246 0 : return NS_OK;
247 : }
248 :
249 0 : NS_IMETHODIMP nsTreeBoxObject::GetColumns(nsITreeColumns** aColumns)
250 : {
251 0 : *aColumns = nsnull;
252 0 : nsTreeBodyFrame* body = GetTreeBody();
253 0 : if (body)
254 0 : return body->GetColumns(aColumns);
255 0 : return NS_OK;
256 : }
257 :
258 0 : NS_IMETHODIMP nsTreeBoxObject::GetRowHeight(PRInt32* aRowHeight)
259 : {
260 0 : *aRowHeight = 0;
261 0 : nsTreeBodyFrame* body = GetTreeBody();
262 0 : if (body)
263 0 : return body->GetRowHeight(aRowHeight);
264 0 : return NS_OK;
265 : }
266 :
267 0 : NS_IMETHODIMP nsTreeBoxObject::GetRowWidth(PRInt32 *aRowWidth)
268 : {
269 0 : *aRowWidth = 0;
270 0 : nsTreeBodyFrame* body = GetTreeBody();
271 0 : if (body)
272 0 : return body->GetRowWidth(aRowWidth);
273 0 : return NS_OK;
274 : }
275 :
276 0 : NS_IMETHODIMP nsTreeBoxObject::GetFirstVisibleRow(PRInt32 *aFirstVisibleRow)
277 : {
278 0 : *aFirstVisibleRow = 0;
279 0 : nsTreeBodyFrame* body = GetTreeBody();
280 0 : if (body)
281 0 : return body->GetFirstVisibleRow(aFirstVisibleRow);
282 0 : return NS_OK;
283 : }
284 :
285 0 : NS_IMETHODIMP nsTreeBoxObject::GetLastVisibleRow(PRInt32 *aLastVisibleRow)
286 : {
287 0 : *aLastVisibleRow = 0;
288 0 : nsTreeBodyFrame* body = GetTreeBody();
289 0 : if (body)
290 0 : return body->GetLastVisibleRow(aLastVisibleRow);
291 0 : return NS_OK;
292 : }
293 :
294 0 : NS_IMETHODIMP nsTreeBoxObject::GetHorizontalPosition(PRInt32 *aHorizontalPosition)
295 : {
296 0 : *aHorizontalPosition = 0;
297 0 : nsTreeBodyFrame* body = GetTreeBody();
298 0 : if (body)
299 0 : return body->GetHorizontalPosition(aHorizontalPosition);
300 0 : return NS_OK;
301 : }
302 :
303 0 : NS_IMETHODIMP nsTreeBoxObject::GetPageLength(PRInt32 *aPageLength)
304 : {
305 0 : *aPageLength = 0;
306 0 : nsTreeBodyFrame* body = GetTreeBody();
307 0 : if (body)
308 0 : return body->GetPageLength(aPageLength);
309 0 : return NS_OK;
310 : }
311 :
312 0 : NS_IMETHODIMP nsTreeBoxObject::GetSelectionRegion(nsIScriptableRegion **aRegion)
313 : {
314 0 : *aRegion = nsnull;
315 0 : nsTreeBodyFrame* body = GetTreeBody();
316 0 : if (body)
317 0 : return body->GetSelectionRegion(aRegion);
318 0 : return NS_OK;
319 : }
320 :
321 : NS_IMETHODIMP
322 0 : nsTreeBoxObject::EnsureRowIsVisible(PRInt32 aRow)
323 : {
324 0 : nsTreeBodyFrame* body = GetTreeBody();
325 0 : if (body)
326 0 : return body->EnsureRowIsVisible(aRow);
327 0 : return NS_OK;
328 : }
329 :
330 : NS_IMETHODIMP
331 0 : nsTreeBoxObject::EnsureCellIsVisible(PRInt32 aRow, nsITreeColumn* aCol)
332 : {
333 0 : nsTreeBodyFrame* body = GetTreeBody();
334 0 : if (body)
335 0 : return body->EnsureCellIsVisible(aRow, aCol);
336 0 : return NS_OK;
337 : return NS_ERROR_NOT_IMPLEMENTED;
338 : }
339 :
340 : NS_IMETHODIMP
341 0 : nsTreeBoxObject::ScrollToRow(PRInt32 aRow)
342 : {
343 0 : nsTreeBodyFrame* body = GetTreeBody(true);
344 0 : if (body)
345 0 : return body->ScrollToRow(aRow);
346 0 : return NS_OK;
347 : }
348 :
349 : NS_IMETHODIMP
350 0 : nsTreeBoxObject::ScrollByLines(PRInt32 aNumLines)
351 : {
352 0 : nsTreeBodyFrame* body = GetTreeBody();
353 0 : if (body)
354 0 : return body->ScrollByLines(aNumLines);
355 0 : return NS_OK;
356 : }
357 :
358 : NS_IMETHODIMP
359 0 : nsTreeBoxObject::ScrollByPages(PRInt32 aNumPages)
360 : {
361 0 : nsTreeBodyFrame* body = GetTreeBody();
362 0 : if (body)
363 0 : return body->ScrollByPages(aNumPages);
364 0 : return NS_OK;
365 : }
366 :
367 : NS_IMETHODIMP
368 0 : nsTreeBoxObject::ScrollToCell(PRInt32 aRow, nsITreeColumn* aCol)
369 : {
370 0 : nsTreeBodyFrame* body = GetTreeBody();
371 0 : if (body)
372 0 : return body->ScrollToCell(aRow, aCol);
373 0 : return NS_OK;
374 : }
375 :
376 : NS_IMETHODIMP
377 0 : nsTreeBoxObject::ScrollToColumn(nsITreeColumn* aCol)
378 : {
379 0 : nsTreeBodyFrame* body = GetTreeBody();
380 0 : if (body)
381 0 : return body->ScrollToColumn(aCol);
382 0 : return NS_OK;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : nsTreeBoxObject::ScrollToHorizontalPosition(PRInt32 aHorizontalPosition)
387 : {
388 0 : nsTreeBodyFrame* body = GetTreeBody();
389 0 : if (body)
390 0 : return body->ScrollToHorizontalPosition(aHorizontalPosition);
391 0 : return NS_OK;
392 : }
393 :
394 0 : NS_IMETHODIMP nsTreeBoxObject::Invalidate()
395 : {
396 0 : nsTreeBodyFrame* body = GetTreeBody();
397 0 : if (body)
398 0 : return body->Invalidate();
399 0 : return NS_OK;
400 : }
401 :
402 0 : NS_IMETHODIMP nsTreeBoxObject::InvalidateColumn(nsITreeColumn* aCol)
403 : {
404 0 : nsTreeBodyFrame* body = GetTreeBody();
405 0 : if (body)
406 0 : return body->InvalidateColumn(aCol);
407 0 : return NS_OK;
408 : }
409 :
410 0 : NS_IMETHODIMP nsTreeBoxObject::InvalidateRow(PRInt32 aIndex)
411 : {
412 0 : nsTreeBodyFrame* body = GetTreeBody();
413 0 : if (body)
414 0 : return body->InvalidateRow(aIndex);
415 0 : return NS_OK;
416 : }
417 :
418 0 : NS_IMETHODIMP nsTreeBoxObject::InvalidateCell(PRInt32 aRow, nsITreeColumn* aCol)
419 : {
420 0 : nsTreeBodyFrame* body = GetTreeBody();
421 0 : if (body)
422 0 : return body->InvalidateCell(aRow, aCol);
423 0 : return NS_OK;
424 : }
425 :
426 0 : NS_IMETHODIMP nsTreeBoxObject::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
427 : {
428 0 : nsTreeBodyFrame* body = GetTreeBody();
429 0 : if (body)
430 0 : return body->InvalidateRange(aStart, aEnd);
431 0 : return NS_OK;
432 : }
433 :
434 0 : NS_IMETHODIMP nsTreeBoxObject::InvalidateColumnRange(PRInt32 aStart, PRInt32 aEnd, nsITreeColumn* aCol)
435 : {
436 0 : nsTreeBodyFrame* body = GetTreeBody();
437 0 : if (body)
438 0 : return body->InvalidateColumnRange(aStart, aEnd, aCol);
439 0 : return NS_OK;
440 : }
441 :
442 0 : NS_IMETHODIMP nsTreeBoxObject::GetRowAt(PRInt32 x, PRInt32 y, PRInt32 *aRow)
443 : {
444 0 : *aRow = 0;
445 0 : nsTreeBodyFrame* body = GetTreeBody();
446 0 : if (body)
447 0 : return body->GetRowAt(x, y, aRow);
448 0 : return NS_OK;
449 : }
450 :
451 0 : NS_IMETHODIMP nsTreeBoxObject::GetCellAt(PRInt32 aX, PRInt32 aY, PRInt32 *aRow, nsITreeColumn** aCol,
452 : nsACString& aChildElt)
453 : {
454 0 : *aRow = 0;
455 0 : *aCol = nsnull;
456 0 : nsTreeBodyFrame* body = GetTreeBody();
457 0 : if (body)
458 0 : return body->GetCellAt(aX, aY, aRow, aCol, aChildElt);
459 0 : return NS_OK;
460 : }
461 :
462 : NS_IMETHODIMP
463 0 : nsTreeBoxObject::GetCoordsForCellItem(PRInt32 aRow, nsITreeColumn* aCol, const nsACString& aElement,
464 : PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
465 : {
466 0 : *aX = *aY = *aWidth = *aHeight = 0;
467 0 : nsTreeBodyFrame* body = GetTreeBody();
468 0 : if (body)
469 0 : return body->GetCoordsForCellItem(aRow, aCol, aElement, aX, aY, aWidth, aHeight);
470 0 : return NS_OK;
471 : }
472 :
473 : NS_IMETHODIMP
474 0 : nsTreeBoxObject::IsCellCropped(PRInt32 aRow, nsITreeColumn* aCol, bool *aIsCropped)
475 : {
476 0 : *aIsCropped = false;
477 0 : nsTreeBodyFrame* body = GetTreeBody();
478 0 : if (body)
479 0 : return body->IsCellCropped(aRow, aCol, aIsCropped);
480 0 : return NS_OK;
481 : }
482 :
483 0 : NS_IMETHODIMP nsTreeBoxObject::RowCountChanged(PRInt32 aIndex, PRInt32 aDelta)
484 : {
485 0 : nsTreeBodyFrame* body = GetTreeBody();
486 0 : if (body)
487 0 : return body->RowCountChanged(aIndex, aDelta);
488 0 : return NS_OK;
489 : }
490 :
491 0 : NS_IMETHODIMP nsTreeBoxObject::BeginUpdateBatch()
492 : {
493 0 : nsTreeBodyFrame* body = GetTreeBody();
494 0 : if (body)
495 0 : return body->BeginUpdateBatch();
496 0 : return NS_OK;
497 : }
498 :
499 0 : NS_IMETHODIMP nsTreeBoxObject::EndUpdateBatch()
500 : {
501 0 : nsTreeBodyFrame* body = GetTreeBody();
502 0 : if (body)
503 0 : return body->EndUpdateBatch();
504 0 : return NS_OK;
505 : }
506 :
507 0 : NS_IMETHODIMP nsTreeBoxObject::ClearStyleAndImageCaches()
508 : {
509 0 : nsTreeBodyFrame* body = GetTreeBody();
510 0 : if (body)
511 0 : return body->ClearStyleAndImageCaches();
512 0 : return NS_OK;
513 : }
514 :
515 : void
516 0 : nsTreeBoxObject::ClearCachedValues()
517 : {
518 0 : mTreeBody = nsnull;
519 0 : }
520 :
521 : // Creation Routine ///////////////////////////////////////////////////////////////////////
522 :
523 : nsresult
524 1 : NS_NewTreeBoxObject(nsIBoxObject** aResult)
525 : {
526 1 : *aResult = new nsTreeBoxObject;
527 1 : if (!*aResult)
528 0 : return NS_ERROR_OUT_OF_MEMORY;
529 1 : NS_ADDREF(*aResult);
530 1 : return NS_OK;
531 4392 : }
532 :
|