# HG changeset patch # User gernotbelger # Date 1530721688 -7200 # Node ID 84397da33d17a74a49376db72942561871efa685 # Parent 83aee0942eae50a1bf1656691b23f0ebea254df3 Allow to control specific behaviour in TwinDatacagePanel Implemented client logic of 'intelligent datacage filtering' for SINFO diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Wed Jul 04 18:28:08 2018 +0200 @@ -143,6 +143,8 @@ String databasket_loading(); + String databasket_empty(); + String theme_top(); String theme_up(); @@ -1550,4 +1552,8 @@ String sinfo_columnlabel_waterlevels(); String error_limit_exceeded_salix(); + + String sinfo_sounding_waterlevel_select_waterlevel(); + + String sinfo_deactivate_intelligent_datacord(); } \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Wed Jul 04 18:28:08 2018 +0200 @@ -57,6 +57,7 @@ scale = Scale databasket = Databasket databasket_loading = Loading Databasket content +databasket_empty = Databasket is empty fix = Fixing fixanalysis = Fixing Analysis next = Next @@ -835,4 +836,6 @@ export_csv_title = Title: sinfo_columnlabel_soundings = Wahl der Peilung -sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels \ No newline at end of file +sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels +sinfo_sounding_waterlevel_select_waterlevel = W\u00e4hlen Sie zuerst eine Peilung +sinfo_deactivate_intelligent_datacord = Intelligente Datenkorbfilterung ausschalten \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Wed Jul 04 18:28:08 2018 +0200 @@ -57,6 +57,7 @@ scale = Skalierung databasket = Datenkorb databasket_loading=Lade Datenkorb Inhalt +databasket_empty = Datenkorb Inhalt ist leer fix = Fixierungsanalyse fixanalysis = Fixierungsanalyse next = Weiter @@ -835,4 +836,6 @@ export_csv_title = Titel: sinfo_columnlabel_soundings = Wahl der Peilung -sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels \ No newline at end of file +sinfo_columnlabel_waterlevels = Wahl des Wasserspiegels +sinfo_sounding_waterlevel_select_waterlevel = W\u00e4hlen Sie zuerst eine Peilung +sinfo_deactivate_intelligent_datacord = Intelligente Datenkorbfilterung ausschalten \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java Wed Jul 04 18:28:08 2018 +0200 @@ -52,39 +52,36 @@ public abstract class AbstractPairRecommendationPanel extends TextProvider { - /** - * Allows for abstraction on how to handle/serialize the recommendation and the used factories. - * Basically this allows to tweak the factory that is delivered from the datacage to be replaced by a specific one... - * - * @author Gernot Belger - */ - public static interface IRecommendationInfo { - - String getFactory(String originalFactory); + /** + * Allows for abstraction on how to handle/serialize the recommendation and the used factories. + * Basically this allows to tweak the factory that is delivered from the datacage to be replaced by a specific one... + * + * @author Gernot Belger + */ + public static interface IRecommendationInfo { - /** - * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there. - * @param recommendation - */ - String getDataStringFactory(Recommendation recommendation); + String getFactory(String originalFactory); - /** - * Set factory of recommendation such that the correct artifacts will - * be cloned for difference calculations. - */ - void adjustRecommendation(Recommendation recommendation); - } - - public static interface IValidator - { - List validate(ListGrid differencesList, FLYSConstants msgProvider); - } + /** + * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there. + * @param recommendation + */ + String getDataStringFactory(Recommendation recommendation); + + /** + * Set factory of recommendation such that the correct artifacts will + * be cloned for difference calculations. + */ + void adjustRecommendation(Recommendation recommendation); + } + + public static interface IValidator + { + List validate(ListGrid differencesList, FLYSConstants msgProvider); + } private static final long serialVersionUID = 8906629596491827857L; - // FIXME: why? we hide the field of the super class with exactly the same thing... - private static FLYSConstants MSG_PROVIDER = GWT.create(FLYSConstants.class); - private String dataName; private final User user; @@ -97,7 +94,7 @@ * be able to identify artifacts that can be removed from the collection. */ private final List removedPairs = - new ArrayList(); + new ArrayList(); /** Service handle to clone and add artifacts to collection. */ private final LoadArtifactServiceAsync loadArtifactService = GWT.create( @@ -107,28 +104,28 @@ private final RemoveArtifactServiceAsync removeArtifactService = GWT.create( org.dive4elements.river.client.client.services.RemoveArtifactService.class); - private final IRecommendationInfo leftInfo; - - private final IRecommendationInfo rightInfo; + private final IRecommendationInfo leftInfo; - private final IValidator validator; + private final IRecommendationInfo rightInfo; - /** - * @param Validates the content of this form when the user clicks 'apply' - * @param leftInfo Delegate for handling the left part of the recommendation-pair - * @param rightInfo Delegate for handling the right part of the recommendation-pair - */ + private final IValidator validator; + + /** + * @param Validates the content of this form when the user clicks 'apply' + * @param leftInfo Delegate for handling the left part of the recommendation-pair + * @param rightInfo Delegate for handling the right part of the recommendation-pair + */ public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) { this.user = user; - this.validator = validator; - this.leftInfo = leftInfo; - this.rightInfo = rightInfo; + this.validator = validator; + this.leftInfo = leftInfo; + this.rightInfo = rightInfo; } - + // FIXME: better than copy/pasting the MSG field into every sub-class but not really nice yet. protected final static FLYSConstants msg() { - return MSG_PROVIDER; - } + return MSG; + } /** * Remove first occurrence of "[" and "]" (if both do occur). @@ -155,7 +152,7 @@ /** * Create a recommendation from a string representation of it. * @param from string in format as shown above. - * @param leftInfo2 + * @param leftInfo2 * @return recommendation from input string. */ private Recommendation createRecommendationFromString(final String from, final IRecommendationInfo info) { @@ -169,7 +166,7 @@ final List facets = new ArrayList(); facets.add(facet); filter.add("longitudinal_section", facets); - + final String factory = info.getFactory( parts[1] ); final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter); @@ -188,12 +185,12 @@ if (recs.length % 2 != 0) return; for (int i = 0; i < recs.length; i+=2) { final Recommendation minuend = - createRecommendationFromString(recs[i+0], this.leftInfo); + createRecommendationFromString(recs[i+0], this.leftInfo); final Recommendation subtrahend = - createRecommendationFromString(recs[i+1], this.rightInfo); + createRecommendationFromString(recs[i+1], this.rightInfo); final RecommendationPairRecord pr = new RecommendationPairRecord( - minuend, subtrahend); + minuend, subtrahend); // This Recommendation Pair comes from the data string and was thus // already cloned. pr.setIsAlreadyLoaded(true); @@ -208,13 +205,13 @@ */ @Override public final Canvas create(final DataList dataList) { - + final Canvas widget = createWidget(); - - final Canvas canvas = createChooserWidgets(widget, dataList, this.user, this.differencesList); - + + final Canvas canvas = createChooserWidgets(widget, dataList, this.user, this.differencesList); + populateGrid(dataList); - + return canvas; } @@ -223,14 +220,14 @@ */ protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList); - private void populateGrid(final DataList dataList) { + private void populateGrid(final DataList dataList) { final Data data = dataList.get(0); this.dataName = data.getLabel(); for (int i = 0; i < dataList.size(); i++) { if (dataList.get(i) != null && dataList.get(i).getItems() != null) { if (dataList.get(i).getItems() != null) { populateGridFromString( - dataList.get(i).getItems()[0].getStringValue()); + dataList.get(i).getItems()[0].getStringValue()); } } } @@ -238,7 +235,7 @@ @Override public final List validate() { - return this.validator.validate(this.differencesList, MSG_PROVIDER); + return this.validator.validate(this.differencesList, msg()); } /** @@ -259,34 +256,34 @@ // Track removed rows, therefore more or less reimplement // setCanRecomeRecords. final ListGridField removeField = - new ListGridField("_removeRecord", "Remove Record"){{ - setType(ListGridFieldType.ICON); - setIcon(GWT.getHostPageBaseURL() + msg().removeFeature()); - setCanEdit(false); - setCanFilter(false); - setCanSort(false); - setCanGroupBy(false); - setCanFreeze(false); - setWidth(25); - }}; - - this.differencesList.setFields(new ListGridField[] {nameField, - capitalField, removeField}); + new ListGridField("_removeRecord", "Remove Record"){{ + setType(ListGridFieldType.ICON); + setIcon(GWT.getHostPageBaseURL() + msg().removeFeature()); + setCanEdit(false); + setCanFilter(false); + setCanSort(false); + setCanGroupBy(false); + setCanFreeze(false); + setWidth(25); + }}; - this.differencesList.addRecordClickHandler(new RecordClickHandler() { - @Override - public void onRecordClick(final RecordClickEvent event) { - // Just handle remove-clicks - if(!event.getField().getName().equals(removeField.getName())) { - return; + this.differencesList.setFields(new ListGridField[] {nameField, + capitalField, removeField}); + + this.differencesList.addRecordClickHandler(new RecordClickHandler() { + @Override + public void onRecordClick(final RecordClickEvent event) { + // Just handle remove-clicks + if(!event.getField().getName().equals(removeField.getName())) { + return; + } + trackRemoved(event.getRecord()); + event.getViewer().removeData(event.getRecord()); } - trackRemoved(event.getRecord()); - event.getViewer().removeData(event.getRecord()); - } - }); - layout.addMember(this.differencesList); + }); + layout.addMember(this.differencesList); - return layout; + return layout; } @@ -322,7 +319,7 @@ for (final ListGridRecord record : records) { final RecommendationPairRecord r = - (RecommendationPairRecord) record; + (RecommendationPairRecord) record; // Do not add "old" recommendations. if (!r.isAlreadyLoaded()) { // Check whether one of those is a dike or similar. @@ -374,47 +371,47 @@ // feedback. for(final String uuid: artifactIdsToRemove) { this.removeArtifactService.remove(this.collection, - uuid, - locale, - new AsyncCallback() { - @Override - public void onFailure(final Throwable caught) { - GWT.log("RemoveArtifact (" + uuid + ") failed."); - } - @Override - public void onSuccess(final Collection coll) { - GWT.log("RemoveArtifact succeeded"); - } - }); + uuid, + locale, + new AsyncCallback() { + @Override + public void onFailure(final Throwable caught) { + GWT.log("RemoveArtifact (" + uuid + ") failed."); + } + @Override + public void onSuccess(final Collection coll) { + GWT.log("RemoveArtifact succeeded"); + } + }); } // Clone new ones (and spawn statics), go forward. this.parameterList.lockUI(); this.loadArtifactService.loadMany( - this.collection, - toClone, - //"staticwkms" and "waterlevel" - null, - locale, - new AsyncCallback() { - @Override - public void onFailure(final Throwable caught) { - caught.printStackTrace(); - GWT.log("Failure of cloning with factories!"); - AbstractPairRecommendationPanel.this.parameterList.unlockUI(); - } - @Override - public void onSuccess(final Artifact[] artifacts) { - GWT.log("Successfully cloned " + toClone.length + - " with factories."); + this.collection, + toClone, + //"staticwkms" and "waterlevel" + null, + locale, + new AsyncCallback() { + @Override + public void onFailure(final Throwable caught) { + caught.printStackTrace(); + GWT.log("Failure of cloning with factories!"); + AbstractPairRecommendationPanel.this.parameterList.unlockUI(); + } + @Override + public void onSuccess(final Artifact[] artifacts) { + GWT.log("Successfully cloned " + toClone.length + + " with factories."); - fireStepForwardEvent(new StepForwardEvent( - getData(toClone, artifacts, toUse))); - AbstractPairRecommendationPanel.this.parameterList.unlockUI(); - } - }); + fireStepForwardEvent(new StepForwardEvent( + getData(toClone, artifacts, toUse))); + AbstractPairRecommendationPanel.this.parameterList.unlockUI(); + } + }); } - + /** * Create Data and DataItem from selection (a long string with identifiers * to construct diff-pairs). @@ -440,21 +437,21 @@ final String uuid = newArtifact.getUuid(); r.setMasterArtifact(uuid); - if (i>0) - dataItemString += "#"; + if (i>0) + dataItemString += "#"; // REMARK: ugly, but we know that the recommandations comes in left/right pairs. final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; - + dataItemString += createDataString(uuid, r, info); } for (int i = 0; i < oldRecommendations.length; i++) { final Recommendation r = oldRecommendations[i]; final String uuid = r.getIDs(); - - if (dataItemString.length() > 0) - dataItemString += "#"; + + if (dataItemString.length() > 0) + dataItemString += "#"; // REMARK: ugly, but we know that the recommandations comes in left/right pairs. final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; @@ -466,7 +463,7 @@ // (e.g. one per pair). final DataItem item = new DefaultDataItem(this.dataName, this.dataName, dataItemString); return new Data[] { new DefaultData( - this.dataName, null, null, new DataItem[] {item}) }; + this.dataName, null, null, new DataItem[] {item}) }; } /** @@ -475,35 +472,35 @@ * @param info Provides the factory to encode. */ protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) { - final String factory = info.getDataStringFactory( recommendation ); - - final Filter filter = recommendation.getFilter(); - Facet f = null; - - if(filter != null) { - final Map> outs = filter.getOuts(); - final Set>> entries = outs.entrySet(); - - for (final Map.Entry> entry: entries) { - final List fs = entry.getValue(); - - f = fs.get(0); - if (f != null) { - break; - } - } - - return "[" + artifactUuid + ";" - + f.getName() - + ";" - + f.getIndex() - + ";" - + recommendation.getDisplayName() + "]"; - } - - return "[" - + artifactUuid - + ";" + factory + ";0;" - + recommendation.getDisplayName() + "]"; + final String factory = info.getDataStringFactory( recommendation ); + + final Filter filter = recommendation.getFilter(); + Facet f = null; + + if(filter != null) { + final Map> outs = filter.getOuts(); + final Set>> entries = outs.entrySet(); + + for (final Map.Entry> entry: entries) { + final List fs = entry.getValue(); + + f = fs.get(0); + if (f != null) { + break; + } + } + + return "[" + artifactUuid + ";" + + f.getName() + + ";" + + f.getIndex() + + ";" + + recommendation.getDisplayName() + "]"; + } + + return "[" + + artifactUuid + + ";" + factory + ";0;" + + recommendation.getDisplayName() + "]"; } } \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java Wed Jul 04 18:28:08 2018 +0200 @@ -25,8 +25,26 @@ * Insert a record into a listgrid when add-this-button clicked. */ public class DatacagePairWidget extends VLayout { + + /** + * Allows for advanced controlling of the behavior of this pair widget. + */ + public static interface IDatacagePairControler { + void setup(DatacageWidget leftWidget, DatacageWidget rightWidget, HLayout toolbarLayout); + } + + /** + * {@link IDatacagePairControler} implementation that does nothing. + */ + public static final IDatacagePairControler NIL_CONTROLER = new IDatacagePairControler() { + @Override + public void setup(final DatacageWidget leftWidget, final DatacageWidget rightWidget, final HLayout toolbarLayout) { + // does nothing + } + }; + /** i18n resource. */ - private final FLYSConstants MSG = GWT.create(FLYSConstants.class); + private static final FLYSConstants MSG = GWT.create(FLYSConstants.class); /** The "remote" ListGrid to insert data to when add-button is clicked. */ private final ListGrid grid; @@ -43,8 +61,9 @@ /** errorMsg maxCount */ private final String msgMaxCount; - public DatacagePairWidget(final DatacageWidgetData leftData, final DatacageWidgetData rightData, final ListGrid grid, final int maxCount, - final String msgMaxCount) { + public DatacagePairWidget(final IDatacagePairControler controler, final DatacageWidgetData leftData, final DatacageWidgetData rightData, + final ListGrid grid, final int maxCount, final String msgMaxCount) { + this.msgMaxCount = msgMaxCount; this.maxCount = maxCount; this.grid = grid; @@ -60,7 +79,10 @@ hLayout.addMember(this.firstDatacageWidget); hLayout.addMember(this.secondDatacageWidget); - final Button plusBtn = new Button(this.MSG.datacage_add_pair()); + final HLayout toolbarLayout = new HLayout(); + toolbarLayout.setAutoHeight(); + + final Button plusBtn = new Button(MSG.datacage_add_pair()); plusBtn.setAutoFit(true); plusBtn.addClickHandler(new ClickHandler() { @Override @@ -68,23 +90,26 @@ plusClicked(); } }); + toolbarLayout.addMember(plusBtn); addMember(hLayout); - addMember(plusBtn); + addMember(toolbarLayout); + + controler.setup(this.firstDatacageWidget, this.secondDatacageWidget, toolbarLayout); } /** * Callback for add-button. * Fires to load for every selected element and handler. */ - public void plusClicked() { + protected final void plusClicked() { final ToLoad toLoad1 = this.firstDatacageWidget.getSelection(); final ToLoad toLoad2 = this.secondDatacageWidget.getSelection(); // FIXME: allows to select folders... but it should not if (toLoad1 == null || toLoad2 == null || toLoad1.toRecommendations().isEmpty() || toLoad2.toRecommendations().isEmpty()) { - SC.say(this.MSG.warning_select_two_values()); + SC.say(MSG.warning_select_two_values()); return; } diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Wed Jul 04 18:28:08 2018 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.client.client.ui; +import org.dive4elements.river.client.client.ui.DatacagePairWidget.IDatacagePairControler; import org.dive4elements.river.client.shared.model.DataList; import org.dive4elements.river.client.shared.model.User; @@ -24,22 +25,28 @@ */ public abstract class DatacageTwinPanel extends AbstractPairRecommendationPanel { + private static final long serialVersionUID = 1L; + private final IDatacageTwinPanelInfo leftInfo; private final IDatacageTwinPanelInfo rightInfo; private final int maxCount; private final String msgMaxCount; + private final IDatacagePairControler controler; + public static interface IDatacageTwinPanelInfo extends IRecommendationInfo { String getOuts(); String getColumnLabel(); } - public DatacageTwinPanel(final User user, final IValidator validator, final IDatacageTwinPanelInfo leftInfo, final IDatacageTwinPanelInfo rightInfo, + public DatacageTwinPanel(final User user, final IValidator validator, final IDatacagePairControler controler, final IDatacageTwinPanelInfo leftInfo, + final IDatacageTwinPanelInfo rightInfo, final int maxCount, final String msgMaxCount) { super(user, validator, leftInfo, rightInfo); + this.controler = controler; this.maxCount = maxCount; this.msgMaxCount = msgMaxCount; this.leftInfo = leftInfo; @@ -63,7 +70,7 @@ final String rightLabel = this.rightInfo.getColumnLabel(); final DatacageWidgetData rightData = new DatacageWidgetData(this.artifact, user, rightOuts, "load-system:true", false, rightLabel); - helperLayout.addMember(new DatacagePairWidget(leftData, rightData, differencesList, this.maxCount, this.msgMaxCount)); + helperLayout.addMember(new DatacagePairWidget(this.controler, leftData, rightData, differencesList, this.maxCount, this.msgMaxCount)); if (dataList != null && dataList.get(0) != null && dataList.get(0).getDescription() != null) { final Label title = new Label(dataList.get(0).getDescription()); diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageWidget.java Wed Jul 04 18:28:08 2018 +0200 @@ -48,7 +48,10 @@ * Display tree of, for example, previous calculations and allows * selection in order to access/clone these. */ -public class DatacageWidget extends VLayout { +public final class DatacageWidget extends VLayout { + + private static final FLYSConstants MSG = GWT.create(FLYSConstants.class); + public static final int MAX_OPEN = 30; public interface DatacageFilter { @@ -62,10 +65,15 @@ } }; + public static final DatacageFilter ACCEPT_NONE_FILTER = new DatacageFilter() { + @Override + public boolean accept(final DataCageNode node) { + return false; + } + }; + private final MetaDataServiceAsync metaDataService = GWT.create(MetaDataService.class); - private final FLYSConstants messages = GWT.create(FLYSConstants.class); - private final List handlers = new ArrayList(); private final List doubleHandlers = new ArrayList(); @@ -105,11 +113,9 @@ this.treeGrid.setShowRoot(false); this.treeGrid.setNodeIcon("[SKIN]/../blank.gif"); this.treeGrid.setShowConnectors(true); - this.treeGrid.setLoadingMessage(this.messages.databasket_loading()); - this.treeGrid.setLoadingDataMessage(this.messages.databasket_loading()); - - // FIXME: other message - this.treeGrid.setEmptyMessage(this.messages.databasket_loading()); + this.treeGrid.setLoadingMessage(MSG.databasket_loading()); + this.treeGrid.setLoadingDataMessage(MSG.databasket_loading()); + this.treeGrid.setEmptyMessage(MSG.databasket_empty()); this.treeGrid.setHoverMoveWithMouse(true); this.treeGrid.setCanHover(true); @@ -157,6 +163,10 @@ updateTree(this.dcTree); } + public TreeGrid getTreeGrid() { + return this.treeGrid; + } + /** Disable input, show spinning wheel of joy. */ private void lockUI() { this.lockScreen = ScreenLock.lockUI(this, this.lockScreen); @@ -211,11 +221,13 @@ public ToLoad getSelection() { // Reset content of toLoads. + + // FIXME: bad... instead we should react to selection events and update toLoad in this way. + this.toLoad = new ToLoad(); - if (this.treeGrid == null) { + if (this.treeGrid == null) return this.toLoad; - } final ListGridRecord[] selection = this.treeGrid.getSelectedRecords(); @@ -278,7 +290,7 @@ } private Button createPlusButton() { - final Button plusBtn = new Button(this.messages.datacageAdd()); + final Button plusBtn = new Button(MSG.datacageAdd()); plusBtn.addClickHandler(new ClickHandler() { @Override public void onClick(final ClickEvent event) { @@ -312,13 +324,13 @@ * Afterwards, add all children of node to stack to parse (next time * collectToLoads is called). */ - private void collectToLoads(TreeNode node) { + private void collectToLoads(final TreeNode root1) { final Stack stack = new Stack(); - stack.push(node); + stack.push(root1); while (!stack.isEmpty()) { - node = stack.pop(); + final TreeNode node = stack.pop(); final String factory = node.getAttribute("factory"); if (factory != null) { // we need at least a factory final String artifact = node.getAttribute("artifact-id"); @@ -384,7 +396,7 @@ updateTree(this.dcTree); } - private void updateTree(final DataCageTree data) { + private void updateTree(final DataCageTree dcData) { this.tree = new Tree(); this.tree.setModelType(TreeModelType.CHILDREN); @@ -394,7 +406,7 @@ this.tree.setShowRoot(false); final IdGenerator idGenerator = new IdGenerator(); - final DataCageNode dcRoot = data.getRoot(); + final DataCageNode dcRoot = dcData.getRoot(); final TreeNode root = buildRecursiveChildren(dcRoot, idGenerator); if (root != null) { this.tree.setRoot(root); @@ -428,19 +440,18 @@ } } // class IdGenerator - private String i18n(String s) { - if (!(s.startsWith("${") && s.endsWith("}"))) { + private String i18n(final String s) { + if (!(s.startsWith("${") && s.endsWith("}"))) return s; - } - s = s.substring(2, s.length() - 1); + final String sub = s.substring(2, s.length() - 1); try { - return this.messages.getString(s); + return MSG.getString(sub); } catch (final MissingResourceException mre) { - GWT.log("cannot find i18n for + '" + s + "'"); - return s; + GWT.log("cannot find i18n for + '" + sub + "'", mre); + return sub; } } diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java Wed Jul 04 18:28:08 2018 +0200 @@ -18,8 +18,10 @@ */ public class WaterlevelTwinPanel extends DatacageTwinPanel { + private static final long serialVersionUID = 1L; + public WaterlevelTwinPanel(final User user) { - super(user, new WaterlevelTwinPanelValidator(), new WaterlevelRecommendationInfo("winfo_diff_twin_panel"), + super(user, new WaterlevelTwinPanelValidator(), DatacagePairWidget.NIL_CONTROLER, new WaterlevelRecommendationInfo("winfo_diff_twin_panel"), new WaterlevelRecommendationInfo("winfo_diff_twin_panel"), 9999, ""); } } \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthMinMaxTwinPanel.java Wed Jul 04 18:28:08 2018 +0200 @@ -27,6 +27,6 @@ private static final NilDatacageTwinPanelInfo RIGHT_INFO = new NilDatacageTwinPanelInfo(MSG.sinfo_columnlabel_waterlevels(), "sinfo_flowdepth_waterlevels"); public FlowDepthMinMaxTwinPanel(final User user) { - super(user, new FlowDepthTwinPanelValidator(), LEFT_INFO, RIGHT_INFO, 9999, ""); + super(user, new FlowDepthTwinPanelValidator(), new WaterlevelSoundingSelectionController(MSG), LEFT_INFO, RIGHT_INFO, 9999, ""); } } \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java Wed Jul 04 18:28:08 2018 +0200 @@ -27,6 +27,6 @@ private static final NilDatacageTwinPanelInfo RIGHT_INFO = new NilDatacageTwinPanelInfo(MSG.sinfo_columnlabel_waterlevels(), "sinfo_flowdepth_waterlevels"); public FlowDepthTwinPanel(final User user, final int maxCount, final String msgMaxCount) { - super(user, new FlowDepthTwinPanelValidator(), LEFT_INFO, RIGHT_INFO, maxCount, msgMaxCount); + super(user, new FlowDepthTwinPanelValidator(), new WaterlevelSoundingSelectionController(MSG), LEFT_INFO, RIGHT_INFO, maxCount, msgMaxCount); } } \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/WaterlevelSoundingSelectionController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/WaterlevelSoundingSelectionController.java Wed Jul 04 18:28:08 2018 +0200 @@ -0,0 +1,143 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui.sinfo; + +import java.util.List; + +import org.dive4elements.river.client.client.FLYSConstants; +import org.dive4elements.river.client.client.ui.DatacagePairWidget.IDatacagePairControler; +import org.dive4elements.river.client.client.ui.DatacageWidget; + +import com.smartgwt.client.data.DataSource; +import com.smartgwt.client.data.DataSourceField; +import com.smartgwt.client.types.Alignment; +import com.smartgwt.client.types.FieldType; +import com.smartgwt.client.types.TitleOrientation; +import com.smartgwt.client.widgets.form.DynamicForm; +import com.smartgwt.client.widgets.form.events.ItemChangedEvent; +import com.smartgwt.client.widgets.form.events.ItemChangedHandler; +import com.smartgwt.client.widgets.grid.events.SelectionUpdatedEvent; +import com.smartgwt.client.widgets.grid.events.SelectionUpdatedHandler; +import com.smartgwt.client.widgets.layout.HLayout; +import com.smartgwt.client.widgets.tree.TreeNode; + +/** + * Implements special behavior when selecting soundings and waterlevels: datacage of waterlevels depends on selection of + * sounding. + * + * @author Gernot Belger + */ +final class WaterlevelSoundingSelectionController implements IDatacagePairControler { + + private static final String FIELD_INTELLIGENCE = "field_intelligence"; + + static final String ATTRIBUTE_YEAR = "year"; + + private final FLYSConstants msg; + + private boolean turnFilterOff; + + public WaterlevelSoundingSelectionController(final FLYSConstants msg) { + this.msg = msg; + } + + @Override + public void setup(final DatacageWidget soundingWidget, final DatacageWidget waterlevelWidget, final HLayout toolbarLayout) { + + soundingWidget.getTreeGrid().addSelectionUpdatedHandler(new SelectionUpdatedHandler() { + + @Override + public void onSelectionUpdated(final SelectionUpdatedEvent event) { + final List selection = soundingWidget.getPlainSelection(); + handleSoundingChanged(waterlevelWidget, selection); + } + }); + + final DynamicForm form = createIntelligenCheckbox(); + toolbarLayout.addMember(form); + form.addItemChangedHandler(new ItemChangedHandler() { + + @Override + public void onItemChanged(final ItemChangedEvent event) { + final Boolean value = (Boolean) form.getValue(FIELD_INTELLIGENCE); + checkboxToggled(value); + handleSoundingChanged(waterlevelWidget, soundingWidget.getPlainSelection()); + } + }); + + /* init to current selection */ + handleSoundingChanged(waterlevelWidget, soundingWidget.getPlainSelection()); + } + + private DynamicForm createIntelligenCheckbox() { + + final DynamicForm form = new DynamicForm(); + form.setTitlePrefix(""); + form.setTitleSuffix(": "); + form.setTitleAlign(Alignment.LEFT); + form.setTitleOrientation(TitleOrientation.LEFT); + + final DataSourceField item = new DataSourceField(FIELD_INTELLIGENCE, FieldType.BOOLEAN); + item.setTitle(this.msg.sinfo_deactivate_intelligent_datacord()); + + final DataSource source = new DataSource(); + source.setFields(item); + form.setDataSource(source); + + form.setValue(FIELD_INTELLIGENCE, false); + + return form; + } + + protected final void checkboxToggled(final Boolean selected) { + this.turnFilterOff = selected == null ? false : selected; + } + + protected final void handleSoundingChanged(final DatacageWidget waterlevelWidget, final List selection) { + + if (this.turnFilterOff) { + waterlevelWidget.setFilter(DatacageWidget.ACCEPT_ALL_FILTER); + waterlevelWidget.getTreeGrid().setEmptyMessage(this.msg.databasket_loading()); + return; + } + + // more than one should never happen, as the have single selection + final TreeNode soundingNode = selection.isEmpty() ? null : selection.get(0); + + if (soundingNode == null || soundingNode.getAttribute("factory") == null) { + waterlevelWidget.setFilter(DatacageWidget.ACCEPT_NONE_FILTER); + waterlevelWidget.getTreeGrid().setEmptyMessage(this.msg.sinfo_sounding_waterlevel_select_waterlevel()); + return; + } + + final Integer soundingYear = getYear(soundingNode); + + if (soundingYear == null) { + // should never happen, as we should only show soundings that actually have a year + waterlevelWidget.setFilter(DatacageWidget.ACCEPT_NONE_FILTER); + waterlevelWidget.getTreeGrid().setEmptyMessage("Der gewählte Wassrspiegel hat keine Informations zum Jahr"); + } else + waterlevelWidget.setFilter(new WaterlevelSoundingYearFilter(soundingYear)); + } + + private static Integer getYear(final TreeNode soundingNode) { + final String year = soundingNode.getAttribute(ATTRIBUTE_YEAR); + if (year == null || year.trim().isEmpty()) + return null; + + try { + return Integer.valueOf(year); + } + catch (final NumberFormatException e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/WaterlevelSoundingYearFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/WaterlevelSoundingYearFilter.java Wed Jul 04 18:28:08 2018 +0200 @@ -0,0 +1,77 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui.sinfo; + +import org.dive4elements.river.client.client.ui.DatacageWidget.DatacageFilter; +import org.dive4elements.river.client.shared.model.AttrList; +import org.dive4elements.river.client.shared.model.DataCageNode; + +/** + * @author Gernot Belger + */ +final class WaterlevelSoundingYearFilter implements DatacageFilter { + + private final int soundingYear; + + public WaterlevelSoundingYearFilter(final int soundingYear) { + this.soundingYear = soundingYear; + } + + @Override + public boolean accept(final DataCageNode node) { + + final AttrList attributes = node.getAttributes(); + if (attributes == null) + return true; + + if (!attributes.hasAttribute("factory")) + return true; + + final Integer waterlevelYear = getYear(attributes); + if (waterlevelYear == null) { + // should never happen, we should only show waterlevels that have a year + return false; + } + + final int diff = Math.abs(this.soundingYear - waterlevelYear); + + return diff <= getMaxYearDifference(); + } + + private int getMaxYearDifference() { + + if (this.soundingYear < 1918) + return 25; + + if (1918 <= this.soundingYear && this.soundingYear < 1958) + return 12; + + if (1958 <= this.soundingYear && this.soundingYear < 1998) + return 6; + + // > 1998 + return 3; + } + + private static Integer getYear(final AttrList attributes) { + + final String year = attributes.getValue(WaterlevelSoundingSelectionController.ATTRIBUTE_YEAR); + if (year == null || year.trim().isEmpty()) + return null; + + try { + return Integer.valueOf(year); + } + catch (final NumberFormatException e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/shared/model/AttrList.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/AttrList.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/AttrList.java Wed Jul 04 18:28:08 2018 +0200 @@ -8,47 +8,64 @@ package org.dive4elements.river.client.shared.model; -import java.util.List; +import java.io.Serializable; import java.util.ArrayList; +import java.util.List; -import java.io.Serializable; - +// FIXME: who implements a thing like this?? this is a HashMap!! public class AttrList implements Serializable { - protected List keyValues; + private static final long serialVersionUID = 1L; + + private List keyValues; public AttrList() { this(5); } - public AttrList(int size) { - keyValues = new ArrayList(size*2); + public AttrList(final int size) { + this.keyValues = new ArrayList(size*2); } public int size() { - return keyValues != null ? keyValues.size()/2 : null; - } - - public String getKey(int index) { - return keyValues.get(index*2); + return this.keyValues.size() / 2; } - public String getValue(int index) { - return keyValues.get(index*2 + 1); + /** + * IMPORTANT: necessary for serialization + */ + public void setKeyValues(final List keyValues) { + this.keyValues = keyValues; } - public void add(String key, String value) { - keyValues.add(key); - keyValues.add(value); + public String getKey(final int index) { + return this.keyValues.get(index*2); } - public boolean hasAttribute(String key) { - for (int i = 0, N = keyValues.size(); i < N; i += 2) { - if (keyValues.get(i).equals(key)) { + public String getValue(final int index) { + return this.keyValues.get(index*2 + 1); + } + + public String getValue(final String key) { + for (int i = 0, N = this.keyValues.size(); i < N; i += 2) { + if (this.keyValues.get(i).equals(key)) { + return this.keyValues.get(i + 1); + } + } + return null; + } + + public void add(final String key, final String value) { + this.keyValues.add(key); + this.keyValues.add(value); + } + + public boolean hasAttribute(final String key) { + for (int i = 0, N = this.keyValues.size(); i < N; i += 2) { + if (this.keyValues.get(i).equals(key)) { return true; } } return false; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java Wed Jul 04 18:28:08 2018 +0200 @@ -8,52 +8,46 @@ package org.dive4elements.river.client.shared.model; +import java.io.Serializable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; - -import java.io.Serializable; import com.google.gwt.core.client.GWT; public class ToLoad implements Serializable { - - /** Two strings. */ - public static class StringTriple { + private static class StringTriple { public String first; public String second; public String third; - public StringTriple(String first, String second, String third) { + public StringTriple(final String first, final String second, final String third) { this.first = first; this.second = second; this.third = third; } @Override public int hashCode() { - return first.hashCode() + second.hashCode() + third.hashCode(); + return this.first.hashCode() + this.second.hashCode() + this.third.hashCode(); } @Override - public boolean equals(Object o) { + public boolean equals(final Object o) { if (!(o instanceof StringTriple)) { return false; } - StringTriple other = (StringTriple) o; - return second.equals(other.second) - && first.equals(other.first) - && third.equals(other.third); + final StringTriple other = (StringTriple) o; + return this.second.equals(other.second) + && this.first.equals(other.first) + && this.third.equals(other.third); } } - public static final String SYNTHETIC_KEY = "key-"; - - protected Map> artifacts; - public ToLoad() { - artifacts = new HashMap>(); - } + private static final String SYNTHETIC_KEY = "key-"; - public static final String uniqueKey(Map map) { + private final Map> artifacts = new HashMap>(); + + public static final String uniqueKey(final Map map) { int idx = map.size(); String key = SYNTHETIC_KEY + idx; @@ -64,39 +58,39 @@ } public void add( - String artifactName, - String factory, - String out, - String name, - String ids, - String displayName - ) { + final String artifactName, + final String factory, + final String out, + final String name, + final String ids, + final String displayName + ) { add(artifactName, factory, out, name, ids, displayName, null); - } + } public void add( - String artifactName, - String factory, - String out, - String name, - String ids, - String displayName, - String targetOut - ) { + String artifactName, + final String factory, + final String out, + final String name, + final String ids, + final String displayName, + final String targetOut + ) { GWT.log("Adding artifact: " + artifactName + " Factory: " + factory + " Out: " + out + " Name: " + name + " Ids: " + ids + " Display Name: " + displayName + " Target Out: " + targetOut); if (artifactName == null) { - artifactName = uniqueKey(artifacts); + artifactName = uniqueKey(this.artifacts); } - Map artifact = artifacts.get( - artifactName); + Map artifact = this.artifacts.get( + artifactName); if (artifact == null) { artifact = new HashMap(); - artifacts.put(artifactName, artifact); + this.artifacts.put(artifactName, artifact); } ArtifactFilter filter = artifact.get(factory); @@ -110,28 +104,28 @@ } public boolean isEmpty() { - return artifacts.isEmpty(); + return this.artifacts.isEmpty(); } public List toRecommendations() { - List recommendations = new ArrayList(); + final List recommendations = new ArrayList(); - for (Map.Entry> all: - artifacts.entrySet() - ) { + for (final Map.Entry> all: + this.artifacts.entrySet() + ) { String masterArtifact = all.getKey(); if (masterArtifact.startsWith(SYNTHETIC_KEY)) { // system data masterArtifact = null; } - for (Map.Entry entry: + for (final Map.Entry entry: all.getValue().entrySet() - ) { - StringTriple triple = entry.getKey(); - String factory = triple.first; - String targetOut = triple.third; - ArtifactFilter artifactFilter = entry.getValue(); + ) { + final StringTriple triple = entry.getKey(); + final String factory = triple.first; + final String targetOut = triple.third; + final ArtifactFilter artifactFilter = entry.getValue(); String ids; Recommendation.Filter filter; @@ -145,8 +139,8 @@ filter = artifactFilter.toFilter(); } - Recommendation recommendation = new Recommendation( - factory, ids, masterArtifact, filter, targetOut); + final Recommendation recommendation = new Recommendation( + factory, ids, masterArtifact, filter, targetOut); recommendation.setDisplayName(triple.second); recommendations.add(recommendation); diff -r 83aee0942eae -r 84397da33d17 gwt-client/src/test/java/test/SimpleRecommendation.java --- a/gwt-client/src/test/java/test/SimpleRecommendation.java Wed Jul 04 17:14:16 2018 +0200 +++ b/gwt-client/src/test/java/test/SimpleRecommendation.java Wed Jul 04 18:28:08 2018 +0200 @@ -69,11 +69,10 @@ final Recommendation recom2 = new Recommendation(rec2.getFactory(), rec2.getIds(), rec2.getTarget()); recom2.setDisplayName(rec2.getDisplayName()); final Artifact[] artifacts = loadMany(new Recommendation[] { recom1, recom2 }, null, collection, serverUrl, locale); - final String rec1String = RecommandationUtils.createDataString(artifacts[0].getUuid(), recom1, new NilDatacageTwinPanelInfo("xxxx", "yyy")); - final String rec2String = RecommandationUtils.createDataString(artifacts[1].getUuid(), recom2, new NilDatacageTwinPanelInfo("xxxx", "yyy")); + final String rec1String = RecommandationUtils.createDataString(artifacts[0].getUuid(), recom1, new NilDatacageTwinPanelInfo(null, "xxxx")); + final String rec2String = RecommandationUtils.createDataString(artifacts[1].getUuid(), recom2, new NilDatacageTwinPanelInfo(null, "xxxx")); final String combinedIdNeu = rec1String + "#" + rec2String; return combinedIdNeu; - } private final Artifact[] loadMany(final Recommendation[] recoms, final String factory, final Collection collection, final String serverUrl, @@ -106,8 +105,7 @@ } } } - return artifacts.toArray(new Artifact[artifacts.size()]); + return artifacts.toArray(new Artifact[artifacts.size()]); } - -} +} \ No newline at end of file