View Javadoc
1   package fr.ifremer.quadrige2.ui.swing.common.table;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 UI Common
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  
27  import com.google.common.base.Preconditions;
28  import org.jdesktop.swingx.JXTable;
29  import org.jdesktop.swingx.table.TableColumnExt;
30  
31  import javax.swing.*;
32  import javax.swing.table.TableCellRenderer;
33  import javax.swing.table.TableColumnModel;
34  import java.awt.Component;
35  import java.awt.Container;
36  import java.awt.Graphics;
37  import java.awt.event.MouseAdapter;
38  import java.awt.event.MouseEvent;
39  import java.util.List;
40  
41  /**
42   * <p>CheckTableColumn class.</p>
43   *
44   * @param <R> type of row UI model
45   * @param <T> type of table UI model
46   * @author Ludovic Pecquot <ludovic.pecquot@e-is.pro>
47   */
48  public class CheckTableColumn<R extends AbstractRowUIModel, T extends AbstractTableUIModel<?, R, T>> extends TableColumnExt {
49  
50      /** Constant <code>FIXED_VIEW_POSITION=0</code> */
51      public static final int FIXED_VIEW_POSITION = 0;
52  
53      private final JXTable table;
54      private final T tableModel;
55      private boolean allSelected;
56      private boolean allEnabled;
57  
58      /**
59       * <p>Getter for the field <code>table</code>.</p>
60       *
61       * @return a {@link JXTable} object.
62       */
63      public JXTable getTable() {
64          return table;
65      }
66  
67      /**
68       * <p>Getter for the field <code>tableModel</code>.</p>
69       *
70       * @return a T object.
71       */
72      public final T getTableModel() {
73          return tableModel;
74      }
75  
76      /**
77       * <p>isAllSelected.</p>
78       *
79       * @return a boolean.
80       */
81      public boolean isAllSelected() {
82          return allSelected;
83      }
84  
85      /**
86       * <p>Setter for the field <code>allSelected</code>.</p>
87       *
88       * @param allSelected a boolean.
89       */
90      public void setAllSelected(boolean allSelected) {
91          this.allSelected = allSelected;
92      }
93  
94      /**
95       * <p>isAllEnabled.</p>
96       *
97       * @return a boolean.
98       */
99      public boolean isAllEnabled() {
100         return allEnabled;
101     }
102 
103     /**
104      * <p>Setter for the field <code>allEnabled</code>.</p>
105      *
106      * @param allEnabled a boolean.
107      */
108     public void setAllEnabled(boolean allEnabled) {
109         this.allEnabled = allEnabled;
110     }
111 
112     /**
113      * <p>Constructor for CheckTableColumn.</p>
114      *
115      * @param table a {@link JXTable} object.
116      * @param tableModel a T object.
117      */
118     public CheckTableColumn(JXTable table, T tableModel) {
119         super(table.getColumnCount());
120         Preconditions.checkNotNull(table);
121         this.table = table;
122         this.tableModel = tableModel;
123         editable = true;
124         hideable = false;
125         sortable = false;
126         allEnabled = true;
127         allSelected = false;
128 
129         setWidth(41);
130         setMinWidth(width);
131         setMaxWidth(width);
132 
133         setCellEditor(table.getDefaultEditor(Boolean.class));
134         setCellRenderer(table.getDefaultRenderer(Boolean.class));
135 
136         // header 
137         setHeaderRenderer(new CheckAllHeaderRenderer(this));
138 
139         // identifier
140         setIdentifier(new CheckTableColumnIdentifier<>());
141     }
142 
143     /** {@inheritDoc} */
144     @Override
145     @SuppressWarnings("unchecked")
146     public ColumnIdentifier<R> getIdentifier() {
147         return (ColumnIdentifier<R>) super.getIdentifier();
148     }
149 
150     private class CheckAllHeaderRenderer extends JCheckBox implements TableCellRenderer {
151 
152         private final CheckTableColumn checkColumn;
153 
154         @SuppressWarnings("unchecked")
155         private CheckAllHeaderRenderer(CheckTableColumn targetColumn) {
156             super((String) null);
157             this.checkColumn = targetColumn;
158 
159             setOpaque(false);
160             setFont(checkColumn.getTable().getTableHeader().getFont());
161 
162             // add mouse listener if the table is editable
163             checkColumn.getTable().getTableHeader().addMouseListener(new MouseAdapter() {
164 
165                 @Override
166                 public void mouseClicked(MouseEvent e) {
167                     JXTable table = checkColumn.getTable();
168 
169                     if (!table.isEnabled() || !table.isEditable()) {
170                         return;
171                     }
172 
173                     TableColumnModel columnModel = table.getColumnModel();
174                     int vci = columnModel.getColumnIndexAtX(e.getX());
175                     int mci = table.convertColumnIndexToModel(vci);
176                     if (mci == checkColumn.getModelIndex()) {
177                         boolean allChecked = !isSelected();
178                         checkColumn.setAllSelected(allChecked);
179                         checkColumn.setAllEnabled(true);
180                         // propagate is selected to all lines
181                         if (checkColumn.getTableModel() != null && checkColumn.getTableModel().getRowCount() > 0) {
182                             for (R row : (List<R>) checkColumn.getTableModel().getRows()) {
183                                 if (!row.isCalculated() /*&& row.isEditable()*/) {
184                                     row.selected = allChecked;
185                                 }
186                             }
187 
188                             // recalculate selected rows
189                             checkColumn.getTableModel().populateSelectedRows();
190                             // redraw immediately
191                             table.getTableHeader().repaint();
192                             table.repaint();
193                         }
194 
195                     }
196                 }
197 
198             });
199         }
200 
201         @Override
202         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
203             TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
204             JLabel l = (JLabel) r.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
205             if (checkColumn.getModelIndex() == table.convertColumnIndexToModel(column)) {
206                 // reset allSelected if table is empty
207                 if (!table.isEnabled() || !checkColumn.getTable().isEditable() || table.getRowCount() == 0) checkColumn.setAllSelected(false);
208                 setSelected(checkColumn.isAllSelected());
209                 setEnabled(checkColumn.isAllEnabled());
210                 l.setIcon(new ComponentIcon(this));
211                 l.setHorizontalAlignment(SwingConstants.CENTER);
212                 l.setVerticalAlignment(SwingConstants.TOP);
213             }
214             l.setText(null);
215             return l;
216         }
217 
218     }
219 
220     class ComponentIcon implements Icon {
221 
222         private final JComponent cmp;
223 
224         public ComponentIcon(JComponent cmp) {
225             this.cmp = cmp;
226         }
227 
228         @Override
229         public int getIconWidth() {
230             return cmp.getPreferredSize().width;
231         }
232 
233         @Override
234         public int getIconHeight() {
235             return cmp.getPreferredSize().height;
236         }
237 
238         @Override
239         public void paintIcon(Component c, Graphics g, int x, int y) {
240             SwingUtilities.paintComponent(g, cmp, (Container) c, x, y, getIconWidth(), getIconHeight());
241         }
242     }
243 
244 }