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 ohos.devtools.views.trace.bean.TabThreadStatesBean; 19 import ohos.devtools.views.trace.util.Final; 20 import ohos.devtools.views.trace.util.Utils; 21 22 import javax.swing.JPanel; 23 import java.awt.Color; 24 import java.awt.Graphics; 25 import java.awt.Graphics2D; 26 import java.awt.Rectangle; 27 import java.awt.RenderingHints; 28 import java.awt.event.MouseAdapter; 29 import java.awt.event.MouseEvent; 30 import java.awt.event.MouseMotionListener; 31 import java.math.BigDecimal; 32 import java.util.ArrayList; 33 import java.util.Comparator; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.stream.Collectors; 37 38 /** 39 * StackBar 40 * 41 * @since 2021/5/27 12:03 42 */ 43 public class StackBar extends JPanel { 44 private List<StateValue> source = new ArrayList<>(); 45 private long totalWallDuration; 46 private StateValue current; 47 private BigDecimal charW = BigDecimal.valueOf(getFontMetrics(getFont().deriveFont(11.0f)).charWidth('a') - 0.2); 48 private int drawX = 0; 49 50 /** 51 * structure function 52 */ StackBar()53 public StackBar() { 54 addMouseMotionListener(new MouseMotionListener() { 55 @Override 56 public void mouseDragged(final MouseEvent event) { 57 } 58 59 @Override 60 public void mouseMoved(final MouseEvent event) { 61 for (int index = 0, size = source.size(); index < size; index++) { 62 if (Utils.pointInRect(source.get(index).drawRect, event.getX(), event.getY())) { 63 if (current != source.get(index)) { 64 current = source.get(index); 65 repaint(); 66 } 67 break; 68 } 69 } 70 } 71 }); 72 addMouseListener(new MouseAdapter() { 73 @Override 74 public void mouseExited(final MouseEvent event) { 75 super.mouseMoved(event); 76 current = null; 77 } 78 }); 79 } 80 81 /** 82 * set data source 83 * 84 * @param data data 85 */ setSource(final List<TabThreadStatesBean> data)86 public void setSource(final List<TabThreadStatesBean> data) { 87 source.clear(); 88 if (data != null) { 89 Map<String, List<TabThreadStatesBean>> collect = 90 data.stream().collect(Collectors.groupingBy(TabThreadStatesBean::getState)); 91 for (String state : collect.keySet()) { 92 long sum = 0L; 93 for (TabThreadStatesBean bean : collect.get(state)) { 94 sum += bean.getWallDuration(); 95 } 96 if ("".equals(state)) { 97 totalWallDuration = sum; 98 } else { 99 StateValue sv = new StateValue(); 100 sv.color = getStateColor(state); 101 sv.state = Utils.getEndState(state) + " : " + Utils.transformTimeToMs(sum) + "ms"; 102 sv.value = sum; 103 source.add(sv); 104 } 105 } 106 source = source.stream().sorted(Comparator.comparing(StateValue::getValue)).collect(Collectors.toList()); 107 } 108 repaint(); 109 } 110 111 @Override paint(final Graphics graphics)112 public void paint(final Graphics graphics) { 113 drawX = 0; 114 if (graphics instanceof Graphics2D) { 115 ((Graphics2D) graphics) 116 .setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 117 } 118 for (StateValue sv : source) { 119 graphics.setFont(getFont().deriveFont(11.0f)); 120 graphics.setColor(sv.color); 121 int trueW; 122 if (sv == current && sv.drawRect.width < charW.doubleValue() * sv.state.length()) { 123 trueW = (int) (charW.doubleValue() * sv.state.length() + 1); 124 } else { 125 trueW = (int) ((sv.value * 1.0 / totalWallDuration) * getWidth() + 1); 126 } 127 if (trueW + drawX > getWidth()) { 128 trueW = getWidth() - drawX - 5; 129 } 130 graphics.fillRect(drawX, 0, trueW, getHeight()); 131 sv.drawRect = new Rectangle(drawX, 0, trueW, getHeight()); 132 133 // 计算单个字符所占宽度 134 if (sv.drawRect.width > charW.doubleValue()) { 135 if (sv.state.startsWith("Sleeping")) { 136 graphics.setColor(Color.gray); 137 } else { 138 graphics.setColor(Color.white); 139 } 140 int chars = (int) (sv.drawRect.width / charW.doubleValue()); 141 if (chars < sv.state.length()) { 142 graphics.drawString(sv.state.substring(0, chars), drawX + 1, 13); 143 } else { 144 graphics.drawString(sv.state, drawX + 1, 13); 145 } 146 } 147 drawX = drawX + trueW + 1; 148 } 149 } 150 getStateColor(String state)151 private Color getStateColor(String state) { 152 switch (state) { 153 case "Running": 154 return new Color(Final.RUNNING_COLOR); 155 case "D": 156 return new Color(Final.UNINTERRUPTIBLE_SLEEP_COLOR); 157 case "S": 158 return new Color(Final.S_COLOR); 159 case "R": 160 case "R+": 161 default: 162 return new Color(Final.R_COLOR); 163 } 164 } 165 166 private class StateValue { 167 private String state; 168 private long value; 169 private Color color; 170 private Rectangle drawRect; 171 getValue()172 private long getValue() { 173 return value; 174 } 175 } 176 } 177