package org.sigmah.client.ui.widget.form;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.sigmah.client.i18n.I18N;
import org.sigmah.shared.command.GetIndicatorDataSources;
import org.sigmah.shared.command.GetProject;
import org.sigmah.shared.dto.IndicatorDTO;
import org.sigmah.shared.dto.IndicatorDataSourceDTO;
import org.sigmah.shared.dto.ProjectDTO;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.ListView;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.AdapterField;
import com.extjs.gxt.ui.client.widget.form.CheckBox;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import java.util.ArrayList;
import org.sigmah.client.dispatch.CommandResultHandler;
import org.sigmah.client.dispatch.DispatchAsync;
import org.sigmah.client.dispatch.monitor.LoadingMask;
import org.sigmah.client.ui.res.icon.IconImageBundle;
import org.sigmah.client.ui.widget.popup.IndicatorBrowsePopup;
import org.sigmah.offline.dao.RequestManager;
import org.sigmah.offline.dao.RequestManagerCallback;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.command.result.VoidResult;
/**
*
* Field widget for the Indicator's {@code dataSourceIds} property.
* The {@code value} of this field is a set of the ids of indicators which
* have been selected as dataSources.
*
* @author Alexander Bertram (akbertram@gmail.com)
* @author Raphaƫl Calabro (rcalabro@ideia.fr) v2
*/
public class DatasourceField extends AdapterField {
private final DispatchAsync dispatcher;
private final ListView<IndicatorDataSourceDTO> listView;
private Button removeButton;
private final CheckBox directBox;
private final CheckBox otherIndicatorsBox;
private final ContentPanel panel;
private final LayoutContainer container;
// Collections.emptySet is not serializable :-(
private static final Set<Integer> EMPTY_SET = new HashSet<Integer>();
private Set<Integer> oldValue = EMPTY_SET;
public DatasourceField(DispatchAsync dispatcher) {
super(new LayoutContainer());
this.dispatcher = dispatcher;
container = (LayoutContainer)getWidget();
directBox = new CheckBox();
directBox.setBoxLabel(I18N.MESSAGES.indicatorDatasourceDirect(I18N.CONSTANTS.loading()));
container.add(directBox);
otherIndicatorsBox = new CheckBox();
otherIndicatorsBox.setBoxLabel(I18N.CONSTANTS.indicatorDataSourceOther());
otherIndicatorsBox.addListener(Events.Change, new Listener<FieldEvent>() {
@Override
public void handleEvent(FieldEvent event) {
boolean checked = event.getValue() == Boolean.TRUE;
showGrid(checked);
onChange();
}
});
container.add(otherIndicatorsBox);
panel = new ContentPanel();
panel.setHeaderVisible(false);
ToolBar toolBar = new ToolBar();
toolBar.add(new Button(I18N.CONSTANTS.addIndicator(), IconImageBundle.ICONS.add(), new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
addSource();
}
}));
removeButton = new Button(I18N.CONSTANTS.remove(), IconImageBundle.ICONS.delete(), new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
removeSelected();
}
});
removeButton.disable();
toolBar.add(removeButton);
panel.setTopComponent(toolBar);
listView = new ListView<IndicatorDataSourceDTO>();
listView.setStore(new ListStore<IndicatorDataSourceDTO>());
listView.setSimpleTemplate("<strong>{indicatorName}</strong><br>{databaseName}");
listView.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<IndicatorDataSourceDTO>() {
@Override
public void selectionChanged(
SelectionChangedEvent<IndicatorDataSourceDTO> se) {
removeButton.setEnabled(!se.getSelection().isEmpty());
}
});
panel.setLayout(new FitLayout());
panel.add(listView);
panel.setHeight(150);
panel.setVisible(false);
container.add(panel);
}
public CheckBox getDirectBox() {
return directBox;
}
private void addSource() {
final IndicatorBrowsePopup dialog = new IndicatorBrowsePopup(dispatcher);
dialog.initialize();
dialog.show(new CommandResultHandler<VoidResult>() {
@Override
protected void onCommandSuccess(VoidResult result) {
for(IndicatorDataSourceDTO datasource : dialog.getSelectionAsDataSources()) {
if(!alreadyIncluded(datasource)) {
listView.getStore().add(datasource);
}
}
dialog.hide();
onChange();
}
});
}
private void onChange() {
fireChangeEvent(oldValue, getValue());
oldValue = getValue();
}
private void removeSelected() {
List<IndicatorDataSourceDTO> selection = listView.getSelectionModel().getSelection();
Set<Integer> oldValue = getValue();
for(IndicatorDataSourceDTO datasource : selection) {
listView.getStore().remove(datasource);
}
if(!selection.isEmpty()) {
fireChangeEvent(oldValue, getValue());
}
}
private boolean alreadyIncluded(IndicatorDataSourceDTO newDatasource) {
for(IndicatorDataSourceDTO datasource : listView.getStore().getModels()) {
if(datasource.getIndicatorId() == newDatasource.getIndicatorId()) {
return true;
}
}
return false;
}
public void load(final Integer projectId, final IndicatorDTO indicator) {
listView.getStore().removeAll();
// Reference on the project name
final String[] projectName = {I18N.CONSTANTS.loading()};
// List of datasources
final ArrayList<IndicatorDataSourceDTO> datasources = new ArrayList<IndicatorDataSourceDTO>();
final RequestManager<VoidResult> requestManager = new RequestManager<VoidResult>(null, new CommandResultHandler<VoidResult>() {
@Override
protected void onCommandSuccess(VoidResult result) {
listView.getStore().add(datasources);
otherIndicatorsBox.disableEvents(true);
otherIndicatorsBox.setValue(!datasources.isEmpty());
showGrid(!datasources.isEmpty());
otherIndicatorsBox.disableEvents(false);
directBox.setValue(indicator == null || indicator.isDirectDataEntryEnabled());
directBox.setBoxLabel(I18N.MESSAGES.indicatorDatasourceDirect(projectName[0]));
oldValue = getValue();
}
});
final LoadingMask loadingMask = new LoadingMask(container);
// Retrieve every visible project
dispatcher.execute(new GetProject(projectId, ProjectDTO.Mode.BASE), new RequestManagerCallback<VoidResult, ProjectDTO>(requestManager) {
@Override
public void onRequestSuccess(ProjectDTO result) {
projectName[0] = result.getName();
}
}, loadingMask);
// Retrieve the associated datasources
if(indicator != null && indicator.getId() != null) {
dispatcher.execute(new GetIndicatorDataSources(indicator.getId()), new RequestManagerCallback<VoidResult, ListResult<IndicatorDataSourceDTO>>(requestManager) {
@Override
public void onRequestSuccess(ListResult<IndicatorDataSourceDTO> result) {
datasources.addAll(result.getData());
}
}, loadingMask);
}
requestManager.ready();
}
@Override
public Set<Integer> getValue() {
if(otherIndicatorsBox.getValue()) {
return getSelectedIds();
} else {
return EMPTY_SET;
}
}
private Set<Integer> getSelectedIds() {
Set<Integer> ids = new HashSet<Integer>();
for(IndicatorDataSourceDTO datasource : listView.getStore().getModels()) {
ids.add(datasource.getIndicatorId());
}
return ids;
}
private void showGrid(boolean visible) {
panel.setVisible(visible);
container.layout(true);
}
}