Field.java :  » Report » datavision-1.1.0 » jimm » datavision » field » Java Open Source

Java Open Source » Report » datavision 1.1.0 
datavision 1.1.0 » jimm » datavision » field » Field.java
package jimm.datavision.field;
import jimm.datavision.*;
import jimm.datavision.gui.FieldWidget;
import jimm.datavision.gui.SectionWidget;
import jimm.util.I18N;
import jimm.util.XMLWriter;
import java.util.Observable;

/**
 * The abstract superclass of visual report fields that display text labels,
 * database columns, special values, aggregate values, formulas, and
 * parameters. A field has a bounds {@link Rectangle} that determines its
 * position within a section and an associated {@link Format} and {@link
 * Border} for determining how to display the field.
 * <p>
 * To avoid repeated font size and line width calculations, a {@link
 * FormattedValueCache} holds the formatted version of this field's value.
 *
 * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
 */
public abstract class Field
    extends Element
    implements Identity, Draggable, Cloneable {

public static final double DEFAULT_WIDTH = 120;
public static final double DEFAULT_HEIGHT = 16;

static Long maxIdSeen = new Long(0);

protected Long id;
protected Rectangle bounds;
protected Format format;
protected Border border;  // Possibly null
protected Object value;    // String or id (column, formula, etc.)
protected FormattedValueCache cache;

/**
 * This factory method constructs and returns a new instance of a subclass
 * of <code>Field</code> based on the <var>type</var> string.
 * <p>
 * If <var>id</var> is <code>null</code>, generates a new id number. This
 * number is one higher than any previously-seen id number. This does
 * <em>not</em> guarantee that no later field will be created manually with
 * the same id number.
 *
 * @param id the unique identifier for the new field; if <code>null</code>,
 * generate a new id
 * @param section the report section containing the field
 * @param type one of "special", "text", "column", "formula", "parameter",
 * "image", or one of the aggregate function names; found in report XML
 */
public static Field create(Long id, Report report, Section section,
         String type, Object value, boolean visible)
{
    if (type == null || type.length() == 0)
  throw new IllegalArgumentException(I18N.get("Field.field_cap")
             + " " + id + ": "
             + I18N.get("Field.need_type"));
  
    type = type.toLowerCase();
    if (type.equals("special"))
  return new SpecialField(id, report, section, value, visible);
    else if (type.equals("text"))
  return new TextField(id, report, section, value, visible);
    else if (type.equals("column"))
  return new ColumnField(id, report, section, value, visible);
     else if (type.equals("formula"))
  return new FormulaField(id, report, section, value, visible);
    else if (type.equals("parameter"))
  return new ParameterField(id, report, section, value, visible);
    else if (type.equals("image"))
  return new ImageField(id, report, section, value, visible);
    else if (type.equals("usercol"))
  return new UserColumnField(id, report, section, value, visible);
    else if (type.equals("subreport"))
  return new SubreportField(id, report, section, value, visible);
    else if (AggregateField.isAggregateFunctionName(type))
  return new AggregateField(id, report, section, value, visible, type);

    throw new IllegalArgumentException(I18N.get("Field.field_cap") + " " + id
               + ": " + I18N.get("Field.unknown")
               + " \"" + type + "\"");
}

/**
 * Creates a field from a drag string. <var>str</var> should a string
 * created by some field's {@link #dragString} method.
 *
 * @param report the report containing this element
 * @param str a drag string
 * @return a new field
 */
public static Field createFromDragString(Report report, String str) {
    int pos = str.indexOf(":");
    if (pos == -1)
  return null;

    String type = str.substring(0, pos);
    String value = str.substring(pos + 1);
    return create(null, report, null, type, value, true);
}



/**
 * Constructor.
 *
 * @param id the unique identifier for the new field
 * @param report the report containing this element
 * @param section the report section containing the field
 * @param value the value this field represents visually
 * @param visible show/hide flag
 */
protected Field(Long id, Report report, Section section, Object value,
    boolean visible)
{
    super(report, section, visible);

    if (id == null)    // Generate new value
  id = new Long(maxIdSeen.longValue() + 1);
    if (id.compareTo(maxIdSeen) == 1)
  maxIdSeen = new Long(id.longValue());
    this.id = id;

    format = Format.createEmptyFormat();
    format.setField(this);
    format.addObserver(this);

    // The defaultField will be null only when we are creating the
    // default field itself.
    Field defaultField = report.getDefaultField();

    this.value = value;
    cache = new FormattedValueCache(this);
    bounds = defaultField != null
  ? new Rectangle(0, 0, defaultField.getBounds().width,
      defaultField.getBounds().height)
  : new Rectangle(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);
    bounds.addObserver(this);

    // Make sure changes to the default field are reflected in the GUI
    if (defaultField != null)
  defaultField.addObserver(this);
}

/**
 * Returns a clone. Subclasses may need ot override this method to copy
 * additional instance variables that are not set in their constructors.
 *
 * @return an almost-ready clone of this object
 */
public Object clone() {
    Field f = Field.create(null, report, section, typeString(), value, true);
    f.bounds = new Rectangle(bounds);
    f.format = (Format)format.clone();
    f.format.setField(f);
    if (border == null)
  f.border = null;
    else {
  f.border = (Border)border.clone();
  f.border.setField(f);
    }
    return f;
}

protected void finalize() throws Throwable {
    bounds.deleteObserver(this);
    if (format != null) format.deleteObserver(this);
    if (border != null) border.deleteObserver(this);
}

public void update(Observable o, Object arg) {
    super.update(o, arg);
    if (format != null)
  format.clearFontCache();
}

public Object getId() { return id; }

/**
 * Returns the bounds rectangle for this field.
 *
 * @return the bounds rectangle
 */
public Rectangle getBounds() { return bounds; }

/**
 * Sets the bounds rectangle.
 *
 * @param newBounds the new bounds rectangle
 */
public void setBounds(Rectangle newBounds) {
    if (bounds != newBounds) {
  bounds.deleteObserver(this);
  bounds = newBounds;
  bounds.addObserver(this);
  setChanged();
  notifyObservers();
    }
}

/**
 * Returns the height needed to output the current value of this field.
 * This default implementation returns the height of the field as
 * defined in the report designer (the bounds height).
 */
public double getOutputHeight() {
    return cache.getOutputHeight(getValue());
}

/**
 * Returns the format for this field. May return <code>null</code>.
 *
 * @return the format, possibly <code>null</code>
 */
public Format getFormat() { return format; }

/**
 * Sets the format. If this field already has a format, you can just modify
 * it instead of giving it a completely new one.
 *
 * @param newFormat the format
 */
public void setFormat(Format newFormat) {
    if (format != newFormat) {
  if (format != null) format.deleteObserver(this);
  format = newFormat;
  format.setField(this);
  if (format != null) format.addObserver(this);
  setChanged();
  notifyObservers();
    }
}

/**
 * Returns the border for this field. May return <code>null</code>.
 *
 * @return the border, possibly <code>null</code>
 */
public Border getBorder() { return border; }

/**
 * Returns the border for this field or, if it is <code>null</code>, the
 * report's default border. If we return the default border, we clone it
 * in order to give it this field.
 *
 * @return this field's border or the default border
 */
public Border getBorderOrDefault() {
    if (border != null)
  return border;

    Border b = (Border)report.getDefaultField().getBorder().clone();
    b.setField(this);
    return b;
}

/**
 * Sets the border.
 *
 * @param newBorder the new border
 */
public void setBorder(Border newBorder) {
    if (border != newBorder) {
  if (border != null) border.deleteObserver(this);
  border = newBorder;
  if (border != null) border.addObserver(this);
  setChanged();
  notifyObservers();
    }
}

/**
 * Returns the value for this field. May return <code>null</code>.
 *
 * @return the value, possibly <code>null</code>
 */
public Object getValue() { return value; }

/**
 * Sets the value.
 *
 * @param newValue the new value
 */
public void setValue(Object newValue) {
    if (value != newValue) {
  value = newValue;
  setChanged();
  notifyObservers();
    }
}

/**
 * Returns a new widget of the appropriate <code>FieldWidget</code>
 * subclass for this field. Subclasses override this method to return
 * different types of widgets.
 *
 * @param sw a field widget
 */
public FieldWidget makeWidget(SectionWidget sw) {
    return new FieldWidget(sw, this);
}

/**
 * Returns the string that specifies this field's type in the report XML.
 *
 * @return a string representing this field's type; used in XML files
 */
public abstract String typeString();

/**
 * Returns the string used to identify a field type when dragging.
 * Usually returns {@link #typeString} plus a value or an id.
 *
 * @return the string used to identify the field when dragging
 */
public abstract String dragString();

/**
 * Returns a string representing the field in the GUI during report design.
 *
 * @return a string useful for display in the design GUI
 */
public String designLabel() { return formulaString(); }

/**
 * Returns a string representing the field as it appears in a formula.
 *
 * @return a string useful in a formula
 */
public abstract String formulaString();

/**
 * Returns <code>true</code> if this field contains a reference to the
 * specified field. Most fields return <code>false</code>; only a {@link
 * AggregateField} or {@link FormulaField} would return <code>true</code>.
 *
 * @param f a field
 * @return <code>true</code> if this field contains a reference to the
 * specified field
 */
public boolean refersTo(Field f) {
    return false;
}

/**
 * Returns <code>true</code> if this field contains a reference to the
 * specified formula. Most fields return <code>false</code>; only a {@link
 * AggregateField} or {@link FormulaField} would return <code>true</code>.
 *
 * @param f a formula
 * @return <code>true</code> if this field contains a reference to the
 * specified field
 */
public boolean refersTo(Formula f) {
    return false;
}

/**
 * Returns <code>true</code> if this field contains a reference to the
 * specified user column. Most fields return <code>false</code>; only a {@link
 * AggregateField}, {@link UserColumnField}, or {@link FormulaField} would
 * return <code>true</code>.
 *
 * @param uc a user column
 * @return <code>true</code> if this field contains a reference to the
 * specified user column
 */
public boolean refersTo(UserColumn uc) {
    return false;
}

/**
 * Returns <code>true</code> if this field contains a reference to the
 * specified parameter. Most fields return <code>false</code>; only a {@link
 * AggregateField} or {@link FormulaField} would return <code>true</code>.
 *
 * @param p a parameter
 * @return <code>true</code> if this field contains a reference to the
 * specified field
 */
public boolean refersTo(Parameter p) {
    return false;
}

/**
 * Returns <code>true</code> if this field can be aggregated. This method
 * returns <code>false</code> by default but is overridded by classes whose
 * values may be aggregated.
 *
 * @return <code>true</code> if this field can be aggregated
 */
public boolean canBeAggregated() {
    return false;
}

/**
 * Returns this fields formatted value, ready for display in the report.
 * If this field is invisible, or <code>getValue</code> returns
 * <code>null</code> then this method will return <code>null</code>.
 *
 * @return the report display string; may be <code>null</code>
 */
public String toString() {
    if (!visible) return null;
    return cache.getFormattedString(getValue());
}

/**
 * Writes this field as an XML tag. Writes bounds, border, and format.
 *
 * @param out a writer that knows how to write XML
 */
public void writeXML(XMLWriter out) {
    out.startElement("field");
    out.attr("id", id);
    out.attr("type", typeString());
    out.attr("value", value);
    if (!visible)
  out.attr("visible", visible);

    writeFieldGuts(out);

    out.endElement();
}

/**
 * Writes objects contained within this field (bounds, border, and format).
 *
 * @param out a writer that knows how to write XML
 */
protected void writeFieldGuts(XMLWriter out) {
    bounds.writeXML(out);
    if (format != null) format.writeXML(out);
    if (border != null) border.writeXML(out);
}

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.