/* * DataPointRecorderNew.java * * Created on Apr 18, 2014 5:57am */ package org.das2.components; import org.das2.dataset.DataSetUpdateEvent; import org.das2.dataset.VectorDataSet; import org.das2.dataset.DataSetUpdateListener; import org.das2.datum.DatumRange; import org.das2.datum.Units; import org.das2.datum.Datum; import org.das2.datum.DatumUtil; import org.das2.datum.TimeUtil; import org.das2.util.monitor.NullProgressMonitor; import org.das2.util.monitor.ProgressMonitor; import org.das2.components.propertyeditor.PropertyEditor; import org.das2.datum.format.DatumFormatter; import org.das2.system.DasLogger; import java.awt.BorderLayout; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.reflect.InvocationTargetException; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; import java.util.prefs.Preferences; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import org.das2.DasApplication; import org.das2.datum.DatumRangeUtil; import org.das2.datum.EnumerationUnits; import org.das2.datum.InconvertibleUnitsException; import org.das2.datum.UnitsUtil; import org.das2.event.DataPointSelectionEvent; import org.das2.qds.AbstractDataSet; import org.das2.qds.ArrayDataSet; import org.das2.qds.DDataSet; import org.das2.qds.DataSetOps; import org.das2.qds.DataSetUtil; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; import org.das2.qds.SparseDataSetBuilder; import org.das2.qds.ops.Ops; import org.das2.qds.util.DataSetBuilder; /** * DataPointRecorderNew is a GUI for storing data points selected by the user. * This is the old recorder but: * 1. uses QDataSet to handle the data. No more strange internal object. * 2. allows the columns to be declared explicitly by code, and data is merged in by name. * @deprecated use DataPointRecorder, which has the same functionality as this "new" code. DataPointRecorderNew is left because of use in Jython scripts. * @author jbf */ public class DataPointRecorderNew extends JPanel { /** * width of time column */ private static final int TIME_WIDTH = 180; protected JTable table; protected JScrollPane scrollPane; protected JButton updateButton; protected final transient List dataPoints; private int selectRow; // this row needs to be selected after the update. /** * units[index]==null if HashMap contains non-datum object. */ protected transient Units[] unitsArray; protected transient Units[] defaultUnitsArray; /** * array of names that are also the column headers. */ protected transient String[] namesArray; protected transient String[] defaultNamesArray; private double[] defaultsArray; /** * bundleDescriptor for the dataset. */ private transient QDataSet bundleDescriptor; protected AbstractTableModel myTableModel; private File saveFile; private boolean modified; private final JLabel messageLabel; private boolean active = true; // false means don't fire updates private transient Preferences prefs = Preferences.userNodeForPackage(this.getClass()); private static final Logger logger = DasLogger.getLogger(DasLogger.GUI_LOG); private final JButton clearSelectionButton; private final Object namesArrayLock; private class MyTableModel extends AbstractTableModel { @Override public int getColumnCount() { synchronized (namesArrayLock) { return namesArray==null ? 0 : namesArray.length; } } @Override public String getColumnName(int j) { synchronized (namesArrayLock) { String result = namesArray[j]; if (unitsArray[j] != null) { if ( unitsArray[j] instanceof EnumerationUnits ) { result += "(ordinal)"; } else if ( UnitsUtil.isTimeLocation( unitsArray[j] ) ) { result += "(UTC)"; } else if ( unitsArray[j]==Units.dimensionless ) { // add nothing. } else { result += "(" + unitsArray[j] + ")"; } } return result; } } @Override public Class getColumnClass(int columnIndex) { return Datum.class; } @Override public int getRowCount() { int nrow = dataPoints.size(); return nrow; } @Override public Object getValueAt(int i, int j) { QDataSet x; synchronized (dataPoints) { x= (QDataSet) dataPoints.get(i); } if (j < x.length()) { Datum d = unitsArray[j].createDatum(x.value(j)); DatumFormatter format = d.getFormatter(); return format.format(d, unitsArray[j]); } else { throw new IndexOutOfBoundsException("no such column"); } } } /** * delete all the points within the interval. This was introduced to support the * case where we are going to reprocess an interval, as with the * RBSP digitizer. * * @param range range to delete, end time is exclusive. */ public void deleteInterval( DatumRange range ) { if ( !sorted ) { throw new IllegalArgumentException("data must be sorted"); } else { synchronized ( dataPoints ) { Comparator comp= new Comparator() { @Override public int compare(Object o1, Object o2) { Datum d1; if ( o1 instanceof QDataSet ) { d1= DataSetUtil.asDatum(((QDataSet)o1).slice(0)); } else if ( o1 instanceof Datum ) { d1= (Datum)o1; } else { throw new IllegalArgumentException("expected Datum or QDataSet"); } Datum d2; if ( o2 instanceof QDataSet ) { d2= DataSetUtil.asDatum(((QDataSet)o2).slice(0)); } else if ( o2 instanceof Datum ) { d2= (Datum)o2; } else { throw new IllegalArgumentException("expected Datum or QDataSet"); } return d1.compareTo(d2); } }; int index1= Collections.binarySearch( dataPoints, range.min(), comp ); if ( index1<0 ) index1= ~index1; int index2= Collections.binarySearch( dataPoints, range.max(), comp ); if ( index2<0 ) index2= ~index2; if ( index1==index2 ) return; int[] arr= new int[ index2-index1 ]; for ( int i=0; i=0; i-- ) { dataPoints.remove(selectedRows[i]); } modified = true; } updateClients(); updateStatus(); if ( active ) { fireDataSetUpdateListenerDataSetUpdated(new DataSetUpdateEvent(this,getDataSet())); } myTableModel.fireTableDataChanged(); } /** * returns a data set of the table data. * @return a data set of the table data. */ public QDataSet getDataSet() { DataSetBuilder b; synchronized ( dataPoints ) { if (dataPoints.isEmpty()) { return null; } else { b= new DataSetBuilder(2,dataPoints.size(),bundleDescriptor.length()); b.putProperty( QDataSet.BUNDLE_1, bundleDescriptor ); for (int irow = 0; irow < dataPoints.size(); irow++) { QDataSet dp = dataPoints.get(irow); b.putValues( -1, dp, dp.length() ); b.nextRecord(); } } } return b.getDataSet(); } /** * returns a data set of the selected table data. Warning: this used to * return a bundle dataset with Y,plane1,plane2,etc that had DEPEND_0 for X. * This now returns a bundle ds[n,m] where m is the number of columns and * n is the number of records. * @return a data set of the selected table data. * @see #select(org.das2.datum.DatumRange, org.das2.datum.DatumRange) which selects part of the dataset. */ public QDataSet getSelectedDataSet() { int[] selectedRows; List ldataPoints; QDataSet lbundleDescriptor; synchronized (this) { selectedRows= getSelectedRowsInModel(); ldataPoints= new ArrayList( dataPoints ); lbundleDescriptor= bundleDescriptor; } DataSetBuilder b; if (selectedRows.length == 0) { return null; } else { b= new DataSetBuilder(2,selectedRows.length,lbundleDescriptor.length()); b.putProperty( QDataSet.BUNDLE_1, lbundleDescriptor ); for (int i = 0; i < selectedRows.length; i++) { int irow = selectedRows[i]; if ( irow selectMe = new ArrayList(); int iclosest= -1; Datum closestDist=null; for (int i = 0; i < dataPoints.size(); i++) { QDataSet p = (QDataSet) dataPoints.get(i); if ( xrange.contains( DataSetUtil.asDatum(p.slice(0)) ) && yrange.contains(DataSetUtil.asDatum(p.slice(1))) ) { selectMe.add( i ); } if ( closestDist==null || DataSetUtil.asDatum((QDataSet)p.slice(0)).subtract(mid).abs().lt( closestDist ) ) { iclosest= i; closestDist= DataSetUtil.asDatum((QDataSet)p.slice(0)).subtract(mid).abs(); } } if ( iclosest!=-1 && selectMe.isEmpty() ) { selectMe= Collections.singletonList(iclosest); } table.getSelectionModel().clearSelection(); for (int i = 0; i < selectMe.size(); i++) { int iselect = selectMe.get(i); table.getSelectionModel().addSelectionInterval(iselect, iselect); } if ( selectMe.size()>0 ) { int iselect= selectMe.get(0); table.scrollRectToVisible(new Rectangle(table.getCellRect( iselect, 0, true)) ); } } } /** * This should be called off the event thread. * @param file * @throws IOException */ public void saveToFile(File file) throws IOException { List dataPoints1; String[] lnamesArray; Units[] lunitsArray; synchronized (this) { lnamesArray= Arrays.copyOf(namesArray,namesArray.length); lunitsArray= Arrays.copyOf(unitsArray,unitsArray.length); dataPoints1= new ArrayList( dataPoints ); } FileOutputStream out = new FileOutputStream(file); try (BufferedWriter r = new BufferedWriter(new OutputStreamWriter(out))) { StringBuilder header = new StringBuilder(); //header.append("## "); // don't use comment characters so that labels and units are used in Autoplot's ascii parser. for (int j = 0; j < lnamesArray.length; j++) { Units units= lunitsArray[j]; String sunits; if ( UnitsUtil.isTimeLocation(units) ) { sunits= "(UTC)"; } else if ( UnitsUtil.isOrdinalMeasurement(units) ) { sunits= "(ordinal)"; } else if ( units==Units.dimensionless ) { sunits= ""; } else { sunits= "("+units+")"; } header.append( lnamesArray[j] ).append(sunits); if ( j 500) { mon = DasProgressPanel.createFramed("reading file"); } // tabs detected in file. String delim= ","; mon.setTaskSize(lineCount); mon.started(); int linenum = 0; final List records= new ArrayList<>(1440); for (String line = r.readLine(); line != null; line = r.readLine()) { linenum++; if (mon.isCancelled()) { break; } line= line.trim(); if ( line.length()==0 ) { continue; } mon.setTaskProgress(linenum); if (line.startsWith("## ") || line.length()>0 && Character.isJavaIdentifierStart( line.charAt(0) ) ) { if ( unitsArray1!=null ) continue; while ( line.startsWith("#") ) line = line.substring(1); if ( !line.contains(delim) ) delim= "\t"; if ( !line.contains(delim) ) delim= "\\s+"; String[] s = line.split(delim); for ( int i=0; i statusHolder= new HashMap<>(); Runnable run= new Runnable() { @Override public void run() { jj.setFileFilter( new FileFilter() { @Override public boolean accept(File pathname) { if ( pathname.isDirectory() ) return true; String fn= pathname.getName(); return fn.endsWith(".dat") || fn.endsWith(".txt"); } @Override public String getDescription() { return "Flat Ascii Tables"; } }); String lastFileString = prefs.get("components.DataPointRecorder.lastFileSave", ""); if (lastFileString.length()>0) { File lastFile= new File(lastFileString); jj.setSelectedFile(lastFile); } statusHolder.put( "status", jj.showSaveDialog(DataPointRecorderNew.this) ); } }; if ( SwingUtilities.isEventDispatchThread() ) { run.run(); } else { try { SwingUtilities.invokeAndWait(run); } catch (InterruptedException | InvocationTargetException ex) { logger.log(Level.SEVERE, null, ex); } } int status= statusHolder.get("status") ; if (status == JFileChooser.APPROVE_OPTION) { try { File pathname= jj.getSelectedFile(); if ( !( pathname.toString().endsWith(".dat") || pathname.toString().endsWith(".txt") ) ) { pathname= new File( pathname.getAbsolutePath() + ".dat" ); } DataPointRecorderNew.this.saveFile = pathname; saveToFile(saveFile); //messageLabel.setText("saved data to "+saveFile); } catch (IOException e1) { DasApplication.getDefaultApplication().getExceptionHandler().handle(e1); return false; } } else if ( status == JFileChooser.CANCEL_OPTION ) { return false; } return true; } public boolean save() { if (saveFile == null) { return saveAs(); } else { try { saveToFile(saveFile); return true; } catch (IOException ex) { DasApplication.getDefaultApplication().getExceptionHandler().handle(ex); return false; } } } /** * shows the current name for the file. * @return the current name for the file. */ public File getCurrentFile() { return this.saveFile; } /** * return true if the file was saved or "don't save" was pressed by the user. * @return true if the file was saved or "don't save" was pressed by the user. */ public boolean saveBeforeExit( ) { if ( this.modified ) { int i= JOptionPane.showConfirmDialog( this, "Save changes before exiting?"); switch (i) { case JOptionPane.OK_OPTION: return save(); case JOptionPane.CANCEL_OPTION: return false; default: return true; } } else { return true; } } private Action getLoadAction() { return new AbstractAction("Open...") { @Override public void actionPerformed(ActionEvent e) { if (checkModified(e)) { JFileChooser jj = new JFileChooser(); String lastFileString = prefs.get("components.DataPointRecorder.lastFileLoad", ""); if ( lastFileString.length()>0 ) { File lastFile; lastFile = new File(lastFileString); jj.setSelectedFile(lastFile); } int status = jj.showOpenDialog(DataPointRecorderNew.this); if (status == JFileChooser.APPROVE_OPTION) { final File loadFile = jj.getSelectedFile(); prefs.put("components.DataPointRecorder.lastFileLoad", loadFile.toString()); Runnable run = new Runnable() { @Override public void run() { try { loadFromFile(loadFile); updateStatus(); } catch (IOException e) { DasApplication.getDefaultApplication().getExceptionHandler().handle(e); } } }; new Thread(run).start(); } } } }; } /** * returns true if the operation should continue, false * if not, meaning the user pressed cancel. */ private boolean checkModified(ActionEvent e) { if (modified) { int n = JOptionPane.showConfirmDialog( DataPointRecorderNew.this, "Current work has not been saved.\n Save first?", "Save work first", JOptionPane.YES_NO_CANCEL_OPTION); if (n == JOptionPane.YES_OPTION) { getSaveAction().actionPerformed(e); } return (n != JOptionPane.CANCEL_OPTION); } else { return true; } } private Action getNewAction() { return new AbstractAction("New") { @Override public void actionPerformed(ActionEvent e) { if (checkModified(e)) { dataPoints.clear(); saveFile = null; updateStatus(); updateClients(); table.repaint(); } } }; } private Action getPropertiesAction() { return new AbstractAction("Properties") { @Override public void actionPerformed(ActionEvent e) { new PropertyEditor(DataPointRecorderNew.this).showDialog(DataPointRecorderNew.this); } }; } private Action getUpdateAction() { return new AbstractAction("Update") { @Override public void actionPerformed(ActionEvent e) { update(); } }; } /** * Notify listeners that the dataset has updated. Pressing the "Update" * button calls this. */ public void update() { fireDataSetUpdateListenerDataSetUpdated(new DataSetUpdateEvent(this)); fireSelectedDataSetUpdateListenerDataSetUpdated(new DataSetUpdateEvent(this)); } /** Creates a new instance of DataPointRecorder */ public DataPointRecorderNew() { super(); this.namesArrayLock = new Object(); dataPoints = new ArrayList(); myTableModel = new MyTableModel(); this.setLayout(new BorderLayout()); JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); fileMenu.add(new JMenuItem(getNewAction())); fileMenu.add(new JMenuItem(getLoadAction())); fileMenu.add(new JMenuItem(getSaveAction())); fileMenu.add(new JMenuItem(getSaveAsAction())); menuBar.add(fileMenu); JMenu editMenu = new JMenu("Edit"); editMenu.add(new JMenuItem(getPropertiesAction())); editMenu.add( new JMenuItem( new AbstractAction("Clear Table Sorting") { @Override public void actionPerformed(ActionEvent e) { table.setAutoCreateRowSorter(false); table.setAutoCreateRowSorter(true); } } ) ); JMenuItem mi; mi= new JMenuItem( new AbstractAction("Delete Selected Items") { @Override public void actionPerformed(ActionEvent e) { int[] selectedRows = getSelectedRowsInModel(); deleteRows(selectedRows); } } ); editMenu.add( mi ); menuBar.add(editMenu); this.add(menuBar, BorderLayout.NORTH); table = new JTable(myTableModel); table.setAutoCreateRowSorter(true); // Java 1.6 table.getTableHeader().setReorderingAllowed(true); table.setColumnModel( new DefaultTableColumnModel() { @Override public int getColumnCount() { synchronized ( namesArrayLock ) { return super.getColumnCount(); //To change body of generated methods, choose Tools | Templates. } } @Override public TableColumn getColumn(int columnIndex) { synchronized ( namesArrayLock ) { return super.getColumn(columnIndex); //To change body of generated methods, choose Tools | Templates. } } }); table.setRowSelectionAllowed(true); table.addMouseListener(new DataPointRecorderNew.MyMouseAdapter(table)); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { fireSelectedDataSetUpdateListenerDataSetUpdated(new DataSetUpdateEvent(DataPointRecorderNew.this)); int selected = table.getSelectedRow(); // we could do a better job here if (selected > -1) { QDataSet dp = dataPoints.get(selected); //System.err.println(dp); Datum x= DataSetUtil.asDatum( dp.slice(0) ); Datum y= DataSetUtil.asDatum( dp.slice(1) ); DataPointSelectionEvent e2 = new DataPointSelectionEvent(DataPointRecorderNew.this, x, y ); e2.setDataSet(dp); fireDataPointSelectionListenerDataPointSelected(e2); } } }); scrollPane = new JScrollPane(table); this.add(scrollPane, BorderLayout.CENTER); JPanel controlStatusPanel = new JPanel(); controlStatusPanel.setLayout(new BoxLayout(controlStatusPanel, BoxLayout.Y_AXIS)); final JPanel controlPanel = new JPanel(); controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS)); updateButton = new JButton(getUpdateAction()); updateButton.setVisible(false); updateButton.setEnabled(false); controlPanel.add(updateButton); clearSelectionButton = new JButton( getClearSelectionAction() ); controlPanel.add( clearSelectionButton ); messageLabel = new JLabel("ready"); messageLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT); controlStatusPanel.add(messageLabel); controlPanel.setAlignmentX(JLabel.LEFT_ALIGNMENT); controlStatusPanel.add(controlPanel); this.add(controlStatusPanel, BorderLayout.SOUTH); } public static DataPointRecorderNew createFramed() { DataPointRecorderNew result; JFrame frame = new JFrame("Data Point Recorder"); result = new DataPointRecorderNew(); frame.getContentPane().add(result); frame.pack(); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); return result; } /** * update fires off the TableDataChanged, and sets the current selected * row if necessary. */ private void updateClients() { if (active) { myTableModel.fireTableDataChanged(); if (selectRow != -1 && table.getRowCount()>selectRow ) { table.setRowSelectionInterval(selectRow, selectRow); table.scrollRectToVisible(table.getCellRect(selectRow, 0, true)); selectRow = -1; } table.repaint(); } } /** * update the status label "(modified)" */ private void updateStatus() { String statusString = (saveFile == null ? "" : (String.valueOf(saveFile) + " ")) + (modified ? "(modified)" : ""); String t= messageLabel.getText(); if ( !statusString.equals(t) ) { messageLabel.setText(statusString); } } private transient Comparator comparator= new Comparator() { @Override public int compare(Object o1, Object o2) { if ( o1 instanceof QDataSet && o2 instanceof QDataSet ) { QDataSet qds1= (QDataSet)o1; QDataSet qds2= (QDataSet)o2; return DataSetUtil.asDatum(qds1.slice(0)).gt( DataSetUtil.asDatum( qds2.slice(0) ) ) ? 1 : -1; } else { throw new IllegalArgumentException("expected qdatasets"); } } }; /** * explicitly declare the number of columns. Call this and then * setColumn to define each column. * @param count the number of columns. */ public void setColumnCount( int count ) { namesArray= new String[count]; unitsArray= new Units[count]; defaultsArray= new double[count]; for ( int i=0; i=namesArray.length ) { throw new IndexOutOfBoundsException("column index is out of bounds (and 0 is the first column)"); } namesArray[i]= name; unitsArray[i]= units; defaultsArray[i]= deft.doubleValue(units); } /** * identify the name and unit for each column. * @param i the column number * @param name a Java identifier for the column, e.g. "StartTime" * @param units units units for the column, or null for dimensionless. * @param deft default value to use when data is not provided, which must be parseable by units. * @throws java.text.ParseException */ public void setColumn( int i, String name, Units units, String deft ) throws ParseException { if ( units==null ) units= Units.dimensionless; if ( units instanceof EnumerationUnits ) { setColumn( i, name, units, ((EnumerationUnits)units).createDatum(deft) ); } else { setColumn( i, name, units, units.parse(deft) ); } } /** * identify the name and unit for each column. * @param i the column number * @param name a Java identifier for the column, e.g. "StartTime" * @param units units units for the column, or null for dimensionless. * @param deft default value to use when data is not provided. */ public void setColumn( int i, String name, Units units, double deft ) { if ( units==null ) units= Units.dimensionless; setColumn( i, name, units, units.createDatum(deft) ); } /** * insert the point into the data points. If the dataset is sorted, then we * replace any point that is within X_LIMIT of the point. * @param newPoint */ private void insertInternal( QDataSet newPoint ) { int newSelect; if ( newPoint.rank()==2 && newPoint.length()==1 ) { newPoint= newPoint.slice(0); } // make sure all the units are correct by converting them as they come in. ArrayDataSet mnp; if ( defaultsArray!=null ) { mnp= DDataSet.wrap( Arrays.copyOf(defaultsArray,defaultsArray.length) ); } else { mnp= DDataSet.createRank1(namesArray.length); } QDataSet bds= (QDataSet) newPoint.property(QDataSet.BUNDLE_0); for ( int i=0; i planes ) { if ( planes==null ) planes= Collections.emptyMap(); DDataSet rec= DDataSet.createRank1( 2 + planes.size() ); SparseDataSetBuilder bdsb= new SparseDataSetBuilder(2); int ii= 0; bdsb.putProperty( QDataSet.NAME, ii, "x" ); bdsb.putProperty( QDataSet.UNITS, ii, x.getUnits() ); rec.putValue( ii, x.doubleValue( x.getUnits() )); ii++; bdsb.putProperty( QDataSet.NAME, ii, "y" ); bdsb.putProperty( QDataSet.UNITS, ii, y.getUnits() ); rec.putValue( ii, y.doubleValue( y.getUnits() )); ii++; for ( Entry e : planes.entrySet() ) { bdsb.putProperty( QDataSet.NAME, ii, e.getKey() ); Object o= e.getValue(); Units theu; if ( o instanceof String ) { Units eu= EnumerationUnits.create("default"); theu= eu; try { rec.putValue( ii, theu.parse((String)o).doubleValue(theu) ); } catch (ParseException ex) { rec.putValue( ii, -1 ); // fill } } else if ( o instanceof Datum ) { theu= ((Datum)o).getUnits(); rec.putValue( ii, ((Datum)o).doubleValue(theu) ); } else if ( o instanceof Number ) { theu= Units.dimensionless; rec.putValue( ii, ((Number)o).doubleValue() ); } else if ( o instanceof QDataSet ) { theu= SemanticOps.getUnits((QDataSet)o); rec.putValue( ii, ((QDataSet)o).value() ); } else { throw new IllegalArgumentException("value must be String, Datum, DataSet or Number"); } bdsb.putProperty( QDataSet.UNITS, ii, theu ); ii++; } bdsb.setLength(ii); QDataSet bds= bdsb.getDataSet(); rec.putProperty(QDataSet.BUNDLE_0,bds); addDataPoint( rec ); } /** * add the record to the collection of records. This should be a * rank 1 bundle or 1-record rank 2 bundle. *
{@code
     *dpr=DataPointRecorder()
     *dpr.addDataPoint( createEvent( '2014-04-23/P1D', 0xFF0000, 'alert' ) )
     *}
* * @param rec rank 1 qdataset, or 1-record rank 2 dataset (ds[1,n]) */ public void addDataPoint( QDataSet rec ) { if ( rec.rank()==2 && rec.length()==1 ) { rec= rec.slice(0); // Jython createEvent produces rank 2 dataset. } synchronized (dataPoints) { if (dataPoints.isEmpty()) { QDataSet bds= (QDataSet) rec.property( QDataSet.BUNDLE_0 ); if ( bds==null ) { SparseDataSetBuilder bdsb= new SparseDataSetBuilder(2); Units u= SemanticOps.getUnits(rec); for ( int i=0;i0 ) { // || selectedListenerListCount>0 ) { updateButton.setEnabled(true); updateButton.setVisible(true); updateButton.setToolTipText(null); return true; } else { updateButton.setEnabled(false); updateButton.setToolTipText("no listeners. See File->Save to save table."); updateButton.setVisible(false); return false; } } private javax.swing.event.EventListenerList listenerList1 = new javax.swing.event.EventListenerList(); public void addDataSetUpdateListener(org.das2.dataset.DataSetUpdateListener listener) { listenerList1.add(org.das2.dataset.DataSetUpdateListener.class, listener); checkUpdateEnable(); } public void removeDataSetUpdateListener(org.das2.dataset.DataSetUpdateListener listener) { listenerList1.remove(org.das2.dataset.DataSetUpdateListener.class, listener); checkUpdateEnable(); } private void fireDataSetUpdateListenerDataSetUpdated(org.das2.dataset.DataSetUpdateEvent event) { Object[] listeners= listenerList1.getListenerList(); for (int i = listeners.length - 2; i >=0; i-= 2) { if (listeners[i] == org.das2.dataset.DataSetUpdateListener.class) { ((org.das2.dataset.DataSetUpdateListener) listeners[i + 1]).dataSetUpdated(event); } } } /** * the selection are the highlighted points in the table. Listeners can grab this data and do something with the * dataset. */ private javax.swing.event.EventListenerList selectedListenerList = new javax.swing.event.EventListenerList(); public void addSelectedDataSetUpdateListener(org.das2.dataset.DataSetUpdateListener listener) { selectedListenerList.add(org.das2.dataset.DataSetUpdateListener.class, listener); checkUpdateEnable(); } public void removeSelectedDataSetUpdateListener(org.das2.dataset.DataSetUpdateListener listener) { selectedListenerList.remove(org.das2.dataset.DataSetUpdateListener.class, listener); checkUpdateEnable(); } private void fireSelectedDataSetUpdateListenerDataSetUpdated(org.das2.dataset.DataSetUpdateEvent event) { Object[] listeners= selectedListenerList.getListenerList(); for ( int i = listeners.length - 2; i >=0; i-=2 ) { if (listeners[i] == org.das2.dataset.DataSetUpdateListener.class) { ((org.das2.dataset.DataSetUpdateListener) listeners[i + 1]).dataSetUpdated(event); } } } /** * Holds value of property sorted. */ private boolean sorted = true; /** * Getter for property sorted. * @return Value of property sorted. */ public boolean isSorted() { return this.sorted; } /** * Setter for property sorted. * @param sorted New value of property sorted. */ public void setSorted(boolean sorted) { this.sorted = sorted; } /** * Registers DataPointSelectionListener to receive events. * @param listener The listener to register. */ public void addDataPointSelectionListener(org.das2.event.DataPointSelectionListener listener) { listenerList1.add(org.das2.event.DataPointSelectionListener.class, listener); } /** * Removes DataPointSelectionListener from the list of listeners. * @param listener The listener to remove. */ public void removeDataPointSelectionListener(org.das2.event.DataPointSelectionListener listener) { listenerList1.remove(org.das2.event.DataPointSelectionListener.class, listener); } /** * Notifies all registered listeners about the event. * * @param event The event to be fired */ private void fireDataPointSelectionListenerDataPointSelected(org.das2.event.DataPointSelectionEvent event) { Object[] listeners= listenerList1.getListenerList(); logger.fine("firing data point selection event"); for (int i = listeners.length - 2; i >= 0; i -= 2 ) { if (listeners[i] == org.das2.event.DataPointSelectionListener.class) { ((org.das2.event.DataPointSelectionListener) listeners[i + 1]).dataPointSelected(event); } } } /** * Holds value of property xTagWidth. */ private Datum xTagWidth = Datum.create(0); /** * Getter for property xTagWidth. When xTagWidth is zero, * this implies there is no binning. * @return Value of property xTagWidth. */ public Datum getXTagWidth() { return this.xTagWidth; } /** * bins for the data, when xTagWidth is non-zero. * @param xTagWidth New value of property xTagWidth. */ public void setXTagWidth(Datum xTagWidth) { this.xTagWidth = xTagWidth; } /** * Holds value of property snapToGrid. */ private boolean snapToGrid = false; /** * Getter for property snapToGrid. * @return Value of property snapToGrid. */ public boolean isSnapToGrid() { return this.snapToGrid; } /** * Setter for property snapToGrid. true indicates the xtag will be reset * so that the tags are equally spaced, each xTagWidth apart. * @param snapToGrid New value of property snapToGrid. */ public void setSnapToGrid(boolean snapToGrid) { this.snapToGrid = snapToGrid; } /** * return true when the data point recorder has been modified. * @return true when the data point recorder has been modified. */ public boolean isModified() { return modified; } }