View Javadoc

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 }