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.ui.JBColor; 19 import com.intellij.util.ui.JBUI; 20 import ohos.devtools.views.trace.util.Utils; 21 22 import javax.swing.SwingUtilities; 23 import javax.swing.border.LineBorder; 24 import java.awt.Graphics; 25 import java.awt.Graphics2D; 26 import java.awt.Point; 27 import java.util.Arrays; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.concurrent.CompletableFuture; 31 import java.util.function.Supplier; 32 33 import static java.util.Objects.nonNull; 34 35 /** 36 * TraceThreadRow 37 * 38 * @since 2021/5/18 13:56 39 */ 40 public class TraceThreadRow<T extends AbstractNode, R extends AbstractNode> extends AbstractRow { 41 private final Integer tid; 42 private IRender render; 43 private List<T> data; 44 private List<R> data2; 45 private T currentData; 46 private R currentData2; 47 private Supplier<List<T>> supplier; 48 private Supplier<List<R>> supplier2; 49 private Long rangeStartNS; 50 private Long rangeEndNS; 51 private Integer x1; 52 private Integer x2; 53 private String threadName; 54 55 /** 56 * structure 57 * 58 * @param name name 59 * @param tid tid 60 */ TraceThreadRow(String name, Integer tid)61 public TraceThreadRow(String name, Integer tid) { 62 super(name + "(Tid:" + tid + ")", true, false); 63 this.tid = tid; 64 this.threadName = name; 65 layout.setComponentConstraints(expandBtn, "split 2,gapleft 15,gaptop 3,gapbottom push"); 66 layout.setComponentConstraints(nameLabel, "gapleft 5,gaptop 3,gapbottom push,w 70!"); 67 loadData(); 68 nameLabelClickConsumer = (event) -> { 69 setSelect(true, null, null); 70 }; 71 } 72 73 /** 74 * getTid 75 * 76 * @return Integer tid 77 */ getTid()78 public Integer getTid() { 79 return tid; 80 } 81 82 /** 83 * setRender 84 * 85 * @param render set current render 86 */ setRender(IRender<T, R> render)87 public void setRender(IRender<T, R> render) { 88 this.render = render; 89 } 90 91 /** 92 * set thread Supplier 93 * 94 * @param supplier set thread supplier 95 */ setSupplier(Supplier<List<T>> supplier)96 public void setSupplier(Supplier<List<T>> supplier) { 97 this.supplier = supplier; 98 } 99 100 /** 101 * set thread function Supplier 102 * 103 * @param supplier set thread function supplier 104 */ setSupplier2(Supplier<List<R>> supplier)105 public void setSupplier2(Supplier<List<R>> supplier) { 106 this.supplier2 = supplier; 107 } 108 109 @Override contentPaint(Graphics graphics)110 public void contentPaint(Graphics graphics) { 111 if (render != null && graphics instanceof Graphics2D) { 112 Graphics2D g2 = (Graphics2D) graphics; 113 if (data != null || data2 != null) { 114 render.paint(g2, data, data2); 115 } else { 116 g2.setColor(JBColor.foreground()); 117 g2.drawString("Loading...", 10, 10 + 12); 118 loadData(); 119 } 120 if (nonNull(x1) && nonNull(x2)) { 121 int xMin = Math.min(x1, x2); 122 int xMax = Math.max(x1, x2); 123 int width = Math.abs(x2 - x1); 124 Common.setAlpha(g2, 0.5F); 125 g2.setColor(JBColor.foreground().darker()); 126 g2.fillRect(0, 0, xMin, getHeight()); 127 g2.fillRect(xMax, 0, getWidth() - xMax, getHeight()); 128 Common.setAlpha(g2, 1F); 129 } 130 } 131 } 132 133 @Override mouseMoveHandler(Point point)134 public void mouseMoveHandler(Point point) { 135 super.mouseMoveHandler(point); 136 if (nonNull(data)) { 137 if (data.stream().filter(it -> contains(it)).anyMatch(it -> it.getRect().contains(point))) { 138 data.stream().filter(it -> contains(it) && it.getRect().contains(point)).forEach(it -> { 139 List<String> stringList = it.getStringList(getTimeByX(Utils.getX(point))); 140 Tip.getInstance().display(content, point, stringList); 141 if (Objects.nonNull(currentData)) { 142 currentData.moveOut(point, content); 143 } 144 it.moveIn(point, content); 145 currentData = it; 146 }); 147 return; 148 } else { 149 if (Objects.nonNull(currentData)) { 150 currentData.moveOut(point, content); 151 } 152 Tip.getInstance().display(content, point, 153 Arrays.asList(getTimeByX(Utils.getX(point)), "Thread:" + threadName, "Tid:" + getTid())); 154 } 155 } 156 if (nonNull(data2)) { 157 if (data2.stream().filter(it -> contains(it)).anyMatch(it -> it.getRect().contains(point))) { 158 data2.stream().filter(it -> contains(it) && it.getRect().contains(point)).forEach(it -> { 159 List<String> stringList = it.getStringList(getTimeByX(Utils.getX(point))); 160 Tip.getInstance().display(content, point, stringList); 161 if (Objects.nonNull(currentData2)) { 162 currentData2.moveOut(point, content); 163 } 164 it.moveIn(point, content); 165 currentData2 = it; 166 }); 167 return; 168 } else { 169 if (Objects.nonNull(currentData2)) { 170 currentData2.moveOut(point, content); 171 } 172 Tip.getInstance().display(content, point, 173 Arrays.asList(getTimeByX(Utils.getX(point)), "Thread:" + threadName, "Tid:" + getTid())); 174 } 175 } 176 } 177 178 @Override loadData()179 public void loadData() { 180 if (!isLoading.get()) { 181 isLoading.set(true); 182 CompletableFuture.runAsync(() -> { 183 if (nonNull(supplier)) { 184 data = supplier.get(); 185 } 186 if (nonNull(supplier2)) { 187 data2 = supplier2.get(); 188 } 189 SwingUtilities.invokeLater(() -> { 190 isLoading.set(false); 191 content.repaint(); 192 }); 193 }, Utils.getPool()).whenComplete((unused, throwable) -> { 194 if (Objects.nonNull(throwable)) { 195 throwable.printStackTrace(); 196 } 197 }); 198 } 199 } 200 201 /** 202 * setSelect 203 * 204 * @param flag flag 205 * @param x1 x1 206 * @param x2 x2 207 */ setSelect(boolean flag, Integer x1, Integer x2)208 public void setSelect(boolean flag, Integer x1, Integer x2) { 209 this.x1 = x1; 210 this.x2 = x2; 211 if (flag) { 212 if (nonNull(x1) && nonNull(x2)) { 213 rangeStartNS = x2ns(Math.min(x1, x2)); 214 rangeEndNS = x2ns(Math.max(x1, x2)); 215 TracePanel.rangeStartNS = rangeStartNS; 216 TracePanel.rangeEndNS = rangeEndNS; 217 } 218 setBorder(new LineBorder(JBUI.CurrentTheme.Link.linkColor(), 1)); 219 setBackground(JBUI.CurrentTheme.Link.linkSecondaryColor()); 220 } else { 221 rangeStartNS = null; 222 rangeEndNS = null; 223 setBorder(null); 224 setBackground(JBColor.background()); 225 } 226 } 227 228 @Override refreshNotify()229 public void refreshNotify() { 230 super.refreshNotify(); 231 if (nonNull(rangeStartNS) && nonNull(rangeEndNS)) { 232 x1 = (int) Common.ns2x(rangeStartNS, getContentBounds()); 233 x2 = (int) Common.ns2x(rangeEndNS, getContentBounds()); 234 } 235 } 236 x2ns(int x1)237 private long x2ns(int x1) { 238 long start = Math.min(startNS, endNS); 239 long end = Math.max(startNS, endNS); 240 long dur = Math.abs(endNS - startNS); 241 if (x1 >= getContentBounds().width) { 242 return end; 243 } 244 if (x1 <= 0) { 245 return start; 246 } 247 double ns = x1 * (dur) * 1.0 / getContentBounds().width; 248 return (long) ns + start; 249 } 250 251 /** 252 * Gets the value of data . 253 * 254 * @return the value of java.util.List<T> 255 */ getData()256 public List<T> getData() { 257 return data; 258 } 259 260 /** 261 * Gets the value of data2 . 262 * 263 * @return the value of java.util.List<R> 264 */ getData2()265 public List<R> getData2() { 266 return data2; 267 } 268 269 /** 270 * interface IRender 271 */ 272 public interface IRender<T, R> { 273 /** 274 * paint 275 * 276 * @param g2 Graphics2D 277 * @param data data 278 * @param data2 data2 279 */ paint(Graphics2D g2, List<T> data, List<R> data2)280 void paint(Graphics2D g2, List<T> data, List<R> data2); 281 } 282 } 283