Package jsynoptic.plugins.jfreechart

Source Code of jsynoptic.plugins.jfreechart.SourceCategoryDataset$SourceHolder

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2003, by :
*     Corporate:
*         Astrium SAS
*         EADS CRC
*     Individual:
*         Nicolas Brodu
*
* $Id: SourceCategoryDataset.java,v 1.4 2006/02/15 18:29:06 cazenave Exp $
*
* Changes
* -------
* 05-Nov-2003 : Initial version (NB);
*
*/

package jsynoptic.plugins.jfreechart;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.jfree.data.AbstractDataset;
import org.jfree.data.CategoryDataset;

import simtools.data.DataException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceCollection;
import simtools.data.DataSourceListener;
import simtools.data.DataSourcePool;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;

/**
* A JFreeChart category data set, using data sources.
*/
public class SourceCategoryDataset extends AbstractDataset implements CategoryDataset, DataSourceListener, CategoryClassifierListener, EndNotificationListener {

  static final long serialVersionUID = 4732659452902199039L;
 
  public class SourceHolder implements Comparable {
    public DataSource source;
    public long startIndex;
    /** Name override. Null => use default*/
    public String name;
   
    /** How many data source entries in each category */
    protected int[] categoryCount;
    /** When set to false, categoryCount is recomputed on demand */
    public boolean needCompute;
   
   
    public SourceHolder(DataSource ds) {
      this(ds,0);
    }

    public SourceHolder(DataSource ds, long idx) {
      source = ds; startIndex = idx;
      needCompute = true;
    }
   
    public SourceHolder(DataSource ds, long idx, String name, int[] categoryCount, boolean needCompute) {
        this.name = name;
        source = ds; startIndex = idx;
        this.needCompute = needCompute;
        this.categoryCount = categoryCount;
    }
   
    /* (non-Javadoc)
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(Object o) {
      SourceHolder sh = (SourceHolder)o; // throws ClassCastException, but that's OK
      // compare our respective index in outer vector
      return SourceCategoryDataset.this.sources.indexOf(this) - SourceCategoryDataset.this.sources.indexOf(o);
    }
   
    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString() {
      if (name!=null) return name;
      String label = DataInfo.getLabel(source);
      if (label!=null) return label;
      return super.toString();
    }
   
   
    public int getCategoryValue(String category) {
      return getCategoryValue(SourceCategoryDataset.this.classifier.categories.indexOf(category));
    }
   
    public int getCategoryValue(int category) {
      if (needCompute) compute();
      return categoryCount[category];
    }
   
    /** Compute the number of data source entries in each catagory */
    public void compute() {
      reset();
      try {
        startIndex = source.computeStartIndex();
      } catch (UnsupportedOperation e1) {
        try {
          startIndex = source.getStartIndex();
        } catch (UnsupportedOperation e) {
          startIndex = 0;
        }
      }
      update();
      needCompute = false;
    }
   
    public void reset() {
      List list = SourceCategoryDataset.this.classifier.categories;
      categoryCount = new int[list.size()]// starts at 0, init by JVM
    }
   
    public void update() {
      List list = SourceCategoryDataset.this.classifier.categories;
      for (long l = startIndex; ;++l) {
        Object o;
        try {
          o = source.getValue(l);
        } catch (DataException e) {
          // stop when there is no more value
          startIndex = l; // And will start from here again at next update()
          break;
        }
        String s = SourceCategoryDataset.this.classifier.getMapper().getString(o);
        // Value not taken in account if it does not belong to a category
        if (s==null) continue;
        int idx = list.indexOf(s);
        if (idx==-1) continue;  
        categoryCount[idx]++;
      }
    }
   
  }

  protected transient Vector sources = new Vector(); // of Holders
  protected transient ArrayList holdersToUpdate = null; // of Holders
  protected transient boolean dirty = false;
 
  protected CategoryClassifier classifier;
 
  protected boolean notifySourceChange = false;
  protected DataInfo info = null;
 
  /**
   * @return Returns the mapper.
   */
  public CategoryClassifier getClassifier() {
    return classifier;
  }
  /**
   * @param mapper The mapper to set.
   */
  public void setClassifier(CategoryClassifier classifier) {
    if (this.classifier!=null) this.classifier.removeListener(this);
    this.classifier = classifier;
    if (this.classifier!=null) this.classifier.addListener(this);
    fireDatasetChanged();
  }
 
 
  public SourceCategoryDataset() {
    notifySourceChange = true;
  }

  public SourceCategoryDataset(DataSourceCollection dsc) {
    setDataSourceCollection(dsc);
    notifySourceChange = true;
  }

  public void setDataSourceCollection(DataSourceCollection dsc) {
    boolean notify = notifySourceChange;
    notifySourceChange = false;
    clear();
    info = dsc.getInformation();
    for (int i=0; i<dsc.size(); ++i) {
      addSource((DataSource)dsc.get(i));
    }
    notifySourceChange = notify;
    if (notifySourceChange) fireDatasetChanged();
  }

