replaced <code></code> with more concise {@code}
[idea/community.git] / plugins / gradle / src / org / jetbrains / plugins / gradle / ui / MatrixControlBuilder.java
1 package org.jetbrains.plugins.gradle.ui;
2
3 import com.intellij.ui.ScrollPaneFactory;
4 import com.intellij.ui.table.JBTable;
5 import org.jetbrains.annotations.NotNull;
6
7 import javax.swing.*;
8 import javax.swing.table.*;
9 import java.awt.*;
10 import java.util.Arrays;
11
12 /**
13  * Allows to build control that shows target matrix-like information.
14  * <p/>
15  * {@code 'Matrix-like'} here means that there is a set of columns and a number of rows where every row contains values for
16  * every column.
17  * <p/>
18  * Example:
19  * <pre>
20  *            | Column1 name   |   Column2 name
21  *  ---------------------------|-----------------
22  *  Row1 name |   Value11      |     Value12
23  *  ---------------------------|-----------------
24  *  Row2 name |   Value21      |     Value22
25  *  ---------------------------|-----------------
26  * </pre>
27  * <p/>
28  * Not thread-safe.
29  * 
30  * @author Denis Zhdanov
31  * @since 3/14/12 3:52 PM
32  */
33 public class MatrixControlBuilder {
34   
35   private final DefaultTableModel myModel = new DefaultTableModel() {
36     @Override
37     public boolean isCellEditable(int row, int column) {
38       return false;
39     }
40   };
41
42   private final JBTable     myTable;
43   private final JComponent  myResult;
44   private final int[]       myColumnWidths;
45   private final FontMetrics myFontMetrics;
46
47   public MatrixControlBuilder(@NotNull String ... columns) {
48     myModel.addColumn(""); // Row name
49     for (String column : columns) {
50       myModel.addColumn(column);
51     }
52     myTable = new JBTable(myModel) {
53       @Override
54       public Dimension getPreferredScrollableViewportSize() {
55         return getPreferredSize();
56       }
57     };
58     myTable.setFocusable(false);
59     myTable.setStriped(true);
60     DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
61     renderer.setHorizontalAlignment(SwingConstants.CENTER);
62     for (int i = 0, max = myTable.getColumnCount(); i < max; i++) {
63       final TableColumn column = myTable.getColumnModel().getColumn(i);
64       if (i > 0) {
65         // Don't align row name.
66         column.setCellRenderer(renderer);
67       }
68       final TableCellRenderer headerRenderer = column.getHeaderRenderer();
69       if (headerRenderer instanceof JLabel) {
70         ((JLabel)headerRenderer).setHorizontalAlignment(SwingConstants.CENTER);
71       }
72     }
73     myResult = ScrollPaneFactory.createScrollPane(myTable);
74     
75     myColumnWidths = new int[columns.length + 1/*'name' column*/];
76     myFontMetrics = myTable.getFontMetrics(myTable.getFont());
77     for (int i = 0; i < columns.length; i++) {
78       myColumnWidths[i + 1] = myFontMetrics.stringWidth(columns[i]);
79     }
80   }
81   
82   /**
83    * Supplies current builder within the information to use during the new row representation.
84    * 
85    * @param name    new row now
86    * @param values  new row values
87    * @throws IllegalArgumentException   if given row values imply number of columns that differs from the number of already configured one
88    */
89   public void addRow(@NotNull String name, @NotNull Object... values) throws IllegalArgumentException {
90     if (values.length != myModel.getColumnCount() - 1) {
91       StringBuilder columns = new StringBuilder();
92       for (int i = 1, max = myModel.getColumnCount(); i < max; i++) {
93         columns.append(myModel.getColumnName(i)).append(", ");
94       }
95       if (columns.length() > 2) {
96         columns.setLength(columns.length() - 2);
97       }
98       throw new IllegalArgumentException(String.format(
99         "Can't add row '%s' to the matrix control. Reason: the row specifies incorrect number of values (%d, expected %d). "
100         + "Registered columns: %s. Given values: %s", name, values.length, myModel.getColumnCount() - 1, columns, Arrays.toString(values)
101         ));
102     }
103     Object[] rowData = new Object[values.length + 1];
104     rowData[0] = name;
105     System.arraycopy(values, 0, rowData, 1, values.length);
106     myModel.addRow(rowData);
107
108     for (int i = 0; i < rowData.length; i++) {
109       myColumnWidths[i] = Math.max(myFontMetrics.stringWidth(rowData[i].toString()), myColumnWidths[i]);
110     }
111   }
112   
113   @NotNull
114   public JComponent build() {
115     final TableColumnModel columnModel = myTable.getColumnModel();
116     for (int i = 0; i < myColumnWidths.length; i++) {
117       columnModel.getColumn(i).setMinWidth(myColumnWidths[i] + 4);
118     }
119     return myResult;
120   }
121 }