示例#1
0
  /**
   * Create PVItem from XML document
   *
   * @param model Model to which this item will belong (but doesn't, yet)
   * @param node XML node with item configuration
   * @return PVItem
   * @throws Exception on error
   */
  public static PVItem fromDocument(final Model model, final Element node) throws Exception {
    final String name = DOMHelper.getSubelementString(node, Model.TAG_NAME);
    final double period = DOMHelper.getSubelementDouble(node, Model.TAG_SCAN_PERIOD, 0.0);

    final PVItem item = new PVItem(name, period);
    final int buffer_size =
        DOMHelper.getSubelementInt(
            node, Model.TAG_LIVE_SAMPLE_BUFFER_SIZE, Preferences.getLiveSampleBufferSize());
    item.setLiveCapacity(buffer_size);

    final String req_txt =
        DOMHelper.getSubelementString(node, Model.TAG_REQUEST, RequestType.OPTIMIZED.name());
    try {
      final RequestType request = RequestType.valueOf(req_txt);
      item.setRequestType(request);
    } catch (Throwable ex) {
      // Ignore
    }

    item.configureFromDocument(model, node);

    // Load archives from saved configuration
    boolean have_imported_data = false;
    Element archive = DOMHelper.findFirstElementNode(node.getFirstChild(), Model.TAG_ARCHIVE);
    while (archive != null) {
      final String url = DOMHelper.getSubelementString(archive, Model.TAG_URL);
      final int key = DOMHelper.getSubelementInt(archive, Model.TAG_KEY);
      final String arch = DOMHelper.getSubelementString(archive, Model.TAG_NAME);

      if (url.startsWith(ImportArchiveReaderFactory.PREFIX)) have_imported_data = true;

      item.addArchiveDataSource(new ArchiveDataSource(url, key, arch));
      archive = DOMHelper.findNextElementNode(archive, Model.TAG_ARCHIVE);
    }

    // When requested, use default archive sources for 'real' archives (RDB, ...)
    // Do not clobber an imported archive data source, a specific file which was
    // probably not meant to be replaced by a default.
    if (Preferences.useDefaultArchives() && !have_imported_data)
      item.useDefaultArchiveDataSources();

    return item;
  }
示例#2
0
/**
 * Data Browser model
 *
 * <p>Maintains a list of {@link ModelItem}s
 *
 * @author Kay Kasemir
 * @author Takashi Nakamoto changed the model to accept multiple items with the same name so that
 *     Data Browser can show the trend of the same PV in different axes or with different waveform
 *     indexes.
 */
@SuppressWarnings("nls")
public class Model {
  /**
   * File extension for data browser config files. plugin.xml registers the editor for this file
   * extension
   */
  public static final String FILE_EXTENSION = "plt"; // $NON-NLS-1$

  /** Previously used file extension */
  public static final String FILE_EXTENSION_OLD = "css-plt"; // $NON-NLS-1$

  // XML file tags
  public static final String TAG_DATABROWSER = "databrowser";
  public static final String TAG_SCROLL = "scroll";
  public static final String TAG_UPDATE_PERIOD = "update_period";
  public static final String TAG_LIVE_SAMPLE_BUFFER_SIZE = "ring_size";
  public static final String TAG_PVLIST = "pvlist";
  public static final String TAG_PV = "pv";
  public static final String TAG_NAME = "name";
  public static final String TAG_DISPLAYNAME = "display_name";
  public static final String TAG_FORMULA = "formula";
  public static final String TAG_AXES = "axes";
  public static final String TAG_AXIS = "axis";
  public static final String TAG_LINEWIDTH = "linewidth";
  public static final String TAG_COLOR = "color";
  public static final String TAG_RED = "red";
  public static final String TAG_GREEN = "green";
  public static final String TAG_BLUE = "blue";
  public static final String TAG_TRACE_TYPE = "trace_type";
  public static final String TAG_SCAN_PERIOD = "period";
  public static final String TAG_INPUT = "input";
  public static final String TAG_ARCHIVE = "archive";
  public static final String TAG_URL = "url";
  public static final String TAG_KEY = "key";
  public static final String TAG_START = "start";
  public static final String TAG_END = "end";
  public static final String TAG_LOG_SCALE = "log_scale";
  public static final String TAG_AUTO_SCALE = "autoscale";
  public static final String TAG_MAX = "max";
  public static final String TAG_MIN = "min";
  public static final String TAG_BACKGROUND = "background";
  public static final String TAG_ARCHIVE_RESCALE = "archive_rescale";
  public static final String TAG_REQUEST = "request";
  public static final String TAG_VISIBLE = "visible";

  public static final String TAG_ANNOTATIONS = "annotations";
  public static final String TAG_ANNOTATION = "annotation";
  public static final String TAG_ANNOTATION_CURSOR_LINE_STYLE = "line_style";
  public static final String TAG_ANNOTATION_SHOW_NAME = "show_name";
  public static final String TAG_ANNOTATION_SHOW_POSITION = "show_position";
  public static final String TAG_ANNOTATION_COLOR = "color";
  public static final String TAG_ANNOTATION_FONT = "font";

  public static final String TAG_TIME = "time";
  public static final String TAG_VALUE = "value";
  public static final String TAG_WAVEFORM_INDEX = "waveform_index";

  /**
   * AJOUT XYGraphMemento
   *
   * @author L.PHILIPPE GANIL
   */
  public static final String TAG_TITLE = "title";

  public static final String TAG_TITLE_TEXT = "text";
  public static final String TAG_TITLE_COLOR = "color";
  public static final String TAG_TITLE_FONT = "font";

  public static final String TAG_FONT = "font";
  public static final String TAG_SCALE_FONT = "scale_font";

  public static final String TAG_TIME_AXIS = "time_axis";

  // GRID LINE
  public static final String TAG_GRID_LINE = "grid_line";
  public static final String TAG_SHOW_GRID_LINE = "show_grid_line";
  public static final String TAG_DASH_GRID_LINE = "dash_grid_line";

  // FORMAT
  public static final String TAG_FORMAT = "format";
  public static final String TAG_AUTO_FORMAT = "auto_format";
  public static final String TAG_TIME_FORMAT = "time_format";
  public static final String TAG_FORMAT_PATTERN = "format_pattern";

  public static final String TAG_GRAPH_SETTINGS = "graph_settings";
  public static final String TAG_SHOW_TITLE = "show_title";
  public static final String TAG_SHOW_LEGEND = "show_legend";
  public static final String TAG_SHOW_PLOT_AREA_BORDER = "show_plot_area_border";
  public static final String TAG_TRANSPARENT = "transparent";

