blob: 9db4e1e4dd60487588118748cd3e506b83e9f5be [file] [log] [blame]
package org.jetbrains.plugins.gradle.ui;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.table.JBTable;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.util.Arrays;
/**
* Allows to build control that shows target matrix-like information.
* <p/>
* <code>'Matrix-like'</code> here means that there is a set of columns and a number of rows where every row contains values for
* every column.
* <p/>
* Example:
* <pre>
* | Column1 name | Column2 name
* ---------------------------|-----------------
* Row1 name | Value11 | Value12
* ---------------------------|-----------------
* Row2 name | Value21 | Value22
* ---------------------------|-----------------
* </pre>
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 3/14/12 3:52 PM
*/
public class MatrixControlBuilder {
private final DefaultTableModel myModel = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
private final JBTable myTable;
private final JComponent myResult;
private final int[] myColumnWidths;
private final FontMetrics myFontMetrics;
public MatrixControlBuilder(@NotNull String ... columns) {
myModel.addColumn(""); // Row name
for (String column : columns) {
myModel.addColumn(column);
}
myTable = new JBTable(myModel) {
@Override
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
};
myTable.setFocusable(false);
myTable.setStriped(true);
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(SwingConstants.CENTER);
for (int i = 0, max = myTable.getColumnCount(); i < max; i++) {
final TableColumn column = myTable.getColumnModel().getColumn(i);
if (i > 0) {
// Don't align row name.
column.setCellRenderer(renderer);
}
final TableCellRenderer headerRenderer = column.getHeaderRenderer();
if (headerRenderer instanceof JLabel) {
((JLabel)headerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
}
}
myResult = ScrollPaneFactory.createScrollPane(myTable);
myColumnWidths = new int[columns.length + 1/*'name' column*/];
myFontMetrics = myTable.getFontMetrics(myTable.getFont());
for (int i = 0; i < columns.length; i++) {
myColumnWidths[i + 1] = myFontMetrics.stringWidth(columns[i]);
}
}
/**
* Supplies current builder within the information to use during the new row representation.
*
* @param name new row now
* @param values new row values
* @throws IllegalArgumentException if given row values imply number of columns that differs from the number of already configured one
*/
public void addRow(@NotNull String name, @NotNull Object... values) throws IllegalArgumentException {
if (values.length != myModel.getColumnCount() - 1) {
StringBuilder columns = new StringBuilder();
for (int i = 1, max = myModel.getColumnCount(); i < max; i++) {
columns.append(myModel.getColumnName(i)).append(", ");
}
if (columns.length() > 2) {
columns.setLength(columns.length() - 2);
}
throw new IllegalArgumentException(String.format(
"Can't add row '%s' to the matrix control. Reason: the row specifies incorrect number of values (%d, expected %d). "
+ "Registered columns: %s. Given values: %s", name, values.length, myModel.getColumnCount() - 1, columns, Arrays.toString(values)
));
}
Object[] rowData = new Object[values.length + 1];
rowData[0] = name;
System.arraycopy(values, 0, rowData, 1, values.length);
myModel.addRow(rowData);
for (int i = 0; i < rowData.length; i++) {
myColumnWidths[i] = Math.max(myFontMetrics.stringWidth(rowData[i].toString()), myColumnWidths[i]);
}
}
@NotNull
public JComponent build() {
final TableColumnModel columnModel = myTable.getColumnModel();
for (int i = 0; i < myColumnWidths.length; i++) {
columnModel.getColumn(i).setMinWidth(myColumnWidths[i] + 4);
}
return myResult;
}
}