• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.distributed;
17 
18 import com.intellij.ui.JBColor;
19 import com.intellij.ui.components.JBLabel;
20 import com.intellij.ui.components.JBPanel;
21 import com.intellij.ui.components.JBTreeTable;
22 import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns;
23 import com.intellij.ui.treeStructure.treetable.TreeColumnInfo;
24 import com.intellij.util.ui.ColumnInfo;
25 import com.intellij.util.ui.JBUI;
26 import net.miginfocom.swing.MigLayout;
27 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager;
28 import ohos.devtools.views.applicationtrace.analysis.TreeTableRowSorter;
29 import ohos.devtools.views.applicationtrace.util.TimeUtils;
30 import ohos.devtools.views.distributed.bean.DetailBean;
31 import ohos.devtools.views.distributed.bean.DistributedFuncBean;
32 import ohos.devtools.views.distributed.util.DetailTreeTableColumn;
33 import ohos.devtools.views.distributed.util.DistributedCache;
34 import ohos.devtools.views.distributed.util.DistributedDataPraser;
35 import ohos.devtools.views.trace.EventDispatcher;
36 import ohos.devtools.views.trace.Tip;
37 import ohos.devtools.views.trace.util.ImageUtils;
38 import org.apache.log4j.LogManager;
39 import org.apache.log4j.Logger;
40 
41 import javax.swing.ImageIcon;
42 import javax.swing.JTable;
43 import javax.swing.JTree;
44 import javax.swing.table.DefaultTableCellRenderer;
45 import javax.swing.tree.DefaultMutableTreeNode;
46 import javax.swing.tree.DefaultTreeCellRenderer;
47 import javax.swing.tree.TreeNode;
48 import javax.swing.tree.TreePath;
49 import java.awt.Component;
50 import java.awt.event.MouseAdapter;
51 import java.awt.event.MouseEvent;
52 import java.util.ArrayList;
53 import java.util.Comparator;
54 import java.util.Enumeration;
55 import java.util.HashMap;
56 import java.util.LinkedHashMap;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Objects;
60 import java.util.concurrent.atomic.AtomicInteger;
61 import java.util.stream.Collectors;
62 
63 /**
64  * DistributedDataCallTreePane
65  *
66  * @since 2021/08/05 16:07
67  */
68 public class DistributedDataCallTreePane extends JBPanel implements IDistributedData {
69     private static final Logger LOGGER = LogManager.getLogger(DistributedDataCallTreePane.class);
70 
71     private Map<String, List<DistributedFuncBean>> chainIdFuncBeanMapA = new HashMap<>();
72     private Map<String, List<DistributedFuncBean>> chainIdFuncBeanMapB = new HashMap<>();
73     private Map<Integer, List<DistributedFuncBean>> parentIdFuncBeanMapA = new HashMap<>();
74     private Map<Integer, List<DistributedFuncBean>> parentIdFuncBeanMapB = new HashMap<>();
75     private DetailBean currentSelectBean = null;
76     private ImageIcon usbIcon = new ImageIcon();
77     private ImageIcon wifiIcon = new ImageIcon();
78     private JBTreeTable treeTable;
79     private DefaultMutableTreeNode root = new DefaultMutableTreeNode();
80     private ColumnInfo[] columns = new ColumnInfo[] {new TreeColumnInfo("Name"),
81         new DetailTreeTableColumn<>("Params", DetailBean.class, String.class) {
82             @Override
83             public String getCompareValue(DetailBean nodeData) {
84                 return nodeData.getParams() == null ? "" : nodeData.getParams();
85             }
86         }, new DetailTreeTableColumn<>("Total (μs)", DetailBean.class, Long.class) {
87         @Override
88         public Long getCompareValue(DetailBean nodeData) {
89             return nodeData.getTotalNS();
90         }
91     }, new DetailTreeTableColumn<>("Delay (μs)", DetailBean.class, Long.class) {
92         @Override
93         public Long getCompareValue(DetailBean nodeData) {
94             return nodeData.getDelayNS();
95         }
96     }};
97 
98     private ListTreeTableModelOnColumns tableModelOnColumns;
99 
100     /**
101      * DistributedDataCallTreePane
102      */
DistributedDataCallTreePane()103     public DistributedDataCallTreePane() {
104         setLayout(new MigLayout("inset 0"));
105         usbIcon.setImage(ImageUtils.getInstance().getIconUsb());
106         wifiIcon.setImage(ImageUtils.getInstance().getIconWifi());
107         initTable();
108         initData();
109     }
110 
initTable()111     private void initTable() {
112         tableModelOnColumns = new ListTreeTableModelOnColumns(root, columns);
113         treeTable = new JBTreeTable(tableModelOnColumns);
114         treeTable.setColumnProportion(0.2F);
115         treeTable.getTree().setExpandsSelectedPaths(true);
116         treeTable.getTree().setExpandableItemsEnabled(true);
117         treeTable.getTree().setCellRenderer(new TreeCellRender());
118         treeTable.setDefaultRenderer(String.class, new ColorCellRenderer());
119         add(treeTable, "push,grow");
120         TreeTableRowSorter sorter = new TreeTableRowSorter(treeTable.getTable().getModel());
121         sorter.setListener((columnIndex, sortOrder) -> {
122             if (columnIndex <= 0 || columnIndex > columns.length) {
123                 return;
124             }
125             tableModelOnColumns.reload();
126         });
127         treeTable.getTable().addMouseListener(new MouseAdapter() {
128             @Override
129             public void mouseExited(MouseEvent event) {
130                 super.mouseExited(event);
131                 Tip.getInstance().hidden();
132             }
133 
134             @Override
135             public void mouseClicked(MouseEvent event) {
136                 super.mouseClicked(event);
137                 if (currentSelectBean != null) {
138                     List<String> stringList = currentSelectBean.getStringList();
139                     Tip.getInstance().display(event, stringList);
140                     EventDispatcher.dispatcherFuncChangeListener(currentSelectBean.getId());
141                 }
142             }
143         });
144         addTreeTableMouseListener();
145         treeTable.getTree().addTreeSelectionListener(event -> {
146             if (treeTable.getTree().getLastSelectedPathComponent() instanceof DefaultMutableTreeNode) {
147                 DefaultMutableTreeNode node =
148                     (DefaultMutableTreeNode) treeTable.getTree().getLastSelectedPathComponent();
149                 if (node != null && node.getUserObject() instanceof DetailBean) {
150                     currentSelectBean = (DetailBean) node.getUserObject();
151                 }
152             }
153         });
154     }
155 
addTreeTableMouseListener()156     private void addTreeTableMouseListener() {
157         treeTable.getTree().addMouseListener(new MouseAdapter() {
158             @Override
159             public void mouseExited(MouseEvent event) {
160                 super.mouseExited(event);
161                 Tip.getInstance().hidden();
162             }
163 
164             @Override
165             public void mouseClicked(MouseEvent event) {
166                 super.mouseClicked(event);
167                 if (currentSelectBean != null) {
168                     List<String> stringList = currentSelectBean.getStringList();
169                     Tip.getInstance().display(event, stringList);
170                     EventDispatcher.dispatcherFuncChangeListener(currentSelectBean.getId());
171                 }
172             }
173         });
174     }
175 
initData()176     private void initData() {
177         EventDispatcher.addClickListener(it -> {
178             if (it instanceof DistributedFuncBean) {
179                 DistributedFuncBean func = (DistributedFuncBean) it;
180                 freshAllDataBySelectData(func);
181             }
182         });
183     }
184 
185     /**
186      * freshFuncSelectData fresh all Func with SelectData
187      */
freshFuncSelectData()188     public void freshFuncSelectData() {
189         if (DistributedFuncBean.currentSelectedFunc != null) {
190             freshAllDataBySelectData(DistributedFuncBean.currentSelectedFunc);
191         } else {
192             freshTreeData(new ArrayList<>(), null);
193         }
194     }
195 
freshAllDataBySelectData(DistributedFuncBean selectBean)196     private void freshAllDataBySelectData(DistributedFuncBean selectBean) {
197         if (chainIdFuncBeanMapA.size() == 0) {
198             chainIdFuncBeanMapA =
199                 DistributedCache.ID_FUNC_BEAN_MAP_A.values().stream().filter((bean) -> !bean.getChainId().isEmpty())
200                     .sorted(Comparator.comparingInt(DistributedFuncBean::getId)).collect(
201                     Collectors.groupingBy(DistributedFuncBean::getChainId, LinkedHashMap::new, Collectors.toList()));
202         }
203         if (chainIdFuncBeanMapB.size() == 0) {
204             chainIdFuncBeanMapB =
205                 DistributedCache.ID_FUNC_BEAN_MAP_B.values().stream().filter((bean) -> !bean.getChainId().isEmpty())
206                     .sorted(Comparator.comparingInt(DistributedFuncBean::getId)).collect(
207                     Collectors.groupingBy(DistributedFuncBean::getChainId, LinkedHashMap::new, Collectors.toList()));
208         }
209         if (parentIdFuncBeanMapA.size() == 0) {
210             parentIdFuncBeanMapA = DistributedCache.ID_FUNC_BEAN_MAP_A.values().stream()
211                 .collect(Collectors.groupingBy(DistributedFuncBean::getParentId));
212         }
213         if (parentIdFuncBeanMapB.size() == 0) {
214             parentIdFuncBeanMapB = DistributedCache.ID_FUNC_BEAN_MAP_B.values().stream()
215                 .collect(Collectors.groupingBy(DistributedFuncBean::getParentId));
216         }
217         DistributedFuncBean head = findHead(selectBean);
218         if (head != null) {
219             List<DefaultMutableTreeNode> treeNodes = getTreeNodes(head);
220             freshTreeData(treeNodes, selectBean);
221         }
222     }
223 
224     /**
225      * freshTreeData fresh all data with select func
226      *
227      * @param nodes nodeList
228      * @param func func
229      */
freshTreeData(List<DefaultMutableTreeNode> nodes, DistributedFuncBean func)230     public void freshTreeData(List<DefaultMutableTreeNode> nodes, DistributedFuncBean func) {
231         if (Objects.isNull(nodes)) {
232             return;
233         }
234         root.removeAllChildren();
235         nodes.forEach(item -> root.add(item));
236         tableModelOnColumns.reload();
237         expandTree(treeTable.getTree());
238         Enumeration<TreeNode> enumeration = root.depthFirstEnumeration();
239         while (enumeration.hasMoreElements()) {
240             TreeNode treNode = enumeration.nextElement();
241             if (treNode instanceof DefaultMutableTreeNode) {
242                 DefaultMutableTreeNode nextElement = (DefaultMutableTreeNode) treNode;
243                 if (nextElement.getUserObject() instanceof DetailBean) {
244                     DetailBean userObject = (DetailBean) nextElement.getUserObject();
245                     if (func.getId().equals(userObject.getId())) {
246                         treeTable.getTree().setSelectionPath(new TreePath(nextElement.getPath()));
247                     }
248                 }
249             }
250         }
251     }
252 
253     /**
254      * findHead find the head func by current func
255      *
256      * @param selectBean selectBean
257      * @return DistributedFuncBean DistributedFuncBean
258      */
findHead(DistributedFuncBean selectBean)259     public DistributedFuncBean findHead(DistributedFuncBean selectBean) {
260         if (selectBean.getParentId() == 0) {
261 
262             // Determines whether the current node is top-level and,
263             // if so, whether it is non-S-non-s and top-level
264             if (!selectBean.getFlag().equals("S")) {
265                 if (selectBean.getSpanId() == selectBean.getParentSpanId()) {
266                     return selectBean;
267                 } else {
268                     return findTopBean(selectBean);
269                 }
270             } else {
271                 return findHead(findBeanDistributed(selectBean));
272             }
273         } else {
274 
275             // The current node is not top-level
276             // Determines whether the current node is s If a non-s node is found up for s
277             DistributedFuncBean parentBeanDistributed = findParentBeanDistributed(selectBean);
278             if (!selectBean.getFlag().equals("S")) {
279                 return findHead(parentBeanDistributed);
280             } else { // Recursively find the top node
281                 if (parentBeanDistributed.getChainId().isEmpty()) { // The parent node is a non-distributed node
282                     DistributedFuncBean beanDistributed = findBeanDistributed(selectBean);
283                     if (beanDistributed != null) {
284                         return findHead(beanDistributed);
285                     }
286                 } else {
287                     return findHead(parentBeanDistributed);
288                 }
289             }
290         }
291         return selectBean;
292     }
293 
findParentBeanDistributed( DistributedFuncBean selectBean)294     private DistributedFuncBean findParentBeanDistributed(
295         DistributedFuncBean selectBean) { // The parent node was found based on the praentid
296         DistributedFuncBean parentA = DistributedCache.ID_FUNC_BEAN_MAP_A.get(selectBean.getParentId());
297         DistributedFuncBean parentB = DistributedCache.ID_FUNC_BEAN_MAP_B.get(selectBean.getParentId());
298         if (selectBean.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
299             return parentA;
300         } else {
301             return parentB;
302         }
303     }
304 
findTopBean(DistributedFuncBean selectBean)305     private DistributedFuncBean findTopBean(DistributedFuncBean selectBean) {
306         if (selectBean.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
307             DistributedFuncBean topA = chainIdFuncBeanMapA.get(selectBean.getChainId()).stream()
308                 .filter((item) -> item.getSpanId().equals(selectBean.getParentSpanId()) && !item.getFlag().equals("S"))
309                 .findFirst().orElse(null);
310             if (topA != null) {
311                 return findHead(topA);
312             }
313             return selectBean;
314         } else {
315             DistributedFuncBean topB = chainIdFuncBeanMapB.get(selectBean.getChainId()).stream()
316                 .filter((item) -> item.getSpanId().equals(selectBean.getParentSpanId()) && !item.getFlag().equals("S"))
317                 .findFirst().orElse(null);
318             if (topB != null) {
319                 return findHead(topB);
320             }
321             return selectBean;
322         }
323     }
324 
findBeanDistributed( DistributedFuncBean selectBean)325     private DistributedFuncBean findBeanDistributed(
326         DistributedFuncBean selectBean) { // Find the parent nodes based on spanid and parenspanid flag c in a and b
327         if (chainIdFuncBeanMapA.containsKey(selectBean.getChainId())) { // Find the corresponding bean in a
328             DistributedFuncBean findBeanA = chainIdFuncBeanMapA.get(selectBean.getChainId()).stream().filter(
329                 (item) -> item.getSpanId().equals(selectBean.getSpanId()) && item.getParentSpanId()
330                     .equals(selectBean.getParentSpanId()) && item.getFlag().equals("C")).findFirst().orElse(null);
331             if (findBeanA == null) {
332                 if (chainIdFuncBeanMapB.containsKey(selectBean.getChainId())) { // The corresponding bean was found in b
333                     DistributedFuncBean findBeanB = chainIdFuncBeanMapB.get(selectBean.getChainId()).stream().filter(
334                         (item) -> item.getSpanId().equals(selectBean.getSpanId()) && item.getParentSpanId()
335                             .equals(selectBean.getParentSpanId()) && item.getFlag().equals("C")).findFirst()
336                         .orElse(null);
337                     if (findBeanB == null) { // Data outage
338                         return null;
339                     }
340                     return findBeanB;
341                 }
342             } else {
343                 return findBeanA;
344             }
345         }
346         return null;
347     }
348 
getTreeNodes(DistributedFuncBean headBean)349     private List<DefaultMutableTreeNode> getTreeNodes(DistributedFuncBean headBean) {
350         List<DefaultMutableTreeNode> nodes = new ArrayList<>();
351         List<DistributedFuncBean> list = new ArrayList<>();
352         headBean.setDelay(0L); // The head node delay is 0
353         headToEndBean(headBean, list);
354         AtomicInteger index = new AtomicInteger(0); // The subscript for the loop
355         list.forEach((item) -> {
356             if (index.get() != 0) {
357                 item.setDelay(item.getStartTs() - list.get(index.get() - 1).getStartTs());
358             }
359             index.getAndAdd(1);
360         });
361         DetailBean middleBean = DistributedDataPraser.collectByName(list);
362         Map<Integer, DefaultMutableTreeNode> funcBeanMap =
363             list.stream().collect(Collectors.toMap(DistributedFuncBean::getId, (bean) -> {
364                 DetailBean detailBean = new DetailBean();
365                 detailBean.mergeFuncBean(bean);
366                 detailBean.mergeDetailcBean(middleBean);
367                 return new DefaultMutableTreeNode(detailBean);
368             }));
369 
370         list.forEach((item) -> {
371             DefaultMutableTreeNode node = funcBeanMap.get(item.getId());
372             if (item.getParentId() == 0) {
373                 DetailBean detailBean = new DetailBean();
374                 detailBean.setName(getPackageName(item.getCurrentType()));
375                 detailBean.setCurrentType(item.getCurrentType());
376                 DefaultMutableTreeNode parentRootNode = new DefaultMutableTreeNode(detailBean);
377                 parentRootNode.add(node);
378                 nodes.add(parentRootNode);
379             } else {
380                 if (funcBeanMap.containsKey(item.getParentId())) {
381                     funcBeanMap.get(item.getParentId()).add(node);
382                 }
383             }
384         });
385         return nodes;
386     }
387 
getPackageName(DistributedFuncBean.BeanDataType type)388     private String getPackageName(DistributedFuncBean.BeanDataType type) {
389         if (type.equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
390             return DistributedCache.getDistribuetedParams().getPkgNameA() + "(" + DistributedCache
391                 .getDistribuetedParams().getDeviceNameA() + ")";
392         } else {
393             return DistributedCache.getDistribuetedParams().getPkgNameB() + "(" + DistributedCache
394                 .getDistribuetedParams().getDeviceNameB() + ")";
395         }
396     }
397 
headToEndBean(DistributedFuncBean headBean, List<DistributedFuncBean> list)398     private void headToEndBean(DistributedFuncBean headBean,
399         List<DistributedFuncBean> list) { // Find all the tree nodes from top to bottom
400         list.add(headBean);
401         if (headBean.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
402             if (parentIdFuncBeanMapA.containsKey(headBean.getId())) {
403                 forEachToMap(parentIdFuncBeanMapA, headBean.getId(), list);
404             } else {
405                 parentIdFuncNotFound(headBean, list);
406             }
407         } else if (headBean.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_B)) {
408             if (parentIdFuncBeanMapB.containsKey(headBean.getId())) {
409                 forEachToMap(parentIdFuncBeanMapB, headBean.getId(), list);
410             } else {
411                 if (headBean.getFlag().equals("C")) {
412                     toNextThreadFunc(headBean, list);
413                 } else if (headBean.getFlag().equals("S")) {
414                     DistributedFuncBean childSBeanB = chainIdFuncBeanMapB.get(headBean.getChainId()).stream()
415                         .filter((item) -> item.getParentSpanId() == headBean.getSpanId()).findFirst().orElse(null);
416                     if (childSBeanB != null) {
417                         headToEndBean(childSBeanB, list);
418                     }
419                 } else if (headBean.getParentId() == 0 && headBean.getParentSpanId() == headBean.getSpanId()
420                     && !headBean.getChainId().isEmpty()) { // Flag is an empty head node
421                     DistributedFuncBean childBeanB = chainIdFuncBeanMapB.get(headBean.getChainId()).stream()
422                         .filter((item) -> item.getParentSpanId() == headBean.getSpanId() && item.getFlag().equals("C"))
423                         .findFirst().orElse(null);
424                     if (childBeanB != null) {
425                         headToEndBean(childBeanB, list);
426                     }
427                 } else {
428                     if (ProfilerLogManager.isDebugEnabled()) {
429                         LOGGER.debug("headBean status error");
430                     }
431                 }
432             }
433         } else {
434             if (ProfilerLogManager.isInfoEnabled()) {
435                 LOGGER.info("CurrentType error");
436             }
437         }
438     }
439 
parentIdFuncNotFound(DistributedFuncBean headBean, List<DistributedFuncBean> list)440     private void parentIdFuncNotFound(DistributedFuncBean headBean, List<DistributedFuncBean> list) {
441         if (headBean.getFlag().equals("C")) {
442             toNextThreadFunc(headBean, list);
443         } else if (headBean.getFlag().equals("S")) {
444             DistributedFuncBean childSBeanA = chainIdFuncBeanMapA.get(headBean.getChainId()).stream()
445                 .filter((item) -> item.getParentSpanId() == headBean.getSpanId()).findFirst().orElse(null);
446             if (childSBeanA != null) {
447                 headToEndBean(childSBeanA, list);
448             }
449         } else if (headBean.getParentId() == 0 && headBean.getParentSpanId() == headBean.getSpanId()
450             && !headBean.getChainId().isEmpty()) { // Flag is an empty head node
451             DistributedFuncBean childBeanA = chainIdFuncBeanMapA.get(headBean.getChainId()).stream()
452                 .filter((item) -> item.getParentSpanId() == headBean.getSpanId() && item.getFlag().equals("C"))
453                 .findFirst().orElse(null);
454             if (childBeanA != null) {
455                 headToEndBean(childBeanA, list);
456             }
457         } else {
458             if (ProfilerLogManager.isDebugEnabled()) {
459                 LOGGER.debug("headBean status error");
460             }
461         }
462     }
463 
forEachToMap(Map<Integer, List<DistributedFuncBean>> map, Integer id, List<DistributedFuncBean> list)464     private void forEachToMap(Map<Integer, List<DistributedFuncBean>> map, Integer id, List<DistributedFuncBean> list) {
465         map.get(id).forEach((item) -> {
466             headToEndBean(item, list);
467         });
468     }
469 
supplementParentBean(DistributedFuncBean headBean, List<DistributedFuncBean> list)470     private void supplementParentBean(DistributedFuncBean headBean, List<DistributedFuncBean> list) {
471 
472         // When C goes to the S of another thread,
473         // the next thread method may appear that is not the top-of-stack method and needs to find the head
474         if (headBean.getDepth() != 0) {
475             DistributedFuncBean parentBean;
476             if (headBean.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
477                 parentBean = DistributedCache.ID_FUNC_BEAN_MAP_A.get(headBean.getParentId());
478             } else {
479                 parentBean = DistributedCache.ID_FUNC_BEAN_MAP_B.get(headBean.getParentId());
480             }
481             list.add(parentBean);
482             supplementParentBean(parentBean, list);
483         }
484     }
485 
toNextThreadFunc(DistributedFuncBean headBean, List<DistributedFuncBean> list)486     private void toNextThreadFunc(DistributedFuncBean headBean, List<DistributedFuncBean> list) {
487         if (headBean.getChainId() == null || headBean.getChainId().isEmpty()) {
488             return;
489         }
490         DistributedFuncBean first = chainIdFuncBeanMapA.get(headBean.getChainId()).stream().filter(
491             (item) -> item.getSpanId().equals(headBean.getSpanId()) && item.getParentSpanId()
492                 .equals(headBean.getParentSpanId()) && item.getFlag().equals("S")).findFirst().orElse(null);
493         if (first != null) {
494             supplementParentBean(first, list);
495             headToEndBean(first, list);
496         } else {
497             chainIdFuncBeanMapB.get(headBean.getChainId()).stream().filter(
498                 (item) -> item.getSpanId().equals(headBean.getSpanId()) && item.getParentSpanId()
499                     .equals(headBean.getParentSpanId()) && item.getFlag().equals("S")).findFirst()
500                 .ifPresent(startBean -> {
501                     supplementParentBean(startBean, list);
502                     headToEndBean(startBean, list);
503                 });
504         }
505     }
506 
507     private class TreeCellRender extends DefaultTreeCellRenderer {
508         @Override
getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)509         public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
510             boolean leaf, int row, boolean hasFocus) {
511             JBLabel jbLabel = new JBLabel();
512             jbLabel.setBorder(JBUI.Borders.empty(5, 5));
513             DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
514             DetailBean userObject = (DetailBean) node.getUserObject();
515             if (userObject != null) {
516                 if (node.getParent() != null && node.getParent() instanceof DefaultMutableTreeNode
517                     && ((DefaultMutableTreeNode) node.getParent()).isRoot()) {
518                     if (userObject.getCurrentType().equals(DistributedFuncBean.BeanDataType.TYPE_A)) {
519                         jbLabel.setIcon(usbIcon);
520                     } else {
521                         jbLabel.setIcon(wifiIcon);
522                     }
523                 }
524                 if (userObject.getChainId() != null && !userObject.getChainId().isEmpty()) {
525                     jbLabel.setText(
526                         userObject.getName() + "[" + userObject.getChainId() + "," + userObject.getSpanId() + ","
527                             + userObject.getParentSpanId() + "]");
528                 } else {
529                     jbLabel.setText(userObject.getName());
530                 }
531             }
532             return jbLabel;
533         }
534     }
535 
536     /**
537      * ColorCellRenderer set the cell color from renderer
538      */
539     public class ColorCellRenderer extends DefaultTableCellRenderer {
540         @Override
getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)541         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
542             int row, int column) {
543             if (value instanceof String) {
544                 setForeground(JBColor.foreground());
545                 super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
546             } else if (value instanceof DetailBean) {
547                 DetailBean bean = (DetailBean) value;
548                 if (column == 1 && bean.getTotalNS() > bean.getMiddleNs() * DistributedCache.getTotalMedianTimes()) {
549                     setForeground(JBColor.RED);
550                 } else if (column == 2
551                     && bean.getDelayNS() > bean.getMiddleDelayNS() * DistributedCache.getDelayMedianTimes()) {
552                     setForeground(JBColor.RED);
553                 } else {
554                     setForeground(JBColor.foreground());
555                 }
556                 super.getTableCellRendererComponent(table,
557                     TimeUtils.getTimeWithUnit(column == 1 ? bean.getTotalNS() : bean.getDelayNS()), isSelected,
558                     hasFocus, row, column);
559             } else {
560                 if (ProfilerLogManager.isDebugEnabled()) {
561                     LOGGER.debug("TableCellRenderer Type does not match");
562                 }
563             }
564             return this;
565         }
566     }
567 }
568