  /**
   * Default colors for newly added item, used over when reaching the end.
   *
   * <p>Very hard to find a long list of distinct colors. This list is definitely too short...
   */
  private static final RGB[] default_colors = {
    new RGB(21, 21, 196), // blue
    new RGB(242, 26, 26), // red
    new RGB(33, 179, 33), // green
    new RGB(0, 0, 0), // black
    new RGB(128, 0, 255), // violett
    new RGB(255, 170, 0), // (darkish) yellow
    new RGB(255, 0, 240), // pink
    new RGB(243, 132, 132), // peachy
    new RGB(0, 255, 11), // neon green
    new RGB(0, 214, 255), // neon blue
    new RGB(114, 40, 3), // brown
    new RGB(219, 128, 4), // orange
  };

  /** Macros */
  private IMacroTableProvider macros = null;

  /** Listeners to model changes */
  private final ArrayList<ModelListener> listeners = new ArrayList<ModelListener>();

  /** Axes configurations */
  private final ArrayList<AxisConfig> axes = new ArrayList<AxisConfig>();

  /**
   * Time Axes configurations Ignore MIN-MAX part because the range is set by start & end properties
   */
  private AxisConfig timeAxis;

  public AxisConfig getTimeAxis() {
    return timeAxis;
  }

  /** All the items in this model */
  private final ArrayList<ModelItem> items = new ArrayList<ModelItem>();

  /**
   * 'run' flag
   *
   * @see #start()
   * @see #stop()
   */
  private boolean is_running = false;

  /** Period in seconds for scrolling or refreshing */
  private double update_period = Preferences.getUpdatePeriod();

  /** Timer used to scan PVItems */
  private final Timer scanner = new Timer("ScanTimer", true);

  /** <code>true</code> if scrolling is enabled */
  private boolean scroll_enabled = true;

  /** Time span of data in seconds */
  private double time_span = Preferences.getTimeSpan();

  /** End time of the data range */
  private Timestamp end_time = Timestamp.now();

  /** Background color */
  private RGB background = new RGB(255, 255, 255);

  /** Annotations */
  private AnnotationInfo[] annotations = new AnnotationInfo[0];

  /** How should plot rescale when archived data arrives? */
  private ArchiveRescale archive_rescale = Preferences.getArchiveRescale();

  /**
   * Manage XYGraph Configuration Settings
   *
   * @author L.PHILIPPE GANIL
   */
  private XYGraphSettings graphSettings = new XYGraphSettings();

  public XYGraphSettings getGraphSettings() {
    return graphSettings;
  }

  public void setGraphSettings(XYGraphSettings xYGraphMem) {
    graphSettings = xYGraphMem;
    // fireXYGraphMemChanged(settings);
  }

  public void fireGraphConfigChanged() {

    for (ModelListener listener : listeners) listener.changedXYGraphConfig();
  }

  /** @param macros Macros to use in this model */
  public void setMacros(final IMacroTableProvider macros) {
    this.macros = macros;
  }

  /**
   * Resolve macros
   *
   * @param text Text that might contain "$(macro)"
   * @return Text with all macros replaced by their value
   */
  public String resolveMacros(final String text) {
    if (macros == null) return text;
    try {
      return MacroUtil.replaceMacros(text, macros);
    } catch (InfiniteLoopException ex) {
      Activator.getLogger()
          .log(Level.WARNING, "Problem in macro {0}: {1}", new Object[] {text, ex.getMessage()});
      return "Macro Error";
    }
  }

  /** @param listener New listener to notify */
  public void addListener(final ModelListener listener) {
    listeners.add(listener);
  }

  /** @param listener Listener to remove */
  public void removeListener(final ModelListener listener) {
    listeners.remove(listener);
  }

  /** @return Number of axes in model */
  public int getAxisCount() {
    return axes.size();
  }

  /**
   * @param axis_index Index of axis, 0 ... <code>getAxisCount()-1</code>
   * @return {@link AxisConfig}
   */
  public AxisConfig getAxis(final int axis_index) {
    return axes.get(axis_index);
  }

  /**
   * Return the AxisConfig with the specifc name or null
   *
   * @param axis_index Index of axis, 0 ... <code>getAxisCount()-1</code>
   * @return {@link AxisConfig}
   */
  public AxisConfig getAxis(final String name) {
    for (AxisConfig axis : axes) {
      // System.err.println(axis.getName() + " == " + name + "=" + (axis.getName().equals(name)));
      if (axis.getName().equals(name)) return axis;
    }

    return null;
  }

  /**
   * Locate index of value axis
   *
   * @param axis Value axis configuration
   * @return Index of axis (0, ...) or -1 if not in Model
   */
  public int getAxisIndex(final AxisConfig axis) {
    return axes.indexOf(axis);
  }

  /**
   * @param axis Axis to test
   * @return First ModelItem that uses the axis, <code>null</code> if axis is empty
   */
  public ModelItem getFirstItemOnAxis(final AxisConfig axis) {
    for (ModelItem item : items) if (item.getAxis() == axis) return item;
    return null;
  }

  /**
   * @param axis Axis to test
   * @return ModelItem linked to this axis count
   */
  public int countActiveItemsOnAxis(final AxisConfig axis) {
    int count = 0;
    for (ModelItem item : items) if (item.getAxis() == axis && item.isVisible()) count++;
    return count;
  }

  /** @return First unused axis (no items on axis), <code>null</code> if none found */
  public AxisConfig getEmptyAxis() {
    for (AxisConfig axis : axes) if (getFirstItemOnAxis(axis) == null) return axis;
    return null;
  }

  /**
   * Add value axis with default settings
   *
   * @return Newly added axis configuration
   */
  public AxisConfig addAxis(String name) {
    if (name == null) name = NLS.bind(Messages.Plot_ValueAxisNameFMT, getAxisCount() + 1);
    final AxisConfig axis = new AxisConfig(name);
    axis.setColor(getNextItemColor());
    addAxis(axis);
    return axis;
  }

  /** @param axis New axis to add */
  public void addAxis(final AxisConfig axis) {
    axes.add(axis);
    axis.setModel(this);
    fireAxisChangedEvent(null);
  }

  /**
   * Add axis at given index. Adding at '1' means the new axis will be at index '1', and what used
   * to be at '1' will be at '2' and so on.
   *
   * @param index Index where axis will be placed.
   * @param axis New axis to add
   */
  public void addAxis(final int index, final AxisConfig axis) {
    axes.add(index, axis);
    axis.setModel(this);
    fireAxisChangedEvent(null);
  }

