• 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.fragment.ruler;
17 
18 import ohos.devtools.views.trace.bean.FlagBean;
19 import ohos.devtools.views.trace.component.AnalystPanel;
20 import ohos.devtools.views.trace.util.Final;
21 import ohos.devtools.views.trace.util.TimeUtils;
22 import ohos.devtools.views.trace.util.Utils;
23 
24 import javax.swing.JComponent;
25 import java.awt.AlphaComposite;
26 import java.awt.BasicStroke;
27 import java.awt.Graphics2D;
28 import java.awt.event.MouseEvent;
29 import java.awt.geom.Rectangle2D;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Optional;
33 
34 /**
35  * Timeline zoom size
36  *
37  * @since 2021/4/22 12:25
38  */
39 public class RulerFragment extends AbstractFragment implements FlagBean.IEventListener {
40     private static final BasicStroke BOLD_STORE = new BasicStroke(2);
41 
42     private final long[] scales =
43         new long[] {50, 100, 200, 500, 1_000, 2_000, 5_000, 10_000, 20_000, 50_000, 100_000, 200_000, 500_000,
44             1_000_000, 2_000_000, 5_000_000, 10_000_000, 20_000_000, 50_000_000, 100_000_000, 200_000_000, 500_000_000,
45             1_000_000_000, 2_000_000_000, 5_000_000_000L, 10_000_000_000L, 20_000_000_000L, 50_000_000_000L,
46             100_000_000_000L, 200_000_000_000L, 500_000_000_000L};
47     private long leftNS;
48     private long rightNS;
49 
50     /**
51      * The current time selection range is based on 20 units.
52      * The zoom level obtained by the position in the scales array is 70ns if calculated
53      */
54     private long min;
55 
56     /**
57      * Then in the middle of 50L 100L min=50L
58      * The current time selection range The position in the zoom level scales array based on 20 units.
59      * If calculated, it is 70ns
60      */
61     private long max;
62 
63     // Then it is in the middle of 50L 100L max = 100L
64     private long l20; // The current time selection range is based on 20 units
65 
66     // When the weight ratio is greater than 24.3%, scale=max; otherwise, scale=min schematic diagram
67     private long scale;
68 
69     // min---l20-------max
70     private long centerNS;  // Select from left to right is true
71 
72     // From right to left is false;
73     // when moving from left to right, use the left as the reference,
74     // and fill the cell to the left; when moving from right to left, fill the cell to the right
75     private double weight; // (l20-min)/(max-min) to get the proportion
76     private int extendHeight;
77     private int selectX;
78     private int selectY;
79     private FlagBean focusFlag = new FlagBean();
80     private List<FlagBean> flags = new ArrayList<>();
81     private double realW;
82     private double startX;
83     private IChange changeListener;
84 
85     /**
86      * Constructor
87      *
88      * @param root Parent component
89      * @param listener monitor
90      */
RulerFragment(final JComponent root, final IChange listener)91     public RulerFragment(final JComponent root, final IChange listener) {
92         this.changeListener = listener;
93         this.setRoot(root);
94         getRect().setBounds(200, 94, root.getWidth(), 40);
95         setRange(0, AnalystPanel.getDURATION(), 0);
96     }
97 
98     /**
99      * Set time range
100      *
101      * @param left left
102      * @param right right
103      * @param center center
104      */
setRange(final long left, final long right, final long center)105     public void setRange(final long left, final long right, final long center) {
106         this.centerNS = center;
107         this.leftNS = left;
108         this.rightNS = right;
109         l20 = (this.rightNS - left) / 20;
110         for (int index = 0; index < scales.length; index++) {
111             if (scales[index] > l20) {
112                 if (index > 0) {
113                     min = scales[index - 1];
114                 } else {
115                     min = 0;
116                 }
117                 max = scales[index];
118                 weight = (l20 - min) * 1.0 / (max - min);
119                 if (weight > 0.243) {
120                     scale = max;
121                 } else {
122                     scale = min;
123                 }
124                 break;
125             }
126         }
127         if (scale == 0) {
128             scale = scales[0];
129         }
130         for (FlagBean flag : flags) {
131             Utils.setX(flag.rect, getX(flag.getNs()));
132         }
133         repaint();
134     }
135 
136     /**
137      * clear the flags
138      */
recycle()139     public void recycle() {
140         flags.clear();
141     }
142 
143     /**
144      * Drawing method
145      *
146      * @param graphics graphics
147      */
148     @Override
draw(final Graphics2D graphics)149     public void draw(final Graphics2D graphics) {
150         getRect().width = getRoot().getWidth() - Utils.getX(getRect());
151         graphics.setFont(Final.SMALL_FONT);
152         graphics.setColor(getRoot().getForeground());
153         if (rightNS - leftNS == 0) {
154             return;
155         }
156         if (scale == 0) {
157             setRange(0, AnalystPanel.getDURATION(), 0);
158         }
159         if (changeListener != null) {
160             changeListener.change(leftNS, rightNS);
161         }
162         if (centerNS == leftNS) { // Fill from left to right
163             drawLeft2Right(graphics);
164         }
165         if (centerNS == rightNS) { // Fill from right to left
166             drawRight2Left(graphics);
167         }
168         for (FlagBean flagBean : flags) {
169             graphics.setColor(flagBean.getColor());
170             graphics.setStroke(new BasicStroke(2));
171             int xAxis = Utils.getX(flagBean.rect);
172             if (xAxis > 0) {
173                 graphics.drawLine(xAxis + Utils.getX(getRect()), Utils.getY(getRect()) + getRect().height / 2,
174                     Utils.getX(getRect()) + xAxis, Utils.getY(getRect()) + getRect().height - 2);
175                 graphics.fillRect(xAxis + Utils.getX(getRect()), Utils.getY(getRect()) + getRect().height / 2, 10, 10);
176                 graphics
177                     .fillRect(xAxis + Utils.getX(getRect()) + 7, Utils.getY(getRect()) + getRect().height / 2 + 2, 7,
178                         7);
179                 flagBean.draw(graphics);
180             }
181         }
182         drawFocusFlag(graphics);
183     }
184 
drawRight2Left(Graphics2D graphics)185     private void drawRight2Left(Graphics2D graphics) {
186         graphics.setColor(getRoot().getForeground());
187         final AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
188         graphics.setComposite(alpha);
189         graphics.drawLine(Utils.getX(getRect()), Utils.getY(getRect()), Utils.getX(getRect()) + getRect().width,
190             Utils.getY(getRect()));
191         long tmpNs = rightNS - leftNS;
192         startX = Utils.getX(getRect()) + getRect().width;
193         realW = (scale * getRect().width) / (rightNS - leftNS);
194         String str;
195         while (tmpNs > 0) {
196             str = TimeUtils.getSecondFromNSecond(tmpNs);
197             if (str.isEmpty()) {
198                 str = "0s";
199             }
200             graphics.setColor(getRoot().getForeground());
201             final AlphaComposite alpha50 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f);
202             graphics.setComposite(alpha50);
203             graphics.drawLine((int) startX, Utils.getY(getRect()), (int) startX,
204                 Utils.getY(getRect()) + getRect().height + extendHeight);
205             graphics.setColor(getRoot().getForeground());
206             final AlphaComposite alphaFul = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f);
207             graphics.setComposite(alphaFul);
208             graphics.drawString("+" + str, (int) startX,
209                 Utils.getY(getRect()) + (int) (graphics.getFontMetrics().getStringBounds("+" + str, graphics)
210                     .getHeight()));
211             startX -= realW;
212             tmpNs -= scale;
213         }
214     }
215 
drawLeft2Right(Graphics2D graphics)216     private void drawLeft2Right(Graphics2D graphics) {
217         if (scale == 0) {
218             return;
219         }
220         long tmpNs = 0L;
221         long yu = leftNS % scale;
222         realW = (scale * getRect().width) / (rightNS - leftNS);
223         startX = Utils.getX(getRect());
224         if (yu != 0) {
225             float firstNodeWidth = (float) ((yu * 1.0) / scale * realW);
226             startX += firstNodeWidth;
227             tmpNs += yu;
228             graphics.setColor(getRoot().getForeground());
229             final AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f);
230             graphics.setComposite(alpha);
231             graphics
232                 .drawLine((int) startX, Utils.getY(getRect()), (int) startX, Utils.getY(getRect()) + getRect().height);
233         }
234         graphics.setColor(getRoot().getForeground());
235         graphics.drawLine(Utils.getX(getRect()), Utils.getY(getRect()), Utils.getX(getRect()) + getRect().width,
236             Utils.getY(getRect()));
237         String str;
238         while (tmpNs < rightNS - leftNS) {
239             graphics.setColor(getRoot().getForeground());
240             final AlphaComposite alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f);
241             graphics.setComposite(alpha);
242             graphics.drawLine((int) startX, Utils.getY(getRect()), (int) startX,
243                 Utils.getY(getRect()) + getRect().height + extendHeight);
244             str = TimeUtils.getSecondFromNSecond(tmpNs);
245             if (str.isEmpty()) {
246                 str = "0s";
247             }
248             graphics.setColor(getRoot().getForeground());
249             final AlphaComposite alphaFull = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f);
250             graphics.setComposite(alphaFull);
251             String timS = "+" + str;
252             Rectangle2D bounds = graphics.getFontMetrics(Final.SMALL_FONT).getStringBounds(timS, graphics);
253             graphics.drawString(timS, (int) startX, (int) (Utils.getY(getRect()) + bounds.getHeight()));
254             startX += realW;
255             tmpNs += scale;
256         }
257     }
258 
drawFocusFlag(Graphics2D graphics)259     private void drawFocusFlag(Graphics2D graphics) {
260         if (focusFlag != null && focusFlag.isVisible()) {
261             final int side = 10;
262             graphics.setColor(focusFlag.getColor());
263             graphics.setStroke(BOLD_STORE);
264             graphics.drawLine(Utils.getX(focusFlag.rect) + Utils.getX(getRect()),
265                 Utils.getY(getRect()) + getRect().height / 2, Utils.getX(getRect()) + Utils.getX(focusFlag.rect),
266                 Utils.getY(getRect()) + getRect().height + extendHeight);
267             graphics.fillRect(Utils.getX(focusFlag.rect) + Utils.getX(getRect()),
268                 Utils.getY(getRect()) + getRect().height / 2, side, side);
269             final int offset = 7;
270             graphics.fillRect(Utils.getX(focusFlag.rect) + Utils.getX(getRect()) + offset,
271                 Utils.getY(getRect()) + getRect().height / 2 + 2, side, side);
272         }
273     }
274 
275     /**
276      * Convert x coordinate according to time
277      *
278      * @param ns ns
279      * @return int int
280      */
getX(final long ns)281     public int getX(final long ns) {
282         return (int) ((ns - leftNS) * getRect().width / ((rightNS - leftNS) * 1.0));
283     }
284 
285     /**
286      * Mouse movement event
287      *
288      * @param event event
289      */
mouseMoved(final MouseEvent event)290     public void mouseMoved(final MouseEvent event) {
291         final int leftW = 200;
292         if (selectY > Utils.getY(getRect()) && selectY < Utils.getY(getRect()) + getRect().height
293             && event.getX() >= leftW) {
294             Optional<FlagBean> first = flags.stream().filter(
295                 bean -> event.getX() >= Utils.getX(bean.rect) + Utils.getX(getRect())
296                     && event.getX() <= Utils.getX(bean.rect) + Utils.getX(getRect()) + bean.rect.width).findFirst();
297             if (first.isPresent()) {
298                 focusFlag.setVisible(false);
299             } else {
300                 focusFlag.setVisible(true);
301                 focusFlag.rect
302                     .setLocation(event.getX() - Utils.getX(getRect()), Utils.getY(getRect()) + getRect().height / 2);
303                 focusFlag.rect.width = 17;
304                 focusFlag.rect.height = getRect().height / 2;
305             }
306         } else {
307             focusFlag.setVisible(false);
308         }
309         getRoot().repaint();
310     }
311 
312     /**
313      * Mouse click event
314      *
315      * @param event event
316      */
mouseClicked(final MouseEvent event)317     public void mouseClicked(final MouseEvent event) {
318         if (edgeInspect(event)) {
319             final int leftW = 200;
320             if (selectY > Utils.getY(getRect()) && selectY < Utils.getY(getRect()) + getRect().height
321                 && event.getX() >= leftW) {
322                 Optional<FlagBean> first = flags.stream().filter(
323                     bean -> event.getX() >= Utils.getX(bean.rect) + Utils.getX(getRect())
324                         && event.getX() <= Utils.getX(bean.rect) + Utils.getX(getRect()) + bean.rect.width).findFirst();
325                 if (first.isPresent()) {
326                     FlagBean flagBean = first.get();
327                     flagBean.onClick(event);
328                 } else {
329                     FlagBean flagBean = new FlagBean();
330                     flagBean.root = getRoot();
331                     flagBean.rect.setLocation(event.getX() - Utils.getX(getRect()),
332                         Utils.getY(getRect()) + getRect().height / 2);
333                     flagBean.setEventListener(this);
334                     flagBean.rect.width = 17;
335                     flagBean.rect.height = getRect().height / 2;
336                     flagBean.setNs(
337                         (long) ((rightNS - leftNS) / (getRect().width * 1.0) * Utils.getX(flagBean.rect)) + leftNS);
338                     flagBean.setVisible(true);
339                     flagBean.onClick(event);
340                     flags.add(flagBean);
341                 }
342                 repaint();
343             }
344         }
345     }
346 
347     /**
348      * FlagBean object click event
349      *
350      * @param event event
351      * @param data data
352      */
353     @Override
click(final MouseEvent event, final FlagBean data)354     public void click(final MouseEvent event, final FlagBean data) {
355         if (AnalystPanel.getiFlagClick() != null) {
356             AnalystPanel.getiFlagClick().click(data);
357         }
358     }
359 
360     /**
361      * Loss of focus event
362      *
363      * @param event event
364      * @param data data
365      */
366     @Override
blur(final MouseEvent event, final FlagBean data)367     public void blur(final MouseEvent event, final FlagBean data) {
368     }
369 
370     /**
371      * Get focus event
372      *
373      * @param event event
374      * @param data data
375      */
376     @Override
focus(final MouseEvent event, final FlagBean data)377     public void focus(final MouseEvent event, final FlagBean data) {
378     }
379 
380     /**
381      * Mouse move event
382      *
383      * @param event event
384      * @param data data
385      */
386     @Override
mouseMove(final MouseEvent event, final FlagBean data)387     public void mouseMove(final MouseEvent event, final FlagBean data) {
388     }
389 
390     /**
391      * Remove the flag mark
392      *
393      * @param data data
394      */
395     @Override
delete(final FlagBean data)396     public void delete(final FlagBean data) {
397         flags.removeIf(bean -> bean.getNs() == data.getNs());
398         repaint();
399     }
400 
401     /**
402      * Gets the value of leftNS .
403      *
404      * @return the value of long
405      */
getLeftNS()406     public long getLeftNS() {
407         return leftNS;
408     }
409 
410     /**
411      * Sets the leftNS .
412      * <p>You can use getLeftNS() to get the value of leftNS</p>
413      *
414      * @param ns ns
415      */
setLeftNS(final long ns)416     public void setLeftNS(final long ns) {
417         this.leftNS = ns;
418     }
419 
420     /**
421      * Gets the value of rightNS .
422      *
423      * @return the value of long
424      */
getRightNS()425     public long getRightNS() {
426         return rightNS;
427     }
428 
429     /**
430      * Sets the rightNS .
431      * <p>You can use getRightNS() to get the value of rightNS</p>
432      *
433      * @param ns ns
434      */
setRightNS(final long ns)435     public void setRightNS(final long ns) {
436         this.rightNS = ns;
437     }
438 
439     /**
440      * Gets the value of scale .
441      *
442      * @return the value of long
443      */
getScale()444     public long getScale() {
445         return scale;
446     }
447 
448     /**
449      * Sets the scale .
450      * <p>You can use getScale() to get the value of scale</p>
451      *
452      * @param scale scale
453      */
setScale(final long scale)454     public void setScale(final long scale) {
455         this.scale = scale;
456     }
457 
458     /**
459      * Gets the value of centerNS .
460      *
461      * @return the value of long
462      */
getCenterNS()463     public long getCenterNS() {
464         return centerNS;
465     }
466 
467     /**
468      * Sets the centerNS .
469      * <p>You can use getCenterNS() to get the value of centerNS</p>
470      *
471      * @param ns ns
472      */
setCenterNS(final long ns)473     public void setCenterNS(final long ns) {
474         this.centerNS = ns;
475     }
476 
477     /**
478      * Gets the value of extendHeight .
479      *
480      * @return the value of int
481      */
getExtendHeight()482     public int getExtendHeight() {
483         return extendHeight;
484     }
485 
486     /**
487      * Sets the extendHeight .
488      * <p>You can use getExtendHeight() to get the value of extendHeight</p>
489      *
490      * @param height height
491      */
setExtendHeight(final int height)492     public void setExtendHeight(final int height) {
493         this.extendHeight = height;
494     }
495 
496     /**
497      * Gets the value of selectX .
498      *
499      * @return the value of int
500      */
getSelectX()501     public int getSelectX() {
502         return selectX;
503     }
504 
505     /**
506      * Sets the selectX .
507      * <p>You can use getSelectX() to get the value of selectX</p>
508      *
509      * @param select select
510      */
setSelectX(final int select)511     public void setSelectX(final int select) {
512         this.selectX = select;
513     }
514 
515     /**
516      * Gets the value of selectY .
517      *
518      * @return the value of int
519      */
getSelectY()520     public int getSelectY() {
521         return selectY;
522     }
523 
524     /**
525      * Sets the selectY .
526      * <p>You can use getSelectY() to get the value of selectY</p>
527      *
528      * @param select select
529      */
setSelectY(final int select)530     public void setSelectY(final int select) {
531         this.selectY = select;
532     }
533 
534     /**
535      * time range change listener
536      */
537     public interface IChange {
538         /**
539          * Time range change monitoring
540          *
541          * @param startNS Starting time
542          * @param endNS End Time
543          */
change(long startNS, long endNS)544         void change(long startNS, long endNS);
545     }
546 }
547