Back to index

lightning-sunbird  0.9+nobinonly
nsTreeBoxObject.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Dave Hyatt <hyatt@mozilla.org> (Original Author)
00024  *   Brian Ryner <bryner@brianryner.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsTreeBoxObject.h"
00040 #include "nsCOMPtr.h"
00041 #include "nsPresContext.h"
00042 #include "nsIPresShell.h"
00043 #include "nsPITreeBoxObject.h"
00044 #include "nsITreeView.h"
00045 #include "nsITreeSelection.h"
00046 #include "nsBoxObject.h"
00047 #include "nsIFrame.h"
00048 #include "nsIAtom.h"
00049 #include "nsINodeInfo.h"
00050 #include "nsXULAtoms.h"
00051 #include "nsChildIterator.h"
00052 #include "nsContentUtils.h"
00053 #include "nsDOMError.h"
00054 
00055 /* Implementation file */
00056 NS_IMPL_ISUPPORTS_INHERITED2(nsTreeBoxObject, nsBoxObject, nsITreeBoxObject,
00057                              nsPITreeBoxObject)
00058 
00059 
00060 NS_IMETHODIMP
00061 nsTreeBoxObject::SetDocument(nsIDocument* aDocument)
00062 {
00063   // this should only be called with a null document, which indicates
00064   // that we're being torn down.
00065   NS_ASSERTION(aDocument == nsnull, "SetDocument called with non-null document");
00066 
00067   // Drop the view's ref to us.
00068   nsCOMPtr<nsISupports> suppView;
00069   GetPropertyAsSupports(NS_LITERAL_STRING("view").get(), getter_AddRefs(suppView));
00070   nsCOMPtr<nsITreeView> treeView(do_QueryInterface(suppView));
00071   if (treeView) {
00072     nsCOMPtr<nsITreeSelection> sel;
00073     treeView->GetSelection(getter_AddRefs(sel));
00074     if (sel)
00075       sel->SetTree(nsnull);
00076     treeView->SetTree(nsnull); // Break the circular ref between the view and us.
00077   }
00078 
00079   return nsBoxObject::SetDocument(aDocument);
00080 }
00081 
00082 
00083 NS_IMETHODIMP
00084 nsTreeBoxObject::InvalidatePresentationStuff()
00085 {
00086   ClearCachedTreeBody();
00087   SetPropertyAsSupports(NS_LITERAL_STRING("view").get(), nsnull);
00088 
00089   return nsBoxObject::InvalidatePresentationStuff();
00090 }
00091   
00092 nsTreeBoxObject::nsTreeBoxObject()
00093   : mTreeBody(nsnull)
00094 {
00095 }
00096 
00097 nsTreeBoxObject::~nsTreeBoxObject()
00098 {
00099   /* destructor code */
00100 }
00101 
00102 
00103 NS_IMETHODIMP nsTreeBoxObject::Init(nsIContent* aContent, nsIPresShell* aPresShell)
00104 {
00105   nsresult rv = nsBoxObject::Init(aContent, aPresShell);
00106   if (NS_FAILED(rv)) return rv;
00107   return NS_OK;
00108 }
00109 
00110 static void FindBodyElement(nsIContent* aParent, nsIContent** aResult)
00111 {
00112   *aResult = nsnull;
00113   ChildIterator iter, last;
00114   for (ChildIterator::Init(aParent, &iter, &last); iter != last; ++iter) {
00115     nsCOMPtr<nsIContent> content = *iter;
00116 
00117     nsINodeInfo *ni = content->GetNodeInfo();
00118     if (ni && ni->Equals(nsXULAtoms::treechildren, kNameSpaceID_XUL)) {
00119       *aResult = content;
00120       NS_ADDREF(*aResult);
00121       break;
00122     } else if (ni && ni->Equals(nsXULAtoms::tree, kNameSpaceID_XUL)) {
00123       // There are nesting tree elements. Only the innermost should
00124       // find the treechilren.
00125       break;
00126     } else if (ni && !ni->Equals(nsXULAtoms::templateAtom, kNameSpaceID_XUL)) {
00127       FindBodyElement(content, aResult);
00128       if (*aResult)
00129         break;
00130     }
00131   }
00132 }
00133 
00134 nsITreeBoxObject*
00135 nsTreeBoxObject::GetTreeBody()
00136 {
00137   if (mTreeBody) {
00138     return mTreeBody;
00139   }
00140 
00141   nsIFrame* frame = GetFrame();
00142   if (!frame)
00143     return nsnull;
00144 
00145   // Iterate over our content model children looking for the body.
00146   nsCOMPtr<nsIContent> content;
00147   FindBodyElement(frame->GetContent(), getter_AddRefs(content));
00148 
00149   nsCOMPtr<nsIPresShell> shell = GetPresShell();
00150   if (!shell) {
00151     return nsnull;
00152   }
00153 
00154   shell->GetPrimaryFrameFor(content, &frame);
00155   if (!frame)
00156      return nsnull;
00157 
00158   // It's a frame. Refcounts are irrelevant.
00159   CallQueryInterface(frame, &mTreeBody);
00160   return mTreeBody;
00161 }
00162 
00163 NS_IMETHODIMP nsTreeBoxObject::GetView(nsITreeView * *aView)
00164 {
00165   nsITreeBoxObject* body = GetTreeBody();
00166   if (body)
00167     return body->GetView(aView);
00168   return NS_OK;
00169 }
00170 
00171 static PRBool
00172 CanTrustView(nsISupports* aValue)
00173 {
00174   // Untrusted content is only allowed to specify known-good views
00175   if (nsContentUtils::IsCallerTrustedForWrite())
00176     return PR_TRUE;
00177   nsCOMPtr<nsINativeTreeView> nativeTreeView = do_QueryInterface(aValue);
00178   if (!nativeTreeView || NS_FAILED(nativeTreeView->EnsureNative())) {
00179     // XXX ERRMSG need a good error here for developers
00180     return PR_FALSE;
00181   }
00182   return PR_TRUE;
00183 }
00184 
00185 NS_IMETHODIMP
00186 nsTreeBoxObject::SetPropertyAsSupports(const PRUnichar* aPropertyName, nsISupports* aValue)
00187 {
00188   NS_ENSURE_ARG(aPropertyName);
00189   
00190   if (nsDependentString(aPropertyName).EqualsLiteral("view") &&
00191       !CanTrustView(aValue))
00192     return NS_ERROR_DOM_SECURITY_ERR;
00193 
00194   return nsBoxObject::SetPropertyAsSupports(aPropertyName, aValue);
00195 }
00196 
00197 NS_IMETHODIMP nsTreeBoxObject::SetView(nsITreeView * aView)
00198 {
00199   if (!CanTrustView(aView))
00200     return NS_ERROR_DOM_SECURITY_ERR;
00201   
00202   nsITreeBoxObject* body = GetTreeBody();
00203   if (body) {
00204     body->SetView(aView);
00205   
00206     // only return if the body frame was able to store the view,
00207     // else we need to cache the property below
00208     nsCOMPtr<nsITreeView> view;
00209     body->GetView(getter_AddRefs(view));
00210     if (view)
00211       return NS_OK;
00212   }
00213   
00214   nsCOMPtr<nsISupports> suppView(do_QueryInterface(aView));
00215   if (suppView)
00216     SetPropertyAsSupports(NS_LITERAL_STRING("view").get(), suppView);
00217   else
00218     RemoveProperty(NS_LITERAL_STRING("view").get());
00219 
00220   return NS_OK;
00221 }
00222 
00223 NS_IMETHODIMP nsTreeBoxObject::GetFocused(PRBool* aFocused)
00224 {
00225   nsITreeBoxObject* body = GetTreeBody();
00226   if (body)
00227     return body->GetFocused(aFocused);
00228   return NS_OK;
00229 }
00230 
00231 NS_IMETHODIMP nsTreeBoxObject::SetFocused(PRBool aFocused)
00232 {
00233   nsITreeBoxObject* body = GetTreeBody();
00234   if (body)
00235     return body->SetFocused(aFocused);
00236   return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP nsTreeBoxObject::GetTreeBody(nsIDOMElement** aElement)
00240 {
00241   nsITreeBoxObject* body = GetTreeBody();
00242   if (body) 
00243     return body->GetTreeBody(aElement);
00244   return NS_OK;
00245 }
00246 
00247 NS_IMETHODIMP nsTreeBoxObject::GetColumns(nsITreeColumns** aColumns)
00248 {
00249   nsITreeBoxObject* body = GetTreeBody();
00250   if (body) 
00251     return body->GetColumns(aColumns);
00252   return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP nsTreeBoxObject::GetRowHeight(PRInt32* _retval)
00256 {
00257   nsITreeBoxObject* body = GetTreeBody();
00258   if (body) 
00259     return body->GetRowHeight(_retval);
00260   return NS_OK;
00261 }
00262 
00263 NS_IMETHODIMP nsTreeBoxObject::GetFirstVisibleRow(PRInt32 *_retval)
00264 {
00265   nsITreeBoxObject* body = GetTreeBody();
00266   if (body)
00267     return body->GetFirstVisibleRow(_retval);
00268   return NS_OK;
00269 }
00270 
00271 NS_IMETHODIMP nsTreeBoxObject::GetLastVisibleRow(PRInt32 *_retval)
00272 {
00273   nsITreeBoxObject* body = GetTreeBody();
00274   if (body)
00275     return body->GetLastVisibleRow(_retval);
00276   return NS_OK;
00277 }
00278 
00279 NS_IMETHODIMP nsTreeBoxObject::GetPageLength(PRInt32 *_retval)
00280 {
00281   nsITreeBoxObject* body = GetTreeBody();
00282   if (body)
00283     return body->GetPageLength(_retval);
00284   return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP
00288 nsTreeBoxObject::EnsureRowIsVisible(PRInt32 aRow)
00289 {
00290   nsITreeBoxObject* body = GetTreeBody();
00291   if (body)
00292     return body->EnsureRowIsVisible(aRow);
00293   return NS_OK;
00294 }
00295 
00296 NS_IMETHODIMP
00297 nsTreeBoxObject::ScrollToRow(PRInt32 aRow)
00298 {
00299   nsITreeBoxObject* body = GetTreeBody();
00300   if (body)
00301     return body->ScrollToRow(aRow);
00302   return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsTreeBoxObject::ScrollByLines(PRInt32 aNumLines)
00307 {
00308   nsITreeBoxObject* body = GetTreeBody();
00309   if (body)
00310     return body->ScrollByLines(aNumLines);
00311   return NS_OK;
00312 }
00313 
00314 NS_IMETHODIMP
00315 nsTreeBoxObject::ScrollByPages(PRInt32 aNumPages)
00316 {
00317   nsITreeBoxObject* body = GetTreeBody();
00318   if (body)
00319     return body->ScrollByPages(aNumPages);
00320   return NS_OK;
00321 }
00322 
00323 
00324 NS_IMETHODIMP nsTreeBoxObject::Invalidate()
00325 {
00326   nsITreeBoxObject* body = GetTreeBody();
00327   if (body)
00328     return body->Invalidate();
00329   return NS_OK;
00330 }
00331 
00332 NS_IMETHODIMP nsTreeBoxObject::InvalidateColumn(nsITreeColumn* aCol)
00333 {
00334   nsITreeBoxObject* body = GetTreeBody();
00335   if (body)
00336     return body->InvalidateColumn(aCol);
00337   return NS_OK;
00338 }
00339 
00340 NS_IMETHODIMP nsTreeBoxObject::InvalidateRow(PRInt32 aIndex)
00341 {
00342   nsITreeBoxObject* body = GetTreeBody();
00343   if (body)
00344     return body->InvalidateRow(aIndex);
00345   return NS_OK;
00346 }
00347 
00348 NS_IMETHODIMP nsTreeBoxObject::InvalidateCell(PRInt32 aRow, nsITreeColumn* aCol)
00349 {
00350   nsITreeBoxObject* body = GetTreeBody();
00351   if (body)
00352     return body->InvalidateCell(aRow, aCol);
00353   return NS_OK;
00354 }
00355 
00356 NS_IMETHODIMP nsTreeBoxObject::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
00357 {
00358   nsITreeBoxObject* body = GetTreeBody();
00359   if (body)
00360     return body->InvalidateRange(aStart, aEnd);
00361   return NS_OK;
00362 }
00363 
00364 NS_IMETHODIMP nsTreeBoxObject::GetRowAt(PRInt32 x, PRInt32 y, PRInt32 *_retval)
00365 {
00366   nsITreeBoxObject* body = GetTreeBody();
00367   if (body)
00368     return body->GetRowAt(x, y, _retval);
00369   return NS_OK;
00370 }
00371 
00372 NS_IMETHODIMP nsTreeBoxObject::GetCellAt(PRInt32 x, PRInt32 y, PRInt32 *row, nsITreeColumn** col,
00373                                          nsACString& childElt)
00374 {
00375   nsITreeBoxObject* body = GetTreeBody();
00376   if (body)
00377     return body->GetCellAt(x, y, row, col, childElt);
00378   return NS_OK;
00379 }
00380 
00381 NS_IMETHODIMP
00382 nsTreeBoxObject::GetCoordsForCellItem(PRInt32 aRow, nsITreeColumn* aCol, const nsACString& aElement, 
00383                                       PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight)
00384 {
00385   nsITreeBoxObject* body = GetTreeBody();
00386   if (body)
00387     return body->GetCoordsForCellItem(aRow, aCol, aElement, aX, aY, aWidth, aHeight);
00388   return NS_OK;
00389 }
00390 
00391 NS_IMETHODIMP
00392 nsTreeBoxObject::IsCellCropped(PRInt32 aRow, nsITreeColumn* aCol, PRBool *_retval)
00393 {  
00394   nsITreeBoxObject* body = GetTreeBody();
00395   if (body)
00396     return body->IsCellCropped(aRow, aCol, _retval);
00397   return NS_OK;
00398 }
00399 
00400 NS_IMETHODIMP nsTreeBoxObject::RowCountChanged(PRInt32 aIndex, PRInt32 aDelta)
00401 {
00402   nsITreeBoxObject* body = GetTreeBody();
00403   if (body)
00404     return body->RowCountChanged(aIndex, aDelta);
00405   return NS_OK;
00406 }
00407 
00408 NS_IMETHODIMP nsTreeBoxObject::BeginUpdateBatch()
00409 {
00410   nsITreeBoxObject* body = GetTreeBody();
00411   if (body)
00412     return body->BeginUpdateBatch();
00413   return NS_OK;
00414 }
00415 
00416 NS_IMETHODIMP nsTreeBoxObject::EndUpdateBatch()
00417 {
00418   nsITreeBoxObject* body = GetTreeBody();
00419   if (body)
00420     return body->EndUpdateBatch();
00421   return NS_OK;
00422 }
00423 
00424 NS_IMETHODIMP nsTreeBoxObject::ClearStyleAndImageCaches()
00425 {
00426   nsITreeBoxObject* body = GetTreeBody();
00427   if (body)
00428     return body->ClearStyleAndImageCaches();
00429   return NS_OK;
00430 }
00431 
00432 void
00433 nsTreeBoxObject::ClearCachedTreeBody()
00434 {
00435   mTreeBody = nsnull;
00436 }    
00437 
00438 // Creation Routine ///////////////////////////////////////////////////////////////////////
00439 
00440 nsresult
00441 NS_NewTreeBoxObject(nsIBoxObject** aResult)
00442 {
00443   *aResult = new nsTreeBoxObject;
00444   if (!*aResult)
00445     return NS_ERROR_OUT_OF_MEMORY;
00446   NS_ADDREF(*aResult);
00447   return NS_OK;
00448 }
00449