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