/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Javier Delgadillo * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsASN1Tree.h" #include "nsIComponentManager.h" #include "nsString.h" #include "nsCRT.h" #include "nsArray.h" NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSASN1Tree, nsIASN1Tree, nsITreeView) nsNSSASN1Tree::nsNSSASN1Tree() :mTopNode(nsnull) { } nsNSSASN1Tree::~nsNSSASN1Tree() { ClearNodes(); } void nsNSSASN1Tree::ClearNodesRecursively(myNode *n) { myNode *walk = n; while (walk) { myNode *kill = walk; if (walk->child) { ClearNodesRecursively(walk->child); } walk = walk->next; delete kill; } } void nsNSSASN1Tree::ClearNodes() { ClearNodesRecursively(mTopNode); mTopNode = nsnull; } void nsNSSASN1Tree::InitChildsRecursively(myNode *n) { if (!n->obj) return; n->seq = do_QueryInterface(n->obj); if (!n->seq) return; // If the object is a sequence, there might still be a reason // why it should not be displayed as a container. // If we decide that it has all the properties to justify // displaying as a container, we will create a new child chain. // If we decide, it does not make sense to display as a container, // we forget that it is a sequence by erasing n->seq. // That way, n->seq and n->child will be either both set or both null. PRBool isContainer; n->seq->GetIsValidContainer(&isContainer); if (!isContainer) { n->seq = nsnull; return; } nsCOMPtr asn1Objects; n->seq->GetASN1Objects(getter_AddRefs(asn1Objects)); PRUint32 numObjects; asn1Objects->GetLength(&numObjects); if (!numObjects) { n->seq = nsnull; return; } myNode *walk = nsnull; myNode *prev = nsnull; PRUint32 i; nsCOMPtr isupports; for (i=0; ichild = walk = new myNode; } else { walk = new myNode; } walk->parent = n; if (prev) { prev->next = walk; } walk->obj = do_QueryElementAt(asn1Objects, i); InitChildsRecursively(walk); prev = walk; } } void nsNSSASN1Tree::InitNodes() { ClearNodes(); mTopNode = new myNode; mTopNode->obj = mASN1Object; InitChildsRecursively(mTopNode); } /* void loadASN1Structure (in nsIASN1Object asn1Object); */ NS_IMETHODIMP nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object *asn1Object) { // // The tree won't automatically re-draw if the contents // have been changed. So I do a quick test here to let // me know if I should forced the tree to redraw itself // by calling RowCountChanged on it. // PRBool redraw = (mASN1Object && mTree); PRInt32 rowsToDelete = 0; if (redraw) { // This is the number of rows we will be deleting after // the contents have changed. rowsToDelete = 0-CountVisibleNodes(mTopNode); } mASN1Object = asn1Object; InitNodes(); if (redraw) { // The number of rows in the new content. PRInt32 newRows = CountVisibleNodes(mTopNode); // Erase all of the old rows. mTree->RowCountChanged(0, rowsToDelete); // Replace them with the new contents mTree->RowCountChanged(0, newRows); } return NS_OK; } /* readonly attribute long rowCount; */ NS_IMETHODIMP nsNSSASN1Tree::GetRowCount(PRInt32 *aRowCount) { if (mASN1Object) { *aRowCount = CountVisibleNodes(mTopNode); } else { *aRowCount = 0; } return NS_OK; } /* attribute nsITreeSelection selection; */ NS_IMETHODIMP nsNSSASN1Tree::GetSelection(nsITreeSelection * *aSelection) { *aSelection = mSelection; NS_IF_ADDREF(*aSelection); return NS_OK; } NS_IMETHODIMP nsNSSASN1Tree::SetSelection(nsITreeSelection * aSelection) { mSelection = aSelection; return NS_OK; } /* void getRowProperties (in long index, in nsISupportsArray properties); */ NS_IMETHODIMP nsNSSASN1Tree::GetRowProperties(PRInt32 index, nsISupportsArray *properties) { return NS_OK; } /* void getCellProperties (in long row, in nsITreeColumn col, in nsISupportsArray properties); */ NS_IMETHODIMP nsNSSASN1Tree::GetCellProperties(PRInt32 row, nsITreeColumn* col, nsISupportsArray *properties) { return NS_OK; } /* void getColumnProperties (in nsITreeColumn col, in nsISupportsArray properties); */ NS_IMETHODIMP nsNSSASN1Tree::GetColumnProperties(nsITreeColumn* col, nsISupportsArray *properties) { return NS_OK; } /* boolean isContainer (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::IsContainer(PRInt32 index, PRBool *_retval) { myNode *n = FindNodeFromIndex(index); if (!n) return NS_ERROR_FAILURE; *_retval = (n->seq != nsnull); return NS_OK; } /* boolean isContainerOpen (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::IsContainerOpen(PRInt32 index, PRBool *_retval) { myNode *n = FindNodeFromIndex(index); if (!n || !n->seq) return NS_ERROR_FAILURE; n->seq->GetIsExpanded(_retval); return NS_OK; } /* boolean isContainerEmpty (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::IsContainerEmpty(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } /* boolean isSeparator (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::IsSeparator(PRInt32 index, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } /* long getLevel (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::GetLevel(PRInt32 index, PRInt32 *_retval) { PRInt32 parentIndex; PRInt32 nodeLevel; myNode *n = FindNodeFromIndex(index, &parentIndex, &nodeLevel); if (!n) return NS_ERROR_FAILURE; *_retval = nodeLevel; return NS_OK; } /* Astring getImageSrc (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::GetImageSrc(PRInt32 row, nsITreeColumn* col, nsAString& _retval) { return NS_OK; } /* long getProgressMode (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::GetProgressMode(PRInt32 row, nsITreeColumn* col, PRInt32* _retval) { return NS_OK; } /* Astring getCellValue (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::GetCellValue(PRInt32 row, nsITreeColumn* col, nsAString& _retval) { return NS_OK; } /* Astring getCellText (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::GetCellText(PRInt32 row, nsITreeColumn* col, nsAString& _retval) { _retval.Truncate(); myNode* n = FindNodeFromIndex(row); if (!n) return NS_ERROR_FAILURE; // There's only one column for ASN1 dump. return n->obj->GetDisplayName(_retval); } /* wstring getDisplayData (in unsigned long index); */ NS_IMETHODIMP nsNSSASN1Tree::GetDisplayData(PRUint32 index, nsAString &_retval) { myNode *n = FindNodeFromIndex(index); if (!n) return NS_ERROR_FAILURE; n->obj->GetDisplayValue(_retval); return NS_OK; } /* void setTree (in nsITreeBoxObject tree); */ NS_IMETHODIMP nsNSSASN1Tree::SetTree(nsITreeBoxObject *tree) { mTree = tree; return NS_OK; } /* void toggleOpenState (in long index); */ NS_IMETHODIMP nsNSSASN1Tree::ToggleOpenState(PRInt32 index) { myNode *n = FindNodeFromIndex(index); if (!n) return NS_ERROR_FAILURE; if (!n->seq) return NS_ERROR_FAILURE; PRBool IsExpanded; n->seq->GetIsExpanded(&IsExpanded); PRInt32 rowCountChange; if (IsExpanded) { rowCountChange = -CountVisibleNodes(n->child); n->seq->SetIsExpanded(PR_FALSE); } else { n->seq->SetIsExpanded(PR_TRUE); rowCountChange = CountVisibleNodes(n->child); } if (mTree) mTree->RowCountChanged(index, rowCountChange); return NS_OK; } /* void cycleHeader (in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::CycleHeader(nsITreeColumn* col) { return NS_OK; } /* void selectionChanged (); */ NS_IMETHODIMP nsNSSASN1Tree::SelectionChanged() { return NS_ERROR_NOT_IMPLEMENTED; } /* void cycleCell (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::CycleCell(PRInt32 row, nsITreeColumn* col) { return NS_OK; } /* boolean isEditable (in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::IsEditable(PRInt32 row, nsITreeColumn* col, PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */ NS_IMETHODIMP nsNSSASN1Tree::SetCellValue(PRInt32 row, nsITreeColumn* col, const nsAString& value) { return NS_OK; } /* void setCellText (in long row, in nsITreeColumn col, in AString value); */ NS_IMETHODIMP nsNSSASN1Tree::SetCellText(PRInt32 row, nsITreeColumn* col, const nsAString& value) { return NS_OK; } /* void performAction (in wstring action); */ NS_IMETHODIMP nsNSSASN1Tree::PerformAction(const PRUnichar *action) { return NS_OK; } /* void performActionOnRow (in wstring action, in long row); */ NS_IMETHODIMP nsNSSASN1Tree::PerformActionOnRow(const PRUnichar *action, PRInt32 row) { return NS_OK; } /* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */ NS_IMETHODIMP nsNSSASN1Tree::PerformActionOnCell(const PRUnichar *action, PRInt32 row, nsITreeColumn* col) { return NS_OK; } // // CanDrop // NS_IMETHODIMP nsNSSASN1Tree::CanDrop(PRInt32 index, PRInt32 orientation, PRBool *_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = PR_FALSE; return NS_OK; } // // Drop // NS_IMETHODIMP nsNSSASN1Tree::Drop(PRInt32 row, PRInt32 orient) { return NS_OK; } // // IsSorted // // ... // NS_IMETHODIMP nsNSSASN1Tree::IsSorted(PRBool *_retval) { *_retval = PR_FALSE; return NS_OK; } /* long getParentIndex (in long rowIndex); */ NS_IMETHODIMP nsNSSASN1Tree::GetParentIndex(PRInt32 rowIndex, PRInt32 *_retval) { PRInt32 parentIndex = -1; myNode *n = FindNodeFromIndex(rowIndex, &parentIndex); if (!n) return NS_ERROR_FAILURE; *_retval = parentIndex; return NS_OK; } /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ NS_IMETHODIMP nsNSSASN1Tree::HasNextSibling(PRInt32 rowIndex, PRInt32 afterIndex, PRBool *_retval) { myNode *n = FindNodeFromIndex(rowIndex); if (!n) return NS_ERROR_FAILURE; if (!n->next) { *_retval = PR_FALSE; } else { PRInt32 nTotalSize = CountVisibleNodes(n); PRInt32 nLastChildPos = rowIndex + nTotalSize -1; PRInt32 nextSiblingPos = nLastChildPos +1; *_retval = (nextSiblingPos > afterIndex); } return NS_OK; } PRInt32 nsNSSASN1Tree::CountVisibleNodes(myNode *n) { if (!n) return 0; myNode *walk = n; PRInt32 count = 0; while (walk) { ++count; if (walk->seq) { PRBool IsExpanded; walk->seq->GetIsExpanded(&IsExpanded); if (IsExpanded) { count += CountVisibleNodes(walk->child); } } walk = walk->next; } return count; } // Entry point for find nsNSSASN1Tree::myNode * nsNSSASN1Tree::FindNodeFromIndex(PRInt32 wantedIndex, PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel) { if (0 == wantedIndex) { if (optionalOutLevel) { *optionalOutLevel = 0; } if (optionalOutParentIndex) { *optionalOutParentIndex = -1; } return mTopNode; } else { PRInt32 index = 0; PRInt32 level = 0; return FindNodeFromIndex(mTopNode, wantedIndex, index, level, optionalOutParentIndex, optionalOutLevel); } } // Internal recursive helper function nsNSSASN1Tree::myNode * nsNSSASN1Tree::FindNodeFromIndex(myNode *n, PRInt32 wantedIndex, PRInt32 &index_counter, PRInt32 &level_counter, PRInt32 *optionalOutParentIndex, PRInt32 *optionalOutLevel) { if (!n) return nsnull; myNode *walk = n; PRInt32 parentIndex = index_counter-1; while (walk) { if (index_counter == wantedIndex) { if (optionalOutLevel) { *optionalOutLevel = level_counter; } if (optionalOutParentIndex) { *optionalOutParentIndex = parentIndex; } return walk; } if (walk->seq) { PRBool IsExpanded; walk->seq->GetIsExpanded(&IsExpanded); if (IsExpanded) { ++index_counter; // set to walk->child ++level_counter; myNode *found = FindNodeFromIndex(walk->child, wantedIndex, index_counter, level_counter, optionalOutParentIndex, optionalOutLevel); --level_counter; if (found) return found; } } walk = walk->next; if (walk) { ++index_counter; } } return nsnull; }