001 package org.springframework.richclient.widget.table;
002
003 import org.springframework.binding.form.FormModel;
004 import org.springframework.context.support.DefaultMessageSourceResolvable;
005 import org.springframework.richclient.form.binding.BindingFactory;
006 import org.springframework.richclient.form.binding.swing.SwingBindingFactory;
007 import org.springframework.richclient.util.RcpSupport;
008 import org.springframework.richclient.widget.editor.AbstractDataEditorWidget;
009
010 import javax.swing.table.TableCellEditor;
011 import javax.swing.table.TableCellRenderer;
012 import java.util.Comparator;
013
014 /**
015 * A column descriptor to access a specific property. Minimal configuration includes the propertyName and an
016 * {@link Accessor}. Other features can be set using the normal bean setters and getters or through a number
017 * of chaining methods. The latter is particularly useful to create columns by instantiating the column with
018 * the minimum requirements and then adding all settings in one go.
019 *
020 * @author Jan Hoskens
021 * @since 0.5.0
022 */
023 public class PropertyColumn
024 {
025
026 /** No specific width set. */
027 public static final int UNSPECIFIED_WIDTH = -1;
028
029 /** Type of the property. */
030 private Class<?> type;
031
032 /** Accessor for the property. */
033 private Accessor accessor;
034
035 /** Name of the property. */
036 private String propertyName;
037
038 /** Header keys used to fetch the column header label from the message resource. */
039 private String[] headerKeys;
040
041 /** Maximum width of the column. */
042 private int maxWidth = UNSPECIFIED_WIDTH;
043
044 /** Minimum width of the column. */
045 private int minWidth = UNSPECIFIED_WIDTH;
046
047 /** Is it possible to resize column? */
048 private boolean resizable = true;
049
050 /** A specific renderer for the column. */
051 private TableCellRenderer renderer;
052
053 /** A specific editor for the column. */
054 private TableCellEditor editor;
055
056 /** Comparator to use when sorting according to this column. */
057 private Comparator<?> comparator;
058
059 /** Is this column a select column? */
060 private boolean isSelectColumn = false;
061
062 /** Can this column be used when filtering locally? */
063 private boolean isFilterColumn = false;
064
065 /** Is the column initially visible? */
066 private boolean visible = true;
067
068 /** Header title fetched from header keys or manually set. */
069 private String header = null;
070
071 public PropertyColumn(final String propertyName)
072 {
073 this.propertyName = propertyName;
074 }
075
076 /**
077 * Minimal construction requires a propertyName and an {@link Accessor}.
078 *
079 * @param propertyName
080 * name of the property.
081 * @param accessor
082 * read-access for the property.
083 */
084 public PropertyColumn(final String propertyName, final Accessor accessor, final Class<?> propertyType)
085 {
086 this.propertyName = propertyName;
087 this.accessor = accessor;
088 this.type = propertyType;
089 }
090
091 /**
092 * Constructor taking all possible arguments.
093 *
094 * @deprecated Please use the other system (minimal constructor + adding necessary elements)
095 */
096 public PropertyColumn(final Class<?> type, final Accessor accessor, final String propertyName,
097 final String[] headerKeys, final int minWidth, final int maxWidth, final boolean resizable,
098 TableCellRenderer renderer, TableCellEditor editor, final Comparator<?> comparator,
099 final boolean isSelectColumn, final boolean visible)
100 {
101 this.type = type;
102 this.accessor = accessor;
103 this.propertyName = propertyName;
104 this.headerKeys = headerKeys;
105 this.minWidth = minWidth;
106 this.maxWidth = maxWidth;
107 this.resizable = resizable;
108 this.editor = editor;
109 this.renderer = renderer;
110 this.comparator = comparator;
111 this.isSelectColumn = isSelectColumn;
112 this.visible = visible;
113 }
114
115 /**
116 * Set the accessor to use when retrieving the property value.
117 *
118 * @param accessor the {@link Accessor} to read the property value.
119 */
120 public void setAccessor(Accessor accessor)
121 {
122 this.accessor = accessor;
123 }
124
125 /**
126 * The type of the property.
127 *
128 * @param type the type of the property.
129 */
130 public void setType(Class<?> type)
131 {
132 this.type = type;
133 }
134
135 /**
136 * Returns the header to be used as column title. If no explicit header was set, the headerKeys are used
137 * to fetch a message from the available resources.
138 */
139 public String getHeader()
140 {
141 if (this.header == null)
142 {
143 if (this.headerKeys == null)
144 {
145 this.headerKeys = new String[2];
146 this.headerKeys[0] = getPropertyName() + ".header";
147 this.headerKeys[1] = getPropertyName();
148 }
149 this.header = RcpSupport.getMessage(new DefaultMessageSourceResolvable(this.headerKeys, null,
150 this.headerKeys[this.headerKeys.length - 1]));
151 }
152 // JTableHeader has a reusable defaultHeaderRenderer on which the default height must be correct.
153 // when painting, the columns headers are processed in order and height is being calculated,
154 // if label is null or empty string header height is 4 and thus leaves us with a very small
155 // table-header, fix this by returning a space (-> font-size is incorporated)
156 return "".equals(this.header) ? " " : this.header;
157 }
158
159 /**
160 * Returns the header keys that are used to fetch the column title if the header property is not set.
161 */
162 public String[] getHeaderKeys()
163 {
164 return headerKeys == null ? null : headerKeys.clone();
165 }
166
167 /**
168 * Chaining method to set header keys.
169 *
170 * @param headerKeys
171 * keys used to fetch the column title from the resources if no header is explicitly set.
172 * @return <code>this</code>
173 */
174 public PropertyColumn withHeaderKeys(String[] headerKeys)
175 {
176 setHeaderKeys(headerKeys);
177 return this;
178 }
179
180 /**
181 * Set the keys used to fetch the column title from the resources if no header is explicitly set.
182 */
183 public void setHeaderKeys(String[] headerKeys)
184 {
185 this.headerKeys = headerKeys;
186 }
187
188 /**
189 * Returns the maximum width for this column.
190 */
191 public int getMaxWidth()
192 {
193 return maxWidth;
194 }
195
196 /**
197 * Chaining method to set the maximum width.
198 *
199 * @param maxWidth
200 * maximum width for this column
201 * @return <code>this</code>
202 */
203 public PropertyColumn withMaxWidth(int maxWidth)
204 {
205 setMaxWidth(maxWidth);
206 return this;
207 }
208
209 /**
210 * Set the maximum width of this column.
211 */
212 public void setMaxWidth(int maxWidth)
213 {
214 this.maxWidth = maxWidth;
215 }
216
217 /**
218 * Returns the minimum width for this column.
219 */
220 public int getMinWidth()
221 {
222 return minWidth;
223 }
224
225 /**
226 * Chaining method to set the minimum width.
227 *
228 * @param minWidth
229 * minimum width for this column
230 * @return <code>this</code>
231 */
232 public PropertyColumn withMinWidth(int minWidth)
233 {
234 setMinWidth(minWidth);
235 return this;
236 }
237
238 /**
239 * Set the minimum width for this column.
240 */
241 public void setMinWidth(int minWidth)
242 {
243 this.minWidth = minWidth;
244 }
245
246 /**
247 * Chaining method to set the minimum and maximum width to the same value. This will create a fixed width
248 * column.
249 *
250 * @param width
251 * fixed width for this column
252 * @return <code>this</code>
253 */
254 public PropertyColumn withFixedWidth(int width)
255 {
256 setMinWidth(width);
257 setMaxWidth(width);
258 return this;
259 }
260
261 public boolean isResizable()
262 {
263 return resizable;
264 }
265
266 public PropertyColumn withResizable(boolean resizable)
267 {
268 setResizable(resizable);
269 return this;
270 }
271
272 public void setResizable(boolean resizable)
273 {
274 this.resizable = resizable;
275 }
276
277 public PropertyColumn withFilterColumn(boolean isFilterColumn)
278 {
279 setFilterColumn(isFilterColumn);
280 return this;
281 }
282
283 public void setFilterColumn(boolean isFilterColumn)
284 {
285 this.isFilterColumn = isFilterColumn;
286 }
287
288 public boolean isFilterColumn()
289 {
290 return isFilterColumn;
291 }
292
293 public TableCellRenderer getRenderer()
294 {
295 return renderer;
296 }
297
298 public PropertyColumn withRenderer(TableCellRenderer renderer)
299 {
300 setRenderer(renderer);
301 return this;
302 }
303
304 public void setRenderer(TableCellRenderer renderer)
305 {
306 this.renderer = renderer;
307 }
308
309 public TableCellEditor getEditor()
310 {
311 return editor;
312 }
313
314 public PropertyColumn withEditor(TableCellEditor editor)
315 {
316 setEditor(editor);
317 return this;
318 }
319
320 public PropertyColumn withEditor(BindingFactory bindingFactory)
321 {
322 return withEditor(new ValueModelTableCellEditor(bindingFactory.getFormModel(), getPropertyName(),
323 bindingFactory.createBinding(getType(), getPropertyName()).getControl()));
324 }
325
326 public PropertyColumn withEditor(FormModel formModel)
327 {
328 return withEditor(new SwingBindingFactory(formModel));
329 }
330
331 public PropertyColumn withEditor(AbstractDataEditorWidget dataEditor)
332 {
333 FormModel formModel = dataEditor.getDetailForm().getFormModel();
334 BindingFactory bindingFactory = dataEditor.getDetailForm().getBindingFactory();
335 return withEditor(new ValueModelTableCellEditor(formModel, getPropertyName(),
336 bindingFactory.createBinding(getType(), getPropertyName()).getControl(), dataEditor.getUpdateCommand()));
337 }
338
339 public void setEditor(TableCellEditor editor)
340 {
341 this.editor = editor;
342 }
343
344 public Comparator<?> getComparator()
345 {
346 return comparator;
347 }
348
349 public PropertyColumn withComparator(Comparator<?> comparator)
350 {
351 setComparator(comparator);
352 return this;
353 }
354
355 public void setComparator(Comparator<?> comparator)
356 {
357 this.comparator = comparator;
358 }
359
360 public PropertyColumn withSelectColumn(boolean isSelectColumn)
361 {
362 setSelectColumn(isSelectColumn);
363 return this;
364 }
365
366 public boolean isSelectColumn()
367 {
368 return isSelectColumn;
369 }
370
371 public void setSelectColumn(boolean isSelectColumn)
372 {
373 this.isSelectColumn = isSelectColumn;
374 }
375
376 public boolean isVisible()
377 {
378 return visible;
379 }
380
381 public PropertyColumn withVisible(boolean visible)
382 {
383 setVisible(visible);
384 return this;
385 }
386
387 public void setVisible(boolean visible)
388 {
389 this.visible = visible;
390 }
391
392 public Class<?> getType()
393 {
394 return type;
395 }
396
397 public Accessor getAccessor()
398 {
399 return accessor;
400 }
401
402 public String getPropertyName()
403 {
404 return propertyName;
405 }
406
407 public void setHeader(String header)
408 {
409 this.header = header;
410 }
411
412
413 }