package org.activityinfo.ui.client.component.importDialog.mapping; import com.google.common.collect.Lists; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.logical.shared.AttachEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.EventBus; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SingleSelectionModel; import org.activityinfo.model.form.FormField; import org.activityinfo.core.shared.importing.match.ColumnMappingGuesser; import org.activityinfo.core.shared.importing.model.ColumnAction; import org.activityinfo.core.shared.importing.model.ImportModel; import org.activityinfo.core.shared.importing.model.MapExistingAction; import org.activityinfo.core.shared.importing.source.SourceColumn; import org.activityinfo.core.shared.importing.strategy.ColumnAccessor; import org.activityinfo.core.shared.importing.strategy.ImportTarget; import org.activityinfo.core.shared.importing.strategy.TargetSiteId; import org.activityinfo.i18n.shared.I18N; import org.activityinfo.ui.client.component.importDialog.ImportPage; import org.activityinfo.ui.client.component.importDialog.PageChangedEvent; import org.activityinfo.ui.client.widget.Panel; import java.util.List; import java.util.Map; /** * Page that allows the user to match columns in an imported table to * {@code FormField}s in an existing {@code FormClass} */ public class ColumnMappingPage extends ResizeComposite implements ImportPage { private static ColumnMatchingPanelUiBinder uiBinder = GWT .create(ColumnMatchingPanelUiBinder.class); interface ColumnMatchingPanelUiBinder extends UiBinder<Widget, ColumnMappingPage> { } public static final int LABEL_LIMIT_IN_MESSAGE = 7; @UiField(provided = true) ColumnMappingGrid dataGrid; @UiField(provided = true) ColumnActionSelector actionSelector; @UiField Label fieldSelectorHeading; @UiField Panel fieldSelectorPanel; private final EventBus eventBus; private final ImportModel importModel; private final SingleSelectionModel<SourceColumn> columnSelectionModel; private final List<MapExistingAction> actions; public ColumnMappingPage(ImportModel importModel, List<MapExistingAction> actions, EventBus eventBus) { this.importModel = importModel; this.actions = actions; this.eventBus = eventBus; columnSelectionModel = new SingleSelectionModel<>(); dataGrid = new ColumnMappingGrid(importModel, columnSelectionModel, eventBus); actionSelector = new ColumnActionSelector(actions, importModel, fieldSelectorPanel); initWidget(uiBinder.createAndBindUi(this)); addAttachHandler(new AttachEvent.Handler() { @Override public void onAttachOrDetach(AttachEvent event) { Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { int parentHeight = fieldSelectorPanel.getElement().getClientHeight() - 90; if (parentHeight > 0) { actionSelector.getScrollPanel().setHeight(parentHeight - 90 + "px"); } } }); } }); columnSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { @Override public void onSelectionChange(SelectionChangeEvent event) { onColumnChanged(columnSelectionModel.getSelectedObject()); } }); actionSelector.addValueChangeHandler(new ValueChangeHandler<ColumnAction>() { @Override public void onValueChange(ValueChangeEvent<ColumnAction> event) { updateColumnMapping(event.getValue()); } }); } private void onColumnChanged(SourceColumn column) { fieldSelectorPanel.removeStyleName(ColumnMappingStyles.INSTANCE.incomplete()); fieldSelectorHeading.setText(column.getHeader()); actionSelector.setValue(importModel.getColumnAction(column)); actionSelector.updateTypeStyles(column.getGuessedType()); } private SourceColumn getSelectedColumn() { return columnSelectionModel.getSelectedObject(); } private void updateColumnMapping(ColumnAction action) { final SourceColumn removedColumn = importModel.setColumnBinding(action, getSelectedColumn()); dataGrid.refreshColumnStyles(getSelectedColumn().getIndex()); if (removedColumn != null) { dataGrid.refreshColumnStyles(removedColumn.getIndex()); } fireStateChanged(); } @Override public void onResize() { super.onResize(); } @Override public boolean isValid() { return collectNotMappedMandatoryColumns(true).isEmpty(); } /** * @param mandatory if true - then only mandatory, if false then ALL * @return */ public List<ImportTarget> collectNotMappedMandatoryColumns(boolean mandatory) { List<ImportTarget> list = Lists.newArrayList(); for (final MapExistingAction action : actions) { final FormField formField = action.getTarget().getFormField(); if (mandatory && !formField.isRequired()) { continue; } final Map<TargetSiteId, ColumnAccessor> mappedColumns = importModel.getMappedColumns(formField.getId()); if (mappedColumns.isEmpty()) { list.add(action.getTarget()); } } return list; } @Override public void fireStateChanged() { final List<ImportTarget> importTargets = collectNotMappedMandatoryColumns(true); if (importTargets.isEmpty()) { eventBus.fireEvent(new PageChangedEvent(true, "")); } else { eventBus.fireEvent(new PageChangedEvent(false, I18N.MESSAGES.pleaseMapAllMandatoryColumns(columnLabels(importTargets)))); } } private static String columnLabels(List<ImportTarget> importTargets) { String s = ""; int size = importTargets.size(); if (size > LABEL_LIMIT_IN_MESSAGE) { // restricted to not get very long message size = LABEL_LIMIT_IN_MESSAGE; } for (int i = 0; i < size; i++) { s += importTargets.get(i).getLabel(); if (i < (size - 1)) { s += ", "; } } return s; } @Override public boolean hasNextStep() { return false; } @Override public boolean hasPreviousStep() { return false; } @Override public void start() { ColumnMappingGuesser guesser = new ColumnMappingGuesser(importModel, collectNotMappedMandatoryColumns(false)); guesser.guess(); dataGrid.refresh(); if (columnSelectionModel.getSelectedSet().isEmpty() || columnSelectionModel.getSelectedObject().getIndex() != 0) { columnSelectionModel.setSelected(importModel.getSourceColumn(0), true); } onNextPage(); Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { refreshGuessedColumns(); } }); } private void refreshGuessedColumns() { for (SourceColumn sourceColumn : importModel.getColumnActions().keySet()) { dataGrid.refreshColumnStyles(sourceColumn.getIndex()); } actionSelector.updateStyles(); } @Override public void nextStep() { } private void onNextPage() { actionSelector.setFocus(); } @Override public void previousStep() { } }