michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nsASN1Tree.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsString.h" michael@0: #include "nsCRT.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsArrayUtils.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNSSASN1Tree, nsIASN1Tree, nsITreeView) michael@0: michael@0: nsNSSASN1Tree::nsNSSASN1Tree() michael@0: :mTopNode(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsNSSASN1Tree::~nsNSSASN1Tree() michael@0: { michael@0: ClearNodes(); michael@0: } michael@0: michael@0: void nsNSSASN1Tree::ClearNodesRecursively(myNode *n) michael@0: { michael@0: myNode *walk = n; michael@0: while (walk) { michael@0: myNode *kill = walk; michael@0: michael@0: if (walk->child) { michael@0: ClearNodesRecursively(walk->child); michael@0: } michael@0: michael@0: walk = walk->next; michael@0: delete kill; michael@0: } michael@0: } michael@0: michael@0: void nsNSSASN1Tree::ClearNodes() michael@0: { michael@0: ClearNodesRecursively(mTopNode); michael@0: mTopNode = nullptr; michael@0: } michael@0: michael@0: void nsNSSASN1Tree::InitChildsRecursively(myNode *n) michael@0: { michael@0: if (!n->obj) michael@0: return; michael@0: michael@0: n->seq = do_QueryInterface(n->obj); michael@0: if (!n->seq) michael@0: return; michael@0: michael@0: // If the object is a sequence, there might still be a reason michael@0: // why it should not be displayed as a container. michael@0: // If we decide that it has all the properties to justify michael@0: // displaying as a container, we will create a new child chain. michael@0: // If we decide, it does not make sense to display as a container, michael@0: // we forget that it is a sequence by erasing n->seq. michael@0: // That way, n->seq and n->child will be either both set or both null. michael@0: michael@0: bool isContainer; michael@0: n->seq->GetIsValidContainer(&isContainer); michael@0: if (!isContainer) { michael@0: n->seq = nullptr; michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr asn1Objects; michael@0: n->seq->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: uint32_t numObjects; michael@0: asn1Objects->GetLength(&numObjects); michael@0: michael@0: if (!numObjects) { michael@0: n->seq = nullptr; michael@0: return; michael@0: } michael@0: michael@0: myNode *walk = nullptr; michael@0: myNode *prev = nullptr; michael@0: michael@0: uint32_t i; michael@0: nsCOMPtr isupports; michael@0: for (i=0; ichild = walk = new myNode; michael@0: } michael@0: else { michael@0: walk = new myNode; michael@0: } michael@0: michael@0: walk->parent = n; michael@0: if (prev) { michael@0: prev->next = walk; michael@0: } michael@0: michael@0: walk->obj = do_QueryElementAt(asn1Objects, i); michael@0: michael@0: InitChildsRecursively(walk); michael@0: michael@0: prev = walk; michael@0: } michael@0: } michael@0: michael@0: void nsNSSASN1Tree::InitNodes() michael@0: { michael@0: ClearNodes(); michael@0: michael@0: mTopNode = new myNode; michael@0: mTopNode->obj = mASN1Object; michael@0: michael@0: InitChildsRecursively(mTopNode); michael@0: } michael@0: michael@0: /* void loadASN1Structure (in nsIASN1Object asn1Object); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object *asn1Object) michael@0: { michael@0: // michael@0: // The tree won't automatically re-draw if the contents michael@0: // have been changed. So I do a quick test here to let michael@0: // me know if I should forced the tree to redraw itself michael@0: // by calling RowCountChanged on it. michael@0: // michael@0: bool redraw = (mASN1Object && mTree); michael@0: int32_t rowsToDelete = 0; michael@0: michael@0: if (redraw) { michael@0: // This is the number of rows we will be deleting after michael@0: // the contents have changed. michael@0: rowsToDelete = 0-CountVisibleNodes(mTopNode); michael@0: } michael@0: michael@0: mASN1Object = asn1Object; michael@0: InitNodes(); michael@0: michael@0: if (redraw) { michael@0: // The number of rows in the new content. michael@0: int32_t newRows = CountVisibleNodes(mTopNode); michael@0: mTree->BeginUpdateBatch(); michael@0: // Erase all of the old rows. michael@0: mTree->RowCountChanged(0, rowsToDelete); michael@0: // Replace them with the new contents michael@0: mTree->RowCountChanged(0, newRows); michael@0: mTree->EndUpdateBatch(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute long rowCount; */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetRowCount(int32_t *aRowCount) michael@0: { michael@0: if (mASN1Object) { michael@0: *aRowCount = CountVisibleNodes(mTopNode); michael@0: } else { michael@0: *aRowCount = 0; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute nsITreeSelection selection; */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetSelection(nsITreeSelection * *aSelection) michael@0: { michael@0: *aSelection = mSelection; michael@0: NS_IF_ADDREF(*aSelection); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::SetSelection(nsITreeSelection * aSelection) michael@0: { michael@0: mSelection = aSelection; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetRowProperties(int32_t index, nsAString& aProps) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetCellProperties(int32_t row, nsITreeColumn* col, michael@0: nsAString& aProps) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetColumnProperties(nsITreeColumn* col, nsAString& aProps) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isContainer (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsContainer(int32_t index, bool *_retval) michael@0: { michael@0: myNode *n = FindNodeFromIndex(index); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_retval = (n->seq != nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isContainerOpen (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsContainerOpen(int32_t index, bool *_retval) michael@0: { michael@0: myNode *n = FindNodeFromIndex(index); michael@0: if (!n || !n->seq) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: n->seq->GetIsExpanded(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isContainerEmpty (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsContainerEmpty(int32_t index, bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isSeparator (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsSeparator(int32_t index, bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getLevel (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetLevel(int32_t index, int32_t *_retval) michael@0: { michael@0: int32_t parentIndex; michael@0: int32_t nodeLevel; michael@0: michael@0: myNode *n = FindNodeFromIndex(index, &parentIndex, &nodeLevel); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_retval = nodeLevel; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getImageSrc (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetImageSrc(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getProgressMode (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getCellValue (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetCellValue(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* Astring getCellText (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetCellText(int32_t row, nsITreeColumn* col, michael@0: nsAString& _retval) michael@0: { michael@0: _retval.Truncate(); michael@0: michael@0: myNode* n = FindNodeFromIndex(row); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // There's only one column for ASN1 dump. michael@0: return n->obj->GetDisplayName(_retval); michael@0: } michael@0: michael@0: /* wstring getDisplayData (in unsigned long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetDisplayData(uint32_t index, nsAString &_retval) michael@0: { michael@0: myNode *n = FindNodeFromIndex(index); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: n->obj->GetDisplayValue(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setTree (in nsITreeBoxObject tree); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::SetTree(nsITreeBoxObject *tree) michael@0: { michael@0: mTree = tree; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void toggleOpenState (in long index); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::ToggleOpenState(int32_t index) michael@0: { michael@0: myNode *n = FindNodeFromIndex(index); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!n->seq) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: bool IsExpanded; michael@0: n->seq->GetIsExpanded(&IsExpanded); michael@0: int32_t rowCountChange; michael@0: if (IsExpanded) { michael@0: rowCountChange = -CountVisibleNodes(n->child); michael@0: n->seq->SetIsExpanded(false); michael@0: } else { michael@0: n->seq->SetIsExpanded(true); michael@0: rowCountChange = CountVisibleNodes(n->child); michael@0: } michael@0: if (mTree) michael@0: mTree->RowCountChanged(index, rowCountChange); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void cycleHeader (in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::CycleHeader(nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void selectionChanged (); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::SelectionChanged() michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: /* void cycleCell (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::CycleCell(int32_t row, nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isEditable (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsEditable(int32_t row, nsITreeColumn* col, michael@0: bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isSelectable (in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::IsSelectable(int32_t row, nsITreeColumn* col, michael@0: bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::SetCellValue(int32_t row, nsITreeColumn* col, michael@0: const nsAString& value) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setCellText (in long row, in nsITreeColumn col, in AString value); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::SetCellText(int32_t row, nsITreeColumn* col, michael@0: const nsAString& value) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performAction (in wstring action); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::PerformAction(const char16_t *action) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performActionOnRow (in wstring action, in long row); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::PerformActionOnRow(const char16_t *action, int32_t row) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::PerformActionOnCell(const char16_t *action, int32_t row, michael@0: nsITreeColumn* col) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // CanDrop michael@0: // michael@0: NS_IMETHODIMP nsNSSASN1Tree::CanDrop(int32_t index, int32_t orientation, michael@0: nsIDOMDataTransfer* aDataTransfer, bool *_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(_retval); michael@0: *_retval = false; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // Drop michael@0: // michael@0: NS_IMETHODIMP nsNSSASN1Tree::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* aDataTransfer) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: // michael@0: // IsSorted michael@0: // michael@0: // ... michael@0: // michael@0: NS_IMETHODIMP nsNSSASN1Tree::IsSorted(bool *_retval) michael@0: { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /* long getParentIndex (in long rowIndex); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::GetParentIndex(int32_t rowIndex, int32_t *_retval) michael@0: { michael@0: int32_t parentIndex = -1; michael@0: michael@0: myNode *n = FindNodeFromIndex(rowIndex, &parentIndex); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: *_retval = parentIndex; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ michael@0: NS_IMETHODIMP michael@0: nsNSSASN1Tree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, michael@0: bool *_retval) michael@0: { michael@0: myNode *n = FindNodeFromIndex(rowIndex); michael@0: if (!n) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!n->next) { michael@0: *_retval = false; michael@0: } michael@0: else { michael@0: int32_t nTotalSize = CountVisibleNodes(n); michael@0: int32_t nLastChildPos = rowIndex + nTotalSize -1; michael@0: int32_t nextSiblingPos = nLastChildPos +1; michael@0: *_retval = (nextSiblingPos > afterIndex); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: int32_t nsNSSASN1Tree::CountVisibleNodes(myNode *n) michael@0: { michael@0: if (!n) michael@0: return 0; michael@0: michael@0: myNode *walk = n; michael@0: int32_t count = 0; michael@0: michael@0: while (walk) { michael@0: ++count; michael@0: michael@0: if (walk->seq) { michael@0: bool IsExpanded; michael@0: walk->seq->GetIsExpanded(&IsExpanded); michael@0: if (IsExpanded) { michael@0: count += CountVisibleNodes(walk->child); michael@0: } michael@0: } michael@0: michael@0: walk = walk->next; michael@0: } michael@0: michael@0: return count; michael@0: } michael@0: michael@0: // Entry point for find michael@0: nsNSSASN1Tree::myNode * michael@0: nsNSSASN1Tree::FindNodeFromIndex(int32_t wantedIndex, michael@0: int32_t *optionalOutParentIndex, int32_t *optionalOutLevel) michael@0: { michael@0: if (0 == wantedIndex) { michael@0: if (optionalOutLevel) { michael@0: *optionalOutLevel = 0; michael@0: } michael@0: if (optionalOutParentIndex) { michael@0: *optionalOutParentIndex = -1; michael@0: } michael@0: return mTopNode; michael@0: } michael@0: else { michael@0: int32_t index = 0; michael@0: int32_t level = 0; michael@0: return FindNodeFromIndex(mTopNode, wantedIndex, index, level, michael@0: optionalOutParentIndex, optionalOutLevel); michael@0: } michael@0: } michael@0: michael@0: // Internal recursive helper function michael@0: nsNSSASN1Tree::myNode * michael@0: nsNSSASN1Tree::FindNodeFromIndex(myNode *n, int32_t wantedIndex, michael@0: int32_t &index_counter, int32_t &level_counter, michael@0: int32_t *optionalOutParentIndex, int32_t *optionalOutLevel) michael@0: { michael@0: if (!n) michael@0: return nullptr; michael@0: michael@0: myNode *walk = n; michael@0: int32_t parentIndex = index_counter-1; michael@0: michael@0: while (walk) { michael@0: if (index_counter == wantedIndex) { michael@0: if (optionalOutLevel) { michael@0: *optionalOutLevel = level_counter; michael@0: } michael@0: if (optionalOutParentIndex) { michael@0: *optionalOutParentIndex = parentIndex; michael@0: } michael@0: return walk; michael@0: } michael@0: michael@0: if (walk->seq) { michael@0: bool IsExpanded; michael@0: walk->seq->GetIsExpanded(&IsExpanded); michael@0: if (IsExpanded) { michael@0: ++index_counter; // set to walk->child michael@0: michael@0: ++level_counter; michael@0: myNode *found = FindNodeFromIndex(walk->child, wantedIndex, index_counter, level_counter, michael@0: optionalOutParentIndex, optionalOutLevel); michael@0: --level_counter; michael@0: michael@0: if (found) michael@0: return found; michael@0: } michael@0: } michael@0: michael@0: walk = walk->next; michael@0: if (walk) { michael@0: ++index_counter; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: