/*
* 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.search;
import java.util.ArrayList;
import java.util.List;
import org.geomajas.annotation.Api;
import org.geomajas.gwt.client.map.layer.VectorLayer;
import org.geomajas.gwt.client.util.WidgetLayout;
import org.geomajas.gwt.client.widget.MapWidget;
import org.geomajas.widget.searchandfilter.client.SearchAndFilterMessages;
import org.geomajas.widget.searchandfilter.client.util.CriterionUtil;
import org.geomajas.widget.searchandfilter.client.util.GsfLayout;
import org.geomajas.widget.searchandfilter.client.widget.search.FavouritesController.FavouriteEvent;
import org.geomajas.widget.searchandfilter.search.dto.Criterion;
import org.geomajas.widget.searchandfilter.search.dto.SearchFavourite;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.layout.VLayout;
/**
* A generic {@link SearchWidget} implemented as a panel which can be embedded anywhere.
* <p>
* To build a search widget combine this search widget with a {@link AbstractSearchPanel}.
*
* @see org.geomajas.widget.searchandfilter.client.widget.search.SearchWidgetRegistry
* @author Kristof Heirwegh
* @since 1.0.0
*/
@Api
public class PanelSearchWidget extends VLayout implements SearchWidget {
private static final SearchAndFilterMessages MESSAGES = GWT.create(SearchAndFilterMessages.class);
private final List<SearchRequestHandler> searchHandlers = new ArrayList<SearchRequestHandler>();
private final List<SaveRequestHandler> saveHandlers = new ArrayList<SaveRequestHandler>();
private final List<FavouriteRequestHandler> favouriteHandlers = new ArrayList<FavouriteRequestHandler>();
private HLayout searchButtonBar;
private IButton searchBtn;
private IButton saveBtn;
private IButton removeFilterBtn;
private AbstractSearchPanel searchPanel;
private String widgetId;
private String name;
private Runnable closeAction;
/**
* @param widgetId
* needed to find the widget in the SearchWidgetRegistry.
* @param name
* name of the widget to show in window title and on buttons.
* @param searchPanel
* your specific implementation of a search
*/
public PanelSearchWidget(String widgetId, String name, final AbstractSearchPanel searchPanel) {
super(WidgetLayout.marginLarge);
if (widgetId == null || searchPanel == null) {
throw new IllegalArgumentException("All parameters are required");
}
this.searchPanel = searchPanel;
this.widgetId = widgetId;
this.name = name;
setMargin(WidgetLayout.marginLarge);
IButton favouritesBtn = new IButton(MESSAGES.searchWidgetAddToFavourites());
favouritesBtn.setIcon(GsfLayout.iconBookmark);
favouritesBtn.setShowDisabledIcon(false);
favouritesBtn.setWidth(favouritesBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
favouritesBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
onAddToFavourites();
}
});
searchBtn = new IButton(MESSAGES.searchWidgetSearch());
searchBtn.setWidth(searchBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
searchBtn.setIcon(GsfLayout.iconFind);
searchBtn.setShowDisabledIcon(false);
searchBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
onSearch();
}
});
IButton resetBtn = new IButton(MESSAGES.searchWidgetReset());
resetBtn.setWidth(resetBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
resetBtn.setIcon(WidgetLayout.iconReset);
resetBtn.setShowDisabledIcon(false);
resetBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
searchPanel.reset();
}
});
saveBtn = new IButton(MESSAGES.searchWidgetSave());
saveBtn.setWidth(saveBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
saveBtn.setIcon(WidgetLayout.iconSave);
saveBtn.setShowDisabledIcon(false);
saveBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
onSave();
}
});
saveBtn.setVisible(false);
IButton cancelBtn = new IButton(MESSAGES.searchWidgetCancel());
cancelBtn.setWidth(cancelBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
cancelBtn.setIcon(WidgetLayout.iconCancel);
cancelBtn.setShowDisabledIcon(false);
cancelBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
cancel();
close();
}
});
IButton filterLayerBtn = new IButton(MESSAGES.searchWidgetFilterLayer());
filterLayerBtn
.setWidth(filterLayerBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
filterLayerBtn.setIcon(GsfLayout.iconFilter);
filterLayerBtn.setShowDisabledIcon(false);
filterLayerBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
onFilterLayer();
}
});
removeFilterBtn = new IButton(MESSAGES.searchWidgetRemoveFilter());
removeFilterBtn.
setWidth(removeFilterBtn.getTitle().length() * GsfLayout.buttonFontWidth + GsfLayout.buttonOffset);
removeFilterBtn.setIcon(GsfLayout.iconRemoveFilter);
removeFilterBtn.setShowDisabledIcon(false);
removeFilterBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
onRemoveFilter();
}
});
addMember(searchPanel);
LayoutSpacer ls = new LayoutSpacer();
ls.setWidth("*");
searchButtonBar = new HLayout(10);
searchButtonBar.setWidth100();
if (searchPanel.canAddToFavourites()) {
searchButtonBar.addMember(favouritesBtn);
}
searchButtonBar.addMember(ls);
if (searchPanel.canFilterLayer()) {
searchButtonBar.addMember(removeFilterBtn);
searchButtonBar.addMember(filterLayerBtn);
}
searchButtonBar.addMember(searchBtn);
searchButtonBar.addMember(saveBtn);
if (searchPanel.canReset()) {
searchButtonBar.addMember(resetBtn);
}
if (searchPanel.canCancel()) {
searchButtonBar.addMember(cancelBtn);
}
addMember(searchButtonBar);
}
/**
* Method which is called to close/end the panel (after cancel or save). It reset the panel and calls the close
* action if present. If no close action is present, it hides the panel.
*/
protected void close() {
reset();
if (null == closeAction) {
hide();
} else {
closeAction.run();
}
}
/**
* Set action to be called when pressing the cancel button.
*
* @param closeAction
* cancel action to call
*/
public void setCloseAction(Runnable closeAction) {
this.closeAction = closeAction;
}
// ----------------------------------------------------------
@Override
public void hideSearchButtons() {
searchButtonBar.hide();
}
@Override
public void showSearchButtons() {
searchButtonBar.show();
}
@Override
public String getSearchWidgetId() {
return widgetId;
}
@Override
public String getName() {
return name;
}
@Override
public void showForSearch() {
saveBtn.setVisible(false);
searchBtn.setVisible(true);
if (searchPanel.canFilterLayer()) {
removeFilterBtn.setVisible(CriterionUtil.isFilterActive());
removeFilterBtn.setDisabled(!CriterionUtil.isFilterActive());
}
show();
bringToFront();
searchBtn.select();
searchBtn.focus();
}
@Override
public void showForSave(final SaveRequestHandler handler) {
if (handler != null) {
addSaveRequestHandler(new OneOffSaveRequestHandler(handler));
}
saveBtn.setVisible(true);
searchBtn.setVisible(false);
show();
bringToFront();
saveBtn.select();
saveBtn.focus();
}
@Override
public void initialize(Criterion settings) {
searchPanel.initialize(settings);
}
@Override
public void reset() {
searchHandlers.clear(); // need to remove showForSearch() handler
saveHandlers.clear(); // need to remove showForSave() handler
searchPanel.reset();
}
@Override
public void onSearchStart() {
searchBtn.setIcon(WidgetLayout.iconAjaxLoading);
searchBtn.setDisabled(true);
}
@Override
public void onSearchEnd() {
searchBtn.setIcon(GsfLayout.iconFind);
searchBtn.setDisabled(false);
}
@Override
public void addSearchRequestHandler(SearchRequestHandler handler) {
searchHandlers.add(handler);
}
@Override
public void removeSearchRequestHandler(SearchRequestHandler handler) {
searchHandlers.remove(handler);
}
@Override
public void addSaveRequestHandler(SaveRequestHandler handler) {
saveHandlers.add(handler);
}
@Override
public void removeSaveRequestHandler(SaveRequestHandler handler) {
saveHandlers.remove(handler);
}
@Override
public void addFavouriteRequestHandler(FavouriteRequestHandler handler) {
favouriteHandlers.add(handler);
}
@Override
public void removeFavouriteRequestHandler(FavouriteRequestHandler handler) {
favouriteHandlers.remove(handler);
}
@Override
public void startSearch() {
onSearch();
}
// ----------------------------------------------------------
// -- buttonActions --
// ----------------------------------------------------------
void onSearch() {
if (searchPanel.validate()) {
setVectorLayerOnWhichSearchIsHappeningVisible();
Criterion critter = searchPanel.getFeatureSearchCriterion();
SearchRequestEvent sre = new SearchRequestEvent(this, critter);
for (SearchRequestHandler handler : searchHandlers) {
handler.onSearchRequested(sre);
}
}
}
private void onSave() {
if (searchPanel.validate()) {
save(searchPanel.getFeatureSearchCriterion());
close();
}
}
private void save(Criterion criterion) {
SaveRequestEvent event = new SaveRequestEvent(this, criterion);
for (SaveRequestHandler handler : saveHandlers) {
handler.onSaveRequested(event);
}
}
private void cancel() {
SaveRequestEvent event = new SaveRequestEvent(this, null);
for (SaveRequestHandler handler : saveHandlers) {
handler.onCancelRequested(event);
}
}
private void onAddToFavourites() {
if (searchPanel.validate()) {
SearchFavourite fav = new SearchFavourite();
fav.setCriterion(searchPanel.getFeatureSearchCriterion());
for (FavouriteRequestHandler handler : favouriteHandlers) {
handler.onAddRequested(new FavouriteEvent(null, fav, this));
}
}
}
void onFilterLayer() {
if (searchPanel.validate()) {
Criterion critter = searchPanel.getFeatureSearchCriterion();
MapWidget map = searchPanel.getMapWidget();
CriterionUtil.clearLayerFilters(map);
CriterionUtil.setLayerFilter(map, critter);
setVectorLayerOnWhichSearchIsHappeningVisible();
removeFilterBtn.setVisible(true);
removeFilterBtn.setDisabled(false);
}
}
void onRemoveFilter() {
CriterionUtil.clearLayerFilters(searchPanel.getMapWidget());
removeFilterBtn.setDisabled(true);
}
private void setVectorLayerOnWhichSearchIsHappeningVisible() {
VectorLayer vectorLayer = searchPanel.getFeatureSearchVectorLayer();
if (null != vectorLayer && !vectorLayer.isVisible()) {
vectorLayer.setVisible(true);
}
}
// ----------------------------------------------------------
/**
* @author Kristof Heirwegh
*/
private class OneOffSaveRequestHandler implements SaveRequestHandler {
private final SaveRequestHandler oneOffHandler;
public OneOffSaveRequestHandler(SaveRequestHandler handler) {
this.oneOffHandler = handler;
}
public void onSaveRequested(SaveRequestEvent event) {
oneOffHandler.onSaveRequested(event);
removeHandler();
}
public void onCancelRequested(SaveRequestEvent event) {
oneOffHandler.onCancelRequested(event);
removeHandler();
}
private void removeHandler() {
GWT.runAsync(new RunAsyncCallback() {
public void onSuccess() {
removeSaveRequestHandler(oneOffHandler);
}
public void onFailure(Throwable reason) {
}
});
}
}
}