package org.autoplot.jythonsupport.ui; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TooManyListenersException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.Timer; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import org.das2.datum.DatumRange; import org.das2.datum.DatumRangeUtil; import org.das2.datum.EnumerationUnits; import org.das2.util.LoggerManager; import org.das2.util.monitor.NullProgressMonitor; import org.python.parser.ast.Assign; import org.python.parser.ast.Attribute; import org.python.parser.ast.Call; import org.python.parser.ast.Module; import org.python.parser.ast.Name; import org.python.parser.ast.Num; import org.python.parser.ast.Str; import org.python.parser.ast.UnaryOp; import org.python.parser.ast.exprType; import org.das2.qds.DataSetUtil; import org.das2.qds.QDataSet; import org.autoplot.datasource.AutoplotSettings; import org.autoplot.datasource.DataSetURI; import org.autoplot.datasource.DataSource; import org.autoplot.datasource.DataSourceFactory; import org.autoplot.datasource.DataSourceUtil; import org.autoplot.datasource.TimeRangeTool; import org.autoplot.datasource.capability.TimeSeriesBrowse; import org.das2.qds.ops.Ops; import org.python.core.PyException; import org.python.parser.ast.BinOp; /** * GUI for specifying mashups, where a number of * data sets are loaded and combined. These are implemented as small * jython scripts, consisting only of declarations and an expression. * @author jbf */ public class DataMashUp extends javax.swing.JPanel { private static final Logger logger = LoggerManager.getLogger("jython.mashup"); private static final String LABEL_DIRECTIONS = "Double-click on the name to set the data set. Shift-click for popup plot."; /** * when a URI results in an exception */ private static final QDataSet ERROR_DS= DataSetUtil.asDataSet( new EnumerationUnits("DataMashUp").createDatum("*Fail*") ); /** * when a data source returns null. */ private static final QDataSet NULL_DS= DataSetUtil.asDataSet( new EnumerationUnits("DataMashUp").createDatum("*Null*") ); /** * set the list of URIs. * @param uris a list of URIs. */ public void setUris( List uris ) { this.namedURIListTool1.setUris( uris ); } /** * set the ids for each of the URIs. * @param ids list of Java identifiers. */ public void setIds( List ids ) { this.namedURIListTool1.setIds( ids ); List isAuto= new ArrayList<>(ids.size()); for ( int i=0; i: "+v.substring(i+2)+""; label.setText(newv); } return label; } }; /** * Creates new form DataMashUp */ public DataMashUp() { initComponents(); List allItems= new ArrayList<>(); List lsms= new ArrayList<>(); lsms.add(mathematicsList); lsms.add(datasetList); lsms.add(filtersList); lsms.add(scratchList); for ( int i=0; i< lsms.size(); i++ ) { JList jc= (JList)lsms.get(i); for ( int j=0; j0 ) { dlm.addElement(s); } } allList.setModel( dlm ); timeRangeRecentComboBox.setPreferenceNode( "timerange" ); namedURIListTool1.setDataMashUp(this); namedURIListTool1.addPropertyChangeListener( NamedURIListTool.PROP_TIMERANGE, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { timeRangeRecentComboBox.setText( namedURIListTool1.getTimeRange().toString() ); } }); DragSource dragSource = DragSource.getDefaultDragSource(); DropTarget dropTarget = new DropTarget(); try { dropTarget.addDropTargetListener(createTreeDropTargetListener()); } catch (TooManyListenersException ex) { logger.log(Level.SEVERE, null, ex); } expressionTree.setDropTarget(dropTarget); DropTarget listDropTarget= new DropTarget(); try { listDropTarget.addDropTargetListener( createListDropTargetListener() ); } catch (TooManyListenersException ex ) { logger.log(Level.SEVERE, null, ex); } scratchList.setDropTarget(listDropTarget); dragSource.createDefaultDragGestureRecognizer(expressionTree, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); // add all jLists dragSource.createDefaultDragGestureRecognizer(mathematicsList, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); dragSource.createDefaultDragGestureRecognizer(datasetList, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); dragSource.createDefaultDragGestureRecognizer(filtersList, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); dragSource.createDefaultDragGestureRecognizer( scratchList, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); dragSource.createDefaultDragGestureRecognizer( allList, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); dragSource.createDefaultDragGestureRecognizer( namedURIListTool1, DnDConstants.ACTION_COPY_OR_MOVE, createDragGestureListener() ); mathematicsList.setCellRenderer( myListCellRenderer ); datasetList.setCellRenderer( myListCellRenderer ); filtersList.setCellRenderer( myListCellRenderer ); scratchList.setCellRenderer( myListCellRenderer ); allList.setCellRenderer( myListCellRenderer ); String data = "ds"; TreePath tp= new TreePath( ( (DefaultMutableTreeNode) expressionTree.getModel().getRoot() ).getPath() ); doDrop(data,tp); Runnable run= () -> { backFromFile(); }; new Thread(run).start(); } private boolean isInfix( String op ) { switch (op) { case "and": case "or": //case "add": //case "multiply": //case "subtract": //case "divide": //case "pow": return true; default: return false; } } /** * return the infix expression for the tree. * @param m the tree, which should have two children. * @param o the root of the tree, which is an operator like "and" or "multiply" * @return the Jython code for the tree. */ private String getInfix( DefaultTreeModel m, Object o) { String op= o.toString(); DefaultMutableTreeNode n= (DefaultMutableTreeNode)o; switch (op) { case "and": return getJython( m, m.getChild( n, 0 ) ) + ".and(" + getJython( m, m.getChild( n, 1 ) ) +")"; case "or": return getJython( m, m.getChild( n, 0 ) ) + ".or(" + getJython( m, m.getChild( n, 1 ) ) +")"; case "multiply": return getJython( m, m.getChild( n, 0 ) ) + "*" + getJython( m, m.getChild( n, 1 ) ); case "add": return getJython( m, m.getChild( n, 0 ) ) + "+" + getJython( m, m.getChild( n, 1 ) ); case "divide": return getJython( m, m.getChild( n, 0 ) ) + "/" + getJython( m, m.getChild( n, 1 ) ); case "subtract": return getJython( m, m.getChild( n, 0 ) ) + "-" + getJython( m, m.getChild( n, 1 ) ); case "pow": return getJython( m, m.getChild( n, 0 ) ) + "**" + getJython( m, m.getChild( n, 1 ) ); default: return null; } } /** * return the Jython expression for this tree. * @param m the tree * @param n the node, typically the root of the tree (maybe always)? * @return the Jython code for the tree. */ private String getJython( DefaultTreeModel m, Object n ) { if ( m.isLeaf(n) ) { return n.toString(); } else { String sn= n.toString(); int iparen= sn.indexOf("("); if ( iparen>-1 ) sn= sn.substring(0,iparen); int nchild= m.getChildCount(n); if ( isInfix(sn) && nchild==2 ) { String alt= getInfix(m, n); if ( alt!=null ) { if ( m.getRoot()==n ) { return alt; } else { return "("+ alt + ")" ; } } else { return getJython( m, m.getChild( n, 0 ) ) + "."+sn+"("+ getJython( m, m.getChild(n,1) ) +")" ; } } else { StringBuilder t= new StringBuilder( sn + "(" ); for ( int i=0; i0 ) t.append(","); t.append( getJython( m, m.getChild( n, i ) ) ); } t.append(")"); return t.toString(); } } } /** * return the mashup as a jython inline script. * @return the mashup as a jython inline script. */ public String getAsJythonInline() { StringBuilder b= new StringBuilder("vap+inline:"); b.append( namedURIListTool1.getAsJythonInline() ); b.append( getJythonSynchronize("&") ); DefaultTreeModel m= (DefaultTreeModel) expressionTree.getModel(); b.append( getJython( m, m.getRoot() ) ); String timerange= timeRangeRecentComboBox.getText(); if ( timeRangeRecentComboBox.isEnabled() ) { b.append("&timerange=").append(timerange.trim().replaceAll(" ","+") ); } return b.toString(); } private StringBuilder getJythonSynchronize(String delim) { StringBuilder b= new StringBuilder(); if ( synchronizeCB.isSelected() ) { String[] ids= namedURIListTool1.getIds(); if ( ids.length>2 ) { StringBuilder list=new StringBuilder("("); list.append(ids[1]); for ( int i=2; i datasets, List usedDatasets) { if ( et instanceof Name ) { String name= ((Name)et).id; if ( datasets.contains(name) || datasets.isEmpty() || name.equals("None") ) { parent.insert( new DefaultMutableTreeNode( name ), i ); } else { parent.insert( new DefaultMutableTreeNode( datasets.get(0) ), i ); } } else if ( et instanceof Num ) { parent.insert( new DefaultMutableTreeNode( String.valueOf(((Num)et).n) ),i ); } else if ( et instanceof Str ) { parent.insert(new DefaultMutableTreeNode( "'"+String.valueOf(((Str)et).s)+"'" ),i ); } else if ( et instanceof Attribute ) { exprType vv= ((Attribute)et).value; if ( vv instanceof Name ) { parent.insert(new DefaultMutableTreeNode( ((Name)vv).id + "." + ((Attribute)et).attr), i ); } else { logger.log(Level.FINE, "expected Name at {0}", (et).toString()); parent.insert(new DefaultMutableTreeNode( "." + ((Attribute)et).attr), i ); } } else if ( et instanceof UnaryOp ) { // a negative number appears as a unary minus op and positive number. exprType et1= ((UnaryOp)et).operand; switch (((UnaryOp)et).op) { case 4: fillTreeExprType( et1, parent, i, datasets, usedDatasets ); ((DefaultMutableTreeNode)parent.getChildAt(i)).setUserObject("-"+((DefaultMutableTreeNode)parent.getChildAt(i)).getUserObject() ); break; case 3: fillTreeExprType( et1, parent, i, datasets, usedDatasets ); ((DefaultMutableTreeNode)parent.getChildAt(i)).setUserObject("+"+((DefaultMutableTreeNode)parent.getChildAt(i)).getUserObject() ); break; default: fillTreeExprType( et1, parent, i, datasets, usedDatasets ); break; } } else if ( et instanceof BinOp ) { // a negative number appears as a unary minus op and positive number. DefaultMutableTreeNode child= new DefaultMutableTreeNode( nameForBinOp( ((BinOp)et).op ) ); fillTreeBinOp( (BinOp)et, child, datasets, usedDatasets ); parent.insert( child, i ); } else { Call call= (Call)et; DefaultMutableTreeNode child= new DefaultMutableTreeNode( funcCallName( call ) ); if ( call.func instanceof Attribute ) { fillTreeCall( ((Attribute)call.func).value, call, child, datasets, usedDatasets ); } else { fillTreeCall(call, child, datasets, usedDatasets ); } parent.insert( child, i); } } private void fillTreeCall( Call c, MutableTreeNode parent, List datasets, List usedDatasets) { for ( int i=0; i datasets, List usedDatasets ) { fillTreeExprType(n, parent, 0, datasets, usedDatasets ); for ( int i=0; i datasets, List usedDatasets ) { fillTreeExprType(c.left, parent, 0, datasets, usedDatasets ); fillTreeExprType(c.right, parent, 1, datasets, usedDatasets ); } private String funcCallName( Call c ) { exprType et= c.func; if ( et instanceof Name ) { Name name= (Name)et; return name.id; } else if ( et instanceof Attribute ) { // x.or(y) Attribute attr= (Attribute)et; return attr.attr; } else { throw new IllegalArgumentException("unsupported call type"); } } public interface Resolver { QDataSet getDataSet( String uri ); BufferedImage getImage( QDataSet qds ); void interactivePlot( QDataSet qds ); } private Resolver resolver; public void setResolver( Resolver r ) { this.directionsLabel.setText(LABEL_DIRECTIONS); this.expressionTree.setRowHeight(0); this.resolver= r; } final Map resolved= new HashMap(); final Map resolvePending= new HashMap(); final Map imaged= new HashMap(); final Map imagePending= new HashMap(); /** * implement a cache to get the dataset from the node. * @param value the node * @return the dataset at this node. */ private QDataSet getDataSet( final TreeNode value ) { String uri= namedURIListTool1.getUriForId(value.toString()); if ( uri==null ) { uri= getAsJythonInline( value ); } if ( SwingUtilities.isEventDispatchThread() ) { QDataSet qds= resolved.get(uri); if ( qds==null ) { synchronized ( resolvePending ) { if ( resolvePending.containsKey(uri) ) { // TODO: locking return null; } else { resolvePending.put( uri, "" ); } } Runnable run= () -> { getDataSet( value ); // call back on a different thread. expressionTree.treeDidChange(); }; new Thread(run).start(); } return qds; } else { synchronized ( resolved ) { QDataSet qds= resolved.get(uri); if ( qds==null ) { logger.log(Level.FINE, "resolving URI {0}", uri ); long t0= System.currentTimeMillis(); try { qds= resolver.getDataSet( uri ); if ( qds==null ) qds= NULL_DS; resolved.put( uri, qds ); resolvePending.remove( uri ); expressionTree.treeDidChange(); logger.log(Level.FINE, "done resolving URI in {0} ms: {1}", new Object[]{System.currentTimeMillis()-t0, uri }); } catch ( Exception ex ) { resolved.put( uri, ERROR_DS ); resolvePending.remove( uri ); expressionTree.treeDidChange(); } } return qds; } } } private BufferedImage getImage( final QDataSet qds ) { if ( SwingUtilities.isEventDispatchThread() ) { BufferedImage im= imaged.get(qds); if ( im==null ) { synchronized ( imagePending ) { if ( imagePending.containsKey(qds) ) { // TODO: locking return null; } else { imagePending.put( qds, "" ); } } Runnable run= () -> { if ( qds!=null ) { getImage( qds ); expressionTree.treeDidChange(); } }; new Thread(run).start(); } return im; } else { synchronized ( imaged ) { BufferedImage im= imaged.get(qds); if ( im==null ) { if ( qds!=null ) { logger.log(Level.FINE, "rendering dataset {0}", qds.toString() ); long t0= System.currentTimeMillis(); im= resolver.getImage( qds ); Graphics g= im.getGraphics(); g.setColor(Color.lightGray); g.drawRect(0,0,im.getWidth()-1,im.getHeight()-1); imaged.put( qds, im ); imagePending.remove( qds ); expressionTree.treeDidChange(); logger.log(Level.FINE, "done rendering dataset in {0} ms: {1}", new Object[]{System.currentTimeMillis()-t0,qds.toString()} ); } } return im; } } } private TreeCellRenderer getCellRenderer( ) { return (JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) -> { String s= value.toString(); Icon icon=null; if ( resolver!=null ) { QDataSet ds= getDataSet( (TreeNode)value ); if ( ds!=null ) { s= "" + s + " " +ds.toString() + ""; BufferedImage im= getImage( ds ); if ( im!=null ) { icon= new ImageIcon(im); } } } else { if ( !((DefaultMutableTreeNode)value).isLeaf() && tree.isCollapsed( row ) ) { //DefaultMutableTreeNode n= (DefaultMutableTreeNode)value; String jy= getJython( (DefaultTreeModel)tree.getModel(), value ); //getAsJythonInline(n); s= "" + s + " " +jy + ""; } } JLabel result= new JLabel( s ); if ( icon!=null ) { result.setIcon(icon); Dimension d= new Dimension( icon.getIconWidth(), icon.getIconHeight() ); result.setMinimumSize(d); result.setPreferredSize( new Dimension( 600, icon.getIconHeight() ) ); } else { if ( resolver!=null ) { BufferedImage im= new BufferedImage(60,60,BufferedImage.TYPE_INT_ARGB); Graphics2D g= (Graphics2D)im.getGraphics(); g.setColor(Color.lightGray); g.drawRect( 0,0, im.getWidth()-1, im.getHeight()-1 ); result.setIcon( new ImageIcon(im) ); Dimension d= new Dimension( 60, 60 ); result.setMinimumSize(d); result.setPreferredSize( new Dimension( 600, 60 ) ); } } return result; }; } private MutableTreeNode getTreeNode( String expr, List datasets, List usedDatasets ) { Module n; try { n= (Module)org.python.core.parser.parse( "x="+expr, "exec" ); } catch ( PyException ex ) { logger.log( Level.SEVERE, ex.getMessage(), ex ); n= (Module)org.python.core.parser.parse( "x='error'", "exec" ); // x=and(ds1,ds2) expr="error "+expr; } DefaultMutableTreeNode root; Assign assign= (Assign)n.body[0]; if ( assign.value instanceof Name ) { String name= ((Name)assign.value).id; if ( datasets.contains(name) || datasets.isEmpty() || name.equals("None") ) { root= new DefaultMutableTreeNode( name ); } else { root= new DefaultMutableTreeNode( datasets.get(datasets.size()-1) ); } } else if ( assign.value instanceof Num ) { root= new DefaultMutableTreeNode( ((Num)assign.value).n ); } else if ( assign.value instanceof Str ) { root= new DefaultMutableTreeNode( expr ); } else if ( assign.value instanceof Attribute ) { root= new DefaultMutableTreeNode( expr ); } else if ( assign.value instanceof UnaryOp ) { // negation, eg: -1.0 UnaryOp op= (UnaryOp)assign.value; if ( op.operand instanceof Num ) { root= new DefaultMutableTreeNode( "-" + String.valueOf(((Num)op.operand).n).trim() ); } else { root= new DefaultMutableTreeNode( "0.0" ); } } else if ( assign.value instanceof BinOp ) { BinOp op= (BinOp)assign.value; String sop= nameForBinOp( op.op ); root= new DefaultMutableTreeNode( sop ); fillTreeBinOp( op, root, datasets, usedDatasets ); } else { root= new DefaultMutableTreeNode( funcCallName( (Call)assign.value ) ); if ( assign.value instanceof Call ) { Call c= (Call)assign.value; if ( c.func instanceof Attribute ) { Attribute attr= (Attribute)c.func; fillTreeCall( attr.value, c, root, datasets, usedDatasets ); } else { fillTreeCall(c, root, datasets, usedDatasets ); } } } return root; } private String nameForBinOp( int op ) { String sop; switch(op) { case 1: sop= "add"; break; case 2: sop= "subtract"; break; case 3: sop= "multiply"; break; case 4: sop= "divide"; break; case 6: sop= "pow"; break; default: throw new IllegalArgumentException("cannot find name for BinOp (internal error at line 732)" ); } return sop; } private void fillTree( String expr, List datasets, List usedDatasets) { Module n= (Module)org.python.core.parser.parse("x="+expr, "exec" ); Assign assign= (Assign)n.body[0]; if ( assign.value instanceof Name ) { DefaultMutableTreeNode root= new DefaultMutableTreeNode( ((Name)assign.value).id ); DefaultTreeModel model= new DefaultTreeModel( root ); expressionTree.setModel(model); expressionTree.setCellRenderer( getCellRenderer() ); } else { exprType et= assign.value; if ( et instanceof Call ) { DefaultMutableTreeNode root= new DefaultMutableTreeNode( funcCallName( (Call)assign.value ) ); DefaultTreeModel model= new DefaultTreeModel( root ); Call c= (Call)assign.value; if ( c.func instanceof Attribute ) { Attribute attr= (Attribute)c.func; fillTreeCall( attr.value, c, root, datasets, usedDatasets ); } else { fillTreeCall(c, root, datasets, usedDatasets ); } expressionTree.setModel(model); } else if ( et instanceof BinOp ) { String sop= nameForBinOp( ((BinOp)et).op ); DefaultMutableTreeNode root= new DefaultMutableTreeNode( sop ); DefaultTreeModel model= new DefaultTreeModel( root ); fillTreeBinOp( (BinOp)et, root, datasets, usedDatasets ); expressionTree.setModel(model); } for (int i = 0; i < expressionTree.getRowCount(); i++) { expressionTree.expandRow(i); } expressionTree.setCellRenderer( getCellRenderer() ); } } /** * only split on the delimiter when we are not within the exclude delimiters. For example, * * x=getDataSet("http://autoplot.org/data/autoplot.cdf?Magnitude&noDep=T")&y=getDataSet('http://autoplot.org/data/autoplot.cdf?BGSEc&slice1=2')&sqrt(x) * * @param s the string to split. * @param delim the delimiter to split on, for example the ampersand (&). * @param exclude1 for example the single quote (') * @param exclude2 for example the double quote (") Note URIs don't support these anyway. * @return the split. * * This is a copy of another code. */ protected static String[] guardedSplit( String s, char delim, char exclude1, char exclude2 ) { if ( delim=='_') throw new IllegalArgumentException("_ not allowed for delim"); StringBuilder scopyb= new StringBuilder(s.length()); char inExclude= (char)0; for ( int i=0; i(char)0 ) c='_'; scopyb.append(c); } String[] ss= scopyb.toString().split(""+delim); int i1= 0; for ( int i=0; i ids= new ArrayList<>(); List uris= new ArrayList<>(); boolean haveAllIds= false; String timerange= null; String explicitTimerange= null; boolean synch= ss.length==1; for ( String s: ss ) { if ( s.trim().length()==0 ) continue; int i= s.indexOf("="); if ( i>-1 ) { Pattern p= Pattern.compile("(.+)=getDataSet\\('(.*)'\\)"); Matcher m= p.matcher(s); if ( m.matches() ) { ids.add(m.group(1)); String suri= m.group(2); URI uri; try { uri= new URI(suri); } catch (URISyntaxException ex) { uri= null; } if ( uri!=null ) { try { DataSourceFactory dsf= DataSetURI.getDataSourceFactory(uri,new NullProgressMonitor()); if ( dsf!=null ) { try { DataSource dss= dsf.getDataSource(new URI(suri)); TimeSeriesBrowse tsb= dss.getCapability( TimeSeriesBrowse.class ); if ( tsb!=null ) { DatumRange tr= tsb.getTimeRange(); if (tr != null) { timerange = tr.toString(); suri= tsb.blurURI(); } else { timerange = ""; } } } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); } } } catch (IOException | IllegalArgumentException | URISyntaxException ex) { logger.log(Level.SEVERE, null, ex); } } uris.add(suri); } else if ( s.contains("synchronize(") ) { synch=true; } else if ( s.contains("synchronizeOne(") ) { synch=true; } else { if ( s.substring(0,i).trim().equals("timerange") ) { explicitTimerange= s.substring(i+1).trim(); } else { throw new IllegalArgumentException("script is not jython mashup"); } } } else { if ( haveAllIds==false ) { haveAllIds= true; setIds(ids); setUris(uris); } fillTree(s, ids, new ArrayList<>() ); } } if ( uris.size()==1 ) { synch= true; } synchronizeCB.setSelected(synch); if ( haveAllIds==false ) { setIds(ids); setUris(uris); } if ( timerange==null ) { timeRangeRecentComboBox.setText( "" ); timeRangeRecentComboBox.setEnabled(false); timeRangeLabel.setEnabled(false); timeRangeLabel.setToolTipText("In-line code does not support Time Series Browse"); } else { if ( explicitTimerange!=null ) timerange= explicitTimerange; timeRangeRecentComboBox.setText( timerange.replaceAll("\\+", " " ) ); timeRangeRecentComboBox.setEnabled(true); timeRangeLabel.setEnabled(true); timeRangeLabel.setToolTipText("Current time range for data requests"); } } public void enableTimeRange() { timeRangeLabel.setEnabled(true); timeRangeRecentComboBox.setEnabled(true); } private static boolean isChildOf( TreeNode parent, TreeNode child ) { while ( child!=null ) { if ( child==parent ) { return true; } else { child= child.getParent(); } } return false; } private void doDrop( String data, TreePath tp ) { doDrop( data, tp, true ); } /** * print the path to a string, comma delimited. * @param newPath * @return */ public static String printPath(Object [] newPath ) { StringBuilder bb= new StringBuilder(); for (Object newPath1 : newPath) { bb.append(","); bb.append(newPath1); } return bb.length()==0 ? "" : bb.substring(1); } /** * insert element into array at index, as long as index is within the array * or at the length of the array. * @param array array of elements * @param index index for insertion, which may be out of bounds for the array. * @param node the object to insert. * @return * @see */ public static Object[] insertElement( Object[] array, int index, Object node ) { if ( array.length>=index ) { Object[] result= new Object[array.length+1]; System.arraycopy( array, 0, result, 0, index ); result[index]= node; System.arraycopy( array, index, result, index+1, array.length-index ); return result; } else { return array; } } /** * * @param data the expression to incorporate into the tree * @param tp the path where the expression is to be inserted * @param moveOldNodeDown if true, then make the drop target the first child. */ private void doDrop( final String data, final TreePath tp, boolean moveOldNodeDown ) { DefaultTreeModel model= (DefaultTreeModel) expressionTree.getModel(); MutableTreeNode oldBranch= (MutableTreeNode)tp.getLastPathComponent(); final Enumeration ppp= expressionTree.getExpandedDescendants(tp); final List expandedDescendants= new ArrayList<>(); if ( ppp!=null ) { while ( ppp.hasMoreElements() ) { expandedDescendants.add(ppp.nextElement()); } } MutableTreeNode parent= (MutableTreeNode)oldBranch.getParent(); final MutableTreeNode newBranch= getTreeNode(data, namedURIListTool1.ids, new ArrayList<>() ); int index= -1; String arg0= null; if ( parent!=null ) { index= parent.getIndex(oldBranch); String vv= oldBranch.toString(); if ( Ops.isSafeName(vv) && oldBranch.getChildCount()==0 ) { arg0=vv; } model.removeNodeFromParent(oldBranch); } if ( moveOldNodeDown && newBranch.getChildCount()>0 ) { // replace the first argument with what we are replacing newBranch.remove(0); newBranch.insert( oldBranch, 0 ); } if ( parent==null ) { model.setRoot(newBranch); } else { model.insertNodeInto( newBranch, parent, index ); } SwingUtilities.invokeLater(() -> { TreePath newTreePath= getPath(newBranch); expressionTree.expandPath( newTreePath ); for ( TreePath tp1 : expandedDescendants ) { Object[] path= tp1.getPath(); Object[] newPath= insertElement( path, tp.getPathCount()-1, newBranch ); TreePath mtp1= new TreePath(newPath); expressionTree.expandPath(mtp1); } imaged.clear(); resolved.clear(); expressionTree.treeDidChange(); }); } private static TreePath getPath(TreeNode treeNode) { List nodes = new ArrayList<>(); if (treeNode != null) { nodes.add(treeNode); treeNode = treeNode.getParent(); while (treeNode != null) { nodes.add(0, treeNode); treeNode = treeNode.getParent(); } } return nodes.isEmpty() ? null : new TreePath(nodes.toArray()); } /** * return true if the script conforms to the Jython mashup requirements. * @param jython script. * @return true if the script conforms to the Jython mashup requirements. */ public static boolean isDataMashupJythonInline( String jython ) { try { DataMashUp dmu= new DataMashUp(); dmu.setAsJythonInline(jython); return !"vap+inline:ds".equals(dmu.getAsJythonInline()); } catch ( Exception ex ) { logger.log( Level.FINER, null, ex ); return false; } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this * code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { bindingGroup = new org.jdesktop.beansbinding.BindingGroup(); palettePopupMenu = new javax.swing.JPopupMenu(); addItemMenuItem = new javax.swing.JMenuItem(); deleteItemsMenuItem = new javax.swing.JMenuItem(); expressionPopupMenu = new javax.swing.JPopupMenu(); editMenuItem = new javax.swing.JMenuItem(); plotMenuItem = new javax.swing.JMenuItem(); jSplitPane1 = new javax.swing.JSplitPane(); jSplitPane2 = new javax.swing.JSplitPane(); jPanel4 = new javax.swing.JPanel(); directionsLabel = new javax.swing.JLabel(); jScrollPane6 = new javax.swing.JScrollPane(); expressionTree = new javax.swing.JTree(); jPanel7 = new javax.swing.JPanel(); jLabel2 = new javax.swing.JLabel(); jTabbedPane1 = new javax.swing.JTabbedPane(); jPanel1 = new javax.swing.JPanel(); jScrollPane3 = new javax.swing.JScrollPane(); mathematicsList = new javax.swing.JList(); jPanel3 = new javax.swing.JPanel(); jScrollPane4 = new javax.swing.JScrollPane(); datasetList = new javax.swing.JList(); jPanel5 = new javax.swing.JPanel(); jScrollPane2 = new javax.swing.JScrollPane(); filtersList = new javax.swing.JList(); myFunctionsPanel = new javax.swing.JPanel(); jScrollPane5 = new javax.swing.JScrollPane(); scratchList = new javax.swing.JList(); jPanel6 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); allList = new javax.swing.JList<>(); jPanel2 = new javax.swing.JPanel(); synchronizeCB = new javax.swing.JCheckBox(); jScrollPane7 = new javax.swing.JScrollPane(); namedURIListTool1 = new org.autoplot.jythonsupport.ui.NamedURIListTool(); jLabel1 = new javax.swing.JLabel(); timeRangeLabel = new javax.swing.JLabel(); timeRangeRecentComboBox = new org.autoplot.datasource.RecentComboBox(); helpButton = new javax.swing.JButton(); calendarButton = new javax.swing.JButton(); addItemMenuItem.setText("Add function..."); addItemMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addItemMenuItemActionPerformed(evt); } }); palettePopupMenu.add(addItemMenuItem); deleteItemsMenuItem.setText("Delete Items"); deleteItemsMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteItemsMenuItemActionPerformed(evt); } }); palettePopupMenu.add(deleteItemsMenuItem); editMenuItem.setText("Edit"); editMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { editMenuItemActionPerformed(evt); } }); expressionPopupMenu.add(editMenuItem); plotMenuItem.setText("Plot"); plotMenuItem.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { plotMenuItemActionPerformed(evt); } }); expressionPopupMenu.add(plotMenuItem); jSplitPane1.setDividerLocation(140); jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); jSplitPane1.setResizeWeight(0.5); jSplitPane2.setDividerLocation(420); directionsLabel.setText("Double-click on the name to set the variable or constant argument, or to replace the branch."); directionsLabel.setAlignmentY(0.0F); directionsLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP); expressionTree.addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { expressionTreeMousePressed(evt); } public void mouseReleased(java.awt.event.MouseEvent evt) { expressionTreeMouseReleased(evt); } public void mouseClicked(java.awt.event.MouseEvent evt) { expressionTreeMouseClicked(evt); } }); jScrollPane6.setViewportView(expressionTree); javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); jPanel4.setLayout(jPanel4Layout); jPanel4Layout.setHorizontalGroup( jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(directionsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 540, Short.MAX_VALUE) .addComponent(jScrollPane6) ); jPanel4Layout.setVerticalGroup( jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel4Layout.createSequentialGroup() .addComponent(directionsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane6, javax.swing.GroupLayout.DEFAULT_SIZE, 292, Short.MAX_VALUE)) ); jSplitPane2.setRightComponent(jPanel4); jLabel2.setText("Drag functions onto the palette to the right."); mathematicsList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "add(x,y)", "subtract(x,y)", "multiply(x,y)", "divide(x,y)", "mod(x,y)", "pow(x,y)", "log10(x)", "sqrt(x)", "abs(x): the absolute value of the data", "magnitude(x): the lengths of the vectors", "toRadians(x)", "toDegrees(x)", "sin(x)", "cos(x)", "tan(x)", "asin(x)", "acos(x)", "atan2(y,x)", "atan(x)", "crossProduct(a,b)" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); mathematicsList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane3.setViewportView(mathematicsList); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 291, Short.MAX_VALUE) ); jTabbedPane1.addTab("mathematics", jPanel1); datasetList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "link(x,y): create data set where y is a function of x", "link(x,y,z): create data set where z is a function of x and y", "slice1(ds,0): slice ds(x,y) to create a new ds(x)", "smooth(ds,5): run boxcar average over the dataset", "putProperty(ds,QDataSet.UNITS,'s'): attach properties to the data", "getProperty(ds,QDataSet.DEPEND_0): get properties, like timetags.", "unbundle(ds,0): remove the 0th dataset from the bundle", "bundle(t,ds1,ds2): bundle the three datasets together", "collapse1(ds): average measurements along the dimension", "total(ds,1): sum measurements along the dimension", "trim1(ds,st,en): trim the indices in the the dimension" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); datasetList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane4.setViewportView(datasetList); javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE) ); jTabbedPane1.addTab("dataset", jPanel3); filtersList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "putValues(ds,w,v)", "removeValues(ds,w)", "removeValuesGreaterThan(ds,v)", "removeValuesLessThan(ds,v)", "where(c)", "lt(ds1,ds2)", "le(ds1,ds2)", "gt(ds1,ds2)", "ge(ds1,ds2)", "eq(ds1,ds2)", "ne(ds1,ds2)", "ds1.or(ds2)", "ds1.and(ds2)" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); filtersList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane2.setViewportView(filtersList); javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5); jPanel5.setLayout(jPanel5Layout); jPanel5Layout.setHorizontalGroup( jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE) ); jPanel5Layout.setVerticalGroup( jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE) ); jTabbedPane1.addTab("filters", jPanel5); scratchList.setToolTipText("scratch is a list for storing expressions"); scratchList.addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent evt) { scratchListMousePressed(evt); } public void mouseReleased(java.awt.event.MouseEvent evt) { scratchListMouseReleased(evt); } public void mouseClicked(java.awt.event.MouseEvent evt) { scratchListMouseClicked(evt); } }); jScrollPane5.setViewportView(scratchList); javax.swing.GroupLayout myFunctionsPanelLayout = new javax.swing.GroupLayout(myFunctionsPanel); myFunctionsPanel.setLayout(myFunctionsPanelLayout); myFunctionsPanelLayout.setHorizontalGroup( myFunctionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE) ); myFunctionsPanelLayout.setVerticalGroup( myFunctionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane5, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE) ); jTabbedPane1.addTab("my functions", myFunctionsPanel); allList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; public int getSize() { return strings.length; } public String getElementAt(int i) { return strings[i]; } }); jScrollPane1.setViewportView(allList); javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); jPanel6.setLayout(jPanel6Layout); jPanel6Layout.setHorizontalGroup( jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel6Layout.createSequentialGroup() .addGap(3, 3, 3) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE) .addGap(3, 3, 3)) ); jPanel6Layout.setVerticalGroup( jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel6Layout.createSequentialGroup() .addGap(3, 3, 3) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE) .addGap(3, 3, 3)) ); jTabbedPane1.addTab("all", jPanel6); javax.swing.GroupLayout jPanel7Layout = new javax.swing.GroupLayout(jPanel7); jPanel7.setLayout(jPanel7Layout); jPanel7Layout.setHorizontalGroup( jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup() .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap()) .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jTabbedPane1)) ); jPanel7Layout.setVerticalGroup( jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel7Layout.createSequentialGroup() .addComponent(jLabel2) .addGap(0, 328, Short.MAX_VALUE)) .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createSequentialGroup() .addGap(23, 23, 23) .addComponent(jTabbedPane1))) ); jSplitPane2.setLeftComponent(jPanel7); jSplitPane1.setBottomComponent(jSplitPane2); synchronizeCB.setSelected(true); synchronizeCB.setText("synchronize data by time tags, interpolating data to the first dataset's time tags"); synchronizeCB.setToolTipText("Nearest Neighbor synchronization is used to line up the data, so that they can be combined."); namedURIListTool1.setMinimumSize(new java.awt.Dimension(100, 100)); namedURIListTool1.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { namedURIListTool1FocusLost(evt); } }); jScrollPane7.setViewportView(namedURIListTool1); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane7, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(synchronizeCB, javax.swing.GroupLayout.DEFAULT_SIZE, 971, Short.MAX_VALUE) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(jScrollPane7, javax.swing.GroupLayout.DEFAULT_SIZE, 97, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(synchronizeCB, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); jSplitPane1.setLeftComponent(jPanel2); jLabel1.setText("Load these Data Sets into variable names:"); timeRangeLabel.setText("Time Range:"); timeRangeLabel.setEnabled(false); timeRangeLabel.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { timeRangeTextFieldFocusLost(evt); } }); timeRangeRecentComboBox.setEnabled(false); timeRangeRecentComboBox.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { timeRangeRecentComboBoxFocusLost(evt); } }); timeRangeRecentComboBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { timeRangeRecentComboBoxActionPerformed(evt); } }); helpButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/help.png"))); // NOI18N helpButton.setText("Help"); helpButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { helpButtonActionPerformed(evt); } }); calendarButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/calendar.png"))); // NOI18N org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, timeRangeRecentComboBox, org.jdesktop.beansbinding.ELProperty.create("${enabled}"), calendarButton, org.jdesktop.beansbinding.BeanProperty.create("enabled")); bindingGroup.addBinding(binding); calendarButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { calendarButtonActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(timeRangeLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(timeRangeRecentComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 265, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(calendarButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(helpButton, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) .addComponent(jSplitPane1) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(timeRangeLabel) .addComponent(timeRangeRecentComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(helpButton) .addComponent(calendarButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSplitPane1)) ); layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {calendarButton, helpButton}); bindingGroup.bind(); }// //GEN-END:initComponents private void timeRangeTextFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_timeRangeTextFieldFocusLost }//GEN-LAST:event_timeRangeTextFieldFocusLost /** * use the resolver to get the QDataSet, then plot it. */ private void plotExpr( ) { TreePath tp= expressionTree.getSelectionPath(); if ( tp==null ) return; QDataSet showMe= resolved.get( getAsJythonInline( (TreeNode)tp.getLastPathComponent() )); if ( showMe!=null ) { resolver.interactivePlot( showMe ); } else { if ( resolver!=null ) { Runnable run= () -> { TreePath tp1 = expressionTree.getSelectionPath(); if (tp1 == null) { return; } QDataSet showMe1 = resolver.getDataSet(getAsJythonInline((TreeNode) tp1.getLastPathComponent())); resolver.interactivePlot(showMe1); }; new Thread(run).start(); } else { logger.info("resolver is not set."); } } } private String getSelectedFunction() { Component c= this.jTabbedPane1.getSelectedComponent(); if ( c instanceof JPanel ) { c= ((JPanel)c).getComponent(0); } if ( c instanceof JScrollPane ) { c= ((javax.swing.JScrollPane)c).getViewport().getComponent(0); } if ( c instanceof JList ) { Object o= ((JList)c).getSelectedValue(); if ( o instanceof String ) { String s= ((String)o); int i= s.indexOf(":"); if ( i>1 && s.charAt(i-1)==')' ) { s= s.substring(0,i); } return s; } } return ""; } private void expressionTreeMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_expressionTreeMouseClicked if ( evt.isShiftDown() ) { TreePath tp= expressionTree.getClosestPathForLocation( evt.getX(), evt.getY() ); expressionTree.setSelectionPath(tp); plotExpr(); } else if ( evt.getClickCount()==2 ) { TreePath tp= expressionTree.getClosestPathForLocation( evt.getX(), evt.getY() ); if ( !expressionTree.getModel().isLeaf(tp.getLastPathComponent()) ) { return; } expressionTree.setSelectionPath(tp); String currentId= tp.getLastPathComponent().toString(); namedURIListTool1.setExpression(getSelectedFunction()); String s= namedURIListTool1.selectDataId(currentId); if ( s!=null ) { doDrop(s,tp); } } }//GEN-LAST:event_expressionTreeMouseClicked private void addItemMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addItemMenuItemActionPerformed String s= JOptionPane.showInputDialog( this, "Add function" ); if ( s!=null && !( s.trim().length()==0 ) ) { addToScratch( s.trim() ); } }//GEN-LAST:event_addItemMenuItemActionPerformed private void deleteItemsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteItemsMenuItemActionPerformed int[] indices= scratchList.getSelectedIndices(); for ( int i=indices.length-1; i>=0; i-- ) { removeFromScratch(indices[i]); } }//GEN-LAST:event_deleteItemsMenuItemActionPerformed private void namedURIListTool1FocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_namedURIListTool1FocusLost // check for TSB when a TSB URI is found. checkForTSB(); }//GEN-LAST:event_namedURIListTool1FocusLost private void expressionTreeMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_expressionTreeMousePressed if ( evt.isPopupTrigger() ) { plotMenuItem.setEnabled( resolver!=null ); expressionPopupMenu.show( evt.getComponent(), evt.getX(), evt.getY() ); } }//GEN-LAST:event_expressionTreeMousePressed private void editMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editMenuItemActionPerformed TreePath tp= expressionTree.getSelectionPath(); if ( tp==null ) { JOptionPane.showMessageDialog( this, "A node must be selected", "Node must be selected", JOptionPane.PLAIN_MESSAGE ); return; } expressionTree.setSelectionPath(tp); if ( !expressionTree.getModel().isLeaf(tp.getLastPathComponent()) ) { String s= getAsJythonInline( (TreeNode)tp.getLastPathComponent() ); int i= s.lastIndexOf("&"); if ( i>-1 ) { s= s.substring(i+1); } else { i= s.lastIndexOf(":"); s= s.substring(i+1); } s= namedURIListTool1.selectDataId(s); if ( s!=null ) { doDrop(s,tp,false); } } else { String currentId= tp.getLastPathComponent().toString(); String s= namedURIListTool1.selectDataId(currentId); namedURIListTool1.setExpression(getSelectedFunction()); if ( s!=null ) { doDrop(s,tp,false); } } }//GEN-LAST:event_editMenuItemActionPerformed private void expressionTreeMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_expressionTreeMouseReleased if ( evt.isPopupTrigger() ) { expressionPopupMenu.show( evt.getComponent(), evt.getX(), evt.getY() ); } }//GEN-LAST:event_expressionTreeMouseReleased private void plotMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_plotMenuItemActionPerformed TreePath tp= expressionTree.getSelectionPath(); if ( tp==null ) { JOptionPane.showMessageDialog( this, "A node must be selected", "Node must be selected", JOptionPane.PLAIN_MESSAGE ); return; } expressionTree.setSelectionPath(tp); plotExpr(); }//GEN-LAST:event_plotMenuItemActionPerformed private void timeRangeRecentComboBoxFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_timeRangeRecentComboBoxFocusLost String s= timeRangeRecentComboBox.getText().trim(); if ( s.length()>0 ) { try { namedURIListTool1.setTimeRange( DatumRangeUtil.parseTimeRange(timeRangeRecentComboBox.getText())); } catch (ParseException ex) { logger.log(Level.SEVERE, null, ex); } } }//GEN-LAST:event_timeRangeRecentComboBoxFocusLost private void timeRangeRecentComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_timeRangeRecentComboBoxActionPerformed String s= timeRangeRecentComboBox.getText().trim(); if ( s.length()>0 ) { try { namedURIListTool1.setTimeRange( DatumRangeUtil.parseTimeRange(timeRangeRecentComboBox.getText())); } catch (ParseException ex) { logger.log(Level.SEVERE, null, ex); } } }//GEN-LAST:event_timeRangeRecentComboBoxActionPerformed private void scratchListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scratchListMouseClicked if ( jTabbedPane1.getSelectedComponent()==myFunctionsPanel ) { if ( evt.isPopupTrigger() ) { palettePopupMenu.show( evt.getComponent(), evt.getX(), evt.getY() ); } } }//GEN-LAST:event_scratchListMouseClicked private void scratchListMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scratchListMouseReleased if ( jTabbedPane1.getSelectedComponent()==myFunctionsPanel ) { if ( evt.isPopupTrigger() ) { palettePopupMenu.show( evt.getComponent(), evt.getX(), evt.getY() ); } } }//GEN-LAST:event_scratchListMouseReleased private void scratchListMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scratchListMousePressed if ( jTabbedPane1.getSelectedComponent()==myFunctionsPanel ) { if ( evt.isPopupTrigger() ) { palettePopupMenu.show( evt.getComponent(), evt.getX(), evt.getY() ); } } }//GEN-LAST:event_scratchListMousePressed private void helpButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_helpButtonActionPerformed DataSourceUtil.openBrowser("http://autoplot.org/help.mashup"); }//GEN-LAST:event_helpButtonActionPerformed private void calendarButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_calendarButtonActionPerformed org.das2.util.LoggerManager.logGuiEvent(evt); TimeRangeTool tt= new TimeRangeTool(); String s= timeRangeRecentComboBox.getText(); if ( s!=null ) tt.setSelectedRange(s); int r= JOptionPane.showConfirmDialog( this, tt, "Select Time Range", JOptionPane.OK_CANCEL_OPTION ); if ( r==JOptionPane.OK_OPTION) { timeRangeRecentComboBox.setText(tt.getSelectedRange()); } }//GEN-LAST:event_calendarButtonActionPerformed /** * this should be called from the event thread, but will start a new thread * to check for a TSB capability. */ private void checkForTSB() { if ( SwingUtilities.isEventDispatchThread() ) { Runnable run= () -> { checkForTSBImmediately(); }; new Thread(run,"checkForTSB").start(); } else { checkForTSBImmediately(); } } private void checkForTSBImmediately() { String[] suris= namedURIListTool1.getUris(); String timerange= this.timeRangeRecentComboBox.getText().trim(); boolean haveTsb= false; for ( String suri: suris ) { URI uri; try { uri= new URI(suri); } catch (URISyntaxException ex) { uri= null; } if ( uri!=null ) { try { DataSourceFactory dsf= DataSetURI.getDataSourceFactory(uri,new NullProgressMonitor()); if ( dsf!=null ) { try { DataSource dss= dsf.getDataSource(new URI(suri)); TimeSeriesBrowse tsb= dss.getCapability( TimeSeriesBrowse.class ); if ( tsb!=null ) { haveTsb= true; if ( timerange.length()==0 ) { timerange= tsb.getTimeRange().toString(); } } } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); } } } catch (IOException | IllegalArgumentException | URISyntaxException ex) { logger.log(Level.SEVERE, null, ex); } } } final String ftimerange= timerange; final boolean fhaveTsb= haveTsb; Runnable run= () -> { if ( fhaveTsb ) { timeRangeRecentComboBox.setEnabled(true); timeRangeLabel.setEnabled(true); timeRangeRecentComboBox.setText( ftimerange ); } else { timeRangeRecentComboBox.setEnabled(false); timeRangeLabel.setEnabled(false); } }; SwingUtilities.invokeLater(run); } private void removeFromScratch( int index ) { ListModel lm= scratchList.getModel(); DefaultListModel dlm; if ( lm instanceof DefaultListModel ) { dlm= (DefaultListModel)lm; } else { dlm= new DefaultListModel(); for ( int i=0; i { backToFile(); }; new Thread( run ).start(); } /** * add the expression to the scratch list. * @param expression */ private void addToScratch(String expression) { final String text0= directionsLabel.getText(); directionsLabel.setText("Replaced expression is added to my functions."); Timer t= new Timer( 1500, (ActionEvent e) -> { directionsLabel.setText(text0); }); t.setRepeats(false); t.start(); ListModel lm= scratchList.getModel(); DefaultListModel dlm; if ( lm instanceof DefaultListModel ) { dlm= (DefaultListModel)lm; } else { dlm= new DefaultListModel(); for ( int i=0; i-1 ) dlm.removeElementAt(remove); dlm.add( dlm.getSize(), expression ); scratchList.setModel(dlm); Runnable run= () -> { backToFile(); }; new Thread( run ).start(); } private void backToFile( ) { try { ListModel m= scratchList.getModel(); File f= new File( AutoplotSettings.settings().resolveProperty( AutoplotSettings.PROP_AUTOPLOTDATA) ); File f1= new File( f, "bookmarks" ); File f2= new File( f1, "mashup.myfunctions.txt" ); try ( PrintWriter w = new PrintWriter( new FileWriter(f2) ) ) { for ( int i=0; i { scratchList.setModel(dlm); }; SwingUtilities.invokeLater(run); } } catch ( IOException ex ) { logger.log( Level.WARNING, ex.getMessage(), ex ); } } final DropTargetListener createTreeDropTargetListener() { return new DropTargetListener() { @Override public void dragEnter(DropTargetDragEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) { dtde.acceptDrag(DnDConstants.ACTION_COPY); } } @Override public void dragOver(DropTargetDragEvent dtde) { TreePath tp= expressionTree.getClosestPathForLocation( dtde.getLocation().x, dtde.getLocation().y ); expressionTree.setSelectionPath(tp); } @Override public void dropActionChanged(DropTargetDragEvent dtde) { } @Override public void dragExit(DropTargetEvent dte) { } @Override public void drop(DropTargetDropEvent dtde) { try { String data = (String) dtde.getTransferable().getTransferData(DataFlavor.stringFlavor); TreePath tp= expressionTree.getClosestPathForLocation( dtde.getLocation().x, dtde.getLocation().y ); DefaultMutableTreeNode n= (DefaultMutableTreeNode)tp.getLastPathComponent(); String old= getJython( (DefaultTreeModel)expressionTree.getModel(), n ); if ( old.contains("(") ) { addToScratch( old ); } if ( data.endsWith(REPLACEARGSFLAG) ) { data= data.substring(0,data.length()-17); doDrop(data,tp,true); } else { doDrop(data,tp,false); } } catch (UnsupportedFlavorException | IOException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } } }; } /** * when the drop target ends with this string (kludge), don't clobber * what's in the tree, instead make it the first argument. */ private static final String REPLACEARGSFLAG = "(REPLACEARGSFLAG)"; final DropTargetListener createListDropTargetListener() { return new DropTargetListener() { @Override public void dragEnter(DropTargetDragEvent dtde) { if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor)) { dtde.acceptDrag(DnDConstants.ACTION_COPY); } } @Override public void dragOver(DropTargetDragEvent dtde) { } @Override public void dropActionChanged(DropTargetDragEvent dtde) { } @Override public void dragExit(DropTargetEvent dte) { } @Override public void drop(DropTargetDropEvent dtde) { try { String data = (String) dtde.getTransferable().getTransferData(DataFlavor.stringFlavor); if ( data.endsWith(REPLACEARGSFLAG) ) { data= data.substring(0,data.length()-17); } addToScratch( data ); } catch (UnsupportedFlavorException | IOException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); } } }; } final DragGestureListener createDragGestureListener() { return (DragGestureEvent dge) -> { String s=null; boolean replaceArgs= false; if ( dge.getComponent() instanceof JList ) { s= (String)((JList)dge.getComponent()).getSelectedValue(); replaceArgs= true; } else if ( dge.getComponent()==expressionTree ) { if ( expressionTree.getSelectionCount()==1 ) { TreePath tp= expressionTree.getSelectionPath(); if ( tp==null ) return; DefaultMutableTreeNode n= (DefaultMutableTreeNode)tp.getLastPathComponent(); s= getJython( (DefaultTreeModel)expressionTree.getModel(), n ); } } else if ( dge.getComponent()==namedURIListTool1 ) { logger.fine("here where dge.getComponent()==namedURIListTool1"); } if ( s!=null ) { if ( s.contains(": ") ) { int i= s.lastIndexOf(": "); s= s.substring(0,i).trim(); } if ( replaceArgs ) s= s + REPLACEARGSFLAG; dge.startDrag(null, new StringSelection(s) ) ; } }; }; public static void main( String[] args ) { DataMashUp dmu= new DataMashUp(); dmu.setResolver( new Resolver() { EnumerationUnits eu= new EnumerationUnits("foo"); @Override public QDataSet getDataSet(String uri) { return DataSetUtil.asDataSet( eu.createDatum(uri) ); } @Override public BufferedImage getImage(QDataSet qds) { BufferedImage result= new BufferedImage(128,32,BufferedImage.TYPE_4BYTE_ABGR); Graphics2D g= (Graphics2D)result.getGraphics(); g.setColor( Color.DARK_GRAY ); g.drawString( eu.createDatum(qds.value()).toString(), 2, 10 ); return result; } @Override public void interactivePlot(QDataSet qds) { System.err.println( qds ); } }); dmu.fillTree("add(a,b)", Collections.singletonList("z"), new ArrayList<>() ); JOptionPane.showConfirmDialog( null, dmu ); System.err.println( dmu.getAsJythonInline() ); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem addItemMenuItem; private javax.swing.JList allList; private javax.swing.JButton calendarButton; private javax.swing.JList datasetList; private javax.swing.JMenuItem deleteItemsMenuItem; private javax.swing.JLabel directionsLabel; private javax.swing.JMenuItem editMenuItem; private javax.swing.JPopupMenu expressionPopupMenu; private javax.swing.JTree expressionTree; private javax.swing.JList filtersList; private javax.swing.JButton helpButton; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel4; private javax.swing.JPanel jPanel5; private javax.swing.JPanel jPanel6; private javax.swing.JPanel jPanel7; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JScrollPane jScrollPane3; private javax.swing.JScrollPane jScrollPane4; private javax.swing.JScrollPane jScrollPane5; private javax.swing.JScrollPane jScrollPane6; private javax.swing.JScrollPane jScrollPane7; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JSplitPane jSplitPane2; private javax.swing.JTabbedPane jTabbedPane1; private javax.swing.JList mathematicsList; private javax.swing.JPanel myFunctionsPanel; private org.autoplot.jythonsupport.ui.NamedURIListTool namedURIListTool1; private javax.swing.JPopupMenu palettePopupMenu; private javax.swing.JMenuItem plotMenuItem; private javax.swing.JList scratchList; private javax.swing.JCheckBox synchronizeCB; private javax.swing.JLabel timeRangeLabel; private org.autoplot.datasource.RecentComboBox timeRangeRecentComboBox; private org.jdesktop.beansbinding.BindingGroup bindingGroup; // End of variables declaration//GEN-END:variables }