package org.activityinfo.ui.client.component.importDialog.mapping;
import com.google.common.base.Objects;
import com.google.common.collect.Maps;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.ScrollPanel;
import org.activityinfo.model.form.FormField;
import org.activityinfo.model.type.FieldTypeClass;
import org.activityinfo.core.shared.importing.model.ColumnAction;
import org.activityinfo.core.shared.importing.model.IgnoreAction;
import org.activityinfo.core.shared.importing.model.ImportModel;
import org.activityinfo.core.shared.importing.model.MapExistingAction;
import org.activityinfo.core.shared.importing.strategy.ImportTarget;
import org.activityinfo.i18n.shared.I18N;
import org.activityinfo.ui.client.widget.Panel;
import org.activityinfo.ui.client.widget.RadioButton;
import java.util.List;
import java.util.Map;
/**
* A simple panel that provides the user with a list of possible properties
* to which to map the column as a list of radioButton buttons.
*/
public class ColumnActionSelector extends Composite implements HasValue<ColumnAction> {
public interface Template extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<span class='mandatory'> * </span> " +
"{0}")
SafeHtml html(String label);
}
private static final Template TEMPLATE = GWT.create(Template.class);
private static int nextUniqueGroupNum = 1;
private String group = "columnBinding" + (nextUniqueGroupNum++);
private Map<ColumnAction, RadioButton> buttons = Maps.newHashMap();
private ColumnAction value = IgnoreAction.INSTANCE;
private final RadioButton ignoreButton;
private final ImportModel importModel;
private final ScrollPanel scrollPanel;
public ColumnActionSelector(List<MapExistingAction> actions, ImportModel importModel, final Panel fieldSelectorPanel) {
this.importModel = importModel;
FlowPanel panel = new FlowPanel();
ignoreButton = createRadioButton(SafeHtmlUtils.fromString(I18N.CONSTANTS.ignoreColumnAction()), IgnoreAction.INSTANCE);
ignoreButton.addStyleName(ColumnMappingStyles.INSTANCE.stateIgnored());
ignoreButton.setValue(true);
panel.add(ignoreButton);
for (final MapExistingAction action : actions) {
final FormField formField = action.getTarget().getFormField();
final String plainLabel = action.getTarget().getLabel();
SafeHtml label = !formField.isRequired() ?
SafeHtmlUtils.fromString(plainLabel) :
TEMPLATE.html(plainLabel);
RadioButton button = createRadioButton(label, action);
panel.add(button);
}
scrollPanel = new ScrollPanel(panel);
initWidget(scrollPanel);
}
public ScrollPanel getScrollPanel() {
return scrollPanel;
}
private RadioButton createRadioButton(SafeHtml label, final ColumnAction action) {
RadioButton button = new RadioButton(group, label);
button.setTabIndex(buttons.size() + 1);
if (action == IgnoreAction.INSTANCE) {
button.addStyleName(ColumnMappingStyles.INSTANCE.stateIgnored());
}
button.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
if (!Objects.equal(action, value)) {
value = action;
ValueChangeEvent.fire(ColumnActionSelector.this, value);
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
updateStyles();
}
});
}
}
});
buttons.put(action, button);
return button;
}
public void setFocus() {
if (ignoreButton.getValue()) {
ignoreButton.setFocus(true);
}
}
@Override
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<ColumnAction> handler) {
return addHandler(handler, ValueChangeEvent.getType());
}
@Override
public ColumnAction getValue() {
return value;
}
@Override
public void setValue(ColumnAction value) {
setValue(value, true);
}
@Override
public void setValue(ColumnAction newValue, boolean fireEvents) {
if (!Objects.equal(this.value, newValue)) {
if (newValue == null) {
// clear the old selection
buttons.get(value).setValue(false);
this.value = newValue;
} else {
this.value = newValue;
// update the UI
RadioButton button = buttons.get(newValue);
assert button != null : "No button for " + newValue;
button.setValue(true);
// update our internal value
buttons.get(newValue).setValue(true);
}
// notify listeners
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
}
public void updateStyles() {
for (Map.Entry<ColumnAction, RadioButton> entry : buttons.entrySet()) {
final ColumnAction columnAction = entry.getKey();
if (columnAction instanceof MapExistingAction) {
final ImportTarget target = ((MapExistingAction) columnAction).getTarget();
final RadioButton button = entry.getValue();
button.removeStyleName(ColumnMappingStyles.INSTANCE.stateBound());
button.removeStyleName(ColumnMappingStyles.INSTANCE.stateUnset());
if (!importModel.getMappedColumns(target.getFormField().getId()).isEmpty()) {
button.addStyleName(ColumnMappingStyles.INSTANCE.stateBound());
} else if (target.getFormField().isRequired()) {
button.addStyleName(ColumnMappingStyles.INSTANCE.stateUnset());
}
}
}
}
public void updateTypeStyles(FieldTypeClass sourceType) {
for (Map.Entry<ColumnAction, RadioButton> entry : buttons.entrySet()) {
final ColumnAction columnAction = entry.getKey();
if (columnAction instanceof MapExistingAction) {
final ImportTarget target = ((MapExistingAction) columnAction).getTarget();
final FieldTypeClass targetType = target.getFormField().getType().getTypeClass();
final RadioButton button = entry.getValue();
button.removeStyleName(ColumnMappingStyles.INSTANCE.typeNotMatched());
button.removeStyleName(ColumnMappingStyles.INSTANCE.typeMatched());
if (targetType == sourceType || (sourceType == FieldTypeClass.FREE_TEXT &&
targetType == FieldTypeClass.REFERENCE)) {
button.addStyleName(ColumnMappingStyles.INSTANCE.typeMatched());
} else {
button.addStyleName(ColumnMappingStyles.INSTANCE.typeNotMatched());
}
}
}
}
}