  /**
   * @param axis Axis to remove
   * @throws Error when axis not in model, or axis in use by model item
   */
  public void removeAxis(final AxisConfig axis) {
    if (!axes.contains(axis)) throw new Error("Unknown AxisConfig");
    for (ModelItem item : items)
      if (item.getAxis() == axis) throw new Error("Cannot removed AxisConfig while in use");
    axis.setModel(null);
    axes.remove(axis);
    fireAxisChangedEvent(null);
  }

  /** @return How should plot rescale after archived data arrived? */
  public ArchiveRescale getArchiveRescale() {
    return archive_rescale;
  }

  /** @param archive_rescale How should plot rescale after archived data arrived? */
  public void setArchiveRescale(final ArchiveRescale archive_rescale) {
    if (this.archive_rescale == archive_rescale) return;
    this.archive_rescale = archive_rescale;
    for (ModelListener listener : listeners) listener.changedArchiveRescale();
  }

  /** @return {@link ModelItem} count in model */
  public int getItemCount() {
    return items.size();
  }

  /**
   * Get one {@link ModelItem}
   *
   * @param i 0... getItemCount()-1
   * @return {@link ModelItem}
   */
  public ModelItem getItem(final int i) {
    return items.get(i);
  }

  /**
   * Locate item by name. If different items with the same exist in this model, the first occurrence
   * will be returned. If no item is found with the given name, <code>null</code> will be returned.
   * Now that this model may have different items with the same name, this method is not recommended
   * to locate an item. This method just returns an item which just happens to have the given name.
   * Use {@link #indexOf(ModelItem)} or {@link #getItem(int)} to locate an item in this model.
   *
   * @param name
   * @return ModelItem by that name or <code>null</code>
   */
  public ModelItem getItem(final String name) {
    for (ModelItem item : items) if (item.getName().equals(name)) return item;
    return null;
  }

  /**
   * Returns the index of the specified item, or -1 if this list does not contain the item.
   *
   * @param item
   * @return ModelItem
   */
  public int indexOf(final ModelItem item) {
    return items.indexOf(item);
  }

  /**
   * Called by items to set their initial color
   *
   * @return 'Next' suggested item color
   */
  private RGB getNextItemColor() {
    return default_colors[items.size() % default_colors.length];
  }

  /**
   * Add item to the model.
   *
   * <p>If the item has no color, this will define its color based on the model's next available
   * color.
   *
   * <p>If the model is already 'running', the item will be 'start'ed.
   *
   * @param item {@link ModelItem} to add
   * @throws RuntimeException if item is already in model
   * @throws Exception on error trying to start a PV Item that's added to a running model
   */
  public void addItem(final ModelItem item) throws Exception {
    // A new item with the same PV name are allowed to be added in the
    // model. This way Data Browser can show the trend of the same PV
    // in different axes or with different waveform indexes. For example,
    // one may want to show the first element of epics://aaa:bbb in axis 1
    // while showing the third element of the same PV in axis 2 to compare
    // their trends in one chart.
    //
    // if (getItem(item.getName()) != null)
    //        throw new RuntimeException("Item " + item.getName() + " already in Model");

    // But, if exactly the same instance of the given ModelItem already exists in this
    // model, it will not be added.
    if (items.indexOf(item) != -1)
      throw new RuntimeException("Item " + item.getName() + " already in Model");

    // Assign default color
    if (item.getColor() == null) item.setColor(getNextItemColor());

    // Force item to be on an axis
    if (item.getAxis() == null) {
      if (axes.size() == 0) addAxis(item.getDisplayName());
      item.setAxis(axes.get(0));
    }
    // Check item axis
    if (!axes.contains(item.getAxis()))
      throw new Exception("Item " + item.getName() + " added with invalid axis " + item.getAxis());

    // Add to model
    items.add(item);
    item.setModel(this);
    if (is_running && item instanceof PVItem) ((PVItem) item).start(scanner);
    // Notify listeners of new item
    for (ModelListener listener : listeners) listener.itemAdded(item);
  }

  /**
   * Remove item from the model.
   *
   * <p>If the model and thus item are 'running', the item will be 'stopped'.
   *
   * @param item
   * @throws RuntimeException if item is already in model
   */
  public void removeItem(final ModelItem item) {
    if (is_running && item instanceof PVItem) {
      final PVItem pv = (PVItem) item;
      pv.stop();
      // Delete its samples:
      // For one, so save memory.
      // Also, in case item is later added back in, its old samples
      // will have gaps because the item was stopped
      pv.getSamples().clear();
    }
    if (!items.remove(item)) throw new RuntimeException("Unknown item " + item.getName());
    // Detach item from model
    item.setModel(null);

    // Notify listeners of removed item
    for (ModelListener listener : listeners) listener.itemRemoved(item);

    // Remove axis if unused
    AxisConfig axis = item.getAxis();
    item.setAxis(null);
    if (countActiveItemsOnAxis(axis) == 0) {
      removeAxis(axis);
      fireAxisChangedEvent(null);
    }
  }

  /** @return Period in seconds for scrolling or refreshing */
  public double getUpdatePeriod() {
    return update_period;
  }

  /** @param period_secs New update period in seconds */
  public void setUpdatePeriod(final double period_secs) {
    // Don't allow updates faster than 10Hz (0.1 seconds)
    if (period_secs < 0.1) update_period = 0.1;
    else update_period = period_secs;
    // Notify listeners
    for (ModelListener listener : listeners) listener.changedUpdatePeriod();
  }

  /**
   * The model supports two types of start/end time handling:
   *
   * <ol>
   *   <li>Scroll mode: While <code>isScrollEnabled=true</code>, the end time is supposed to be
   *       'now' and the start time is supposed to be <code>getTimespan()</code> seconds before
   *       'now'.
   *   <li>Fixed start/end time: While <code>isScrollEnabled=false</code>, the methods <code>
   *       getStartTime()</code>, <code>getEndTime</code> return a fixed start/end time.
   * </ol>
   *
   * @return <code>true</code> if scrolling is enabled
   */
  public synchronized boolean isScrollEnabled() {
    return scroll_enabled;
  }

  /** @param scroll_enabled Should scrolling be enabled? */
  public void enableScrolling(final boolean scroll_enabled) {
    synchronized (this) {
      if (this.scroll_enabled == scroll_enabled) return;
      this.scroll_enabled = scroll_enabled;
    }
    // Notify listeners
    for (ModelListener listener : listeners) listener.scrollEnabled(scroll_enabled);
  }

  /**
   * @return time span of data in seconds
   * @see #isScrollEnabled()
   */
  public synchronized double getTimespan() {
    return time_span;
  }

