teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5993: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5993: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.client.ui.chart; raimund@2906: gernotbelger@9072: import java.util.Date; gernotbelger@9072: import java.util.HashMap; raimund@2935: import java.util.Map; gernotbelger@9263: import java.util.Set; gernotbelger@9072: gernotbelger@9072: import org.dive4elements.river.client.client.Config; gernotbelger@9072: import org.dive4elements.river.client.client.ui.CollectionView; gernotbelger@9072: import org.dive4elements.river.client.shared.model.AbstractFixBunduArtifact; gernotbelger@9072: import org.dive4elements.river.client.shared.model.Artifact; gernotbelger@9072: import org.dive4elements.river.client.shared.model.Collection; gernotbelger@9263: import org.dive4elements.river.client.shared.model.CollectionItem; gernotbelger@9072: import org.dive4elements.river.client.shared.model.FixFilter; gernotbelger@9072: import org.dive4elements.river.client.shared.model.OutputMode; gernotbelger@9263: import org.dive4elements.river.client.shared.model.SINFOArtifact; raimund@2935: sascha@2911: import com.google.gwt.core.client.GWT; raimund@3362: import com.google.gwt.i18n.client.NumberFormat; sascha@2911: import com.smartgwt.client.types.Alignment; gernotbelger@9263: import com.smartgwt.client.util.SC; sascha@2911: import com.smartgwt.client.widgets.Button; sascha@2911: import com.smartgwt.client.widgets.Canvas; sascha@2911: import com.smartgwt.client.widgets.events.ClickEvent; sascha@2911: import com.smartgwt.client.widgets.events.ClickHandler; sascha@2911: import com.smartgwt.client.widgets.form.DynamicForm; sascha@2911: import com.smartgwt.client.widgets.form.fields.TextItem; raimund@2918: import com.smartgwt.client.widgets.form.fields.events.KeyPressEvent; raimund@2918: import com.smartgwt.client.widgets.form.fields.events.KeyPressHandler; raimund@2906: import com.smartgwt.client.widgets.layout.HLayout; raimund@2906: import com.smartgwt.client.widgets.layout.VLayout; sascha@2911: import com.smartgwt.client.widgets.tab.events.TabSelectedEvent; raimund@2906: import com.smartgwt.client.widgets.tab.events.TabSelectedHandler; raimund@2906: raimund@2906: /** felix@4320: * Tab representing and showing one Chart-output with a "navi" thing. raimund@2906: * raimund@2906: * @author Ingo Weinzierl raimund@2906: */ gernotbelger@9072: public class NaviChartOutputTab extends ChartOutputTab implements TabSelectedHandler { gernotbelger@9263: private TextItem currentkm; gernotbelger@9263: gernotbelger@9263: private final NumberFormat kmFormat = NumberFormat.getDecimalFormat(); gernotbelger@9263: gernotbelger@9263: private INaviChartStepper stepper; raimund@2906: gernotbelger@9072: public NaviChartOutputTab(final String title, final Collection collection, final OutputMode mode, final CollectionView collectionView) { raimund@2906: super(title, collection, mode, collectionView); gernotbelger@9263: gernotbelger@9263: this.stepper = new NilNaviChartStepper(); gernotbelger@9263: gernotbelger@9072: this.right.removeChild(this.chart); gernotbelger@9072: this.right.addChild(createNaviChart()); raimund@2906: collectionView.registerTabHandler(this); raimund@2906: } raimund@2906: raimund@2906: protected Canvas createNaviChart() { gernotbelger@9072: final Artifact art = this.collectionView.getArtifact(); gernotbelger@9072: final VLayout root = new VLayout(); raimund@2906: root.setWidth100(); raimund@2906: root.setHeight100(); raimund@2906: gernotbelger@9072: final HLayout layout = new HLayout(); raimund@2906: layout.setAlign(Alignment.CENTER); raimund@2906: gernotbelger@9072: final DynamicForm form = new DynamicForm(); gernotbelger@9072: final Button lower = new Button("<<"); raimund@2906: lower.setWidth(30); gernotbelger@9072: final Button upper = new Button(">>"); raimund@2906: upper.setWidth(30); gernotbelger@9072: this.currentkm = new TextItem(); gernotbelger@9072: this.currentkm.setWidth(60); gernotbelger@9072: this.currentkm.setShowTitle(false); raimund@2906: gernotbelger@9072: form.setFields(this.currentkm); raimund@2906: form.setWidth(60); raimund@2906: gernotbelger@9263: this.stepper = createStepper(art); felix@6017: felix@6017: // Always jump to the from km when initialized. gernotbelger@9263: final double currentKm = this.stepper.getCurrentKm(); gernotbelger@9263: this.collectionView.setCurrentKm(currentKm); gernotbelger@9263: this.currentkm.setValue(this.kmFormat.format(currentKm)); raimund@2906: raimund@2906: lower.addClickHandler(new ClickHandler() { gernotbelger@9072: @Override gernotbelger@9072: public void onClick(final ClickEvent ce) { raimund@2906: updateChartDown(); raimund@2906: } raimund@2906: }); raimund@2906: raimund@2906: upper.addClickHandler(new ClickHandler() { gernotbelger@9072: @Override gernotbelger@9072: public void onClick(final ClickEvent ce) { raimund@2906: updateChartUp(); raimund@2906: } raimund@2906: }); raimund@2906: gernotbelger@9072: this.currentkm.addKeyPressHandler(new KeyPressHandler() { gernotbelger@9072: @Override gernotbelger@9072: public void onKeyPress(final KeyPressEvent kpe) { gernotbelger@9263: gernotbelger@9263: if (!kpe.getKeyName().equals("Enter")) raimund@2918: return; gernotbelger@9263: gernotbelger@9072: if (kpe.getItem().getValue() != null) { gernotbelger@9263: final String kmText = kpe.getItem().getValue().toString(); gernotbelger@9263: updateChartKm(kmText); raimund@2906: } raimund@2906: } raimund@2906: }); raimund@2906: layout.addMember(lower); raimund@2906: layout.addMember(form); raimund@2906: layout.addMember(upper); raimund@2906: gernotbelger@9072: root.addMember(this.chart); raimund@2906: root.addMember(layout); raimund@2906: return root; raimund@2906: } raimund@2906: gernotbelger@9263: private INaviChartStepper createStepper(final Artifact art) { gernotbelger@9263: gernotbelger@9263: if (art instanceof AbstractFixBunduArtifact) { gernotbelger@9263: final AbstractFixBunduArtifact fix = (AbstractFixBunduArtifact) art; gernotbelger@9263: final FixFilter fixFilter = fix.getFilter(); gernotbelger@9263: gernotbelger@9263: final double fromKm = fixFilter.getLowerKm(); gernotbelger@9263: final double toKm = fixFilter.getUpperKm(); gernotbelger@9263: gernotbelger@9263: final String s = fix.getArtifactDescription().getDataValueAsString("ld_step"); gernotbelger@9263: try { gernotbelger@9263: final double ds = Double.parseDouble(s); gernotbelger@9263: return new MinMaxStepNaviChartStepper(fromKm, toKm, ds); gernotbelger@9263: } gernotbelger@9263: catch (final NumberFormatException nfe) { gernotbelger@9263: return new MinMaxStepNaviChartStepper(fromKm, toKm, 100d); gernotbelger@9263: } gernotbelger@9263: } else if (art instanceof SINFOArtifact) { gernotbelger@9263: /* special case for SINFO-Flood-Duration */ gernotbelger@9263: final SINFOArtifact sinfo = (SINFOArtifact) art; gernotbelger@9263: gernotbelger@9263: final CollectionItem item = this.collection.getItem(sinfo.getUuid()); gernotbelger@9263: gernotbelger@9263: final Set validKms = sinfo.getValidDurationChartKms(item); gernotbelger@9263: return new DistinctValuesNaviChartStepper(validKms); gernotbelger@9263: } else { gernotbelger@9263: // Probably WINFOArtifact kind of artifact. gernotbelger@9263: gernotbelger@9263: double fromKm; gernotbelger@9263: double toKm; gernotbelger@9263: gernotbelger@9263: final double[] kmRange = art.getArtifactDescription().getKMRange(); gernotbelger@9263: if (kmRange != null && kmRange.length == 2) { gernotbelger@9263: fromKm = kmRange[0]; gernotbelger@9263: toKm = kmRange[1]; gernotbelger@9263: } else { gernotbelger@9263: GWT.log("No KM range in description found."); gernotbelger@9263: return new NilNaviChartStepper(); gernotbelger@9263: } gernotbelger@9263: gernotbelger@9263: final String ld_step = art.getArtifactDescription().getDataValueAsString("ld_step"); gernotbelger@9263: try { gernotbelger@9263: final Double step = Double.valueOf(ld_step); gernotbelger@9263: return new MinMaxStepNaviChartStepper(fromKm, toKm, step); gernotbelger@9263: } gernotbelger@9263: catch (final Exception e) { gernotbelger@9263: GWT.log("No ld_steps data or not parsable.", e); gernotbelger@9263: return new MinMaxStepNaviChartStepper(fromKm, toKm, 100d); gernotbelger@9263: } gernotbelger@9263: } gernotbelger@9263: } gernotbelger@9263: gernotbelger@9263: protected void updateChartKm(final String kmText) { gernotbelger@9263: gernotbelger@9263: NaviChartOutputTab.this.tbarPanel.deselectControls(); gernotbelger@9263: gernotbelger@9263: try { gernotbelger@9263: final double d = this.kmFormat.parse(kmText); gernotbelger@9263: gernotbelger@9263: final double validCurrentKm = this.stepper.setValidCurrentKm(d); gernotbelger@9263: updateCurrentKm(validCurrentKm); gernotbelger@9263: } gernotbelger@9263: catch (final NumberFormatException e) { gernotbelger@9263: SC.warn("Invalid value: " + kmText); gernotbelger@9263: // do nothing, but an error message would be nice gernotbelger@9263: } gernotbelger@9263: } gernotbelger@9263: felix@5963: /** felix@5963: * Callback when km-up-button is clicked. felix@5963: * Increases collectionViews KM and refreshes view. felix@5963: */ raimund@2906: protected void updateChartUp() { gernotbelger@9263: gernotbelger@9263: this.tbarPanel.deselectControls(); gernotbelger@9263: gernotbelger@9263: final double nextKm = this.stepper.stepForward(); gernotbelger@9263: updateCurrentKm(nextKm); raimund@2906: } felix@4321: felix@5963: /** felix@5963: * Callback when km-down-button is clicked. felix@5963: * Decreases collectionViews KM and refreshes view. felix@5963: */ raimund@2906: protected void updateChartDown() { gernotbelger@9263: gernotbelger@9263: this.tbarPanel.deselectControls(); gernotbelger@9263: gernotbelger@9263: final double prevKm = this.stepper.stepBackward(); gernotbelger@9263: updateCurrentKm(prevKm); gernotbelger@9263: } gernotbelger@9263: gernotbelger@9263: private void updateCurrentKm(final double currentKm) { gernotbelger@9263: gernotbelger@9263: this.collectionView.setCurrentKm(currentKm); gernotbelger@9263: gernotbelger@9263: this.tbarPanel.updateLinks(); gernotbelger@9263: gernotbelger@9263: updateChartPanel(); gernotbelger@9263: updateChartInfo(); gernotbelger@9263: gernotbelger@9263: this.currentkm.setValue(this.kmFormat.format(currentKm)); gernotbelger@9263: this.tbarPanel.onZoom(null); raimund@2906: raimund@2906: } raimund@2906: gernotbelger@9072: /** raimund@2936: * Returns the existing chart panel. raimund@2936: * raimund@2936: * @return the existing chart panel. raimund@2936: */ raimund@2936: @Override raimund@2936: public Canvas getChartPanel() { gernotbelger@9072: return this.chart; raimund@2936: } raimund@2936: raimund@2906: /** raimund@2906: * Builds the URL that points to the chart image. raimund@2906: * gernotbelger@9072: * @param width gernotbelger@9072: * The width of the requested chart. gernotbelger@9072: * @param height gernotbelger@9072: * The height of the requested chart. gernotbelger@9072: * @param xr gernotbelger@9072: * Optional x range (used for zooming). gernotbelger@9072: * @param yr gernotbelger@9072: * Optional y range (used for zooming). raimund@2906: * raimund@2906: * @return the URL to the chart image. raimund@2906: */ raimund@2906: @Override gernotbelger@9072: protected String getImgUrl(final int width, final int height) { gernotbelger@9072: final Config config = Config.getInstance(); raimund@2906: raimund@2906: String imgUrl = GWT.getModuleBaseURL(); raimund@2906: imgUrl += "chart"; gernotbelger@9072: imgUrl += "?uuid=" + this.collection.identifier(); gernotbelger@9072: imgUrl += "&type=" + this.mode.getName(); raimund@2906: imgUrl += "&locale=" + config.getLocale(); raimund@2906: imgUrl += "×tamp=" + new Date().getTime(); raimund@2906: imgUrl += "&width=" + Integer.toString(width); raimund@2906: imgUrl += "&height=" + Integer.toString(height - 40); raimund@2906: gernotbelger@9072: final Number[] zoom = getZoomValues(); raimund@2906: raimund@2906: if (zoom != null) { raimund@2906: if (zoom[0].intValue() != 0 || zoom[1].intValue() != 1) { raimund@2906: // a zoom range of 0-1 means displaying the whole range. In such raimund@2906: // case we don't need to zoom. raimund@2906: imgUrl += "&minx=" + zoom[0]; raimund@2906: imgUrl += "&maxx=" + zoom[1]; raimund@2906: } raimund@2906: raimund@2906: if (zoom[2].intValue() != 0 || zoom[3].intValue() != 1) { raimund@2906: // a zoom range of 0-1 means displaying the whole range. In such raimund@2906: // case we don't need to zoom. raimund@2906: imgUrl += "&miny=" + zoom[2]; raimund@2906: imgUrl += "&maxy=" + zoom[3]; raimund@2906: } raimund@2906: } raimund@2906: gernotbelger@9263: if (this.collectionView.getCurrentKm() == -1) { gernotbelger@9263: // REMARK: this happens, because we get called from the constructor of our super class gernotbelger@9263: gernotbelger@9263: if (this.collectionView.getArtifact() instanceof AbstractFixBunduArtifact) { gernotbelger@9072: final AbstractFixBunduArtifact fix = (AbstractFixBunduArtifact) this.collectionView.getArtifact(); gernotbelger@9099: this.collectionView.setCurrentKm(fix.getFilter().getLowerKm()); raimund@2906: } gernotbelger@9263: else gernotbelger@9263: this.collectionView.setCurrentKm(this.collectionView.getArtifact().getArtifactDescription().getKMRange()[0]); felix@4322: } gernotbelger@9263: gernotbelger@9072: if (this.collectionView.getCurrentKm() != -1) { gernotbelger@9072: imgUrl += "¤tKm=" + this.collectionView.getCurrentKm(); raimund@2906: } raimund@2906: raimund@2906: return imgUrl; raimund@2906: } raimund@2906: gernotbelger@9072: @Override gernotbelger@9072: public void onTabSelected(final TabSelectedEvent tse) { raimund@2906: if (this.equals(tse.getTab())) { gernotbelger@9263: gernotbelger@9263: final double currentKm = this.collectionView.getCurrentKm(); gernotbelger@9263: gernotbelger@9263: final double validCurrentKm = this.stepper.setValidCurrentKm(currentKm); gernotbelger@9263: updateCurrentKm(validCurrentKm); raimund@2906: } raimund@2906: } raimund@2906: raimund@2935: @Override raimund@2935: public Map getChartAttributes() { raimund@2935: Map attr = new HashMap(); raimund@2935: raimund@2935: attr = super.getChartAttributes(); gernotbelger@9072: attr.put("km", String.valueOf(this.collectionView.getCurrentKm())); raimund@2935: raimund@2935: return attr; raimund@2935: } felix@5964: gernotbelger@9072: /** gernotbelger@9072: * In contrast to supers implementation, include the currently selected gernotbelger@9072: * km in the url. gernotbelger@9072: */ felix@5964: @Override gernotbelger@9072: public String getExportUrl(final int width, final int height, final String format) { felix@5964: String url = super.getExportUrl(width, height, format); gernotbelger@9072: if (this.collectionView.getCurrentKm() != -1) { gernotbelger@9072: url += "¤tKm=" + this.collectionView.getCurrentKm(); felix@5964: } felix@5964: return url; felix@5964: } gernotbelger@9263: }