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.component; 17 18 import com.intellij.ui.components.JBViewport; 19 import ohos.devtools.views.trace.fragment.AbstractDataFragment; 20 import ohos.devtools.views.trace.fragment.CpuDataFragment; 21 import ohos.devtools.views.trace.fragment.ruler.CpuFragment; 22 import ohos.devtools.views.trace.fragment.ruler.LeftFragment; 23 import ohos.devtools.views.trace.fragment.ruler.RulerFragment; 24 import ohos.devtools.views.trace.fragment.ruler.TopFragment; 25 import ohos.devtools.views.trace.util.Final; 26 import ohos.devtools.views.trace.util.Utils; 27 28 import javax.swing.JComponent; 29 import java.awt.Graphics; 30 import java.awt.Graphics2D; 31 import java.awt.event.MouseEvent; 32 import java.util.List; 33 import java.util.concurrent.CopyOnWriteArrayList; 34 35 /** 36 * Timeline component 37 * 38 * @since 2021/04/20 12:24 39 */ 40 public final class TimeViewPort extends JBViewport { 41 /** 42 * Initial height of the time axis 43 */ 44 protected static int height = 140; 45 46 /** 47 * Favorite fragment list 48 */ 49 protected final List<AbstractDataFragment> favoriteFragments = new CopyOnWriteArrayList<>(); 50 51 /** 52 * Fragment above 53 */ 54 protected TopFragment topFragment; 55 56 /** 57 * Fragment on the left 58 */ 59 protected LeftFragment leftFragment; 60 61 /** 62 * Cpu fragment 63 */ 64 protected CpuFragment cpuFragment; 65 66 /** 67 * Rule fragment 68 */ 69 protected RulerFragment rulerFragment; 70 71 private final IRangeChangeListener rangeChangeListener; 72 private final IHeightChangeListener heightChangeListener; 73 74 /** 75 * Constructor。 76 * 77 * @param heightChangeListener Altitude change monitoring 78 * @param rangeChangeListener Altitude change monitoring 79 */ TimeViewPort(IHeightChangeListener heightChangeListener, IRangeChangeListener rangeChangeListener)80 public TimeViewPort(IHeightChangeListener heightChangeListener, IRangeChangeListener rangeChangeListener) { 81 this.rangeChangeListener = rangeChangeListener; 82 this.heightChangeListener = heightChangeListener; 83 this.topFragment = new TopFragment(this); 84 this.leftFragment = new LeftFragment(this); 85 this.cpuFragment = new CpuFragment(this, (leftX, rightX, leftNS, rightNS, centerNS) -> { 86 leftFragment.setStartTime(leftNS); 87 rulerFragment.setRange(leftNS, rightNS, centerNS); 88 }); 89 this.rulerFragment = new RulerFragment(this, (startNS, endNS) -> { 90 if (rangeChangeListener != null) { 91 rangeChangeListener.change(startNS, endNS); 92 } 93 }); 94 this.setOpaque(true); 95 setFont(Final.NORMAL_FONT); 96 } 97 98 /** 99 * mouse clicked handler 100 * 101 * @param event event 102 */ mouseClicked(MouseEvent event)103 public void mouseClicked(MouseEvent event) { 104 for (AbstractDataFragment favoriteFragment : favoriteFragments) { 105 favoriteFragment.mouseClicked(event); 106 } 107 rulerFragment.mouseClicked(event); 108 } 109 110 /** 111 * set root height 112 * 113 * @param rootHeight root height 114 */ setRootHeight(int rootHeight)115 public void setRootHeight(int rootHeight) { 116 rulerFragment.setExtendHeight(rootHeight - height); 117 leftFragment.setExtendHeight(rootHeight - height); 118 } 119 120 /** 121 * collect fragment 122 * 123 * @param dataFragment fragment 124 */ favorite(AbstractDataFragment dataFragment)125 public void favorite(AbstractDataFragment dataFragment) { 126 dataFragment.setVisible(false); 127 dataFragment.favoriteGraph.favorite(true); 128 Utils.setY(dataFragment.getRect(), height); 129 height += dataFragment.getRect().height; 130 favoriteFragments.add(dataFragment); 131 if (heightChangeListener != null) { 132 heightChangeListener.change(height); 133 repaint(); 134 } 135 } 136 137 /** 138 * cancel collect fragment 139 * 140 * @param dataFragment fragment 141 */ cancel(AbstractDataFragment dataFragment)142 public void cancel(AbstractDataFragment dataFragment) { 143 if (favoriteFragments.contains(dataFragment)) { 144 dataFragment.setVisible(true); 145 dataFragment.favoriteGraph.favorite(false); 146 height -= dataFragment.getRect().height; 147 favoriteFragments.remove(dataFragment); 148 if (heightChangeListener != null) { 149 heightChangeListener.change(height); 150 repaint(); 151 } 152 } 153 } 154 155 @Override paintComponent(Graphics graphics)156 protected void paintComponent(Graphics graphics) { 157 super.paintComponent(graphics); 158 } 159 160 @Override paint(Graphics graphics)161 public void paint(Graphics graphics) { 162 super.paint(graphics); 163 if (graphics instanceof Graphics2D) { 164 Graphics2D g2 = (Graphics2D) graphics; 165 graphics.setColor(getBackground()); 166 graphics.fillRect(0, 0, getWidth(), height); 167 leftFragment.draw(g2); 168 topFragment.draw(g2); 169 cpuFragment.draw(g2); 170 rulerFragment.draw(g2); 171 for (int index = favoriteFragments.size() - 1; index >= 0; index--) { 172 AbstractDataFragment frg = favoriteFragments.get(index); 173 if (index == favoriteFragments.size() - 1) { 174 Utils.setY(frg.getRect(), height - frg.getRect().height); 175 Utils.setY(frg.getDescRect(), height - frg.getRect().height); 176 Utils.setY(frg.getDataRect(), height - frg.getRect().height); 177 } else { 178 Utils.setY(frg.getRect(), 179 Utils.getY(favoriteFragments.get(index + 1).getRect()) - frg.getRect().height); 180 Utils.setY(frg.getDescRect(), 181 Utils.getY(favoriteFragments.get(index + 1).getRect()) - frg.getRect().height); 182 Utils.setY(frg.getDataRect(), 183 Utils.getY(favoriteFragments.get(index + 1).getRect()) - frg.getRect().height); 184 } 185 frg.draw(g2); 186 } 187 } 188 } 189 190 /** 191 * custom mouse event pressed 192 * 193 * @param event mouse event 194 */ mousePressed(final MouseEvent event)195 public void mousePressed(final MouseEvent event) { 196 Object eventSource = event.getSource(); 197 if (eventSource instanceof JComponent) { 198 JComponent jComponent = (JComponent) eventSource; 199 int scrollY = event.getY() + jComponent 200 .getY(); // subtract the scroll height of the parent node. After scrolling down, y is a negative number. 201 cpuFragment.setSelectX( 202 event.getX() < Utils.getX(cpuFragment.getRect()) ? Utils.getX(cpuFragment.getRect()) : event.getX()); 203 cpuFragment.setSelectY(scrollY); 204 rulerFragment.setSelectX( 205 event.getX() < Utils.getX(rulerFragment.getRect()) ? Utils.getX(rulerFragment.getRect()) 206 : event.getX()); 207 rulerFragment.setSelectY(scrollY); 208 } 209 } 210 211 /** 212 * custom mouse event dragged 213 * 214 * @param event mouse event 215 */ 216 public void mouseDragged(final MouseEvent event) { 217 cpuFragment.mouseDragged(event); 218 } 219 220 /** 221 * custom mouse event moved 222 * 223 * @param event mouse event 224 */ 225 public void mouseMoved(final MouseEvent event) { 226 Object eventSource = event.getSource(); 227 if (eventSource instanceof JComponent) { 228 JComponent jComponent = (JComponent) eventSource; 229 int scrollY = event.getY() + jComponent 230 .getY(); // Subtract the scroll height of the parent node. After scrolling down, y is a negative number. 231 cpuFragment.setSelectX( 232 event.getX() < Utils.getX(cpuFragment.getRect()) ? Utils.getX(cpuFragment.getRect()) : event.getX()); 233 cpuFragment.setSelectY(scrollY); 234 rulerFragment.setSelectX( 235 event.getX() < Utils.getX(rulerFragment.getRect()) ? Utils.getX(rulerFragment.getRect()) 236 : event.getX()); 237 rulerFragment.setSelectY(scrollY); 238 CpuDataFragment.focusCpuData = null; 239 rulerFragment.mouseMoved(event); 240 favoriteFragments.forEach(fragment -> fragment.mouseMoved(event)); 241 } 242 } 243 244 /** 245 * recycle all fragments 246 */ 247 public void recycle() { 248 TimeViewPort.height = 140; 249 if (favoriteFragments != null) { 250 favoriteFragments.forEach(AbstractDataFragment::recycle); 251 favoriteFragments.clear(); 252 } 253 } 254 255 /** 256 * Timeline interval change listener 257 */ 258 @FunctionalInterface 259 public interface IRangeChangeListener { 260 /** 261 * change callback 262 * 263 * @param startNS start time 264 * @param endNS end time 265 */ 266 void change(long startNS, long endNS); 267 } 268 269 /** 270 * Height change listener 271 */ 272 @FunctionalInterface 273 public interface IHeightChangeListener { 274 /** 275 * change callback 276 * 277 * @param height height change 278 */ 279 void change(int height); 280 } 281 } 282