• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import {Component, EventEmitter, Input, Output} from '@angular/core';
17import {DiffType, HierarchyTreeNode, UiTreeNode, UiTreeUtils} from 'viewers/common/ui_tree_utils';
18import {nodeInnerItemStyles} from 'viewers/components/styles/node.styles';
19
20@Component({
21  selector: 'tree-node',
22  template: `
23    <button *ngIf="showChevron()" class="icon-button toggle-tree-btn" (click)="toggleTree($event)">
24      <mat-icon>
25        {{ isCollapsed ? 'arrow_drop_down' : 'chevron_right' }}
26      </mat-icon>
27    </button>
28
29    <div *ngIf="showLeafNodeIcon()" class="leaf-node-icon-wrapper">
30      <mat-icon class="leaf-node-icon"></mat-icon>
31    </div>
32
33    <button *ngIf="showPinNodeIcon()" class="icon-button pin-node-btn" (click)="pinNode($event)">
34      <mat-icon>
35        {{ isPinned ? 'star' : 'star_border' }}
36      </mat-icon>
37    </button>
38
39    <div class="description">
40      <tree-node-data-view *ngIf="!isPropertiesTreeNode()" [item]="item"></tree-node-data-view>
41      <tree-node-properties-data-view
42        *ngIf="isPropertiesTreeNode()"
43        [item]="item"></tree-node-properties-data-view>
44    </div>
45
46    <button
47      *ngIf="hasChildren && !isCollapsed"
48      class="icon-button expand-tree-btn"
49      [class]="collapseDiffClass"
50      (click)="expandTree($event)">
51      <mat-icon aria-hidden="true"> more_horiz </mat-icon>
52    </button>
53  `,
54  styles: [nodeInnerItemStyles],
55})
56export class TreeNodeComponent {
57  @Input() item!: UiTreeNode;
58  @Input() isLeaf?: boolean;
59  @Input() flattened?: boolean;
60  @Input() isCollapsed?: boolean;
61  @Input() hasChildren?: boolean = false;
62  @Input() isPinned?: boolean = false;
63  @Input() isInPinnedSection?: boolean = false;
64  @Input() isAlwaysCollapsed?: boolean;
65
66  @Output() toggleTreeChange = new EventEmitter<void>();
67  @Output() expandTreeChange = new EventEmitter<boolean>();
68  @Output() pinNodeChange = new EventEmitter<UiTreeNode>();
69
70  collapseDiffClass = '';
71
72  ngOnChanges() {
73    this.collapseDiffClass = this.updateCollapseDiffClass();
74  }
75
76  isPropertiesTreeNode() {
77    return !(this.item instanceof HierarchyTreeNode);
78  }
79
80  showPinNodeIcon() {
81    return (
82      (!this.isPropertiesTreeNode() && !UiTreeUtils.isParentNode(this.item.kind ?? '')) ?? false
83    );
84  }
85
86  toggleTree(event: MouseEvent) {
87    if (!this.isAlwaysCollapsed) {
88      event.stopPropagation();
89      this.toggleTreeChange.emit();
90    }
91  }
92
93  showChevron() {
94    return !this.isLeaf && !this.flattened && !this.isInPinnedSection;
95  }
96
97  showLeafNodeIcon() {
98    return !this.showChevron() && !this.isInPinnedSection;
99  }
100
101  expandTree(event: MouseEvent) {
102    event.stopPropagation();
103    this.expandTreeChange.emit();
104  }
105
106  pinNode(event: MouseEvent) {
107    event.stopPropagation();
108    this.pinNodeChange.emit(this.item);
109  }
110
111  updateCollapseDiffClass() {
112    if (this.isCollapsed) {
113      return '';
114    }
115
116    const childrenDiffClasses = this.getAllDiffTypesOfChildren(this.item);
117
118    childrenDiffClasses.delete(DiffType.NONE);
119    childrenDiffClasses.delete(undefined);
120
121    if (childrenDiffClasses.size === 0) {
122      return '';
123    }
124    if (childrenDiffClasses.size === 1) {
125      const diffType = childrenDiffClasses.values().next().value;
126      return diffType;
127    }
128    return DiffType.MODIFIED;
129  }
130
131  private getAllDiffTypesOfChildren(item: UiTreeNode) {
132    if (!item.children) {
133      return new Set();
134    }
135
136    const classes = new Set();
137    for (const child of item.children) {
138      if (child.diffType) {
139        classes.add(child.diffType);
140      }
141      for (const diffClass of this.getAllDiffTypesOfChildren(child)) {
142        classes.add(diffClass);
143      }
144    }
145
146    return classes;
147  }
148}
149