Java tutorial
/* * Copyright 2016 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package stroom.statistics.client.common.presenter; import com.google.gwt.cell.client.CheckboxCell; import com.google.gwt.cell.client.FieldUpdater; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.cellview.client.Column; import com.google.inject.Inject; import com.google.web.bindery.event.shared.EventBus; import com.google.web.bindery.event.shared.HandlerRegistration; import com.gwtplatform.mvp.client.MyPresenterWidget; import stroom.alert.client.event.ConfirmEvent; import stroom.alert.client.presenter.ConfirmCallback; import stroom.data.grid.client.DataGridView; import stroom.data.grid.client.DataGridViewImpl; import stroom.data.grid.client.EndColumn; import stroom.dispatch.client.AsyncCallbackAdaptor; import stroom.dispatch.client.ClientDispatchAsync; import stroom.entity.client.event.DirtyEvent; import stroom.entity.client.event.DirtyEvent.DirtyHandler; import stroom.entity.client.event.HasDirtyHandlers; import stroom.entity.client.presenter.HasRead; import stroom.entity.client.presenter.HasWrite; import stroom.entity.shared.ResultList; import stroom.statistics.client.common.presenter.StatisticsCustomMaskListPresenter.MaskHolder; import stroom.statistics.shared.CustomRollUpMask; import stroom.statistics.shared.RollUpBitMaskPermGenerationAction; import stroom.statistics.shared.StatisticField; import stroom.statistics.shared.StatisticStoreEntity; import stroom.statistics.shared.StatisticsDataSourceData; import stroom.statistics.shared.StatisticsDataSourceFieldChangeAction; import stroom.widget.button.client.GlyphButtonView; import stroom.widget.button.client.GlyphIcons; import stroom.widget.button.client.ImageButtonView; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; public class StatisticsCustomMaskListPresenter extends MyPresenterWidget<DataGridView<MaskHolder>> implements HasRead<StatisticStoreEntity>, HasWrite<StatisticStoreEntity>, HasDirtyHandlers { public interface Resources extends ClientBundle { ImageResource autoGenerate(); ImageResource autoGenerateDisabled(); } private final GlyphButtonView newButton; private final GlyphButtonView removeButton; private final ImageButtonView autoGenerateButton; private MaskHolder selectedElement; private StatisticStoreEntity statisticsDataSource; private MaskHolderList maskList = new MaskHolderList(); private final List<Column<MaskHolder, ?>> columns = new ArrayList<Column<MaskHolder, ?>>(); private final ClientDispatchAsync dispatcher; @SuppressWarnings("unchecked") @Inject public StatisticsCustomMaskListPresenter(final EventBus eventBus, final Resources resources, final ClientDispatchAsync dispatcher) { super(eventBus, new DataGridViewImpl<MaskHolder>(true, true)); newButton = getView().addButton(GlyphIcons.NEW_ITEM); newButton.setTitle("New roll-up permutation"); autoGenerateButton = getView().addButton("Auto-generate roll-up permutations", resources.autoGenerate(), resources.autoGenerateDisabled(), true); removeButton = getView().addButton(GlyphIcons.REMOVE); removeButton.setTitle("Remove roll-up permutation"); maskList = new MaskHolderList(); this.dispatcher = dispatcher; refreshModel(); } @Override protected void onBind() { super.onBind(); registerHandler(newButton.addClickHandler(event -> { if ((event.getNativeButton() & NativeEvent.BUTTON_LEFT) != 0) { onAdd(event); } })); registerHandler(removeButton.addClickHandler(event -> { if ((event.getNativeButton() & NativeEvent.BUTTON_LEFT) != 0) { onRemove(event); } })); registerHandler(autoGenerateButton.addClickHandler(event -> { if ((event.getNativeButton() & NativeEvent.BUTTON_LEFT) != 0) { onAutoGenerate(event); } })); registerHandler(getView().getSelectionModel().addSelectionHandler(event -> enableButtons())); } private void enableButtons() { autoGenerateButton.setEnabled(true); if (maskList != null && maskList.size() > 0) { selectedElement = getView().getSelectionModel().getSelected(); final boolean enabled = selectedElement != null; removeButton.setEnabled(enabled); } else { removeButton.setEnabled(false); } } private void addColumns() { int fieldPos = 0; for (final StatisticField statisticField : statisticsDataSource.getStatisticFields()) { addStatFieldColumn(fieldPos++, statisticField.getFieldName()); } final EndColumn<MaskHolder> endColumn = new EndColumn<MaskHolder>(); getView().addEndColumn(endColumn); columns.add(endColumn); } private void removeAllColumns() { for (final Column<MaskHolder, ?> column : columns) { getView().removeColumn(column); } } private void addStatFieldColumn(final int fieldPositionNumber, final String fieldname) { // Enabled. final Column<MaskHolder, Boolean> rolledUpColumn = new Column<MaskHolder, Boolean>(new CheckboxCell()) { @Override public Boolean getValue(final MaskHolder row) { return row.getMask().isTagRolledUp(fieldPositionNumber); } }; rolledUpColumn.setFieldUpdater(new FieldUpdater<MaskHolder, Boolean>() { @Override public void update(final int index, final MaskHolder row, final Boolean value) { row.getMask().setRollUpState(fieldPositionNumber, value); DirtyEvent.fire(StatisticsCustomMaskListPresenter.this, true); } }); getView().addResizableColumn(rolledUpColumn, fieldname, 100); columns.add(rolledUpColumn); } private void onAdd(final ClickEvent event) { this.maskList.addMask(new CustomRollUpMask()); // dataProvider.refresh(); refreshModel(); DirtyEvent.fire(StatisticsCustomMaskListPresenter.this, true); } private void onAutoGenerate(final ClickEvent event) { final StatisticsCustomMaskListPresenter thisInstance = this; ConfirmEvent.fire(this, "Are you sure you want to clear the existing roll-ups and generate all possible permutations for the field list?", new ConfirmCallback() { @Override public void onResult(final boolean result) { if (result) { dispatcher.execute( new RollUpBitMaskPermGenerationAction( statisticsDataSource.getStatisticFieldCount()), new AsyncCallbackAdaptor<ResultList<CustomRollUpMask>>() { @Override public void onSuccess(final ResultList<CustomRollUpMask> result) { updateState(new HashSet<CustomRollUpMask>(result.getValues())); DirtyEvent.fire(thisInstance, true); } }); } } }); } private void onRemove(final ClickEvent event) { final List<MaskHolder> list = getView().getSelectionModel().getSelectedItems(); if (maskList != null && list != null && list.size() > 0) { maskList.removeAll(list); getView().getSelectionModel().clear(); // dataProvider.refresh(); refreshModel(); DirtyEvent.fire(StatisticsCustomMaskListPresenter.this, true); } } private void refreshFromEntity(final StatisticStoreEntity statisticsDataSource) { maskList.clear(); maskList.addMasks(statisticsDataSource.getCustomRollUpMasks()); addNoRollUpPerm(); refreshModel(); } private void addNoRollUpPerm() { // add a line with no rollups as a starting point if (statisticsDataSource.getCustomRollUpMasks().size() == 0 && statisticsDataSource.getStatisticFieldCount() > 0) { maskList.addMask(new CustomRollUpMask(Collections.<Integer>emptyList())); } } public void refreshModel() { getView().setRowData(0, maskList); getView().setRowCount(maskList.size(), true); } @Override public void read(final StatisticStoreEntity statisticsDataSource) { // initialise the columns and hold the statDataSource on first time // or if we are passed a different object if (this.statisticsDataSource == null || this.statisticsDataSource != statisticsDataSource) { this.statisticsDataSource = statisticsDataSource; removeAllColumns(); addColumns(); } refreshFromEntity(statisticsDataSource); } @Override public void write(final StatisticStoreEntity entity) { entity.getStatisticDataSourceDataObject() .setCustomRollUpMasks(new HashSet<CustomRollUpMask>(maskList.getMasks())); } @Override public HandlerRegistration addDirtyHandler(final DirtyHandler handler) { return addHandlerToSource(DirtyEvent.getType(), handler); } /** * Call this method to inform this that it needs to update its display based * on state that has changed on another tab * * @param customRollUpMasks The rollup masks as updated by another tab */ public void updateState(final Set<CustomRollUpMask> customRollUpMasks) { maskList.clear(); maskList.addMasks(customRollUpMasks); addNoRollUpPerm(); removeAllColumns(); addColumns(); refreshModel(); } public void reComputeRollUpBitMask(final StatisticsDataSourceData oldStatisticsDataSourceData, final StatisticsDataSourceData newStatisticsDataSourceData) { // grab the mask list from this presenter oldStatisticsDataSourceData.setCustomRollUpMasks(new HashSet<CustomRollUpMask>(maskList.getMasks())); dispatcher.execute( new StatisticsDataSourceFieldChangeAction(oldStatisticsDataSourceData, newStatisticsDataSourceData), new AsyncCallbackAdaptor<StatisticsDataSourceData>() { @Override public void onSuccess(final StatisticsDataSourceData result) { newStatisticsDataSourceData.setCustomRollUpMasks(result.getCustomRollUpMasks()); updateState(result.getCustomRollUpMasks()); } ; }); } /** * Wrap the mask with an ID value that can be used for equality checks in * the UI, to allow multiple rows with the same check box values */ public static class MaskHolder { private final int id; private final CustomRollUpMask mask; public MaskHolder(final int id, final CustomRollUpMask mask) { this.id = id; this.mask = mask; } public int getId() { return id; } public CustomRollUpMask getMask() { return mask; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final MaskHolder other = (MaskHolder) obj; if (id != other.id) return false; return true; } } /** * Extension of ArrayList that adds an ID value to each * {@link CustomRollUpMask} object added to it */ public static class MaskHolderList extends ArrayList<MaskHolder> { private static final long serialVersionUID = 4981870664808232963L; private int idCounter = 0; public boolean addMask(final CustomRollUpMask mask) { final MaskHolder holder = new MaskHolder(idCounter++, mask); return super.add(holder); } public boolean addMasks(final Collection<CustomRollUpMask> masks) { final List<MaskHolder> list = new ArrayList<MaskHolder>(); for (final CustomRollUpMask mask : masks) { final MaskHolder holder = new MaskHolder(idCounter++, mask); list.add(holder); } return super.addAll(list); } public List<CustomRollUpMask> getMasks() { final List<CustomRollUpMask> list = new ArrayList<CustomRollUpMask>(); for (final MaskHolder holder : this) { list.add(holder.getMask()); } return list; } } }