gernotbelger@8852: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde gernotbelger@8852: * Software engineering by Intevation GmbH gernotbelger@8852: * gernotbelger@8852: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@8852: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@8852: * documentation coming with Dive4Elements River for details. gernotbelger@8852: */ gernotbelger@8852: gernotbelger@8852: package org.dive4elements.river.client.client.ui; gernotbelger@8852: gernotbelger@8875: import java.util.ArrayList; gernotbelger@8875: import java.util.List; gernotbelger@8875: import java.util.Map; gernotbelger@8875: import java.util.Set; gernotbelger@8852: gernotbelger@8852: import org.dive4elements.river.client.client.Config; gernotbelger@8852: import org.dive4elements.river.client.client.FLYSConstants; gernotbelger@8852: import org.dive4elements.river.client.client.event.StepForwardEvent; gernotbelger@8852: import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; gernotbelger@8852: import org.dive4elements.river.client.client.services.RemoveArtifactServiceAsync; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Artifact; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Collection; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Data; gernotbelger@8852: import org.dive4elements.river.client.shared.model.DataItem; gernotbelger@8852: import org.dive4elements.river.client.shared.model.DataList; gernotbelger@8852: import org.dive4elements.river.client.shared.model.DefaultData; gernotbelger@8852: import org.dive4elements.river.client.shared.model.DefaultDataItem; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Recommendation; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Recommendation.Facet; gernotbelger@8852: import org.dive4elements.river.client.shared.model.Recommendation.Filter; gernotbelger@8852: import org.dive4elements.river.client.shared.model.User; gernotbelger@8852: gernotbelger@8875: import com.google.gwt.core.client.GWT; gernotbelger@8875: import com.google.gwt.user.client.rpc.AsyncCallback; gernotbelger@8875: import com.smartgwt.client.data.Record; gernotbelger@8875: import com.smartgwt.client.types.ListGridFieldType; gernotbelger@8875: import com.smartgwt.client.widgets.Canvas; gernotbelger@8875: import com.smartgwt.client.widgets.events.ClickEvent; gernotbelger@8875: import com.smartgwt.client.widgets.grid.ListGrid; gernotbelger@8875: import com.smartgwt.client.widgets.grid.ListGridField; gernotbelger@8875: import com.smartgwt.client.widgets.grid.ListGridRecord; gernotbelger@8875: import com.smartgwt.client.widgets.grid.events.RecordClickEvent; gernotbelger@8875: import com.smartgwt.client.widgets.grid.events.RecordClickHandler; gernotbelger@8875: import com.smartgwt.client.widgets.layout.VLayout; gernotbelger@8852: gernotbelger@8852: // TODO Probably better to branch off AbstractUIProvider. gernotbelger@8852: // TODO Merge with other datacage-widget impls. gernotbelger@8852: /** gernotbelger@8852: * Panel containing a Grid and a "next" button. The Grid is fed by a gernotbelger@8852: * DatacagePairWidget which is put in the input-helper area. gernotbelger@8852: */ gernotbelger@8852: public abstract class AbstractPairRecommendationPanel gernotbelger@8852: extends TextProvider { gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Allows for abstraction on how to handle/serialize the recommendation and the used factories. gernotbelger@8875: * Basically this allows to tweak the factory that is delivered from the datacage to be replaced by a specific one... gernotbelger@8875: * gernotbelger@8852: * @author Gernot Belger gernotbelger@8852: */ gernotbelger@8852: public static interface IRecommendationInfo { gernotbelger@8852: gernotbelger@8875: String getFactory(String originalFactory); gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there. gernotbelger@8875: * @param recommendation gernotbelger@8852: */ gernotbelger@8875: String getDataStringFactory(Recommendation recommendation); gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Set factory of recommendation such that the correct artifacts will gernotbelger@8852: * be cloned for difference calculations. gernotbelger@8852: */ gernotbelger@8852: void adjustRecommendation(Recommendation recommendation); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: public static interface IValidator gernotbelger@8852: { gernotbelger@8852: List validate(ListGrid differencesList, FLYSConstants msgProvider); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: private static final long serialVersionUID = 8906629596491827857L; gernotbelger@8852: gernotbelger@8852: // FIXME: why? we hide the field of the super class with exactly the same thing... gernotbelger@8852: private static FLYSConstants MSG_PROVIDER = GWT.create(FLYSConstants.class); gernotbelger@8852: gernotbelger@8852: private String dataName; gernotbelger@8852: gernotbelger@8875: private final User user; gernotbelger@8852: gernotbelger@8852: /** ListGrid that displays user-selected pairs to build differences with. */ gernotbelger@8852: private ListGrid differencesList; gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * List to track previously selected but now removed pairs. (Needed to gernotbelger@8852: * be able to identify artifacts that can be removed from the collection. gernotbelger@8852: */ gernotbelger@8875: private final List removedPairs = gernotbelger@8852: new ArrayList(); gernotbelger@8852: gernotbelger@8852: /** Service handle to clone and add artifacts to collection. */ gernotbelger@8875: private final LoadArtifactServiceAsync loadArtifactService = GWT.create( gernotbelger@8852: org.dive4elements.river.client.client.services.LoadArtifactService.class); gernotbelger@8852: gernotbelger@8852: /** Service to remove artifacts from collection. */ gernotbelger@8875: private final RemoveArtifactServiceAsync removeArtifactService = GWT.create( gernotbelger@8852: org.dive4elements.river.client.client.services.RemoveArtifactService.class); gernotbelger@8852: gernotbelger@8875: private final IRecommendationInfo leftInfo; gernotbelger@8852: gernotbelger@8875: private final IRecommendationInfo rightInfo; gernotbelger@8852: gernotbelger@8875: private final IValidator validator; gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * @param Validates the content of this form when the user clicks 'apply' gernotbelger@8852: * @param leftInfo Delegate for handling the left part of the recommendation-pair gernotbelger@8852: * @param rightInfo Delegate for handling the right part of the recommendation-pair gernotbelger@8852: */ gernotbelger@8875: public AbstractPairRecommendationPanel(final User user, final IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) { gernotbelger@8852: this.user = user; gernotbelger@8852: this.validator = validator; gernotbelger@8852: this.leftInfo = leftInfo; gernotbelger@8852: this.rightInfo = rightInfo; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: // FIXME: better than copy/pasting the MSG field into every sub-class but not really nice yet. gernotbelger@8852: protected final static FLYSConstants msg() { gernotbelger@8852: return MSG_PROVIDER; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Remove first occurrence of "[" and "]" (if both do occur). gernotbelger@8852: * @param value String to be stripped of [] (might be null). gernotbelger@8852: * @return input string but with [ and ] removed, or input string if no gernotbelger@8852: * brackets were found. gernotbelger@8852: * @see StringUtil.unbracket gernotbelger@8852: */ gernotbelger@8852: // FIXME: check if this is the same as STringUItils#unbracket gernotbelger@8875: private static final String unbracket(final String value) { gernotbelger@8852: // null- guard. gernotbelger@8852: if (value == null) return value; gernotbelger@8852: gernotbelger@8875: final int start = value.indexOf("["); gernotbelger@8875: final int end = value.indexOf("]"); gernotbelger@8852: gernotbelger@8852: if (start < 0 || end < 0) { gernotbelger@8852: return value; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: return value.substring(start + 1, end); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Create a recommendation from a string representation of it. gernotbelger@8852: * @param from string in format as shown above. gernotbelger@8852: * @param leftInfo2 gernotbelger@8852: * @return recommendation from input string. gernotbelger@8852: */ gernotbelger@8852: private Recommendation createRecommendationFromString(final String from, final IRecommendationInfo info) { gernotbelger@8852: // TODO Construct "real" filter. gernotbelger@8875: final String[] parts = unbracket(from).split(";"); gernotbelger@8875: final Recommendation.Filter filter = new Recommendation.Filter(); gernotbelger@8875: final Recommendation.Facet facet = new Recommendation.Facet( gernotbelger@8852: parts[1], gernotbelger@8852: parts[2]); gernotbelger@8852: gernotbelger@8875: final List facets = new ArrayList(); gernotbelger@8852: facets.add(facet); gernotbelger@8852: filter.add("longitudinal_section", facets); gernotbelger@8852: gernotbelger@8875: final String factory = info.getFactory( parts[1] ); gernotbelger@8852: gernotbelger@8852: final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter); gernotbelger@8852: r.setDisplayName(parts[3]); gernotbelger@8852: return r; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Add RecomendationPairRecords from input String to the ListGrid. gernotbelger@8852: */ gernotbelger@8875: private void populateGridFromString(final String from){ gernotbelger@8852: // Split this string. gernotbelger@8852: // Create according recommendations and display strings. gernotbelger@8875: final String[] recs = from.split("#"); gernotbelger@8852: if (recs.length % 2 != 0) return; gernotbelger@8852: for (int i = 0; i < recs.length; i+=2) { gernotbelger@8875: final Recommendation minuend = gernotbelger@8875: createRecommendationFromString(recs[i+0], this.leftInfo); gernotbelger@8875: final Recommendation subtrahend = gernotbelger@8875: createRecommendationFromString(recs[i+1], this.rightInfo); gernotbelger@8852: gernotbelger@8875: final RecommendationPairRecord pr = new RecommendationPairRecord( gernotbelger@8852: minuend, subtrahend); gernotbelger@8852: // This Recommendation Pair comes from the data string and was thus gernotbelger@8852: // already cloned. gernotbelger@8852: pr.setIsAlreadyLoaded(true); gernotbelger@8852: this.differencesList.addData(pr); gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Creates the graphical representation and interaction widgets for the data. gernotbelger@8852: * @param dataList the data. gernotbelger@8852: * @return graphical representation and interaction widgets for data. gernotbelger@8852: */ gernotbelger@8852: @Override gernotbelger@8875: public final Canvas create(final DataList dataList) { gernotbelger@8852: gernotbelger@8852: final Canvas widget = createWidget(); gernotbelger@8852: gernotbelger@8875: final Canvas canvas = createChooserWidgets(widget, dataList, this.user, this.differencesList); gernotbelger@8852: gernotbelger@8852: populateGrid(dataList); gernotbelger@8852: gernotbelger@8852: return canvas; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this widget. gernotbelger@8852: */ gernotbelger@8852: protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList); gernotbelger@8852: gernotbelger@8875: private void populateGrid(final DataList dataList) { gernotbelger@8875: final Data data = dataList.get(0); gernotbelger@8852: this.dataName = data.getLabel(); gernotbelger@8852: for (int i = 0; i < dataList.size(); i++) { gernotbelger@8852: if (dataList.get(i) != null && dataList.get(i).getItems() != null) { gernotbelger@8852: if (dataList.get(i).getItems() != null) { gernotbelger@8852: populateGridFromString( gernotbelger@8852: dataList.get(i).getItems()[0].getStringValue()); gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: @Override gernotbelger@8852: public final List validate() { gernotbelger@8875: return this.validator.validate(this.differencesList, MSG_PROVIDER); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Creates layout with grid that displays selection inside. gernotbelger@8852: */ gernotbelger@8852: protected final Canvas createWidget() { gernotbelger@8875: final VLayout layout = new VLayout(); gernotbelger@8875: this.differencesList = new ListGrid(); gernotbelger@8852: gernotbelger@8875: this.differencesList.setCanEdit(false); gernotbelger@8875: this.differencesList.setCanSort(false); gernotbelger@8875: this.differencesList.setShowHeaderContextMenu(false); gernotbelger@8875: this.differencesList.setHeight(150); gernotbelger@8875: this.differencesList.setShowAllRecords(true); gernotbelger@8852: gernotbelger@8875: final ListGridField nameField = new ListGridField("first", "Minuend"); gernotbelger@8875: final ListGridField capitalField = new ListGridField("second", "Subtrahend"); gernotbelger@8852: // Track removed rows, therefore more or less reimplement gernotbelger@8852: // setCanRecomeRecords. gernotbelger@8852: final ListGridField removeField = gernotbelger@8852: new ListGridField("_removeRecord", "Remove Record"){{ gernotbelger@8852: setType(ListGridFieldType.ICON); gernotbelger@8852: setIcon(GWT.getHostPageBaseURL() + msg().removeFeature()); gernotbelger@8852: setCanEdit(false); gernotbelger@8852: setCanFilter(false); gernotbelger@8852: setCanSort(false); gernotbelger@8852: setCanGroupBy(false); gernotbelger@8852: setCanFreeze(false); gernotbelger@8852: setWidth(25); gernotbelger@8852: }}; gernotbelger@8852: gernotbelger@8875: this.differencesList.setFields(new ListGridField[] {nameField, gernotbelger@8852: capitalField, removeField}); gernotbelger@8852: gernotbelger@8875: this.differencesList.addRecordClickHandler(new RecordClickHandler() { gernotbelger@8852: @Override gernotbelger@8852: public void onRecordClick(final RecordClickEvent event) { gernotbelger@8852: // Just handle remove-clicks gernotbelger@8852: if(!event.getField().getName().equals(removeField.getName())) { gernotbelger@8852: return; gernotbelger@8852: } gernotbelger@8852: trackRemoved(event.getRecord()); gernotbelger@8852: event.getViewer().removeData(event.getRecord()); gernotbelger@8852: } gernotbelger@8852: }); gernotbelger@8875: layout.addMember(this.differencesList); gernotbelger@8852: gernotbelger@8852: return layout; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Add record to list of removed records. gernotbelger@8852: */ gernotbelger@8875: protected final void trackRemoved(final Record r) { gernotbelger@8875: final RecommendationPairRecord pr = (RecommendationPairRecord) r; gernotbelger@8852: this.removedPairs.add(pr); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Validates data, does nothing if invalid, otherwise clones new selected gernotbelger@8852: * waterlevels and add them to collection, forward the artifact. gernotbelger@8852: */ gernotbelger@8852: @Override gernotbelger@8875: public void onClick(final ClickEvent e) { gernotbelger@8852: GWT.log("AbstractPairRecommendationPanel.onClick"); gernotbelger@8852: gernotbelger@8875: final List errors = validate(); gernotbelger@8852: if (errors != null && !errors.isEmpty()) { gernotbelger@8852: showErrors(errors); gernotbelger@8852: return; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8875: final Config config = Config.getInstance(); gernotbelger@8875: final String locale = config.getLocale(); gernotbelger@8852: gernotbelger@8875: final ListGridRecord[] records = this.differencesList.getRecords(); gernotbelger@8852: gernotbelger@8875: final List ar = new ArrayList(); gernotbelger@8875: final List all = new ArrayList(); gernotbelger@8875: gernotbelger@8875: for (final ListGridRecord record : records) { gernotbelger@8875: final RecommendationPairRecord r = gernotbelger@8852: (RecommendationPairRecord) record; gernotbelger@8852: // Do not add "old" recommendations. gernotbelger@8852: if (!r.isAlreadyLoaded()) { gernotbelger@8852: // Check whether one of those is a dike or similar. gernotbelger@8852: // TODO differentiate and merge: new clones, new, old. gernotbelger@8875: final Recommendation firstR = r.getFirst(); gernotbelger@8875: this.leftInfo.adjustRecommendation(firstR); gernotbelger@8852: gernotbelger@8875: final Recommendation secondR = r.getSecond(); gernotbelger@8875: this.rightInfo.adjustRecommendation(secondR); gernotbelger@8852: ar.add(firstR); gernotbelger@8852: ar.add(secondR); gernotbelger@8852: } gernotbelger@8852: else { gernotbelger@8852: all.add(r.getFirst()); gernotbelger@8852: all.add(r.getSecond()); gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: final Recommendation[] toClone = ar.toArray(new Recommendation[ar.size()]); gernotbelger@8852: final Recommendation[] toUse = all.toArray(new Recommendation[all.size()]); gernotbelger@8852: gernotbelger@8852: // Find out whether "old" artifacts have to be removed. gernotbelger@8875: final List artifactIdsToRemove = new ArrayList(); gernotbelger@8875: for (final RecommendationPairRecord rp: this.removedPairs) { gernotbelger@8852: Recommendation first = rp.getFirst(); gernotbelger@8852: Recommendation second = rp.getSecond(); gernotbelger@8852: gernotbelger@8875: for (final Recommendation recommendation: toUse) { gernotbelger@8852: if (first != null && first.getIDs().equals(recommendation.getIDs())) { gernotbelger@8852: first = null; gernotbelger@8852: } gernotbelger@8852: if (second != null && second.getIDs().equals(recommendation.getIDs())) { gernotbelger@8852: second = null; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: if (first == null && second == null) { gernotbelger@8852: break; gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: if (first != null) { gernotbelger@8852: artifactIdsToRemove.add(first.getIDs()); gernotbelger@8852: } gernotbelger@8852: if (second != null) { gernotbelger@8852: artifactIdsToRemove.add(second.getIDs()); gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: // Remove old artifacts, if any. Do this asychronously without much gernotbelger@8852: // feedback. gernotbelger@8852: for(final String uuid: artifactIdsToRemove) { gernotbelger@8875: this.removeArtifactService.remove(this.collection, gernotbelger@8852: uuid, gernotbelger@8852: locale, gernotbelger@8852: new AsyncCallback() { gernotbelger@8852: @Override gernotbelger@8875: public void onFailure(final Throwable caught) { gernotbelger@8852: GWT.log("RemoveArtifact (" + uuid + ") failed."); gernotbelger@8852: } gernotbelger@8852: @Override gernotbelger@8875: public void onSuccess(final Collection coll) { gernotbelger@8852: GWT.log("RemoveArtifact succeeded"); gernotbelger@8852: } gernotbelger@8852: }); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: // Clone new ones (and spawn statics), go forward. gernotbelger@8875: this.parameterList.lockUI(); gernotbelger@8875: this.loadArtifactService.loadMany( gernotbelger@8852: this.collection, gernotbelger@8852: toClone, gernotbelger@8852: //"staticwkms" and "waterlevel" gernotbelger@8852: null, gernotbelger@8852: locale, gernotbelger@8852: new AsyncCallback() { gernotbelger@8852: @Override gernotbelger@8875: public void onFailure(final Throwable caught) { gernotbelger@8852: caught.printStackTrace(); gernotbelger@8852: GWT.log("Failure of cloning with factories!"); gernotbelger@8875: AbstractPairRecommendationPanel.this.parameterList.unlockUI(); gernotbelger@8852: } gernotbelger@8852: @Override gernotbelger@8875: public void onSuccess(final Artifact[] artifacts) { gernotbelger@8852: GWT.log("Successfully cloned " + toClone.length + gernotbelger@8852: " with factories."); gernotbelger@8852: gernotbelger@8852: fireStepForwardEvent(new StepForwardEvent( gernotbelger@8852: getData(toClone, artifacts, toUse))); gernotbelger@8875: AbstractPairRecommendationPanel.this.parameterList.unlockUI(); gernotbelger@8852: } gernotbelger@8852: }); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Create Data and DataItem from selection (a long string with identifiers gernotbelger@8852: * to construct diff-pairs). gernotbelger@8852: * gernotbelger@8852: * @param newRecommendations "new" recommendations (did not survive a gernotbelger@8852: * backjump). gernotbelger@8852: * @param newArtifacts artifacts cloned from newRecommendations. gernotbelger@8852: * @param oldRecommendations old recommendations that survived a backjump. gernotbelger@8852: * gernotbelger@8852: * @return dataitem with a long string with identifiers to construct gernotbelger@8852: * diff-pairs. gernotbelger@8852: */ gernotbelger@8852: protected final Data[] getData( gernotbelger@8875: final Recommendation[] newRecommendations, gernotbelger@8875: final Artifact[] newArtifacts, gernotbelger@8875: final Recommendation[] oldRecommendations) gernotbelger@8852: { gernotbelger@8852: // Construct string with info about selections. gernotbelger@8852: String dataItemString = ""; gernotbelger@8852: for (int i = 0; i < newRecommendations.length; i++) { gernotbelger@8875: final Recommendation r = newRecommendations[i]; gernotbelger@8875: final Artifact newArtifact = newArtifacts[i]; gernotbelger@8875: final String uuid = newArtifact.getUuid(); gernotbelger@8852: r.setMasterArtifact(uuid); gernotbelger@8852: gernotbelger@8852: if (i>0) gernotbelger@8852: dataItemString += "#"; gernotbelger@8852: gernotbelger@8852: // REMARK: ugly, but we know that the recommandations comes in left/right pairs. gernotbelger@8875: final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; gernotbelger@8852: gernotbelger@8852: dataItemString += createDataString(uuid, r, info); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: for (int i = 0; i < oldRecommendations.length; i++) { gernotbelger@8875: final Recommendation r = oldRecommendations[i]; gernotbelger@8875: final String uuid = r.getIDs(); gernotbelger@8852: gernotbelger@8852: if (dataItemString.length() > 0) gernotbelger@8852: dataItemString += "#"; gernotbelger@8852: gernotbelger@8852: // REMARK: ugly, but we know that the recommandations comes in left/right pairs. gernotbelger@8875: final IRecommendationInfo info = i % 2 == 0 ? this.leftInfo : this.rightInfo; gernotbelger@8852: gernotbelger@8852: dataItemString += createDataString(uuid, r, info); gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: // TODO some hassle could be resolved by using multiple DataItems gernotbelger@8852: // (e.g. one per pair). gernotbelger@8875: final DataItem item = new DefaultDataItem(this.dataName, this.dataName, dataItemString); gernotbelger@8852: return new Data[] { new DefaultData( gernotbelger@8875: this.dataName, null, null, new DataItem[] {item}) }; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: /** gernotbelger@8852: * Creates part of the String that encodes minuend or subtrahend. gernotbelger@8852: * @param recommendation Recommendation to wrap in string. gernotbelger@8852: * @param info Provides the factory to encode. gernotbelger@8852: */ gernotbelger@8852: protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) { gernotbelger@8875: final String factory = info.getDataStringFactory( recommendation ); gernotbelger@8852: gernotbelger@8875: final Filter filter = recommendation.getFilter(); gernotbelger@8852: Facet f = null; gernotbelger@8852: gernotbelger@8852: if(filter != null) { gernotbelger@8875: final Map> outs = filter.getOuts(); gernotbelger@8875: final Set>> entries = outs.entrySet(); gernotbelger@8852: gernotbelger@8875: for (final Map.Entry> entry: entries) { gernotbelger@8875: final List fs = entry.getValue(); gernotbelger@8852: gernotbelger@8852: f = fs.get(0); gernotbelger@8852: if (f != null) { gernotbelger@8852: break; gernotbelger@8852: } gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: return "[" + artifactUuid + ";" gernotbelger@8852: + f.getName() gernotbelger@8852: + ";" gernotbelger@8852: + f.getIndex() gernotbelger@8852: + ";" gernotbelger@8852: + recommendation.getDisplayName() + "]"; gernotbelger@8852: } gernotbelger@8852: gernotbelger@8852: return "[" gernotbelger@8852: + artifactUuid gernotbelger@8852: + ";" + factory + ";0;" gernotbelger@8852: + recommendation.getDisplayName() + "]"; gernotbelger@8852: } gernotbelger@8852: }