  /**
   * @param start_time Start and ..
   * @param end_time end time of the range to display
   */
  public void setTimerange(final Timestamp start_time, final Timestamp end_time) {
    final double new_span = end_time.durationFrom(start_time).toSeconds();
    if (new_span > 0) {
      synchronized (this) {
        this.end_time = end_time;
        time_span = new_span;
      }
    }
    // Notify listeners
    for (ModelListener listener : listeners) listener.changedTimerange();
  }

  /**
   * @param time_span time span of data in seconds
   * @see #isScrollEnabled()
   */
  public void setTimespan(final double time_span) {
    if (time_span > 0) {
      synchronized (this) {
        this.time_span = time_span;
      }
    }
    // Notify listeners
    for (ModelListener listener : listeners) listener.changedTimerange();
  }

  /**
   * @return Start time of the data range
   * @see #isScrollEnabled()
   */
  public synchronized Timestamp getStartTime() {
    return getEndTime().minus(TimeDuration.ofSeconds(time_span));
  }

  /**
   * @return End time of the data range
   * @see #isScrollEnabled()
   */
  public synchronized Timestamp getEndTime() {
    if (scroll_enabled) end_time = Timestamp.now();
    return end_time;
  }

  /**
   * @return String representation of start time. While scrolling, this is a relative time,
   *     otherwise an absolute date/time.
   */
  public synchronized String getStartSpecification() {
    if (scroll_enabled) return new RelativeTime(-time_span).toString();
    else return TimestampHelper.format(getStartTime());
  }

  /**
   * @return String representation of end time. While scrolling, this is a relative time, otherwise
   *     an absolute date/time.
   */
  public synchronized String getEndSpecification() {
    if (scroll_enabled) return RelativeTime.NOW;
    else return TimestampHelper.format(end_time);
  }

  /** @return Background color */
  public RGB getPlotBackground() {
    return background;
  }

  /** @param rgb New background color */
  public void setPlotBackground(final RGB rgb) {
    if (background.equals(rgb)) return;
    background = rgb;
    // Notify listeners
    System.out.println("**** Model.setPlotBackground() ****");

    for (ModelListener listener : listeners) listener.changedColors();
  }

  /** @param annotations Annotations to keep in model */
  public void setAnnotations(final AnnotationInfo[] annotations) {
    setAnnotations(annotations, true);
  }

  public void setAnnotations(final AnnotationInfo[] annotations, final boolean fireChanged) {
    this.annotations = annotations;
    if (fireChanged) fireAnnotationsChanged();
  }

  protected void fireAnnotationsChanged() {
    for (ModelListener listener : listeners) listener.changedAnnotations();
  }

  /** @return Annotation infos of model */
  public AnnotationInfo[] getAnnotations() {
    return annotations;
  }

  /**
   * Start all items: Connect PVs, initiate scanning, ...
   *
   * @throws Exception on error
   */
  public void start() throws Exception {
    if (is_running) throw new RuntimeException("Model already started");
    for (ModelItem item : items) {
      if (!(item instanceof PVItem)) continue;
      final PVItem pv_item = (PVItem) item;
      pv_item.start(scanner);
    }
    is_running = true;
  }

  /** Stop all items: Disconnect PVs, ... */
  public void stop() {
    if (!is_running) throw new RuntimeException("Model wasn't started");
    is_running = false;
    for (ModelItem item : items) {
      if (!(item instanceof PVItem)) continue;
      final PVItem pv_item = (PVItem) item;
      pv_item.stop();
      ImportArchiveReaderFactory.removeCachedArchives(pv_item.getArchiveDataSources());
    }
  }

  /**
   * Test if any ModelItems received new samples, if formulas need to be re-computed, since the last
   * time this method was called.
   *
   * @return <code>true</code> if there were new samples
   */
  public boolean updateItemsAndCheckForNewSamples() {
    boolean anything_new = false;
    // Update any formulas
    for (ModelItem item : items) {
      if (item instanceof FormulaItem && ((FormulaItem) item).reevaluate()) anything_new = true;
    }
    // Check and reset PV Items
    for (ModelItem item : items) {
      if (item instanceof PVItem && item.getSamples().testAndClearNewSamplesFlag())
        anything_new = true;
    }
    return anything_new;
  }

  /**
   * Notify listeners of changed axis configuration
   *
   * @param axis Axis that changed
   */
  public void fireAxisChangedEvent(final AxisConfig axis) {
    for (ModelListener listener : listeners) listener.changedAxis(axis);
  }

  /**
   * Notify listeners of changed item visibility
   *
   * @param item Item that changed
   */
  void fireItemVisibilityChanged(final ModelItem item) {
    for (ModelListener listener : listeners) listener.changedItemVisibility(item);
  }

  /**
   * Notify listeners of changed item configuration
   *
   * @param item Item that changed
   */
  void fireItemLookChanged(final ModelItem item) {
    for (ModelListener listener : listeners) listener.changedItemLook(item);
  }

  /**
   * Notify listeners of changed item configuration
   *
   * @param item Item that changed
   */
  void fireItemDataConfigChanged(final PVItem item) {
    for (ModelListener listener : listeners) listener.changedItemDataConfig(item);
  }

  /**
   * Find a formula that uses a model item as an input.
   *
   * @param item Item that's potentially used in a formula
   * @return First Formula found that uses this item, or <code>null</code> if none found
   */
  public FormulaItem getFormulaWithInput(final ModelItem item) {
    // Update any formulas
    for (ModelItem i : items) {
      if (!(i instanceof FormulaItem)) continue;
      final FormulaItem formula = (FormulaItem) i;
      if (formula.usesInput(item)) return formula;
    }
    return null;
  }

  /**
   * Write RGB color to XML document
   *
   * @param writer
   * @param level Indentation level
   * @param tag_name
   * @param color
   */
  static void writeColor(
      final PrintWriter writer, final int level, final String tag_name, final RGB color) {
    XMLWriter.start(writer, level, tag_name);
    writer.println();
    XMLWriter.XML(writer, level + 1, Model.TAG_RED, color.red);
    XMLWriter.XML(writer, level + 1, Model.TAG_GREEN, color.green);
    XMLWriter.XML(writer, level + 1, Model.TAG_BLUE, color.blue);
    XMLWriter.end(writer, level, tag_name);
    writer.println();
  }

  /**
   * Load RGB color from XML document
   *
   * @param node Parent node of the color
   * @param color_tag Name of tag that contains the color
   * @return RGB or <code>null</code> if no color found
   */
  static RGB loadColorFromDocument(final Element node, final String color_tag) {
    if (node == null) return new RGB(0, 0, 0);
    final Element color = DOMHelper.findFirstElementNode(node.getFirstChild(), color_tag);
    if (color == null) return null;
    final int red = DOMHelper.getSubelementInt(color, Model.TAG_RED, 0);
    final int green = DOMHelper.getSubelementInt(color, Model.TAG_GREEN, 0);
    final int blue = DOMHelper.getSubelementInt(color, Model.TAG_BLUE, 0);
    return new RGB(red, green, blue);
  }

