Back to index

lightning-sunbird  0.9+nobinonly
nsASN1Tree.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Javier Delgadillo <javi@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsASN1Tree.h"
00038 #include "nsIComponentManager.h"
00039 #include "nsString.h"
00040 #include "nsCRT.h"
00041 #include "nsArray.h"
00042 
00043 NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Tree, nsIASN1Tree, 
00044                                                  nsITreeView)
00045 
00046 nsNSSASN1Tree::nsNSSASN1Tree() 
00047 :mTopNode(nsnull)
00048 {
00049 }
00050 
00051 nsNSSASN1Tree::~nsNSSASN1Tree()
00052 {
00053   ClearNodes();
00054 }
00055 
00056 void nsNSSASN1Tree::ClearNodesRecursively(myNode *n)
00057 {
00058   myNode *walk = n;
00059   while (walk) {
00060     myNode *kill = walk;
00061 
00062     if (walk->child) {
00063       ClearNodesRecursively(walk->child);
00064     }
00065     
00066     walk = walk->next;
00067     delete kill;
00068   }
00069 }
00070 
00071 void nsNSSASN1Tree::ClearNodes()
00072 {
00073   ClearNodesRecursively(mTopNode);
00074   mTopNode = nsnull;
00075 }
00076 
00077 void nsNSSASN1Tree::InitChildsRecursively(myNode *n)
00078 {
00079   if (!n->obj)
00080     return;
00081 
00082   n->seq = do_QueryInterface(n->obj);
00083   if (!n->seq)
00084     return;
00085 
00086   // If the object is a sequence, there might still be a reason
00087   // why it should not be displayed as a container.
00088   // If we decide that it has all the properties to justify
00089   // displaying as a container, we will create a new child chain.
00090   // If we decide, it does not make sense to display as a container,
00091   // we forget that it is a sequence by erasing n->seq.
00092   // That way, n->seq and n->child will be either both set or both null.
00093 
00094   PRBool isContainer;
00095   n->seq->GetIsValidContainer(&isContainer);
00096   if (!isContainer) {
00097     n->seq = nsnull;
00098     return;
00099   }
00100 
00101   nsCOMPtr<nsIMutableArray> asn1Objects;
00102   n->seq->GetASN1Objects(getter_AddRefs(asn1Objects));
00103   PRUint32 numObjects;
00104   asn1Objects->GetLength(&numObjects);
00105   
00106   if (!numObjects) {
00107     n->seq = nsnull;
00108     return;
00109   }
00110   
00111   myNode *walk = nsnull;
00112   myNode *prev = nsnull;
00113   
00114   PRUint32 i;
00115   nsCOMPtr<nsISupports> isupports;
00116   for (i=0; i<numObjects; i++) {
00117     if (0 == i) {
00118       n->child = walk = new myNode;
00119     }
00120     else {
00121       walk = new myNode;
00122     }
00123 
00124     walk->parent = n;
00125     if (prev) {
00126       prev->next = walk;
00127     }
00128   
00129     walk->obj = do_QueryElementAt(asn1Objects, i);
00130 
00131     InitChildsRecursively(walk);
00132 
00133     prev = walk;
00134   }
00135 }
00136 
00137 void nsNSSASN1Tree::InitNodes()
00138 {
00139   ClearNodes();
00140 
00141   mTopNode = new myNode;
00142   mTopNode->obj = mASN1Object;
00143 
00144   InitChildsRecursively(mTopNode);
00145 }
00146 
00147 /* void loadASN1Structure (in nsIASN1Object asn1Object); */
00148 NS_IMETHODIMP 
00149 nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object *asn1Object)
00150 {
00151   //
00152   // The tree won't automatically re-draw if the contents
00153   // have been changed.  So I do a quick test here to let
00154   // me know if I should forced the tree to redraw itself
00155   // by calling RowCountChanged on it.
00156   //
00157   PRBool redraw = (mASN1Object && mTree);
00158   PRInt32 rowsToDelete = 0;
00159 
00160   if (redraw) {
00161     // This is the number of rows we will be deleting after
00162     // the contents have changed.
00163     rowsToDelete = 0-CountVisibleNodes(mTopNode);
00164   }
00165 
00166   mASN1Object = asn1Object;
00167   InitNodes();
00168 
00169   if (redraw) {
00170     // The number of rows in the new content.
00171     PRInt32 newRows = CountVisibleNodes(mTopNode);
00172     // Erase all of the old rows.
00173     mTree->RowCountChanged(0, rowsToDelete);
00174     // Replace them with the new contents
00175     mTree->RowCountChanged(0, newRows);
00176   }
00177 
00178   return NS_OK;
00179 }
00180 
00181 /* readonly attribute long rowCount; */
00182 NS_IMETHODIMP 
00183 nsNSSASN1Tree::GetRowCount(PRInt32 *aRowCount)
00184 {
00185   if (mASN1Object) {
00186     *aRowCount = CountVisibleNodes(mTopNode);
00187   } else {
00188     *aRowCount = 0;
00189   }
00190   return NS_OK;
00191 }
00192 
00193 /* attribute nsITreeSelection selection; */
00194 NS_IMETHODIMP 
00195 nsNSSASN1Tree::GetSelection(nsITreeSelection * *aSelection)
00196 {
00197   *aSelection = mSelection;
00198   NS_IF_ADDREF(*aSelection);
00199   return NS_OK;
00200 }
00201 
00202 NS_IMETHODIMP 
00203 nsNSSASN1Tree::SetSelection(nsITreeSelection * aSelection)
00204 {
00205   mSelection = aSelection;
00206   return NS_OK;
00207 }
00208 
00209 /* void getRowProperties (in long index, in nsISupportsArray properties); */
00210 NS_IMETHODIMP 
00211 nsNSSASN1Tree::GetRowProperties(PRInt32 index, nsISupportsArray *properties)
00212 {
00213   return NS_OK;
00214 }
00215 
00216 /* void getCellProperties (in long row, in nsITreeColumn col,
00217                            in nsISupportsArray properties); */
00218 NS_IMETHODIMP 
00219 nsNSSASN1Tree::GetCellProperties(PRInt32 row, nsITreeColumn* col, 
00220                                  nsISupportsArray *properties)
00221 {
00222   return NS_OK;
00223 }
00224 
00225 /* void getColumnProperties (in nsITreeColumn col,
00226                              in nsISupportsArray properties); */
00227 NS_IMETHODIMP 
00228 nsNSSASN1Tree::GetColumnProperties(nsITreeColumn* col, 
00229                                    nsISupportsArray *properties)
00230 {
00231   return NS_OK;
00232 }
00233 
00234 /* boolean isContainer (in long index); */
00235 NS_IMETHODIMP 
00236 nsNSSASN1Tree::IsContainer(PRInt32 index, PRBool *_retval)
00237 {
00238   myNode *n = FindNodeFromIndex(index);
00239   if (!n)
00240     return NS_ERROR_FAILURE;
00241 
00242   *_retval = (n->seq != nsnull);
00243   return NS_OK; 
00244 }
00245 
00246 /* boolean isContainerOpen (in long index); */
00247 NS_IMETHODIMP 
00248 nsNSSASN1Tree::IsContainerOpen(PRInt32 index, PRBool *_retval)
00249 {
00250   myNode *n = FindNodeFromIndex(index);
00251   if (!n || !n->seq)
00252     return NS_ERROR_FAILURE;
00253 
00254   n->seq->GetIsExpanded(_retval);
00255   return NS_OK;
00256 }
00257 
00258 /* boolean isContainerEmpty (in long index); */
00259 NS_IMETHODIMP 
00260 nsNSSASN1Tree::IsContainerEmpty(PRInt32 index, PRBool *_retval)
00261 {
00262   *_retval = PR_FALSE;
00263   return NS_OK;
00264 }
00265 
00266 /* boolean isSeparator (in long index); */
00267 NS_IMETHODIMP 
00268 nsNSSASN1Tree::IsSeparator(PRInt32 index, PRBool *_retval)
00269 {
00270   *_retval = PR_FALSE;
00271   return NS_OK; 
00272 }
00273 
00274 /* long getLevel (in long index); */
00275 NS_IMETHODIMP 
00276 nsNSSASN1Tree::GetLevel(PRInt32 index, PRInt32 *_retval)
00277 {
00278   PRInt32 parentIndex;
00279   PRInt32 nodeLevel;
00280 
00281   myNode *n = FindNodeFromIndex(index, &parentIndex, &nodeLevel);
00282   if (!n)
00283     return NS_ERROR_FAILURE;
00284 
00285   *_retval = nodeLevel;
00286   return NS_OK; 
00287 }
00288 
00289 /* Astring getImageSrc (in long row, in nsITreeColumn col); */
00290 NS_IMETHODIMP 
00291 nsNSSASN1Tree::GetImageSrc(PRInt32 row, nsITreeColumn* col, 
00292                            nsAString& _retval)
00293 {
00294   return NS_OK;
00295 }
00296 
00297 /* long getProgressMode (in long row, in nsITreeColumn col); */
00298 NS_IMETHODIMP 
00299 nsNSSASN1Tree::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval)
00300 {
00301   return NS_OK;
00302 }
00303 
00304 /* Astring getCellValue (in long row, in nsITreeColumn col); */
00305 NS_IMETHODIMP 
00306 nsNSSASN1Tree::GetCellValue(PRInt32 row, nsITreeColumn* col, 
00307                             nsAString& _retval)
00308 {
00309   return NS_OK;
00310 }
00311 
00312 /* Astring getCellText (in long row, in nsITreeColumn col); */
00313 NS_IMETHODIMP 
00314 nsNSSASN1Tree::GetCellText(PRInt32 row, nsITreeColumn* col, 
00315                            nsAString& _retval)
00316 {
00317   _retval.Truncate();
00318 
00319   myNode* n = FindNodeFromIndex(row);
00320   if (!n)
00321     return NS_ERROR_FAILURE;
00322 
00323   // There's only one column for ASN1 dump.
00324   return n->obj->GetDisplayName(_retval);
00325 }
00326 
00327 /* wstring getDisplayData (in unsigned long index); */
00328 NS_IMETHODIMP 
00329 nsNSSASN1Tree::GetDisplayData(PRUint32 index, nsAString &_retval)
00330 {
00331   myNode *n = FindNodeFromIndex(index);
00332   if (!n)
00333     return NS_ERROR_FAILURE;
00334 
00335   n->obj->GetDisplayValue(_retval);
00336   return NS_OK;
00337 }
00338 
00339 /* void setTree (in nsITreeBoxObject tree); */
00340 NS_IMETHODIMP 
00341 nsNSSASN1Tree::SetTree(nsITreeBoxObject *tree)
00342 {
00343   mTree = tree;
00344   return NS_OK;
00345 }
00346 
00347 /* void toggleOpenState (in long index); */
00348 NS_IMETHODIMP 
00349 nsNSSASN1Tree::ToggleOpenState(PRInt32 index)
00350 {
00351   myNode *n = FindNodeFromIndex(index);
00352   if (!n)
00353     return NS_ERROR_FAILURE;
00354 
00355   if (!n->seq)
00356     return NS_ERROR_FAILURE;
00357 
00358   PRBool IsExpanded;
00359   n->seq->GetIsExpanded(&IsExpanded);
00360   PRInt32 rowCountChange;
00361   if (IsExpanded) {
00362     rowCountChange = -CountVisibleNodes(n->child);
00363     n->seq->SetIsExpanded(PR_FALSE);
00364   } else {
00365     n->seq->SetIsExpanded(PR_TRUE);
00366     rowCountChange = CountVisibleNodes(n->child);
00367   }
00368   if (mTree)
00369     mTree->RowCountChanged(index, rowCountChange);
00370   return NS_OK;
00371 }
00372 
00373 /* void cycleHeader (in nsITreeColumn col); */
00374 NS_IMETHODIMP 
00375 nsNSSASN1Tree::CycleHeader(nsITreeColumn* col)
00376 {
00377   return NS_OK;
00378 }
00379 
00380 /* void selectionChanged (); */
00381 NS_IMETHODIMP 
00382 nsNSSASN1Tree::SelectionChanged()
00383 {
00384   return NS_ERROR_NOT_IMPLEMENTED;
00385 }
00386 
00387 /* void cycleCell (in long row, in nsITreeColumn col); */
00388 NS_IMETHODIMP 
00389 nsNSSASN1Tree::CycleCell(PRInt32 row, nsITreeColumn* col)
00390 {
00391   return NS_OK;
00392 }
00393 
00394 /* boolean isEditable (in long row, in nsITreeColumn col); */
00395 NS_IMETHODIMP 
00396 nsNSSASN1Tree::IsEditable(PRInt32 row, nsITreeColumn* col, 
00397                           PRBool *_retval)
00398 {
00399   *_retval = PR_FALSE;
00400   return NS_OK;
00401 }
00402 
00403 /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */
00404 NS_IMETHODIMP 
00405 nsNSSASN1Tree::SetCellValue(PRInt32 row, nsITreeColumn* col, 
00406                             const nsAString& value)
00407 {
00408   return NS_OK;
00409 }
00410 
00411 /* void setCellText (in long row, in nsITreeColumn col, in AString value); */
00412 NS_IMETHODIMP 
00413 nsNSSASN1Tree::SetCellText(PRInt32 row, nsITreeColumn* col, 
00414                            const nsAString& value)
00415 {
00416   return NS_OK;
00417 }
00418 
00419 /* void performAction (in wstring action); */
00420 NS_IMETHODIMP 
00421 nsNSSASN1Tree::PerformAction(const PRUnichar *action)
00422 {
00423   return NS_OK;
00424 }
00425 
00426 /* void performActionOnRow (in wstring action, in long row); */
00427 NS_IMETHODIMP 
00428 nsNSSASN1Tree::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
00429 {
00430   return NS_OK;
00431 }
00432 
00433 /* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */
00434 NS_IMETHODIMP 
00435 nsNSSASN1Tree::PerformActionOnCell(const PRUnichar *action, PRInt32 row, 
00436                                    nsITreeColumn* col)
00437 {
00438   return NS_OK;
00439 }
00440 
00441 //
00442 // CanDrop
00443 //
00444 NS_IMETHODIMP nsNSSASN1Tree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval)
00445 {
00446   NS_ENSURE_ARG_POINTER(_retval);
00447   *_retval = PR_FALSE;
00448   
00449   return NS_OK;
00450 }
00451 
00452 
00453 //
00454 // Drop
00455 //
00456 NS_IMETHODIMP nsNSSASN1Tree::Drop(PRInt32 row, PRInt32 orient)
00457 {
00458   return NS_OK;
00459 }
00460 
00461 
00462 //
00463 // IsSorted
00464 //
00465 // ...
00466 //
00467 NS_IMETHODIMP nsNSSASN1Tree::IsSorted(PRBool *_retval)
00468 {
00469   *_retval = PR_FALSE;
00470   return NS_OK;
00471 }
00472 
00473 
00474 /* long getParentIndex (in long rowIndex); */
00475 NS_IMETHODIMP 
00476 nsNSSASN1Tree::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval)
00477 {
00478   PRInt32 parentIndex = -1;
00479 
00480   myNode *n = FindNodeFromIndex(rowIndex, &parentIndex);
00481   if (!n)
00482     return NS_ERROR_FAILURE;
00483 
00484   *_retval = parentIndex;
00485   return NS_OK; 
00486 }
00487 
00488 /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */
00489 NS_IMETHODIMP 
00490 nsNSSASN1Tree::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, 
00491                               PRBool *_retval)
00492 {
00493   myNode *n = FindNodeFromIndex(rowIndex);
00494   if (!n)
00495     return NS_ERROR_FAILURE;
00496 
00497   if (!n->next) {
00498     *_retval = PR_FALSE;
00499   }
00500   else {
00501     PRInt32 nTotalSize = CountVisibleNodes(n);
00502     PRInt32 nLastChildPos = rowIndex + nTotalSize -1;
00503     PRInt32 nextSiblingPos = nLastChildPos +1;
00504     *_retval = (nextSiblingPos > afterIndex);
00505   }
00506 
00507   return NS_OK; 
00508 }
00509 
00510 PRInt32 nsNSSASN1Tree::CountVisibleNodes(myNode *n)
00511 {
00512   if (!n)
00513     return 0;
00514 
00515   myNode *walk = n;
00516   PRInt32 count = 0;
00517   
00518   while (walk) {
00519     ++count;
00520 
00521     if (walk->seq) {
00522       PRBool IsExpanded;
00523       walk->seq->GetIsExpanded(&IsExpanded);
00524       if (IsExpanded) {
00525         count += CountVisibleNodes(walk->child);
00526       }
00527     }
00528 
00529     walk = walk->next;
00530   }
00531 
00532   return count;
00533 }
00534 
00535 // Entry point for find
00536 nsNSSASN1Tree::myNode *
00537 nsNSSASN1Tree::FindNodeFromIndex(PRInt32 wantedIndex, 
00538                                  PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel)
00539 {
00540   if (0 == wantedIndex) {
00541     if (optionalOutLevel) {
00542       *optionalOutLevel = 0;
00543     }
00544     if (optionalOutParentIndex) {
00545       *optionalOutParentIndex = -1;
00546     }
00547     return mTopNode;
00548   }
00549   else {
00550     PRInt32 index = 0;
00551     PRInt32 level = 0;
00552     return FindNodeFromIndex(mTopNode, wantedIndex, index, level, 
00553                              optionalOutParentIndex, optionalOutLevel);
00554   }
00555 }
00556 
00557 // Internal recursive helper function
00558 nsNSSASN1Tree::myNode *
00559 nsNSSASN1Tree::FindNodeFromIndex(myNode *n, PRInt32 wantedIndex,
00560                                  PRInt32 &index_counter, PRInt32 &level_counter,
00561                                  PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel)
00562 {
00563   if (!n)
00564     return nsnull;
00565 
00566   myNode *walk = n;
00567   PRInt32 parentIndex = index_counter-1;
00568   
00569   while (walk) {
00570     if (index_counter == wantedIndex) {
00571       if (optionalOutLevel) {
00572         *optionalOutLevel = level_counter;
00573       }
00574       if (optionalOutParentIndex) {
00575         *optionalOutParentIndex = parentIndex;
00576       }
00577       return walk;
00578     }
00579 
00580     if (walk->seq) {
00581       PRBool IsExpanded;
00582       walk->seq->GetIsExpanded(&IsExpanded);
00583       if (IsExpanded) {
00584         ++index_counter; // set to walk->child
00585 
00586         ++level_counter;
00587         myNode *found = FindNodeFromIndex(walk->child, wantedIndex, index_counter, level_counter,
00588                                           optionalOutParentIndex, optionalOutLevel);
00589         --level_counter;
00590 
00591         if (found)
00592           return found;
00593       }
00594     }
00595 
00596     walk = walk->next;
00597     if (walk) {
00598       ++index_counter;
00599     }
00600   }
00601 
00602   return nsnull;
00603 }
00604