/* * Copyright 2005-2016 Bas Leijdekkers, Sixth and Red River Software * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sixrr.metrics.ui.metricdisplay; import com.intellij.openapi.project.Project; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TableSpeedSearch; import com.intellij.ui.table.JBTable; import com.sixrr.metrics.Metric; import com.sixrr.metrics.MetricCategory; import com.sixrr.metrics.metricModel.*; import com.sixrr.metrics.profile.MetricDisplaySpecification; import com.sixrr.metrics.profile.MetricInstance; import com.sixrr.metrics.profile.MetricTableSpecification; import com.sixrr.metrics.profile.MetricsProfileRepository; import com.sixrr.metrics.utils.MetricsCategoryNameUtil; import com.sixrr.metrics.utils.MetricsReloadedBundle; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.*; import java.awt.*; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.*; import java.util.List; public class MetricsDisplay { private boolean hasOverlay = false; private final Map<MetricCategory, JTable> tables = new EnumMap<MetricCategory, JTable>(MetricCategory.class); private final JTabbedPane tabbedPane = new JTabbedPane(); public MetricsDisplay(@NotNull Project project) { final JTable projectMetricsTable = new JBTable(); tables.put(MetricCategory.Project, projectMetricsTable); final JTable fileTypeMetricsTable = new JBTable(); tables.put(MetricCategory.FileType, fileTypeMetricsTable); final JTable moduleMetricsTable = new JBTable(); tables.put(MetricCategory.Module, moduleMetricsTable); final JTable packageMetricsTable = new JBTable(); tables.put(MetricCategory.Package, packageMetricsTable); final JTable classMetricsTable = new JBTable(); tables.put(MetricCategory.Class, classMetricsTable); final JTable interfaceMetricsTable = new JBTable(); tables.put(MetricCategory.Interface, interfaceMetricsTable); final JTable methodMetricsTable = new JBTable(); tables.put(MetricCategory.Method, methodMetricsTable); setupTable(projectMetricsTable, project); setupTable(fileTypeMetricsTable, project); setupTable(moduleMetricsTable, project); setupTable(packageMetricsTable, project); setupTable(classMetricsTable, project); setupTable(interfaceMetricsTable, project); setupTable(methodMetricsTable, project); tabbedPane.add(MetricsReloadedBundle.message("project.metrics"), ScrollPaneFactory.createScrollPane(projectMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("file.type.metrics"), ScrollPaneFactory.createScrollPane(fileTypeMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("module.metrics"), ScrollPaneFactory.createScrollPane(moduleMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("package.metrics"), ScrollPaneFactory.createScrollPane(packageMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("class.metrics"), ScrollPaneFactory.createScrollPane(classMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("interface.metrics"), ScrollPaneFactory.createScrollPane(interfaceMetricsTable)); tabbedPane.add(MetricsReloadedBundle.message("method.metrics"), ScrollPaneFactory.createScrollPane(methodMetricsTable)); } private static void setupTable(JTable table, Project project) { new TableSpeedSearch(table); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); table.addMouseListener(new MetricTableMouseListener(project, table)); final JTableHeader tableHeader = table.getTableHeader(); tableHeader.addMouseListener(new MetricTableHeaderMouseListener(project, table)); } public void setMetricsResults(MetricDisplaySpecification displaySpecification, MetricsRun run) { final MetricCategory[] categories = MetricCategory.values(); for (final MetricCategory category : categories) { final JTable table = tables.get(category); final String type = MetricsCategoryNameUtil.getShortNameForCategory(category); final MetricTableSpecification tableSpecification = displaySpecification.getSpecification(category); final MetricsResult results = run.getResultsForCategory(category); final MetricTableModel model = new MetricTableModel(results, type, tableSpecification); table.setModel(model); final Container tab = table.getParent().getParent(); if (model.getRowCount() == 0) { tabbedPane.remove(tab); continue; } final String longName = MetricsCategoryNameUtil.getLongNameForCategory(category); tabbedPane.add(tab, longName); final MyColumnListener columnListener = new MyColumnListener(tableSpecification, table); final TableColumnModel columnModel = table.getColumnModel(); columnModel.addColumnModelListener(columnListener); final int columnCount = columnModel.getColumnCount(); for (int i = 0; i < columnCount; i++) { final TableColumn column = columnModel.getColumn(i); column.addPropertyChangeListener(columnListener); } setRenderers(table, type); setColumnWidths(table, tableSpecification); } } public void updateMetricsResults(MetricsRun run, MetricDisplaySpecification displaySpecification) { final MetricCategory[] categories = MetricCategory.values(); for (final MetricCategory category : categories) { final JTable table = tables.get(category); final MetricTableModel model = (MetricTableModel) table.getModel(); model.setResults(run.getResultsForCategory(category)); final String shortName = MetricsCategoryNameUtil.getShortNameForCategory(category); setRenderers(table, shortName); final MetricTableSpecification specification = displaySpecification.getSpecification(category); setColumnWidths(table, specification); } } public void updateMetricsResultsWithDiff(MetricsRun results, MetricDisplaySpecification displaySpecification) { final MetricCategory[] categories = MetricCategory.values(); for (final MetricCategory category : categories) { final JTable table = tables.get(category); final MetricTableModel model = (MetricTableModel) table.getModel(); final MetricsResult prevResults = model.getResults(); model.setPrevResults(prevResults); model.setResults(results.getResultsForCategory(category)); final Container tab = table.getParent().getParent(); if (model.getRowCount() == 0) { tabbedPane.remove(tab); continue; } final String longName = MetricsCategoryNameUtil.getLongNameForCategory(category); tabbedPane.add(tab, longName); final String shortName = MetricsCategoryNameUtil.getShortNameForCategory(category); setRenderers(table, shortName); final MetricTableSpecification specification = displaySpecification.getSpecification(category); setColumnWidths(table, specification); } hasOverlay = true; } public void overlayWithDiff(MetricsRun prevRun, MetricDisplaySpecification displaySpecification) { final MetricCategory[] categories = MetricCategory.values(); for (final MetricCategory category : categories) { final JTable table = tables.get(category); final MetricTableModel model = (MetricTableModel) table.getModel(); model.setPrevResults(prevRun.getResultsForCategory(category)); final Container tab = table.getParent().getParent(); if (model.getRowCount() == 0) { tabbedPane.remove(tab); continue; } final String longName = MetricsCategoryNameUtil.getLongNameForCategory(category); tabbedPane.add(tab, longName); final String shortName = MetricsCategoryNameUtil.getShortNameForCategory(category); setRenderers(table, shortName); final MetricTableSpecification specification = displaySpecification.getSpecification(category); setColumnWidths(table, specification); } hasOverlay = true; } public void removeDiffOverlay(MetricDisplaySpecification displaySpecification) { final MetricCategory[] categories = MetricCategory.values(); for (final MetricCategory category : categories) { final JTable table = tables.get(category); final MetricTableModel model = (MetricTableModel) table.getModel(); model.setPrevResults(null); final Container tab = table.getParent().getParent(); if (model.getRowCount() == 0) { tabbedPane.remove(tab); continue; } final String longName = MetricsCategoryNameUtil.getLongNameForCategory(category); tabbedPane.add(tab, longName); final String shortName = MetricsCategoryNameUtil.getShortNameForCategory(category); setRenderers(table, shortName); final MetricTableSpecification specification = displaySpecification.getSpecification(category); setColumnWidths(table, specification); } hasOverlay = false; } private static void setColumnWidths(JTable table, MetricTableSpecification tableSpecification) { final TableModel model = table.getModel(); final TableColumnModel columnModel = table.getColumnModel(); final List<Integer> columnWidths = tableSpecification.getColumnWidths(); final List<String> columnOrder = tableSpecification.getColumnOrder(); if (columnWidths != null && !columnWidths.isEmpty()) { final int columnCount = model.getColumnCount(); for (int i = 0; i < columnCount; i++) { final String columnName = model.getColumnName(i); final int index = columnOrder.indexOf(columnName); if (index != -1) { final Integer width = columnWidths.get(index); final TableColumn column = columnModel.getColumn(i); column.setPreferredWidth(width.intValue()); } } } else { final Graphics graphics = table.getGraphics(); final Font font = table.getFont(); final FontMetrics fontMetrics = table.getFontMetrics(font); final int rowCount = model.getRowCount(); int maxFirstColumnWidth = 100; for (int i = 0; i < rowCount; i++) { final String name = (String) model.getValueAt(i, 0); if (name != null) { final Rectangle2D stringBounds = fontMetrics.getStringBounds(name, graphics); final double stringWidth = stringBounds.getWidth(); if (stringWidth > maxFirstColumnWidth) { maxFirstColumnWidth = (int) stringWidth; } } } final int allocatedFirstColumnWidth = Math.min(300, maxFirstColumnWidth + 5); final TableColumn column = columnModel.getColumn(0); column.setPreferredWidth(allocatedFirstColumnWidth); } } private static void setRenderers(JTable table, String type) { final MetricTableModel model = (MetricTableModel) table.getModel(); final MetricInstance[] metrics = model.getMetricsInstances(); Arrays.sort(metrics, new MetricInstanceAbbreviationComparator()); final TableColumnModel columnModel = table.getColumnModel(); for (int i = 0; i < model.getColumnCount(); i++) { final String columnName = model.getColumnName(i); final TableColumn column = columnModel.getColumn(i); if (columnName.equals(type)) { column.setCellRenderer(new MetricCellRenderer(null)); column.setHeaderRenderer(new HeaderRenderer(null, model, SwingConstants.LEFT)); } else { final MetricInstance metricInstance = model.getMetricForColumn(i); final TableCellRenderer renderer = new MetricCellRenderer(metricInstance); column.setCellRenderer(renderer); final Metric metric = metricInstance.getMetric(); final String displayName = metric.getDisplayName(); column.setHeaderRenderer(new HeaderRenderer(displayName, model, SwingConstants.RIGHT)); } } } public JTabbedPane getTabbedPane() { return tabbedPane; } public boolean hasDiffOverlay() { return hasOverlay; } public MetricCategory getSelectedCategory() { final Component component = tabbedPane.getSelectedComponent(); for (MetricCategory category : MetricCategory.values()) { final JTable table = tables.get(category); if (table.getParent().getParent().equals(component)) { return category; } } return null; } private class MyColumnListener implements TableColumnModelListener, PropertyChangeListener { private final MetricTableSpecification tableSpecification; private final JTable table; MyColumnListener(MetricTableSpecification tableSpecification, JTable table) { this.tableSpecification = tableSpecification; this.table = table; } @Override public void columnAdded(TableColumnModelEvent e) { } @Override public void columnRemoved(TableColumnModelEvent e) { } @Override public void columnMoved(TableColumnModelEvent e) { saveColumnSpecification(); } @Override public void columnMarginChanged(ChangeEvent e) { } @Override public void columnSelectionChanged(ListSelectionEvent e) { } @Override @SuppressWarnings("HardCodedStringLiteral") public void propertyChange(PropertyChangeEvent evt) { final String propertyName = evt.getPropertyName(); if ("width".equalsIgnoreCase(propertyName)) { saveColumnSpecification(); } } private void saveColumnSpecification() { final TableColumnModel columnModel = table.getColumnModel(); final int numColumns = table.getColumnCount(); final List<String> columns = new ArrayList<String>(numColumns); final List<Integer> columnWidths = new ArrayList<Integer>(numColumns); for (int i = 0; i < numColumns; i++) { final String columnName = table.getColumnName(i); columns.add(columnName); final TableColumn column = columnModel.getColumn(i); final int columnWidth = column.getWidth(); columnWidths.add(Integer.valueOf(columnWidth)); } tableSpecification.setColumnOrder(columns); tableSpecification.setColumnWidths(columnWidths); MetricsProfileRepository.getInstance().persistCurrentProfile(); } } }