  /**
   * Load RGB color from XML document
   *
   * @param node Parent node of the color
   * @return RGB or <code>null</code> if no color found
   */
  static RGB loadColorFromDocument(final Element node) {
    return loadColorFromDocument(node, Model.TAG_COLOR);
  }

  /**
   * Write XML formatted Model content.
   *
   * @param out OutputStream, will be closed when done.
   */
  public void write(final OutputStream out) {
    final PrintWriter writer = new PrintWriter(out);

    XMLWriter.header(writer);
    XMLWriter.start(writer, 0, TAG_DATABROWSER);
    writer.println();

    // L.PHILIPPE
    // Save config graph settings
    XYGraphSettingsXMLUtil XYGraphMemXML = new XYGraphSettingsXMLUtil(graphSettings);
    XYGraphMemXML.write(writer);

    // Time axis
    XMLWriter.XML(writer, 1, TAG_SCROLL, isScrollEnabled());
    XMLWriter.XML(writer, 1, TAG_UPDATE_PERIOD, getUpdatePeriod());
    if (isScrollEnabled()) {
      XMLWriter.XML(writer, 1, TAG_START, new RelativeTime(-getTimespan()));
      XMLWriter.XML(writer, 1, TAG_END, RelativeTime.NOW);
    } else {
      XMLWriter.XML(writer, 1, TAG_START, getStartTime());
      XMLWriter.XML(writer, 1, TAG_END, getEndTime());
    }

    // Time axis config
    if (timeAxis != null) {
      XMLWriter.start(writer, 1, TAG_TIME_AXIS);
      writer.println();
      timeAxis.write(writer);
      XMLWriter.end(writer, 1, TAG_TIME_AXIS);
      writer.println();
    }

    // Misc.
    writeColor(writer, 1, TAG_BACKGROUND, background);
    XMLWriter.XML(writer, 1, TAG_ARCHIVE_RESCALE, archive_rescale.name());

    // Value axes
    XMLWriter.start(writer, 1, TAG_AXES);
    writer.println();
    for (AxisConfig axis : axes) axis.write(writer);
    XMLWriter.end(writer, 1, TAG_AXES);
    writer.println();

    // Annotations
    XMLWriter.start(writer, 1, TAG_ANNOTATIONS);
    writer.println();
    for (AnnotationInfo annotation : annotations) annotation.write(writer);
    XMLWriter.end(writer, 1, TAG_ANNOTATIONS);
    writer.println();

    // PVs (Formulas)
    XMLWriter.start(writer, 1, TAG_PVLIST);
    writer.println();
    for (ModelItem item : items) item.write(writer);
    XMLWriter.end(writer, 1, TAG_PVLIST);
    writer.println();
    XMLWriter.end(writer, 0, TAG_DATABROWSER);
    writer.close();
  }

  public void setTimeAxis(AxisConfig timeAxis) {
    this.timeAxis = timeAxis;
  }

  /**
   * Read XML formatted Model content.
   *
   * @param stream InputStream, will be closed when done.
   * @throws Exception on error
   * @throws RuntimeException if model was already in use
   */
  public void read(final InputStream stream) throws Exception {
    final DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    final Document doc = docBuilder.parse(stream);
    loadFromDocument(doc);
  }

