|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 #include "nsASN1Tree.h" |
|
5 #include "nsIComponentManager.h" |
|
6 #include "nsString.h" |
|
7 #include "nsCRT.h" |
|
8 #include "nsIMutableArray.h" |
|
9 #include "nsArrayUtils.h" |
|
10 |
|
11 NS_IMPL_ISUPPORTS(nsNSSASN1Tree, nsIASN1Tree, nsITreeView) |
|
12 |
|
13 nsNSSASN1Tree::nsNSSASN1Tree() |
|
14 :mTopNode(nullptr) |
|
15 { |
|
16 } |
|
17 |
|
18 nsNSSASN1Tree::~nsNSSASN1Tree() |
|
19 { |
|
20 ClearNodes(); |
|
21 } |
|
22 |
|
23 void nsNSSASN1Tree::ClearNodesRecursively(myNode *n) |
|
24 { |
|
25 myNode *walk = n; |
|
26 while (walk) { |
|
27 myNode *kill = walk; |
|
28 |
|
29 if (walk->child) { |
|
30 ClearNodesRecursively(walk->child); |
|
31 } |
|
32 |
|
33 walk = walk->next; |
|
34 delete kill; |
|
35 } |
|
36 } |
|
37 |
|
38 void nsNSSASN1Tree::ClearNodes() |
|
39 { |
|
40 ClearNodesRecursively(mTopNode); |
|
41 mTopNode = nullptr; |
|
42 } |
|
43 |
|
44 void nsNSSASN1Tree::InitChildsRecursively(myNode *n) |
|
45 { |
|
46 if (!n->obj) |
|
47 return; |
|
48 |
|
49 n->seq = do_QueryInterface(n->obj); |
|
50 if (!n->seq) |
|
51 return; |
|
52 |
|
53 // If the object is a sequence, there might still be a reason |
|
54 // why it should not be displayed as a container. |
|
55 // If we decide that it has all the properties to justify |
|
56 // displaying as a container, we will create a new child chain. |
|
57 // If we decide, it does not make sense to display as a container, |
|
58 // we forget that it is a sequence by erasing n->seq. |
|
59 // That way, n->seq and n->child will be either both set or both null. |
|
60 |
|
61 bool isContainer; |
|
62 n->seq->GetIsValidContainer(&isContainer); |
|
63 if (!isContainer) { |
|
64 n->seq = nullptr; |
|
65 return; |
|
66 } |
|
67 |
|
68 nsCOMPtr<nsIMutableArray> asn1Objects; |
|
69 n->seq->GetASN1Objects(getter_AddRefs(asn1Objects)); |
|
70 uint32_t numObjects; |
|
71 asn1Objects->GetLength(&numObjects); |
|
72 |
|
73 if (!numObjects) { |
|
74 n->seq = nullptr; |
|
75 return; |
|
76 } |
|
77 |
|
78 myNode *walk = nullptr; |
|
79 myNode *prev = nullptr; |
|
80 |
|
81 uint32_t i; |
|
82 nsCOMPtr<nsISupports> isupports; |
|
83 for (i=0; i<numObjects; i++) { |
|
84 if (0 == i) { |
|
85 n->child = walk = new myNode; |
|
86 } |
|
87 else { |
|
88 walk = new myNode; |
|
89 } |
|
90 |
|
91 walk->parent = n; |
|
92 if (prev) { |
|
93 prev->next = walk; |
|
94 } |
|
95 |
|
96 walk->obj = do_QueryElementAt(asn1Objects, i); |
|
97 |
|
98 InitChildsRecursively(walk); |
|
99 |
|
100 prev = walk; |
|
101 } |
|
102 } |
|
103 |
|
104 void nsNSSASN1Tree::InitNodes() |
|
105 { |
|
106 ClearNodes(); |
|
107 |
|
108 mTopNode = new myNode; |
|
109 mTopNode->obj = mASN1Object; |
|
110 |
|
111 InitChildsRecursively(mTopNode); |
|
112 } |
|
113 |
|
114 /* void loadASN1Structure (in nsIASN1Object asn1Object); */ |
|
115 NS_IMETHODIMP |
|
116 nsNSSASN1Tree::LoadASN1Structure(nsIASN1Object *asn1Object) |
|
117 { |
|
118 // |
|
119 // The tree won't automatically re-draw if the contents |
|
120 // have been changed. So I do a quick test here to let |
|
121 // me know if I should forced the tree to redraw itself |
|
122 // by calling RowCountChanged on it. |
|
123 // |
|
124 bool redraw = (mASN1Object && mTree); |
|
125 int32_t rowsToDelete = 0; |
|
126 |
|
127 if (redraw) { |
|
128 // This is the number of rows we will be deleting after |
|
129 // the contents have changed. |
|
130 rowsToDelete = 0-CountVisibleNodes(mTopNode); |
|
131 } |
|
132 |
|
133 mASN1Object = asn1Object; |
|
134 InitNodes(); |
|
135 |
|
136 if (redraw) { |
|
137 // The number of rows in the new content. |
|
138 int32_t newRows = CountVisibleNodes(mTopNode); |
|
139 mTree->BeginUpdateBatch(); |
|
140 // Erase all of the old rows. |
|
141 mTree->RowCountChanged(0, rowsToDelete); |
|
142 // Replace them with the new contents |
|
143 mTree->RowCountChanged(0, newRows); |
|
144 mTree->EndUpdateBatch(); |
|
145 } |
|
146 |
|
147 return NS_OK; |
|
148 } |
|
149 |
|
150 /* readonly attribute long rowCount; */ |
|
151 NS_IMETHODIMP |
|
152 nsNSSASN1Tree::GetRowCount(int32_t *aRowCount) |
|
153 { |
|
154 if (mASN1Object) { |
|
155 *aRowCount = CountVisibleNodes(mTopNode); |
|
156 } else { |
|
157 *aRowCount = 0; |
|
158 } |
|
159 return NS_OK; |
|
160 } |
|
161 |
|
162 /* attribute nsITreeSelection selection; */ |
|
163 NS_IMETHODIMP |
|
164 nsNSSASN1Tree::GetSelection(nsITreeSelection * *aSelection) |
|
165 { |
|
166 *aSelection = mSelection; |
|
167 NS_IF_ADDREF(*aSelection); |
|
168 return NS_OK; |
|
169 } |
|
170 |
|
171 NS_IMETHODIMP |
|
172 nsNSSASN1Tree::SetSelection(nsITreeSelection * aSelection) |
|
173 { |
|
174 mSelection = aSelection; |
|
175 return NS_OK; |
|
176 } |
|
177 |
|
178 NS_IMETHODIMP |
|
179 nsNSSASN1Tree::GetRowProperties(int32_t index, nsAString& aProps) |
|
180 { |
|
181 return NS_OK; |
|
182 } |
|
183 |
|
184 NS_IMETHODIMP |
|
185 nsNSSASN1Tree::GetCellProperties(int32_t row, nsITreeColumn* col, |
|
186 nsAString& aProps) |
|
187 { |
|
188 return NS_OK; |
|
189 } |
|
190 |
|
191 NS_IMETHODIMP |
|
192 nsNSSASN1Tree::GetColumnProperties(nsITreeColumn* col, nsAString& aProps) |
|
193 { |
|
194 return NS_OK; |
|
195 } |
|
196 |
|
197 /* boolean isContainer (in long index); */ |
|
198 NS_IMETHODIMP |
|
199 nsNSSASN1Tree::IsContainer(int32_t index, bool *_retval) |
|
200 { |
|
201 myNode *n = FindNodeFromIndex(index); |
|
202 if (!n) |
|
203 return NS_ERROR_FAILURE; |
|
204 |
|
205 *_retval = (n->seq != nullptr); |
|
206 return NS_OK; |
|
207 } |
|
208 |
|
209 /* boolean isContainerOpen (in long index); */ |
|
210 NS_IMETHODIMP |
|
211 nsNSSASN1Tree::IsContainerOpen(int32_t index, bool *_retval) |
|
212 { |
|
213 myNode *n = FindNodeFromIndex(index); |
|
214 if (!n || !n->seq) |
|
215 return NS_ERROR_FAILURE; |
|
216 |
|
217 n->seq->GetIsExpanded(_retval); |
|
218 return NS_OK; |
|
219 } |
|
220 |
|
221 /* boolean isContainerEmpty (in long index); */ |
|
222 NS_IMETHODIMP |
|
223 nsNSSASN1Tree::IsContainerEmpty(int32_t index, bool *_retval) |
|
224 { |
|
225 *_retval = false; |
|
226 return NS_OK; |
|
227 } |
|
228 |
|
229 /* boolean isSeparator (in long index); */ |
|
230 NS_IMETHODIMP |
|
231 nsNSSASN1Tree::IsSeparator(int32_t index, bool *_retval) |
|
232 { |
|
233 *_retval = false; |
|
234 return NS_OK; |
|
235 } |
|
236 |
|
237 /* long getLevel (in long index); */ |
|
238 NS_IMETHODIMP |
|
239 nsNSSASN1Tree::GetLevel(int32_t index, int32_t *_retval) |
|
240 { |
|
241 int32_t parentIndex; |
|
242 int32_t nodeLevel; |
|
243 |
|
244 myNode *n = FindNodeFromIndex(index, &parentIndex, &nodeLevel); |
|
245 if (!n) |
|
246 return NS_ERROR_FAILURE; |
|
247 |
|
248 *_retval = nodeLevel; |
|
249 return NS_OK; |
|
250 } |
|
251 |
|
252 /* Astring getImageSrc (in long row, in nsITreeColumn col); */ |
|
253 NS_IMETHODIMP |
|
254 nsNSSASN1Tree::GetImageSrc(int32_t row, nsITreeColumn* col, |
|
255 nsAString& _retval) |
|
256 { |
|
257 return NS_OK; |
|
258 } |
|
259 |
|
260 /* long getProgressMode (in long row, in nsITreeColumn col); */ |
|
261 NS_IMETHODIMP |
|
262 nsNSSASN1Tree::GetProgressMode(int32_t row, nsITreeColumn* col, int32_t* _retval) |
|
263 { |
|
264 return NS_OK; |
|
265 } |
|
266 |
|
267 /* Astring getCellValue (in long row, in nsITreeColumn col); */ |
|
268 NS_IMETHODIMP |
|
269 nsNSSASN1Tree::GetCellValue(int32_t row, nsITreeColumn* col, |
|
270 nsAString& _retval) |
|
271 { |
|
272 return NS_OK; |
|
273 } |
|
274 |
|
275 /* Astring getCellText (in long row, in nsITreeColumn col); */ |
|
276 NS_IMETHODIMP |
|
277 nsNSSASN1Tree::GetCellText(int32_t row, nsITreeColumn* col, |
|
278 nsAString& _retval) |
|
279 { |
|
280 _retval.Truncate(); |
|
281 |
|
282 myNode* n = FindNodeFromIndex(row); |
|
283 if (!n) |
|
284 return NS_ERROR_FAILURE; |
|
285 |
|
286 // There's only one column for ASN1 dump. |
|
287 return n->obj->GetDisplayName(_retval); |
|
288 } |
|
289 |
|
290 /* wstring getDisplayData (in unsigned long index); */ |
|
291 NS_IMETHODIMP |
|
292 nsNSSASN1Tree::GetDisplayData(uint32_t index, nsAString &_retval) |
|
293 { |
|
294 myNode *n = FindNodeFromIndex(index); |
|
295 if (!n) |
|
296 return NS_ERROR_FAILURE; |
|
297 |
|
298 n->obj->GetDisplayValue(_retval); |
|
299 return NS_OK; |
|
300 } |
|
301 |
|
302 /* void setTree (in nsITreeBoxObject tree); */ |
|
303 NS_IMETHODIMP |
|
304 nsNSSASN1Tree::SetTree(nsITreeBoxObject *tree) |
|
305 { |
|
306 mTree = tree; |
|
307 return NS_OK; |
|
308 } |
|
309 |
|
310 /* void toggleOpenState (in long index); */ |
|
311 NS_IMETHODIMP |
|
312 nsNSSASN1Tree::ToggleOpenState(int32_t index) |
|
313 { |
|
314 myNode *n = FindNodeFromIndex(index); |
|
315 if (!n) |
|
316 return NS_ERROR_FAILURE; |
|
317 |
|
318 if (!n->seq) |
|
319 return NS_ERROR_FAILURE; |
|
320 |
|
321 bool IsExpanded; |
|
322 n->seq->GetIsExpanded(&IsExpanded); |
|
323 int32_t rowCountChange; |
|
324 if (IsExpanded) { |
|
325 rowCountChange = -CountVisibleNodes(n->child); |
|
326 n->seq->SetIsExpanded(false); |
|
327 } else { |
|
328 n->seq->SetIsExpanded(true); |
|
329 rowCountChange = CountVisibleNodes(n->child); |
|
330 } |
|
331 if (mTree) |
|
332 mTree->RowCountChanged(index, rowCountChange); |
|
333 return NS_OK; |
|
334 } |
|
335 |
|
336 /* void cycleHeader (in nsITreeColumn col); */ |
|
337 NS_IMETHODIMP |
|
338 nsNSSASN1Tree::CycleHeader(nsITreeColumn* col) |
|
339 { |
|
340 return NS_OK; |
|
341 } |
|
342 |
|
343 /* void selectionChanged (); */ |
|
344 NS_IMETHODIMP |
|
345 nsNSSASN1Tree::SelectionChanged() |
|
346 { |
|
347 return NS_ERROR_NOT_IMPLEMENTED; |
|
348 } |
|
349 |
|
350 /* void cycleCell (in long row, in nsITreeColumn col); */ |
|
351 NS_IMETHODIMP |
|
352 nsNSSASN1Tree::CycleCell(int32_t row, nsITreeColumn* col) |
|
353 { |
|
354 return NS_OK; |
|
355 } |
|
356 |
|
357 /* boolean isEditable (in long row, in nsITreeColumn col); */ |
|
358 NS_IMETHODIMP |
|
359 nsNSSASN1Tree::IsEditable(int32_t row, nsITreeColumn* col, |
|
360 bool *_retval) |
|
361 { |
|
362 *_retval = false; |
|
363 return NS_OK; |
|
364 } |
|
365 |
|
366 /* boolean isSelectable (in long row, in nsITreeColumn col); */ |
|
367 NS_IMETHODIMP |
|
368 nsNSSASN1Tree::IsSelectable(int32_t row, nsITreeColumn* col, |
|
369 bool *_retval) |
|
370 { |
|
371 *_retval = false; |
|
372 return NS_OK; |
|
373 } |
|
374 |
|
375 /* void setCellValue (in long row, in nsITreeColumn col, in AString value); */ |
|
376 NS_IMETHODIMP |
|
377 nsNSSASN1Tree::SetCellValue(int32_t row, nsITreeColumn* col, |
|
378 const nsAString& value) |
|
379 { |
|
380 return NS_OK; |
|
381 } |
|
382 |
|
383 /* void setCellText (in long row, in nsITreeColumn col, in AString value); */ |
|
384 NS_IMETHODIMP |
|
385 nsNSSASN1Tree::SetCellText(int32_t row, nsITreeColumn* col, |
|
386 const nsAString& value) |
|
387 { |
|
388 return NS_OK; |
|
389 } |
|
390 |
|
391 /* void performAction (in wstring action); */ |
|
392 NS_IMETHODIMP |
|
393 nsNSSASN1Tree::PerformAction(const char16_t *action) |
|
394 { |
|
395 return NS_OK; |
|
396 } |
|
397 |
|
398 /* void performActionOnRow (in wstring action, in long row); */ |
|
399 NS_IMETHODIMP |
|
400 nsNSSASN1Tree::PerformActionOnRow(const char16_t *action, int32_t row) |
|
401 { |
|
402 return NS_OK; |
|
403 } |
|
404 |
|
405 /* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */ |
|
406 NS_IMETHODIMP |
|
407 nsNSSASN1Tree::PerformActionOnCell(const char16_t *action, int32_t row, |
|
408 nsITreeColumn* col) |
|
409 { |
|
410 return NS_OK; |
|
411 } |
|
412 |
|
413 // |
|
414 // CanDrop |
|
415 // |
|
416 NS_IMETHODIMP nsNSSASN1Tree::CanDrop(int32_t index, int32_t orientation, |
|
417 nsIDOMDataTransfer* aDataTransfer, bool *_retval) |
|
418 { |
|
419 NS_ENSURE_ARG_POINTER(_retval); |
|
420 *_retval = false; |
|
421 |
|
422 return NS_OK; |
|
423 } |
|
424 |
|
425 |
|
426 // |
|
427 // Drop |
|
428 // |
|
429 NS_IMETHODIMP nsNSSASN1Tree::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* aDataTransfer) |
|
430 { |
|
431 return NS_OK; |
|
432 } |
|
433 |
|
434 |
|
435 // |
|
436 // IsSorted |
|
437 // |
|
438 // ... |
|
439 // |
|
440 NS_IMETHODIMP nsNSSASN1Tree::IsSorted(bool *_retval) |
|
441 { |
|
442 *_retval = false; |
|
443 return NS_OK; |
|
444 } |
|
445 |
|
446 |
|
447 /* long getParentIndex (in long rowIndex); */ |
|
448 NS_IMETHODIMP |
|
449 nsNSSASN1Tree::GetParentIndex(int32_t rowIndex, int32_t *_retval) |
|
450 { |
|
451 int32_t parentIndex = -1; |
|
452 |
|
453 myNode *n = FindNodeFromIndex(rowIndex, &parentIndex); |
|
454 if (!n) |
|
455 return NS_ERROR_FAILURE; |
|
456 |
|
457 *_retval = parentIndex; |
|
458 return NS_OK; |
|
459 } |
|
460 |
|
461 /* boolean hasNextSibling (in long rowIndex, in long afterIndex); */ |
|
462 NS_IMETHODIMP |
|
463 nsNSSASN1Tree::HasNextSibling(int32_t rowIndex, int32_t afterIndex, |
|
464 bool *_retval) |
|
465 { |
|
466 myNode *n = FindNodeFromIndex(rowIndex); |
|
467 if (!n) |
|
468 return NS_ERROR_FAILURE; |
|
469 |
|
470 if (!n->next) { |
|
471 *_retval = false; |
|
472 } |
|
473 else { |
|
474 int32_t nTotalSize = CountVisibleNodes(n); |
|
475 int32_t nLastChildPos = rowIndex + nTotalSize -1; |
|
476 int32_t nextSiblingPos = nLastChildPos +1; |
|
477 *_retval = (nextSiblingPos > afterIndex); |
|
478 } |
|
479 |
|
480 return NS_OK; |
|
481 } |
|
482 |
|
483 int32_t nsNSSASN1Tree::CountVisibleNodes(myNode *n) |
|
484 { |
|
485 if (!n) |
|
486 return 0; |
|
487 |
|
488 myNode *walk = n; |
|
489 int32_t count = 0; |
|
490 |
|
491 while (walk) { |
|
492 ++count; |
|
493 |
|
494 if (walk->seq) { |
|
495 bool IsExpanded; |
|
496 walk->seq->GetIsExpanded(&IsExpanded); |
|
497 if (IsExpanded) { |
|
498 count += CountVisibleNodes(walk->child); |
|
499 } |
|
500 } |
|
501 |
|
502 walk = walk->next; |
|
503 } |
|
504 |
|
505 return count; |
|
506 } |
|
507 |
|
508 // Entry point for find |
|
509 nsNSSASN1Tree::myNode * |
|
510 nsNSSASN1Tree::FindNodeFromIndex(int32_t wantedIndex, |
|
511 int32_t *optionalOutParentIndex, int32_t *optionalOutLevel) |
|
512 { |
|
513 if (0 == wantedIndex) { |
|
514 if (optionalOutLevel) { |
|
515 *optionalOutLevel = 0; |
|
516 } |
|
517 if (optionalOutParentIndex) { |
|
518 *optionalOutParentIndex = -1; |
|
519 } |
|
520 return mTopNode; |
|
521 } |
|
522 else { |
|
523 int32_t index = 0; |
|
524 int32_t level = 0; |
|
525 return FindNodeFromIndex(mTopNode, wantedIndex, index, level, |
|
526 optionalOutParentIndex, optionalOutLevel); |
|
527 } |
|
528 } |
|
529 |
|
530 // Internal recursive helper function |
|
531 nsNSSASN1Tree::myNode * |
|
532 nsNSSASN1Tree::FindNodeFromIndex(myNode *n, int32_t wantedIndex, |
|
533 int32_t &index_counter, int32_t &level_counter, |
|
534 int32_t *optionalOutParentIndex, int32_t *optionalOutLevel) |
|
535 { |
|
536 if (!n) |
|
537 return nullptr; |
|
538 |
|
539 myNode *walk = n; |
|
540 int32_t parentIndex = index_counter-1; |
|
541 |
|
542 while (walk) { |
|
543 if (index_counter == wantedIndex) { |
|
544 if (optionalOutLevel) { |
|
545 *optionalOutLevel = level_counter; |
|
546 } |
|
547 if (optionalOutParentIndex) { |
|
548 *optionalOutParentIndex = parentIndex; |
|
549 } |
|
550 return walk; |
|
551 } |
|
552 |
|
553 if (walk->seq) { |
|
554 bool IsExpanded; |
|
555 walk->seq->GetIsExpanded(&IsExpanded); |
|
556 if (IsExpanded) { |
|
557 ++index_counter; // set to walk->child |
|
558 |
|
559 ++level_counter; |
|
560 myNode *found = FindNodeFromIndex(walk->child, wantedIndex, index_counter, level_counter, |
|
561 optionalOutParentIndex, optionalOutLevel); |
|
562 --level_counter; |
|
563 |
|
564 if (found) |
|
565 return found; |
|
566 } |
|
567 } |
|
568 |
|
569 walk = walk->next; |
|
570 if (walk) { |
|
571 ++index_counter; |
|
572 } |
|
573 } |
|
574 |
|
575 return nullptr; |
|
576 } |
|
577 |