Back to index

lightning-sunbird  0.9+nobinonly
nsTreeColumns.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.org 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) 2003
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Dave Hyatt <hyatt@mozilla.org> (Original Author)
00024  *   Jan Varga <varga@ku.sk>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * 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 
00040 #include "nsINameSpaceManager.h"
00041 #include "nsHTMLAtoms.h"
00042 #include "nsXULAtoms.h"
00043 #include "nsIDOMElement.h"
00044 #include "nsIBoxObject.h"
00045 #include "nsIDocument.h"
00046 #include "nsTreeColumns.h"
00047 #include "nsTreeUtils.h"
00048 #include "nsStyleContext.h"
00049 #include "nsIDOMClassInfo.h"
00050 #include "nsINodeInfo.h"
00051 
00052 // Column class that caches all the info about our column.
00053 nsTreeColumn::nsTreeColumn(nsTreeColumns* aColumns, nsIFrame* aFrame)
00054   : mFrame(aFrame),
00055     mColumns(aColumns),
00056     mNext(nsnull),
00057     mPrevious(nsnull)
00058 {
00059   CacheAttributes();
00060 }
00061 
00062 nsTreeColumn::~nsTreeColumn()
00063 {
00064   if (mNext) {
00065     mNext->SetPrevious(nsnull);
00066     NS_RELEASE(mNext);
00067   }
00068 }
00069 
00070 // QueryInterface implementation for nsTreeColumn
00071 NS_INTERFACE_MAP_BEGIN(nsTreeColumn)
00072   NS_INTERFACE_MAP_ENTRY(nsITreeColumn)
00073   NS_INTERFACE_MAP_ENTRY(nsISupports)
00074   NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(TreeColumn)
00075 NS_INTERFACE_MAP_END
00076                                                                                 
00077 NS_IMPL_ADDREF(nsTreeColumn)
00078 NS_IMPL_RELEASE(nsTreeColumn)
00079 
00080 NS_IMETHODIMP
00081 nsTreeColumn::GetElement(nsIDOMElement** aElement)
00082 {
00083   return CallQueryInterface(GetContent(), aElement);
00084 }
00085 
00086 NS_IMETHODIMP
00087 nsTreeColumn::GetColumns(nsITreeColumns** aColumns)
00088 {
00089   NS_IF_ADDREF(*aColumns = mColumns);
00090   return NS_OK;
00091 }
00092 
00093 NS_IMETHODIMP
00094 nsTreeColumn::GetX(PRInt32* aX)
00095 {
00096   float t2p = mFrame->GetPresContext()->TwipsToPixels();
00097   *aX = NSToIntRound(GetX() * t2p);
00098   return NS_OK;
00099 }
00100 
00101 NS_IMETHODIMP
00102 nsTreeColumn::GetWidth(PRInt32* aWidth)
00103 {
00104   float t2p = mFrame->GetPresContext()->TwipsToPixels();
00105   *aWidth = NSToIntRound(GetWidth() * t2p);
00106   return NS_OK;
00107 }
00108 
00109 NS_IMETHODIMP
00110 nsTreeColumn::GetId(nsAString& aId)
00111 {
00112   aId = GetId();
00113   return NS_OK;
00114 }
00115 
00116 NS_IMETHODIMP
00117 nsTreeColumn::GetIdConst(const PRUnichar** aIdConst)
00118 {
00119   *aIdConst = mId.get();
00120   return NS_OK;
00121 }
00122 
00123 NS_IMETHODIMP
00124 nsTreeColumn::GetAtom(nsIAtom** aAtom)
00125 {
00126   NS_IF_ADDREF(*aAtom = GetAtom());
00127   return NS_OK;
00128 }
00129 
00130 NS_IMETHODIMP
00131 nsTreeColumn::GetIndex(PRInt32* aIndex)
00132 {
00133   *aIndex = GetIndex();
00134   return NS_OK;
00135 }
00136 
00137 NS_IMETHODIMP
00138 nsTreeColumn::GetPrimary(PRBool* aPrimary)
00139 {
00140   *aPrimary = IsPrimary();
00141   return NS_OK;
00142 }
00143 
00144 NS_IMETHODIMP
00145 nsTreeColumn::GetCycler(PRBool* aCycler)
00146 {
00147   *aCycler = IsCycler();
00148   return NS_OK;
00149 }
00150 
00151 NS_IMETHODIMP
00152 nsTreeColumn::GetEditable(PRBool* aEditable)
00153 {
00154   *aEditable = IsEditable();
00155   return NS_OK;
00156 }
00157 
00158 NS_IMETHODIMP
00159 nsTreeColumn::GetType(PRInt16* aType)
00160 {
00161   *aType = GetType();
00162   return NS_OK;
00163 }
00164 
00165 NS_IMETHODIMP
00166 nsTreeColumn::GetNext(nsITreeColumn** _retval)
00167 {
00168   NS_IF_ADDREF(*_retval = GetNext());
00169   return NS_OK;
00170 }
00171 
00172 NS_IMETHODIMP
00173 nsTreeColumn::GetPrevious(nsITreeColumn** _retval)
00174 {
00175   NS_IF_ADDREF(*_retval = GetPrevious());
00176   return NS_OK;
00177 }
00178 
00179 NS_IMETHODIMP
00180 nsTreeColumn::Invalidate()
00181 {
00182   CacheAttributes();
00183   return NS_OK;
00184 }
00185 
00186 void
00187 nsTreeColumn::CacheAttributes()
00188 {
00189   nsIContent* content = GetContent();
00190 
00191   // Fetch the Id.
00192   content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::id, mId);
00193 
00194   // If we have an Id, cache the Id as an atom.
00195   if (!mId.IsEmpty()) {
00196     mAtom = do_GetAtom(mId);
00197   }
00198 
00199   // Cache our index.
00200   nsTreeUtils::GetColumnIndex(content, &mIndex);
00201 
00202   const nsStyleVisibility* vis = mFrame->GetStyleVisibility();
00203 
00204   // Cache our text alignment policy.
00205   const nsStyleText* textStyle = mFrame->GetStyleText();
00206 
00207   mTextAlignment = textStyle->mTextAlign;
00208   if (mTextAlignment == 0 || mTextAlignment == 2) { // Left or Right
00209     if (vis->mDirection == NS_STYLE_DIRECTION_RTL)
00210       mTextAlignment = 2 - mTextAlignment; // Right becomes left, left becomes right.
00211   }
00212 
00213   // Figure out if we're the primary column (that has to have indentation
00214   // and twisties drawn.
00215   mIsPrimary = PR_FALSE;
00216   nsAutoString primary;
00217   content->GetAttr(kNameSpaceID_None, nsXULAtoms::primary, primary);
00218   if (primary.EqualsLiteral("true"))
00219     mIsPrimary = PR_TRUE;
00220 
00221   // Figure out if we're a cycling column (one that doesn't cause a selection
00222   // to happen).
00223   mIsCycler = PR_FALSE;
00224   nsAutoString cycler;
00225   content->GetAttr(kNameSpaceID_None, nsXULAtoms::cycler, cycler);
00226   if (cycler.EqualsLiteral("true"))
00227     mIsCycler = PR_TRUE;
00228 
00229   mIsEditable = PR_FALSE;
00230   nsAutoString editable;
00231   content->GetAttr(kNameSpaceID_None, nsXULAtoms::editable, editable);
00232   if (editable.EqualsLiteral("true"))
00233     mIsEditable = PR_TRUE;
00234 
00235   // Figure out our column type. Default type is text.
00236   mType = nsITreeColumn::TYPE_TEXT;
00237   nsAutoString type;
00238   content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, type);
00239   if (type.EqualsLiteral("checkbox"))
00240     mType = nsITreeColumn::TYPE_CHECKBOX;
00241   else if (type.EqualsLiteral("progressmeter"))
00242     mType = nsITreeColumn::TYPE_PROGRESSMETER;
00243 
00244   // Fetch the crop style.
00245   mCropStyle = 0;
00246   nsAutoString crop;
00247   content->GetAttr(kNameSpaceID_None, nsXULAtoms::crop, crop);
00248   if (crop.EqualsLiteral("center"))
00249     mCropStyle = 1;
00250   else if (crop.EqualsLiteral("left") ||
00251            crop.EqualsLiteral("start"))
00252     mCropStyle = 2;
00253 }
00254 
00255 
00256 nsTreeColumns::nsTreeColumns(nsITreeBoxObject* aTree)
00257   : mTree(aTree),
00258     mFirstColumn(nsnull)
00259 {
00260 }
00261 
00262 nsTreeColumns::~nsTreeColumns()
00263 {
00264   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00265     currCol->SetColumns(nsnull);
00266   }
00267   NS_IF_RELEASE(mFirstColumn);
00268 }
00269 
00270 // QueryInterface implementation for nsTreeColumns
00271 NS_INTERFACE_MAP_BEGIN(nsTreeColumns)
00272   NS_INTERFACE_MAP_ENTRY(nsITreeColumns)
00273   NS_INTERFACE_MAP_ENTRY(nsISupports)
00274   NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(TreeColumns)
00275 NS_INTERFACE_MAP_END
00276                                                                                 
00277 NS_IMPL_ADDREF(nsTreeColumns)
00278 NS_IMPL_RELEASE(nsTreeColumns)
00279 
00280 NS_IMETHODIMP
00281 nsTreeColumns::GetTree(nsITreeBoxObject** _retval)
00282 {
00283   NS_IF_ADDREF(*_retval = mTree);
00284   return NS_OK;
00285 }
00286 
00287 NS_IMETHODIMP
00288 nsTreeColumns::GetCount(PRInt32* _retval)
00289 {
00290   EnsureColumns();
00291   *_retval = 0;
00292   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00293     ++(*_retval);
00294   }
00295   return NS_OK;
00296 }
00297 
00298 NS_IMETHODIMP
00299 nsTreeColumns::GetFirstColumn(nsITreeColumn** _retval)
00300 {
00301   NS_IF_ADDREF(*_retval = GetFirstColumn());
00302   return NS_OK;
00303 }
00304 
00305 NS_IMETHODIMP
00306 nsTreeColumns::GetLastColumn(nsITreeColumn** _retval)
00307 {
00308   EnsureColumns();
00309   *_retval = nsnull;
00310   nsTreeColumn* currCol = mFirstColumn;
00311   while (currCol) {
00312     nsTreeColumn* next = currCol->GetNext();
00313     if (!next) {
00314       NS_ADDREF(*_retval = currCol);
00315       break;
00316     }
00317     currCol = next;
00318   }
00319   return NS_OK;
00320 }
00321 
00322 NS_IMETHODIMP
00323 nsTreeColumns::GetPrimaryColumn(nsITreeColumn** _retval)
00324 {
00325   NS_IF_ADDREF(*_retval = GetPrimaryColumn());
00326   return NS_OK;
00327 }
00328 
00329 NS_IMETHODIMP
00330 nsTreeColumns::GetSortedColumn(nsITreeColumn** _retval)
00331 {
00332   EnsureColumns();
00333   *_retval = nsnull;
00334   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00335     nsAutoString attr;
00336     currCol->GetContent()->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, attr);
00337     if (!attr.IsEmpty()) {
00338       NS_ADDREF(*_retval = currCol);
00339       return NS_OK;
00340     }
00341   }
00342   return NS_OK;
00343 }
00344 
00345 NS_IMETHODIMP
00346 nsTreeColumns::GetKeyColumn(nsITreeColumn** _retval)
00347 {
00348   EnsureColumns();
00349   *_retval = nsnull;
00350 
00351   nsTreeColumn* first;
00352   nsTreeColumn* primary;
00353   nsTreeColumn* sorted;
00354   first = primary = sorted = nsnull;
00355 
00356   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00357     nsIContent* content = currCol->GetContent();
00358 
00359     // Skip hidden columns.
00360     nsAutoString attr;
00361     content->GetAttr(kNameSpaceID_None, nsHTMLAtoms::hidden, attr);
00362     if (attr.EqualsLiteral("true"))
00363       continue;
00364 
00365     // Skip non-text column
00366     if (currCol->GetType() != nsITreeColumn::TYPE_TEXT)
00367       continue;
00368 
00369     if (!first)
00370       first = currCol;
00371     
00372     content->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, attr);
00373     if (!attr.IsEmpty()) {
00374       // Use sorted column as the key.
00375       sorted = currCol;
00376       break;
00377     }
00378 
00379     if (currCol->IsPrimary())
00380       if (!primary)
00381         primary = currCol;
00382   }
00383 
00384   if (sorted)
00385     *_retval = sorted;
00386   else if (primary)
00387     *_retval = primary;
00388   else
00389     *_retval = first;
00390 
00391   NS_IF_ADDREF(*_retval);
00392   return NS_OK;
00393 }
00394 
00395 NS_IMETHODIMP
00396 nsTreeColumns::GetColumnFor(nsIDOMElement* aElement, nsITreeColumn** _retval)
00397 {
00398   EnsureColumns();
00399   *_retval = nsnull;
00400   nsCOMPtr<nsIContent> element = do_QueryInterface(aElement);
00401   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00402     if (currCol->GetContent() == element) {
00403       NS_ADDREF(*_retval = currCol);
00404       break;
00405     }
00406   }
00407 
00408   return NS_OK;
00409 }
00410 
00411 NS_IMETHODIMP
00412 nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval)
00413 {
00414   EnsureColumns();
00415   *_retval = nsnull;
00416   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00417     if (currCol->GetId().Equals(aId)) {
00418       NS_ADDREF(*_retval = currCol);
00419       break;
00420     }
00421   }
00422   return NS_OK;
00423 }
00424 
00425 NS_IMETHODIMP
00426 nsTreeColumns::GetColumnAt(PRInt32 aIndex, nsITreeColumn** _retval)
00427 {
00428   EnsureColumns();
00429   *_retval = nsnull;
00430   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00431     if (currCol->GetIndex() == aIndex) {
00432       NS_ADDREF(*_retval = currCol);
00433       break;
00434     }
00435   }
00436   return NS_OK;
00437 }
00438 
00439 NS_IMETHODIMP
00440 nsTreeColumns::InvalidateColumns()
00441 {
00442   NS_IF_RELEASE(mFirstColumn);
00443   return NS_OK;
00444 }
00445 
00446 NS_IMETHODIMP
00447 nsTreeColumns::RestoreNaturalOrder()
00448 {
00449   if (!mTree)
00450     return NS_OK;
00451 
00452   nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
00453   nsCOMPtr<nsIDOMElement> element;
00454   boxObject->GetElement(getter_AddRefs(element));
00455   nsCOMPtr<nsIContent> content = do_QueryInterface(element);
00456 
00457   nsCOMPtr<nsIContent> colsContent;
00458   nsTreeUtils::GetImmediateChild(content, nsXULAtoms::treecols, getter_AddRefs(colsContent));
00459   if (!colsContent)
00460     return NS_OK;
00461 
00462   PRUint32 numChildren = colsContent->GetChildCount();
00463   for (PRUint32 i = 0; i < numChildren; ++i) {
00464     nsIContent *child = colsContent->GetChildAt(i);
00465     nsAutoString ordinal;
00466     ordinal.AppendInt(i);
00467     child->SetAttr(kNameSpaceID_None, nsXULAtoms::ordinal, ordinal, PR_TRUE);
00468   }
00469 
00470   NS_IF_RELEASE(mFirstColumn);
00471 
00472   mTree->Invalidate();
00473 
00474   return NS_OK;
00475 }
00476 
00477 nsTreeColumn*
00478 nsTreeColumns::GetPrimaryColumn()
00479 {
00480   EnsureColumns();
00481   for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) {
00482     if (currCol->IsPrimary()) {
00483       return currCol;
00484     }
00485   }
00486   return nsnull;
00487 }
00488 
00489 void
00490 nsTreeColumns::EnsureColumns()
00491 {
00492   if (mTree && !mFirstColumn) {
00493     nsCOMPtr<nsIBoxObject> boxObject = do_QueryInterface(mTree);
00494     nsCOMPtr<nsIDOMElement> treeElement;
00495     boxObject->GetElement(getter_AddRefs(treeElement));
00496     nsCOMPtr<nsIContent> treeContent = do_QueryInterface(treeElement);
00497 
00498     nsCOMPtr<nsIContent> colsContent;
00499     nsTreeUtils::GetDescendantChild(treeContent, nsXULAtoms::treecols, getter_AddRefs(colsContent));
00500     if (!colsContent)
00501       return;
00502 
00503     nsCOMPtr<nsIDocument> document = treeContent->GetDocument();
00504     nsIPresShell *shell = document->GetShellAt(0);
00505     if (!shell)
00506       return;
00507 
00508     nsIFrame* colsFrame = nsnull;
00509     shell->GetPrimaryFrameFor(colsContent, &colsFrame);
00510     if (!colsFrame)
00511       return;
00512 
00513     nsIBox* colBox = nsnull;
00514     colsFrame->GetChildBox(&colBox);
00515 
00516     nsTreeColumn* currCol = nsnull;
00517     while (colBox) {
00518       nsIContent* colContent = colBox->GetContent();
00519 
00520       nsINodeInfo *ni = colContent->GetNodeInfo();
00521       if (ni && ni->Equals(nsXULAtoms::treecol, kNameSpaceID_XUL)) { 
00522         // Create a new column structure.
00523         nsTreeColumn* col = new nsTreeColumn(this, colBox);
00524         if (!col)
00525           return;
00526 
00527         if (currCol) {
00528           currCol->SetNext(col);
00529           col->SetPrevious(currCol);
00530         }
00531         else {
00532           NS_ADDREF(mFirstColumn = col);
00533         }
00534         currCol = col;
00535       }
00536 
00537       colBox->GetNextBox(&colBox);
00538     }
00539   }
00540 }