/* * This is part of Geomajas, a GIS framework, http://www.geomajas.org/. * * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium. * * The program is available in open source according to the GNU Affero * General Public License. All contributions in this program are covered * by the Geomajas Contributors License Agreement. For full licensing * details, see LICENSE.txt in the project root. */ package org.geomajas.gwt.client.map.feature; import org.geomajas.annotation.Api; import org.geomajas.configuration.AbstractAttributeInfo; import org.geomajas.geometry.Coordinate; import org.geomajas.gwt.client.gfx.Paintable; import org.geomajas.gwt.client.gfx.PainterVisitor; import org.geomajas.gwt.client.map.layer.VectorLayer; import org.geomajas.gwt.client.spatial.Bbox; import org.geomajas.gwt.client.spatial.geometry.Geometry; import org.geomajas.gwt.client.util.AttributeUtil; import org.geomajas.gwt.client.util.GeometryConverter; import org.geomajas.layer.feature.Attribute; import org.geomajas.layer.feature.attribute.AssociationValue; import org.geomajas.layer.feature.attribute.BooleanAttribute; import org.geomajas.layer.feature.attribute.CurrencyAttribute; import org.geomajas.layer.feature.attribute.DateAttribute; import org.geomajas.layer.feature.attribute.DoubleAttribute; import org.geomajas.layer.feature.attribute.FloatAttribute; import org.geomajas.layer.feature.attribute.ImageUrlAttribute; import org.geomajas.layer.feature.attribute.IntegerAttribute; import org.geomajas.layer.feature.attribute.LongAttribute; import org.geomajas.layer.feature.attribute.ManyToOneAttribute; import org.geomajas.layer.feature.attribute.OneToManyAttribute; import org.geomajas.layer.feature.attribute.ShortAttribute; import org.geomajas.layer.feature.attribute.StringAttribute; import org.geomajas.layer.feature.attribute.UrlAttribute; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * <p> * Definition of an object belonging to a {@link VectorLayer}. A feature is an object with a unique ID * within it's layer, a list of alpha-numerical attributes and a geometry. * </p> * * @author Pieter De Graef * @since 1.6.0 */ @Api public class Feature implements Paintable, Cloneable { /** Unique identifier */ private String id; /** Reference to the layer. */ private VectorLayer layer; /** Map of this feature's attributes. */ private Map<String, Attribute> attributes = new HashMap<String, Attribute>(); /** Are the attributes lazy Loaded yet? */ private boolean attributesLoaded; /** This feature's geometry. */ private Geometry geometry; /** The identifier of this feature's style. */ private String styleId; /** Label text. */ private String label = ""; // new features have no label yet, empty string to avoid npe ! /** Coordinate for the label. */ private Coordinate labelPosition; /** is the feature clipped ? */ private boolean clipped; /** * Is it allowed for the user in question to edit this feature? */ private boolean updatable; /** * Is it allowed for the user in question to delete this feature? */ private boolean deletable; private String crs; // Constructors: /** No-arguments constructor. */ public Feature() { this((org.geomajas.layer.feature.Feature) null, null); } /** * Construct feature with given id for given layer. * * @param id feature id * @param layer layer */ public Feature(String id, VectorLayer layer) { this(layer); this.id = id; } /** * Construct a feature for given layer. * * @param layer layer */ public Feature(VectorLayer layer) { this((org.geomajas.layer.feature.Feature) null, layer); } /** * Construct a feature based from a feature DTO for given layer. * * @param dto feature dto * @param layer layer */ public Feature(org.geomajas.layer.feature.Feature dto, VectorLayer layer) { this.layer = layer; this.geometry = null; this.styleId = null; this.labelPosition = null; this.clipped = false; if (null != dto) { label = dto.getLabel(); attributes = dto.getAttributes(); attributesLoaded = true; id = dto.getId(); geometry = GeometryConverter.toGwt(dto.getGeometry()); styleId = dto.getStyleId(); crs = dto.getCrs(); setUpdatable(dto.isUpdatable()); setDeletable(dto.isDeletable()); } else { if (layer != null) { // Create empty attributes: for (AbstractAttributeInfo attrInfo : layer.getLayerInfo().getFeatureInfo().getAttributes()) { attributes.put(attrInfo.getName(), AttributeUtil.createEmptyAttribute(attrInfo)); } } setUpdatable(true); setDeletable(true); } } // Paintable implementation: public void accept(PainterVisitor visitor, Object group, Bbox bounds, boolean recursive) { visitor.visit(this, group); } public String getId() { return id; } // Class specific functions: /** Clone the object. */ public Feature clone() { // NOSONAR overwriting clone but not using super.clone() Feature feature = new Feature(this.layer); if (null != attributes) { feature.attributes = new HashMap<String, Attribute>(); for (Entry<String, Attribute> entry : attributes.entrySet()) { feature.attributes.put(entry.getKey(), (Attribute<?>) entry.getValue().clone()); } } feature.clipped = clipped; feature.labelPosition = labelPosition; feature.label = label; feature.layer = layer; if (null != geometry) { feature.geometry = (Geometry) geometry.clone(); } feature.id = id; feature.styleId = styleId; feature.crs = crs; feature.deletable = deletable; feature.updatable = updatable; feature.attributesLoaded = attributesLoaded; return feature; } /** * Get attribute value for given attribute name. * * @param attributeName attribute name * @return attribute value */ public Object getAttributeValue(String attributeName) { Attribute attribute = getAttributes().get(attributeName); if (attribute != null) { return attribute.getValue(); } return null; } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setBooleanAttribute(String name, Boolean value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof BooleanAttribute)) { throw new IllegalStateException("Cannot set boolean value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((BooleanAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setCurrencyAttribute(String name, String value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof CurrencyAttribute)) { throw new IllegalStateException("Cannot set currency value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((CurrencyAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setDateAttribute(String name, Date value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof DateAttribute)) { throw new IllegalStateException("Cannot set date value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((DateAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setDoubleAttribute(String name, Double value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof DoubleAttribute)) { throw new IllegalStateException("Cannot set double value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((DoubleAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setFloatAttribute(String name, Float value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof FloatAttribute)) { throw new IllegalStateException("Cannot set float value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((FloatAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setImageUrlAttribute(String name, String value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof ImageUrlAttribute)) { throw new IllegalStateException("Cannot set imageUrl value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((ImageUrlAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setIntegerAttribute(String name, Integer value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof IntegerAttribute)) { throw new IllegalStateException("Cannot set integer value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((IntegerAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setLongAttribute(String name, Long value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof LongAttribute)) { throw new IllegalStateException("Cannot set boolean value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((LongAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setShortAttribute(String name, Short value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof ShortAttribute)) { throw new IllegalStateException("Cannot set short value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((ShortAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setStringAttribute(String name, String value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof StringAttribute)) { throw new IllegalStateException("Cannot set boolean value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((StringAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setUrlAttribute(String name, String value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof UrlAttribute)) { throw new IllegalStateException("Cannot set url value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((UrlAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void setManyToOneAttribute(String name, AssociationValue value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof ManyToOneAttribute)) { throw new IllegalStateException("Cannot set manyToOne value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } ((ManyToOneAttribute) attribute).setValue(value); } /** * Set attribute value of given type. * * @param name attribute name * @param value attribute value */ public void addOneToManyValue(String name, AssociationValue value) { Attribute attribute = getAttributes().get(name); if (!(attribute instanceof OneToManyAttribute)) { throw new IllegalStateException("Cannot set oneToMany value on attribute with different type, " + attribute.getClass().getName() + " setting value " + value); } OneToManyAttribute oneToMany = (OneToManyAttribute) attribute; if (oneToMany.getValue() == null) { oneToMany.setValue(new ArrayList<AssociationValue>()); } oneToMany.getValue().add(value); } /** * Transform this object into a DTO feature. * * @return dto for this feature */ public org.geomajas.layer.feature.Feature toDto() { org.geomajas.layer.feature.Feature dto = new org.geomajas.layer.feature.Feature(); dto.setAttributes(attributes); dto.setClipped(clipped); dto.setId(id); dto.setGeometry(GeometryConverter.toDto(geometry)); dto.setCrs(crs); dto.setLabel(getLabel()); return dto; } /** * Get feature label. * * @return label */ public String getLabel() { return label; } /** * Set feature label. * * @param label * @since 1.15.0 */ public void setLabel(String label) { this.label = label; } // Getters and setters: /** * Crs as (optionally) set by the backend. * * @return crs for this feature */ public String getCrs() { return crs; } /** * Get the attributes map, throws exception when it needs to be lazy loaded. * * @return attributes map * @throws IllegalStateException * attributes not present because of lazy loading */ public Map<String, Attribute> getAttributes() throws IllegalStateException { return attributes; } /** * Set the attributes map. * * @param attributes * attributes map */ public void setAttributes(Map<String, Attribute> attributes) { if (null == attributes) { throw new IllegalArgumentException("Attributes should be not-null."); } this.attributes = attributes; this.attributesLoaded = true; } /** * Check whether the attributes are already available or should be lazy loaded. * * @return true when attributes are available */ public boolean isAttributesLoaded() { return attributesLoaded; } /** * Get the feature's geometry, throws exception when it needs to be lazy loaded. * * @return geometry * @throws IllegalStateException * attributes not present because of lazy loading */ public Geometry getGeometry() throws IllegalStateException { if (null == geometry) { throw new IllegalStateException("Geometry not available, use LazyLoader."); } return geometry; } /** * Set the geometry. * * @param geometry * geometry */ public void setGeometry(Geometry geometry) { this.geometry = geometry; } /** * Check whether the geometry is already available or should be lazy loaded. * * @return true when geometry are available */ public boolean isGeometryLoaded() { return geometry != null; } /** * Is this feature selected? * * @return true when feature is selected */ public boolean isSelected() { return layer.isFeatureSelected(getId()); } /** * Get the layer which contains this feature. * * @return layer which contains this feature */ public VectorLayer getLayer() { return layer; } /** * Is the logged in user allowed to edit this feature? * * @return true when edit/update is allowed for this feature */ public boolean isUpdatable() { return updatable; } /** * Set whether the logged in user is allowed to edit/update this feature. * * @param editable * true when edit/update is allowed for this feature */ public void setUpdatable(boolean editable) { this.updatable = editable; } /** * Is the logged in user allowed to delete this feature? * * @return true when delete is allowed for this feature */ public boolean isDeletable() { return deletable; } /** * Set whether the logged in user is allowed to delete this feature. * * @param deletable * true when deleting this feature is allowed */ public void setDeletable(boolean deletable) { this.deletable = deletable; } /** * Get the style id for this feature. * * @return style if */ public String getStyleId() { return styleId; } /** * Set the style id for this feature. * * @param styleId style id */ public void setStyleId(String styleId) { this.styleId = styleId; } }