/*
* 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.widget.featureinfo.client.widget;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.geomajas.configuration.AbstractAttributeInfo;
import org.geomajas.configuration.AbstractReadOnlyAttributeInfo;
import org.geomajas.gwt.client.map.MapModel;
import org.geomajas.gwt.client.map.feature.Feature;
import org.geomajas.gwt.client.map.layer.Layer;
import org.geomajas.gwt.client.map.layer.RasterLayer;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.widget.featureinfo.client.FeatureInfoMessages;
import com.google.gwt.core.client.GWT;
import com.smartgwt.client.types.AutoFitWidthApproach;
import com.smartgwt.client.types.Autofit;
import com.smartgwt.client.types.GroupStartOpen;
import com.smartgwt.client.widgets.grid.HoverCustomizer;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
/**
* <p>
* The <code>MultiLayerFeaturesList</code> is a class providing a floating
* window that shows a list of all the features (possibly from different layers)
* provided to it. Clicking on a feature in the list, results in a call of the
* provided
* {@link org.geomajas.widget.featureinfo.client.widget.FeatureClickHandler}.
* </p>
*
* @author An Buyle
* @author Oliver May
* @author Wout Swartenbroekx
*/
public class MultiLayerFeaturesList extends ListGrid {
private static final int MAX_ROWS = 25;
private static final FeatureInfoMessages MESSAGES = GWT.create(FeatureInfoMessages.class);
private final Map<String, RasterLayer> rasterLayers = new HashMap<String, RasterLayer>();
private final Map<String, Feature> vectorFeatures = new HashMap<String, Feature>();
private final Map<String, Feature> rasterFeatures = new HashMap<String, Feature>();
/**
* external handler, called when clicking on a feature in the list
*/
private final FeatureClickHandler featureClickHandler;
private final MapWidget mapWidget;
private Map<String, String> featuresListLabels;
private static final String LABEL = "LABEL";
private static final String FEATURE_ID = "FEATURE_ID";
private static final String LAYER_ID = "LAYER_ID";
private static final String LAYER_LABEL = "LAYER_LABEL";
// -------------------------------------------------------------------------
// Constructor:
// -------------------------------------------------------------------------
/**
* Create an instance.
*
* @param mapWidget map widget
* @param featureClickHandler handler
*/
public MultiLayerFeaturesList(final MapWidget mapWidget, FeatureClickHandler featureClickHandler) {
super();
this.mapWidget = mapWidget;
this.featureClickHandler = featureClickHandler;
buildWidget();
}
/**
* Feed a map of features to the widget, so it can be built.
*
* @param featureMap feature map
*/
public void setFeatures(Map<String, List<org.geomajas.layer.feature.Feature>> featureMap) {
MapModel mapModel = mapWidget.getMapModel();
for (Entry<String, List<org.geomajas.layer.feature.Feature>> clientLayerId : featureMap.entrySet()) {
Layer<?> layer = mapModel.getLayer(clientLayerId.getKey());
if (null != layer) {
List<org.geomajas.layer.feature.Feature> orgFeatures = clientLayerId.getValue();
if (!orgFeatures.isEmpty()) {
addFeatures(layer, orgFeatures);
}
}
}
}
private void addFeatures(Layer<?> layer, List<org.geomajas.layer.feature.Feature> orgFeatures) {
if (layer instanceof VectorLayer) {
VectorLayer vLayer = (VectorLayer) layer;
for (org.geomajas.layer.feature.Feature featDTO : orgFeatures) {
Feature feat = new Feature(featDTO, vLayer);
vLayer.getFeatureStore().addFeature(feat);
vectorFeatures.put(getFullFeatureId(feat, vLayer), feat);
addFeature(feat, vLayer);
}
} else if (layer instanceof RasterLayer) {
RasterLayer rLayer = (RasterLayer) layer;
rasterLayers.put(layer.getId(), rLayer);
for (org.geomajas.layer.feature.Feature featDTO : orgFeatures) {
Feature feat = new Feature(featDTO, null);
rasterFeatures.put(getFullFeatureId(feat, rLayer), feat);
addFeature(feat, rLayer);
}
}
}
@Override
/* Override getCellCSSText to implement padding-left of ordinary feature rows */
protected String getCellCSSText(ListGridRecord record, int rowNum, int colNum) {
// Note: using listGrid.setCellPadding() would also padd group rows
String newStyle;
String style = record.getCustomStyle(); /* returns groupNode if group row, else e.g. null */
if (LABEL.equals(getFieldName(colNum)) && (null == style || !"groupNode".equalsIgnoreCase(style))) {
newStyle = "padding-left: 40px;";
} else { /* groupCell */
newStyle = "padding-left: 5px;";
}
if (null != super.getCellCSSText(record, rowNum, colNum)) {
newStyle = super.getCellCSSText(record, rowNum, colNum) + newStyle;
/* add padding after original, the latter specified wins. */
}
return newStyle;
}
/**
* Adds a new feature to the grid list. A {@link VectorLayer} must have been
* set first, and the feature must belong to that VectorLayer.
*
* @param feature
* The feature to be added to the grid list.
* @return Returns true in case of success, and false if the feature is null
* or if the feature does not belong to the correct layer or if the
* layer has not yet been set.
*/
private boolean addFeature(Feature feature, Layer<?> layer) {
// Basic checks:
if (feature == null || layer == null ) {
return false;
}
// Feature checks out, add it to the grid:
ListGridRecord record = new ListGridRecord();
if (layer instanceof VectorLayer) {
record.setAttribute(LABEL, getLabel(feature));
} else if (layer instanceof RasterLayer) {
record.setAttribute(LABEL, feature.getId());
}
record.setAttribute(FEATURE_ID, getFullFeatureId(feature, layer));
record.setAttribute(LAYER_ID, layer.getId());
record.setAttribute(LAYER_LABEL, layer.getLabel());
addData(record);
return true;
}
private String getLabel(Feature f) {
if (null != featuresListLabels) {
for (Map.Entry<String, String> entry : featuresListLabels.entrySet()) {
if (f.getLayer().getId().equalsIgnoreCase(entry.getKey())) {
return (String) f.getAttributeValue(entry.getValue());
}
}
}
return f.getLabel();
}
private static String getFullFeatureId(Feature feature, Layer<?> layer) {
return layer.getId() + "." + feature.getId();
}
/**
* Build the entire widget.
*/
private void buildWidget() {
// setTitle(MESSAGES.nearbyFeaturesListTooltip());
setShowEmptyMessage(true);
setWidth100();
setHeight100();
setShowHeader(false);
setShowAllRecords(true);
// List size calculation
setDefaultWidth(400);
setDefaultHeight(300);
setAutoFitData(Autofit.BOTH);
setAutoFitMaxRecords(MAX_ROWS);
setAutoFitFieldWidths(true);
setAutoFitWidthApproach(AutoFitWidthApproach.BOTH);
ListGridField labelField = new ListGridField(LABEL);
ListGridField featIdField = new ListGridField(FEATURE_ID);
ListGridField layerField = new ListGridField(LAYER_ID);
ListGridField layerLabelField = new ListGridField(LAYER_LABEL);
setGroupByField(LAYER_LABEL);
setGroupStartOpen(GroupStartOpen.ALL);
setFields(/* dummyIndentField, */labelField, layerField, featIdField, layerLabelField);
hideField(LAYER_ID);
hideField(FEATURE_ID);
hideField(LAYER_LABEL);
addRecordClickHandler(new RecordClickHandler() {
public void onRecordClick(RecordClickEvent event) {
String fId = event.getRecord().getAttribute(FEATURE_ID);
String lId = event.getRecord().getAttribute(LAYER_ID);
Feature feat = vectorFeatures.get(fId);
if (feat != null) {
featureClickHandler.onClick(feat, feat.getLayer());
} else {
Layer<?> rasterLayer = rasterLayers.get(lId);
feat = rasterFeatures.get(fId);
featureClickHandler.onClick(feat, rasterLayer);
}
}
});
setShowHover(true);
setCanHover(true);
setHoverWidth(200);
setHoverCustomizer(new HoverCustomizer() {
public String hoverHTML(Object value, ListGridRecord record, int rowNum, int colNum) {
String fId = record.getAttribute(FEATURE_ID);
Feature feat = vectorFeatures.get(fId);
StringBuilder tooltip = new StringBuilder();
if (feat != null) {
for (AbstractAttributeInfo a : feat.getLayer().getLayerInfo().getFeatureInfo().getAttributes()) {
if (a instanceof AbstractReadOnlyAttributeInfo &&
((AbstractReadOnlyAttributeInfo) a).isIdentifying()) {
tooltip.append("<b>");
tooltip.append(((AbstractReadOnlyAttributeInfo) a).getLabel());
tooltip.append("</b>: ");
tooltip.append(feat.getAttributeValue(a.getName()));
tooltip.append("<br/>");
}
}
tooltip.append(MESSAGES.nearbyFeaturesListTooltip());
}
return tooltip.toString();
}
});
}
/**
* @param featuresListLabels
* the featuresListLabels to set
*/
public void setFeaturesListLabels(Map<String, String> featuresListLabels) {
this.featuresListLabels = featuresListLabels;
}
}