KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jimm > datavision > field > Field


1 package jimm.datavision.field;
2 import jimm.datavision.*;
3 import jimm.datavision.gui.FieldWidget;
4 import jimm.datavision.gui.SectionWidget;
5 import jimm.util.I18N;
6 import jimm.util.XMLWriter;
7 import java.util.Observable JavaDoc;
8
9 /**
10  * The abstract superclass of visual report fields that display text labels,
11  * database columns, special values, aggregate values, formulas, and
12  * parameters. A field has a bounds {@link Rectangle} that determines its
13  * position within a section and an associated {@link Format} and {@link
14  * Border} for determining how to display the field.
15  * <p>
16  * To avoid repeated font size and line width calculations, a {@link
17  * FormattedValueCache} holds the formatted version of this field's value.
18  *
19  * @author Jim Menard, <a HREF="mailto:jimm@io.com">jimm@io.com</a>
20  */

21 public abstract class Field
22     extends Element
23     implements Identity, Draggable, Cloneable JavaDoc {
24
25 public static final double DEFAULT_WIDTH = 120;
26 public static final double DEFAULT_HEIGHT = 16;
27
28 static Long JavaDoc maxIdSeen = new Long JavaDoc(0);
29
30 protected Long JavaDoc id;
31 protected Rectangle bounds;
32 protected Format format;
33 protected Border border; // Possibly null
34
protected Object JavaDoc value; // String or id (column, formula, etc.)
35
protected FormattedValueCache cache;
36
37 /**
38  * This factory method constructs and returns a new instance of a subclass
39  * of <code>Field</code> based on the <var>type</var> string.
40  * <p>
41  * If <var>id</var> is <code>null</code>, generates a new id number. This
42  * number is one higher than any previously-seen id number. This does
43  * <em>not</em> guarantee that no later field will be created manually with
44  * the same id number.
45  *
46  * @param id the unique identifier for the new field; if <code>null</code>,
47  * generate a new id
48  * @param section the report section containing the field
49  * @param type one of "special", "text", "column", "formula", "parameter",
50  * "image", or one of the aggregate function names; found in report XML
51  */

52 public static Field create(Long JavaDoc id, Report report, Section section,
53                String JavaDoc type, Object JavaDoc value, boolean visible)
54 {
55     if (type == null || type.length() == 0)
56     throw new IllegalArgumentException JavaDoc(I18N.get("Field.field_cap")
57                        + " " + id + ": "
58                        + I18N.get("Field.need_type"));
59     
60     type = type.toLowerCase();
61     if (type.equals("special"))
62     return new SpecialField(id, report, section, value, visible);
63     else if (type.equals("text"))
64     return new TextField(id, report, section, value, visible);
65     else if (type.equals("column"))
66     return new ColumnField(id, report, section, value, visible);
67      else if (type.equals("formula"))
68     return new FormulaField(id, report, section, value, visible);
69     else if (type.equals("parameter"))
70     return new ParameterField(id, report, section, value, visible);
71     else if (type.equals("image"))
72     return new ImageField(id, report, section, value, visible);
73     else if (type.equals("usercol"))
74     return new UserColumnField(id, report, section, value, visible);
75     else if (type.equals("subreport"))
76     return new SubreportField(id, report, section, value, visible);
77     else if (AggregateField.isAggregateFunctionName(type))
78     return new AggregateField(id, report, section, value, visible, type);
79
80     throw new IllegalArgumentException JavaDoc(I18N.get("Field.field_cap") + " " + id
81                        + ": " + I18N.get("Field.unknown")
82                        + " \"" + type + "\"");
83 }
84
85 /**
86  * Creates a field from a drag string. <var>str</var> should a string
87  * created by some field's {@link #dragString} method.
88  *
89  * @param report the report containing this element
90  * @param str a drag string
91  * @return a new field
92  */

93 public static Field createFromDragString(Report report, String JavaDoc str) {
94     int pos = str.indexOf(":");
95     if (pos == -1)
96     return null;
97
98     String JavaDoc type = str.substring(0, pos);
99     String JavaDoc value = str.substring(pos + 1);
100     return create(null, report, null, type, value, true);
101 }
102
103
104
105 /**
106  * Constructor.
107  *
108  * @param id the unique identifier for the new field
109  * @param report the report containing this element
110  * @param section the report section containing the field
111  * @param value the value this field represents visually
112  * @param visible show/hide flag
113  */

114 protected Field(Long JavaDoc id, Report report, Section section, Object JavaDoc value,
115         boolean visible)
116 {
117     super(report, section, visible);
118
119     if (id == null) // Generate new value
120
id = new Long JavaDoc(maxIdSeen.longValue() + 1);
121     if (id.compareTo(maxIdSeen) == 1)
122     maxIdSeen = new Long JavaDoc(id.longValue());
123     this.id = id;
124
125     format = Format.createEmptyFormat();
126     format.setField(this);
127     format.addObserver(this);
128
129     // The defaultField will be null only when we are creating the
130
// default field itself.
131
Field defaultField = report.getDefaultField();
132
133     this.value = value;
134     cache = new FormattedValueCache(this);
135     bounds = defaultField != null
136     ? new Rectangle(0, 0, defaultField.getBounds().width,
137             defaultField.getBounds().height)
138     : new Rectangle(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);
139     bounds.addObserver(this);
140
141     // Make sure changes to the default field are reflected in the GUI
142
if (defaultField != null)
143     defaultField.addObserver(this);
144 }
145
146 /**
147  * Returns a clone. Subclasses may need ot override this method to copy
148  * additional instance variables that are not set in their constructors.
149  *
150  * @return an almost-ready clone of this object
151  */

152 public Object JavaDoc clone() {
153     Field f = Field.create(null, report, section, typeString(), value, true);
154     f.bounds = new Rectangle(bounds);
155     f.format = (Format)format.clone();
156     f.format.setField(f);
157     if (border == null)
158     f.border = null;
159     else {
160     f.border = (Border)border.clone();
161     f.border.setField(f);
162     }
163     return f;
164 }
165
166 protected void finalize() throws Throwable JavaDoc {
167     bounds.deleteObserver(this);
168     if (format != null) format.deleteObserver(this);
169     if (border != null) border.deleteObserver(this);
170 }
171
172 public void update(Observable JavaDoc o, Object JavaDoc arg) {
173     super.update(o, arg);
174     if (format != null)
175     format.clearFontCache();
176 }
177
178 public Object JavaDoc getId() { return id; }
179
180 /**
181  * Returns the bounds rectangle for this field.
182  *
183  * @return the bounds rectangle
184  */

185 public Rectangle getBounds() { return bounds; }
186
187 /**
188  * Sets the bounds rectangle.
189  *
190  * @param newBounds the new bounds rectangle
191  */

192 public void setBounds(Rectangle newBounds) {
193     if (bounds != newBounds) {
194     bounds.deleteObserver(this);
195     bounds = newBounds;
196     bounds.addObserver(this);
197     setChanged();
198     notifyObservers();
199     }
200 }
201
202 /**
203  * Returns the height needed to output the current value of this field.
204  * This default implementation returns the height of the field as
205  * defined in the report designer (the bounds height).
206  */

207 public double getOutputHeight() {
208     return cache.getOutputHeight(getValue());
209 }
210
211 /**
212  * Returns the format for this field. May return <code>null</code>.
213  *
214  * @return the format, possibly <code>null</code>
215  */

216 public Format getFormat() { return format; }
217
218 /**
219  * Sets the format. If this field already has a format, you can just modify
220  * it instead of giving it a completely new one.
221  *
222  * @param newFormat the format
223  */

224 public void setFormat(Format newFormat) {
225     if (format != newFormat) {
226     if (format != null) format.deleteObserver(this);
227     format = newFormat;
228     format.setField(this);
229     if (format != null) format.addObserver(this);
230     setChanged();
231     notifyObservers();
232     }
233 }
234
235 /**
236  * Returns the border for this field. May return <code>null</code>.
237  *
238  * @return the border, possibly <code>null</code>
239  */

240 public Border getBorder() { return border; }
241
242 /**
243  * Returns the border for this field or, if it is <code>null</code>, the
244  * report's default border. If we return the default border, we clone it
245  * in order to give it this field.
246  *
247  * @return this field's border or the default border
248  */

249 public Border getBorderOrDefault() {
250     if (border != null)
251     return border;
252
253     Border b = (Border)report.getDefaultField().getBorder().clone();
254     b.setField(this);
255     return b;
256 }
257
258 /**
259  * Sets the border.
260  *
261  * @param newBorder the new border
262  */

263 public void setBorder(Border newBorder) {
264     if (border != newBorder) {
265     if (border != null) border.deleteObserver(this);
266     border = newBorder;
267     if (border != null) border.addObserver(this);
268     setChanged();
269     notifyObservers();
270     }
271 }
272
273 /**
274  * Returns the value for this field. May return <code>null</code>.
275  *
276  * @return the value, possibly <code>null</code>
277  */

278 public Object JavaDoc getValue() { return value; }
279
280 /**
281  * Sets the value.
282  *
283  * @param newValue the new value
284  */

285 public void setValue(Object JavaDoc newValue) {
286     if (value != newValue) {
287     value = newValue;
288     setChanged();
289     notifyObservers();
290     }
291 }
292
293 /**
294  * Returns a new widget of the appropriate <code>FieldWidget</code>
295  * subclass for this field. Subclasses override this method to return
296  * different types of widgets.
297  *
298  * @param sw a field widget
299  */

300 public FieldWidget makeWidget(SectionWidget sw) {
301     return new FieldWidget(sw, this);
302 }
303
304 /**
305  * Returns the string that specifies this field's type in the report XML.
306  *
307  * @return a string representing this field's type; used in XML files
308  */

309 public abstract String JavaDoc typeString();
310
311 /**
312  * Returns the string used to identify a field type when dragging.
313  * Usually returns {@link #typeString} plus a value or an id.
314  *
315  * @return the string used to identify the field when dragging
316  */

317 public abstract String JavaDoc dragString();
318
319 /**
320  * Returns a string representing the field in the GUI during report design.
321  *
322  * @return a string useful for display in the design GUI
323  */

324 public String JavaDoc designLabel() { return formulaString(); }
325
326 /**
327  * Returns a string representing the field as it appears in a formula.
328  *
329  * @return a string useful in a formula
330  */

331 public abstract String JavaDoc formulaString();
332
333 /**
334  * Returns <code>true</code> if this field contains a reference to the
335  * specified field. Most fields return <code>false</code>; only a {@link
336  * AggregateField} or {@link FormulaField} would return <code>true</code>.
337  *
338  * @param f a field
339  * @return <code>true</code> if this field contains a reference to the
340  * specified field
341  */

342 public boolean refersTo(Field f) {
343     return false;
344 }
345
346 /**
347  * Returns <code>true</code> if this field contains a reference to the
348  * specified formula. Most fields return <code>false</code>; only a {@link
349  * AggregateField} or {@link FormulaField} would return <code>true</code>.
350  *
351  * @param f a formula
352  * @return <code>true</code> if this field contains a reference to the
353  * specified field
354  */

355 public boolean refersTo(Formula f) {
356     return false;
357 }
358
359 /**
360  * Returns <code>true</code> if this field contains a reference to the
361  * specified user column. Most fields return <code>false</code>; only a {@link
362  * AggregateField}, {@link UserColumnField}, or {@link FormulaField} would
363  * return <code>true</code>.
364  *
365  * @param uc a user column
366  * @return <code>true</code> if this field contains a reference to the
367  * specified user column
368  */

369 public boolean refersTo(UserColumn uc) {
370     return false;
371 }
372
373 /**
374  * Returns <code>true</code> if this field contains a reference to the
375  * specified parameter. Most fields return <code>false</code>; only a {@link
376  * AggregateField} or {@link FormulaField} would return <code>true</code>.
377  *
378  * @param p a parameter
379  * @return <code>true</code> if this field contains a reference to the
380  * specified field
381  */

382 public boolean refersTo(Parameter p) {
383     return false;
384 }
385
386 /**
387  * Returns <code>true</code> if this field can be aggregated. This method
388  * returns <code>false</code> by default but is overridded by classes whose
389  * values may be aggregated.
390  *
391  * @return <code>true</code> if this field can be aggregated
392  */

393 public boolean canBeAggregated() {
394     return false;
395 }
396
397 /**
398  * Returns this fields formatted value, ready for display in the report.
399  * If this field is invisible, or <code>getValue</code> returns
400  * <code>null</code> then this method will return <code>null</code>.
401  *
402  * @return the report display string; may be <code>null</code>
403  */

404 public String JavaDoc toString() {
405     if (!visible) return null;
406     return cache.getFormattedString(getValue());
407 }
408
409 /**
410  * Writes this field as an XML tag. Writes bounds, border, and format.
411  *
412  * @param out a writer that knows how to write XML
413  */

414 public void writeXML(XMLWriter out) {
415     out.startElement("field");
416     out.attr("id", id);
417     out.attr("type", typeString());
418     out.attr("value", value);
419     if (!visible)
420     out.attr("visible", visible);
421
422     writeFieldGuts(out);
423
424     out.endElement();
425 }
426
427 /**
428  * Writes objects contained within this field (bounds, border, and format).
429  *
430  * @param out a writer that knows how to write XML
431  */

432 protected void writeFieldGuts(XMLWriter out) {
433     bounds.writeXML(out);
434     if (format != null) format.writeXML(out);
435     if (border != null) border.writeXML(out);
436 }
437
438 }
439
Popular Tags