001/* ---------------------------------------------------------------------------- 002 The Kiwi Toolkit - A Java Class Library 003 Copyright (C) 1998-2004 Mark A. Lindner 004 005 This library is free software; you can redistribute it and/or 006 modify it under the terms of the GNU General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This library is distributed in the hope that it will be useful, 011 but WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 General Public License for more details. 014 015 You should have received a copy of the GNU General Public License 016 along with this library; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 018 02111-1307, USA. 019 020 The author may be contacted at: mark_a_lindner@yahoo.com 021 ---------------------------------------------------------------------------- 022 $Log: DomainObjectTableModel.java,v $ 023 Revision 1.7 2004/05/13 21:38:56 markl 024 comment block updates 025 026 Revision 1.6 2003/04/30 04:36:00 markl 027 Fire model events as appropriate. Added updateObjectAt() method. 028 029 Revision 1.5 2003/01/19 09:33:06 markl 030 Javadoc & comment header updates. 031 032 Revision 1.4 2001/03/12 04:11:42 markl 033 Source code cleanup. 034 035 Revision 1.3 1999/08/13 07:11:35 markl 036 Added support for column widths. 037 038 Revision 1.2 1999/07/25 13:41:44 markl 039 Fixes and API additions. 040 041 Revision 1.1 1999/07/16 07:11:22 markl 042 Initial revision 043 ---------------------------------------------------------------------------- 044*/ 045 046package kiwi.ui.model; 047 048import java.sql.*; 049import java.util.*; 050import javax.swing.*; 051import javax.swing.table.*; 052 053import kiwi.db.*; 054import kiwi.util.*; 055 056/** A <code>TableModel</code> that may be used to display a (potentially 057 * editable) list of persistent domain objects in a <code>JTable</code>. 058 * 059 * @author Mark Lindner 060 * 061 * @see kiwi.db.PersistentObject 062 * @see kiwi.db.DomainObjectFieldAdapter 063 */ 064 065public class DomainObjectTableModel extends AbstractTableModel 066 { 067 private DomainObjectFieldAdapter fieldAdapter; 068 private Vector data; 069 private boolean modified = false; 070 private boolean deferredStore = false; 071 private ExceptionHandler errorHandler = null; 072 073 /** Construct a new <code>DomainObjectTableModel</code> for the given 074 * field adapter. 075 * 076 * @param adapter The field adapter to use. 077 */ 078 079 public DomainObjectTableModel(DomainObjectFieldAdapter adapter) 080 { 081 super(); 082 fieldAdapter = adapter; 083 data = new Vector(); 084 } 085 086 /** Set the <i>deferred store</i> mode for this model. If deferred store is 087 * on (default), editing of a value in the model causes the corresponding 088 * <code>PersistentObject</code> to be written to the persistent store 089 * immediately via a call to its <code>store()</code> method. If deferred 090 * store is off, no automatic stores are performed. 091 * 092 * @param flag A flag that specifies whether deferred mode should be on 093 * (<code>true</code>) or off (<code>false</code>). 094 */ 095 096 public void setDeferredStore(boolean flag) 097 { 098 deferredStore = flag; 099 } 100 101 /** Get the <i>deferred store</i> mode for this model. 102 * 103 * @return <code>true</code> if deferred store is on, and <code>false</code> 104 * otherwise. 105 */ 106 107 public boolean getDeferredStore() 108 { 109 return(deferredStore); 110 } 111 112 /** Get the name of a given column. 113 * 114 * @param column The index of the column. 115 * @return The name of the field that corresponds to the given column. 116 */ 117 118 public String getColumnName(int column) 119 { 120 return(fieldAdapter.getFieldName(column)); 121 } 122 123 /** Add an object to the end of the data vector. A new row will be added 124 * at the bottom of the table model. 125 * 126 * @param object The <code>PersistentObject</code> to add. 127 */ 128 129 public void addObject(PersistentObject object) 130 { 131 int index = data.size(); 132 data.addElement(object); 133 modified = true; 134 135 fireTableRowsInserted(index, index); 136 } 137 138 /** Insert an object at the specified position in the data vector. A new row 139 * will be inserted at the corresponding position in the table model. 140 * 141 * @param object The <code>PersistentObject</code> to add. 142 * @param row The row at which to insert the object. 143 */ 144 145 public void insertObjectAt(PersistentObject object, int row) 146 { 147 data.insertElementAt(object, row); 148 modified = true; 149 150 fireTableRowsInserted(row, row); 151 } 152 153 /** Notify the model that the object at the given row has been updated. 154 * 155 * @param row The row of the updated object. 156 * @since Kiwi 1.4.2 157 */ 158 159 public void updateObjectAt(int row) 160 { 161 if((row < 0) || (row >= data.size())) 162 throw new IllegalArgumentException("Row out of bounds"); 163 164 fireTableRowsUpdated(row, row); 165 } 166 167 /** Remove all objects from the data vector. All rows will be removed from 168 * the table model. 169 */ 170 171 public void clear() 172 { 173 data.removeAllElements(); 174 modified = true; 175 } 176 177 /** Remove the object at the specified position from the data vector. The 178 * row at the corresponding position in the table model will be removed. 179 * 180 * @param row The row of the object to remove. 181 */ 182 183 public void removeObjectAt(int row) 184 { 185 data.removeElementAt(row); 186 modified = true; 187 188 fireTableRowsDeleted(row, row); 189 } 190 191 /** Get the row count for this model. 192 * 193 * @return The number of objects in the data vector (e.g., the number of 194 * rows in the table model). 195 */ 196 197 public int getRowCount() 198 { 199 return(data.size()); 200 } 201 202 /** Get the column count for this model. 203 * 204 * @return The number of columns in this table model (e.g., the number of 205 * fields as reported by the field adapter). 206 */ 207 208 public int getColumnCount() 209 { 210 return(fieldAdapter.getFieldCount()); 211 } 212 213 /** Get the value at the specified row and column in the table model. 214 * 215 * @param row The row. 216 * @param column The column 217 * @return The object at the specified coordinates. 218 */ 219 220 public Object getValueAt(int row, int column) 221 { 222 PersistentObject object = (PersistentObject)data.elementAt(row); 223 return(fieldAdapter.getField(object, column)); 224 } 225 226 /** Set the value at the specified row and column in the table model. 227 * 228 * @param row The row. 229 * @param column The column 230 * @param value The new object for the specified coordinates. 231 */ 232 233 public void setValueAt(Object value, int row, int column) 234 { 235 PersistentObject object = (PersistentObject)data.elementAt(row); 236 try 237 { 238 fieldAdapter.setField(object, column, value); 239 if(!deferredStore) 240 object.store(); 241 modified = true; 242 243 fireTableRowsUpdated(row, row); 244 } 245 catch(MutatorException ex) 246 { 247 _deliverException(ex); 248 } 249 catch(SQLException ex) 250 { 251 _deliverException(ex); 252 } 253 } 254 255 /** Prepare a <code>JTable</code> for use with this model. This method 256 * creates the necessary columns in the <code>JTable</code> and assigns 257 * the appropriate cell renderers and editors (as provided by the field 258 * adapter) for each column. 259 * 260 * @param table The <code>JTable</code> with which this model will be used. 261 */ 262 263 public void prepareJTable(JTable table) 264 { 265 TableColumnModel cmodel = table.getColumnModel(); 266 int cols = cmodel.getColumnCount(); 267 268 for(int i = 0; i < cols; i++) 269 { 270 TableColumn tc = cmodel.getColumn(i); 271 tc.setCellRenderer(fieldAdapter.getCellRenderer(i)); 272 tc.setCellEditor(fieldAdapter.getCellEditor(i)); 273 274 int w = fieldAdapter.getFieldPreferredWidth(i); 275 if(w > 0) 276 tc.setPreferredWidth(w); 277 278 w = fieldAdapter.getFieldMinWidth(i); 279 if(w > 0) 280 tc.setMinWidth(w); 281 282 w = fieldAdapter.getFieldMaxWidth(i); 283 if(w > 0) 284 tc.setMaxWidth(w); 285 } 286 } 287 288 /** Get the <code>PersistentObject</code> for the specified row in the 289 * table model. 290 * 291 * @param row The row. 292 * @return The <code>PersistentObject</code> represented in the given row. 293 * @see #getRowForObject 294 */ 295 296 public PersistentObject getObjectForRow(int row) 297 { 298 return((PersistentObject)data.elementAt(row)); 299 } 300 301 /** Get the row for the specified <code>PersistentObject</code>. 302 * 303 * @param object The <code>PersistentObject</code> to locate. 304 * @return The row in the table model that represents the given object. 305 * @see #getObjectForRow 306 */ 307 308 public int getRowForObject(PersistentObject object) 309 { 310 return(data.indexOf(object)); 311 } 312 313 /** Determine if the cell at the given coordinates is editable. 314 * 315 * @param row The row. 316 * @param column The column. 317 * @return <code>true</code> if the cell at the given row and column is 318 * editable and <code>false</code> otherwise. The field adapter is consulted 319 * to determine if the field corresponding to the given column is mutable. 320 */ 321 322 public boolean isCellEditable(int row, int column) 323 { 324 return(fieldAdapter.isFieldEditable(column)); 325 } 326 327 /** Determine if the data in this model has been modified. 328 * 329 * @return <code>true</code> if modifications have been made, and 330 * <code>false</code> otherwise. 331 * 332 * @see #clearModified 333 */ 334 335 public boolean isModified() 336 { 337 return(modified); 338 } 339 340 /** Clear the modification flag for this model. 341 * 342 * @see #isModified 343 */ 344 345 public void clearModified() 346 { 347 modified = false; 348 } 349 350 /** Get the object type for the specified column. 351 * 352 * @param column The column. 353 * @return A <code>Class</code> object for the specified column. This value 354 * is ultimately obtained by calling the <code>getFieldClass()</code> method 355 * of the field adapter. 356 */ 357 358 public Class getColumnClass(int column) 359 { 360 return(fieldAdapter.getFieldClass(column)); 361 } 362 363 /** Set the <code>ExceptionHandler</code> for this model. If an exception 364 * occurs while a domain object is being updated as a result of a change 365 * to one of the values in this model, the exception is caught and delivered 366 * to the handler (if one is registered). 367 * 368 * @param handler The new (possibly <code>null</code>) exception handler. 369 */ 370 371 public void setExceptionHandler(ExceptionHandler handler) 372 { 373 this.errorHandler = handler; 374 } 375 376 /** Get the current <code>ExceptionHandler</code> for this model. 377 * 378 * @return The current (possibly <code>null</code>) exception handler. 379 */ 380 381 public ExceptionHandler getExceptionHandler() 382 { 383 return(errorHandler); 384 } 385 386 /* Deliver an exception to a handler, if one is registered. */ 387 388 private void _deliverException(Exception ex) 389 { 390 if(errorHandler != null) 391 errorHandler.exceptionRaised(ex); 392 } 393 394 } 395 396/* end of source file */