package net.dirtyfilthy.Bitten; import java.awt.event.KeyEvent; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import javax.swing.JOptionPane; import prefuse.Constants; import prefuse.Display; import prefuse.Visualization; import prefuse.action.ActionList; import prefuse.action.RepaintAction; import prefuse.action.assignment.ColorAction; import prefuse.action.assignment.DataColorAction; import prefuse.action.assignment.DataSizeAction; import prefuse.action.layout.graph.ForceDirectedLayout; import prefuse.action.layout.graph.NodeLinkTreeLayout; import prefuse.activity.Activity; import prefuse.controls.ControlAdapter; import prefuse.controls.DragControl; import prefuse.controls.FocusControl; import prefuse.controls.PanControl; import prefuse.controls.ZoomControl; import prefuse.data.Graph; import prefuse.data.Table; import prefuse.data.event.EventConstants; import prefuse.data.io.DataIOException; import prefuse.data.io.sql.ConnectionFactory; import prefuse.data.io.sql.DatabaseDataSource; import prefuse.render.DefaultRendererFactory; import prefuse.render.EdgeRenderer; import prefuse.render.LabelRenderer; import prefuse.util.ColorLib; import prefuse.util.force.DragForce; import prefuse.util.force.EulerIntegrator; import prefuse.visual.VisualItem; public class AddressView extends Display { private DatabaseDataSource dbSource; private String label="label"; private Table transactionNodeTable=new Table(); private Table transactionEdgeTable=new Table(); private Graph graph; private Visualization viz; private Connection db; public AddressView(Connection c) throws SQLException{ db=c; int[] palette = new int[] { ColorLib.rgb(255,180,180), ColorLib.rgb(190,190,255), ColorLib.rgb(190,190,0) }; dbSource=ConnectionFactory.getDatabaseConnection(c); transactionNodeTable.addColumn("id",int.class); transactionNodeTable.addColumn("type",int.class); transactionNodeTable.addColumn("btc",double.class); transactionEdgeTable.addColumn("id", int.class); transactionEdgeTable.addColumn("source", int.class); transactionEdgeTable.addColumn("target", int.class); transactionEdgeTable.addColumn("btc",double.class); transactionEdgeTable.addColumn("type",int.class); graph=new Graph(transactionNodeTable, transactionEdgeTable, true, "id", "source","target"); viz=new Visualization(); viz.add("graph", graph); // draw the "name" label for NodeItems LabelRenderer r = new LabelRenderer("id"); r.setRoundedCorner(8, 8); // round the corners EdgeRenderer e = new EdgeRenderer(); e.setArrowType(Constants.EDGE_ARROW_FORWARD); e.setArrowHeadSize(8, 8); FocusControl focusControl=new FocusControl(2){ public void itemClicked(VisualItem i, java.awt.event.MouseEvent e){ int id=i.getInt("id"); expandAddress(id); } }; ControlAdapter keyboardAdapter=new ControlAdapter(){ public void keyTyped(KeyEvent e){ processKeys(e); } private void processKeys(KeyEvent e){ switch(e.getKeyChar()){ case 's': showSearchDialog(); break; } } }; // create a new default renderer factory // return our name label renderer as the default for all non-EdgeItems // includes straight line edges for EdgeItems by default viz.setRendererFactory(new DefaultRendererFactory(r,e)); ActionList layout = new ActionList(Activity.INFINITY); ForceDirectedLayout f=new ForceDirectedLayout("graph"); // f.getForceSimulator().setIntegrator(new EulerIntegrator()); f.getForceSimulator().addForce(new DragForce((float) 0.01)); layout.add(f); //layout.add(new NodeLinkTreeLayout("graph")); layout.add(new RepaintAction()); DataColorAction fill = new DataColorAction("graph.nodes", "type", Constants.NOMINAL, VisualItem.FILLCOLOR, palette); ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0)); // use light grey for edges ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(200)); ColorAction fill2 = new ColorAction("graph.edges", VisualItem.FILLCOLOR, ColorLib.gray(200)); DataSizeAction edgeWidth = new DataSizeAction("graph.edges", "btc"); DataColorAction edgeColor = new DataColorAction("graph.edges", "type", Constants.NUMERICAL, VisualItem.STROKECOLOR,new int[] {ColorLib.rgb(255,0,0),ColorLib.rgb(0,255,0)}); edgeColor.setBinCount(2); edgeWidth.setScale(Constants.LOG_SCALE); edgeWidth.setMaximumSize(20); ActionList color = new ActionList(); color.add(text); color.add(edgeColor); color.add(fill); color.add(fill2); color.add(edgeWidth); viz.putAction("layout", layout); viz.putAction("color", color); setSize(720, 500); // set display size setVisualization(viz); addControlListener(new DragControl()); // drag items around addControlListener(new PanControl()); // pan with background left-drag addControlListener(new ZoomControl()); // zoom with vertical right-drag addControlListener(focusControl); addControlListener(keyboardAdapter); viz.run("color"); // start up the animated layout viz.run("layout"); } public void showSearchDialog(){ String s = (String)JOptionPane.showInputDialog(this, "Search:","Search", JOptionPane.QUESTION_MESSAGE); expandStringAddress(s, true); } public void expandAddress(final long addressId){ System.out.println("expanding tran "+addressId); Runnable r=new Runnable() { public void run(){ try { ArrayList<Long> a=new ArrayList<Long>(); PreparedStatement s=db.prepareStatement("SELECT from_address_id AS id FROM transaction_outputs LEFT JOIN transaction_inputs ON transaction_inputs.transaction_id=transaction_outputs.transaction_id WHERE to_address_id=? UNION SELECT to_address_id as id FROM transaction_inputs LEFT JOIN transaction_outputs ON transaction_inputs.transaction_id=transaction_outputs.transaction_id WHERE from_address_id=? "); s.setLong(1, addressId); s.setLong(2, addressId); ResultSet rs=s.executeQuery(); while(rs.next()){ a.add(rs.getLong(1)); } rs.close(); loadAddress((Long[]) a.toArray(new Long[a.size()])); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; new Thread(r).start(); } public void expandOutputMulti(final Long[] idz, boolean sync){ System.out.println("expanding out "+idz); Runnable r=new Runnable() { public void run(){ try { StringBuilder builder = new StringBuilder(); for (int i = 0; i < idz.length;) { builder.append(idz[i]); if (++i < idz.length) { builder.append(","); } } ArrayList<Long> a=new ArrayList<Long>(); PreparedStatement s=db.prepareStatement("SELECT DISTINCT (transaction_id) as id from transaction_outputs where id IN ("+builder+") UNION SELECT DISTINCT (transaction_id) as id from transaction_inputs where previous_output_id IN ("+builder+")"); System.out.println("execute query"); ResultSet rs=s.executeQuery(); while(rs.next()){ a.add(rs.getLong(1)); } rs.close(); // loadTransaction((Long[]) a.toArray(new Long[a.size()])); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; if(sync){ r.run(); } else{ new Thread(r).start(); } } public void expandStringAddress(final String address, boolean sync){ Runnable r=new Runnable() { public void run(){ try { ArrayList<Long> a=new ArrayList<Long>(); PreparedStatement s=db.prepareStatement("SELECT DISTINCT id from addresses where addresses.base58hash=? "); s.setString(1, address.trim()); System.out.println("execute query find address "+address); ResultSet rs=s.executeQuery(); System.out.println("after exec"); while(rs.next()){ a.add(rs.getLong(1)); } rs.close(); System.out.println("load transaction"); loadAddress((Long[]) a.toArray(new Long[a.size()])); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; if(sync){ r.run(); } else{ new Thread(r).start(); } } public void expandOutput(final long outputId, boolean sync){ System.out.println("expanding out "+outputId); Runnable r=new Runnable() { public void run(){ try { ArrayList<Long> a=new ArrayList<Long>(); PreparedStatement s=db.prepareStatement("SELECT DISTINCT (transactions.id) from transactions left join transaction_inputs ON transactions.id=transaction_inputs.transaction_id LEFT JOIN transaction_outputs ON transactions.id=transaction_outputs.transaction_id WHERE transaction_outputs.id=? OR transaction_inputs.previous_output_id=?"); s.setLong(1, outputId); s.setLong(2, outputId); System.out.println("execute query"); ResultSet rs=s.executeQuery(); while(rs.next()){ a.add(rs.getLong(1)); } rs.close(); System.out.println("load transaction"); // loadTransaction((Long[]) a.toArray(new Long[a.size()])); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; if(sync){ r.run(); } else{ new Thread(r).start(); } } public void loadAddress(Long[] idz){ String sql=""; StringBuilder builder = new StringBuilder(); for (int i = 0; i < idz.length;) { builder.append(idz[i]); if (++i < idz.length) { builder.append(","); } } synchronized(viz){ try { sql="SELECT id AS id, 0 as type, 0.0 AS btc FROM addresses WHERE id IN("+builder+")"; dbSource.getData(transactionNodeTable,sql,"id"); sql="SELECT DISTINCT from_address_id AS id, 0 AS type, 0 AS btc FROM transaction_outputs LEFT JOIN transaction_inputs ON transaction_outputs.transaction_id=transaction_inputs.transaction_id WHERE transaction_outputs.to_address_id IN("+builder+") AND from_address_id IS NOT NULL"; dbSource.getData(transactionNodeTable,sql,"id"); sql="SELECT DISTINCT to_address_id AS id, 0 AS type, 0 AS btc FROM transaction_inputs LEFT JOIN transaction_outputs ON transaction_outputs.transaction_id=transaction_inputs.transaction_id WHERE transaction_inputs.from_address_id IN("+builder+") AND to_address_id IS NOT NULL"; dbSource.getData(transactionNodeTable,sql,"id"); sql="SELECT transaction_outputs.id+(99*transaction_inputs.id) as id, to_address_id as target, from_address_id as source, value/100000000.0 AS btc, 0 AS type FROM transaction_inputs LEFT JOIN transaction_outputs ON transaction_outputs.transaction_id=transaction_inputs.transaction_id WHERE from_address_id IN ("+builder+") AND to_address_id NOT NULL"; dbSource.getData(transactionEdgeTable,sql,"id"); sql="SELECT transaction_outputs.id+(99*transaction_inputs.id) as id, to_address_id as target, from_address_id as source, value/100000000.0 AS btc, 0 AS type FROM transaction_outputs LEFT JOIN transaction_inputs ON transaction_outputs.transaction_id=transaction_inputs.transaction_id WHERE to_address_id IN ("+builder+") AND from_address_id NOT NULL"; dbSource.getData(transactionEdgeTable,sql,"id"); viz.run("color"); } catch (DataIOException e) { throw new RuntimeException(e); } } } }