0001: /*
0002: The contents of this file are subject to the Common Public Attribution License
0003: Version 1.0 (the "License"); you may not use this file except in compliance with
0004: the License. You may obtain a copy of the License at
0005: http://www.projity.com/license . The License is based on the Mozilla Public
0006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
0007: software over a computer network and provide for limited attribution for the
0008: Original Developer. In addition, Exhibit A has been modified to be consistent
0009: with Exhibit B.
0010:
0011: Software distributed under the License is distributed on an "AS IS" basis,
0012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
0013: specific language governing rights and limitations under the License. The
0014: Original Code is OpenProj. The Original Developer is the Initial Developer and
0015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
0016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
0017:
0018: Alternatively, the contents of this file may be used under the terms of the
0019: Projity End-User License Agreeement (the Projity License), in which case the
0020: provisions of the Projity License are applicable instead of those above. If you
0021: wish to allow use of your version of this file only under the terms of the
0022: Projity License and not to allow others to use your version of this file under
0023: the CPAL, indicate your decision by deleting the provisions above and replace
0024: them with the notice and other provisions required by the Projity License. If
0025: you do not delete the provisions above, a recipient may use your version of this
0026: file under either the CPAL or the Projity License.
0027:
0028: [NOTE: The text of this license may differ slightly from the text of the notices
0029: in Exhibits A and B of the license at http://www.projity.com/license. You should
0030: use the latest text at http://www.projity.com/license for your modifications.
0031: You may not remove this license text from the source files.]
0032:
0033: Attribution Information: Attribution Copyright Notice: Copyright � 2006, 2007
0034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
0035: an open source solution from Projity. Attribution URL: http://www.projity.com
0036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
0037: alternatives listed on http://www.projity.com/logo
0038:
0039: Display of Attribution Information is required in Larger Works which are defined
0040: in the CPAL as a work which combines Covered Code or portions thereof with code
0041: not governed by the terms of the CPAL. However, in addition to the other notice
0042: obligations, all copies of the Covered Code in Executable and Source Code form
0043: distributed must, as a form of attribution of the original author, include on
0044: each user interface screen the "OpenProj" logo visible to all users. The
0045: OpenProj logo should be located horizontally aligned with the menu bar and left
0046: justified on the top left of the screen adjacent to the File menu. The logo
0047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
0048: must direct them back to http://www.projity.com.
0049: */
0050: package com.projity.field;
0051:
0052: import java.lang.reflect.InvocationTargetException;
0053: import java.lang.reflect.Method;
0054: import java.text.Format;
0055: import java.text.NumberFormat;
0056: import java.text.ParseException;
0057: import java.text.SimpleDateFormat;
0058: import java.util.ArrayList;
0059: import java.util.Collection;
0060: import java.util.Comparator;
0061: import java.util.Date;
0062: import java.util.Iterator;
0063: import java.util.Map;
0064:
0065: import javax.swing.JTextField;
0066:
0067: import org.apache.commons.beanutils.MethodUtils;
0068: import org.apache.commons.beanutils.PropertyUtils;
0069: import org.apache.commons.collections.comparators.ComparableComparator;
0070: import org.apache.commons.lang.builder.ToStringBuilder;
0071:
0072: import com.projity.configuration.Configuration;
0073: import com.projity.configuration.FieldDictionary;
0074: import com.projity.contrib.util.Log;
0075: import com.projity.contrib.util.LogFactory;
0076: import com.projity.datatype.Duration;
0077: import com.projity.datatype.DurationFormat;
0078: import com.projity.datatype.Hyperlink;
0079: import com.projity.datatype.Money;
0080: import com.projity.datatype.PercentFormat;
0081: import com.projity.datatype.RateFormat;
0082: import com.projity.datatype.TimeUnit;
0083: import com.projity.datatype.Work;
0084: import com.projity.document.Document;
0085: import com.projity.field.Select.InvalidChoiceException;
0086: import com.projity.grouping.core.GroupNodeImpl;
0087: import com.projity.grouping.core.Node;
0088: import com.projity.grouping.core.VoidNodeImpl;
0089: import com.projity.grouping.core.hierarchy.BelongsToHierarchy;
0090: import com.projity.grouping.core.model.NodeModel;
0091: import com.projity.grouping.core.model.WalkersNodeModel;
0092: import com.projity.grouping.core.summaries.NodeWalker;
0093: import com.projity.grouping.core.summaries.SummaryNames;
0094: import com.projity.grouping.core.summaries.SummaryVisitor;
0095: import com.projity.grouping.core.summaries.SummaryVisitorFactory;
0096: import com.projity.options.CalendarOption;
0097: import com.projity.options.EditOption;
0098: import com.projity.pm.calendar.WorkingCalendar;
0099: import com.projity.pm.task.BelongsToDocument;
0100: import com.projity.pm.task.Project;
0101: import com.projity.pm.time.Interval;
0102: import com.projity.scripting.ScriptedFormula;
0103: import com.projity.server.data.DataObject;
0104: import com.projity.strings.Messages;
0105: import com.projity.util.ClassUtils;
0106:
0107: /**
0108: *
0109: */
0110: public class Field implements SummaryNames, Cloneable, Comparable,
0111: Finder, Comparator {
0112: static Log log = LogFactory.getLog(FieldDictionary.class);
0113: private static final String EMPTY_STRING = "";
0114: private static final String PASSWORD_MASK = "********";
0115: private static final String NON_IMPLEMENTED = "<not implemented>";
0116: public static final String NOT_APPLICABLE = "<N/A>";
0117: public static final String NO_CHOICE = "";
0118: public static final String MULTIPLE_VALUES = Messages
0119: .getString("Symbol.multipleValues");
0120: private String configurationId; // what's read in from config file.
0121: private String id; // id read from config or modified if array field
0122: private String name; // id converted to string from properties file
0123: private String englishName;
0124: private Select select = null;
0125: private OptionsFilter filter = null;
0126: private FieldAccessible accessControl = null;
0127: private ScriptedFormula formula = null;
0128: private int summary = NONE;
0129: private int groupSummary = NONE;
0130: private Range range = null;
0131: private Integer ZERO = new Integer(0);
0132: private boolean nameField = false;
0133: private boolean map = false;
0134: private String url = null;
0135: private boolean image = false;
0136: private boolean startValue = false; // for dates, whether to use start of day
0137: private boolean endValue = false; // for dates, whether to end of day
0138: boolean dateOnly = false; // for date fields, whether to show time
0139: private String extraCategory = null; // for extra fields, such as those from salesforce
0140: // reflection info - these do not change, so that can be reused across all
0141: // fields
0142: private static Class[] getterParams = new Class[] {};
0143: private static Class[] getterIndexedParams = new Class[] { int.class };
0144: private static Class[] getterContextParams = new Class[] { FieldContext.class }; // context
0145: private static Class[] getterIndexedContextParams = new Class[] {
0146: int.class, FieldContext.class }; // context
0147: private String property;
0148: private String referencedObjectProperty = null;
0149: private String referencedIdProperty = null;
0150: private String finder = null;
0151: private Class clazz = null;
0152: private Method methodGet = null;
0153: private Method methodSet = null;
0154: private Method methodReset = null;
0155: private Method methodReadOnly = null;
0156: private Method methodHide = null;
0157: private Method methodOptions = null;
0158: private Method finderMethod = null;
0159: private Class internalType = null; // return type of getter
0160: private Class externalType = null; // if non null then its the logical
0161: // type. For example, externalType=Date,
0162: // internalType=long for date values
0163: private Class displayType = null;
0164: private Object defaultValue = null;
0165: private String errorMessage = null;
0166: private int textWidth = Integer.MAX_VALUE;
0167: private int columnWidth = 0; // column width for spreadsheet
0168: private int svgColumnWidth = 0; //due to font conversion svg column width can different
0169: private Comparator comparator = null;
0170: private boolean getHasNoContext = false; // if the getter is just a property getter
0171: private boolean setHasNoContext = false; // if the setter is just a property setter
0172: private boolean resetHasNoContext = false; // if reset is just a getter
0173: private boolean readOnlyHasNoContext = false; // if read-only is just a getter
0174: private boolean hideHasNoContext = false; // if hide is just a getter
0175: private boolean optionsHasNoContext = false; // if options is just a getter
0176:
0177: // properties that can be set from XML
0178: private boolean readOnly = false; // if value is always read only
0179: private boolean dontLimitToChoices = false; // if a choice list exists and
0180: // value need not be in the list
0181: private boolean scalar = true; // if the value can be accessed as a scalar
0182: // (normal case)
0183: private boolean vector = false; // if the value can be accessed as a vector
0184: private boolean cantReset = false; // if the field can't be reset
0185: private boolean hideZeroValues = false; // if the field text should be null
0186: // if value is default
0187: private boolean callValidateOnClear = false; // if the value must be
0188: // validated on clearing
0189:
0190: private boolean password = false; // if the value is a password and should
0191: // not be displayed
0192: private boolean money = false; // if the value is a money
0193: private boolean percent = false; // if the value is a percentage and
0194: // should be displayed as such
0195: private boolean duration = false; // if the field holds a duration
0196: private boolean rate = false; // if the field holds a value
0197: private boolean work = false; // if the field holds a work value
0198: private boolean date = false; // if the field holds a date
0199: private boolean zeroBasedIndex = false; // if should create a 0 index too.
0200: private int indexes = 0; // nonzero number of elements
0201: private int index = 0; // index of this field in indexed property
0202: private boolean memo = false; // if the field is a multiline edit.
0203: private boolean dynamicOptions = false; // whether a combo needs to be
0204: // evaluated every time shown
0205: private boolean hasToolTip = false;
0206: private boolean validOnObjectCreate = true; // whether this field can appear on New Item Dialogs.
0207: private boolean dirtiesWholeDocument = false; // wehter modifying this field causes all parts of its document to be dirty
0208: private String action = null;
0209: private boolean graphical = false; // to flag for fields like indicator
0210: private FieldContext specialFieldContext = null; // for web to set exact context
0211: public String lookupTypes = null; // types separated by semicolons
0212: private boolean server;
0213: private String help = null;
0214: private String alias = null;
0215: private boolean custom = false;
0216:
0217: /*
0218: * (non-Javadoc)
0219: *
0220: * @see java.lang.Object#toString()
0221: */
0222: public String toString() {
0223: return getName();
0224: }
0225:
0226: /**
0227: * @param range
0228: * The range to set.
0229: */
0230: public void setRange(Range range) {
0231: this .range = range;
0232: }
0233:
0234: public Range getRange() {
0235: return range;
0236: }
0237:
0238: /**
0239: * Fields are constructed using chained properties
0240: *
0241: */
0242: public Field() {
0243: }
0244:
0245: public final void setProperty(String property) {
0246: this .property = property;
0247: }
0248:
0249: public final void setClass(Class clazz) {
0250: this .clazz = clazz;
0251: }
0252:
0253: public final Class getClazz() {
0254: return clazz;
0255: }
0256:
0257: /**
0258: * To see if the field applies to the object, see if the field's type is a
0259: * supertype or same as object
0260: *
0261: * @param object
0262: * @return
0263: */
0264: public boolean isApplicable(Object object) {
0265: if (object == null)
0266: return false;
0267: if (object instanceof DelegatesFields) {// for objects that delegate, they should be able to display anything
0268: if (((DelegatesFields) object).delegates(this ))
0269: return true;
0270: }
0271:
0272: return isApplicable(object.getClass());
0273: }
0274:
0275: public boolean isApplicable(Class type) {
0276: return clazz.isAssignableFrom(type);
0277: }
0278:
0279: /**
0280: * Is field applicable to any type in types array
0281: *
0282: * @param types
0283: * @return
0284: */
0285: public boolean isApplicable(Class[] types) {
0286: for (int i = 0; i < types.length; i++) {
0287: if (isApplicable(types[i]))
0288: return true;
0289: }
0290: return false;
0291: }
0292:
0293: public final void setName(String name) {
0294: this .name = name;
0295: }
0296:
0297: public final void setEnglishName(String englishName) {
0298: this .englishName = englishName;
0299: }
0300:
0301: /**
0302: * @return Returns the select.
0303: */
0304: public Select getSelect() {
0305: return select;
0306: }
0307:
0308: public final void setSelect(Select select) {
0309: this .select = select;
0310: }
0311:
0312: public final String convertIdToString(Object id) {
0313: if (select == null) {
0314: log.error("calling convertIdToString on non select field"
0315: + getName());
0316: return null;
0317: }
0318: return (String) select.getKey(id);
0319: }
0320:
0321: // Strange: digester doesn't set summary property. sum is used instead
0322: public final void setSum(String summaryType) {
0323: setSummary(summaryType);
0324: }
0325:
0326: public final void setSummary(String summaryType) {
0327: this .summary = SummaryVisitorFactory.getSummaryId(summaryType);
0328: if (summary == NONE)
0329: log.warn("unknown summary type: " + summaryType
0330: + " for field " + getName());
0331: }
0332:
0333: public final void setGroupSum(String summaryType) {
0334: this .groupSummary = SummaryVisitorFactory
0335: .getSummaryId(summaryType);
0336: if (groupSummary == NONE)
0337: log.warn("unknown summary type: " + summaryType
0338: + " for field " + getName());
0339: }
0340:
0341: public final void setExternalType(Class externalType) {
0342: this .externalType = externalType;
0343: }
0344:
0345: public final void setTextWidth(int textWidth) {
0346: this .textWidth = textWidth;
0347: }
0348:
0349: public int getTextWidth(Object object, FieldContext context) { // can
0350: // override
0351: // in
0352: // weird
0353: // circumstances
0354: return textWidth;
0355: }
0356:
0357: public int getTextWidth() {
0358: return textWidth;
0359: }
0360:
0361: /**
0362: * @return Returns the .
0363: */
0364: public int getColumnWidth() {
0365: return columnWidth;
0366: }
0367:
0368: /**
0369: * @param columnWidth
0370: * The columnWidth to set.
0371: */
0372: public void setColumnWidth(int columnWidth) {
0373: this .columnWidth = columnWidth;
0374: }
0375:
0376: public int getColumnWidth(boolean svg) {
0377: return (svg) ? getSvgColumnWidth() : getColumnWidth();
0378: }
0379:
0380: public int getSvgColumnWidth() {
0381: return svgColumnWidth;
0382: }
0383:
0384: public void setSvgColumnWidth(int svgColumnWidth) {
0385: this .svgColumnWidth = svgColumnWidth;
0386: }
0387:
0388: public final void setComparator(Comparator comparator) {
0389: this .comparator = comparator;
0390: }
0391:
0392: public Comparator getComparator() {
0393: if (comparator == null)
0394: return ClassUtils.getComparator(getDisplayType());
0395: return comparator;
0396: }
0397:
0398: public int getSummary() {
0399: return summary;
0400: }
0401:
0402: public int getGroupSummary() {
0403: return groupSummary;
0404: }
0405:
0406: // added for groups
0407: public SummaryVisitor getSummaryVisitor(int summary,
0408: boolean forceDeep) {
0409: return SummaryVisitorFactory.getInstance(summary,
0410: getDisplayType(), forceDeep); // TODO
0411: // use
0412: // internalType
0413: // instead?
0414: }
0415:
0416: public SummaryVisitor getSummaryVisitor(boolean forceDeep) {
0417: return getSummaryVisitor(summary, forceDeep);
0418: }
0419:
0420: public boolean hasOptions() {
0421: return (select != null);
0422: }
0423:
0424: public boolean isHasOptions() {
0425: return hasOptions();
0426: }
0427:
0428: public boolean hasFilter() {
0429: return (filter != null);
0430: }
0431:
0432: public boolean isHasFilter() {
0433: return hasFilter();
0434: }
0435:
0436: /**
0437: * For use in populating a list box
0438: *
0439: * @param object
0440: * TODO
0441: * @return
0442: */
0443: public Object[] getOptions(Object object) {
0444: if (select == null)
0445: return null;
0446: Object[] options = select.getKeyArray();
0447: if (filter == null)
0448: return options;
0449: else
0450: return filter.getOptions(options, select.getValueList(),
0451: object);
0452: }
0453:
0454: public boolean hasDynamicSelect() {
0455: return select != null && !select.isStatic();
0456: }
0457:
0458: /**
0459: * @return Returns the type to use for this field in spreadsheets and
0460: * dialogs.
0461: *
0462: */
0463: public Class getDisplayType() {
0464: return displayType;
0465: }
0466:
0467: /**
0468: * Return the name in shortned form: e.g. Long, String, etc.
0469: * @return
0470: */
0471: public String typeName() {
0472: if (isPercent())
0473: return "Percent";
0474: if (isImage())
0475: return "Image";
0476: String t = getDisplayType().toString();
0477: int i = t.lastIndexOf(".");
0478: if (i != -1)
0479: return t.substring(i + 1);
0480: return t;
0481:
0482: }
0483:
0484: public String internalTypeName() {
0485: String t = internalType.toString();
0486: int i = t.lastIndexOf(".");
0487: if (i != -1)
0488: return t.substring(i + 1);
0489: return t;
0490:
0491: }
0492:
0493: private String toText(Object value, Object object) {
0494: if (value == null)
0495: return EMPTY_STRING;
0496: if (defaultValue != null && hideZeroValues
0497: && defaultValue.equals(value))
0498: return EMPTY_STRING;
0499: Format f = getFormat(object);
0500: if (f != null) {
0501: return f.format(value);
0502: } else {
0503: if (isHyperlink())
0504: return ((Hyperlink) value).toString();
0505: return FieldConverter.toString(value, getDisplayType(),
0506: null); // Convert
0507: // to
0508: // string
0509: }
0510: }
0511:
0512: public String toExternalText(Object value, Object obj) {
0513: if (hasOptions())
0514: return convertValueToStringUsingOptions(value);
0515: else
0516: return toText(value, obj);
0517: }
0518:
0519: public final String getText(Object object, FieldContext context) {
0520: if (!isApplicable(object))
0521: return NOT_APPLICABLE;
0522:
0523: if (password) // don't show passwords
0524: return PASSWORD_MASK;
0525:
0526: if (context == null)
0527: context = specialFieldContext;
0528: Object value = null;
0529: try {
0530: value = getValue(object, context);
0531: if (hasOptions()) {
0532: return convertValueToStringUsingOptions(value);
0533: }
0534: } catch (IllegalArgumentException e1) {
0535: e1.printStackTrace();
0536: }
0537: return toText(value, object);
0538: }
0539:
0540: public final String getText(Node node, WalkersNodeModel nodeModel,
0541: FieldContext context) {
0542: Object object = node.getImpl();
0543: if (!isApplicable(object))
0544: return NOT_APPLICABLE;
0545:
0546: if (password) // don't show passwords
0547: return PASSWORD_MASK;
0548: if (context == null)
0549: context = specialFieldContext;
0550: Object value = null;
0551: try {
0552: value = getValue(node, nodeModel, context);
0553: if (hasOptions()) {
0554: return convertValueToStringUsingOptions(value);
0555: }
0556: } catch (IllegalArgumentException e1) {
0557: e1.printStackTrace();
0558: }
0559: return toText(value, object);
0560: }
0561:
0562: public final String getText(ObjectRef objectRef,
0563: FieldContext context) {
0564: if (context == null)
0565: context = specialFieldContext;
0566:
0567: if (objectRef.getCollection() != null) {
0568: return ""
0569: + getCommonValue(objectRef.getCollection(), true,
0570: true);
0571: }
0572: if (objectRef.getNode() != null)
0573: return getText(objectRef.getNode(), objectRef
0574: .getNodeModel(), context);
0575: else
0576: return getText(objectRef.getObject(), context);
0577: }
0578:
0579: public String convertValueToStringUsingOptions(Object value) {
0580: String result = (String) select.getKey(value);
0581: if (result != null)
0582: return result;
0583: else if (value instanceof String)
0584: return value.toString();
0585: if (!dontLimitToChoices)
0586: return NO_CHOICE;
0587: return value.toString();
0588: }
0589:
0590: public int getSummaryForGroup() {
0591: if (groupSummary != NONE)
0592: return groupSummary;
0593: // else
0594: return summary;
0595: }
0596:
0597: /**
0598: * See if this node displays its own data for the field or uses summary
0599: * value
0600: *
0601: * @param node
0602: * @param nodeModel
0603: * @return true if the node dispalys own value
0604: */
0605: private boolean nodeHasNonSummarizedValue(Node node,
0606: WalkersNodeModel nodeModel) {
0607: // special behaviour for groups
0608: int sum = summary;
0609: if (node.getImpl() instanceof GroupNodeImpl) {
0610: sum = getSummaryForGroup();
0611: }
0612: // if (node.getImpl() instanceof Document) // for projects which don't roll up
0613: // return true;
0614:
0615: return (sum == NONE || sum == THIS || !nodeModel
0616: .isSummary(node));
0617: }
0618:
0619: public boolean hasSummary() {
0620: return summary != NONE;
0621: }
0622:
0623: public Object getValue(Node node, WalkersNodeModel nodeModel,
0624: FieldContext context) {
0625: Object result;
0626: Object object = node.getImpl();
0627: if (object instanceof VoidNodeImpl)
0628: return null;
0629: // if ("Field.userRole".equals(id) && object instanceof ResourceImpl){
0630: // ResourceImpl r=(ResourceImpl)object;
0631: // if (!r.isUser()) return null;
0632: // }
0633: if (!(object instanceof GroupNodeImpl)
0634: && isHidden(object, context))
0635: return null;
0636: if (context == null)
0637: context = specialFieldContext;
0638:
0639: if ("Field.duration".equals(id)
0640: && (object instanceof GroupNodeImpl)) {
0641: Document document = nodeModel.getDocument();
0642: if (document == null || !(document instanceof Project))
0643: return null;
0644: WorkingCalendar wc = (WorkingCalendar) ((Project) document)
0645: .getWorkCalendar();
0646:
0647: // startDate, endDate calculated twice. Can find better
0648: Field startField = FieldDictionary.getInstance()
0649: .getFieldFromId("Field.start");
0650: Field endField = FieldDictionary.getInstance()
0651: .getFieldFromId("Field.finish");
0652: Date start = (Date) getSummarizedValueForField(startField,
0653: node, nodeModel, context);
0654: Date end = (Date) getSummarizedValueForField(endField,
0655: node, nodeModel, context);
0656:
0657: double t = wc
0658: .compare(end.getTime(), start.getTime(), false);
0659: result = new Duration(Duration.getInstance(t
0660: / CalendarOption.getInstance().getMillisPerDay(),
0661: TimeUnit.DAYS));
0662: // TODO 8 IS A HACK REPLACE ALL THIS SECTION
0663: } else {
0664: if (nodeHasNonSummarizedValue(node, nodeModel)) {// if no summary
0665: // or leaf
0666: result = getValue(object, context);
0667: if (hasOptions()) {
0668: result = convertValueToStringUsingOptions(result);
0669: }
0670: } else {
0671: result = getSummarizedValueForField(this , node,
0672: nodeModel, context);
0673: }
0674: }
0675: if (isWork() && result != null) { // work must be formatted correctly
0676: ((Work) result).setWork(true);
0677: }
0678: return result;
0679: }
0680:
0681: public Object getValue(ObjectRef objectRef, FieldContext context) {
0682: if (context == null)
0683: context = specialFieldContext;
0684:
0685: if (objectRef.getCollection() != null) {
0686: return getCommonValue(objectRef.getCollection(), true,
0687: false);
0688: }
0689:
0690: if (objectRef.getNode() != null)
0691: return getValue(objectRef.getNode(), objectRef
0692: .getNodeModel(), context);
0693: else
0694: return getValue(objectRef.getObject(), context);
0695: }
0696:
0697: private static Object getSummarizedValueForField(Field field,
0698: Node node, WalkersNodeModel nodeModel, FieldContext context) {
0699: // group's special summaries handled here
0700: if (context == null)
0701: context = field.specialFieldContext;
0702:
0703: Object object = node.getImpl();
0704: NodeWalker walkingVisitor = (NodeWalker) field
0705: .getSummaryVisitor(
0706: (object instanceof GroupNodeImpl) ? field
0707: .getSummaryForGroup() : field
0708: .getSummary(),
0709: object instanceof Document);
0710: walkingVisitor.setNode(node);
0711: walkingVisitor.setNodeModel(nodeModel);
0712: walkingVisitor.setContext(context);
0713: walkingVisitor.setField(field);
0714: Object result = walkingVisitor.getSummary();
0715: if (result instanceof Double) { // convert to proper display type
0716: result = ClassUtils.doubleToObject((Double) result, field
0717: .getDisplayType());
0718: }
0719: if ((object instanceof GroupNodeImpl) && field.hasOptions()) { // TODO
0720: // should
0721: // apply
0722: // to
0723: // summaries
0724: // other
0725: // than
0726: // group
0727: result = field.convertValueToStringUsingOptions(result);
0728: }
0729: return result;
0730: }
0731:
0732: private Object getPropertyValue(Object object, FieldContext context) {
0733: Object result = null;
0734: if (context == null)
0735: context = specialFieldContext;
0736:
0737: if (isFormula()) {
0738: result = this .evaluateFormula(object); // for now not time distrib
0739: } else {
0740: if (methodGet == null)
0741: return null;
0742: try {
0743:
0744: if (getHasNoContext)
0745: result = methodGet.invoke(object,
0746: (isIndexed() ? new Object[] { new Integer(
0747: index) } : new Object[] {}));
0748: else {
0749: result = methodGet.invoke(object,
0750: (isIndexed() ? new Object[] {
0751: new Integer(index), context }
0752: : new Object[] { context }));
0753: }
0754:
0755: } catch (IllegalArgumentException e) {
0756: System.out.println("Bad field " + this );
0757: e.printStackTrace();
0758: } catch (IllegalAccessException e) {
0759: System.out.println("Bad field " + this );
0760: e.printStackTrace();
0761: } catch (InvocationTargetException e) {
0762: System.out.println("Bad field " + this );
0763: e.printStackTrace();
0764: }
0765: }
0766: return result;
0767: }
0768:
0769: public Object getValue(Object object) {
0770: return getValue(object, null);
0771: }
0772:
0773: public Object getValue(Object object, FieldContext context) {
0774: if (!isApplicable(object))
0775: return null;
0776: if (context == null)
0777: context = specialFieldContext;
0778:
0779: Object result = null;
0780: if (object instanceof DelegatesFields) {
0781: DelegatesFields delegator = (DelegatesFields) object;
0782: if (delegator.delegates(this )) {
0783: result = delegator.getDelegatedFieldValue(this );
0784: return result;
0785: }
0786: }
0787: result = getPropertyValue(object, context);
0788: if (isMap()) {
0789: if (result == null) // if no map
0790: return null;
0791: result = ((Map) result).get(getId());
0792: }
0793: if (hasExternalType()) { // need to convert once more
0794: if (FieldContext.isScripting(context)) {
0795: if (isDuration()) // for durations get rid of unit when scripting
0796: result = Long.valueOf(Duration
0797: .millis(((Long) result).longValue()));
0798: } else {
0799: try {// convert to external type
0800: result = FieldConverter.convert(result,
0801: externalType, context); // convert a long to date for example
0802: } catch (FieldParseException e1) {
0803: e1.printStackTrace();
0804: result = null;
0805: }
0806: }
0807: }
0808: if (hideZeroValues && isZero(result))
0809: return null;
0810:
0811: // if (result != null && url != null) {
0812: // result = "<html><a href=\"" + result + "\">" + url + "</a></html>";
0813: // }
0814: return result;
0815: }
0816:
0817: public boolean isZero(Object value) {
0818: if (value instanceof Number)
0819: return (((Number) value).doubleValue() == 0.0);
0820: else if (value instanceof String)
0821: return (((String) value).length() == 0);
0822: return false;
0823: }
0824:
0825: public final void setText(Object object, String textValue,
0826: FieldContext context) throws FieldParseException {
0827: if (context == null)
0828: context = specialFieldContext;
0829: if (isReadOnly(object, context)) { // don't allow setting of read only
0830: // fields
0831: // log.warn("Tried to set text of read only field" + getId());
0832: return;
0833: }
0834: Object value = preprocessText(object, textValue, context);
0835: if (value == textValue) {
0836: Format f = getFormat(object);
0837: if (f != null) {
0838: try {
0839: value = f.parseObject(textValue);
0840: } catch (ParseException e) {
0841: throw new FieldParseException(e);
0842: }
0843: } else {
0844: value = FieldConverter
0845: .convert(textValue,
0846: hasExternalType() ? externalType
0847: : internalType, context); // converts
0848: // to
0849: // Date
0850: }
0851: }
0852: setInternalValueAndUpdate(object, this , value, context);
0853: }
0854:
0855: public final void setText(Node node, WalkersNodeModel nodeModel,
0856: String textValue, FieldContext context)
0857: throws FieldParseException {
0858: if (context == null)
0859: context = specialFieldContext;
0860: if (isReadOnly(node, nodeModel, context)) { // don't allow setting of
0861: // read only fields
0862: // log.warn("Tried to set text of read only field" + getId());
0863: return;
0864: }
0865: Object object = node.getImpl();
0866: Object value = preprocessText(object, textValue, context);
0867: if (value == textValue) {
0868: Format f = getFormat(object);
0869: if (f != null) {
0870: try {
0871: value = f.parseObject(textValue);
0872: } catch (ParseException e) {
0873: throw new FieldParseException(e);
0874: }
0875: } else {
0876: value = FieldConverter
0877: .convert(textValue,
0878: hasExternalType() ? externalType
0879: : internalType, context); // converts
0880: // to
0881: // Date
0882: }
0883: }
0884: setValue(node, nodeModel, this , value, context);
0885: }
0886:
0887: public final void setText(ObjectRef objectRef, String textValue,
0888: FieldContext context) throws FieldParseException {
0889: if (context == null)
0890: context = specialFieldContext;
0891: if (objectRef.getCollection() != null) {
0892: Iterator i = objectRef.getCollection().iterator();
0893: while (i.hasNext()) {
0894: setText(i.next(), textValue, context);
0895: }
0896: } else if (objectRef.getNode() != null)
0897: setText(objectRef.getNode(), objectRef.getNodeModel(),
0898: textValue, context);
0899: else
0900: setText(objectRef.getObject(), textValue, context);
0901: }
0902:
0903: /**
0904: * Called from spreadsheet
0905: *
0906: * @param node
0907: * Node modifield
0908: * @param nodeModel
0909: * nodeModel where node lives
0910: * @param source
0911: * Source of change (for event)
0912: * @param value
0913: * value
0914: * @param context
0915: * @throws FieldParseException
0916: */
0917: public void setValue(Node node, WalkersNodeModel nodeModel,
0918: Object source, Object value, FieldContext context)
0919: throws FieldParseException {
0920: if (context == null)
0921: context = specialFieldContext;
0922: Object object = node.getImpl();
0923: setValue(object, source, value, context);
0924: }
0925:
0926: public void setValue(Object object, Object source, Object value,
0927: FieldContext context) throws FieldParseException {
0928: if (context == null)
0929: context = specialFieldContext;
0930: if (hasOptions()) {
0931: if (value instanceof String)
0932: value = preprocessText(object, (String) value, context);
0933: } else {
0934: if (value instanceof String && hasExternalType()) // do a first
0935: // pass,
0936: // converting
0937: // say, from
0938: // string to
0939: // Duration
0940: value = FieldConverter.convert(value, externalType,
0941: context);
0942: if (value == null)
0943: throw new FieldParseException(errorMessage(value,
0944: object));
0945: }
0946: setInternalValueAndUpdate(object, source, value, context);
0947: }
0948:
0949: private void setInternalValueAndUpdate(Object object,
0950: Object source, Object value, FieldContext context)
0951: throws FieldParseException {
0952: if (context == null)
0953: context = specialFieldContext;
0954: if (setInternalValue(object, value, context)) { // if succeeded in setting value
0955: if (context == null || !context.isNoUpdate())
0956: fireEvent(object, source, context);
0957: }
0958: }
0959:
0960: public void fireEvent(Object object, Object source,
0961: FieldContext context) {
0962: if (context == null)
0963: context = specialFieldContext;
0964: if (object instanceof BelongsToDocument && source != null) { // if no source then no update
0965: if (!FieldContext.isNoUpdate(context)) {
0966: Document document = ((BelongsToDocument) object)
0967: .getDocument();
0968: document.getObjectEventManager().fireUpdateEvent(
0969: source, object, this );
0970: if (isDirtiesWholeDocument())
0971: document.setAllChildrenDirty(true);
0972: }
0973: }
0974: }
0975:
0976: public boolean setValue(Object object, Object source, Object value) {
0977: try {
0978: setValue(object, source, value, null);
0979: return true;
0980: } catch (FieldParseException e) {
0981: return false;
0982: }
0983: }
0984:
0985: public void setValue(ObjectRef objectRef, Object source,
0986: Object value, FieldContext context)
0987: throws FieldParseException {
0988: if (context == null)
0989: context = specialFieldContext;
0990: if (objectRef.getCollection() != null) {
0991: Iterator i = objectRef.getCollection().iterator();
0992: while (i.hasNext()) {
0993: setValue(i.next(), source, value, context);
0994: }
0995: } else if (objectRef.getNode() != null)
0996: setValue(objectRef.getNode(), objectRef.getNodeModel(),
0997: source, value, context);
0998: else
0999: setValue(objectRef.getObject(), source, value, context);
1000: }
1001:
1002: public String syntaxErrorForField() {
1003: return errorMessage(null, null);
1004: }
1005:
1006: private String errorMessage(Object value, Object object) {
1007: String message;
1008: if (errorMessage != null)
1009: message = errorMessage;
1010: else if (isDuration())
1011: message = "Message.invalidDuration";
1012: else if (isDate())
1013: message = "Message.invalidDate";
1014: else if (isRate())
1015: message = "Message.invalidRate";
1016: else if (isMoney())
1017: message = "Message.invalidCost";
1018: else
1019: message = "Message.invalidInput";
1020: return Messages.getString(message);
1021:
1022: }
1023:
1024: public Object getMultipleValueForType() {
1025: if (isDuration())
1026: return Duration.ZERO;
1027: else if (isDate())
1028: return null;
1029: else if (isPercent())
1030: return ClassUtils.PERCENT_MULTIPLE_VALUES;
1031: else
1032: return ClassUtils.getMultipleValueForType(internalType);
1033: }
1034:
1035: public boolean setInternalValue(Object object, Object value,
1036: FieldContext context) throws FieldParseException {
1037: if (context == null)
1038: context = specialFieldContext;
1039: if (!FieldContext.isForceValue(context)
1040: && isReadOnly(object, context)) { // don't allow setting of read only
1041: // fields
1042: // log.warn("Tried to set value of read only field" + getId());
1043: return false;
1044: }
1045:
1046: if (value != null && value.equals(getValue(object, context))) // if
1047: // not
1048: // change,
1049: // do
1050: // nothing
1051: return false; // TODO certain time-distibued fields need to be
1052: // changed
1053:
1054: if (hasExternalType()) { // does the second pass, converting from
1055: // say, Date to long
1056: value = FieldConverter
1057: .convert(value, internalType, context); // convert
1058: // from
1059: // date
1060: // to
1061: // long
1062: // for
1063: // example
1064: if (value == null && !isMap()) // TODO is this how to treat null values?
1065: return false;
1066:
1067: }
1068:
1069: if (range != null) {
1070: range.validate(value, this );
1071: }
1072:
1073: if (methodSet == null)
1074: return false;
1075: if (FieldContext.isParseOnly(context)) // if just parsing, do not set
1076: return false;
1077: try {
1078: if (isMap()) {
1079: Map map = (Map) getPropertyValue(object, context);
1080: map.put(getId(), value);
1081: } else if (setHasNoContext) {
1082: methodSet.invoke(object, (isIndexed() ? new Object[] {
1083: new Integer(index), value }
1084: : new Object[] { value }));
1085: } else {
1086: methodSet.invoke(object, (isIndexed() ? new Object[] {
1087: new Integer(index), value, context }
1088: : new Object[] { value, context }));
1089: }
1090: //LC
1091: if (object instanceof DataObject) {
1092: if (context == null || !context.isNoDirty())
1093: ((DataObject) object).setDirty(true);
1094: }
1095:
1096: } catch (IllegalArgumentException e) {
1097: throw new FieldParseException(e);
1098: } catch (IllegalAccessException e) {
1099: e.printStackTrace();
1100: } catch (InvocationTargetException e) {
1101: Throwable cause = e.getCause();
1102: e.printStackTrace();
1103: if (cause != null && cause instanceof FieldParseException)
1104: throw (FieldParseException) cause;
1105: else {
1106: // setters can throw other values, so don't treat as bad exception
1107: throw new FieldParseException(cause.getMessage());
1108: }
1109: }
1110: return true;
1111: }
1112:
1113: /**
1114: * @return Returns the readOnly. It's a static vlue
1115: */
1116: public boolean isReadOnly() {
1117: return readOnly;
1118: }
1119:
1120: /**
1121: * See if a node is read only. Before calling the object-based version of
1122: * read-only, it checks to see if the node is a summarized parent and if the
1123: * field is a summarized value, thus read only
1124: *
1125: * @param node
1126: * @param nodeModel
1127: * @param context
1128: * @return
1129: */
1130: public boolean isReadOnly(Node node, WalkersNodeModel nodeModel,
1131: FieldContext context) {
1132: if (context == null)
1133: context = specialFieldContext;
1134: if (node.getImpl() instanceof GroupNodeImpl)
1135: return true;
1136: if (summary == THIS && nodeModel.isSummary(node)) // for parents with
1137: // This summary type
1138: return true;
1139: if (!nodeHasNonSummarizedValue(node, nodeModel))
1140: return true;
1141: return isReadOnly(node.getImpl(), context);
1142:
1143: }
1144:
1145: public boolean isReadOnly(ObjectRef objectRef, FieldContext context) {
1146: if (context == null)
1147: context = specialFieldContext;
1148: if (objectRef.getCollection() != null) {
1149: Iterator i = objectRef.getCollection().iterator();
1150: while (i.hasNext()) {
1151: if (isReadOnly(i.next(), context))
1152: return true;
1153: }
1154: return false;
1155: }
1156: if (objectRef.getNode() != null)
1157: return isReadOnly(objectRef.getNode(), objectRef
1158: .getNodeModel(), context);
1159: else
1160: return isReadOnly(objectRef.getObject(), context);
1161: }
1162:
1163: /**
1164: * See if the field is read only
1165: *
1166: * @param object
1167: * @param context
1168: * @return
1169: */
1170: public boolean isReadOnly(Object object, FieldContext context) {
1171: if (context == null)
1172: context = specialFieldContext;
1173:
1174: if (readOnly) {
1175: return true;
1176: }
1177: if (!isApplicable(object)) { // if the object doesn't treat this
1178: // field
1179: return true;
1180: }
1181: if (isFormula())
1182: return true;
1183: // if (isHidden(object,context))
1184: // return true;
1185:
1186: if (object instanceof BelongsToHierarchy) { // for dialogs
1187: // for parents with This summary type
1188: // System.out.println("summary is " + summary + " THIS " + THIS + " NONE
1189: // " + NONE + " parent " + ((BelongsToHierarchy)object).isParent());
1190: if (summary != NONE)
1191: if (((BelongsToHierarchy) object).isParent())
1192: return true;
1193: }
1194:
1195: if (ClassUtils.isObjectReadOnly(object))
1196: return true;
1197: if (ClassUtils.isObjectFieldReadOnly(object, this ))
1198: return true;
1199: if ((object instanceof DelegatesFields)
1200: && ((DelegatesFields) object).delegates(this ))
1201: return true;
1202: Boolean value = (Boolean) invokeContextMethod(methodReadOnly,
1203: object, context, readOnlyHasNoContext);
1204: if (value != null)
1205: return value.booleanValue();
1206:
1207: return false;
1208: }
1209:
1210: public boolean isHidden(Object object, FieldContext context) {
1211: if (context == null)
1212: context = specialFieldContext;
1213: if (methodHide == null)
1214: return false;
1215: Boolean value = (Boolean) invokeContextMethod(methodHide,
1216: object, context, hideHasNoContext);
1217: if (value != null)
1218: return value.booleanValue();
1219: // TODO maybe test if objet itself is hidden
1220: return false;
1221: }
1222:
1223: public Object mapStringToValue(String textValue) {
1224: if (select == null)
1225: return null;
1226: try {
1227: return select.getValue(textValue);
1228: } catch (InvalidChoiceException e) {
1229: return null;
1230: }
1231: }
1232:
1233: public String mapValueToString(Object value) {
1234: if (select == null)
1235: return null;
1236: return (String) select.getKey(value);
1237: }
1238:
1239: protected Object preprocessText(Object object, String textValue,
1240: FieldContext context) throws FieldParseException {
1241: if (context == null)
1242: context = specialFieldContext;
1243: Object value;
1244: if (select != null) {
1245: if (textValue == null)
1246: return null;
1247: if (textValue.trim().length() == 0 && select.isAllowNull()) // special
1248: // case
1249: textValue = Select.EMPTY;
1250:
1251: try {
1252: value = select.getValue(textValue);
1253: } catch (InvalidChoiceException e) {
1254: throw new FieldParseException(Messages
1255: .getString("Message.invalidChoice")
1256: + ": " + textValue);
1257: }
1258: if (value == null
1259: && (!select.isAllowNull() || textValue != Select.EMPTY))
1260: throw new FieldParseException(Messages
1261: .getString("Message.invalidChoice")
1262: + ": " + textValue);
1263: } else if (this .isBoolean()) {
1264: value = Boolean.valueOf(textValue);
1265: } else {
1266: value = textValue;
1267: }
1268: return value;
1269: }
1270:
1271: public boolean isValidChoice(String textValue) {
1272: try {
1273: preprocessText(null, textValue, null);
1274: } catch (FieldParseException e) {
1275: return false;
1276: }
1277: return true;
1278: }
1279:
1280: private final void setAccessorMethods() {
1281: if (clazz != null && property != null) {
1282: StringBuffer javaName = new StringBuffer(property);
1283: javaName.setCharAt(0, Character.toUpperCase(javaName
1284: .charAt(0)));
1285:
1286: // First look for a getter that has a context (indexed or not)
1287: methodGet = MethodUtils.getAccessibleMethod(clazz, "get"
1288: + javaName,
1289: (isIndexed() ? getterIndexedContextParams
1290: : getterContextParams));
1291: if (methodGet == null) // try is instead of get
1292: methodGet = MethodUtils.getAccessibleMethod(clazz, "is"
1293: + javaName,
1294: (isIndexed() ? getterIndexedContextParams
1295: : getterContextParams));
1296:
1297: // If not found, then use standard getter (indexed or not)
1298: if (methodGet == null) {
1299: getHasNoContext = true;
1300: methodGet = MethodUtils.getAccessibleMethod(clazz,
1301: "get" + javaName,
1302: (isIndexed() ? getterIndexedParams
1303: : getterParams));
1304: if (methodGet == null) // try is instead of get
1305: methodGet = MethodUtils.getAccessibleMethod(clazz,
1306: "is" + javaName,
1307: (isIndexed() ? getterIndexedParams
1308: : getterParams));
1309: }
1310: if (methodGet != null)
1311: internalType = methodGet.getReturnType();
1312: else
1313: log.error("Not getter found for field " + getId());
1314:
1315: // First look for a setter that has a context (indexed or not)
1316: methodSet = MethodUtils.getAccessibleMethod(clazz, "set"
1317: + javaName, (isIndexed() ? new Class[] { int.class,
1318: internalType, FieldContext.class } : new Class[] {
1319: internalType, FieldContext.class }));
1320:
1321: // If not found, then use standard setter (indexed or not)
1322: if (methodSet == null) {
1323: setHasNoContext = true;
1324: methodSet = MethodUtils.getAccessibleMethod(clazz,
1325: "set" + javaName, (isIndexed() ? new Class[] {
1326: int.class, internalType }
1327: : new Class[] { internalType }));
1328: }
1329: if (methodSet == null && !readOnly) {
1330: log.warn("No setter found for non-read-only field: "
1331: + getId());
1332: }
1333: methodReset = MethodUtils.getAccessibleMethod(clazz,
1334: "fieldReset" + javaName, getterContextParams);
1335:
1336: if (resetHasNoContext = (methodReset == null))
1337: methodReset = MethodUtils.getAccessibleMethod(clazz,
1338: "fieldReset" + javaName, getterParams);
1339:
1340: methodReadOnly = MethodUtils.getAccessibleMethod(clazz,
1341: "isReadOnly" + javaName, getterContextParams);
1342: if (readOnlyHasNoContext = (methodReadOnly == null))
1343: methodReadOnly = MethodUtils.getAccessibleMethod(clazz,
1344: "isReadOnly" + javaName, getterParams);
1345: //lc
1346: // methodObjectReadOnly = MethodUtils.getAccessibleMethod(clazz, "isReadOnly", getterParams);
1347:
1348: methodHide = MethodUtils.getAccessibleMethod(clazz,
1349: "fieldHide" + javaName,
1350: (isIndexed() ? getterIndexedContextParams
1351: : getterContextParams));
1352: if (hideHasNoContext = (methodHide == null))
1353: methodHide = MethodUtils.getAccessibleMethod(clazz,
1354: "fieldHide" + javaName,
1355: (isIndexed() ? getterIndexedParams
1356: : getterParams));
1357: methodOptions = MethodUtils.getAccessibleMethod(clazz,
1358: "fieldOptions" + javaName, getterContextParams);
1359: if (optionsHasNoContext = (methodOptions == null))
1360: methodOptions = MethodUtils.getAccessibleMethod(clazz,
1361: "fieldOptions" + javaName, getterParams);
1362: }
1363: }
1364:
1365: private final Object invokeContextMethod(Method method,
1366: Object object, FieldContext context, boolean noContext) {
1367: if (context == null)
1368: context = specialFieldContext;
1369: if (method == null)
1370: return null;
1371: try {
1372: if (noContext) {
1373: if (isIndexed())
1374: return method.invoke(object, new Object[] {
1375: new Integer(getIndex()), null });
1376: else
1377: return method.invoke(object, (Object[]) null);
1378: } else {
1379: if (isIndexed())
1380: return method.invoke(object, new Object[] {
1381: new Integer(getIndex()), context });
1382: else
1383: return method.invoke(object,
1384: new Object[] { context });
1385: }
1386: } catch (IllegalArgumentException e) {
1387: e.printStackTrace();
1388: } catch (IllegalAccessException e) {
1389: e.printStackTrace();
1390: } catch (InvocationTargetException e) {
1391: e.printStackTrace();
1392: }
1393: return null;
1394: }
1395:
1396: private boolean hasExternalType() {
1397: return (externalType != null && externalType != internalType);
1398: }
1399:
1400: /**
1401: * @return Returns the id.
1402: */
1403: public String getId() {
1404: return id;
1405: }
1406:
1407: /**
1408: * @param id
1409: * The id to set.
1410: */
1411: public void setId(String id) {
1412: this .id = id;
1413: }
1414:
1415: public String getIdWithoutPrefix() {
1416: int i = id.indexOf('.');
1417: if (i != -1)
1418: return id.substring(i + 1);
1419: else
1420: return id;
1421: }
1422:
1423: private int getDefaultColumnWidth() {
1424: if (isDuration()) {
1425: return 75;
1426: } else if (isDate()) {
1427: return 115;
1428: } else if (isMoney()) {
1429: return 100;
1430: } else if (isRate()) {
1431: return 75;
1432: } else if (getDisplayType() == Boolean.class) {
1433: return 40;
1434: } else {
1435: return 150;
1436: }
1437: }
1438:
1439: private int getSvgDefaultColumnWidth() {
1440: if (isDate())
1441: return 130;
1442: else
1443: return getDefaultColumnWidth();
1444: }
1445:
1446: public boolean build() {
1447: configurationId = id; // id can change if array field, so store off
1448: // initial value
1449: boolean result = true;
1450: if (id == null) {
1451: log.error("Field has no id!");
1452: result = false;
1453: }
1454: if (property == null) {
1455: log.error("Field has no property:" + id);
1456: result = false;
1457: }
1458:
1459: if (name == null) // if not explicitly set, use id as string id
1460: name = Messages.getString(id);
1461: setAccessorMethods();
1462: map = Map.class.isAssignableFrom(internalType); // see if map
1463:
1464: if (isWork()) {
1465: setExternalType(Work.class);
1466: } else if (isDuration()) {
1467: setExternalType(Duration.class);
1468: } else if (isDate()) {
1469: setExternalType(Date.class);
1470: } else if (isMoney() && !isRate()) {
1471: setExternalType(Money.class);
1472: }
1473:
1474: displayType = (externalType == null) ? internalType
1475: : externalType;
1476:
1477: if (displayType != null && displayType.isPrimitive()) {
1478: displayType = ClassUtils
1479: .primitiveToObjectClass(displayType);
1480: externalType = displayType; // is this necessary?
1481: }
1482: if (finder != null) {
1483: finderMethod = ClassUtils.staticMethodFromFullName(finder,
1484: new Class[] { Object.class, Object.class });
1485: if (finderMethod == null)
1486: Field.log.error("invalid finder method " + finder
1487: + " for field" + name);
1488:
1489: }
1490: if (columnWidth == 0)
1491: columnWidth = getDefaultColumnWidth();
1492: if (svgColumnWidth == 0)
1493: svgColumnWidth = getSvgDefaultColumnWidth();
1494:
1495: return result;
1496: }
1497:
1498: public void setType(String type) {
1499: try {
1500: setExternalType(Class.forName(type));
1501: } catch (ClassNotFoundException e) {
1502: // TODO Auto-generated catch block
1503: e.printStackTrace();
1504: }
1505: }
1506:
1507: /**
1508: * @return Returns the name.
1509: */
1510: public String getName() {
1511: if (getAlias() != null)
1512: return getAlias();
1513: return name;
1514: }
1515:
1516: public String getDefaultName() {
1517: return name;
1518: }
1519:
1520: public boolean isBoolean() {
1521: return getDisplayType() == Boolean.class;
1522: }
1523:
1524: /**
1525: * @return Returns the duration.
1526: */
1527: public boolean isDuration() {
1528: return duration;
1529: }
1530:
1531: /**
1532: * @param duration
1533: * The duration to set.
1534: */
1535: public void setDuration(boolean duration) {
1536: this .duration = duration;
1537: }
1538:
1539: /**
1540: * @return Returns the callValidateOnClear.
1541: */
1542: public boolean isCallValidateOnClear() {
1543: return callValidateOnClear;
1544: }
1545:
1546: /**
1547: * @param callValidateOnClear
1548: * The callValidateOnClear to set.
1549: */
1550: public void setCallValidateOnClear(boolean callValidateOnClear) {
1551: this .callValidateOnClear = callValidateOnClear;
1552: }
1553:
1554: /**
1555: * @return Returns the cantReset.
1556: */
1557: public boolean isCantReset() {
1558: return cantReset;
1559: }
1560:
1561: /**
1562: * @param cantReset
1563: * The cantReset to set.
1564: */
1565: public void setCantReset(boolean cantReset) {
1566: this .cantReset = cantReset;
1567: }
1568:
1569: /**
1570: * @return Returns the money.
1571: */
1572: public boolean isMoney() {
1573: return money;
1574: }
1575:
1576: /**
1577: * @param money
1578: * The money to set.
1579: */
1580: public void setMoney(boolean money) {
1581: this .money = money;
1582: }
1583:
1584: /**
1585: * @return Returns the defaultValue.
1586: */
1587: public Object getDefaultValue() {
1588: return defaultValue;
1589: }
1590:
1591: /**
1592: * @param defaultValue
1593: * The defaultValue to set.
1594: */
1595: public void setDefaultValue(Object defaultValue) {
1596: this .defaultValue = defaultValue;
1597: }
1598:
1599: /**
1600: * @return Returns the dontLimitToChoices.
1601: */
1602: public boolean isDontLimitToChoices() {
1603: return dontLimitToChoices;
1604: }
1605:
1606: /**
1607: * @param dontLimitToChoices
1608: * The dontLimitToChoices to set.
1609: */
1610: public void setDontLimitToChoices(boolean dontLimitToChoices) {
1611: this .dontLimitToChoices = dontLimitToChoices;
1612: }
1613:
1614: /**
1615: * @return Returns the formula.
1616: */
1617: public boolean isFormula() {
1618: return formula != null;
1619: }
1620:
1621: /**
1622: * @param formula
1623: * The formula to set.
1624: */
1625: public void setFormula(String formulaName, String variableName,
1626: String formulaText) {
1627: // formula = FormulaFactory.addScripted("Field", formulaName, variableName, formulaText);
1628: throw new RuntimeException("setFormula"); //TODO if used, need to handle addNormal too
1629: }
1630:
1631: public void clearFormula() {
1632: formula = null;
1633: }
1634:
1635: public Object evaluateFormula(Object object) {
1636: try {
1637: return formula.evaluate(object);
1638: } catch (InvalidFormulaException e) {
1639: log.error("Formula is invalid " + formula.getText());
1640: return null;
1641: }
1642: }
1643:
1644: /**
1645: * @return Returns the hideZeroValues.
1646: */
1647: public boolean isHideZeroValues() {
1648: return hideZeroValues;
1649: }
1650:
1651: /**
1652: * @param hideZeroValues
1653: * The hideZeroValues to set.
1654: */
1655: public void setHideZeroValues(boolean hideZeroValues) {
1656: this .hideZeroValues = hideZeroValues;
1657: }
1658:
1659: /**
1660: * @return Returns the password.
1661: */
1662: public boolean isPassword() {
1663: return password;
1664: }
1665:
1666: /**
1667: * @param password
1668: * The password to set.
1669: */
1670: public void setPassword(boolean password) {
1671: this .password = password;
1672: }
1673:
1674: /**
1675: * @return Returns the percent.
1676: */
1677: public boolean isPercent() {
1678: return percent;
1679: }
1680:
1681: /**
1682: * @param percent
1683: * The percent to set.
1684: */
1685: public void setPercent(boolean percent) {
1686: this .percent = percent;
1687: }
1688:
1689: /**
1690: * @param readOnly
1691: * The readOnly to set.
1692: */
1693: public void setReadOnly(boolean readOnly) {
1694: this .readOnly = readOnly;
1695: }
1696:
1697: /**
1698: * @return Returns the scalar.
1699: */
1700: public boolean isScalar() {
1701: return scalar;
1702: }
1703:
1704: /**
1705: * @param scalar
1706: * The scalar to set.
1707: */
1708: public void setScalar(boolean scalar) {
1709: this .scalar = scalar;
1710: }
1711:
1712: /**
1713: * @return Returns the vector.
1714: */
1715: public boolean isVector() {
1716: return vector;
1717: }
1718:
1719: /**
1720: * @param vector
1721: * The vector to set.
1722: */
1723: public void setVector(boolean vector) {
1724: this .vector = vector;
1725: }
1726:
1727: /**
1728: * @return Returns the indexes.
1729: */
1730: public int getIndexes() {
1731: return indexes;
1732: }
1733:
1734: /**
1735: * @param indexes
1736: * The indexes to set.
1737: */
1738: public void setIndexes(int indexes) {
1739: this .indexes = indexes;
1740: }
1741:
1742: /**
1743: * Set the array size of the custom field this applies to
1744: *
1745: * @param boundsField
1746: */
1747: public void setBoundsField(String boundsField) {
1748: if (indexes > 0) //Pb with IBM JDK, some boundsField with indexes=0 are reseting some settings
1749: ClassUtils.setStaticField(boundsField, indexes);
1750: }
1751:
1752: /**
1753: * @return Returns the index.
1754: */
1755: public int getIndex() {
1756: return index;
1757: }
1758:
1759: /**
1760: * @param index
1761: * The index to set.
1762: */
1763: public void setIndex(int index) {
1764: this .index = index;
1765: }
1766:
1767: public boolean isIndexed() {
1768: return indexes != 0;
1769: }
1770:
1771: public Object clone() {
1772: // TODO Auto-generated method stub
1773: try {
1774: return super .clone();
1775: } catch (CloneNotSupportedException e) {
1776: // TODO Auto-generated catch block
1777: e.printStackTrace();
1778: return null;
1779: }
1780: }
1781:
1782: public Field createIndexedField(int index) {
1783: Field indexedField = (Field) clone();
1784: indexedField.setIndex(index);
1785: String indexSuffix = "";
1786: if (indexedField.isZeroBasedIndex()) {
1787: if (index > 0)
1788: indexSuffix += index;
1789: } else {
1790: indexSuffix += index + 1;
1791: }
1792: indexedField.setId(getId().replaceFirst("#", indexSuffix));
1793: indexedField.setName(getName().replaceFirst("#", indexSuffix));
1794: return indexedField;
1795: }
1796:
1797: /**
1798: * Make a new field with an integrated context that uses the given interval
1799: * @param f
1800: * @param interval
1801: * @return
1802: */
1803: public static Field createIntervalField(Field f, Interval interval) {
1804: FieldContext fieldContext = new FieldContext();
1805: fieldContext.setInterval(interval);
1806: Field field = (Field) f.clone();
1807: field.specialFieldContext = new FieldContext();
1808: return field;
1809: }
1810:
1811: static SimpleDateFormat f = new SimpleDateFormat("E");
1812:
1813: public String getLabel() {
1814: if (specialFieldContext == null)
1815: return getName();
1816: long start = specialFieldContext.getInterval().getStart();
1817: return f.format(new Date(start));
1818: }
1819:
1820: /**
1821: * @return Returns the date.
1822: */
1823: public boolean isDate() {
1824: return date;
1825: }
1826:
1827: /**
1828: * @param date
1829: * The date to set.
1830: */
1831: public void setDate(boolean date) {
1832: this .date = date;
1833: }
1834:
1835: /**
1836: * Compares two fields. Normally a simple String compareTo is used, but in
1837: * the case of array fields, I compare their indexes - we want such fields
1838: * to sort numerically and not alphabetically so that for example, Cost11
1839: * appears after Cost2 and not before.
1840: */
1841: public int compareTo(Object to) {
1842: if (to == null)
1843: throw new NullPointerException();
1844: if (!(to instanceof Field))
1845: throw new ClassCastException();
1846: Field toField = (Field) to;
1847: if (configurationId == toField.configurationId) { // if array field,
1848: // then compare
1849: // indexes
1850: return index - toField.index;
1851: } else {
1852: return getName().compareTo(toField.getName());
1853: }
1854: }
1855:
1856: /**
1857: * Sets each object in a collection to value. Exceptions are ignored
1858: *
1859: * @param collection
1860: * @param value
1861: */
1862: public void setValueForEach(Collection collection, Object value,
1863: FieldContext context, Object eventSource) {
1864: if (context == null)
1865: context = specialFieldContext;
1866: if (collection == null)
1867: return;
1868: Iterator i = collection.iterator();
1869: Object current;
1870: while (i.hasNext()) {
1871: current = i.next();
1872: try {
1873: setValue(current, eventSource, value, context);
1874: } catch (FieldParseException e) {
1875: // TODO Auto-generated catch block
1876: e.printStackTrace();
1877: }
1878: }
1879:
1880: }
1881:
1882: /**
1883: * Given a collection, if each elements shares the same value for this
1884: * field, the value is returned, Otherwise null is returned.
1885: *
1886: * @param collection
1887: * @param useMultipleValue
1888: * If true, the default value will be used if no elements or
1889: * values differ
1890: * @return
1891: */
1892: public Object getCommonValue(Collection collection,
1893: boolean useMultipleValue, boolean text) {
1894: if (collection == null)
1895: return null;
1896: Iterator i = collection.iterator();
1897: Object value = null;
1898: Object current;
1899: Object currentValue;
1900: Comparator comparatorToUse = (text ? ComparableComparator
1901: .getInstance() : getComparator());
1902: while (i.hasNext()) {
1903: current = i.next();
1904: if (text)
1905: currentValue = getText(current, null);
1906: else
1907: currentValue = getValue(current, null);
1908: if (value == null)
1909: value = currentValue;
1910: else if (0 != comparatorToUse.compare(currentValue, value)) {
1911: value = null;
1912: break;
1913: }
1914: }
1915: if (value == null && useMultipleValue) {
1916: value = getMultipleValueForType();
1917: }
1918: return value;
1919: }
1920:
1921: /**
1922: * Given a collection, return the text for a field if each elements shares
1923: * the same value, otherwise return "--"
1924: *
1925: * @param collection
1926: * @return
1927: */
1928: public String getCommonValueString(Collection collection) {
1929: if (collection == null || collection.size() == 0)
1930: return null;
1931: Object common = getCommonValue(collection, false, true);
1932: if (common == null)
1933: return MULTIPLE_VALUES;
1934: else
1935: return common.toString();
1936: }
1937:
1938: public Object findFirstInCollection(Object value,
1939: Collection collection) {
1940: Iterator i = collection.iterator();
1941: Object current;
1942: while (i.hasNext()) {
1943: current = i.next();
1944: if (0 == getComparator().compare(getValue(current, null),
1945: value))
1946: return current;
1947: }
1948: return null;
1949: }
1950:
1951: public Object[] findAllInCollection(Object value,
1952: Collection collection) {
1953: ArrayList result = new ArrayList();
1954: Iterator i = collection.iterator();
1955: Object current;
1956: while (i.hasNext()) {
1957: current = i.next();
1958: if (0 == getComparator().compare(getValue(current, null),
1959: value))
1960: result.add(current);
1961: }
1962: return result.toArray();
1963: }
1964:
1965: /**
1966: * @return Returns the work.
1967: */
1968: public boolean isWork() {
1969: return work;
1970: }
1971:
1972: public boolean isDurationOrWork() {
1973: return isWork() || isDuration();
1974: }
1975:
1976: /**
1977: * @param work
1978: * The work to set.
1979: */
1980: public void setWork(boolean work) {
1981: setDuration(work); // work is always a duration too
1982: this .work = work;
1983: }
1984:
1985: public void setFinder(String finder) {
1986: this .finder = finder;
1987: }
1988:
1989: /*
1990: * (non-Javadoc)
1991: *
1992: * @see com.projity.field.Finder#find(java.lang.Object)
1993: */
1994: public Object find(Object key, Collection container) {
1995: if (finderMethod == null)
1996: return findFirstInCollection(key, container);
1997:
1998: try {
1999: return finderMethod.invoke(null, new Object[] { key,
2000: container });
2001: } catch (Exception e) {
2002: return null;
2003: }
2004: }
2005:
2006: /**
2007: * Compare two objects using this field. In this way i
2008: */
2009: public int compare(Object arg0, Object arg1) {
2010: return getComparator().compare(getValue(arg0, null),
2011: getValue(arg1, null));
2012: }
2013:
2014: /**
2015: * @return Returns the value.
2016: */
2017: public boolean isRate() {
2018: return rate;
2019: }
2020:
2021: /**
2022: * @param value
2023: * The value to set.
2024: */
2025: public void setRate(boolean rate) {
2026: this .rate = rate;
2027: }
2028:
2029: /**
2030: * @return Returns the zeroBasedIndex.
2031: */
2032: public boolean isZeroBasedIndex() {
2033: return zeroBasedIndex;
2034: }
2035:
2036: /**
2037: * @param zeroBasedIndex
2038: * The zeroBasedIndex to set.
2039: */
2040: public void setZeroBasedIndex(boolean zeroBasedIndex) {
2041: this .zeroBasedIndex = zeroBasedIndex;
2042: }
2043:
2044: public double getScaleFactor() {
2045: if (isWork() || isDuration())
2046: return CalendarOption.getInstance().getMillisPerDay();
2047: else
2048: return 1.0;
2049: }
2050:
2051: public Format getFormat() {
2052: return getFormat(null);
2053: }
2054:
2055: public Format getFormat(Object object) {
2056: if (isWork()) {
2057: return DurationFormat.getWorkInstance();
2058: } else if (isRate()) {
2059: return RateFormat.getInstance(object, isMoney(),
2060: isPercent(), true);
2061: } else if (isMoney()) {
2062: return Money.getMoneyFormatInstance();
2063: } else if (isDuration()) {
2064: return DurationFormat.getInstance();
2065: } else if (isPercent()) {
2066: return PercentFormat.getInstance();
2067: } else if (isDate()) {
2068: return EditOption.getInstance().getDateFormat();
2069: } else if (displayType == Double.class
2070: || displayType == Float.class
2071: || displayType == Integer.class) {
2072: return NumberFormat.getInstance();
2073: }
2074: return null;
2075: }
2076:
2077: public boolean isNumber() {
2078: return displayType == Double.class
2079: || displayType == Float.class
2080: || displayType == Integer.class
2081: || displayType == Long.class;
2082:
2083: }
2084:
2085: public int getHorizontalAlignment() {
2086: if (isImage() || isBoolean())
2087: return JTextField.CENTER;
2088: else if (isWork() || isRate() || isMoney() || isDuration()
2089: || isDate() || isPercent() || isNumber())
2090: return JTextField.RIGHT;
2091: else
2092: return JTextField.LEFT;
2093:
2094: }
2095:
2096: public static Object value(Field field, Node node,
2097: NodeModel nodeModel) {
2098: return field.getValue(node, nodeModel, null);
2099: }
2100:
2101: public static Object value(Field field, Object object) {
2102: return field.getValue(object, null);
2103: }
2104:
2105: /**
2106: * @return Returns the property.
2107: */
2108: public String getProperty() {
2109: return property;
2110: }
2111:
2112: /**
2113: * @return Returns the referencedObjectProperty.
2114: */
2115: public String getReferencedObjectProperty() {
2116: return referencedObjectProperty;
2117: }
2118:
2119: /**
2120: * @param referencedObjectProperty
2121: * The referencedObjectProperty to set.
2122: */
2123: public void setReferencedObjectProperty(
2124: String referencedObjectProperty) {
2125: this .referencedObjectProperty = referencedObjectProperty;
2126: }
2127:
2128: /**
2129: * @return Returns the referencedIdProperty.
2130: */
2131: public String getReferencedIdProperty() {
2132: return referencedIdProperty;
2133: }
2134:
2135: /**
2136: * @param referencedIdProperty
2137: * The referencedIdProperty to set.
2138: */
2139: public void setReferencedIdProperty(String referencedIdProperty) {
2140: this .referencedIdProperty = referencedIdProperty;
2141: }
2142:
2143: public Object getValueFromProperty(Object obj) {
2144: if (property == null)
2145: return null;
2146: try {
2147: return PropertyUtils.getProperty(obj, property);
2148: } catch (IllegalAccessException e) {
2149: } catch (InvocationTargetException e) {
2150: } catch (NoSuchMethodException e) {
2151: }
2152: return null;
2153:
2154: }
2155:
2156: public Object getReferencedObject(Object obj) {
2157: if (referencedObjectProperty == null)
2158: return null;
2159: try {
2160: return PropertyUtils.getProperty(obj,
2161: referencedObjectProperty);
2162: } catch (IllegalAccessException e) {
2163: } catch (InvocationTargetException e) {
2164: } catch (NoSuchMethodException e) {
2165: }
2166: return null;
2167: }
2168:
2169: public Long getReferencedId(Object obj) {
2170: Long result = null;
2171: if (referencedIdProperty != null) {
2172: try {
2173: result = (Long) PropertyUtils.getProperty(obj,
2174: referencedIdProperty);
2175: // System.out.println("____ref id = " + result);
2176: } catch (IllegalAccessException e) {
2177: } catch (InvocationTargetException e) {
2178: } catch (NoSuchMethodException e) {
2179: }
2180: }
2181: return result;
2182: }
2183:
2184: public boolean isLink() {
2185: return referencedObjectProperty != null
2186: || referencedIdProperty != null;
2187: }
2188:
2189: /**
2190: * @return Returns the memo.
2191: */
2192: public boolean isMemo() {
2193: return memo;
2194: }
2195:
2196: /**
2197: * @param memo
2198: * The memo to set.
2199: */
2200: public void setMemo(boolean memo) {
2201: this .memo = memo;
2202: }
2203:
2204: /**
2205: * @return Returns the nameField.
2206: */
2207: public boolean isNameField() {
2208: return nameField;
2209: }
2210:
2211: /**
2212: * @param nameField
2213: * The nameField to set.
2214: */
2215: public void setNameField(boolean nameField) {
2216: this .nameField = nameField;
2217: }
2218:
2219: public final String getErrorMessage() {
2220: return errorMessage;
2221: }
2222:
2223: public final void setErrorMessage(String errorMessage) {
2224: this .errorMessage = errorMessage;
2225: }
2226:
2227: public boolean isStandardType() {
2228: boolean nonStandard = isDuration() || isRate() || hasOptions()
2229: || isMoney();
2230: return !nonStandard;
2231: }
2232:
2233: final public boolean isDynamicOptions() {
2234: return dynamicOptions;
2235: }
2236:
2237: final public void setDynamicOptions(boolean dynamicOptions) {
2238: this .dynamicOptions = dynamicOptions;
2239: }
2240:
2241: /**
2242: * Copies field data from one object to another. Does not copy read only
2243: * fields
2244: *
2245: * @param to
2246: * @param from
2247: */
2248: public void copyData(Object to, Object from) {
2249: if (isReadOnly(to, null))
2250: return;
2251: Object value = getValue(from, null);
2252: setValue(to, null, value);
2253: }
2254:
2255: /**
2256: * Copies multiple fields from one object to another
2257: *
2258: * @param fieldArray
2259: * @param to
2260: * @param from
2261: */
2262: public static void copyData(Collection fieldArray, Object to,
2263: Object from) {
2264: Iterator i = fieldArray.iterator();
2265: while (i.hasNext()) {
2266: ((Field) i.next()).copyData(to, from);
2267: }
2268:
2269: }
2270:
2271: /**
2272: * Copies data from a map which contains Field Ids (e.g. Field.work) as keys
2273: * and values (either string or object) to the destination to. Read Only
2274: * fields are ignored.
2275: *
2276: * @param to
2277: * @param fromMap
2278: * @throws FieldParseException
2279: */
2280: public static void copyData(Object to, Map fromMap)
2281: throws FieldParseException {
2282: Iterator i = fromMap.keySet().iterator();
2283: FieldContext context;
2284: while (i.hasNext()) {
2285: String fieldId = (String) i.next();
2286: Field field = Configuration.getFieldFromId(fieldId);
2287: context = field.specialFieldContext;
2288: if (!field.isReadOnly(to, context)) {
2289: Object data = fromMap.get(fieldId);
2290: if (data instanceof String)
2291: field.setText(to, (String) fromMap.get(fieldId),
2292: context);
2293: else
2294: field.setValue(to, data, context);
2295: }
2296: }
2297: }
2298:
2299: /**
2300: * Copies a set of fields, defined by the fieldArray to a map with their
2301: * values
2302: *
2303: * @param toMap
2304: * @param from
2305: * @param fieldArray
2306: */
2307: public static void copyData(Map toMap, Object from,
2308: Collection fieldArray) {
2309: FieldContext context = null;
2310: Iterator i = fieldArray.iterator();
2311: while (i.hasNext()) {
2312: Field field = (Field) i.next();
2313: context = field.specialFieldContext;
2314: String value = field.getText(from, context);
2315: toMap.put(field.getId(), value);
2316: }
2317:
2318: }
2319:
2320: public final boolean isHasToolTip() {
2321: return hasToolTip;
2322: }
2323:
2324: public final void setHasToolTip(boolean hasToolTip) {
2325: this .hasToolTip = hasToolTip;
2326: }
2327:
2328: public final boolean isMap() {
2329: return map;
2330: }
2331:
2332: public final String getExtraCategory() {
2333: return extraCategory;
2334: }
2335:
2336: public final void setExtraCategory(String extraCategory) {
2337: this .extraCategory = extraCategory;
2338: }
2339:
2340: public boolean isExtra() {
2341: return extraCategory != null;
2342: }
2343:
2344: public Object convertValueForExport(Object value) {
2345: if (value instanceof Duration)
2346: value = Double.valueOf(((Duration) value).getAsDays());
2347: return value;
2348: }
2349:
2350: public final String getUrl() {
2351: return url;
2352: }
2353:
2354: public final void setUrl(String url) {
2355: this .url = url;
2356: }
2357:
2358: public final boolean isHyperlink() {
2359: return getUrl() != null;
2360: }
2361:
2362: public final boolean isValidOnObjectCreate() {
2363: return validOnObjectCreate;
2364: }
2365:
2366: public final void setValidOnObjectCreate(boolean validOnObjectCreate) {
2367: this .validOnObjectCreate = validOnObjectCreate;
2368: }
2369:
2370: public final boolean isDirtiesWholeDocument() {
2371: return dirtiesWholeDocument;
2372: }
2373:
2374: public final void setDirtiesWholeDocument(
2375: boolean dirtiesWholeDocument) {
2376: this .dirtiesWholeDocument = dirtiesWholeDocument;
2377: }
2378:
2379: public final String getAction() {
2380: return action;
2381: }
2382:
2383: public final void setAction(String action) {
2384: this .action = action;
2385: }
2386:
2387: public void invokeAction(Object obj) {
2388: if (action == null || obj == null)
2389: return;
2390: Object value = getValue(obj, null);
2391: if (value instanceof Hyperlink)
2392: ((Hyperlink) value).invoke();
2393: }
2394:
2395: public final boolean isImage() {
2396: return image;
2397: }
2398:
2399: public final void setImage(boolean image) {
2400: this .image = image;
2401: }
2402:
2403: public String dump() {
2404: return ToStringBuilder.reflectionToString(this );
2405: }
2406:
2407: public FieldContext getSpecialFieldContext() {
2408: return specialFieldContext;
2409: }
2410:
2411: public void setSpecialFieldContext(FieldContext specialFieldContext) {
2412: this .specialFieldContext = specialFieldContext;
2413: }
2414:
2415: public Comparator getComparator(boolean ascending) {
2416: if (ascending == true)
2417: return this ;
2418: else {
2419: return new Comparator() {
2420: public int compare(Object o1, Object o2) {
2421: return Field.this .compare(o2, o1);
2422: }
2423: };
2424: }
2425: }
2426:
2427: public boolean isComparable() {
2428: return !isImage();
2429: }
2430:
2431: public OptionsFilter getFilter() {
2432: return filter;
2433: }
2434:
2435: public void setFilter(OptionsFilter filter) {
2436: this .filter = filter;
2437: }
2438:
2439: public FieldAccessible getAccessControl() {
2440: return accessControl;
2441: }
2442:
2443: public void setAccessControl(FieldAccessible accessControl) {
2444: this .accessControl = accessControl;
2445: }
2446:
2447: public boolean isAuthorized(int role) {
2448: return accessControl == null
2449: || accessControl.isAuthorized(role);
2450: }
2451:
2452: public boolean isGraphical() {
2453: return graphical;
2454: }
2455:
2456: public void setGraphical(boolean graphical) {
2457: this .graphical = graphical;
2458: }
2459:
2460: public String getLookupTypes() {
2461: return lookupTypes;
2462: }
2463:
2464: public void setLookupTypes(String lookupTypes) {
2465: this .lookupTypes = lookupTypes;
2466: }
2467:
2468: public boolean isServer() {
2469: return server;
2470: }
2471:
2472: public void setServer(boolean server) {
2473: this .server = server;
2474: }
2475:
2476: public static String getMetadataStringHeader() {
2477: return "Name" + "\t" + "Id (for API)" + "\t" + "API type"
2478: + "\t" + "POD type" + "\t" + "Read Only" + "\t"
2479: + "Notes";
2480:
2481: }
2482:
2483: public String getMetadataString() {
2484: String result = getName() + "\t" + getIdWithoutPrefix() + "\t"
2485: + internalTypeName() + "\t" + typeName() + "\t"
2486: + isReadOnly() + "\t";
2487: if (hasDynamicSelect()) {
2488: result += "Choices are dynamic";
2489: } else if (select != null) {
2490: result += select.documentOptions();
2491: }
2492: return result;
2493: }
2494:
2495: public boolean isStartValue() {
2496: return startValue;
2497: }
2498:
2499: public void setStartValue(boolean startValue) {
2500: this .startValue = startValue;
2501: }
2502:
2503: public boolean isEndValue() {
2504: return endValue;
2505: }
2506:
2507: public void setEndValue(boolean endValue) {
2508: this .endValue = endValue;
2509: }
2510:
2511: public boolean isDateOnly() {
2512: return dateOnly;
2513: }
2514:
2515: public void setDateOnly(boolean dateOnly) {
2516: this .dateOnly = dateOnly;
2517: }
2518:
2519: public String getHelp() {
2520: return help;
2521: }
2522:
2523: public void setHelp(String help) {
2524: this .help = help;
2525: }
2526:
2527: public String getAlias() {
2528: return alias;
2529: }
2530:
2531: public void setAlias(String alias) {
2532: this .alias = alias;
2533: }
2534:
2535: public boolean isCustom() {
2536: return custom;
2537: }
2538:
2539: public void setCustom(boolean custom) {
2540: this .custom = custom;
2541: }
2542:
2543: public String getSummaryType() {
2544: if (isStartValue())
2545: return "min";
2546: if (isEndValue())
2547: return "max";
2548: int summary = getGroupSummary();
2549: if (summary == SummaryNames.NONE)
2550: summary = getSummary();
2551: //System.out.println("Field "+ this + " group " + getGroupSummary() + " sum " + getSummary());
2552: switch (summary) {
2553: case SummaryNames.SUM:
2554: return "sum";
2555: case SummaryNames.COUNT_ALL:
2556: case SummaryNames.COUNT_FIRST_SUBLEVEL:
2557: case SummaryNames.COUNT_NONSUMMARIES:
2558: return "count";
2559: case SummaryNames.AVERAGE:
2560: case SummaryNames.AVERAGE_FIRST_SUBLEVEL:
2561: return "average";
2562:
2563: }
2564: return null;
2565: }
2566:
2567: }
|