• 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.trace;
17 
18 import com.intellij.ui.components.JBPanel;
19 import com.intellij.ui.components.JBScrollPane;
20 import com.intellij.util.Consumer;
21 import net.miginfocom.swing.MigLayout;
22 import ohos.devtools.views.perftrace.bean.PrefFunc;
23 import ohos.devtools.views.trace.util.Utils;
24 
25 import javax.swing.SwingUtilities;
26 import java.awt.Component;
27 import java.awt.Graphics2D;
28 import java.awt.Point;
29 import java.awt.Rectangle;
30 import java.awt.event.MouseAdapter;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseMotionAdapter;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Objects;
38 import java.util.Optional;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.stream.Collectors;
41 
42 /**
43  * TracePanel
44  *
45  * @since 2021/5/13 13:06
46  */
47 public class TracePanel extends JBPanel {
48     /**
49      * DURATION
50      */
51     public static long DURATION = 10_000_000_000L;
52 
53     /**
54      * currentSelectThreadIds
55      */
56     public static List<Integer> currentSelectThreadIds = new ArrayList<>();
57 
58     /**
59      * time shaft start time
60      */
61     public static long START_TS;
62 
63     /**
64      * time shaft end time
65      */
66     public static long END_TS;
67 
68     /**
69      * root TracePanel
70      */
71     public static TracePanel root;
72 
73     /**
74      * current start time
75      */
76     public static long startNS;
77 
78     /**
79      * current end time
80      */
81     public static long endNS;
82 
83     /**
84      * range start time
85      */
86     public static Long rangeStartNS;
87 
88     /**
89      * range end time
90      */
91     public static Long rangeEndNS;
92 
93     private TimeShaft timeShaft;
94     private Ruler ruler;
95     private JBScrollPane scrollPane;
96     private JBPanel contentPanel;
97     private List<Component> componentList;
98     private Point startPoint;
99     private Point endPoint;
100     private List<Component> allComponent;
101 
102     /**
103      * structure function
104      */
TracePanel()105     public TracePanel() {
106         this(true);
107     }
108 
109     /**
110      * TracePanel constructor
111      *
112      * @param showTimeShaft showTimeShaft
113      */
TracePanel(boolean showTimeShaft)114     public TracePanel(boolean showTimeShaft) {
115         timeShaft = new TimeShaft((startNS, endNS, scale) -> {
116             EventDispatcher.dispatcherRange(startNS, endNS, scale);
117             Component[] components = contentPanel.getComponents();
118             for (Component component : components) {
119                 if (component instanceof ExpandPanel) {
120                     ((ExpandPanel) component).refresh(startNS, endNS);
121                 }
122             }
123         }, keyEvent -> timeShaftComplete(), mouseEvent -> timeShaftComplete());
124         contentPanel = new JBPanel();
125         contentPanel.setLayout(new MigLayout("inset 0,wrap 1", "[grow,fill]", "0[]0"));
126         contentPanel.setFocusable(true);
127         contentPanel.setBorder(null);
128         setLayout(new MigLayout("inset 0", "", "0[]0"));
129         scrollPane = new JBScrollPane(contentPanel);
130         scrollPane.setBorder(null);
131         ruler = new Ruler(TracePanel.DURATION);
132         if (showTimeShaft) {
133             add(ruler, "wrap,pushx,growx,h 20!");
134             add(timeShaft, "wrap,pushx,growx,h 50!");
135         }
136         add(scrollPane, "push,grow");
137         setBorder(null);
138         scrollPane.getVerticalScrollBar().addAdjustmentListener(event -> {
139             Component[] components = contentPanel.getComponents();
140             for (Component component : components) {
141                 if (scrollPane.getViewport().getViewRect().intersects(component.getBounds())) {
142                     if (component instanceof ExpandPanel) {
143                         ((ExpandPanel) component).refresh(startNS, endNS);
144                     }
145                 }
146             }
147         });
148         root = this;
149         contentPanelAddListen();
150     }
151 
contentPanelAddListen()152     private void contentPanelAddListen() {
153         contentPanel.addMouseListener(new MouseAdapter() {
154             @Override
155             public void mousePressed(MouseEvent event) {
156                 super.mousePressed(event);
157                 mousePressedThreadRow(event);
158             }
159 
160             @Override
161             public void mouseClicked(MouseEvent event) {
162                 super.mouseClicked(event);
163                 PrefFunc.setSelectedPrefFunc(null);
164                 mouseClickThreadRow(event);
165             }
166 
167             @Override
168             public void mouseExited(MouseEvent event) {
169                 super.mouseExited(event);
170                 Tip.getInstance().hidden();
171             }
172 
173             @Override
174             public void mouseReleased(MouseEvent event) {
175                 super.mouseReleased(event);
176             }
177         });
178         contentPanel.addMouseMotionListener(new MouseMotionAdapter() {
179             @Override
180             public void mouseDragged(MouseEvent event) {
181                 super.mouseDragged(event);
182                 PrefFunc.setSelectedPrefFunc(null);
183                 mouseDraggedThreadRow(event);
184             }
185 
186             @Override
187             public void mouseMoved(MouseEvent event) {
188                 super.mouseMoved(event);
189                 tip(event);
190             }
191         });
192     }
193 
194     /**
195      * range end time
196      *
197      * @return get current contentPanel
198      */
getContentPanel()199     public JBPanel getContentPanel() {
200         return contentPanel;
201     }
202 
timeShaftComplete()203     private void timeShaftComplete() {
204         Arrays.stream(contentPanel.getComponents()).filter(it -> it instanceof ExpandPanel)
205             .map(it -> ((ExpandPanel) it)).filter(it -> !it.isCollapsed()).forEach(
206             it -> Arrays.stream(it.getContent().getComponents()).filter(row -> row instanceof TraceSimpleRow)
207                 .map(row -> ((TraceSimpleRow) row))
208                 .filter(row -> row.getRowName().toLowerCase(Locale.ENGLISH).startsWith("cpu"))
209                 .forEach(row -> row.reload()));
210     }
211 
tip(MouseEvent event)212     private void tip(MouseEvent event) {
213         if (Objects.isNull(allComponent)) {
214             allComponent = Arrays.stream(contentPanel.getComponents()).filter(ExpandPanel.class::isInstance)
215                 .flatMap(component -> Arrays.stream(((ExpandPanel) component).getContent().getComponents()))
216                 .collect(Collectors.toList());
217         }
218         boolean flag = allComponent.stream().anyMatch(it -> {
219             if (it instanceof AbstractRow) {
220                 AbstractRow row = (AbstractRow) it;
221                 Rectangle rectangle = SwingUtilities.convertRectangle(row, row.getContentBounds(), contentPanel);
222                 if (rectangle.contains(event.getPoint())) {
223                     return true;
224                 }
225             }
226             return false;
227         });
228         if (flag) {
229             allComponent.forEach(component -> {
230                 if (component instanceof AbstractRow) {
231                     AbstractRow row = (AbstractRow) component;
232                     Rectangle rectangle = SwingUtilities.convertRectangle(row, row.getContentBounds(), contentPanel);
233                     if (rectangle.contains(event.getPoint())) {
234                         Point point = SwingUtilities.convertPoint(contentPanel, event.getPoint(), row.content);
235                         row.mouseMoveHandler(point);
236                     }
237                 }
238             });
239         } else {
240             Tip.getInstance().hidden();
241         }
242     }
243 
244     /**
245      * structure function
246      *
247      * @param startNS startNS
248      * @param endNS endNS
249      */
setRange(long startNS, long endNS)250     public void setRange(long startNS, long endNS) {
251         Optional.ofNullable(timeShaft).ifPresent(tf -> tf.setRange(startNS, endNS));
252     }
253 
mouseDraggedThreadRow(MouseEvent event)254     private void mouseDraggedThreadRow(MouseEvent event) {
255         endPoint = SwingUtilities.convertPoint(contentPanel, event.getPoint(), componentList.get(0).getParent());
256         int xPoint = Math.min(Utils.getX(startPoint), Utils.getX(endPoint));
257         int yPoint = Math.min(Utils.getY(startPoint), Utils.getY(endPoint));
258         int width = Math.abs(Utils.getX(startPoint) - Utils.getX(endPoint)) == 0 ? 1
259             : Math.abs(Utils.getX(startPoint) - Utils.getX(endPoint));
260         int height = Math.abs(Utils.getY(startPoint) - Utils.getY(endPoint));
261         Rectangle range = new Rectangle(xPoint, yPoint, width, height);
262 
263         for (Component component : componentList) {
264             if (component instanceof TraceThreadRow) {
265                 TraceThreadRow cp = (TraceThreadRow) component;
266                 if (range.intersects(component.getBounds())) {
267                     if (!currentSelectThreadIds.contains(cp.getTid())) {
268                         currentSelectThreadIds.add(cp.getTid());
269                     }
270                     cp.setSelect(true, xPoint - Utils.getX(cp.getContentBounds()),
271                         xPoint + width - Utils.getX(cp.getContentBounds()));
272                 } else {
273                     if (currentSelectThreadIds.contains(cp.getTid())) {
274                         currentSelectThreadIds.remove(cp.getTid());
275                     }
276                     cp.setSelect(false, null, null);
277                 }
278             }
279         }
280         notifySelectRangeChange();
281         Tip.getInstance().hidden();
282     }
283 
mouseClickThreadRow(MouseEvent event)284     private void mouseClickThreadRow(MouseEvent event) {
285         TracePanel.rangeStartNS = null;
286         TracePanel.rangeEndNS = null;
287         AtomicBoolean flag = new AtomicBoolean(false);
288         componentList.forEach(component -> {
289             if (component instanceof TraceThreadRow) {
290                 TraceThreadRow<?, ?> thread = (TraceThreadRow<?, ?>) component;
291                 if (thread.getBounds().contains(startPoint) && Utils.getX(startPoint) < Utils
292                     .getX(thread.getContentBounds())) {
293                     if (!currentSelectThreadIds.contains(thread.getTid())) {
294                         currentSelectThreadIds.add(thread.getTid());
295                     }
296                     thread.setSelect(true, null, null);
297                 } else {
298                     Point point = SwingUtilities.convertPoint(event.getComponent(), event.getPoint(), thread.content);
299                     if ((thread.getData() != null && thread.getData().stream()
300                         .anyMatch(it -> it.getRect().contains(point))) || (thread.getData2() != null && thread
301                         .getData2().stream().anyMatch(it -> it.getRect().contains(point)))) {
302                         if (Objects.nonNull(thread.getData())) {
303                             thread.getData().stream().filter(it -> it.getRect().contains(point)).findFirst()
304                                 .ifPresent(it -> it.onClick(event));
305                         }
306                         if (Objects.nonNull(thread.getData2())) {
307                             thread.getData2().stream().filter(it -> it.getRect().contains(point)).findFirst()
308                                 .ifPresent(it -> it.onClick(event));
309                         }
310                         flag.set(true);
311                     }
312                     currentSelectThreadIds.remove(thread.getTid());
313                     thread.setSelect(false, null, null);
314                 }
315             }
316         });
317         if (!flag.get()) {
318             notifySelectRangeChange();
319         }
320     }
321 
notifySelectRangeChange()322     private void notifySelectRangeChange() {
323         if (Objects.isNull(TracePanel.rangeStartNS) && Objects.isNull(TracePanel.rangeEndNS)) {
324             EventDispatcher.dispatcherThreadRange(TracePanel.startNS, TracePanel.endNS, currentSelectThreadIds);
325         } else {
326             long st = TracePanel.rangeStartNS < TracePanel.startNS ? TracePanel.startNS : TracePanel.rangeStartNS;
327             long et = TracePanel.rangeEndNS > TracePanel.endNS ? TracePanel.endNS : TracePanel.rangeEndNS;
328             EventDispatcher.dispatcherThreadRange(st, et, currentSelectThreadIds);
329         }
330     }
331 
mousePressedThreadRow(MouseEvent event)332     private void mousePressedThreadRow(MouseEvent event) {
333         if (Objects.isNull(componentList)) {
334             componentList = Arrays.stream(contentPanel.getComponents()).filter(component -> {
335                 if (component instanceof ExpandPanel) {
336                     ExpandPanel ep = (ExpandPanel) component;
337                     if (!ep.getTitle().startsWith("Display") && !ep.getTitle().startsWith("CPU")) {
338                         return true;
339                     }
340                 }
341                 return false;
342             }).flatMap(component -> Arrays.stream(((ExpandPanel) component).getContent().getComponents()))
343                 .collect(Collectors.toList());
344         }
345         if (componentList.size() > 0) {
346             startPoint = SwingUtilities.convertPoint(contentPanel, event.getPoint(), componentList.get(0).getParent());
347         }
348     }
349 
350     /**
351      * paint the TimeShaft
352      *
353      * @param consumer consumer
354      */
paintTimeShaft(Consumer<Graphics2D> consumer)355     public void paintTimeShaft(Consumer<Graphics2D> consumer) {
356         timeShaft.setTimeShaftConsumer(consumer);
357         timeShaft.repaint();
358     }
359 
360     /**
361      * get the TimeShaft
362      *
363      * @return timeShaft timeShaft
364      */
getTimeShaft()365     public TimeShaft getTimeShaft() {
366         return timeShaft;
367     }
368 
369     /**
370      * get the TimeRuler
371      *
372      * @return ruler timeRuler
373      */
getRuler()374     public Ruler getRuler() {
375         return ruler;
376     }
377 }
378