code: /*--------------------------------------------------------------*
    Copyright (C) 2006-2020 OpenSim Ltd.
  
    This file is distributed WITHOUT ANY WARRANTY. See the file
    'License' for details on this and other legal matters.
  *--------------------------------------------------------------*/
  package org.omnetpp.scave.python;
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.swt.widgets.Display;
  import org.omnetpp.scave.charting.PlotBase;
  import org.omnetpp.scave.charting.properties.PlotProperty;
  import org.omnetpp.scave.pychart.INativeChartPlotter;
  
  /**
   * Implementation of the methods of the omnetpp.scave.plot Python module
   * for native charts.
   *
   * Collects the data to be put on the plot from the chart script, and handles
   * the batched setting of the visual plot properties.
   */
  class NativeChartPlotter implements INativeChartPlotter {
  
      /** The native plot widget on which to set the visual properties. */
      private PlotBase plot;
  
      /** The native plot widget on which to set the visual properties. */
      private GroupsSeriesDataset scalarDataset = new GroupsSeriesDataset();
      private XYDataset xyDataset = new XYDataset();
      private HistogramDataset histogramDataset = new HistogramDataset();
  
      private Map<String, String> pendingPropertyChanges = new HashMap<>();
  
      public NativeChartPlotter(PlotBase plot) {
          this.plot = plot;
      }
  
      @Override
      public void plotScalars(byte[] pickledData, Map<String, String> props) {
          List<String> seriesKeys = scalarDataset.addValues(pickledData);
  
          pendingPropertyChanges.putAll(props);
          for (String seriesKey : seriesKeys)
              for (String propKey : props.keySet())
                  pendingPropertyChanges.put(propKey + "/" + seriesKey, props.get(propKey));
      }
  
      @Override
      public void plotVectors(byte[] pickledData, Map<String, String> props) {
          List<String> lineKeys = xyDataset.addVectors(pickledData);
  
          for (String lineKey : lineKeys)
              for (String propKey : props.keySet())
                  pendingPropertyChanges.put(propKey + "/" + lineKey, props.get(propKey));
      }
  
      @Override
      public void plotHistograms(byte[] pickledData, Map<String, String> props) {
          List<String> histKeys = histogramDataset.addValues(pickledData);
  
          for (String histKey : histKeys)
              for (String propKey : props.keySet())
                  pendingPropertyChanges.put(propKey + "/" + histKey, props.get(propKey));
      }
  
      public GroupsSeriesDataset getScalarDataset() {
          return scalarDataset;
      }
  
      public XYDataset getXyDataset() {
          return xyDataset;
      }
  
      public HistogramDataset getHistogramDataset() {
          return histogramDataset;
      }
  
      @Override
      public boolean isEmpty() {
          return scalarDataset.getSeriesCount() == 0
                  && scalarDataset.getGroupCount() == 0
                  && xyDataset.getSeriesCount() == 0
                  && histogramDataset.getSeriesCount() == 0;
      }
  
      protected void doSetProperty(String key, String value) {
          final RuntimeException exc[] = new RuntimeException[] { null };
          Display.getDefault().syncExec(() -> {
              try {
                  plot.setProperty(key, value);
              }
              catch (RuntimeException e) {
                  exc[0] = e;
              }
          });
          if (exc[0] != null)
              throw exc[0];
      }
  
      protected void doSetProperties(Map<String, String> props) {
          final RuntimeException exc[] = new RuntimeException[] { null };
          Display.getDefault().syncExec(() -> {
              try {
                  plot.runBatchedUpdates(() -> {
                      for (String k : props.keySet())
                          plot.setProperty(k, props.get(k));
                  });
              }
              catch (RuntimeException e) {
                  exc[0] = e;
              }
          });
          if (exc[0] != null)
              throw exc[0];
      }
  
      public void applyPendingPropertyChanges() {
          try {
              doSetProperties(pendingPropertyChanges);
          }
          finally {
              pendingPropertyChanges.clear();
          }
      }
  
      @Override
      public void setProperty(String key, String value) {
          pendingPropertyChanges.put(key, value);
      }
  
      @Override
      public void setProperties(Map<String, String> properties) {
          pendingPropertyChanges.putAll(properties);
      }
  
      @Override
      public void setGroupTitles(List<String> titles) {
           scalarDataset.setGroupTitles(titles);
      }
  
      public String getWarning() {
          return plot.getWarningText();
      }
  
      public void setWarning(String message) {
          plot.setWarningText(message);
      }
  
      public void reset() {
          // The old datasets are not disposed of here, because NativeChartPlotter will
          // need them for just a bit longer to avoid flicker upon refreshing the chart.
          scalarDataset = new GroupsSeriesDataset();
          xyDataset = new XYDataset();
          histogramDataset = new HistogramDataset();
  
          for (PlotProperty p : plot.getProperties())
              setProperty(p.getName(), p.getDefaultValueAsString());
      }
  
      public void dispose() {
          if (xyDataset != null)
              xyDataset.dispose();
      }
  
      @Override
      public Set<String> getSupportedPropertyKeys() {
          Set<String> result = new HashSet<String>();
          result.addAll(Arrays.asList(plot.getPropertyNames()));
          return result;
      }
  }
  