/*
* 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.searchandfilter.client.widget.multifeaturelistgrid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.geomajas.annotation.Api;
import org.geomajas.gwt.client.map.feature.Feature;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.widget.featureinfo.client.widget.factory.FeatureDetailWidgetFactory;
import org.geomajas.widget.searchandfilter.client.SearchAndFilterMessages;
import org.geomajas.widget.searchandfilter.client.widget.search.SearchEvent;
import org.geomajas.widget.searchandfilter.client.widget.search.SearchHandler;
import org.geomajas.widget.searchandfilter.search.dto.Criterion;
import com.google.gwt.core.client.GWT;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import com.smartgwt.client.widgets.tab.events.CloseClickHandler;
import com.smartgwt.client.widgets.tab.events.TabCloseClickEvent;
import com.smartgwt.client.widgets.toolbar.ToolStripButton;
/**
* A collection of FeatureListGrids.
*
* @author Kristof Heirwegh
* @author Joachim Van der Auwera
* @author An Buyle
* @author Oliver May
*
* @since 1.0.0
*/
@Api
public class MultiFeatureListGrid extends Canvas implements SearchHandler {
protected final MapWidget map;
protected TabSet tabset;
protected Label empty;
protected boolean clearTabsetOnSearch;
protected boolean showDetailsOnSingleResult;
protected boolean showCsvExportAction = true;
private boolean sortFeatures;
private static final SearchAndFilterMessages MESSAGES = GWT.create(SearchAndFilterMessages.class);
private List<ExtraButton> extraButtons = new ArrayList<ExtraButton>();
public MultiFeatureListGrid(MapWidget map) {
super();
this.map = map;
tabset = new TabSet();
tabset.setWidth100();
tabset.setHeight100();
tabset.setOverflow(Overflow.HIDDEN);
tabset.addCloseClickHandler(new CloseClickHandler() {
public void onCloseClick(TabCloseClickEvent event) {
setEmpty((tabset.getTabs().length == 1));
}
});
this.addChild(tabset);
empty = new Label(MESSAGES.multiFeatureListGridNoData());
empty.setWidth100();
empty.setAlign(Alignment.CENTER);
empty.setPadding(15);
this.addChild(empty);
}
public void initialize() {
}
public MapWidget getMap() {
return map;
}
public boolean isClearTabsetOnSearch() {
return clearTabsetOnSearch;
}
public void setClearTabsetOnSearch(boolean clearTabsetOnSearch) {
this.clearTabsetOnSearch = clearTabsetOnSearch;
}
public boolean isShowDetailsOnSingleResult() {
return showDetailsOnSingleResult;
}
public void setShowDetailsOnSingleResult(boolean showDetailsOnSingleResult) {
this.showDetailsOnSingleResult = showDetailsOnSingleResult;
}
public boolean isShowCsvExportAction() {
return showCsvExportAction;
}
public void setShowCsvExportAction(boolean showCsvExportAction) {
this.showCsvExportAction = showCsvExportAction;
}
public void setSortFeatures(boolean sortFeatures) {
this.sortFeatures = sortFeatures;
}
public boolean doSortFeatures() {
return sortFeatures;
}
/**
* Remove all data from the widget.
*/
public void removeAll() {
for (Tab tab : tabset.getTabs()) {
tabset.removeTab(tab);
}
setEmpty();
}
/**
* Remove just the given layer (if it exists).
*
* @param layer layer to remove
*/
public void remove(VectorLayer layer) {
removeTab(layer);
}
/**
* Add features in the widget for several layers.
*
* @param featureMap map of features per layer
*/
public void addFeatures(Map<VectorLayer, List<Feature>> featureMap) {
addFeatures(featureMap, null);
}
/**
* Add features in the widget for several layers.
*
* @param featureMap map of features per layer
* @param criterion the original request for this search
*/
public void addFeatures(Map<VectorLayer, List<Feature>> featureMap, Criterion criterion) {
if (showDetailsOnSingleResult && featureMap.size() == 1) {
// sorting is never needed if only 1 entry
List<Feature> features = featureMap.values().iterator().next();
if (features.size() == 1) {
showFeatureDetailWindow(map, features.get(0));
}
}
//Add feature tabs in map order
for (VectorLayer layer : map.getMapModel().getVectorLayers()) {
if (featureMap.containsKey(layer)) {
addFeatures(layer, featureMap.get(layer), criterion);
}
}
tabset.selectTab(0);
}
private void addFeatures(VectorLayer layer, List<Feature> features, Criterion criterion) {
FeatureListGridTab tab = getOrCreateTab(layer);
tab.empty();
tab.setSortFeatures(sortFeatures);
tab.setCriterion(criterion);
tab.addFeatures(features);
tabset.addTab(tab, 0);
setEmpty();
}
/**
* Add a button in the tool strip at the requested position.
*
* @param layerId layer which needs the extra button
* @param button button to add
* @param position position
*/
@Api
public void addButton(String layerId, ToolStripButton button, int position) {
extraButtons.add(new ExtraButton(constructIdSaveLayerId(layerId), button, position));
}
// ----------------------------------------------------------
// -- SearchHandler --
// ----------------------------------------------------------
public void onSearchStart(SearchEvent event) {
} // not used
public void onSearchEnd(SearchEvent event) {
} // not used
public void onSearchDone(SearchEvent event) {
if (clearTabsetOnSearch) {
removeAll();
}
addFeatures(event.getResult(), event.getCriterion());
}
// ----------------------------------------------------------
private void setEmpty(boolean state) {
empty.setVisible(state);
}
private void setEmpty() {
setEmpty((tabset.getTabs().length == 0));
}
private void removeTab(VectorLayer layer) {
String id = tabset.getID() + "_" + constructIdSaveLayerId(layer.getId());
if (tabset.getTab(id) != null) {
tabset.removeTab(id);
setEmpty();
}
}
private FeatureListGridTab getOrCreateTab(VectorLayer layer) {
String idSaveLayerId = constructIdSaveLayerId(layer.getId());
String id = tabset.getID() + "_" + idSaveLayerId;
FeatureListGridTab t = (FeatureListGridTab) tabset.getTab(id);
if (t == null) {
t = new FeatureListGridTab(map, layer, isShowCsvExportAction());
t.setID(id);
for (ExtraButton button : extraButtons) {
if (idSaveLayerId.equals(button.getIdSaveLayerId())) {
t.addButton(button.getButton(), button.getPosition());
}
}
}
return t;
}
private String constructIdSaveLayerId(String layerId) {
layerId = layerId.replaceAll("\\-", "_"); // SmartGWT does not support '-' char in ID FeatureListGridTab
return layerId;
}
/**
* Get the selected records for the tab.
*
* @param layerId layer to get selected items for
* @return selected records
*/
@Api
public ListGridRecord[] getSelection(String layerId) {
String id = tabset.getID() + "_" + constructIdSaveLayerId(layerId);
FeatureListGridTab tab = (FeatureListGridTab) tabset.getTab(id);
if (tab != null) {
return tab.getSelection();
}
return null;
}
/**
* Container for keeping a button until attached to a tab.
*
* @author Joachim Van der Auwera
*/
private static class ExtraButton {
private String idSaveLayerId;
private ToolStripButton button;
private int position;
public ExtraButton(String idSaveLayerId, ToolStripButton button, int position) {
this.idSaveLayerId = idSaveLayerId;
this.button = button;
this.position = position;
}
public String getIdSaveLayerId() {
return idSaveLayerId;
}
public ToolStripButton getButton() {
return button;
}
public int getPosition() {
return position;
}
}
//FIXME: move to a service?
public static void showFeatureDetailWindow(final MapWidget mapWidget, final Feature feature) {
Window window = FeatureDetailWidgetFactory.createFeatureDetailWindow(feature, false);
window.setPageTop(mapWidget.getAbsoluteTop() + 10);
window.setPageLeft(mapWidget.getAbsoluteLeft() + 10);
window.draw();
}
}