Mercurial > dive4elements > river
diff gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java @ 8852:8f6d6d26e96f
Refaktored the DatacageTwinPanel so it is reusable.
author | gernotbelger |
---|---|
date | Thu, 18 Jan 2018 18:32:30 +0100 |
parents | 36f52c80b7ac |
children | 28df64078f27 |
line wrap: on
line diff
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Thu Jan 18 18:26:30 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Thu Jan 18 18:32:30 2018 +0100 @@ -8,511 +8,56 @@ package org.dive4elements.river.client.client.ui; +import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.User; + import com.google.gwt.core.client.GWT; -import com.google.gwt.user.client.rpc.AsyncCallback; - -import com.smartgwt.client.data.Record; -import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.widgets.Canvas; -import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.grid.ListGrid; -import com.smartgwt.client.widgets.grid.ListGridField; -import com.smartgwt.client.widgets.grid.ListGridRecord; -import com.smartgwt.client.widgets.grid.events.RecordClickEvent; -import com.smartgwt.client.widgets.grid.events.RecordClickHandler; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; -import org.dive4elements.river.client.client.Config; -import org.dive4elements.river.client.client.FLYSConstants; -import org.dive4elements.river.client.client.event.StepForwardEvent; -import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; -import org.dive4elements.river.client.client.services.RemoveArtifactServiceAsync; -import org.dive4elements.river.client.shared.model.Artifact; -import org.dive4elements.river.client.shared.model.Collection; -import org.dive4elements.river.client.shared.model.Data; -import org.dive4elements.river.client.shared.model.DataItem; -import org.dive4elements.river.client.shared.model.DataList; -import org.dive4elements.river.client.shared.model.DefaultData; -import org.dive4elements.river.client.shared.model.DefaultDataItem; -import org.dive4elements.river.client.shared.model.Recommendation; -import org.dive4elements.river.client.shared.model.Recommendation.Facet; -import org.dive4elements.river.client.shared.model.Recommendation.Filter; -import org.dive4elements.river.client.shared.model.User; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -// TODO Probably better to branch off AbstractUIProvider. -// TODO Merge with other datacage-widget impls. /** - * Panel containing a Grid and a "next" button. The Grid is fed by a + * A {@link AbstractPairRecommendationPanel} that uses a 'TwinDatacage' in the help-input area. * DatacagePairWidget which is put in the input-helper area. */ -public class DatacageTwinPanel -extends TextProvider { - - private static final long serialVersionUID = 8906629596491827857L; - - protected static FLYSConstants MSG = GWT.create(FLYSConstants.class); - - protected String dataName; - - protected User user; - - /** ListGrid that displays user-selected pairs to build differences with. */ - protected ListGrid differencesList; - - /** - * List to track previously selected but now removed pairs. (Needed to - * be able to identify artifacts that can be removed from the collection. - */ - protected List<RecommendationPairRecord> removedPairs = - new ArrayList<RecommendationPairRecord>(); - - /** Service handle to clone and add artifacts to collection. */ - LoadArtifactServiceAsync loadArtifactService = GWT.create( - org.dive4elements.river.client.client.services.LoadArtifactService.class); - - /** Service to remove artifacts from collection. */ - RemoveArtifactServiceAsync removeArtifactService = GWT.create( - org.dive4elements.river.client.client.services.RemoveArtifactService.class); - - - public DatacageTwinPanel(User user) { - super(); - this.user = user; - } - - - /** - * Remove first occurrence of "[" and "]" (if both do occur). - * @param value String to be stripped of [] (might be null). - * @return input string but with [ and ] removed, or input string if no - * brackets were found. - * @see StringUtil.unbracket - */ - public static final String unbracket(String value) { - // null- guard. - if (value == null) return value; - - int start = value.indexOf("["); - int end = value.indexOf("]"); - - if (start < 0 || end < 0) { - return value; - } - - value = value.substring(start + 1, end); +public abstract class DatacageTwinPanel +extends AbstractPairRecommendationPanel { - return value; - } - - - /** - * Create a recommendation from a string representation of it. - * @param from string in format as shown above. - * @return recommendation from input string. - */ - public Recommendation createRecommendationFromString(String from, String factory) { - // TODO Construct "real" filter. - String[] parts = unbracket(from).split(";"); - Recommendation.Filter filter = new Recommendation.Filter(); - Recommendation.Facet facet = new Recommendation.Facet( - parts[1], - parts[2]); - - List<Recommendation.Facet> facets = new ArrayList<Recommendation.Facet> - (); - facets.add(facet); - filter.add("longitudinal_section", facets); - Recommendation r = new Recommendation(factory, parts[0], - this.artifact.getUuid(), filter); - r.setDisplayName(parts[3]); - return r; - } - + private IDatacageTwinPanelInfo leftInfo; + private IDatacageTwinPanelInfo rightInfo; - /** - * Add RecomendationPairRecords from input String to the ListGrid. - */ - public void populateGridFromString(String from, String factory){ - // Split this string. - // Create according recommendations and display strings. - String[] recs = from.split("#"); - if (recs.length % 2 != 0) return; - for (int i = 0; i < recs.length; i+=2) { - Recommendation minuend = - createRecommendationFromString(recs[i+0], factory); - Recommendation subtrahend = - createRecommendationFromString(recs[i+1], factory); + public static interface IDatacageTwinPanelInfo extends IRecommendationInfo + { + String getOuts(); + } + + public DatacageTwinPanel(final User user, IValidator validator, final IDatacageTwinPanelInfo leftInfo, final IDatacageTwinPanelInfo rightInfo ) { + super(user, validator, leftInfo, rightInfo); - RecommendationPairRecord pr = new RecommendationPairRecord( - minuend, subtrahend); - // This Recommendation Pair comes from the data string and was thus - // already cloned. - pr.setIsAlreadyLoaded(true); - this.differencesList.addData(pr); - } - } - - - /** - * Creates the graphical representation and interaction widgets for the data. - * @param dataList the data. - * @return graphical representation and interaction widgets for data. - */ + this.leftInfo = leftInfo; + this.rightInfo = rightInfo; + } + @Override - public Canvas create(DataList dataList) { + protected final Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User user, final ListGrid differencesList) { GWT.log("createData()"); - Canvas widget = createWidget(); Canvas submit = getNextButton(); VLayout layout = new VLayout(); HLayout helperLayout = new HLayout(); - helperLayout.addMember(new DatacagePairWidget(this.artifact, - user, "winfo_diff_twin_panel", differencesList)); + + final String leftOuts = leftInfo.getOuts(); + final String rightOuts = rightInfo.getOuts(); + + helperLayout.addMember(new DatacagePairWidget(this.artifact, user, leftOuts, rightOuts, differencesList)); layout.addMember(widget); layout.addMember(submit); layout.setMembersMargin(10); this.helperContainer.addMember(helperLayout); - populateGrid(dataList, "waterlevel"); - return layout; - } - - protected void populateGrid(DataList dataList, String factory) { - 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(), - factory); - } - } - } - } - - - /** - * Validates the selection. - * @return List of internationalized errror messages (if any). - */ - @Override - public List<String> validate() { - List<String> errors = new ArrayList<String>(); - if (differencesList.getRecords().length == 0) { - errors.add(MSG.error_no_waterlevel_pair_selected()); - } - // Check whether minuend and subtrahend are equal. - for (ListGridRecord record: differencesList.getRecords()) { - RecommendationPairRecord r = (RecommendationPairRecord) record; - if (r.getFirst().equals(r.getSecond())) { - errors.add(MSG.error_same_waterlevels_in_pair()); - } - } - - return errors; - } - - - /** - * Creates layout with grid that displays selection inside. - */ - public Canvas createWidget() { - VLayout layout = new VLayout(); - differencesList = new ListGrid(); - - differencesList.setCanEdit(false); - differencesList.setCanSort(false); - differencesList.setShowHeaderContextMenu(false); - differencesList.setHeight(150); - differencesList.setShowAllRecords(true); - - ListGridField nameField = new ListGridField("first", "Minuend"); - ListGridField capitalField = new ListGridField("second", "Subtrahend"); - // 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); - }}; - - differencesList.setFields(new ListGridField[] {nameField, - capitalField, removeField}); - - 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()); - } - }); - layout.addMember(differencesList); - return layout; } - - - /** - * Add record to list of removed records. - */ - public void trackRemoved(Record r) { - RecommendationPairRecord pr = (RecommendationPairRecord) r; - this.removedPairs.add(pr); - } - - /** - * Set factory of recommendation such that the correct artifacts will - * be cloned for difference calculations. - */ - public void adjustRecommendation(Recommendation recommendation) { - // XXX: THIS IS AN EVIL HACK TO MAKE W-DIFFERENCES WORK AGAIN! - // TODO: Throw all this code away and do it with server side recommendations! - recommendation.setTargetOut("w_differences"); - - if (recommendation.getIDs() != null) { - GWT.log("Setting staticwkms factory for rec with ID " - + recommendation.getIDs()); - recommendation.setFactory("staticwkms"); - } - /* - // So far, we do not need to rewrite the factory anymore, - // except for staticwkms; probably other cases will pop up later. - else if (recommendation.getFactory().equals("winfo")) { - GWT.log("Setting waterlevel factory for a winfo rec."); - recommendation.setFactory("waterlevel"); - } - */ - else { - GWT.log("Leave rec. id " + recommendation.getIDs() + ", factory " - + recommendation.getFactory() + " untouched."); - } - } - - /** - * Validates data, does nothing if invalid, otherwise clones new selected - * waterlevels and add them to collection, forward the artifact. - */ - @Override - public void onClick(ClickEvent e) { - GWT.log("DatacageTwinPanel.onClick"); - - List<String> errors = validate(); - if (errors != null && !errors.isEmpty()) { - showErrors(errors); - return; - } - - Config config = Config.getInstance(); - String locale = config.getLocale(); - - ListGridRecord[] records = differencesList.getRecords(); - - List<Recommendation> ar = new ArrayList<Recommendation>(); - List<Recommendation> all = new ArrayList<Recommendation>(); - - for (ListGridRecord record : records) { - RecommendationPairRecord r = - (RecommendationPairRecord) record; - // Do not add "old" recommendations. - if (!r.isAlreadyLoaded()) { - // Check whether one of those is a dike or similar. - // TODO differentiate and merge: new clones, new, old. - Recommendation firstR = r.getFirst(); - adjustRecommendation(firstR); - - Recommendation secondR = r.getSecond(); - adjustRecommendation(secondR); - ar.add(firstR); - ar.add(secondR); - } - else { - all.add(r.getFirst()); - all.add(r.getSecond()); - } - } - - final Recommendation[] toClone = ar.toArray(new Recommendation[ar.size()]); - final Recommendation[] toUse = all.toArray(new Recommendation[all.size()]); - - // Find out whether "old" artifacts have to be removed. - List<String> artifactIdsToRemove = new ArrayList<String>(); - for (RecommendationPairRecord rp: this.removedPairs) { - Recommendation first = rp.getFirst(); - Recommendation second = rp.getSecond(); - - for (Recommendation recommendation: toUse) { - if (first != null && first.getIDs().equals(recommendation.getIDs())) { - first = null; - } - if (second != null && second.getIDs().equals(recommendation.getIDs())) { - second = null; - } - - if (first == null && second == null) { - break; - } - } - if (first != null) { - artifactIdsToRemove.add(first.getIDs()); - } - if (second != null) { - artifactIdsToRemove.add(second.getIDs()); - } - } - - // Remove old artifacts, if any. Do this asychronously without much - // feedback. - for(final String uuid: artifactIdsToRemove) { - removeArtifactService.remove(this.collection, - uuid, - locale, - new AsyncCallback<Collection>() { - @Override - public void onFailure(Throwable caught) { - GWT.log("RemoveArtifact (" + uuid + ") failed."); - } - @Override - public void onSuccess(Collection collection) { - GWT.log("RemoveArtifact succeeded"); - } - }); - } - - // Clone new ones (and spawn statics), go forward. - parameterList.lockUI(); - loadArtifactService.loadMany( - this.collection, - toClone, - //"staticwkms" and "waterlevel" - null, - locale, - new AsyncCallback<Artifact[]>() { - @Override - public void onFailure(Throwable caught) { - GWT.log("Failure of cloning with factories!"); - parameterList.unlockUI(); - } - @Override - public void onSuccess(Artifact[] artifacts) { - GWT.log("Successfully cloned " + toClone.length + - " with factories."); - - fireStepForwardEvent(new StepForwardEvent( - getData(toClone, artifacts, toUse))); - parameterList.unlockUI(); - } - }); - } - - - /** - * Create Data and DataItem from selection (a long string with identifiers - * to construct diff-pairs). - * - * @param newRecommendations "new" recommendations (did not survive a - * backjump). - * @param newArtifacts artifacts cloned from newRecommendations. - * @param oldRecommendations old recommendations that survived a backjump. - * - * @return dataitem with a long string with identifiers to construct - * diff-pairs. - */ - protected Data[] getData( - Recommendation[] newRecommendations, - Artifact[] newArtifacts, - Recommendation[] oldRecommendations) - { - // Construct string with info about selections. - String dataItemString = ""; - for (int i = 0; i < newRecommendations.length; i++) { - Recommendation r = newRecommendations[i]; - Artifact newArtifact = newArtifacts[i]; - String uuid = newArtifact.getUuid(); - r.setMasterArtifact(uuid); - if (i>0) dataItemString += "#"; - - dataItemString += createDataString(uuid, r); - } - - for (int i = 0; i < oldRecommendations.length; i++) { - Recommendation r = oldRecommendations[i]; - String uuid = r.getIDs(); - if (dataItemString.length() > 0) dataItemString += "#"; - - dataItemString += createDataString(uuid, r); - } - - // TODO some hassle could be resolved by using multiple DataItems - // (e.g. one per pair). - DataItem item = new DefaultDataItem(dataName, dataName, dataItemString); - return new Data[] { new DefaultData( - dataName, null, null, new DataItem[] {item}) }; - } - - - protected String createDataString(String artifact, Recommendation recommendation) { - return createDataString(artifact, recommendation, "staticwkms"); - } - - /** - * Creates part of the String that encodes minuend or subtrahend. - * @param artifact Artifacts UUID. - * @param recommendation Recommendation to wrap in string. - * @param factory The factory to encode. - */ - protected String createDataString( - String artifact, - Recommendation recommendation, - String factory) - { - Filter filter = recommendation.getFilter(); - Facet f = null; - - if(filter != null) { - Map<String, List<Facet>> outs = filter.getOuts(); - Set<Map.Entry<String, List<Facet>>> entries = outs.entrySet(); - - for (Map.Entry<String, List<Facet>> entry: entries) { - List<Facet> fs = entry.getValue(); - - f = fs.get(0); - if (f != null) { - break; - } - } - - return "[" + artifact + ";" - + f.getName() - + ";" - + f.getIndex() - + ";" - + recommendation.getDisplayName() + "]"; - } - else { - return "[" - + artifact - + ";" + factory + ";0;" - + recommendation.getDisplayName() + "]"; - } - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file