package info.limpet.ui.data_provider.data; import java.awt.geom.Point2D; import info.limpet.IBaseQuantityCollection; import info.limpet.QuantityRange; import info.limpet.UIProperty; import info.limpet.data.operations.spatial.GeoSupport; import info.limpet.ui.Activator; import info.limpet.ui.propertyeditors.SliderPropertyDescriptor; import javax.measure.Measure; import javax.measure.quantity.Quantity; import javax.measure.unit.Unit; import org.eclipse.core.runtime.Status; import org.eclipse.ui.views.properties.PropertyDescriptor; import org.eclipse.ui.views.properties.TextPropertyDescriptor; /** * A helper class that encapsulates some logic about certain property types. Each subclass handles * specific type and must implement {@link #getDefaulValue(UIProperty)} and * {@link #doCreatePropertyDescriptor(String, UIProperty)} methods. */ public abstract class PropertyTypeHandler { /** * can this handler handle a property of the specified type? * * @param propertyType * the type of the property * @return yes/no */ public abstract boolean canHandle(Class<?> propertyType); /** * Some {@link CellEditor}s represent the model property with different type in the UI, for * example String for double values. * * @param cellEditorValue * the cell editor value * @param propertyOwner * the object that owns the property * @return the model value */ public Object toModelValue(Object cellEditorValue, Object propertyOwner) { return cellEditorValue; } /** * Some {@link CellEditor}s represent the model property with different type in the UI, for * example String for double values. * * @param modelValue * the model value * @param propertyOwner * the object that owns the property * @return the cell editor value */ public Object toCellEditorValue(Object modelValue, Object properyOwner) { return modelValue; } /** * @param propertyId * @param metadata * @return the Property descriptor */ protected abstract PropertyDescriptor doCreatePropertyDescriptor( String propertyId, UIProperty metadata); /** * @param metadata * @return default value */ abstract Object getDefaulValue(UIProperty metadata); /** * create the property descriptor for the specified property * * @param propertyId * @param metadata * @return */ final PropertyDescriptor createPropertyDescriptor(String propertyId, UIProperty metadata) { final PropertyDescriptor propertyDescriptor = doCreatePropertyDescriptor(propertyId, metadata); propertyDescriptor.setCategory(metadata.category()); return propertyDescriptor; } /** * A handler for String type properties */ public static final PropertyTypeHandler STRING = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return metadata.defaultString(); } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { return new TextPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return propertyType.equals(String.class); } }; /** * A handler for boolean type properties */ public static final PropertyTypeHandler BOOLEAN = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return metadata.defaultBoolean(); } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { return new CheckboxPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return "boolean".equals(propertyType.getName()); } }; /** * A handler for int type properties */ public static final PropertyTypeHandler INTEGER = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return metadata.defaultInt(); } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { return new SliderPropertyDescriptor(propertyId, metadata.name(), metadata .min(), metadata.max()); } @Override public boolean canHandle(Class<?> propertyType) { return "int".equals(propertyType.getName()); } }; /** * A handler for double primitive type and Number type properties. */ public static final PropertyTypeHandler DOUBLE = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return metadata.defaultDouble(); } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { return new TextPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return Number.class == propertyType || "double".equals(propertyType.getName()); } public Object toModelValue(Object cellEditorValue, Object propertyOwner) { return Double.parseDouble((String) cellEditorValue); }; public Object toCellEditorValue(Object modelValue, Object propertyOwner) { return modelValue + ""; }; }; /** * A handler for {@link Unit} typed properties */ public static final PropertyTypeHandler UNIT = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return Unit.ONE; } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { // TODO: ideally this would be a drop down list, where user can select // values. // In that case toModel and toUI would need to deal with indices return new TextPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return propertyType == Unit.class; } public Object toModelValue(Object cellEditorValue, Object propertyOwner) { // TODO: here we should have some form of conversion from string to Unit // (perhaps reuse the logic already in CsvParser class) return cellEditorValue; }; public Object toCellEditorValue(Object modelValue, Object propertyOwner) { return modelValue + ""; }; }; /** * A handler for {@link QuantityRange} typed properties. This property type handler only makes * sense when propertyOwner is an {@link IBaseQuantityCollection} instance */ public static final PropertyTypeHandler QUANTITY_RANGE = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return null; } protected PropertyDescriptor doCreatePropertyDescriptor( String propertyId, UIProperty metadata) { return new TextPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return propertyType == QuantityRange.class; } @SuppressWarnings( {"unchecked", "rawtypes"}) public Object toModelValue(Object cellEditorValue, Object propertyOwner) { QuantityRange newR = null; IBaseQuantityCollection<?> tt = (IBaseQuantityCollection<?>) propertyOwner; // try to get a range from the string String str = (String) cellEditorValue; if (str.length() > 0) { // ok, split it up String[] bits = str.split(":"); if (bits.length == 2) { String min = bits[0].trim(); String max = bits[1].trim(); try { double minV = Double.parseDouble(min); double maxV = Double.parseDouble(max); if (maxV > minV) { Unit<?> collUnits = tt.getUnits(); newR = new QuantityRange(Measure.valueOf(minV, collUnits), Measure.valueOf(maxV, collUnits)); } } catch (NumberFormatException fe) { Activator.logError(Status.ERROR, "Failed to extract number range", fe); } } else { Activator.logError(Status.ERROR, "Number format string not properly constructed:" + str + " (should be 1:10)", null); } } return newR; }; @SuppressWarnings("unchecked") public Object toCellEditorValue(Object modelValue, Object propertyOwner) { final String str; QuantityRange<Quantity> range = (QuantityRange<Quantity>) modelValue; IBaseQuantityCollection<Quantity> qc = (IBaseQuantityCollection<Quantity>) propertyOwner; if (range != null) { str = "" + range.getMinimum().longValue(qc.getUnits()) + " : " + range.getMaximum().longValue(qc.getUnits()); } else { str = " : "; } return str; }; }; /** * A handler for {@link Geometry} typed properties */ static final PropertyTypeHandler GEOMETRY = new PropertyTypeHandler() { @Override public Object getDefaulValue(UIProperty metadata) { return null; } protected PropertyDescriptor doCreatePropertyDescriptor(String propertyId, UIProperty metadata) { return new TextPropertyDescriptor(propertyId, metadata.name()); } @Override public boolean canHandle(Class<?> propertyType) { return propertyType == Point2D.class; } public Object toModelValue(Object cellEditorValue, Object propertyOwner) { Point2D newL = null; // try to get a location from the string String str = (String) cellEditorValue; if (str.length() > 0) { // ok, split it up String[] bits = str.split(":"); if (bits.length == 2) { String lat = bits[0].trim(); String lng = bits[1].trim(); try { double latV = Double.parseDouble(lat); double lngV = Double.parseDouble(lng); newL = GeoSupport.getCalculator().createPoint(lngV, latV); } catch (NumberFormatException fe) { Activator.logError(Status.ERROR, "Failed to extract number location", fe); } } else { Activator.logError(Status.ERROR, "Number format string not properly constructed:" + str + " (should be 1:10)", null); } } return newL; }; public Object toCellEditorValue(Object modelValue, Object propertyOwner) { Point2D location = (Point2D) modelValue; return location.getY() + " : " + location.getX(); }; }; }