diff --git a/.classpath b/.classpath index 6cb6c677295e1216745131319e1ae767d6ec0707..a071b60b897152574377095ebcbba10e4c73a6e3 100644 --- a/.classpath +++ b/.classpath @@ -17,5 +17,11 @@ <classpathentry kind="lib" path="lib/picard/picard.jar"/> <classpathentry kind="lib" path="lib/picard/sam.jar"/> <classpathentry kind="lib" path="lib/commons-net-2.2.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-awt-util.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-dom.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-ext.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-svggen.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-util.jar"/> + <classpathentry kind="lib" path="lib/batik/batik-xml.jar"/> <classpathentry kind="output" path="ant-build/classes/main"/> </classpath> diff --git a/ChangeLog b/ChangeLog index fbadef0ebfb378428aa21c873d7ee1b2038f9b80..7ed00133084c4621843b5c9698d3d2c987357053 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,16 @@ Version XX + Add SVG (scalable vector graphics) support for Artemis, ACT and DNAPlotter. + + Add support for indexed user graphs using tabix. For example file.plot is a tab + delimited file with column 1 containing the sequence name and column 2 the + positions: + (grep ^"#" file.plot; grep -v ^"#" file.plot | sort -k1,1 -k2,2n) | bgzip > sorted.plot.gz ; + tabix -s 1 -b 2 -e 2 sorted.plot.gz + + Option added to show or hide the average line in the graphs. + + BAM coverage heatmap view added. + Add Rfam sequence search from the RUN menu. Base similarity graph for each VCF added to the VCF view. @@ -13,7 +25,7 @@ Version XX Coverage plots from read alignments (BAM) can be plotted by their strand. - Addition of a Project File Manager for grouping files together for + Addition of a Project File Manager used to group files together for launching in Artemis. When a project has been added or updated the details are saved at the end of each session in '.artemis.project.properties' in the user's home directory. diff --git a/Makefile b/Makefile index 2b20f14ece3af9b84a4e24312cf1947a80b95f5e..ed4aa75a3222ede16e40a62782898bcc73ef2423 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ SHELL=/bin/sh JAVAC := javac -source 1.5 -target 1.5 $(OPT_FLAGS) $(EXTRA_FLAGS) -REAL_CLASSPATH := CLASSPATH=lib/biojava.jar:lib/jemAlign.jar:lib/j2ssh/j2ssh-core.jar:lib/ibatis/ibatis-2.3.4.726.jar:lib/ibatis/log4j-1.2.14.jar:lib/postgresql-8.4-701.jdbc3.jar:lib/picard/picard.jar:lib/picard/sam.jar:lib/commons-net-2.2.jar:. +REAL_CLASSPATH := CLASSPATH=lib/biojava.jar:lib/jemAlign.jar:lib/j2ssh/j2ssh-core.jar:lib/ibatis/ibatis-2.3.4.726.jar:lib/ibatis/log4j-1.2.14.jar:lib/postgresql-8.4-701.jdbc3.jar:lib/picard/picard.jar:lib/picard/sam.jar:lib/commons-net-2.2.jar:lib/batik/batik-awt-util.jar:lib/batik/batik-dom.jar:lib/batik/batik-ext.jar:lib/batik/batik-svggen.jar:lib/batik/batik-util.jar:lib/batik/batik-xml.jar:. NAMES:= \ uk/ac/sanger/artemis/OptionChangeListener \ diff --git a/act b/act index f7aa1fae3f11804ae4620735b055c2a48bd6347f..4200521ecdb9b2301b3e989c86fcdd295cd31de7 100755 --- a/act +++ b/act @@ -31,6 +31,9 @@ ACT_HOME=`dirname "$PRG"`/. CLASSPATH=$ACT_HOME:$ACT_HOME/lib/JacORB.jar:$ACT_HOME/lib/jemAlign.jar:$ACT_HOME/lib/jakarta-regexp-1.2.jar:$ACT_HOME/lib/macos.jar:$ACT_HOME/lib/chado-14-interface.jar:$ACT_HOME/lib/postgresql-8.4-701.jdbc3.jar:$CLASSPATH +# batik jars +CLASSPATH=$CLASSPATH:$ACT_HOME/lib/batik/batik-awt-util.jar:$ACT_HOME/lib/batik/batik-dom.jar:$ACT_HOME/lib/batik/batik-ext.jar:$ACT_HOME/lib/batik/batik-svggen.jar:$ACT_HOME/lib/batik/batik-util.jar:$ACT_HOME/lib/batik/batik-xml.jar + # j2ssh jars CLASSPATH=$CLASSPATH:$ACT_HOME/lib/j2ssh/commons-logging.jar:$ACT_HOME/lib/j2ssh/j2ssh-core.jar:$ACT_HOME/lib/j2ssh/ diff --git a/art b/art index 16cf2c2afe8c6c6159ad4871913c25d0eb8c6f4d..16f98d7ddb46a161f3f00f1be7a09da05bfbf2f5 100755 --- a/art +++ b/art @@ -6,8 +6,6 @@ # necessary a symbolic link can be made to this script from # /usr/local/bin/ or elsewhere. -# $Header: //tmp/pathsoft/artemis/art,v 1.26 2009-09-21 15:45:47 tjc Exp $ - # resolve links - $0 may be a link PRG=$0 progname=`basename $0` @@ -30,6 +28,9 @@ LIBDIR=/nfs/pathsoft/prod/javalibs CLASSPATH=$ARTEMIS_HOME:$ARTEMIS_HOME/lib/biojava.jar:$ARTEMIS_HOME/lib/jemAlign.jar:$ARTEMIS_HOME/lib/jakarta-regexp-1.2.jar:$ARTEMIS_HOME/lib/macos.jar:$ARTEMIS_HOME/lib/postgresql-8.4-701.jdbc3.jar:$CLASSPATH +# batik jars +CLASSPATH=$CLASSPATH:$ARTEMIS_HOME/lib/batik/batik-awt-util.jar:$ARTEMIS_HOME/lib/batik/batik-dom.jar:$ARTEMIS_HOME/lib/batik/batik-ext.jar:$ARTEMIS_HOME/lib/batik/batik-svggen.jar:$ARTEMIS_HOME/lib/batik/batik-util.jar:$ARTEMIS_HOME/lib/batik/batik-xml.jar + # j2ssh jars CLASSPATH=$CLASSPATH:$ARTEMIS_HOME/lib/j2ssh/commons-logging.jar:$ARTEMIS_HOME/lib/j2ssh/j2ssh-core.jar:$ARTEMIS_HOME/lib/j2ssh/ diff --git a/etc/log4j.properties b/etc/log4j.properties index d714f791dc537de7e2620242fe4f862020053fe2..1fcb68fee4c8bd8d66b8299cda3a373952c85c67 100644 --- a/etc/log4j.properties +++ b/etc/log4j.properties @@ -37,6 +37,7 @@ log4j.logger.uk.ac.sanger.artemis.components.variant=DEBUG, R log4j.logger.uk.ac.sanger.artemis.io.ReadAndWriteEntry=DEBUG, R log4j.logger.uk.ac.sanger.artemis.io.GFFStreamFeature=DEBUG, R log4j.logger.uk.ac.sanger.artemis.util.FTPSeekableStream=DEBUG, R +log4j.logger.uk.ac.sanger.artemis.plot.UserDataAlgorithm=DEBUG, R #log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG, stdout, R #log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG, stdout, R diff --git a/etc/versions b/etc/versions index 83ee417ea300c88422ad233affd7d903999c84d8..01440428135bbe52ccd3e3e46e320f373727852f 100644 --- a/etc/versions +++ b/etc/versions @@ -1,4 +1,4 @@ -Artemis Release 14.2.2 -ACT Release 11.2.2 -DNAPlotter Release 1.8 +Artemis Release 14.2.3 +ACT Release 11.2.3 +DNAPlotter Release 1.9 BamView 1.2.6 diff --git a/lib/batik/batik-awt-util.jar b/lib/batik/batik-awt-util.jar new file mode 100644 index 0000000000000000000000000000000000000000..f8d0d8d0aef4defbef79b77cf9ce3e960b24b39e Binary files /dev/null and b/lib/batik/batik-awt-util.jar differ diff --git a/lib/batik/batik-dom.jar b/lib/batik/batik-dom.jar new file mode 100644 index 0000000000000000000000000000000000000000..dab1ab3ba9b27f82062d5d2e000972808f325555 Binary files /dev/null and b/lib/batik/batik-dom.jar differ diff --git a/lib/batik/batik-ext.jar b/lib/batik/batik-ext.jar new file mode 100644 index 0000000000000000000000000000000000000000..deaad0cf03a362f3854774104010db6997effb6f Binary files /dev/null and b/lib/batik/batik-ext.jar differ diff --git a/lib/batik/batik-svggen.jar b/lib/batik/batik-svggen.jar new file mode 100644 index 0000000000000000000000000000000000000000..ede092150cd2f19af5d34ae902c3ef4819fbb283 Binary files /dev/null and b/lib/batik/batik-svggen.jar differ diff --git a/lib/batik/batik-util.jar b/lib/batik/batik-util.jar new file mode 100644 index 0000000000000000000000000000000000000000..6dd43a696abb84a074f99a45b22c650eb4d8b148 Binary files /dev/null and b/lib/batik/batik-util.jar differ diff --git a/lib/batik/batik-xml.jar b/lib/batik/batik-xml.jar new file mode 100644 index 0000000000000000000000000000000000000000..af2fbf6b06948405ff7c30e2c1cea3acb5aafb0b Binary files /dev/null and b/lib/batik/batik-xml.jar differ diff --git a/lib/batik/version b/lib/batik/version new file mode 100644 index 0000000000000000000000000000000000000000..b55ee096feeb1ba544a96cb51064ccd5cfd8e951 --- /dev/null +++ b/lib/batik/version @@ -0,0 +1,5 @@ +http://xmlgraphics.apache.org/batik/ + +SVN (batik-1.8pre) version (13-NOV-2012): + +http://people.apache.org/builds/xml-batik/batik-svn-12-11-13.zip diff --git a/uk/ac/sanger/artemis/circular/PrintDNAImage.java b/uk/ac/sanger/artemis/circular/PrintDNAImage.java index 603a9bb008ce448cbc55d8fc445148041829647d..74005d93af7f8451d600c8b5e7f572c43bd15106 100644 --- a/uk/ac/sanger/artemis/circular/PrintDNAImage.java +++ b/uk/ac/sanger/artemis/circular/PrintDNAImage.java @@ -35,7 +35,13 @@ import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JComboBox; @@ -53,6 +59,17 @@ import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.border.Border; +import org.apache.batik.dom.GenericDOMImplementation; +import org.apache.batik.svggen.SVGGeneratorContext; +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; + +import uk.ac.sanger.artemis.Options; +import uk.ac.sanger.artemis.components.PrintArtemis; +import uk.ac.sanger.artemis.components.StickyFileChooser; + @@ -225,18 +242,15 @@ public class PrintDNAImage extends ScrollPanel f.setVisible(true); } - /** - * * Provide some options for the image created - * */ private File showOptions() { - String cwd = System.getProperty("user.dir"); - JFileChooser fc = new JFileChooser(cwd); - File fselect = new File(cwd+System.getProperty("file.separator")+ - "dna.jpg"); + final StickyFileChooser fc = new StickyFileChooser(); + File fselect = new File(fc.getCurrentDirectory()+ + System.getProperty("file.separator")+ + "dnaplotter.png"); fc.setSelectedFile(fselect); // file name prefix @@ -250,10 +264,28 @@ public class PrintDNAImage extends ScrollPanel bdown.add(labFormat); Box bacross = Box.createHorizontalBox(); - JComboBox formatSelect = - new JComboBox(javax.imageio.ImageIO.getWriterFormatNames()); - formatSelect.setSelectedItem("jpg"); - + final JComboBox formatSelect = new JComboBox(PrintArtemis.getImageFormats()); + formatSelect.setSelectedItem("png"); + formatSelect.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + String selected; + if(fc.getSelectedFile() != null) + { + selected = fc.getSelectedFile().getAbsolutePath(); + String fmts[] = PrintArtemis.getImageFormats(); + for(int i=0; i<fmts.length; i++) + selected = selected.replaceAll("."+fmts[i]+"$", ""); + } + else + selected = "dnaplotter"; + + fc.setSelectedFile(new File(selected+"."+ + formatSelect.getSelectedItem())); + } + }); + Dimension d = formatSelect.getPreferredSize(); formatSelect.setMaximumSize(d); bacross.add(Box.createHorizontalGlue()); @@ -291,9 +323,6 @@ public class PrintDNAImage extends ScrollPanel System.out.println("Java 1.4+ is required"); } } - - - /** * Print to one jpeg or png file @@ -310,10 +339,15 @@ public class PrintDNAImage extends ScrollPanel Dimension d = dna.getSize(); double imageWidth = d.getWidth(); double imageHeight = d.getHeight(); - Paper paper = format.getPaper(); + if(type.equals("svg")) + { + createSVG(file, d); + return; + } + + Paper paper = format.getPaper(); paper.setSize(imageWidth,imageHeight); - paper.setImageableArea(0,0, imageWidth,imageHeight+imageHeight); format.setPaper(paper); @@ -329,6 +363,42 @@ public class PrintDNAImage extends ScrollPanel "This option requires Java 1.4 or higher."); } } + + private void createSVG(final File fout, Dimension d) + { + final DOMImplementation domImpl = + GenericDOMImplementation.getDOMImplementation(); + final Document doc = domImpl.createDocument( + "http://www.w3.org/2000/svg", "svg", null); + + SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc); + ctx.setComment("Generated by DNAPlotter with Batik SVG Generator"); + final SVGGraphics2D svgG = new SVGGraphics2D(ctx, true); + svgG.setFont(Options.getOptions().getFont()); + svgG.setSVGCanvasSize(d); + paintComponent(svgG); + + try + { + final Writer out = new OutputStreamWriter( + new FileOutputStream(fout), "UTF-8"); + svgG.stream(out, true); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + catch (SVGGraphics2DIOException e) + { + e.printStackTrace(); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + + return; + } } diff --git a/uk/ac/sanger/artemis/components/AlignmentViewer.java b/uk/ac/sanger/artemis/components/AlignmentViewer.java index e8d30b680561d660fcc42fe8bfac62ab23be649e..19666975697068eea1cd7a757948defd32395d60 100644 --- a/uk/ac/sanger/artemis/components/AlignmentViewer.java +++ b/uk/ac/sanger/artemis/components/AlignmentViewer.java @@ -40,6 +40,9 @@ import java.util.Vector; import java.util.Comparator; import java.util.Arrays; import javax.swing.*; + +import org.apache.batik.svggen.SVGGraphics2D; + import java.io.FileWriter; import java.io.IOException; @@ -1172,14 +1175,25 @@ public class AlignmentViewer extends CanvasPanel if(offscreen == null) offscreen = createImage(canvas_width, canvas_height); - Graphics og = offscreen.getGraphics(); - og.setClip(0,0,canvas_width,canvas_height); + final Graphics og; + if(!(g instanceof SVGGraphics2D)) + { + og = offscreen.getGraphics(); + og.setClip(0,0,canvas_width,canvas_height); + } + else + og = g; + og.setColor(Color.white); og.fillRect(0, 0, canvas_width, canvas_height); drawAlignments(og); drawLabels(og); - g.drawImage(offscreen, 0, 0, null); - og.dispose(); + + if(!(g instanceof SVGGraphics2D)) + { + g.drawImage(offscreen, 0, 0, null); + og.dispose(); + } } } diff --git a/uk/ac/sanger/artemis/components/BasePlot.java b/uk/ac/sanger/artemis/components/BasePlot.java index 9d595b25bd9fb27d6e2bfbc9066dfe5e759880bf..1d46bfb497a598e6c9c28144bd353318685422a3 100644 --- a/uk/ac/sanger/artemis/components/BasePlot.java +++ b/uk/ac/sanger/artemis/components/BasePlot.java @@ -722,6 +722,13 @@ public class BasePlot extends Plot **/ public int drawMultiValueGraph(Graphics g, LineAttributes[] lines) { + if( getAlgorithm() instanceof UserDataAlgorithm && + ((UserDataAlgorithm)getAlgorithm()).FORMAT == UserDataAlgorithm.TABIX_INDEXED_FORMAT) + { + ((UserDataAlgorithm) getAlgorithm()).readIndexValues( + entryGroup.getSequenceEntry(), getStart(), getEnd()); + } + if(recalculate_flag) recalculateValues(); @@ -735,11 +742,9 @@ public class BasePlot extends Plot final int window_size = getWindowSize(); // the number of values to plot at each x position - final int get_values_return_count = + final int nvalues = getBaseAlgorithm().getValueCount(); - final int number_of_values = value_array_array[0].length; - boolean isWiggle = false; boolean isBlast = false; if(getAlgorithm() instanceof UserDataAlgorithm) @@ -753,17 +758,16 @@ public class BasePlot extends Plot isBlast = true; } - if(number_of_values > 1 && !isWiggle) + if(value_array_array[0].length > 1 && !isWiggle) drawGlobalAverage(g, min_value, max_value); Stroke stroke = ((Graphics2D)g).getStroke(); - for(int value_index = 0; value_index < get_values_return_count; - ++value_index) + for(int i = 0; i < nvalues; ++i) { - if(value_index < lines.length) + if(i < lines.length) { - g.setColor(lines[value_index].getLineColour()); - ((Graphics2D)g).setStroke(lines[value_index].getStroke()); + g.setColor(lines[i].getLineColour()); + ((Graphics2D)g).setStroke(lines[i].getStroke()); } else g.setColor(Color.black); @@ -778,8 +782,8 @@ public class BasePlot extends Plot drawPoints(g, min_value, max_value, step_size, window_size, getWidthInBases(), offset, - value_array_array[value_index], value_index, - get_values_return_count, isWiggle, isBlast); + value_array_array[i], i, + nvalues, isWiggle, isBlast); } ((Graphics2D)g).setStroke(stroke); @@ -870,7 +874,7 @@ public class BasePlot extends Plot } } - return get_values_return_count; + return nvalues; } diff --git a/uk/ac/sanger/artemis/components/BioJavaEntrySource.java b/uk/ac/sanger/artemis/components/BioJavaEntrySource.java index 8f9a64ce7cbf0db3e1d8d4d89c45440407d63214..ca1c454014268b0febef7f0557ed724138c7d1c7 100644 --- a/uk/ac/sanger/artemis/components/BioJavaEntrySource.java +++ b/uk/ac/sanger/artemis/components/BioJavaEntrySource.java @@ -25,29 +25,12 @@ package uk.ac.sanger.artemis.components; -import java.net.*; import java.io.*; -import java.util.*; -import java.lang.RuntimeException; -import org.biojava.bio.program.das.*; -import org.biojava.bio.BioException; -import org.biojava.bio.seq.io.SequenceBuilderFactory; -import org.biojava.bio.seq.io.EmblProcessor; -import org.biojava.bio.seq.io.SmartSequenceBuilder; -import org.biojava.bio.seq.io.SymbolTokenization; -import org.biojava.bio.seq.io.StreamReader; -import org.biojava.bio.seq.io.SequenceFormat; import org.biojava.bio.seq.io.EmblLikeFormat; -import org.biojava.bio.seq.SequenceIterator; -import org.biojava.bio.symbol.Alphabet; -import org.biojava.bio.seq.DNATools; import uk.ac.sanger.artemis.util.*; import uk.ac.sanger.artemis.io.BioJavaEntry; -import uk.ac.sanger.artemis.io.EntryInformation; -import uk.ac.sanger.artemis.io.SimpleEntryInformation; - import uk.ac.sanger.artemis.*; import uk.ac.sanger.artemis.sequence.*; @@ -145,50 +128,6 @@ public class BioJavaEntrySource implements EntrySource public Entry getEntry (final boolean show_progress) throws OutOfRangeException, NoSequenceException, IOException { -// DASSequence dasSeq = null; - -// try { -// final URL dbURL = -// new URL("http://genome.ornl.gov/das/das.cgi/ecoli"); -// // new URL("http://genome.cse.ucsc.edu:80/cgi-bin/das/cb1"); -// // new URL("http://servlet.sanger.ac.uk:8080/das/ens1131cds/"); -// final DASSequenceDB dasDB = new DASSequenceDB (dbURL); - -// final Set ids = dasDB.ids(); - -// for (Iterator i = ids.iterator(); i.hasNext(); ) { -// System.out.println(i.next().toString()); -// } - -// // dasSeq = (DASSequence) dasDB.getSequence((String) ids.iterator().next()); - -// SequenceIterator si = dasDB.sequenceIterator(); - -// if (si.hasNext()) { -// dasSeq = (DASSequence) si.nextSequence(); - -// System.err.println("Got: " + dasSeq); - -// final BioJavaEntry bioJavaEntry = new BioJavaEntry (dasSeq); - -// return new Entry (bioJavaEntry); -// } else { -// System.err.println("No more sequences..."); -// } - - -// // final BioJavaEntry emblEntry = -// // new BioJavaEntry (document, new EmblLikeFormat ()); - -// // return new Entry (emblEntry); -// } catch (MalformedURLException mue) { -// mue.printStackTrace(); -// } catch (BioException be) { -// be.printStackTrace(); -// } - -// return null; - final String fileName = "/nfs/team81/kmr/pow/java2/AE002734.game"; final FileDocument document = new FileDocument (new File (fileName)); @@ -196,14 +135,6 @@ public class BioJavaEntrySource implements EntrySource new BioJavaEntry (document, new EmblLikeFormat ()); return new Entry (emblEntry); - -// final String fileName = "/nfs/team81/kmr/pow/java2/AB000095.embl"; -// final FileDocument document = new FileDocument (new File (fileName)); - -// final BioJavaEntry emblEntry = -// new BioJavaEntry (document, new EmblLikeFormat ()); - -// return new Entry (emblEntry); } /** diff --git a/uk/ac/sanger/artemis/components/FeatureDisplay.java b/uk/ac/sanger/artemis/components/FeatureDisplay.java index 8c279573a1c5a75526dad041e9ebdf18d7d97d00..bc6cb235cc3856f9fcd2c9b5ac22cd50078475dd 100644 --- a/uk/ac/sanger/artemis/components/FeatureDisplay.java +++ b/uk/ac/sanger/artemis/components/FeatureDisplay.java @@ -68,6 +68,8 @@ import javax.swing.UIManager; import javax.swing.ImageIcon; import javax.swing.JFrame; +import org.apache.batik.svggen.SVGGraphics2D; + /** * This component is used for displaying an Entry. * @@ -1890,8 +1892,19 @@ public class FeatureDisplay extends EntryGroupPanel // draw fwd bases if(getScaleFactor() == 0) - g.drawString(forward_visible_bases, offset * getFontWidth(), - yposition + getFontAscent() + 1); + { + if(!(g instanceof SVGGraphics2D)) + g.drawString(forward_visible_bases, offset * getFontWidth(), + yposition + getFontAscent() + 1); + else + { + // for svg graphics + for(int i=0;i<forward_visible_bases.length();i++) + g.drawString(String.valueOf(forward_visible_bases.charAt(i)), + (offset+i)*getFontWidth(), + yposition + getFontAscent() + 1); + } + } else { for(int base_index = 0; base_index < forward_sequence_length; @@ -1914,8 +1927,19 @@ public class FeatureDisplay extends EntryGroupPanel // draw bwd bases if(getScaleFactor() == 0) - g.drawString(reverse_visible_bases, offset * getFontWidth(), - yposition + getFontAscent() + 1); + { + if(!(g instanceof SVGGraphics2D)) + g.drawString(reverse_visible_bases, offset * getFontWidth(), + yposition + getFontAscent() + 1); + else + { + // for svg graphics + for(int i=0;i<reverse_visible_bases.length();i++) + g.drawString(String.valueOf(reverse_visible_bases.charAt(i)), + (offset+i)*getFontWidth(), + yposition + getFontAscent() + 1); + } + } else { for(int base_index = 0; base_index < reverse_sequence_length; @@ -2200,8 +2224,15 @@ public class FeatureDisplay extends EntryGroupPanel else draw_x_position = (int)((offset + frame_start + 1) * getScaleValue()); - g.drawString(codons, draw_x_position, + if(!(g instanceof SVGGraphics2D)) + g.drawString(codons, draw_x_position, draw_y_position + getFontAscent() + 1); + else + { + for(int i=0;i<codons.length();i++) + g.drawString(String.valueOf(codons.charAt(i)), draw_x_position+(i*getFontWidth() ), + draw_y_position + getFontAscent() + 1); + } } /** diff --git a/uk/ac/sanger/artemis/components/FeaturePlot.java b/uk/ac/sanger/artemis/components/FeaturePlot.java index 646f45c368a9789ed1a739fe710bb5d12dd82a7e..6d3425b093317139eac5c5016b5d38432f9e922c 100644 --- a/uk/ac/sanger/artemis/components/FeaturePlot.java +++ b/uk/ac/sanger/artemis/components/FeaturePlot.java @@ -25,24 +25,30 @@ package uk.ac.sanger.artemis.components; -import uk.ac.sanger.artemis.sequence.*; -import uk.ac.sanger.artemis.util.OutOfRangeException; -import uk.ac.sanger.artemis.util.ReadOnlyException; -import uk.ac.sanger.artemis.*; -import uk.ac.sanger.artemis.io.EntryInformationException; -import uk.ac.sanger.artemis.plot.*; -import java.awt.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + +import uk.ac.sanger.artemis.Feature; +import uk.ac.sanger.artemis.FeatureChangeEvent; +import uk.ac.sanger.artemis.FeatureChangeListener; +import uk.ac.sanger.artemis.Options; +import uk.ac.sanger.artemis.plot.FeatureAlgorithm; +import uk.ac.sanger.artemis.plot.LineAttributes; +import uk.ac.sanger.artemis.sequence.AminoAcidSequence; + /** * The components of this class display a plot of a FeatureAlgorithm for a * particular feature. - * * @author Kim Rutherford - * @version $Id: FeaturePlot.java,v 1.11 2009-07-20 15:11:17 tjc Exp $ **/ public class FeaturePlot extends Plot implements DisplayAdjustmentListener, FeatureChangeListener { + + private static final long serialVersionUID = 1L; + /** * Create a new FeatureDisplay object. * @param algorithm The object that will generate the values we plot in @@ -102,10 +108,9 @@ public class FeaturePlot extends Plot public void displayAdjustmentValueChanged (DisplayAdjustmentEvent event) { start_base = event.getStart (); end_base = event.getEnd (); - width_in_bases = event.getWidthInBases (); + //width_in_bases = event.getWidthInBases (); recalculate_flag = true; - repaint(); } @@ -138,13 +143,6 @@ public class FeaturePlot extends Plot return end_base; } - /** - * Return the width in bases of the display, from the last event. - **/ - private int getWidthInBases () { - return width_in_bases; - } - /** * This array is used by drawGraph (). It is reallocated when the scale * changes. @@ -386,12 +384,6 @@ public class FeaturePlot extends Plot **/ private int end_base; - /** - * The width in bases of the display, as obtained from the - * DisplayAdjustmentEvent. - **/ - private int width_in_bases; - protected void calculateFeatures(boolean fromPeak) { // TODO Auto-generated method stub diff --git a/uk/ac/sanger/artemis/components/MultiComparator.java b/uk/ac/sanger/artemis/components/MultiComparator.java index b9a64b897040179a9cc5739a90d08ab8ad26dd26..06a393fb88061a2b83333f2d734681cb74525b34 100644 --- a/uk/ac/sanger/artemis/components/MultiComparator.java +++ b/uk/ac/sanger/artemis/components/MultiComparator.java @@ -39,8 +39,20 @@ import uk.ac.sanger.artemis.io.EntryInformationException; import uk.ac.sanger.artemis.io.DocumentEntryFactory; import uk.ac.sanger.artemis.io.DocumentEntry; -import java.awt.*; -import java.awt.event.*; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.IOException; import java.io.File; import java.net.URL; @@ -58,9 +70,7 @@ import javax.swing.JPanel; * This JFrame component contains an arbitrary number of AlignmentViewer * components and FeatureDisplay components along with ComparatorGlue objects * to keep them synchronized. - * - * @author Kim Rutherford <kmr@sanger.ac.uk> - * @version $Id: MultiComparator.java,v 1.22 2008-09-03 10:58:33 tjc Exp $ + * @author Kim Rutherford **/ public class MultiComparator extends JFrame @@ -132,9 +142,6 @@ public class MultiComparator extends JFrame /** Used to show the progress of loading file. */ private InputStreamProgressListener progress_listener; - /** current group used for drag and drop */ - private int current_group = -1; - /** * Initialise entry_group_array and comparison_data_array and create all * the FeatureDisplay and AlignmentViewer components. @@ -162,16 +169,10 @@ public class MultiComparator extends JFrame this.progress_listener = progress_listener; this.entry_sources = Utilities.getEntrySources(this, null); - final StringBuffer title_buffer = new StringBuffer(); - - title_buffer.append("ACT: "); - + final StringBuffer title_buffer = new StringBuffer("ACT: "); for(int i = 0; i < entry_group_array.length - 1; ++i) - { - final String sequence_name = - entry_group_array[i].getDefaultEntry().getName(); - title_buffer.append(sequence_name).append(" vs "); - } + title_buffer.append( + entry_group_array[i].getDefaultEntry().getName()).append(" vs "); final EntryGroup last_entry_group = entry_group_array[entry_group_array.length - 1]; @@ -206,7 +207,6 @@ public class MultiComparator extends JFrame getGotoEventSourceArray()[i]); final int scroll_bar_position; - if(i == getEntryGroupArray().length - 1 && getEntryGroupArray().length == 2) { @@ -255,17 +255,11 @@ public class MultiComparator extends JFrame getAlignmentViewerArray()[i]); } - final Font default_font = getDefaultFont(); - - setFont(default_font); - + setFont(getDefaultFont()); makeMenus(); - - GridBagLayout gridbag = new GridBagLayout(); - getContentPane().setLayout(gridbag); + getContentPane().setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); - c.gridwidth = GridBagConstraints.REMAINDER; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.NORTH; @@ -598,7 +592,7 @@ public class MultiComparator extends JFrame **/ private void makeMenus() { - final Font default_font = getDefaultFont(); + //final Font default_font = getDefaultFont(); final JMenuBar menu_bar = new JMenuBar(); setJMenuBar(menu_bar); diff --git a/uk/ac/sanger/artemis/components/Plot.java b/uk/ac/sanger/artemis/components/Plot.java index 9fcc723afc22fc2d14351ac2cb072652b0873014..5a24f1de1757616800c3ed93e3537d071b716282 100644 --- a/uk/ac/sanger/artemis/components/Plot.java +++ b/uk/ac/sanger/artemis/components/Plot.java @@ -29,8 +29,15 @@ import uk.ac.sanger.artemis.Options; import uk.ac.sanger.artemis.circular.TextFieldFloat; import uk.ac.sanger.artemis.plot.*; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Scrollbar; import java.awt.event.*; +import java.util.Vector; import javax.swing.JMenu; import javax.swing.JPanel; @@ -44,15 +51,16 @@ import javax.swing.JMenuItem; import javax.swing.JScrollBar; import javax.swing.JPopupMenu; +import org.apache.batik.svggen.SVGGraphics2D; + /** * This class implements a simple plot component. - * * @author Kim Rutherford - * @version $Id: Plot.java,v 1.26 2009-08-18 09:01:44 tjc Exp $ **/ public abstract class Plot extends JPanel { + private static final long serialVersionUID = 1L; /** scroll bar for changing the window size. */ private JScrollBar window_changer = null; @@ -73,12 +81,16 @@ public abstract class Plot extends JPanel * drawScaleLine() is called. **/ private boolean draw_scale; + + private final int SCROLL_NOB_SIZE = 10; /** * Set to true if drawMultiValueGraph() should call recalculateValues(). * It is reset to false by recalculateValues(). **/ protected boolean recalculate_flag = true; + + private boolean showAverage = true; /** * The x position of the last click or -1 if the user hasn't clicked @@ -95,7 +107,7 @@ public abstract class Plot extends JPanel /** * A vector of those objects listening for PlotMouse events. **/ - final private java.util.Vector listener_list = new java.util.Vector(); + final private Vector<PlotMouseListener> listener_list = new Vector<PlotMouseListener>(); /** * Recalculate the values all the state that is used for drawing the plot @@ -116,10 +128,12 @@ public abstract class Plot extends JPanel /** number of graph lines to be drawn */ private int numPlots; - /** colour array for graph drawing */ protected LineAttributes lines[]; private int lastPaintHeight = getHeight(); + + /** the minimum distance in pixels between the labels */ + private final static int MINIMUM_LABEL_SPACING = 50; /** * Create a new plot component. @@ -130,34 +144,27 @@ public abstract class Plot extends JPanel **/ public Plot(Algorithm algorithm, boolean draw_scale) { - super(); + super(new BorderLayout()); this.algorithm = algorithm; this.draw_scale = draw_scale; - final Font font = Options.getOptions().getFont(); - - setFont(font); - FontMetrics fm = getFontMetrics(font); + setFont(Options.getOptions().getFont()); + FontMetrics fm = getFontMetrics(getFont()); font_height = fm.getHeight(); - setLayout(new BorderLayout()); - final int MAX_WINDOW; - if(getAlgorithm().getDefaultMaxWindowSize() != null) MAX_WINDOW = getAlgorithm().getDefaultMaxWindowSize().intValue(); else MAX_WINDOW = 500; final int MIN_WINDOW; - if(getAlgorithm().getDefaultMinWindowSize() != null) MIN_WINDOW = getAlgorithm().getDefaultMinWindowSize().intValue(); else MIN_WINDOW = 5; final int START_WINDOW; - if(getAlgorithm().getDefaultWindowSize() == null) START_WINDOW = 10; else @@ -189,17 +196,11 @@ public abstract class Plot extends JPanel } }); - -// setBackground(Color.white); add(window_changer, "East"); - addMouseListener(mouse_listener); addMouseMotionListener(mouse_motion_listener); - } - final int SCROLL_NOB_SIZE = 10; - /** * Return the algorithm that was passed to the constructor. **/ @@ -220,8 +221,7 @@ public abstract class Plot extends JPanel final MouseListener mouse_listener = new MouseAdapter() { /** - * Listen for mouse press events so that we can do a popup menu and a - * crosshair. + * Listen for mouse press popup menu and crosshair events. **/ public void mousePressed(MouseEvent event) { @@ -296,10 +296,9 @@ public abstract class Plot extends JPanel }); popup.add(setScale); - final JCheckBoxMenuItem scaling_toggle = - new JCheckBoxMenuItem("Scaling"); - scaling_toggle.setState(getAlgorithm().scalingFlag()); + final JCheckBoxMenuItem scaling_toggle = + new JCheckBoxMenuItem("Scaling",getAlgorithm().scalingFlag()); scaling_toggle.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent _) @@ -309,10 +308,19 @@ public abstract class Plot extends JPanel repaint(); } }); - popup.add(scaling_toggle); - - + + final JCheckBoxMenuItem showAverageLn = new JCheckBoxMenuItem("Show average", showAverage); + showAverageLn.addItemListener(new ItemListener() + { + public void itemStateChanged(ItemEvent _) + { + showAverage = showAverageLn.isSelected(); + repaint(); + } + }); + popup.add(showAverageLn); + if(Plot.this instanceof BasePlot) { final JMenuItem showMinMaxValues = @@ -351,13 +359,11 @@ public abstract class Plot extends JPanel } }); } - - + popup.addSeparator(); final JMenu max_window_size = new JMenu("Maximum Window Size"); - popup.add(max_window_size); final int[] window_sizes = @@ -366,9 +372,7 @@ public abstract class Plot extends JPanel 200000, 500000, 1000000 }; - JMenuItem window_size_item; - for(int i = 0 ; i < window_sizes.length ; ++i) { final int size = i; @@ -440,7 +444,6 @@ public abstract class Plot extends JPanel } final JSplitPane splitPane = getJSplitPane(); - if(splitPane == null) { popup.addSeparator(); @@ -458,8 +461,7 @@ public abstract class Plot extends JPanel { public void actionPerformed(ActionEvent e) { - Dimension d = getSize(); - rescale((int) (d.height * 0.9f)); + rescale((int) (getSize().height * 0.9f)); } }); @@ -467,8 +469,7 @@ public abstract class Plot extends JPanel { public void actionPerformed(ActionEvent e) { - Dimension d = getSize(); - rescale((int) (d.height * 1.1f)); + rescale((int) (getSize().height * 1.1f)); } }); @@ -486,12 +487,10 @@ public abstract class Plot extends JPanel if(select == 1) return; - try { - final int value = Integer - .parseInt(newGraphHgt.getText().trim()); - rescale(value); + rescale(Integer.parseInt( + newGraphHgt.getText().trim())); } catch(NumberFormatException nfe) { @@ -611,7 +610,7 @@ public abstract class Plot extends JPanel PlotMouseListener listener; for(int i = 0; i < listener_list.size(); ++i) { - listener = (PlotMouseListener)listener_list.elementAt(i); + listener = listener_list.elementAt(i); listener.mouseClick(getPointPosition(cross_hair_position)); } } @@ -625,7 +624,7 @@ public abstract class Plot extends JPanel PlotMouseListener listener; for(int i = 0; i < listener_list.size(); ++i) { - listener = (PlotMouseListener)listener_list.elementAt(i); + listener = listener_list.elementAt(i); listener.mouseDrag(getPointPosition(drag_start_position), getPointPosition(cross_hair_position)); } @@ -640,7 +639,7 @@ public abstract class Plot extends JPanel PlotMouseListener listener; for(int i = 0; i < listener_list.size(); ++i) { - listener = (PlotMouseListener)listener_list.elementAt(i); + listener = listener_list.elementAt(i); listener.mouseDoubleClick(getPointPosition(cross_hair_position)); } } @@ -685,11 +684,17 @@ public abstract class Plot extends JPanel if(offscreen == null || lastPaintHeight != height) offscreen = createImage(width, height); - Graphics og = offscreen.getGraphics(); - og.setClip(0, 0, width, height); - og.setColor(Color.WHITE); - og.fillRect(0, 0, width, height); - + final Graphics og; + if(g instanceof SVGGraphics2D) + og = g; + else + { + og = offscreen.getGraphics(); + og.setClip(0, 0, width, height); + og.setColor(Color.WHITE); + og.fillRect(0, 0, width, height); + } + // Redraw the graph on the canvas using the algorithm from the // constructor. @@ -706,8 +711,12 @@ public abstract class Plot extends JPanel numPlots = drawMultiValueGraph(og,lines); drawLabels(og,numPlots); - g.drawImage(offscreen, 0, 0, null); - og.dispose(); + + if( !(g instanceof SVGGraphics2D) ) + { + g.drawImage(offscreen, 0, 0, null); + og.dispose(); + } lastPaintHeight = height; } @@ -737,31 +746,19 @@ public abstract class Plot extends JPanel drag_start_position = -1; } - // the minimum distance in pixels between the labels - private final static int MINIMUM_LABEL_SPACING = 50; - /** - * Draw the scale line at the bottom of the graph. + * Draw the scale line at the bottom of the graph (used by FeaturePlot). * @param start The base on the left * @param end The base on the right **/ protected void drawScaleLine(final Graphics g, final int start, final int end) { - final int width = getWidth() - window_changer.getWidth(); - final int height = getHeight(); - - final int scale_number_y_pos = height - 1; - + final int hgt = getHeight(); + final int scale_number_y_pos = hgt - 1; final float bases_per_pixel = 1.0F; - // set the spacing so that the labels are at multiples of 10 - final int base_label_spacing = MINIMUM_LABEL_SPACING; - - final int label_spacing = (int)(base_label_spacing / bases_per_pixel); - - final int possible_index_of_first_label = start / base_label_spacing; - + final int possible_index_of_first_label = start / MINIMUM_LABEL_SPACING; final int index_of_first_label; if(possible_index_of_first_label == 0) @@ -769,22 +766,18 @@ public abstract class Plot extends JPanel else index_of_first_label = possible_index_of_first_label; - final int index_of_last_label = end / base_label_spacing; - - String label_string; + final int index_of_last_label = end / MINIMUM_LABEL_SPACING; for(int i = index_of_first_label; i <= index_of_last_label; i++) { - label_string = String.valueOf((int)(i * base_label_spacing)); - final int scale_number_x_pos = - (int)((i * base_label_spacing - start) / bases_per_pixel); + (int)((i * MINIMUM_LABEL_SPACING - start) / bases_per_pixel); - g.drawString(label_string, + g.drawString(String.valueOf((int)(i * MINIMUM_LABEL_SPACING)), scale_number_x_pos + 2, scale_number_y_pos); - g.drawLine(scale_number_x_pos, height - getScaleHeight() / 2, - scale_number_x_pos, height - getScaleHeight()); + g.drawLine(scale_number_x_pos, hgt - getScaleHeight() / 2, + scale_number_x_pos, hgt - getScaleHeight()); } } @@ -977,7 +970,8 @@ public abstract class Plot extends JPanel final float max_value) { // if a heatmap do not show the average - if(lines != null && lines[0].getPlotType().equals(LineAttributes.PLOT_TYPES[2])) + if(!showAverage || ( + lines != null && lines[0].getPlotType().equals(LineAttributes.PLOT_TYPES[2]))) return; final Float average = getAlgorithm().getAverage(); @@ -1129,22 +1123,6 @@ public abstract class Plot extends JPanel { return font_height; } - - /** - * Used to get the X coordinate for the tooltip text. - * @param total_unit_count The maximum number of residues/bases we can - * show. This is used to draw the scale line and to calculate the - * distance (in pixels) between plot points. - * @param start_position The distance from the edge of the canvas (measured - * in residues/bases) to start drawing the plot. - * @param xpos The mouse position on the canvas. - **/ - protected int getXCoordinate(final int total_unit_count, - final int start_position, - final int xpos) - { - return (xpos * total_unit_count)/getSize().width + start_position; - } /** * Used to get the Y coordinate for the tooltip text. @@ -1162,7 +1140,6 @@ public abstract class Plot extends JPanel final float plot_values[], int base_pos) { int ypos = (int)((base_pos - start_position - (window_size/2))/step_size); - if(ypos < 0) ypos = 0; else if(ypos > plot_values.length-1) @@ -1170,5 +1147,4 @@ public abstract class Plot extends JPanel return plot_values[ypos]; } - } diff --git a/uk/ac/sanger/artemis/components/PrintACT.java b/uk/ac/sanger/artemis/components/PrintACT.java index 0c3403f5ce10d36bea209722515b04262073ad47..5928f777c2463d516a4dfcba0ff7d2e0b6093c9d 100644 --- a/uk/ac/sanger/artemis/components/PrintACT.java +++ b/uk/ac/sanger/artemis/components/PrintACT.java @@ -32,7 +32,12 @@ import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; import javax.swing.Box; import javax.swing.JCheckBox; @@ -50,12 +55,18 @@ import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.KeyStroke; +import org.apache.batik.dom.GenericDOMImplementation; +import org.apache.batik.svggen.SVGGeneratorContext; +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; + +import uk.ac.sanger.artemis.Options; import uk.ac.sanger.artemis.editor.ScrollPanel; /** -* * Use to print images from ACT -* */ public class PrintACT extends ScrollPanel implements Printable { @@ -274,18 +285,15 @@ public class PrintACT extends ScrollPanel implements Printable } /** - * * Print to a jpeg or png file - * */ public void print() { // file chooser - String cwd = System.getProperty("user.dir"); - JFileChooser fc = new JFileChooser(cwd); - File fselect = new File(cwd+ - System.getProperty("file.separator")+ - "act.png"); + final StickyFileChooser fc = new StickyFileChooser(); + File fselect = new File(fc.getCurrentDirectory()+ + System.getProperty("file.separator")+ + "act.png"); fc.setSelectedFile(fselect); // file name prefix @@ -296,8 +304,27 @@ public class PrintACT extends ScrollPanel implements Printable YBox.add(labFormat); Box bacross = Box.createHorizontalBox(); - JComboBox formatSelect = - new JComboBox(javax.imageio.ImageIO.getWriterFormatNames()); + final JComboBox formatSelect = new JComboBox(PrintArtemis.getImageFormats()); + formatSelect.setSelectedItem("png"); + formatSelect.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + String selected; + if(fc.getSelectedFile() != null) + { + selected = fc.getSelectedFile().getAbsolutePath(); + String fmts[] = PrintArtemis.getImageFormats(); + for(int i=0; i<fmts.length; i++) + selected = selected.replaceAll("."+fmts[i]+"$", ""); + } + else + selected = "act"; + + fc.setSelectedFile(new File(selected+"."+ + formatSelect.getSelectedItem())); + } + }); formatSelect.setSelectedItem("png"); Dimension d = formatSelect.getPreferredSize(); @@ -319,6 +346,12 @@ public class PrintACT extends ScrollPanel implements Printable // remove file extension String fsave = fc.getSelectedFile().getAbsolutePath().toLowerCase(); + if(fsave.endsWith(".svg")) + { + createSVG(fc.getSelectedFile()); + return; + } + if(fsave.endsWith(".png") || fsave.endsWith(".jpg") || fsave.endsWith(".jpeg") ) @@ -345,12 +378,46 @@ public class PrintACT extends ScrollPanel implements Printable } } + private void createSVG(final File fout) + { + final DOMImplementation domImpl = + GenericDOMImplementation.getDOMImplementation(); + final Document doc = domImpl.createDocument( + "http://www.w3.org/2000/svg", "svg", null); + + SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc); + ctx.setComment("Generated by ACT with Batik SVG Generator"); + final SVGGraphics2D svgG = new SVGGraphics2D(ctx, true); + svgG.setFont(Options.getOptions().getFont()); + svgG.setSVGCanvasSize( getImageSize() ); + paintComponent(svgG); + + try + { + final Writer out = new OutputStreamWriter( + new FileOutputStream(fout), "UTF-8"); + svgG.stream(out, true); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + catch (SVGGraphics2DIOException e) + { + e.printStackTrace(); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + + return; + } + /** - * * Returns a generated image * @param pageIndex page number * @return image - * */ private RenderedImage createImage() { diff --git a/uk/ac/sanger/artemis/components/PrintArtemis.java b/uk/ac/sanger/artemis/components/PrintArtemis.java index f72fef4d423ef4f2a13579c2d7b5b8707ddcdf41..5c37fd88450813938b079ccc60009130b29de40a 100644 --- a/uk/ac/sanger/artemis/components/PrintArtemis.java +++ b/uk/ac/sanger/artemis/components/PrintArtemis.java @@ -29,9 +29,26 @@ import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.awt.event.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; +import java.util.Arrays; +import java.util.HashSet; + import javax.swing.*; -import java.io.*; +import org.apache.batik.dom.GenericDOMImplementation; +import org.apache.batik.svggen.SVGGeneratorContext; +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; + +import uk.ac.sanger.artemis.Options; import uk.ac.sanger.artemis.editor.ScrollPanel; /** @@ -66,15 +83,45 @@ public class PrintArtemis extends ScrollPanel implements Printable } /** - * * Override paintComponent to draw entry - * */ - public void paintComponent(Graphics g) + public void paintComponent(Graphics g2d) { // let UI delegate paint first (incl. background filling) - super.paintComponent(g); - Graphics2D g2d = (Graphics2D)g.create(); + super.paintComponent(g2d); + + // feature list + if(featListDisplay.isSelected()) + { + FeatureList flist = entry.getFeatureList(); + Point ploc = flist.getViewport().getViewPosition(); + try + { + int translateX = 0; + if(selectDisplay.isSelected()) + translateX += entry.getSelectionInfoDisplay().getHeight(); + if(groupsDisplay.isSelected()) + translateX += entry.getEntryGroupDisplay().getHeight(); + if(plotsDisplay.isSelected()) + translateX += entry.getBasePlotGroup().getHeight(); + if(jamDisplay.isSelected() && entry.getBamPanel() != null && entry.getBamPanel().isVisible()) + translateX += entry.getBamPanel().getHeight()-1; + if(vcfDisplay.isSelected() && entry.getVcfView() != null && entry.getVcfView().isVisible()) + translateX += entry.getVcfPanel().getHeight(); + if(onelineDisplay.isSelected()) + translateX += entry.getOneLinePerEntryDisplay().getHeight(); + if(featDisplay.isSelected()) + translateX += entry.getFeatureDisplay().getHeight(); + if(baseDisplay.isSelected()) + translateX += entry.getBaseDisplay().getHeight(); + + translateX-=2+ploc.y; + g2d.translate(0,translateX); + flist.paintComponent(g2d); + g2d.translate(0,-translateX); + } + catch(IllegalArgumentException e){} // thrown if the list is not visible + } // selection info if(selectDisplay.isSelected()) @@ -128,24 +175,9 @@ public class PrintArtemis extends ScrollPanel implements Printable entry.getBaseDisplay().paintComponent(g2d); g2d.translate(0,entry.getBaseDisplay().getHeight()); } - - // feature list - if(featListDisplay.isSelected()) - { - FeatureList flist = entry.getFeatureList(); - Point ploc = flist.getViewport().getViewPosition(); - try - { - BufferedImage offScreen = new BufferedImage(flist.getViewport().getWidth(), - flist.getViewport().getHeight(), BufferedImage.TYPE_INT_RGB); - Graphics og = offScreen.getGraphics(); - og.translate(0,-ploc.y); - flist.paintComponent(og); - g2d.drawImage(offScreen, 0, 0, null); - } - catch(IllegalArgumentException e){} // thrown if the list is not visible - } } + + /** @@ -153,7 +185,7 @@ public class PrintArtemis extends ScrollPanel implements Printable * Set the size of the image * */ - private void setImageSize() + private Dimension getImageSize() { height = 0; width = entry.getFeatureDisplay().getDisplayWidth(); @@ -185,9 +217,14 @@ public class PrintArtemis extends ScrollPanel implements Printable if(featListDisplay.isSelected()) height += entry.getFeatureList().getViewport().getExtentSize().height; - setPreferredSize(new Dimension(width,height)); + return new Dimension(width,height); } + private void setImageSize() + { + setPreferredSize(getImageSize()); + } + /** * * Display a print preview page @@ -391,6 +428,21 @@ public class PrintArtemis extends ScrollPanel implements Printable f.setVisible(true); } + public static String[] getImageFormats() + { + final String fmts[] = javax.imageio.ImageIO.getWriterFormatNames(); + final HashSet<String> list = new HashSet<String>(); + for(int i=0; i<fmts.length; i++) + list.add(fmts[i].toLowerCase()); + + final String tmpFmts[] = new String[list.size()+1]; + System.arraycopy(list.toArray(), 0, tmpFmts, 0, list.size()); + tmpFmts[tmpFmts.length-1] = "svg"; + Arrays.sort(tmpFmts); + + return tmpFmts; + } + /** * * Print to a jpeg or png file @@ -399,7 +451,7 @@ public class PrintArtemis extends ScrollPanel implements Printable public void print() { // file chooser - StickyFileChooser fc = new StickyFileChooser(); + final StickyFileChooser fc = new StickyFileChooser(); File fselect = new File(fc.getCurrentDirectory()+ System.getProperty("file.separator")+ "artemis.png"); @@ -413,9 +465,27 @@ public class PrintArtemis extends ScrollPanel implements Printable YBox.add(labFormat); Box bacross = Box.createHorizontalBox(); - JComboBox formatSelect = - new JComboBox(javax.imageio.ImageIO.getWriterFormatNames()); + final JComboBox formatSelect = new JComboBox(getImageFormats()); formatSelect.setSelectedItem("png"); + formatSelect.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + String selected; + if(fc.getSelectedFile() != null) + { + selected = fc.getSelectedFile().getAbsolutePath(); + String fmts[] = getImageFormats(); + for(int i=0; i<fmts.length; i++) + selected = selected.replaceAll("."+fmts[i]+"$", ""); + } + else + selected = "artemis"; + + fc.setSelectedFile(new File(selected+"."+ + formatSelect.getSelectedItem())); + } + }); Dimension d = formatSelect.getPreferredSize(); formatSelect.setMaximumSize(d); @@ -488,6 +558,13 @@ public class PrintArtemis extends ScrollPanel implements Printable // remove file extension String fsave = fc.getSelectedFile().getAbsolutePath().toLowerCase(); + + if(fsave.endsWith(".svg")) + { + createSVG(fc.getSelectedFile()); + return; + } + if(fsave.endsWith(".png") || fsave.endsWith(".jpg") || fsave.endsWith(".jpeg") ) @@ -514,6 +591,45 @@ public class PrintArtemis extends ScrollPanel implements Printable } } + private void createSVG(final File fout) + { + final DOMImplementation domImpl = + GenericDOMImplementation.getDOMImplementation(); + final Document doc = domImpl.createDocument( + "http://www.w3.org/2000/svg", "svg", null); + + SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc); + ctx.setComment("Generated by Artemis with Batik SVG Generator"); + final SVGGraphics2D svgG = new SVGGraphics2D(ctx, true); + svgG.setFont(Options.getOptions().getFont()); + final FontMetrics fm = svgG.getFontMetrics(); + final Dimension d = getImageSize(); + svgG.setSVGCanvasSize( new Dimension( + d.width+fm.stringWidth(" "), d.height+fm.getHeight()) ); + paintComponent(svgG); + + try + { + final Writer out = new OutputStreamWriter( + new FileOutputStream(fout), "UTF-8"); + svgG.stream(out, true); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + catch (SVGGraphics2DIOException e) + { + e.printStackTrace(); + } + catch (FileNotFoundException e) + { + e.printStackTrace(); + } + + return; + } + protected void doPrintActions() { final PrinterJob pj=PrinterJob.getPrinterJob(); @@ -575,7 +691,7 @@ public class PrintArtemis extends ScrollPanel implements Printable public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException { setImageSize(); - Graphics2D g2 = (Graphics2D) g; + Graphics2D g2 = (Graphics2D)g.create(); // RepaintManager.currentManager(this).setDoubleBufferingEnabled(false); Dimension d = this.getSize(); //get size of document diff --git a/uk/ac/sanger/artemis/components/variant/TabixReader.java b/uk/ac/sanger/artemis/components/variant/TabixReader.java index a42cdf5431db2708dfed279fcdd60e5883cfd429..102d718982e3eb8575a1deac9b15040eaf33d2f7 100644 --- a/uk/ac/sanger/artemis/components/variant/TabixReader.java +++ b/uk/ac/sanger/artemis/components/variant/TabixReader.java @@ -413,8 +413,28 @@ public class TabixReader extends AbstractVCFReader return mSeq; } - protected String getFileName() + public int getStartColumn() + { + return mBc; + } + + public int getEndColumn() + { + return mEc; + } + + public int getSeqColumn() + { + return mSc; + } + + public String getFileName() { return mFn; } + + public char getCommentChar() + { + return (char)mMeta; + } } diff --git a/uk/ac/sanger/artemis/plot/Algorithm.java b/uk/ac/sanger/artemis/plot/Algorithm.java index 434d20230f527492e21cc714beb43b37426415e0..1ffeb9e5ce2170ccc6d16978a6defdd4b3245f76 100644 --- a/uk/ac/sanger/artemis/plot/Algorithm.java +++ b/uk/ac/sanger/artemis/plot/Algorithm.java @@ -143,6 +143,14 @@ public abstract class Algorithm { { return algorithm_name; } + + /** + * Return the name of this algorithm. + **/ + public void setAlgorithmName (String algorithm_name) + { + this.algorithm_name = algorithm_name; + } /** * Return the short (one word) name of this algorithm, as passed tp the diff --git a/uk/ac/sanger/artemis/plot/UserDataAlgorithm.java b/uk/ac/sanger/artemis/plot/UserDataAlgorithm.java index 84c6561ab82e46ec20e7cbb4b0dbe5d3ddc011fd..0a69f718add3b0acc61c65572245071d91b9a580 100644 --- a/uk/ac/sanger/artemis/plot/UserDataAlgorithm.java +++ b/uk/ac/sanger/artemis/plot/UserDataAlgorithm.java @@ -1,10 +1,7 @@ /* UserDataAlgorithm.java - * - * created: Wed May 10 2000 - * * This file is part of Artemis * - * Copyright (C) 2000 Genome Research Limited + * Copyright (C) 2000-2012 Genome Research Limited * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,52 +16,57 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/plot/UserDataAlgorithm.java,v 1.14 2009-07-22 12:51:54 tjc Exp $ */ package uk.ac.sanger.artemis.plot; -import uk.ac.sanger.artemis.sequence.*; - -import uk.ac.sanger.artemis.util.*; +import uk.ac.sanger.artemis.Entry; +import uk.ac.sanger.artemis.sequence.Bases; +import uk.ac.sanger.artemis.sequence.Strand; +import uk.ac.sanger.artemis.util.Document; +import uk.ac.sanger.artemis.util.FileDocument; +import uk.ac.sanger.artemis.util.LinePushBackReader; +import uk.ac.sanger.artemis.util.StringVector; +import uk.ac.sanger.artemis.components.variant.TabixReader; +import uk.ac.sanger.artemis.io.IndexFastaStream; import uk.ac.sanger.artemis.io.ReadFormatException; - import java.awt.Color; import java.awt.GridLayout; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.Arrays; import java.util.HashMap; import java.util.regex.Pattern; - import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JOptionPane; import javax.swing.JPanel; +import net.sf.samtools.util.BlockCompressedInputStream; + /** * Objects of this class have one useful method - getValues (), which takes a * range of bases and returns a single floating point number. The number is * calculated by averaging the values from a data file. The Strand to use is * set in the constructor. - * - * @author Kim Rutherford <kmr@sanger.ac.uk> - * @version $Id: UserDataAlgorithm.java,v 1.14 2009-07-22 12:51:54 tjc Exp $ + * @author Kim Rutherford **/ public class UserDataAlgorithm extends BaseAlgorithm { /** A base per line file format */ public static int BASE_PER_LINE_FORMAT = 1; - /** Base position is specified in the first column file format */ public static int BASE_SPECIFIED_FORMAT = 2; - /** Wiggle format */ public static int WIGGLE_VARIABLE_STEP_FORMAT = 3; - public static int WIGGLE_FIXED_STEP_FORMAT = 4; - - public static int BLAST_FORMAT = 5; - public static int MSPCRUNCH_BLAST_FORMAT = 6; + public static int WIGGLE_FIXED_STEP_FORMAT = 4; + public static int BLAST_FORMAT = 5; + public static int MSPCRUNCH_BLAST_FORMAT = 6; + public static int TABIX_INDEXED_FORMAT = 7; /** The data read by the constructor - for BASE_PER_LINE_FORMAT */ private float data[][] = null; @@ -76,7 +78,6 @@ public class UserDataAlgorithm extends BaseAlgorithm /** The maximum value in the data array. */ private float data_max = Float.MIN_VALUE; - /** The minimum value in the data array. */ private float data_min = Float.MAX_VALUE; @@ -95,8 +96,10 @@ public class UserDataAlgorithm extends BaseAlgorithm public int FORMAT = BASE_PER_LINE_FORMAT; private LineAttributes lines[]; - - public Wiggle wiggle[]; + private Wiggle wiggle[]; + private TabixIdxGraph idxReader; + private static org.apache.log4j.Logger logger4j = + org.apache.log4j.Logger.getLogger(UserDataAlgorithm.class); /** * Create a new UserDataAlgorithm object. This reads a file @@ -109,51 +112,63 @@ public class UserDataAlgorithm extends BaseAlgorithm * @param logTransform true if the log transformation is to be * shown. **/ - public UserDataAlgorithm (final Strand strand, final Document document, + public UserDataAlgorithm (final Strand strand, final Document doc, final boolean logTransform) throws IOException { - super (strand, "User algorithm from " + document.getName (), "user"); - + super (strand, + (logTransform ? "User log plot " + doc.getName () : + "User plot " + doc.getName ()), "user"); this.logTransform = logTransform; - final Reader document_reader = document.getReader (); - LinePushBackReader pushback_reader = new LinePushBackReader (document_reader); - String first_line = pushback_reader.readLine (); + if(isIndexed(doc) && doc.getInputStream() instanceof BlockCompressedInputStream) + { + setAlgorithmName( + (logTransform ? "Indexed log plot " + doc.getName () : + "Indexed plot " + doc.getName ())); + FORMAT = TABIX_INDEXED_FORMAT; + idxReader = new TabixIdxGraph( + ((FileDocument) doc).getFile().getAbsolutePath()); + number_of_values = idxReader.getNumberOfValues(); + return; + } + + final Reader doc_reader = doc.getReader (); + final LinePushBackReader pushback_reader = new LinePushBackReader (doc_reader); + String firstLn = pushback_reader.readLine (); - Pattern dataPattern = Pattern.compile("^\\s*([\\d\\.-]+\\s*)+$"); - Pattern blastPattern = Pattern.compile( + final Pattern dataPattern = Pattern.compile("^\\s*([\\d\\.-]+\\s*)+$"); + final Pattern blastPattern = Pattern.compile( "^(\\S+\\t+){2}[\\d\\.]+\\t+(\\d+\\t+){7}\\S+\\t+(\\s*\\d+)$"); - Pattern mspCrunchPattern = Pattern.compile( + final Pattern mspCrunchPattern = Pattern.compile( "^\\d+\\s[\\d\\.]+(\\s\\d+){2}\\s\\D\\S+(\\s\\d+){2}\\s\\D\\S+.*"); - if(dataPattern.matcher(first_line).matches()) + if(dataPattern.matcher(firstLn).matches()) FORMAT = BASE_PER_LINE_FORMAT; - else if(blastPattern.matcher(first_line).matches()) + else if(blastPattern.matcher(firstLn).matches()) FORMAT = BLAST_FORMAT; - else if(mspCrunchPattern.matcher(first_line).matches()) + else if(mspCrunchPattern.matcher(firstLn).matches()) FORMAT = MSPCRUNCH_BLAST_FORMAT; else { - StringBuffer header = new StringBuffer(first_line+"\n"); - - while(!dataPattern.matcher(first_line).matches()) + StringBuffer header = new StringBuffer(firstLn+"\n"); + while(!dataPattern.matcher(firstLn).matches()) { - first_line = pushback_reader.readLine ().trim(); - header.append(first_line+"\n"); + firstLn = pushback_reader.readLine ().trim(); + header.append(firstLn+"\n"); } FORMAT = parseHeader(header); } final Pattern patt = Pattern.compile("\\s+"); - String tokens[] = patt.split(first_line); + String tokens[] = patt.split(firstLn); if (tokens.length < 1) throw new ReadFormatException ("unknown file type"); this.number_of_values = tokens.length; - pushback_reader.pushBack (first_line); + pushback_reader.pushBack (firstLn); if(FORMAT == BASE_PER_LINE_FORMAT) data = new float [strand.getSequenceLength ()][tokens.length]; @@ -167,7 +182,20 @@ public class UserDataAlgorithm extends BaseAlgorithm else readWiggle(pushback_reader); pushback_reader.close(); - document_reader.close(); + doc_reader.close(); + } + + /** + * Test if the tabix (.tbi) index is present. + * @param doc + * @return + */ + private static boolean isIndexed(Document doc) + { + if(doc instanceof FileDocument) + return (new File( + ((FileDocument)doc).getFile().getAbsolutePath() + ".tbi")).exists(); + return false; } /** @@ -373,8 +401,7 @@ public class UserDataAlgorithm extends BaseAlgorithm coordIndexStart = 2; coordIndexEnd = 3; } - - + while ((line = pushback_reader.readLine ()) != null) { String tokens[] = patt.split(line.trim()); @@ -488,7 +515,6 @@ public class UserDataAlgorithm extends BaseAlgorithm public void getValues (int start, int end, final float [] values) { final int value_count = getValueCount (); - if(getStrand ().getDirection() == Bases.REVERSE) { int tstart = start; @@ -521,6 +547,8 @@ public class UserDataAlgorithm extends BaseAlgorithm values[i] = values[i]/count; } } + else if(FORMAT == TABIX_INDEXED_FORMAT) + idxReader.getValues(start, end, values); else { for (int i = 0 ; i < value_count ; ++i) @@ -542,7 +570,6 @@ public class UserDataAlgorithm extends BaseAlgorithm private int parseHeader(StringBuffer headerText) throws ReadFormatException { FORMAT = BASE_SPECIFIED_FORMAT; - BufferedReader reader = new BufferedReader( new StringReader(headerText.toString())); @@ -604,7 +631,7 @@ public class UserDataAlgorithm extends BaseAlgorithm * * @param trackLine */ - private void parseTrackLine(String trackLine) + private void parseTrackLine(final String trackLine) { String colour = "0,0,0"; int beginIndex = trackLine.indexOf(" color="); @@ -618,9 +645,9 @@ public class UserDataAlgorithm extends BaseAlgorithm incrementLines(LineAttributes.parse(colour)); } - private void incrementLines(Color colour) + private void incrementLines(final Color c) { - LineAttributes line = new LineAttributes(colour); + LineAttributes line = new LineAttributes(c); if(lines == null) lines = new LineAttributes[1]; @@ -800,7 +827,7 @@ public class UserDataAlgorithm extends BaseAlgorithm return wiggle[index].span; } - public boolean isWiggleFormat() + protected boolean isWiggleFormat() { if(FORMAT == WIGGLE_VARIABLE_STEP_FORMAT || FORMAT == WIGGLE_FIXED_STEP_FORMAT) @@ -808,10 +835,171 @@ public class UserDataAlgorithm extends BaseAlgorithm return false; } + public void readIndexValues(Entry seqEntry, int start, int end) + { + if(start<1) + start = 1; + idxReader.readValuesForRange(seqEntry, start, end); + } + class Wiggle { int start; int step; int span = 0; } + + class TabixIdxGraph + { + private TabixReader reader; + /** number of columns with values */ + private int nValues = 1; + private float[][] rvalues; + private boolean startColIsEndCol = true; + private int sbeg, send; + + TabixIdxGraph(final String fName) throws IOException + { + this.reader = new TabixReader(fName); + if(getStartColumn() != getEndColumn()) + startColIsEndCol = false; + + final StringBuffer headerBuffer = new StringBuffer(); + String metaChar = String.valueOf(reader.getCommentChar()); + String hdr; + while( (hdr = reader.readLine() ) != null && hdr.startsWith(metaChar) ) + headerBuffer.append(hdr + "\n"); + //System.out.println("Header "+headerBuffer.toString()); + + // assume base end column is last column before columns of values + nValues = reader.readLine().split("\\t").length - getEndColumn(); + } + + /** + * Return the values between a pair of bases + * @param start + * @param end + * @param values + */ + private void getValues(int start, int end, final float[] values) + { + for (int i = 0 ; i < getNumberOfValues() ; ++i) + { + values [i] = 0; + for (int base = start ; base <= end ; ++base) + values [i] += rvalues[base - this.sbeg][i] / (end - start + 1); + } + } + + /** + * Get the sequence name + * @param seqEntry - sequence entry + * @return + */ + private String getReferenceName(Entry seqEntry) + { + String refStr = null; + if(seqEntry.getEMBLEntry().getSequence() instanceof IndexFastaStream) + refStr = + ((IndexFastaStream)seqEntry.getEMBLEntry().getSequence()).getContig(); + else if(seqEntry.getHeaderText() != null) + { + final String hdr = seqEntry.getHeaderText(); + int idx = hdr.indexOf("ID "); + if (idx == -1) + { + idx = hdr.indexOf("LOCUS "); // genbank + if (idx > -1) + refStr = hdr.substring(idx + 12).split("[;\\s]")[0]; + } + else + refStr = hdr.substring(idx + 5).split("[;\\s]")[0]; + } + + final String seqNames[] = reader.getSeqNames(); + if(refStr == null || !Arrays.asList(seqNames).contains(refStr)) + { + logger4j.debug(refStr+" NOT FOUND IN "+reader.getFileName()+ + " SET TO DEFAULT "+seqNames[0]); + refStr = reader.getSeqNames()[0]; + } + return refStr; + } + + /** + * Read the values in a range + * @param seqEntry - sequence entry + * @param start - start base + * @param end - end base + */ + private void readValuesForRange(Entry seqEntry, int start, int end) + { + if(end <= start || (start == this.sbeg && end == this.send)) + return; + + this.sbeg = start; + this.send = end; + rvalues = new float[end-start+1][getNumberOfValues()]; + final String r = getReferenceName(seqEntry)+":"+start+"-"+end; + try + { + final TabixReader.Iterator tbxIt = reader.query(r); + String ln; + while( tbxIt != null && (ln = tbxIt.next()) != null ) + { + StringVector parts = StringVector.getStrings(ln, "\t", true); + final int base; + if(startColIsEndCol) + base = Integer.parseInt((String)parts.get(getStartColumn()-1)) - start; + else + { + int b = Integer.parseInt((String)parts.get(getStartColumn()-1)); + int e = Integer.parseInt((String)parts.get(getEndColumn()-1)); + base = b + ((b - e)/2) - start; + } + for(int i=0; i<rvalues[base].length; i++) + { + float val = Float.parseFloat( (String) parts.get(i+getEndColumn()) ); + if(logTransform) + val = (float) Math.log(val+1); + + if (val > data_max) + data_max = val; + if (val < data_min) + data_min = val; + rvalues[base][i] = val; + } + } + } + catch (IOException e) + { + logger4j.debug("IOException READING RANGE "+r+" FROM "+reader.getFileName()); + e.printStackTrace(); + } + catch (NumberFormatException e) + { + logger4j.debug("NumberFormatException READING RANGE "+r+" FROM "+reader.getFileName()); + e.printStackTrace(); + } + } + + /** + * Number of columns with values + * @return + */ + private int getNumberOfValues() + { + return nValues; + } + + private int getStartColumn() + { + return reader.getStartColumn(); + } + + private int getEndColumn() + { + return reader.getEndColumn(); + } + } }