  /**
   * Load model
   *
   * @param doc DOM document
   * @throws Exception on error
   * @throws RuntimeException if model was already in use
   */
  private void loadFromDocument(final Document doc) throws Exception {
    if (is_running || items.size() > 0) throw new RuntimeException("Model was already in use");

    // Check if it's a <databrowser/>.
    doc.getDocumentElement().normalize();
    final Element root_node = doc.getDocumentElement();
    if (!root_node.getNodeName().equals(TAG_DATABROWSER))
      throw new Exception("Wrong document type");

    synchronized (this) {
      scroll_enabled = DOMHelper.getSubelementBoolean(root_node, TAG_SCROLL, scroll_enabled);
    }
    update_period = DOMHelper.getSubelementDouble(root_node, TAG_UPDATE_PERIOD, update_period);

    final String start = DOMHelper.getSubelementString(root_node, TAG_START);
    final String end = DOMHelper.getSubelementString(root_node, TAG_END);
    if (start.length() > 0 && end.length() > 0) {
      final StartEndTimeParser times = new StartEndTimeParser(start, end);
      setTimerange(
          TimestampHelper.fromCalendar(times.getStart()),
          TimestampHelper.fromCalendar(times.getEnd()));
    }

    RGB color = loadColorFromDocument(root_node, TAG_BACKGROUND);
    if (color != null) background = color;

    try {
      archive_rescale =
          ArchiveRescale.valueOf(DOMHelper.getSubelementString(root_node, TAG_ARCHIVE_RESCALE));
    } catch (Throwable ex) {
      archive_rescale = ArchiveRescale.STAGGER;
    }

    // Load Time Axis
    final Element timeAxisNode =
        DOMHelper.findFirstElementNode(root_node.getFirstChild(), TAG_TIME_AXIS);
    if (timeAxisNode != null) {
      // Load PV items
      Element axisNode = DOMHelper.findFirstElementNode(timeAxisNode.getFirstChild(), TAG_AXIS);
      timeAxis = AxisConfig.fromDocument(axisNode);
    }

    // Load value Axes
    Element list = DOMHelper.findFirstElementNode(root_node.getFirstChild(), TAG_AXES);
    if (list != null) {
      // Load PV items
      Element item = DOMHelper.findFirstElementNode(list.getFirstChild(), TAG_AXIS);
      while (item != null) {
        addAxis(AxisConfig.fromDocument(item));
        item = DOMHelper.findNextElementNode(item, TAG_AXIS);
      }
    }

    // Load Annotations
    list = DOMHelper.findFirstElementNode(root_node.getFirstChild(), TAG_ANNOTATIONS);
    if (list != null) {
      // Load PV items
      Element item = DOMHelper.findFirstElementNode(list.getFirstChild(), TAG_ANNOTATION);
      final List<AnnotationInfo> infos = new ArrayList<AnnotationInfo>();
      try {
        while (item != null) {
          final AnnotationInfo annotation = AnnotationInfo.fromDocument(item);
          infos.add(annotation);
          item = DOMHelper.findNextElementNode(item, TAG_ANNOTATION);
        }
      } catch (Throwable ex) {
        Activator.getLogger().log(Level.INFO, "XML error in Annotation", ex);
      }
      // Add to document
      annotations = infos.toArray(new AnnotationInfo[infos.size()]);
    }

    // ADD by Laurent PHILIPPE
    // Load Title and graph settings
    try {
      graphSettings = XYGraphSettingsXMLUtil.fromDocument(root_node.getFirstChild());
    } catch (Throwable ex) {
      Activator.getLogger().log(Level.INFO, "XML error in Title or  graph settings", ex);
    }

    // Backwards compatibility with previous data browser which
    // used global buffer size for all PVs
    final int buffer_size =
        DOMHelper.getSubelementInt(root_node, Model.TAG_LIVE_SAMPLE_BUFFER_SIZE, -1);

    // Load PVs/Formulas
    list = DOMHelper.findFirstElementNode(root_node.getFirstChild(), TAG_PVLIST);
    if (list != null) {
      // Load PV items
      Element item = DOMHelper.findFirstElementNode(list.getFirstChild(), TAG_PV);
      while (item != null) {
        final PVItem model_item = PVItem.fromDocument(this, item);
        if (buffer_size > 0) model_item.setLiveCapacity(buffer_size);
        // Adding item creates the axis for it if not already there
        addItem(model_item);
        // Backwards compatibility with previous data browser which
        // stored axis configuration with each item: Update axis from that.
        final AxisConfig axis = model_item.getAxis();
        String s = DOMHelper.getSubelementString(item, TAG_AUTO_SCALE);
        if (s.equalsIgnoreCase("true")) axis.setAutoScale(true);
        s = DOMHelper.getSubelementString(item, TAG_LOG_SCALE);
        if (s.equalsIgnoreCase("true")) axis.setLogScale(true);
        final double min = DOMHelper.getSubelementDouble(item, Model.TAG_MIN, axis.getMin());
        final double max = DOMHelper.getSubelementDouble(item, Model.TAG_MAX, axis.getMax());
        axis.setRange(min, max);

        item = DOMHelper.findNextElementNode(item, TAG_PV);
      }
      // Load Formulas
      item = DOMHelper.findFirstElementNode(list.getFirstChild(), TAG_FORMULA);
      while (item != null) {
        addItem(FormulaItem.fromDocument(this, item));
        item = DOMHelper.findNextElementNode(item, TAG_FORMULA);
      }
    }
  }
}
 /** {@inheritDoc} */
 @Override
 public void run() {
   Activator.getLogger().log(Level.FINE, "Starting {0}", ArchiveFetchJob.this); // $NON-NLS-1$
   final BenchmarkTimer timer = new BenchmarkTimer();
   long samples = 0;
   final int bins = Preferences.getPlotBins();
   final ArchiveDataSource archives[] = item.getArchiveDataSources();
   List<ArchiveDataSource> sourcesWhereChannelDoesntExist = new ArrayList<>();
   for (int i = 0; i < archives.length && !cancelled; ++i) {
     final ArchiveDataSource archive = archives[i];
     final String url = archive.getUrl();
     // Display "N/total", using '1' for the first sub-archive.
     synchronized (this) {
       message =
           NLS.bind(
               Messages.ArchiveFetchDetailFmt,
               new Object[] {archive.getName(), (i + 1), archives.length});
     }
     try {
       final ArchiveReader the_reader;
       synchronized (this) {
         the_reader = reader = ArchiveRepository.getInstance().getArchiveReader(url);
       }
       the_reader.enableConcurrency(concurrency);
       final ValueIterator value_iter;
       try {
         if (item.getRequestType() == RequestType.RAW)
           value_iter =
               the_reader.getRawValues(archive.getKey(), item.getResolvedName(), start, end);
         else
           value_iter =
               the_reader.getOptimizedValues(
                   archive.getKey(), item.getResolvedName(), start, end, bins);
       } catch (UnknownChannelException e) {
         // Do not immediately notify about unknown channels. First search for the data in all
         // archive
         // sources and only report this kind of errors at the end
         sourcesWhereChannelDoesntExist.add(archives[i]);
         continue;
       }
       // Get samples into array
       final List<VType> result = new ArrayList<VType>();
       while (value_iter.hasNext()) result.add(value_iter.next());
       samples += result.size();
       item.mergeArchivedSamples(the_reader.getServerName(), result);
       if (cancelled) break;
       value_iter.close();
     } catch (Exception ex) { // Tell listener unless it's the result of a 'cancel'?
       if (!cancelled) listener.archiveFetchFailed(ArchiveFetchJob.this, archive, ex);
       // Continue with the next data source
     } finally {
       synchronized (this) {
         if (reader != null) reader.close();
         reader = null;
       }
     }
   }
   if (!sourcesWhereChannelDoesntExist.isEmpty() && !cancelled) {
     listener.channelNotFound(
         ArchiveFetchJob.this,
         sourcesWhereChannelDoesntExist.size() < archives.length,
         sourcesWhereChannelDoesntExist.toArray(
             new ArchiveDataSource[sourcesWhereChannelDoesntExist.size()]));
   }
   timer.stop();
   if (!cancelled) listener.fetchCompleted(ArchiveFetchJob.this);
   Activator.getLogger()
       .log(
           Level.FINE,
           "Ended {0} with {1} samples in {2}", //$NON-NLS-1$
           new Object[] {ArchiveFetchJob.this, samples, timer});
 }
示例#4
0
/**
 * Data Browser Model Item for 'live' PV.
 *
 * <p>Holds both historic and live data in PVSamples. Performs the periodic scans of a control
 * system PV.
 *
 * <p>Also implements IProcessVariable so that context menus can link to related CSS tools.
 *
 * @author Kay Kasemir
 * @author Takashi Nakamoto changed PVItem to handle waveform index.
 */
public class PVItem extends ModelItem implements PVReaderListener<List<VType>>, Cloneable {
  /** Historic and 'live' samples for this PV */
  private PVSamples samples = new PVSamples();

  /** Where to get archived data for this item. */
  private ArrayList<ArchiveDataSource> archives = new ArrayList<ArchiveDataSource>();

  /** Control system PV, set when running */
  private PVReader<List<VType>> pv = null;

  /** Most recently received value */
  private volatile VType current_value;

  /** Scan period in seconds, &le;0 to 'monitor' */
  private double period;

  /** Timer that was used to schedule the scanner */
  private Timer scan_timer = null;

  /** For a period &gt;0, this timer task performs the scanning */
  private TimerTask scanner = null;

  /** Archive data request type */
  private RequestType request_type = RequestType.OPTIMIZED;

  /** Waveform Index */
  private int waveform_index = 0;

