View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.table;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 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  import org.jdesktop.swingx.table.TableColumnExt;
27  
28  import javax.swing.*;
29  import javax.swing.table.TableCellRenderer;
30  import javax.swing.table.TableColumnModel;
31  import java.awt.Component;
32  import java.awt.Container;
33  import java.awt.Graphics;
34  import java.awt.event.MouseAdapter;
35  import java.awt.event.MouseEvent;
36  import java.util.List;
37  
38  import static org.nuiton.i18n.I18n.n;
39  
40  /**
41   * <p>CheckTableColumn class.</p>
42   *
43   * @param <R> type of row UI model
44   * @author Ludovic Pecquot <ludovic.pecquot@e-is.pro>
45   */
46  public class CheckTableColumn<R extends AbstractRowUIModel> extends TableColumnExt implements FixedColumn {
47  
48      private final SwingTable table;
49      private boolean allSelected;
50      private boolean allEnabled;
51  
52      /**
53       * <p>Getter for the field <code>table</code>.</p>
54       *
55       * @return a {@link SwingTable} object.
56       */
57      public SwingTable getTable() {
58          return table;
59      }
60  
61      /**
62       * <p>Getter for the field <code>tableModel</code>.</p>
63       *
64       * @return a T object.
65       */
66      public final AbstractTableUIModel getTableModel() {
67          return table.getTableModel().getTableUIModel();
68      }
69  
70      /**
71       * <p>isAllSelected.</p>
72       *
73       * @return a boolean.
74       */
75      public boolean isAllSelected() {
76          return allSelected;
77      }
78  
79      /**
80       * <p>Setter for the field <code>allSelected</code>.</p>
81       *
82       * @param allSelected a boolean.
83       */
84      public void setAllSelected(boolean allSelected) {
85          this.allSelected = allSelected;
86      }
87  
88      /**
89       * <p>isAllEnabled.</p>
90       *
91       * @return a boolean.
92       */
93      public boolean isAllEnabled() {
94          return allEnabled;
95      }
96  
97      /**
98       * <p>Setter for the field <code>allEnabled</code>.</p>
99       *
100      * @param allEnabled a boolean.
101      */
102     public void setAllEnabled(boolean allEnabled) {
103         this.allEnabled = allEnabled;
104     }
105 
106     /**
107      * <p>Constructor for CheckTableColumn.</p>
108      *
109      * @param table      a {@link SwingTable} object.
110      */
111     public CheckTableColumn(SwingTable table/*, T tableModel*/) {
112         super(table.getColumnCount());
113         this.table = table;
114         editable = true;
115         hideable = false;
116         sortable = false;
117         allEnabled = true;
118         allSelected = false;
119 
120         setWidth(41);
121         setMinWidth(width);
122         setMaxWidth(width);
123 
124         setCellEditor(table.getDefaultEditor(Boolean.class));
125         setCellRenderer(table.getDefaultRenderer(Boolean.class));
126 
127         // header 
128         setHeaderRenderer(new CheckAllHeaderRenderer(this));
129 
130         // identifier
131         setIdentifier(new CheckTableColumnIdentifier<>());
132     }
133 
134     /**
135      * {@inheritDoc}
136      */
137     @Override
138     @SuppressWarnings("unchecked")
139     public ColumnIdentifier<R> getIdentifier() {
140         return (ColumnIdentifier<R>) super.getIdentifier();
141     }
142 
143     @Override
144     public Integer getFixedPosition() {
145         return 1;
146     }
147 
148     public static final class CheckTableColumnIdentifier<R extends AbstractRowUIModel> extends ColumnIdentifier<R> {
149 
150         /**
151          * <p>Constructor for CheckTableColumnIdentifier.</p>
152          */
153         protected CheckTableColumnIdentifier() {
154             super(AbstractRowUIModel.PROPERTY_SELECTED,
155                 null,
156                 n("quadrige3.table.checkAllColumn.tip"),
157                 Boolean.class,
158                 null,
159                 false);
160         }
161     }
162 
163     private class CheckAllHeaderRenderer extends JCheckBox implements TableCellRenderer {
164 
165         private final CheckTableColumn checkColumn;
166 
167         @SuppressWarnings("unchecked")
168         private CheckAllHeaderRenderer(CheckTableColumn targetColumn) {
169             super((String) null);
170             this.checkColumn = targetColumn;
171 
172             setOpaque(false);
173             setFont(checkColumn.getTable().getTableHeader().getFont());
174 
175             // add mouse listener if the table is editable
176             checkColumn.getTable().getTableHeader().addMouseListener(new MouseAdapter() {
177 
178                 @Override
179                 public void mouseClicked(MouseEvent e) {
180                     SwingTable table = checkColumn.getTable();
181 
182                     if (!table.isEnabled() || !table.isEditable()) {
183                         return;
184                     }
185 
186                     TableColumnModel columnModel = table.getColumnModel();
187                     int vci = columnModel.getColumnIndexAtX(e.getX());
188                     if (table.getColumn(vci) == checkColumn) {
189                         boolean allChecked = !isSelected();
190                         checkColumn.setAllSelected(allChecked);
191                         checkColumn.setAllEnabled(true);
192                         // propagate is selected to all lines
193                         if (checkColumn.getTableModel() != null && checkColumn.getTableModel().getRowCount() > 0) {
194                             for (R row : (List<R>) checkColumn.getTableModel().getRows()) {
195                                 if (!row.isCalculated() /*&& row.isEditable()*/) {
196                                     row.selected = allChecked;
197                                 }
198                             }
199 
200                             // recalculate selected rows
201                             checkColumn.getTableModel().populateSelectedRows();
202                             // redraw immediately
203                             table.getTableHeader().repaint();
204                             table.repaint();
205                         }
206 
207                     }
208                 }
209 
210             });
211         }
212 
213         @Override
214         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
215             if (table == null) {
216                 return new JLabel();
217             }
218             TableCellRenderer r = table.getTableHeader().getDefaultRenderer();
219             JLabel l = (JLabel) r.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
220             if (table.getColumnModel().getColumn(column) == checkColumn) {
221                 // reset allSelected if table is empty
222                 if (!table.isEnabled() || !checkColumn.getTable().isEditable() || table.getRowCount() == 0) checkColumn.setAllSelected(false);
223                 setSelected(checkColumn.isAllSelected());
224                 setEnabled(checkColumn.isAllEnabled());
225                 l.setIcon(new ComponentIcon(this));
226                 l.setHorizontalAlignment(SwingConstants.CENTER);
227                 l.setVerticalAlignment(SwingConstants.TOP);
228             }
229             l.setText(null);
230             return l;
231         }
232 
233     }
234 
235     class ComponentIcon implements Icon {
236 
237         private final JComponent cmp;
238 
239         public ComponentIcon(JComponent cmp) {
240             this.cmp = cmp;
241         }
242 
243         @Override
244         public int getIconWidth() {
245             return cmp.getPreferredSize().width;
246         }
247 
248         @Override
249         public int getIconHeight() {
250             return cmp.getPreferredSize().height;
251         }
252 
253         @Override
254         public void paintIcon(Component c, Graphics g, int x, int y) {
255             SwingUtilities.paintComponent(g, cmp, (Container) c, x, y, getIconWidth(), getIconHeight());
256         }
257     }
258 
259 }