  public void addDataSourceCollection(DataSourceCollection dsc) {
    boolean notify = notifySourceChange;
    notifySourceChange = false;
    for (int i=0; i<dsc.size(); ++i) {
      addSource((DataSource)dsc.get(i));
    }
    notifySourceChange = notify;
    if (notifySourceChange) fireDatasetChanged();
  }

  public DataSource getSource(int i) {
    return ((SourceHolder)sources.get(i)).source;
  }

  public void addSource(DataSource ds) {
    addSource(ds,0);
  }
 
  public void addSource(DataSource ds, long index) {
    if (ds==null) return;
    sources.add(new SourceHolder(ds, index));
    ds.addListener(this);
    ds.addEndNotificationListener(this);
    if (notifySourceChange) fireDatasetChanged();
 

  public void removeSource(DataSource ds) {
    if (ds==null) return;
    ds.removeListener(this);
    ds.removeEndNotificationListener(this);
    for (Iterator it = sources.iterator(); it.hasNext();) {
      SourceHolder sh = (SourceHolder)it.next();
      if ((sh.source!=null) && sh.source.equals(ds)) {
        sh.source.removeListener(this);
        sh.source.removeEndNotificationListener(this);
        it.remove();
      }
    }
    if (notifySourceChange) fireDatasetChanged();
 

  public void removeSource(int i) {
    SourceHolder sh = (SourceHolder)sources.get(i);
    if (sh.source!=null) {
        sh.source.removeListener(this);
        sh.source.removeEndNotificationListener(this);
    }
    sources.remove(i);
    if (notifySourceChange) fireDatasetChanged();
 

  public void clear() {
    for (Iterator it = sources.iterator(); it.hasNext();) {
      SourceHolder sh = (SourceHolder)it.next();
      if (sh.source!=null) {
          sh.source.removeListener(this);
          sh.source.removeEndNotificationListener(this);
      }
      it.remove();
    }
    info = null;
    if (notifySourceChange) fireDatasetChanged();
  }

  /** Changes the name of the source entry at index i, overrides the default.
   * You can revert to the default name by setting the override to null
   * @param series the series for which to set a name override
   * @param name the new name
   */
  public void setName(int series, String name) {
    SourceHolder sh = (SourceHolder)sources.get(series);
    sh.name = name;
  }

  public String getName(int series) {
    SourceHolder sh = (SourceHolder)sources.get(series);
    return sh.toString();
  }
 
  public void setName(String name) {
    if (info==null) info = new DataInfo(name);
    else info.label = name;
  }

  public String getName() {
    if (info==null) return "";
    return info.label;
  }

 
// Category data set methods 
 
   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getRowKey(int)
  */
   public Comparable getRowKey(int row) {
     return (Comparable)sources.get(row);
   }

   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getRowIndex(java.lang.Comparable)
  */
   public int getRowIndex(Comparable key) {
     return sources.indexOf(key);
   }

   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getRowKeys()
  */
   public List getRowKeys() {
     return sources;
   }
  
   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getColumnKey(int)
  */
   public Comparable getColumnKey(int column) {
       if (classifier==null) return null;
       return (Comparable)classifier.categories.get(column);
   }

   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getColumnIndex(java.lang.Comparable)
  */
   public int getColumnIndex(Comparable key) {
       if (classifier==null) return -1;
       return classifier.categories.indexOf(key);
   }

   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getColumnKeys()
  */
   public List getColumnKeys() {
       if (classifier==null) return new Vector(); // empty
       return classifier.categories;
   }

   /* (non-Javadoc)
  * @see org.jfree.data.KeyedValues2D#getValue(java.lang.Comparable, java.lang.Comparable)
  */
   public Number getValue(Comparable rowKey, Comparable columnKey) {
       return new Integer(((SourceHolder)rowKey).getCategoryValue((String)columnKey));
   }

   /* (non-Javadoc)
  * @see org.jfree.data.Values2D#getRowCount()
  */
   public int getRowCount() {
     return sources.size();
   }

   /* (non-Javadoc)
  * @see org.jfree.data.Values2D#getColumnCount()
  */
   public int getColumnCount() {
       if (classifier==null) return 0;
     return classifier.categories.size();
   }

   /* (non-Javadoc)
  * @see org.jfree.data.Values2D#getValue(int, int)
  */
   public Number getValue(int row, int column) {
       return new Integer(((SourceHolder)sources.get(row)).getCategoryValue(column));
   }
 

// Bridge between listeners from different worlds

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceValueChanged(simtools.data.DataSource, long, long)
   */
  public void DataSourceValueChanged(DataSource ds, long minIndex, long maxIndex) {
    for (Iterator it = sources.iterator(); it.hasNext();) {
      SourceHolder sh = (SourceHolder)it.next();
      if (ds.equals(sh.source)) {
        if (sh.startIndex > minIndex) sh.needCompute = true; // lazy update
        else {
            if (holdersToUpdate == null) holdersToUpdate = new ArrayList();
            holdersToUpdate.add(sh);
        }
        dirty = true;
        break;
      }
    }
  }

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceIndexRangeChanged(simtools.data.DataSource, long, long)
   */
  public void DataSourceIndexRangeChanged(DataSource ds, long startIndex, long lastIndex) {
    for (Iterator it = sources.iterator(); it.hasNext();) {
      SourceHolder sh = (SourceHolder)it.next();
      if (ds.equals(sh.source)) {
        // if start index outside range, restart computations
        if ((sh.startIndex > lastIndex) || (sh.startIndex < startIndex)) {
          sh.reset();
          sh.startIndex = startIndex;
        }
        // Otherwise, just update with values not taken in account
          if (holdersToUpdate == null) holdersToUpdate = new ArrayList();
          holdersToUpdate.add(sh);
        dirty = true;
        break;
      }
    }
  }

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceInfoChanged(simtools.data.DataSource, simtools.data.DataInfo)
   */
  public void DataSourceInfoChanged(DataSource ds, DataInfo newInfo) {
    dirty = true; // update legend
  }

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceValueRangeChanged(simtools.data.DataSource)
   */
  public void DataSourceValueRangeChanged(DataSource ds) {
    // don't care, the mapper will do its job
  }

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceOrderChanged(simtools.data.DataSource, int)
   */
  public void DataSourceOrderChanged(DataSource ds, int newOrder) {
    // don't care at all
  }

  /* (non-Javadoc)
   * @see simtools.data.DataSourceListener#DataSourceReplaced(simtools.data.DataSource, simtools.data.DataSource)
   */
  public void DataSourceReplaced(DataSource oldData, DataSource newData) {
    for (int i=0; i<sources.size(); ++i) {
      SourceHolder sh = (SourceHolder)sources.get(i);
      if(sh.source==oldData){
        sh.source=newData;
        if(newData!=null){
          sh.source.addListener(this);
          sh.source.addEndNotificationListener(this);
            sh.compute();
        }
          oldData.removeListener(this);
          oldData.removeEndNotificationListener(this);
      }
    }
  }

  /* (non-Javadoc)
     * @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
     */
    public void notificationEnd(Object referer) {
    if (dirty) {
      if (holdersToUpdate!=null) {
          for (Iterator it = holdersToUpdate.iterator(); it.hasNext();) {
          SourceHolder sh = (SourceHolder)it.next();
          sh.update();
        }
            holdersToUpdate = null;
      }
        dirty = false;
        fireDatasetChanged();
    }
    }

  /* (non-Javadoc)
   * @see jsynoptic.plugins.jfreechart.CategoryClassifierListener#classifierModified(jsynoptic.plugins.jfreechart.CategoryClassifier)
   */
  public void classifierModified(CategoryClassifier classifier) {
    for (Iterator it = sources.iterator(); it.hasNext();)
      ((SourceHolder)it.next()).needCompute = true;
    fireDatasetChanged();
  }

 
//  Take care of serialisation. Special handling for datasources

  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
    out.defaultWriteObject();
    int n = sources.size();
    out.writeInt(n);
    for (int i=0; i<n; ++i) {
      SourceHolder sh = (SourceHolder)sources.get(i);
      DataSourcePool.global.writeDataSource(out, sh.source);
      out.writeLong(sh.startIndex);
      out.writeObject(sh.name);
    }
  }

  private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
    in.defaultReadObject();
    int n =in.readInt();
    sources = new Vector();
    for (int i=0; i<n; ++i) {
      SourceHolder sh;
      sources.add(sh = new SourceHolder(
        DataSourcePool.global.readDataSource(in),
        in.readLong()
      ));
      sh.name = (String)in.readObject();
      if (sh.source!=null) {
          sh.source.addListener(this);
          sh.source.addEndNotificationListener(this);
      }
    }
  }


  /* (non-Javadoc)
   * @see java.lang.Object#clone()
   */
  public Object clone() throws CloneNotSupportedException {
      SourceCategoryDataset c = (SourceCategoryDataset)super.clone();
      c.sources = new Vector();
      c.info = DataInfo.clone(info);
      // Deep copy, and correct handling of listeners
      for (Iterator it = sources.iterator(); it.hasNext();) {
          SourceHolder sh = (SourceHolder)it.next();
          c.sources.add(c.new SourceHolder(sh.source, sh.startIndex, sh.name, sh.categoryCount, sh.needCompute));
          if (sh.source != null) {
              sh.source.addListener(c);
              sh.source.addEndNotificationListener(c);
          }
      }
      return c;
  }

  /**
   * @return
   */
  public SourceCategoryDataset cloneSet() {
      try {
          return (SourceCategoryDataset)clone();
      } catch (CloneNotSupportedException e) {
          return null;
      }
  }
 
 
}

TOP

Related Classes of jsynoptic.plugins.jfreechart.SourceCategoryDataset$SourceHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.