package jimm.datavision.field;
import jimm.datavision.*;
import jimm.datavision.gui.FieldWidget;
import jimm.datavision.gui.FormulaWidget;
import jimm.datavision.gui.SectionWidget;
import java.util.Collection;
import java.util.Observer;
import java.util.Observable;
/**
* A formula field represents a formula calculated on-the-fly. The value of a
* formula field holds a {@link Formula} object. (In the XML, the formula
* field's value is the id of the formula.)
*
* @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
*/
public class FormulaField extends Field implements Observer {
protected Formula formula;
/**
* Constructs a formula field with the specified id in the specified report
* section whose {@link Formula}'s id is <var>value</var>.
*
* @param id the new field's id
* @param report the report containing this element
* @param section the report section in which the field resides
* @param value the id of a formula
* @param visible show/hide flag
*/
public FormulaField(Long id, Report report, Section section, Object value,
boolean visible)
{
super(id, report, section, value, visible);
formula = report.findFormula(value);
formula.addObserver(this);
}
protected void finalize() throws Throwable {
formula.deleteObserver(this);
super.finalize();
}
public void update(Observable o, Object arg) {
setChanged();
notifyObservers(arg);
}
public FieldWidget makeWidget(SectionWidget sw) {
return new FormulaWidget(sw, this);
}
/**
* Not really used; we drag formulas, not formula fields.
*/
public String dragString() {
return typeString() + ":" + formula.getId();
}
/**
* Returns the formula.
*
* @return the formula
*/
public Formula getFormula() { return formula; }
/**
* Sets the formula.
*
* @param newFormula the new formula
*/
public void setFormula(Formula newFormula) {
if (formula != newFormula) {
formula.deleteObserver(this);
formula = newFormula;
formula.addObserver(this);
setChanged();
notifyObservers();
}
}
public String typeString() { return "formula"; }
public String designLabel() { return formula.designLabel(); }
public String formulaString() { return formula.formulaString(); }
public boolean refersTo(Field f) {
return formula.refersTo(f);
}
public boolean refersTo(Formula f) {
return f == formula || formula.refersTo(f);
}
public boolean refersTo(UserColumn uc) {
return formula.refersTo(uc);
}
public boolean refersTo(Parameter p) {
return formula.refersTo(p);
}
/**
* This override returns <code>true</code> if this formula is in a detail
* section. We don't really know that this formula returns a number, so
* we'll err on the side of allowing aggregation.
*
* @return <code>true</code> if this field can be aggregated
*/
public boolean canBeAggregated() {
// Section can be null during dragging.
return section != null && section.isDetail();
}
/**
* Returns the value of this field. For formula fields, this is the
* value generated by evaluating the {@link Formula}.
*
* @return the result of evaluating the formula
*/
public Object getValue() { return formula.eval(this); }
/**
* Returns a collection of the columns used in the formula. This is used
* by the report's query when it is figuring out what columns and tables
* are used by the report. Calls {@link Formula#columnsUsed}.
*
* @return a possibly empty collection of database columns
* @see jimm.datavision.source.Query#findSelectablesUsed
*/
public Collection columnsUsed() {
return formula.columnsUsed();
}
/**
* Returns a collection of the user columns used in the formula. This is
* used by the report's query when it is figuring out what columns, tables,
* and user columns are used by the report. Calls
* {@link Formula#userColumnsUsed}.
*
* @return a possibly empty collection of user columns
* @see jimm.datavision.source.Query#findSelectablesUsed
*/
public Collection userColumnsUsed() {
return formula.userColumnsUsed();
}
}