  /**
   * Indicating if the history data is automatically refreshed, whenever the live buffer is too
   * small to show all the data
   */
  private boolean automaticRefresh = Preferences.isAutomaticHistoryRefresh();

  /**
   * Initialize
   *
   * @param name PV name
   * @param period Scan period in seconds, &le;0 to 'monitor'
   * @throws Exception on error
   */
  public PVItem(final String name, final double period) throws Exception {
    super(name);
    this.period = period;
  }

  /** @return Waveform index */
  @Override
  public int getWaveformIndex() {
    return waveform_index;
  }

  /** @param index New waveform index */
  @Override
  public void setWaveformIndex(int index) {
    if (index < 0) index = 0;
    if (index == waveform_index) return;
    waveform_index = index;

    // change all the index of samples in this instance
    samples.setWaveformIndex(waveform_index);

    //        fireItemLookChanged();
  }

  /** Set new item name, which changes the underlying PV name {@inheritDoc} */
  @Override
  public boolean setName(final String new_name) throws Exception {
    if (!super.setName(new_name)) return false;
    // Stop PV, clear samples
    final boolean running = (pv != null);
    if (running) stop();
    samples.clear();
    // Create new PV, maybe start it
    if (running) start(scan_timer);
    return true;
  }

  /** @return Scan period in seconds, &le;0 to 'monitor' */
  public double getScanPeriod() {
    return period;
  }

  /**
   * Update scan period.
   *
   * <p>When called on a running item, this stops and re-starts the PV.
   *
   * @param period New scan period in seconds, &le;0 to 'monitor'
   * @throws Exception On error re-starting a running PVItem
   */
  public void setScanPeriod(double period) throws Exception {
    // Don't 'scan' faster than 1 Hz. Instead switch to on-change.
    if (period < 0.1) period = 0.0;
    final boolean running = (pv != null);
    if (running) stop();
    this.period = period;
    if (running) start(scan_timer);
    //        fireItemLookChanged();
  }

  @Override
  void setModel(Model model) {
    super.setModel(model);
    this.automaticRefresh = model.isAutomaticHistoryRefresh();
  }

  /** @return Maximum number of live samples in ring buffer */
  public int getLiveCapacity() {
    return samples.getLiveCapacity();
  }

  /**
   * Set new capacity for live sample ring buffer
   *
   * <p>
   *
   * @param new_capacity New sample count capacity
   * @throws Exception on out-of-memory error
   */
  public void setLiveCapacity(final int new_capacity) throws Exception {
    samples.setLiveCapacity(new_capacity);
    //        fireItemLookChanged();
  }

  /** @return Archive data sources for this item */
  public ArchiveDataSource[] getArchiveDataSources() {
    return (ArchiveDataSource[]) archives.toArray(new ArchiveDataSource[archives.size()]);
  }

  /** Replace archives with settings from preferences */
  public void useDefaultArchiveDataSources() {
    archives.clear();
    for (ArchiveDataSource arch : Preferences.getArchives()) archives.add(arch);
    fireItemDataConfigChanged();
  }

  /**
   * @param archive Archive data source
   * @return <code>true</code> if PV uses given data source
   */
  public boolean hasArchiveDataSource(final ArchiveDataSource archive) {
    for (ArchiveDataSource arch : archives) if (arch.equals(archive)) return true;
    return false;
  }

  /**
   * @param archive Archive to add as a source to this item
   * @throws Error when archive is already used
   */
  @SuppressWarnings("nls")
  public void addArchiveDataSource(final ArchiveDataSource archive) {
    if (hasArchiveDataSource(archive)) throw new Error("Duplicate archive " + archive);
    archives.add(archive);
    fireItemDataConfigChanged();
  }

  /** @param archive Archives to add as a source to this item. Duplicates are ignored */
  public void addArchiveDataSource(final ArchiveDataSource archs[]) {
    boolean change = false;
    for (ArchiveDataSource archive : archs)
      if (!archives.contains(archive)) {
        change = true;
        archives.add(archive);
      }
    if (change) fireItemDataConfigChanged();
  }

  /** @param archive Archive to remove as a source from this item. */
  public void removeArchiveDataSource(final ArchiveDataSource archive) {
    if (archives.remove(archive)) fireItemDataConfigChanged();
  }

  /** @param archive Archives to remove as a source from this item. Ignored when not used. */
  public void removeArchiveDataSource(final ArchiveDataSource archs[]) {
    boolean change = false;
    for (ArchiveDataSource archive : archs) if (archives.remove(archive)) change = true;
    if (change) fireItemDataConfigChanged();
  }

  /**
   * Replace existing archive data sources with given archives
   *
   * @param archs ArchiveDataSources to use for this item
   */
  public void setArchiveDataSource(final ArchiveDataSource archs[]) {
    // Check if they are the same, i.e. count AND order match
    if (archs.length == archives.size()) {
      boolean same = true;
      for (int i = 0; i < archs.length; ++i)
        if (!archs[i].equals(archives.get(i))) {
          same = false;
          break;
        }
      if (same) return;
    }
    // Different archives
    archives.clear();
    for (ArchiveDataSource arch : archs) archives.add(arch);
    fireItemDataConfigChanged();
  }

  /** @return Archive data request type */
  public RequestType getRequestType() {
    return request_type;
  }

  /** @param request_type New request type */
  public void setRequestType(final RequestType request_type) {
    if (this.request_type == request_type) return;
    this.request_type = request_type;
    fireItemDataConfigChanged();
  }

  /** Notify listeners */
  private void fireItemDataConfigChanged() {
    if (model != null) model.fireItemDataConfigChanged(this);
  }

  /**
   * Connect control system PV, start scanning, ...
   *
   * @throws Exception on error
   */
  @SuppressWarnings("nls")
  public void start(final Timer timer) throws Exception {
    if (pv != null) throw new RuntimeException("Already started " + getName());
    this.scan_timer = timer;
    pv =
        PVManager.read(newValuesOf(vType(getResolvedName())))
            .timeout(ofSeconds(30.0))
            .readListener(this)
            .maxRate(ofSeconds(0.1));
    // Log every received value?
    if (period <= 0.0) return;
    // Start scanner for periodic log
    scanner =
        new TimerTask() {
          @Override
          public void run() {
            final VType value = current_value;
            Activator.getLogger()
                .log(Level.FINE, "PV {0} scans {1}", new Object[] {getName(), value});
            logValueAsNow(value);
          }
        };
    final long delay = (long) (period * 1000);
    timer.schedule(scanner, delay, delay);
  }

  /** Disconnect from control system PV, stop scanning, ... */
  @SuppressWarnings("nls")
  public void stop() {
    if (pv == null) throw new RuntimeException("Not running " + getName());
    if (scanner != null) {
      scanner.cancel();
      scanner = null;
    }
    pv.close();
    pv = null;
  }

