1 /*
2 * Copyright 2006-2016 The JGUIraffe Team.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License")
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.sf.jguiraffe.gui.platform.swing.builder.components.table;
17
18 import javax.swing.Icon;
19 import javax.swing.JTable;
20 import javax.swing.event.TableModelEvent;
21 import javax.swing.table.AbstractTableModel;
22 import javax.swing.table.TableCellEditor;
23 import javax.swing.table.TableCellRenderer;
24 import java.util.Date;
25 import java.util.EnumMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import net.sf.jguiraffe.gui.builder.components.tags.table.ColumnClass;
30 import net.sf.jguiraffe.gui.builder.components.tags.table.TableFormController;
31 import net.sf.jguiraffe.gui.builder.components.tags.table.TableTag;
32
33 /**
34 * <p>
35 * A table model implementation for tables defined by the {@link TableTag} tag
36 * handler class.
37 * </p>
38 * <p>
39 * This class implements the typical table model functionality based on an
40 * {@link TableFormController} object
41 * provided by a {@code TableTag} instance. Many methods can directly delegate
42 * to the controller object.
43 * </p>
44 *
45 * @author Oliver Heger
46 * @version $Id: SwingTableModel.java 205 2012-01-29 18:29:57Z oheger $
47 */
48 public class SwingTableModel extends AbstractTableModel
49 {
50 /**
51 * The serial version UID.
52 */
53 private static final long serialVersionUID = 5747770889625181193L;
54
55 /** A mapping from logic column classes to Java classes. */
56 private static final Map<ColumnClass, Class<?>> LOGIC_CLASSES;
57
58 /** Stores a reference to the tag defining the table. */
59 private final TableTag tableTag;
60
61 /** The table form controller. */
62 private final TableFormController controller;
63
64 /** Holds a reference to the associated table. */
65 private final JTable table;
66
67 /** Holds a reference to the associated custom renderer implementation. */
68 private transient TableCellRenderer customRenderer;
69
70 /** Holds a reference to the associated custom editor implementation. */
71 private transient TableCellEditor customEditor;
72
73 /**
74 * Creates a new instance of {@code SwingTableModel} and initializes it.
75 *
76 * @param tt the tag defining the underlying table
77 * @param tab the associated table
78 */
79 public SwingTableModel(TableTag tt, JTable tab)
80 {
81 tableTag = tt;
82 table = tab;
83 controller = tt.getTableFormController();
84 }
85
86 /**
87 * Returns the list with the data of this model. The list contains beans
88 * that define the values of the single columns.
89 *
90 * @return the data list of this model
91 */
92 public List<Object> getModelData()
93 {
94 return getController().getDataModel();
95 }
96
97 /**
98 * Returns the table tag this model is based onto.
99 *
100 * @return the table tag
101 */
102 public TableTag getTableTag()
103 {
104 return tableTag;
105 }
106
107 /**
108 * Returns a reference to the associated table.
109 *
110 * @return the table
111 */
112 public JTable getTable()
113 {
114 return table;
115 }
116
117 /**
118 * Returns the number of columns of the represented table.
119 *
120 * @return the number of columns of this table
121 */
122 public int getColumnCount()
123 {
124 return getController().getColumnCount();
125 }
126
127 /**
128 * Returns the number of rows of the represented table.
129 *
130 * @return the number of rows of this table
131 */
132 public int getRowCount()
133 {
134 return getController().getRowCount();
135 }
136
137 /**
138 * Returns the value at the specified cell.
139 *
140 * @param row the row index
141 * @param col the column index
142 * @return the value of this cell
143 */
144 public Object getValueAt(int row, int col)
145 {
146 getController().selectCurrentRow(row);
147 return getController().getColumnValue(col);
148 }
149
150 /**
151 * Returns the data class of the specified column. This implementation
152 * checks whether a logic column class was specified. If this is the case,
153 * it is mapped to the corresponding Java class. Otherwise, the Java class
154 * is directly obtained from the column definition.
155 *
156 * @param col the column index
157 * @return the data class for the specified column
158 */
159 @Override
160 public Class<?> getColumnClass(int col)
161 {
162 Class<?> result = LOGIC_CLASSES.get(getController().getLogicDataClass(col));
163 return (result != null) ? result : getController().getDataClass(col);
164 }
165
166 /**
167 * Returns the name for the specified column.
168 *
169 * @param col the column index
170 * @return the title for this column
171 */
172 @Override
173 public String getColumnName(int col)
174 {
175 return getController().getColumnName(col);
176 }
177
178 /**
179 * Returns a flag whether the specified cell can be modified.
180 *
181 * @param row the row index
182 * @param col the column index
183 * @return a flag whether this cell can be edited
184 */
185 @Override
186 public boolean isCellEditable(int row, int col)
187 {
188 return getController().isColumnEditable(col);
189 }
190
191 /**
192 * Sets the value for the specified cell.
193 *
194 * @param value the value to set
195 * @param row the row index
196 * @param col the column index
197 */
198 @Override
199 public void setValueAt(Object value, int row, int col)
200 {
201 getController().selectCurrentRow(row);
202 getController().setColumnValue(getTable(), col, value);
203 }
204
205 /**
206 * Notifies listeners about a change in the data of this model. This
207 * implementation also notifies the {@code TableFormController} about this
208 * change.
209 *
210 * @param event the event
211 */
212 @Override
213 public void fireTableChanged(TableModelEvent event)
214 {
215 super.fireTableChanged(event);
216 getController()
217 .invalidateRange(event.getFirstRow(), event.getLastRow());
218 }
219
220 /**
221 * Checks whether for the specified column a custom editor is specified.
222 *
223 * @param col the column index
224 * @return a flag if this column has its own editor
225 */
226 public boolean hasEditor(int col)
227 {
228 return getController().hasEditor(col);
229 }
230
231 /**
232 * Returns the cell editor associated with this model. There is exactly one
233 * editor that is capable to serve all columns of this table (that define a
234 * custom editor).
235 *
236 * @return the cell editor used for the represented table
237 */
238 public TableCellEditor getEditor()
239 {
240 if (customEditor == null)
241 {
242 customEditor = new SwingTableCellEditor(this);
243 }
244 return customEditor;
245 }
246
247 /**
248 * Tests whether for the specified column a custom renderer is specified.
249 *
250 * @param col the column index
251 * @return a flag whether this column has a custom renderer
252 */
253 public boolean hasRenderer(int col)
254 {
255 return getController().hasRenderer(col);
256 }
257
258 /**
259 * Returns the cell renderer associated with this model. There is exactly
260 * one renderer that is capable of rendering all columns of this table that
261 * define a custom renderer.
262 *
263 * @return the cell renderer used for the represented table
264 */
265 public TableCellRenderer getRenderer()
266 {
267 if (customRenderer == null)
268 {
269 customRenderer = new SwingTableCellRenderer(this);
270 }
271 return customRenderer;
272 }
273
274 /**
275 * Validates the column with the specified index. This method is always
276 * called when the user has entered data into a cell of the table. It
277 * delegates to the editor form to validate the input fields used in this
278 * column. It will also notify the <code>TableEditorValidationHandler</code>
279 * set for this table. If validation is successful, the value(s) will be
280 * written into the model.
281 *
282 * @param col the column to be validated
283 * @return a flag whether the data is valid
284 */
285 protected boolean validateColumn(int col)
286 {
287 //TODO to be removed when dependend objects have been adapted
288 return true;
289 }
290
291 /**
292 * Returns the {@code TableFormController} used by this model.
293 *
294 * @return the {@code TableFormController}
295 */
296 TableFormController getController()
297 {
298 return controller;
299 }
300
301 static
302 {
303 LOGIC_CLASSES = new EnumMap<ColumnClass, Class<?>>(ColumnClass.class);
304 LOGIC_CLASSES.put(ColumnClass.BOOLEAN, Boolean.class);
305 LOGIC_CLASSES.put(ColumnClass.DATE, Date.class);
306 LOGIC_CLASSES.put(ColumnClass.FLOAT, Double.class);
307 LOGIC_CLASSES.put(ColumnClass.ICON, Icon.class);
308 LOGIC_CLASSES.put(ColumnClass.NUMBER, Number.class);
309 LOGIC_CLASSES.put(ColumnClass.STRING, String.class);
310 }
311 }