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.trace; 17 18 import com.intellij.icons.AllIcons; 19 import com.intellij.ui.JBColor; 20 import com.intellij.ui.components.JBLabel; 21 import com.intellij.ui.components.JBPanel; 22 import com.intellij.util.Consumer; 23 import net.miginfocom.swing.MigLayout; 24 import ohos.devtools.views.applicationtrace.bean.Cpu; 25 import ohos.devtools.views.applicationtrace.bean.CpuFreq; 26 import ohos.devtools.views.applicationtrace.bean.Frame; 27 import ohos.devtools.views.applicationtrace.bean.Func; 28 import ohos.devtools.views.applicationtrace.bean.Thread; 29 import ohos.devtools.views.applicationtrace.bean.VsyncAppBean; 30 import ohos.devtools.views.applicationtrace.util.TimeUtils; 31 import ohos.devtools.views.distributed.bean.DistributedFuncBean; 32 import ohos.devtools.views.distributed.util.DistributedCommon; 33 import ohos.devtools.views.perftrace.bean.PrefFunc; 34 35 import javax.swing.Icon; 36 import javax.swing.JButton; 37 import java.awt.Color; 38 import java.awt.Dimension; 39 import java.awt.Graphics; 40 import java.awt.Point; 41 import java.awt.Rectangle; 42 import java.awt.event.ComponentAdapter; 43 import java.awt.event.ComponentEvent; 44 import java.awt.event.MouseEvent; 45 import java.util.Objects; 46 import java.util.concurrent.atomic.AtomicBoolean; 47 48 /** 49 * AbstractRow 50 * 51 * @since 2021/5/20 15:50 52 */ 53 public abstract class AbstractRow extends JBPanel { 54 /** 55 * current row content JBPanel 56 */ 57 public JBPanel content; 58 59 /** 60 * current row startNS 61 */ 62 protected long startNS; 63 64 /** 65 * current row endNS 66 */ 67 protected long endNS; 68 69 /** 70 * current row isLoading 71 */ 72 protected AtomicBoolean isLoading = new AtomicBoolean(false); 73 74 /** 75 * current row MigLayout layout 76 */ 77 protected MigLayout layout = new MigLayout("inset 0", "0[110!,left]0[grow,fill]0", "0[grow,fill,center]0"); 78 79 /** 80 * current row JBLabel nameLabel 81 */ 82 protected JBLabel nameLabel = new JBLabel(); 83 84 /** 85 * current row MouseEvent Consumer nameLabelClickConsumer 86 */ 87 protected Consumer<MouseEvent> nameLabelClickConsumer; 88 89 /** 90 * current row JButton expandBtn 91 */ 92 protected JButton expandBtn = new JButton(); 93 94 private Icon myExpandIcon = AllIcons.General.ArrowRight; 95 private Icon myCollapseIcon = AllIcons.General.ArrowDown; 96 private boolean myIsInitialized; 97 private boolean myIsCollapsed; 98 private int threadHeight = 14; 99 private int funcHeight = 20; 100 private int maxDept = 1; 101 private final String rowName; 102 private final int collapsedNodeHeight = 1; 103 104 /** 105 * fresh the Notify data by startNS and endNS 106 * 107 * @param name name 108 * @param hasExpand hasExpand 109 * @param defaultExpand defaultExpand 110 */ AbstractRow(String name, boolean hasExpand, boolean defaultExpand)111 public AbstractRow(String name, boolean hasExpand, boolean defaultExpand) { 112 this.rowName = name; 113 setLayout(layout); 114 expandBtn.setBorderPainted(false); 115 expandBtn.setContentAreaFilled(false); 116 expandBtn.setBackground(new Color(0, 0, 0, 0)); 117 expandBtn.setMaximumSize(new Dimension(myExpandIcon.getIconWidth(), myExpandIcon.getIconHeight())); 118 expandBtn.setFocusable(true); 119 nameLabel.setText(name); 120 if (hasExpand) { 121 add(expandBtn, "split 2,w 5!,gapleft 15,gapright 5"); 122 add(nameLabel, "gapleft 10,w 80!"); 123 } else { 124 add(nameLabel, "gapleft 15,w 90!"); 125 } 126 content = new JBPanel() { 127 @Override 128 protected void paintComponent(Graphics graphics) { 129 super.paintComponent(graphics); 130 contentPaint(graphics); 131 } 132 }; 133 content.setBackground(JBColor.background().darker()); 134 add(content, "growx,pushx"); 135 setCollapsed(!defaultExpand); 136 expandBtn.addActionListener(event -> setCollapsed(!myIsCollapsed)); 137 } 138 139 /** 140 * isCollapsed 141 * 142 * @return isCollapsed 143 */ isCollapsed()144 public boolean isCollapsed() { 145 return myIsCollapsed; 146 } 147 148 /** 149 * getStartNS 150 * 151 * @return long startNS 152 */ getStartNS()153 public long getStartNS() { 154 return startNS; 155 } 156 157 /** 158 * getEndNS 159 * 160 * @return long endNS 161 */ getEndNS()162 public long getEndNS() { 163 return endNS; 164 } 165 166 /** 167 * get Row Name 168 * 169 * @return String rowName 170 */ getRowName()171 public String getRowName() { 172 return rowName; 173 } 174 175 /** 176 * fresh the row data by startNS and endNS 177 * 178 * @param startNS startNS 179 * @param endNS endNS 180 */ refresh(long startNS, long endNS)181 public void refresh(long startNS, long endNS) { 182 this.startNS = startNS; 183 this.endNS = endNS; 184 content.repaint(); 185 refreshNotify(); 186 } 187 188 /** 189 * fresh the Notify data by startNS and endNS 190 */ refreshNotify()191 public void refreshNotify() { 192 long time = endNS + startNS; 193 } 194 195 /** 196 * fresh the Notify data by startNS and endNS 197 * 198 * @return return the Rectangle from the content 199 */ getContentBounds()200 public Rectangle getContentBounds() { 201 return content.getBounds(); 202 } 203 204 /** 205 * get the max height 206 * 207 * @return return the max height 208 */ evalHeight()209 protected int evalHeight() { 210 int maxHeight = maxDept * getFuncHeight() + getFuncHeight(); 211 if (maxHeight < 30) { 212 maxHeight = 30; 213 } 214 return maxHeight; 215 } 216 217 /** 218 * Set whether to expand 219 * 220 * @param isCollapsed isCollapsed 221 */ setCollapsed(boolean isCollapsed)222 public void setCollapsed(boolean isCollapsed) { 223 setCollapsed(isCollapsed, null); 224 } 225 226 /** 227 * Set whether to expand 228 * 229 * @param isCollapsed isCollapsed 230 * @param finish null 231 */ setCollapsed(boolean isCollapsed, Consumer<Rectangle> finish)232 public void setCollapsed(boolean isCollapsed, Consumer<Rectangle> finish) { 233 int defHeight = getBounds().height; 234 if (Objects.nonNull(finish)) { 235 addComponentListener(new ComponentAdapter() { 236 @Override 237 public void componentResized(ComponentEvent event) { 238 super.componentResized(event); 239 if (defHeight != event.getComponent().getBounds().height) { 240 finish.consume(event.getComponent().getBounds()); 241 } 242 } 243 }); 244 } 245 try { 246 if (isCollapsed) { 247 setFuncHeight(collapsedNodeHeight); 248 setThreadHeight(collapsedNodeHeight); 249 } else { 250 setFuncHeight(20); 251 setThreadHeight(14); 252 } 253 if (getParent() != null && getParent().getLayout() instanceof MigLayout) { 254 MigLayout migLayout = (MigLayout) getParent().getLayout(); 255 migLayout.setComponentConstraints(this, "growx,pushx,h " + evalHeight() + "!"); 256 } 257 myIsCollapsed = isCollapsed; 258 Icon icon = myIsCollapsed ? myExpandIcon : myCollapseIcon; 259 if (icon != null) { 260 expandBtn.setIcon(icon); 261 expandBtn.setBorder(null); 262 expandBtn.setBorderPainted(false); 263 } 264 if (isCollapsed) { 265 expandBtn.requestFocusInWindow(); 266 expandBtn.setSelected(true); 267 } else { 268 content.requestFocusInWindow(); 269 } 270 revalidate(); 271 repaint(); 272 } finally { 273 myIsInitialized = true; 274 } 275 } 276 277 /** 278 * get the threadHeight 279 * 280 * @return return the current threadHeight 281 */ getThreadHeight()282 public int getThreadHeight() { 283 return threadHeight; 284 } 285 286 /** 287 * set the threadHeight 288 * 289 * @param threadHeight threadHeight 290 */ setThreadHeight(int threadHeight)291 public void setThreadHeight(int threadHeight) { 292 this.threadHeight = threadHeight; 293 } 294 295 /** 296 * get the FuncHeight 297 * 298 * @return return the current FuncHeight 299 */ getFuncHeight()300 public int getFuncHeight() { 301 return funcHeight; 302 } 303 304 /** 305 * set the FuncHeight 306 * 307 * @param funcHeight funcHeight 308 */ setFuncHeight(int funcHeight)309 public void setFuncHeight(int funcHeight) { 310 this.funcHeight = funcHeight; 311 } 312 313 /** 314 * get the Name 315 * 316 * @return return the current nameLabel text 317 */ getName()318 public String getName() { 319 return nameLabel.getText(); 320 } 321 322 /** 323 * contentPaint paint content 324 * 325 * @param graphics graphics 326 */ contentPaint(Graphics graphics)327 public abstract void contentPaint(Graphics graphics); 328 329 /** 330 * load data 331 */ loadData()332 public abstract void loadData(); 333 334 /** 335 * set the Point 336 * 337 * @param point point 338 */ mouseMoveHandler(Point point)339 public void mouseMoveHandler(Point point) { 340 super.getName(); 341 } 342 343 /** 344 * get the time by x Coordinates 345 * 346 * @param xCoordinates xCoordinates 347 * @return time string 348 */ getTimeByX(int xCoordinates)349 public String getTimeByX(int xCoordinates) { 350 double width = (getEndNS() - getStartNS()) * xCoordinates * 1.0 / getContentBounds().getWidth(); 351 return TimeUtils.getTimeFormatString((long) width + getStartNS()); 352 } 353 354 /** 355 * get the func is in this row 356 * 357 * @param func func 358 * @return return the row is contains func 359 */ contains(Func func)360 public boolean contains(Func func) { 361 return func.getStartTs() + func.getDur() > getStartNS() && func.getStartTs() < getEndNS(); 362 } 363 364 /** 365 * get the threadData is in this row 366 * 367 * @param threadData threadData 368 * @return return the row is contains threadData 369 */ contains(Thread threadData)370 public boolean contains(Thread threadData) { 371 return threadData.getStartTime() + threadData.getDuration() > getStartNS() 372 && threadData.getStartTime() < getEndNS(); 373 } 374 375 /** 376 * get the cpu is in this row 377 * 378 * @param cpu cpu 379 * @return return the row is contains Cpu 380 */ contains(Cpu cpu)381 public boolean contains(Cpu cpu) { 382 return cpu.getStartTime() + cpu.getDuration() > getStartNS() && cpu.getStartTime() < getEndNS(); 383 } 384 385 /** 386 * get the CpuFreq is in this row 387 * 388 * @param item item 389 * @return return the row is contains CpuFreq 390 */ contains(CpuFreq item)391 public boolean contains(CpuFreq item) { 392 return item.getStartTime() + item.getDuration() > getStartNS() && item.getStartTime() < getEndNS(); 393 } 394 395 /** 396 * get the VsyncAppBean is in this row 397 * 398 * @param item item 399 * @return return the row is contains VsyncAppBean 400 */ contains(VsyncAppBean item)401 public boolean contains(VsyncAppBean item) { 402 return item.getStartTime() + item.getDuration() > getStartNS() && item.getStartTime() < getEndNS(); 403 } 404 405 /** 406 * get the Frame is in this row 407 * 408 * @param item item 409 * @return return the row is contains Frame 410 */ contains(Frame item)411 public boolean contains(Frame item) { 412 return item.getStartNs() + item.getDur() > getStartNS() && item.getStartNs() < getEndNS(); 413 } 414 415 /** 416 * get the PrefFunc is in this row 417 * 418 * @param func func 419 * @return return the row is contains PrefFunc 420 */ contains(PrefFunc func)421 public boolean contains(PrefFunc func) { 422 return func.getEndTs() > getStartNS() && func.getStartTs() < getEndNS(); 423 } 424 425 /** 426 * get the PrefFunc is in this row 427 * 428 * @param func func 429 * @return return the row is contains PrefFunc 430 */ contains(DistributedFuncBean func)431 public boolean contains(DistributedFuncBean func) { 432 return func.getEndTs() > getStartNS() && func.getStartTs() < getEndNS(); 433 } 434 435 /** 436 * get the Object is in this row 437 * 438 * @param obj obj 439 * @return return the row is contains obj 440 */ contains(Object obj)441 public boolean contains(Object obj) { 442 if (obj instanceof PrefFunc) { 443 return contains((PrefFunc) obj); 444 } else if (obj instanceof CpuFreq) { 445 return contains((CpuFreq) obj); 446 } else if (obj instanceof Cpu) { 447 return contains((Cpu) obj); 448 } else if (obj instanceof Thread) { 449 return contains((Thread) obj); 450 } else if (obj instanceof Func) { 451 return contains((Func) obj); 452 } else if (obj instanceof VsyncAppBean) { 453 return contains((VsyncAppBean) obj); 454 } else if (obj instanceof Frame) { 455 return contains((Frame) obj); 456 } else if (obj instanceof DistributedFuncBean) { 457 return contains((DistributedFuncBean) obj); 458 } else { 459 return false; 460 } 461 } 462 463 /** 464 * get the Rectangle by Cpu node 465 * 466 * @param node node 467 * @param padding Rectangle padding 468 * @return return Rectangle 469 */ getRectByNode(Cpu node, int padding)470 public Rectangle getRectByNode(Cpu node, int padding) { 471 double x1; 472 double x2; 473 if (node.getStartTime() < getStartNS()) { 474 x1 = 0; 475 } else { 476 x1 = Common.ns2x(node.getStartTime(), getContentBounds()); 477 } 478 if (node.getStartTime() + node.getDuration() > getEndNS()) { 479 x2 = getContentBounds().getWidth(); 480 } else { 481 x2 = Common.ns2x(node.getStartTime() + node.getDuration(), getContentBounds()); 482 } 483 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 484 return new Rectangle((int) x1, (int) (getContentBounds().getY() + padding), (int) getV, 485 (int) (getContentBounds().getHeight() - padding * 2)); 486 } 487 488 /** 489 * get the Rectangle by Thread node 490 * 491 * @param node node 492 * @param height Rectangle height 493 * @return return Rectangle 494 */ getRectByNode(Thread node, int height)495 public Rectangle getRectByNode(Thread node, int height) { 496 double x1; 497 double x2; 498 if (node.getStartTime() < getStartNS()) { 499 x1 = Common.ns2x(getStartNS(), getContentBounds()); 500 } else { 501 x1 = Common.ns2x(node.getStartTime(), getContentBounds()); 502 } 503 if (node.getStartTime() + node.getDuration() > getEndNS()) { 504 x2 = Common.ns2x(getEndNS(), getContentBounds()); 505 } else { 506 x2 = Common.ns2x(node.getStartTime() + node.getDuration(), getContentBounds()); 507 } 508 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 509 return new Rectangle((int) x1, (int) (getContentBounds().getY()), (int) getV, height); 510 } 511 512 /** 513 * get the Rectangle by PrefFunc node 514 * 515 * @param node node 516 * @param height Rectangle height 517 * @param paddingTop Rectangle paddingTop 518 * @return return Rectangle 519 */ getRectByNode(PrefFunc node, int paddingTop, int height)520 public Rectangle getRectByNode(PrefFunc node, int paddingTop, int height) { 521 double x1; 522 double x2; 523 if (node.getStartTs() < getStartNS()) { 524 x1 = Common.ns2x(getStartNS(), getContentBounds()); 525 } else { 526 x1 = Common.ns2x(node.getStartTs(), getContentBounds()); 527 } 528 if (node.getEndTs() > getEndNS()) { 529 x2 = Common.ns2x(getEndNS(), getContentBounds()); 530 } else { 531 x2 = Common.ns2x(node.getEndTs(), getContentBounds()); 532 } 533 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 534 return new Rectangle((int) x1, (int) (getContentBounds().getY() + node.getDepth() * height + paddingTop), 535 (int) getV, height); 536 } 537 538 /** 539 * get the Rectangle by Func node 540 * 541 * @param node node 542 * @param height Rectangle height 543 * @param paddingTop Rectangle paddingTop 544 * @return return Rectangle 545 */ getRectByNode(Func node, int paddingTop, int height)546 public Rectangle getRectByNode(Func node, int paddingTop, int height) { 547 double x1; 548 double x2; 549 if (node.getStartTs() < getStartNS()) { 550 x1 = Common.ns2x(getStartNS(), getContentBounds()); 551 } else { 552 x1 = Common.ns2x(node.getStartTs(), getContentBounds()); 553 } 554 if (node.getStartTs() + node.getDur() > getEndNS()) { 555 x2 = Common.ns2x(getEndNS(), getContentBounds()); 556 } else { 557 x2 = Common.ns2x(node.getStartTs() + node.getDur(), getContentBounds()); 558 } 559 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 560 return new Rectangle((int) x1, (int) (getContentBounds().getY() + node.getDepth() * height + paddingTop), 561 (int) getV, height); 562 } 563 564 /** 565 * get the Rectangle by FuncBean node 566 * 567 * @param node node 568 * @param height Rectangle height 569 * @param paddingTop Rectangle paddingTop 570 * @return return Rectangle 571 */ getRectByNode(DistributedFuncBean node, int paddingTop, int height)572 public Rectangle getRectByNode(DistributedFuncBean node, int paddingTop, int height) { 573 double x1; 574 double x2; 575 if (node.getStartTs() < getStartNS()) { 576 x1 = DistributedCommon.ns2x(getStartNS(), getContentBounds()); 577 } else { 578 x1 = DistributedCommon.ns2x(node.getStartTs(), getContentBounds()); 579 } 580 if (node.getStartTs() + node.getDur() > getEndNS()) { 581 x2 = DistributedCommon.ns2x(getEndNS(), getContentBounds()); 582 } else { 583 x2 = DistributedCommon.ns2x(node.getStartTs() + node.getDur(), getContentBounds()); 584 } 585 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 586 return new Rectangle((int) x1, (int) (getContentBounds().getY() + node.getDepth() * height + paddingTop), 587 (int) getV, height); 588 } 589 590 /** 591 * get the Rectangle by CpuFreq node 592 * 593 * @param node node 594 * @return return Rectangle 595 */ getRectByNode(CpuFreq node)596 public Rectangle getRectByNode(CpuFreq node) { 597 double x1; 598 double x2; 599 if (node.getStartTime() < getStartNS()) { 600 x1 = Common.ns2x(getStartNS(), getContentBounds()); 601 } else { 602 x1 = Common.ns2x(node.getStartTime(), getContentBounds()); 603 } 604 if (node.getStartTime() + node.getDuration() > getEndNS()) { 605 x2 = Common.ns2x(getEndNS(), getContentBounds()); 606 } else { 607 x2 = Common.ns2x(node.getStartTime() + node.getDuration(), getContentBounds()); 608 } 609 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 610 return new Rectangle((int) x1, (int) (getContentBounds().getY()), (int) getV, getContentBounds().height); 611 } 612 613 /** 614 * get the Rectangle by VsyncAppBean node 615 * 616 * @param node node 617 * @return return Rectangle 618 */ getRectByNode(VsyncAppBean node)619 public Rectangle getRectByNode(VsyncAppBean node) { 620 double x1; 621 double x2; 622 if (node.getStartTime() < getStartNS()) { 623 x1 = Common.ns2x(getStartNS(), getContentBounds()); 624 } else { 625 x1 = Common.ns2x(node.getStartTime(), getContentBounds()); 626 } 627 if (node.getStartTime() + node.getDuration() > getEndNS()) { 628 x2 = Common.ns2x(getEndNS(), getContentBounds()); 629 } else { 630 x2 = Common.ns2x(node.getStartTime() + node.getDuration(), getContentBounds()); 631 } 632 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 633 return new Rectangle((int) x1, (int) (getContentBounds().getY()), (int) getV, getContentBounds().height); 634 } 635 636 /** 637 * get the Rectangle by Frame node 638 * 639 * @param node node 640 * @param height Rectangle height 641 * @return return Rectangle 642 */ getRectByNode(Frame node, int height)643 public Rectangle getRectByNode(Frame node, int height) { 644 double x1; 645 double x2; 646 if (node.getStartNs() < getStartNS()) { 647 x1 = Common.ns2x(getStartNS(), getContentBounds()); 648 } else { 649 x1 = Common.ns2x(node.getStartNs(), getContentBounds()); 650 } 651 if (node.getStartNs() + node.getDur() > getEndNS()) { 652 x2 = Common.ns2x(getEndNS(), getContentBounds()); 653 } else { 654 x2 = Common.ns2x(node.getStartNs() + node.getDur(), getContentBounds()); 655 } 656 double getV = x2 - x1 <= 1 ? 1 : x2 - x1; 657 return new Rectangle((int) x1, (int) (getContentBounds().getY() + 5), (int) getV, height); 658 } 659 660 /** 661 * get the maxDept 662 * 663 * @return maxDept maxDept 664 */ getMaxDept()665 public int getMaxDept() { 666 return this.maxDept; 667 } 668 669 /** 670 * set the maxDept 671 * 672 * @param maxDept maxDept 673 */ setMaxDept(int maxDept)674 public void setMaxDept(int maxDept) { 675 this.maxDept = maxDept; 676 } 677 } 678