  /** {@inheritDoc} */
  @Override
  public PVSamples getSamples() {
    return samples;
  }

  /** {@inheritDoc} */
  @SuppressWarnings("nls")
  @Override
  public void pvChanged(final PVReaderEvent<List<VType>> event) {
    final PVReader<List<VType>> pv = event.getPvReader();
    // Check for error
    final Exception error = pv.lastException();
    if (error != null)
      Activator.getLogger().log(Level.FINE, "PV " + pv.getName() + " error", error);

    final List<VType> values = pv.getValue();
    if (values == null) { // No current value
      current_value = null;
      // In 'monitor' mode, mark in live sample buffer
      if (period <= 0) logDisconnected();
      return;
    } else {
      boolean added = false;
      for (VType value : values) {
        // Cache most recent for 'scanned' operation
        current_value = value;
        // In 'monitor' mode, add to live sample buffer
        if (period <= 0) {
          Activator.getLogger()
              .log(Level.FINE, "PV {0} received {1}", new Object[] {getName(), value});
          samples.addLiveSample(value);
          added = true;
        }
      }
      if (automaticRefresh
          && added
          && samples.isHistoryRefreshNeeded(model.getStartTime(), model.getEndTime())) {
        model.fireItemRefreshRequested(this);
      }
    }
  }

  /** @param value Value to log with 'now' as time stamp */
  private void logValueAsNow(final VType value) {
    if (value == null) logDisconnected();
    else
      // Transform value to have 'now' as time stamp
      samples.addLiveSample(VTypeHelper.transformTimestampToNow(value));
  }

  /** Add one(!) 'disconnected' sample */
  private void logDisconnected() {
    synchronized (samples) {
      final int size = samples.getSize();
      if (size > 0) {
        final String last = VTypeHelper.getMessage(samples.getSample(size - 1).getValue());
        // Does last sample already have 'disconnected' status?
        if (Messages.Model_Disconnected.equals(last)) return;
      }
      samples.addLiveSample(new PlotSample(Messages.LiveData, Messages.Model_Disconnected));
    }
  }

  /**
   * Add data retrieved from an archive to the 'historic' section
   *
   * @param server_name Archive server that provided these samples
   * @param new_samples Historic data
   */
  public synchronized void mergeArchivedSamples(
      final String server_name, final List<VType> new_samples) {
    samples.mergeArchivedData(server_name, new_samples);
    if (automaticRefresh
        && samples.isHistoryRefreshNeeded(model.getStartTime(), model.getEndTime())) {
      model.fireItemRefreshRequested(this);
    }
  }

  /**
   * Write XML formatted PV configuration
   *
   * @param writer PrintWriter
   */
  @Override
  public void write(final PrintWriter writer) {
    XMLWriter.start(writer, 2, Model.TAG_PV);
    writer.println();
    writeCommonConfig(writer);
    XMLWriter.XML(writer, 3, Model.TAG_SCAN_PERIOD, getScanPeriod());
    XMLWriter.XML(writer, 3, Model.TAG_LIVE_SAMPLE_BUFFER_SIZE, getLiveCapacity());
    XMLWriter.XML(writer, 3, Model.TAG_REQUEST, getRequestType().name());
    for (ArchiveDataSource archive : archives) {
      XMLWriter.start(writer, 3, Model.TAG_ARCHIVE);
      writer.println();
      XMLWriter.XML(writer, 4, Model.TAG_NAME, archive.getName());
      XMLWriter.XML(writer, 4, Model.TAG_URL, archive.getUrl());
      XMLWriter.XML(writer, 4, Model.TAG_KEY, archive.getKey());
      XMLWriter.end(writer, 3, Model.TAG_ARCHIVE);
      writer.println();
    }
    XMLWriter.end(writer, 2, Model.TAG_PV);
    writer.println();
  }

  /**
   * Create PVItem from XML document
   *
   * @param model Model to which this item will belong (but doesn't, yet)
   * @param node XML node with item configuration
   * @return PVItem
   * @throws Exception on error
   */
  public static PVItem fromDocument(final Model model, final Element node) throws Exception {
    final String name = DOMHelper.getSubelementString(node, Model.TAG_NAME);
    final double period = DOMHelper.getSubelementDouble(node, Model.TAG_SCAN_PERIOD, 0.0);

    final PVItem item = new PVItem(name, period);
    final int buffer_size =
        DOMHelper.getSubelementInt(
            node, Model.TAG_LIVE_SAMPLE_BUFFER_SIZE, Preferences.getLiveSampleBufferSize());
    item.setLiveCapacity(buffer_size);

    final String req_txt =
        DOMHelper.getSubelementString(node, Model.TAG_REQUEST, RequestType.OPTIMIZED.name());
    try {
      final RequestType request = RequestType.valueOf(req_txt);
      item.setRequestType(request);
    } catch (Throwable ex) {
      // Ignore
    }

    item.configureFromDocument(model, node);

    // Load archives from saved configuration
    boolean have_imported_data = false;
    Element archive = DOMHelper.findFirstElementNode(node.getFirstChild(), Model.TAG_ARCHIVE);
    while (archive != null) {
      final String url = DOMHelper.getSubelementString(archive, Model.TAG_URL);
      final int key = DOMHelper.getSubelementInt(archive, Model.TAG_KEY);
      final String arch = DOMHelper.getSubelementString(archive, Model.TAG_NAME);

      if (url.startsWith(ImportArchiveReaderFactory.PREFIX)) have_imported_data = true;

      item.addArchiveDataSource(new ArchiveDataSource(url, key, arch));
      archive = DOMHelper.findNextElementNode(archive, Model.TAG_ARCHIVE);
    }

    // When requested, use default archive sources for 'real' archives (RDB, ...)
    // Do not clobber an imported archive data source, a specific file which was
    // probably not meant to be replaced by a default.
    if (Preferences.useDefaultArchives() && !have_imported_data)
      item.useDefaultArchiveDataSources();

    return item;
  }

  public PVItem clone() {
    PVItem ret = (PVItem) super.clone();
    ret.samples = samples;
    ret.archives = archives;
    ret.pv = pv;
    ret.current_value = current_value;
    ret.period = period;
    ret.scan_timer = scan_timer;
    ret.request_type = request_type;
    ret.waveform_index = waveform_index;
    return ret;
  }
}
示例#5
0
 /** Replace archives with settings from preferences */
 public void useDefaultArchiveDataSources() {
   archives.clear();
   for (ArchiveDataSource arch : Preferences.getArchives()) archives.add(arch);
   fireItemDataConfigChanged();
 }