diff --git a/uk/ac/sanger/artemis/circular/Block.java b/uk/ac/sanger/artemis/circular/Block.java index 8a24bc6adbd521ae3d7510c9cd1831164855affa..5265b6670e41550ee76ece435195effae8c03048 100644 --- a/uk/ac/sanger/artemis/circular/Block.java +++ b/uk/ac/sanger/artemis/circular/Block.java @@ -610,7 +610,7 @@ public class Block implements Transferable * @param x x position * @param y y position */ - public void setBlockLocation(int x, int y, final TrackViewer viewer) + public void setBlockLocation(int x, int y, final TrackManager viewer) { if(current_dna.isCircular()) { diff --git a/uk/ac/sanger/artemis/circular/DNADraw.java b/uk/ac/sanger/artemis/circular/DNADraw.java index 86be7aa9d55c3be7a8de86e9d91f531535c8ead6..ecd09010fc420a83d03f2e1679a12662d1a7b9ec 100644 --- a/uk/ac/sanger/artemis/circular/DNADraw.java +++ b/uk/ac/sanger/artemis/circular/DNADraw.java @@ -61,7 +61,11 @@ import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; +import java.io.BufferedReader; +import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; @@ -87,7 +91,6 @@ public class DNADraw extends ScrollPanel implements Printable, DragGestureListener, DragSourceListener, DropTargetListener { - private static final long serialVersionUID = 1L; public static JScrollPane jsp; private DNADraw current_dna; @@ -130,7 +133,7 @@ public class DNADraw extends ScrollPanel private Graph userGraph; protected static int Y_SHIFT = -35; protected static int THETA = -90; - private TrackViewer viewer; + private TrackManager trackManager; private AffineTransform original; // linear plot variables @@ -197,7 +200,28 @@ public class DNADraw extends ScrollPanel this.addMouseListener(mouseListener); } - + private String getVersion() + { + final ClassLoader cl = this.getClass().getClassLoader(); + try + { + String line; + InputStream in = cl.getResourceAsStream("etc/versions"); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + while((line = reader.readLine()) != null) + { + if(line.startsWith("DNAPlot")) + return line.substring( "DNAPlot".length() ).trim(); + } + reader.close(); + in.close(); + } + catch (Exception ex) + { + } + return null; + } + /** * Add list of features to a track * @param features @@ -956,7 +980,7 @@ public class DNADraw extends ScrollPanel * @param g * @return */ - private boolean containsGraph(Graph g) + protected boolean containsGraph(Graph g) { int ncomponents = getComponentCount(); for(int i=0; i<ncomponents; i++) @@ -1099,7 +1123,7 @@ public class DNADraw extends ScrollPanel public void actionPerformed(ActionEvent e) { Wizard.readEntry(DNADraw.this, getBases()); - viewer.refresh(); + trackManager.refresh(); repaint(); } }); @@ -1141,7 +1165,13 @@ public class DNADraw extends ScrollPanel fileMenu.add(printPreview); fileMenu.add(new JSeparator()); - + fileMenu.add(TrackManager.getExportTrackTemplateMenuItem(null, this)); + + if(trackManager == null) + trackManager = new TrackManager(DNADraw.this); + fileMenu.add(trackManager.getImportTrackTemplateMenuItem(null)); + fileMenu.add(new JSeparator()); + final JMenuItem fileMenuExit; if(!close) fileMenuExit = new JMenuItem("Exit"); @@ -1199,7 +1229,11 @@ public class DNADraw extends ScrollPanel graph_menu.add(gc); final JCheckBoxMenuItem gcPlot = new JCheckBoxMenuItem("Draw"); - gcPlot.setState(false); + + if(gcGraph == null) + gcPlot.setState(false); + else + gcPlot.setState(true); gcPlot.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent event) @@ -1236,8 +1270,12 @@ public class DNADraw extends ScrollPanel JMenu gcSkew = new JMenu("GC Skew"); graph_menu.add(gcSkew); - final JCheckBoxMenuItem gcSkewPlot = new JCheckBoxMenuItem("GC Skew plot"); - gcSkewPlot.setState(false); + final JCheckBoxMenuItem gcSkewPlot = new JCheckBoxMenuItem("Draw"); + if(gcSkewGraph == null) + gcSkewPlot.setState(false); + else + gcSkewPlot.setState(true); + gcSkewPlot.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent event) @@ -1277,8 +1315,11 @@ public class DNADraw extends ScrollPanel JMenu user = new JMenu("User"); graph_menu.add(user); - final JCheckBoxMenuItem userPlot = new JCheckBoxMenuItem("User plot"); - userPlot.setState(false); + final JCheckBoxMenuItem userPlot = new JCheckBoxMenuItem("Draw"); + if(userGraph == null) + userPlot.setState(false); + else + userPlot.setState(true); userPlot.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent event) @@ -1377,12 +1418,12 @@ public class DNADraw extends ScrollPanel if(getArtemisEntryGroup() != null) { - viewer = new TrackViewer(DNADraw.this); + trackManager = new TrackManager(DNADraw.this); tracksMenu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - viewer.setVisible(true); + trackManager.setVisible(true); } }); } @@ -1685,7 +1726,7 @@ public class DNADraw extends ScrollPanel { Point loc = e.getLocation(); Block b = (Block)t.getTransferData(Block.BLOCK); - b.setBlockLocation(loc.x,loc.y,viewer); + b.setBlockLocation(loc.x,loc.y,trackManager); DNADraw.this.repaint(); } catch(Exception ufe){} @@ -1725,110 +1766,6 @@ public class DNADraw extends ScrollPanel { return block; } - - public static void main(String arg[]) - { - final Wizard wiz = new Wizard(null); - final DNADraw dna = wiz.getDNADraw(); - - /** - final DNADraw dna = new DNADraw(); - final String seq = - "taaaggtagaattggaaaaattggaaaaattggaaaaatcatgtgatcac"+ - "tgtaaaacaactaacaaatgcaagaatgattatgataaaaataaatgtga"+ - "aaagtgtaaaacgagatgtcaacaatatgataattttattcttaaatgga"+ - "aaactctattcgatatacaatctaagaaatacaaagaattgtatgaacca"+ - "atagatacaaaaaactctacttatgatcatgttgaaaattttgtacaaaa"+ - "gttgaaaaaatataaaaatgaatgttctgttgaaagcgtttctgaatatc"+ - "ttcatgaaacaagtaagtgtttgaattataaatttgatgaaaatgatggt"+ - "tcttctaatatacgatcatatgcttttgaagaaacaccaaaaagttataa"+ - "agaagcttgcagttgtacattaccttctaagaatccattggataattgtc"+ - "ctaccgatcaaaacaaagatgtatgtaaggaattacaaacttttaccttc"+ - "tgctcgaagaatgattatgataataatcttgataattggaacgcatacct"+ - "tgttcttaatagttcagatgataataaaggtgtattgattcctccaagaa"+ - "gaagacatttatgtacaagacctatcactgcatataattatagaaaaggt"+ - "gataaagaaattttaaaaaaaaaacttcttacttctgctttcagtcaagg"+ - "acaattgttaggtcaaaaatataaatcggaagaagagttgtgctttgagg"+ - "caatgaaatatagttatgcagattattccgatataattaaaggaactgat"+ - "atgatggacacttcattatctgaaaaaattaaaaaaatatttgaaacatc"+ - "aaatcaagacactgaagattgtaaaacatggtgggaaaaaaatagaagtc"+ - "atgtatggcacgctatgttatgtggatatatatcaaaaaacaaaaatgag"+ - "aacattaacccaaaatggtgtaatgtacctactgaagatggaactgatca"+ - "attcttaagatggttaattgaatgggcaatgcaagcatgtaaagaaaaga"+ - "aacgtgtaagggattcattaaaaacaaaatgtcgttgttcaaacaaagat"+ - "aattttaaagcgtcagaattattaagacaacctggatgtcagaatgatat"+ - "tagaaaatatattagcttgaatatattgatacaaaattcaatggaaaatc"+ - "taaatataaaatataaaaaattcaaagatcaatcttcaggtttagggttc"+ - "agggtttagggttcagggtttagggtttagggttcagggttttaggttta"+ - "gggttcagggtttagggttcagggtttagggtttagggttcagggtttta"+ - "gggtttagggttcagggtttagggtttaggtttagggtttaggtttaggg"+ - "ttcagggtttaggtttagggttcagggtttaggtttagggttcagggttt"+ - "agggttcagggttcagggtttagggttccggtttagggttcagggttcag"+ - "ggtttagggtttagggtttagggttcagggttcaggtttagggtttaggg"+ - "ttcagggtttagggtttaggtttcagggtttagggtttagggtttagggt"+ - "ttaggtttagggtttagggtttaggtttagggtttagggttcatggttta"+ - "gggtttagggtttagggtttagggtttagggtttaggtttagggttgtgg"+ - "tttagggtttagggtttagggttcagggtttagggtttagggttcagggt"; - - Bases bases = new Bases(new uk.ac.sanger.artemis.io.RawStreamSequence(seq)); - - dna.setBases( bases ); - int sequenceLength = bases.getLength(); - - - // set sequence length and - Hashtable lineAttr = new Hashtable(); - lineAttr.put("lsize",new Integer(1)); - lineAttr.put("circular",new Boolean(true)); - lineAttr.put("start",new Integer(0)); - lineAttr.put("end",new Integer(sequenceLength)); - dna.setLineAttributes(lineAttr); - - // set ticks - int div; - if(sequenceLength < 1000) - div = 100; - else if(sequenceLength < 10000) - div = 1000; - else if(sequenceLength < 100000) - div = 10000; - else - div = 100000; - int tick = sequenceLength/div; - tick = tick*(div/10); - dna.setMinorTickInterval(tick); - dna.setTickInterval(tick); - - final List features = new Vector(); - features.add(new Feature("a", 20, 250, 2)); - features.add(new Feature("b", 300, 550, 2)); - - final Track track = new Track(0.9); - dna.setGeneticMarker(new Vector()); - dna.addFeaturesToTrack(features, track, true); - - final Track track2 = new Track(0.8); - dna.addFeatureToTrack(new Feature("cc", 1400, 1555, 5), track2, true); - **/ - - // - final JFrame f = new JFrame("DNA Viewer"); - - Dimension d = f.getToolkit().getScreenSize(); - jsp = new JScrollPane(dna); - jsp.getViewport().setBackground(Color.white); - f.getContentPane().add(jsp); - f.setJMenuBar(dna.createMenuBar()); - - //dna.add(new Graph(dna)); - f.pack(); - f.setLocation(((int)d.getWidth()-f.getWidth())/4, - ((int)d.getHeight()-f.getHeight())/2); - - - //dna.add(dna.new BlockPanel(dna)); - f.setVisible(true); - } public int getBasesPerLine() @@ -1901,6 +1838,83 @@ public class DNADraw extends ScrollPanel { this.borderHeight2 = borderHeight2; } + + public TrackManager getTrackManager() + { + return trackManager; + } + + public void setTrackManager(TrackManager trackManager) + { + this.trackManager = trackManager; + } + + public Graph getGcGraph() + { + return gcGraph; + } + + public void setGcGraph(Graph gcGraph) + { + this.gcGraph = gcGraph; + } + + public Graph getGcSkewGraph() + { + return gcSkewGraph; + } + + public void setGcSkewGraph(Graph gcSkewGraph) + { + this.gcSkewGraph = gcSkewGraph; + } + + public Graph getUserGraph() + { + return userGraph; + } + + public void setUserGraph(Graph userGraph) + { + this.userGraph = userGraph; + } + + public static void main(String arg[]) + { + final Wizard wiz; + + if(arg.length > 0 && arg[0].equals("-t")) + { + final File fileTemplate = new File(arg[1]); + wiz = new Wizard(fileTemplate); + } + else + wiz = new Wizard((DNADraw)null); + final DNADraw dna = wiz.getDNADraw(); + + // + final String version = dna.getVersion(); + final JFrame f = new JFrame(); + if(version == null) + f.setTitle("DNA Plot"); + else + f.setTitle("DNA Plot :: "+version); + + Dimension d = f.getToolkit().getScreenSize(); + jsp = new JScrollPane(dna); + jsp.getViewport().setBackground(Color.white); + f.getContentPane().add(jsp); + f.setJMenuBar(dna.createMenuBar()); + + //dna.add(new Graph(dna)); + f.pack(); + f.setLocation(((int)d.getWidth()-f.getWidth())/4, + ((int)d.getHeight()-f.getHeight())/2); + + + //dna.add(dna.new BlockPanel(dna)); + f.setVisible(true); + } /*class BlockPanel extends JPanel { diff --git a/uk/ac/sanger/artemis/circular/Graph.java b/uk/ac/sanger/artemis/circular/Graph.java index d82cd9066b551da8d1d9280ddc4508bdb6872880..156ad5677a402474f2eb70502a3c0bbeefee79d2 100644 --- a/uk/ac/sanger/artemis/circular/Graph.java +++ b/uk/ac/sanger/artemis/circular/Graph.java @@ -102,26 +102,7 @@ public abstract class Graph extends JPanel int nvalues = bases.getLength()/getBaseStepSize(); if(value_array == null) - { - value_array = new float [nvalues]; - gcAverage = 0; - for(int i=0; i<nvalues; i++) - { - int start = (i*getBaseStepSize())+1; - int end = start+getWindowSize(); - - if(end > bases.getLength()) - end = bases.getLength(); - - value_array[i] = calculateValue(start, end); - if(value_array[i] > maxValue) - maxValue = value_array[i]; - if(value_array[i] < minValue) - minValue = value_array[i]; - gcAverage += value_array[i]; - } - gcAverage = gcAverage/nvalues; - } + calcGraphValues(); int minPos = (int)((ddiameter/2.d)*getTrack()); int maxPos = minPos + (int)((ddiameter/2.d)*getGraphHeight()); @@ -181,31 +162,10 @@ public abstract class Graph extends JPanel int borderHeight2 = getCurrentDna().getBorderHeight2(); Bases bases = getBases(); - int nvalues = bases.getLength()/getBaseStepSize(); if(value_array == null) - { - value_array = new float [nvalues]; - gcAverage = 0; - for(int i=0; i<nvalues; i++) - { - int start = (i*getBaseStepSize())+1; - int end = start+getWindowSize(); - - if(end > bases.getLength()) - end = bases.getLength(); - - value_array[i] = calculateValue(start, end); - if(value_array[i] > maxValue) - maxValue = value_array[i]; - if(value_array[i] < minValue) - minValue = value_array[i]; - gcAverage += value_array[i]; - } - gcAverage = gcAverage/nvalues; - } - + calcGraphValues(); int minPos = (int)(lineHeight*(1-getTrack())); int maxPos = minPos + (int)(lineHeight*getGraphHeight()); @@ -239,6 +199,30 @@ public abstract class Graph extends JPanel } } + protected void calcGraphValues() + { + Bases bases = getBases(); + int nvalues = bases.getLength()/getBaseStepSize(); + value_array = new float [nvalues]; + gcAverage = 0; + for(int i=0; i<nvalues; i++) + { + int start = (i*getBaseStepSize())+1; + int end = start+getWindowSize(); + + if(end > bases.getLength()) + end = bases.getLength(); + + value_array[i] = calculateValue(start, end); + if(value_array[i] > maxValue) + maxValue = value_array[i]; + if(value_array[i] < minValue) + minValue = value_array[i]; + gcAverage += value_array[i]; + } + gcAverage = gcAverage/nvalues; + } + protected int getWindowSize() { return windowSize; @@ -514,6 +498,55 @@ public abstract class Graph extends JPanel repaint(); } + /** + * Used to write out options to template file + * @return + */ + protected String getOptionsStr() + { + return "height="+getGraphHeight()+" window_size="+getWindowSize()+ + " base_step_size="+getBaseStepSize()+" track="+getTrack()+ + " minus_colour="+getMinusColour().getRed()+":"+ + getMinusColour().getGreen()+":"+ + getMinusColour().getBlue()+ + " plus_colour="+getPlusColour().getRed()+":"+ + getPlusColour().getGreen()+":"+ + getPlusColour().getBlue(); + } + + /** + * Used when reading in a template file + * @param options + */ + protected void setOptionsStr(final String options[]) + { + for(int i=0; i<options.length; i++) + { + if(options[i].startsWith("height")) + setGraphHeight(Float.parseFloat(options[i+1])); + else if(options[i].startsWith("window_size")) + setWindowSize(Integer.parseInt(options[i+1])); + else if(options[i].startsWith("base_step_size")) + setBaseStepSize(Integer.parseInt(options[i+1])); + else if(options[i].startsWith("track")) + setTrack(Double.parseDouble(options[i+1])); + else if(options[i].startsWith("minus_colour")) + { + String col[] = options[i+1].split(":"); + setMinusColour(new Color(Integer.parseInt(col[0]), + Integer.parseInt(col[1]), + Integer.parseInt(col[2]))); + } + else if(options[i].startsWith("plus_colour")) + { + String col[] = options[i+1].split(":"); + setPlusColour(new Color(Integer.parseInt(col[0]), + Integer.parseInt(col[1]), + Integer.parseInt(col[2]))); + } + } + } + private void setColorButton(final JButton button, final Color col, final ActionListener okListener, diff --git a/uk/ac/sanger/artemis/circular/Track.java b/uk/ac/sanger/artemis/circular/Track.java index 4c0c2bf556460b55d51c1313b0523fb1a2deaee3..eda2666b36cefac9a53fd17b1636cfcb62e7e51c 100644 --- a/uk/ac/sanger/artemis/circular/Track.java +++ b/uk/ac/sanger/artemis/circular/Track.java @@ -21,6 +21,11 @@ package uk.ac.sanger.artemis.circular; import java.awt.Color; +import java.io.IOException; +import java.io.Writer; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; import uk.ac.sanger.artemis.Entry; import uk.ac.sanger.artemis.Feature; @@ -28,6 +33,7 @@ import uk.ac.sanger.artemis.FeatureKeyPredicate; import uk.ac.sanger.artemis.FeatureKeyQualifierPredicate; import uk.ac.sanger.artemis.FeaturePredicate; import uk.ac.sanger.artemis.io.Key; +import uk.ac.sanger.artemis.util.FileDocument; public class Track { @@ -235,4 +241,126 @@ public class Track { this.colour = colour; } + + protected void setPropertiesFromTemplate(final String line) + { + final String properties[] = line.split("\t"); + + setPosition(Double.parseDouble(properties[0])); + setSize(Float.parseFloat(properties[1])); + setShowForward(Boolean.parseBoolean(properties[2])); + setShowReverse(Boolean.parseBoolean(properties[3])); + setNotQualifier(Boolean.parseBoolean(properties[4])); + setAny(Boolean.parseBoolean(properties[5])); + + if(properties[6].equals("null")) + setKeyStr(null); + else + setKeyStr(properties[6]); + if(properties[7].equals("null")) + setQualifier(null); + else + setQualifier(properties[7]); + if(properties[8].equals("null")) + setQualifierValue(null); + else + setQualifierValue(properties[8]); + if(properties[9].equals("null")) + setColour(null); + else + { + String colourRGB[] = properties[9].split(":"); + Color colour = new Color(Integer.parseInt(colourRGB[0]), + Integer.parseInt(colourRGB[1]), + Integer.parseInt(colourRGB[2])); + setColour(colour); + } + } + + /** + * Write the track properties out + * @param writer + * @throws IOException + */ + protected void write(final Writer writer) throws IOException + { + writer.write(position+"\t"+ + size+"\t"+ + showForward+"\t"+ + showReverse+"\t"+ + isNotQualifier()+"\t"+ + any+"\t"+ + keyStr+"\t"+ + qualifier+"\t"+ + qualifierValue+"\t"+ + ( colour != null ? + colour.getRed()+":"+colour.getGreen()+":"+colour.getBlue() : null)+"\t"+ + ( entry != null ? entry.getName()+"\t"+entry.getRootDocument() : null )+ + "\n"); + } + + /** + * Write a header line for the track properties + * @param writer + * @throws IOException + */ + protected static void writeHeader(final Writer writer, final DNADraw dna) throws IOException + { + DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); + writer.write("## DNA Plot :: track template (created: "+ + dateFormat.format(new Date())+")\n"); + writer.write("# line attributes: start="+dna.getStart()+ + " end="+dna.getEnd()+" " + + "line_size="+dna.getLineSize()+ + " circular="+dna.isCircular()); + + if(!dna.isCircular()) + writer.write(" line_height="+dna.getLineHeight()+ + " bases_per_line="+dna.getBasesPerLine()); + + writer.write("\n# tick marks: major="+dna.getTickInterval()+ + " minor="+dna.getMinorTickInterval()+"\n"); + + // graphs + if(dna.getUserGraph() != null && dna.containsGraph(dna.getUserGraph())) + { + FileDocument doc = (FileDocument) ((UserGraph)dna.getUserGraph()).getDocument(); + String fileName = doc.getFile().getAbsolutePath(); + + writer.write("# User Graph: "+dna.getUserGraph().getOptionsStr()+ + " file_name="+fileName+"\n"); + } + if(dna.getGcGraph() != null && dna.containsGraph(dna.getGcGraph())) + writer.write("# GC Graph: "+dna.getGcGraph().getOptionsStr()+"\n"); + if(dna.getGcSkewGraph() != null && dna.containsGraph(dna.getGcSkewGraph())) + writer.write("# GC Skew Graph: "+dna.getGcSkewGraph().getOptionsStr()+"\n"); + + writer.write( + "# Columns are:\n"+ + "# POS - track position\n"+ + "# SIZE - track size\n"+ + "# FWD - show forward strand features\n"+ + "# REV - show reverse strand features\n"+ + "# NOT - use NOT\n"+ + "# ANY - show any features\n"+ + "# KEY - show features of this key\n"+ + "# QUAL - show features with this qualifier\n"+ + "# VAL - show features with this qualifier value(s)\n"+ + "# COL - colour for this track e.g. 255:0:0 (R:G:B) or NULL\n"+ + "# NAME - file entry name or null\n"+ + "# DIR - root directory for this file\n#\n"); + writer.write( + "#POS\t"+ + "SIZE\t"+ + "FWD\t"+ + "REV\t"+ + "NOT \t"+ + "ANY\t"+ + "KEY\t"+ + "QUAL\t"+ + "VAL\t"+ + "COL\t"+ + "NAME\t"+ + "DIR\n"); + } } \ No newline at end of file diff --git a/uk/ac/sanger/artemis/circular/TrackViewer.java b/uk/ac/sanger/artemis/circular/TrackManager.java similarity index 75% rename from uk/ac/sanger/artemis/circular/TrackViewer.java rename to uk/ac/sanger/artemis/circular/TrackManager.java index 833f744b0fb8da4542001d1e2a54e74969ecc713..aec1accef32d8122e1feed990a08ff7ead3342d4 100644 --- a/uk/ac/sanger/artemis/circular/TrackViewer.java +++ b/uk/ac/sanger/artemis/circular/TrackManager.java @@ -29,13 +29,24 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; import java.util.StringTokenizer; import java.util.Vector; import javax.swing.JButton; import javax.swing.JCheckBox; +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.JScrollPane; @@ -51,11 +62,12 @@ import uk.ac.sanger.artemis.FeaturePredicateVector; import uk.ac.sanger.artemis.FeatureVector; import uk.ac.sanger.artemis.components.KeyChoice; import uk.ac.sanger.artemis.components.QualifierChoice; +import uk.ac.sanger.artemis.components.StickyFileChooser; import uk.ac.sanger.artemis.io.Key; import uk.ac.sanger.artemis.io.Range; import uk.ac.sanger.artemis.io.RangeVector; -class TrackViewer extends JFrame +class TrackManager extends JFrame { private static final long serialVersionUID = 1L; private DNADraw dnaDraw; @@ -70,21 +82,147 @@ class TrackViewer extends JFrame private TextFieldFloat trackSize[]; private TextFieldFloat trackPosition[]; - public TrackViewer(final DNADraw dnaDraw) + public TrackManager(final DNADraw dnaDraw) { super("Track Manager"); this.dnaDraw = dnaDraw; setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + + createMenu(); JScrollPane jsp = new JScrollPane(getPanelComponents()); getContentPane().add(jsp); pack(); } - protected void refresh() + /** + * Create a menu for the track manager. + */ + private void createMenu() { - getContentPane().removeAll(); - getContentPane().add(getPanelComponents()); - pack(); + final JMenu menuFile = new JMenu("File"); + final JMenuBar menuBar = new JMenuBar(); + setJMenuBar(menuBar); + menuBar.add(menuFile); + menuFile.add(getExportTrackTemplateMenuItem(this, dnaDraw)); + menuFile.add(getImportTrackTemplateMenuItem(this)); + final JMenuItem closeMenu = new JMenuItem("Close"); + closeMenu.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + TrackManager.this.setVisible(false); + } + }); + menuFile.add(closeMenu); + } + + protected JMenuItem getImportTrackTemplateMenuItem(final JFrame f) + { + final JMenuItem readTemplate = new JMenuItem("Import Track Template..."); + readTemplate.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + StickyFileChooser fileDialog = new StickyFileChooser(); + int status = fileDialog.showOpenDialog(f); + if(status == JFileChooser.CANCEL_OPTION) + return; + + final File fileRead = fileDialog.getSelectedFile(); + if(!fileRead.exists()) + { + JOptionPane.showMessageDialog(f, + fileRead.getName()+" not found.", + "Problem Reading File", + JOptionPane.WARNING_MESSAGE); + return; + } + + try + { + final FileReader reader = new FileReader(fileRead); + BufferedReader inputStream = new BufferedReader(reader); + String inLine = null; + + Track[] tracks = Wizard.getTracks(); + int trackCount = 0; + + while ((inLine = inputStream.readLine()) != null) + { + if(inLine.startsWith("#") || inLine.trim().equals("")) + continue; + + if(trackCount >= tracks.length) + { + addTrack(); + tracks = Wizard.getTracks(); + } + tracks[trackCount].setPropertiesFromTemplate(inLine); + trackCount++; + } + inputStream.close(); + reader.close(); + refresh(); + } + catch(FileNotFoundException e) + { + e.printStackTrace(); + } + catch(IOException e) + { + e.printStackTrace(); + } + } + }); + return readTemplate; + } + + /** + * Menu Item with associated ActionListener for exporting the properties + * of this track. + * @param f + * @return + */ + protected static JMenuItem getExportTrackTemplateMenuItem(final JFrame f, + final DNADraw dnaDraw) + { + final JMenuItem saveTemplate = new JMenuItem("Export Track Template..."); + saveTemplate.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + StickyFileChooser fileDialog = new StickyFileChooser(); + int status = fileDialog.showSaveDialog(f); + if(status == JFileChooser.CANCEL_OPTION) + return; + + final File fileWrite = fileDialog.getSelectedFile(); + if(fileWrite.exists()) + { + status = JOptionPane.showConfirmDialog(f, fileWrite.getName()+ + " exists. Overwrite?", + "Selected File Exists", + JOptionPane.OK_CANCEL_OPTION); + if(status == JFileChooser.CANCEL_OPTION) + return; + } + + final Track[] tracks = Wizard.getTracks(); + try + { + final Writer writer = new FileWriter(fileWrite); + Track.writeHeader(writer, dnaDraw); + for(int i=0; i<tracks.length; i++) + tracks[i].write(writer); + writer.close(); + } + catch(IOException e) + { + e.printStackTrace(); + } + } + }); + return saveTemplate; } private JPanel getPanelComponents() @@ -344,9 +482,7 @@ class TrackViewer extends JFrame pack(); setVisible(true); - update(Wizard.getTracks(), keyChoice, qualifierChoice, qualifierValue, - notQualifier, showForward, showReverse, - showAny, trackSize, trackPosition); + update(Wizard.getTracks()); } }); optionBox.add(deleteTrack, c); @@ -362,9 +498,7 @@ class TrackViewer extends JFrame { public void actionPerformed(ActionEvent e) { - update(tracks, keyChoice, qualifierChoice, qualifierValue, - notQualifier, showForward, showReverse, - showAny, trackSize, trackPosition); + update(tracks); } }); @@ -378,36 +512,39 @@ class TrackViewer extends JFrame { public void actionPerformed(ActionEvent e) { - Entry entry; - if(Wizard.getTracks().length > 0) - entry = Wizard.getTracks()[0].getEntry(); - else - entry = dnaDraw.getArtemisEntryGroup().elementAt(0); - - Wizard.addTrack( entry ); - getContentPane().removeAll(); - - JScrollPane jsp = new JScrollPane(getPanelComponents()); - getContentPane().add(jsp); - pack(); - - setVisible(true); + addTrack(); } }); return optionBox; } - private void update(final Track[] tracks, - final KeyChoice keyChoice[], - final QualifierChoice qualifierChoice[], - final JTextField qualifierValue[] , - final JCheckBox notQualifier[], - final JCheckBox showForward[], - final JCheckBox showReverse[], - final JCheckBox showAny[], - final TextFieldFloat trackSize[], - final TextFieldFloat trackPosition[]) + protected void refresh() + { + getContentPane().removeAll(); + JScrollPane jsp = new JScrollPane(getPanelComponents()); + getContentPane().add(jsp); + pack(); + } + + private void addTrack() + { + Entry entry; + if(Wizard.getTracks().length > 0) + entry = Wizard.getTracks()[0].getEntry(); + else + entry = dnaDraw.getArtemisEntryGroup().elementAt(0); + + Wizard.addTrack( entry ); + refresh(); + setVisible(true); + } + + /** + * Update the tracks based on the Track Manager settings + * @param tracks + */ + protected void update(final Track[] tracks) { // update tracks for(int i=0; i<tracks.length; i++) @@ -472,15 +609,21 @@ class TrackViewer extends JFrame } tracks[i].setShowForward(showForward[i].isSelected()); tracks[i].setShowReverse(showReverse[i].isSelected()); + tracks[i].setNotQualifier(!notQualifier[i].isSelected()); tracks[i].setSize((float) trackSize[i].getValue()); tracks[i].setPosition(trackPosition[i].getValue()); } // update viewer + updateDNADraw(dnaDraw, tracks); + } + + + private static void updateDNADraw(final DNADraw dnaDraw, final Track[] tracks) + { dnaDraw.getBlock().removeAll(dnaDraw.getBlock()); final FeatureVector features = dnaDraw.getArtemisEntryGroup().getAllFeatures(); - for(int i=0; i<features.size(); i++) { Feature f = features.elementAt(i); diff --git a/uk/ac/sanger/artemis/circular/UserGraph.java b/uk/ac/sanger/artemis/circular/UserGraph.java index 4b3346250aa8572f59f444839ac965d4c152a85f..fe6cd2fc9eca6ae9e5a824430d9be2d039834aca 100644 --- a/uk/ac/sanger/artemis/circular/UserGraph.java +++ b/uk/ac/sanger/artemis/circular/UserGraph.java @@ -55,12 +55,15 @@ public class UserGraph extends Graph * The average calculated by readData (). **/ private float average_value = 0; + + private Document document; public UserGraph(DNADraw currentDna, final Document document) throws IOException { super(currentDna); + this.document = document; final Reader document_reader = document.getReader(); LinePushBackReader pushback_reader = @@ -147,5 +150,10 @@ public class UserGraph extends Graph } average_value /= seqLength; } + + public Document getDocument() + { + return document; + } } \ No newline at end of file diff --git a/uk/ac/sanger/artemis/circular/Wizard.java b/uk/ac/sanger/artemis/circular/Wizard.java index 34cada978d1c283a5c682e6068e91dda02cf2fa7..495b81743d75622c00de3a0c5dcd129ec1b1c24d 100644 --- a/uk/ac/sanger/artemis/circular/Wizard.java +++ b/uk/ac/sanger/artemis/circular/Wizard.java @@ -24,14 +24,21 @@ package uk.ac.sanger.artemis.circular; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; import java.util.Vector; import java.util.Hashtable; import javax.swing.Box; import javax.swing.ButtonGroup; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JProgressBar; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; @@ -43,10 +50,17 @@ import uk.ac.sanger.artemis.Feature; import uk.ac.sanger.artemis.FeatureVector; import uk.ac.sanger.artemis.Options; import uk.ac.sanger.artemis.SimpleEntryGroup; +import uk.ac.sanger.artemis.components.EntryFileDialog; +import uk.ac.sanger.artemis.components.MessageDialog; +import uk.ac.sanger.artemis.components.StickyFileChooser; +import uk.ac.sanger.artemis.components.Utilities; +import uk.ac.sanger.artemis.io.EntryInformation; import uk.ac.sanger.artemis.io.Range; import uk.ac.sanger.artemis.io.RangeVector; import uk.ac.sanger.artemis.sequence.Bases; import uk.ac.sanger.artemis.sequence.NoSequenceException; +import uk.ac.sanger.artemis.util.Document; +import uk.ac.sanger.artemis.util.DocumentFactory; import uk.ac.sanger.artemis.util.OutOfRangeException; @@ -73,6 +87,18 @@ public class Wizard // option 2 - edit existing dna if(n == 0) dna = getDNADrawFromFile(dna_current); + else if(n == 3) + { + StickyFileChooser chooser = new StickyFileChooser(); + chooser.showOpenDialog(null); + + File fileTemplate = chooser.getSelectedFile(); + if(!fileTemplate.exists()) + JOptionPane.showMessageDialog(null, + fileTemplate.getName()+" cannot be found!", + "Missing File", JOptionPane.WARNING_MESSAGE); + loadTemplate(fileTemplate); + } else if(n == 1 || n == 2) { Vector block = new Vector(); @@ -165,8 +191,286 @@ public class Wizard s = la.getEnd(); dna.setEnd(s); + } + } + + /** + * Open a DNA plot based on a template file + * @param template + */ + public Wizard(final File template) + { + loadTemplate(template); + } + + /** + * Load from a template file + * @param template + */ + private void loadTemplate(final File template) + { + final JFrame f = new JFrame(); + f.setUndecorated(true); + JPanel panel = (JPanel) f.getContentPane(); + JProgressBar progress = new JProgressBar(1,10); + progress.setStringPainted(true); + progress.setString("Reading from "+template.getName()+" "); + progress.setValue(2); + progress.setPreferredSize(new Dimension(350, progress.getPreferredSize().height)); + panel.add(progress, BorderLayout.CENTER); + f.pack(); + Utilities.centreFrame(f); + f.setVisible(true); + + if(dna == null) + dna = new DNADraw(); + Options.getOptions(); + + + try + { + final FileReader reader = new FileReader(template); + final BufferedReader inputStream = new BufferedReader(reader); + final EntryGroup entryGroup = new SimpleEntryGroup(); + final Hashtable fileEntrys = new Hashtable(); + Vector v_tracks = new Vector(); + String inLine = null; + String lineAttrStr[] = null; + String tickMarksStr[] = null; + String gcGraphStr[] = null; + String gcSkewGraphStr[] = null; + String userGraphStr[] = null; + + String lineAttrStart = "# line attributes:"; + String tickMarksStart = "# tick marks:"; + String gcGraphStart = "# GC Graph:"; + String gcSkewGraphStart = "# GC Skew Graph:"; + String userGraphStart = "# User Graph:"; + + while((inLine = inputStream.readLine()) != null) + { + if(inLine.startsWith("#") || inLine.trim().equals("")) + { + if(inLine.startsWith(lineAttrStart)) + lineAttrStr = inLine.substring(lineAttrStart.length()).trim().split("[=\\s]"); + else if(inLine.startsWith(tickMarksStart)) + tickMarksStr = inLine.substring(tickMarksStart.length()).trim().split("[=\\s]"); + else if(inLine.startsWith(gcGraphStart)) + gcGraphStr = inLine.substring(gcGraphStart.length()).trim().split("[=\\s]"); + else if(inLine.startsWith(gcSkewGraphStart)) + gcSkewGraphStr = inLine.substring(gcSkewGraphStart.length()).trim().split("[=\\s]"); + else if(inLine.startsWith(userGraphStart)) + userGraphStr = inLine.substring(userGraphStart.length()).trim().split("[=\\s]"); + continue; + } + + String properties[] = inLine.split("\t"); + String fileName = properties[11] + File.separator + properties[10]; + Entry entry; + if(!fileEntrys.containsKey(fileName)) + { + progress.setString("Reading "+properties[10]); + progress.setValue(4); + entry = getEntry(fileName, entryGroup); + if(entry == null) + continue; + fileEntrys.put(fileName, entry); + } + else + { + entry = (Entry)fileEntrys.get(fileName); + } + + Track track = new Track(.9,entry); + track.setPropertiesFromTemplate(inLine); + v_tracks.add(track); + } + inputStream.close(); + reader.close(); + + progress.setString("Read template "+template.getName()); + progress.setValue(7); + Track[] newTracks = new Track[v_tracks.size()]; + for(int i=0; i<v_tracks.size(); i++) + newTracks[i] = (Track) v_tracks.get(i); + + Wizard.tracks = newTracks; + + dna.setArtemisEntryGroup(entryGroup); + + int sequenceLength = entryGroup.getSequenceEntry().getBases().getLength(); + + Hashtable lineAttr = new Hashtable(); + lineAttr.put("lsize", new Integer(1)); + lineAttr.put("circular", new Boolean(true)); + lineAttr.put("start", new Integer(0)); + lineAttr.put("end", new Integer(sequenceLength)); + if(lineAttrStr != null) + { + for(int i=0; i<lineAttrStr.length; i++) + { + if(lineAttrStr[i].startsWith("line_size")) + lineAttr.put("lsize", new Integer(lineAttrStr[i+1])); + else if(lineAttrStr[i].startsWith("circular")) + lineAttr.put("circular", new Boolean(lineAttrStr[i+1])); + else if(lineAttrStr[i].startsWith("line_height")) + dna.setLineHeight(Float.parseFloat(lineAttrStr[i+1])); + else if(lineAttrStr[i].startsWith("bases_per_line")) + dna.setBasesPerLine(Integer.parseInt(lineAttrStr[i+1])); + } + } + dna.setLineAttributes(lineAttr); + + final int div; + if(sequenceLength < 1000) + div = 100; + else if(sequenceLength < 10000) + div = 1000; + else if(sequenceLength < 100000) + div = 10000; + else + div = 100000; + int tick = sequenceLength / div; + tick = tick * (div / 10); + int tick2 = tick / 2; + tick = tick2 * 2; + + if(tickMarksStr != null) + { + for(int i=0; i<tickMarksStr.length; i++) + { + if(tickMarksStr[i].startsWith("major")) + tick = Integer.parseInt(tickMarksStr[i+1]); + else if(tickMarksStr[i].startsWith("minor")) + tick2 = Integer.parseInt(tickMarksStr[i+1]); + } + } + + dna.setGeneticMarker(new Vector()); + dna.setRestrictionEnzyme(new Vector()); + dna.setMinorTickInterval(tick2); + dna.setTickInterval(tick); + + TrackManager trackManager = dna.getTrackManager(); + if(trackManager == null) + { + trackManager = new TrackManager(dna); + dna.setTrackManager(trackManager); + } + trackManager.update(tracks); + loadGraphs(gcGraphStr, gcSkewGraphStr, userGraphStr, dna, progress); + } + catch(FileNotFoundException e) + { + e.printStackTrace(); + } + catch(IOException e) + { + e.printStackTrace(); + } + catch(NoSequenceException e) + { + e.printStackTrace(); + } + f.dispose(); + } + + /** + * + * @param gcGraphStr + * @param gcSkewGraphStr + * @param userGraphStr + * @param dna + */ + private void loadGraphs(final String gcGraphStr[], + final String gcSkewGraphStr[], + final String userGraphStr[], + final DNADraw dna, + final JProgressBar progress) + { + if(gcGraphStr != null) + { + if(progress != null) + progress.setString("Calculating GC graph points"); + GCGraph gcGraph = new GCGraph(dna); + gcGraph.setOptionsStr(gcGraphStr); + dna.setGcGraph(gcGraph); + gcGraph.calcGraphValues(); + dna.add(gcGraph); + } + if(gcSkewGraphStr != null) + { + if(progress != null) + progress.setString("Calculating GC Skew graph points"); + GCSkewGraph gcSkewGraph = new GCSkewGraph(dna); + gcSkewGraph.setOptionsStr(gcSkewGraphStr); + dna.setGcSkewGraph(gcSkewGraph); + gcSkewGraph.calcGraphValues(); + dna.add(gcSkewGraph); + } + if(userGraphStr != null) + { + String fileName = null; + for(int i=0;i<userGraphStr.length; i++) + { + if(userGraphStr[i].startsWith("file_name")) + fileName = userGraphStr[i+1]; + } + final uk.ac.sanger.artemis.util.Document document = + new uk.ac.sanger.artemis.util.FileDocument(new File(fileName)); + try + { + if(progress != null) + progress.setString("Calculating user graph points"); + UserGraph userGraph = new UserGraph(dna, document); + userGraph.setOptionsStr(userGraphStr); + dna.setUserGraph(userGraph); + userGraph.calcGraphValues(); + dna.add(userGraph); + } + catch(IOException e) + { + e.printStackTrace(); + return; + } + } + } + + private Entry getEntry(final String entryFileName, final EntryGroup entryGroup) + throws NoSequenceException + { + final Document entry_document = DocumentFactory.makeDocument(entryFileName); + final EntryInformation artemis_entry_information = + Options.getArtemisEntryInformation(); + + final uk.ac.sanger.artemis.io.Entry new_embl_entry = + EntryFileDialog.getEntryFromFile(null, entry_document, + artemis_entry_information, + false); + + if(new_embl_entry == null) // the read failed + return null; + Entry entry = null; + try + { + Bases bases = null; + if(entryGroup.getSequenceEntry() != null) + bases = entryGroup.getSequenceEntry().getBases(); + if(bases == null) + entry = new Entry(new_embl_entry); + else + entry = new Entry(bases,new_embl_entry); + + entryGroup.add(entry); + } + catch(OutOfRangeException e) + { + new MessageDialog(null, "read failed: one of the features in " + + entryFileName + " has an out of range " + + "location: " + e.getMessage()); } + return entry; } /** @@ -377,10 +681,8 @@ public class Wizard JRadioButton[] radioButtons; - if(dna_current != null) - radioButtons = new JRadioButton[3]; - else - radioButtons = new JRadioButton[2]; + radioButtons = new JRadioButton[3]; + final ButtonGroup group = new ButtonGroup(); radioButtons[0] = new JRadioButton("Read in sequence file"); group.add(radioButtons[0]); @@ -390,14 +692,20 @@ public class Wizard bdown.add(radioButtons[0]); bdown.add(radioButtons[1]); + radioButtons[0].setSelected(true); if(dna_current != null) { radioButtons[2] = new JRadioButton("Edit current dna display"); group.add(radioButtons[2]); radioButtons[2].setSelected(true); - bdown.add(radioButtons[2]); } - + else + { + radioButtons[2] = new JRadioButton("Read template file"); + group.add(radioButtons[2]); + } + bdown.add(radioButtons[2]); + JPanel pane = new JPanel(new BorderLayout()); pane.add(bdown); JOptionPane.showMessageDialog(null, @@ -408,8 +716,10 @@ public class Wizard return 0; else if(radioButtons[1].isSelected()) return 1; - else if(radioButtons[2].isSelected()) + else if(radioButtons[2].isSelected() && dna_current != null) return 2; + else if(radioButtons[2].isSelected()) + return 3; return 1; }