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.layout.chartview.memory.javaagent; 17 18 import com.intellij.ui.JBColor; 19 import com.intellij.ui.components.JBLabel; 20 import com.intellij.ui.components.JBPanel; 21 import com.intellij.ui.components.JBTabbedPane; 22 import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; 23 import com.intellij.ui.treeStructure.treetable.TreeTableModel; 24 import net.miginfocom.swing.MigLayout; 25 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager; 26 import ohos.devtools.services.memory.agentbean.AgentHeapBean; 27 import ohos.devtools.views.common.ColorConstants; 28 import ohos.devtools.views.common.LayoutConstants; 29 import ohos.devtools.views.common.UtConstant; 30 import ohos.devtools.views.common.customcomp.CustomComboBox; 31 import ohos.devtools.views.common.customcomp.CustomJBComboBoxUI; 32 import ohos.devtools.views.common.customcomp.CustomJBTextField; 33 import ohos.devtools.views.common.treetable.ExpandTreeTable; 34 import ohos.devtools.views.layout.chartview.memory.MemoryItemView; 35 import org.apache.logging.log4j.LogManager; 36 import org.apache.logging.log4j.Logger; 37 38 import javax.swing.BorderFactory; 39 import javax.swing.SwingUtilities; 40 import javax.swing.event.ChangeEvent; 41 import javax.swing.event.ChangeListener; 42 import javax.swing.event.DocumentEvent; 43 import javax.swing.event.DocumentListener; 44 import javax.swing.tree.DefaultMutableTreeNode; 45 import java.awt.BorderLayout; 46 import java.awt.Dimension; 47 import java.awt.Font; 48 import java.awt.event.FocusEvent; 49 import java.awt.event.FocusListener; 50 import java.util.ArrayList; 51 import java.util.List; 52 import java.util.stream.Collectors; 53 54 import static ohos.devtools.views.common.Constant.IS_DEVELOP_MODE; 55 56 /** 57 * MemoryTreeTablePanel 58 * 59 * @since : 2021/10/25 60 */ 61 public class MemoryTreeTablePanel extends JBPanel { 62 private static final Logger LOGGER = LogManager.getLogger(MemoryTreeTablePanel.class); 63 private static final int FEATURES_WIDTH = 1520; 64 65 private static final int NUM_5 = 5; 66 private static final int NUM_8 = 8; 67 68 private MemoryAgentHeapInfoPanel memoryAgentHeapInfoPanel; 69 70 /** 71 * MemoryTreeTablePanel 72 * 73 * @param memoryItemView memoryItemView 74 * @param sessionId sessionId 75 * @param chartName chartName 76 */ MemoryTreeTablePanel(MemoryItemView memoryItemView, long sessionId, String chartName)77 public MemoryTreeTablePanel(MemoryItemView memoryItemView, long sessionId, String chartName) { 78 if (ProfilerLogManager.isInfoEnabled()) { 79 LOGGER.info("MemoryTreeTablePanel"); 80 } 81 this.setOpaque(true); 82 this.setLayout(new BorderLayout()); 83 // leftTab 84 JBLabel leftTab = new JBLabel("Table"); 85 leftTab.setBorder(BorderFactory 86 .createEmptyBorder(LayoutConstants.NUM_2, LayoutConstants.RECORD_BORDER_SPACE, LayoutConstants.NUM_2, 0)); 87 leftTab.setOpaque(false); 88 leftTab.setPreferredSize(new Dimension(LayoutConstants.JPA_LABEL_WIDTH, LayoutConstants.DEVICES_HEIGHT)); 89 Font font = new Font(Font.DIALOG, Font.PLAIN, LayoutConstants.FONT_SIZE); 90 leftTab.setFont(font); 91 leftTab.setBounds(LayoutConstants.RECORD_BORDER_SPACE, LayoutConstants.NUM_2, 92 LayoutConstants.RECORD_TABBED_BOUNDS_WIDTH, LayoutConstants.NUM_20); 93 // TAB 94 JBTabbedPane jbTabbedPane = new JBTabbedPane(); 95 jbTabbedPane.setBorder( 96 BorderFactory.createEmptyBorder(LayoutConstants.NUM_2, LayoutConstants.NUM_20, LayoutConstants.NUM_2, 0)); 97 // tableTab 98 JBPanel tableTab = createTableTab(memoryItemView, sessionId, chartName); 99 tableTab.setBorder(BorderFactory.createEmptyBorder(NUM_8, 0, NUM_8, 0)); 100 // Custom jbTabbedPane 101 jbTabbedPane.addTab("", tableTab); 102 jbTabbedPane.setTabComponentAt(jbTabbedPane.indexOfComponent(tableTab), leftTab); 103 // rightTab 104 JBLabel rightTab = new JBLabel("Visualization"); 105 rightTab.setBorder(BorderFactory 106 .createEmptyBorder(LayoutConstants.NUM_2, LayoutConstants.RECORD_TABBED_BORDER, LayoutConstants.NUM_2, 0)); 107 rightTab.setOpaque(false); 108 rightTab.setPreferredSize(new Dimension(LayoutConstants.JPA_LABEL_WIDTH, LayoutConstants.DEVICES_HEIGHT)); 109 rightTab.setFont(font); 110 rightTab.setBounds(LayoutConstants.RECORD_TABBED_BOUNDS_POINT, LayoutConstants.NUM_2, 111 LayoutConstants.RECORD_TABBED_BOUNDS_WIDTH, LayoutConstants.NUM_20); 112 // viewTab 113 JBPanel viewTab = createViewTab(); 114 viewTab.setBorder(BorderFactory.createEmptyBorder(NUM_8, 0, NUM_8, 0)); 115 // Custom jbTabbedPane 116 if (IS_DEVELOP_MODE) { 117 jbTabbedPane.addTab("", viewTab); 118 jbTabbedPane.setTabComponentAt(jbTabbedPane.indexOfComponent(viewTab), rightTab); 119 } 120 this.add(jbTabbedPane, BorderLayout.CENTER); 121 // Set the label panel changeListener 122 jbTabbedPane.addChangeListener(new ChangeListener() { 123 @Override 124 public void stateChanged(ChangeEvent event) { 125 } 126 }); 127 } 128 createTableTab(MemoryItemView memoryItemView, long sessionId, String chartName)129 private JBPanel createTableTab(MemoryItemView memoryItemView, long sessionId, String chartName) { 130 if (ProfilerLogManager.isInfoEnabled()) { 131 LOGGER.info("createTableTab"); 132 } 133 JBPanel tablePanel = new JBPanel(new MigLayout("insets 0")); 134 tablePanel.setBorder(BorderFactory.createEmptyBorder(NUM_5, 0, NUM_5, 0)); 135 tablePanel.setOpaque(true); 136 137 // itemViewBox 138 List<String> itemViewBox = new ArrayList<>(); 139 itemViewBox.add("View app heaps"); 140 141 // itemViewBox 142 List<String> itemArraysBox = new ArrayList<>(); 143 itemArraysBox.add("Arrange by class"); 144 145 // Reserved Tree Table panel 146 memoryAgentHeapInfoPanel = new MemoryAgentHeapInfoPanel(memoryItemView, sessionId, chartName); 147 memoryAgentHeapInfoPanel.setOpaque(true); 148 memoryAgentHeapInfoPanel.setBackground(JBColor.background().brighter()); 149 150 // add to table Tab Options panel 151 tablePanel.add(createHeapFeatures(itemViewBox, itemArraysBox), "wrap"); 152 tablePanel.add(memoryAgentHeapInfoPanel, "dock south"); 153 154 return tablePanel; 155 } 156 createViewTab()157 private JBPanel createViewTab() { 158 if (ProfilerLogManager.isInfoEnabled()) { 159 LOGGER.info("createViewTab"); 160 } 161 JBPanel viewPanel = new JBPanel(new BorderLayout()); 162 viewPanel.setBorder(BorderFactory.createEmptyBorder(NUM_5, 0, NUM_5, 0)); 163 viewPanel.setOpaque(true); 164 165 List<String> itemBox = new ArrayList<>(); 166 itemBox.add("View all heaps"); 167 itemBox.add("View app heaps"); 168 itemBox.add("View zygote heaps"); 169 itemBox.add("View image heaps"); 170 itemBox.add("View JNI heaps"); 171 172 // Reserved Tree Table panel 173 JBPanel recordTable = new JBPanel(); 174 recordTable.setOpaque(true); 175 recordTable.setBorder(BorderFactory.createEmptyBorder(NUM_5, 0, 0, 0)); 176 177 // add to table Tab Options panel 178 viewPanel.add(createHeapFeatures(itemBox, itemBox), BorderLayout.NORTH); 179 viewPanel.add(recordTable, BorderLayout.CENTER); 180 181 return viewPanel; 182 } 183 createHeapFeatures(List<String> itemViewBox, List<String> itemArrangeBox)184 private JBPanel createHeapFeatures(List<String> itemViewBox, List<String> itemArrangeBox) { 185 if (ProfilerLogManager.isInfoEnabled()) { 186 LOGGER.info("createHeapFeatures"); 187 } 188 // tableFeatures 189 JBPanel tableFeatures = new JBPanel(); 190 tableFeatures.setOpaque(false); 191 tableFeatures.setPreferredSize(new Dimension(FEATURES_WIDTH, LayoutConstants.RECORD_FEATURES_HEIGHT)); 192 tableFeatures.setBackground(JBColor.background().darker()); 193 tableFeatures.setBorder(BorderFactory.createEmptyBorder(NUM_8, 0, NUM_8, 0)); 194 tableFeatures.setLayout(new MigLayout("insets 0")); 195 tableFeatures.setBorder(BorderFactory.createEmptyBorder(NUM_8, 0, NUM_8, 0)); 196 197 // tableFeatures add itemViewBox 198 CustomComboBox viewBox = new CustomComboBox(); 199 viewBox.setName(UtConstant.UT_MEMORY_TREE_TABLE_VIEW); 200 viewBox.setUI(new CustomJBComboBoxUI()); 201 viewBox.setBorder(BorderFactory.createLineBorder(ColorConstants.NATIVE_RECORD_BORDER, 1)); 202 viewBox.setPreferredSize( 203 new Dimension(LayoutConstants.RECORD_COMBO_BOX_WIDTH, LayoutConstants.RECORD_SEARCH_HEIGHT)); 204 for (String item : itemViewBox) { 205 viewBox.addItem(item); 206 } 207 viewBox.setSelectedIndex(0); 208 tableFeatures.add(viewBox); 209 210 // tableFeatures add itemArrangeBox 211 CustomComboBox arrangeBox = new CustomComboBox(); 212 arrangeBox.setName(UtConstant.UT_MEMORY_TREE_TABLE_ARRANGE); 213 arrangeBox.setUI(new CustomJBComboBoxUI()); 214 arrangeBox.setBorder(BorderFactory.createLineBorder(ColorConstants.NATIVE_RECORD_BORDER, 1)); 215 arrangeBox.setPreferredSize( 216 new Dimension(LayoutConstants.RECORD_COMBO_BOX_WIDTH, LayoutConstants.RECORD_SEARCH_HEIGHT)); 217 for (String item : itemArrangeBox) { 218 arrangeBox.addItem(item); 219 } 220 arrangeBox.setSelectedIndex(0); 221 tableFeatures.add(arrangeBox); 222 223 JBPanel searchPanel = new JBPanel(); 224 searchPanel.setOpaque(true); 225 searchPanel.setLayout(new BorderLayout()); 226 227 // tableFeatures Search 228 CustomJBTextField search = new CustomJBTextField(); 229 search.setBorder(BorderFactory.createLineBorder(ColorConstants.NATIVE_RECORD_BORDER, 1)); 230 search.setText("Search"); 231 search 232 .setPreferredSize(new Dimension(LayoutConstants.RECORD_SEARCH_WIDTH, LayoutConstants.RECORD_SEARCH_HEIGHT)); 233 addSearchListener(search); 234 searchPanel.add(search, BorderLayout.WEST); 235 236 tableFeatures.add(searchPanel, "wrap"); 237 return tableFeatures; 238 } 239 addSearchListener(CustomJBTextField search)240 private void addSearchListener(CustomJBTextField search) { 241 search.addFocusListener(new FocusListener() { 242 @Override 243 public void focusGained(FocusEvent focusEvent) { 244 if ("Search".equals(search.getText())) { 245 search.setText(""); 246 memoryAgentHeapInfoPanel.getTreeTable().getVerticalScrollBar() 247 .removeMouseMotionListener(memoryAgentHeapInfoPanel.getMouseMotionAdapter()); 248 } 249 } 250 251 @Override 252 public void focusLost(FocusEvent focusEvent) { 253 if (search.getText().length() < 1) { 254 search.setText("Search"); 255 memoryAgentHeapInfoPanel.getTreeTable().getVerticalScrollBar() 256 .addMouseMotionListener(memoryAgentHeapInfoPanel.getMouseMotionAdapter()); 257 } 258 } 259 }); 260 search.getDocument().addDocumentListener(new DocumentListener() { 261 @Override 262 public void insertUpdate(DocumentEvent event) { 263 searchInsertUpdate(search); 264 } 265 266 @Override 267 public void removeUpdate(DocumentEvent event) { 268 // search 269 searchRemoveUpdate(search); 270 } 271 272 /** 273 * Gives notification that an attribute or set of attributes changed. 274 * 275 * @param documentEvent the document event 276 */ 277 @Override 278 public void changedUpdate(DocumentEvent documentEvent) { 279 } 280 }); 281 } 282 283 /** 284 * searchRemoveUpdate 285 * 286 * @param search search 287 */ searchRemoveUpdate(CustomJBTextField search)288 public void searchRemoveUpdate(CustomJBTextField search) { 289 String text = search.getText(); 290 ExpandTreeTable treeTable = memoryAgentHeapInfoPanel.getTreeTable(); 291 TreeTableModel model = treeTable.getModel(); 292 if (model instanceof ListTreeTableModelOnColumns) { 293 SwingUtilities.invokeLater(new Runnable() { 294 @Override 295 public void run() { 296 ListTreeTableModelOnColumns tableModel = (ListTreeTableModelOnColumns) model; 297 DefaultMutableTreeNode root = null; 298 Object tableModelRoot = tableModel.getRoot(); 299 if (tableModelRoot instanceof DefaultMutableTreeNode) { 300 root = (DefaultMutableTreeNode) tableModelRoot; 301 List<AgentHeapBean> datas = memoryAgentHeapInfoPanel.getAllAgentDatas().stream() 302 .filter(agentDataNode -> agentDataNode.getAgentClazzName().contains(text)) 303 .collect(Collectors.toList()); 304 root.removeAllChildren(); 305 int totalAllocations = 0; 306 int totalDeallocations = 0; 307 int totalTotalCount = 0; 308 long totalShallowSize = 0L; 309 for (AgentHeapBean agentHeapBean : datas) { 310 totalAllocations = totalAllocations + agentHeapBean.getAgentAllocationsCount(); 311 totalDeallocations = totalDeallocations + agentHeapBean.getAgentDeAllocationsCount(); 312 totalTotalCount = totalTotalCount + agentHeapBean.getAgentTotalInstanceCount(); 313 totalShallowSize = totalShallowSize + agentHeapBean.getAgentTotalshallowSize(); 314 root.add(new DefaultMutableTreeNode(agentHeapBean)); 315 } 316 AgentHeapBean userObject = null; 317 Object rootUserObject = root.getUserObject(); 318 if (rootUserObject instanceof AgentHeapBean) { 319 userObject = (AgentHeapBean) rootUserObject; 320 userObject.setAgentAllocationsCount(totalAllocations); 321 userObject.setAgentDeAllocationsCount(totalDeallocations); 322 userObject.setAgentTotalInstanceCount(totalTotalCount); 323 userObject.setAgentTotalshallowSize(totalShallowSize); 324 root.setUserObject(userObject); 325 } 326 } 327 tableModel.reload(); 328 memoryAgentHeapInfoPanel.getTreeTable().getVerticalScrollBar().setValue(0); 329 } 330 }); 331 } 332 } 333 334 /** 335 * searchInsertUpdate 336 * 337 * @param search search 338 */ searchInsertUpdate(CustomJBTextField search)339 public void searchInsertUpdate(CustomJBTextField search) { 340 String text = search.getText(); 341 ExpandTreeTable treeTable = memoryAgentHeapInfoPanel.getTreeTable(); 342 TreeTableModel model = treeTable.getModel(); 343 if (model instanceof ListTreeTableModelOnColumns) { 344 SwingUtilities.invokeLater(new Runnable() { 345 @Override 346 public void run() { 347 ListTreeTableModelOnColumns tableModel = (ListTreeTableModelOnColumns) model; 348 DefaultMutableTreeNode root = null; 349 Object tableModelRoot = tableModel.getRoot(); 350 if (tableModelRoot instanceof DefaultMutableTreeNode) { 351 root = (DefaultMutableTreeNode) tableModelRoot; 352 List<AgentHeapBean> datas = memoryAgentHeapInfoPanel.getAllAgentDatas().stream() 353 .filter(agentDataNode -> agentDataNode.getAgentClazzName().contains(text)) 354 .collect(Collectors.toList()); 355 root.removeAllChildren(); 356 int totalAllocations = 0; 357 int totalDeallocations = 0; 358 int totalTotalCount = 0; 359 long totalShallowSize = 0L; 360 for (AgentHeapBean agentHeapBean : datas) { 361 totalAllocations = totalAllocations + agentHeapBean.getAgentAllocationsCount(); 362 totalDeallocations = totalDeallocations + agentHeapBean.getAgentDeAllocationsCount(); 363 totalTotalCount = totalTotalCount + agentHeapBean.getAgentTotalInstanceCount(); 364 totalShallowSize = totalShallowSize + agentHeapBean.getAgentTotalshallowSize(); 365 root.add(new DefaultMutableTreeNode(agentHeapBean)); 366 } 367 AgentHeapBean userObject = null; 368 Object rootUserObject = root.getUserObject(); 369 if (rootUserObject instanceof AgentHeapBean) { 370 userObject = (AgentHeapBean) rootUserObject; 371 userObject.setAgentAllocationsCount(totalAllocations); 372 userObject.setAgentDeAllocationsCount(totalDeallocations); 373 userObject.setAgentTotalInstanceCount(totalTotalCount); 374 userObject.setAgentTotalshallowSize(totalShallowSize); 375 root.setUserObject(userObject); 376 } 377 } 378 tableModel.reload(); 379 memoryAgentHeapInfoPanel.getTreeTable().getVerticalScrollBar().setValue(0); 380 } 381 }); 382 } 383 } 384 getMemoryAgentHeapInfoPanel()385 public MemoryAgentHeapInfoPanel getMemoryAgentHeapInfoPanel() { 386 return memoryAgentHeapInfoPanel; 387 } 388 } 389