1 /* VCFview
2  *
3  * created: July 2010
4  *
5  * This file is part of Artemis
6  *
7  * Copyright(C) 2010  Genome Research Limited
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or(at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  */
24 
25 package uk.ac.sanger.artemis.components.variant;
26 import java.awt.AlphaComposite;
27 import java.awt.BorderLayout;
28 import java.awt.Color;
29 import java.awt.Component;
30 import java.awt.Composite;
31 import java.awt.Container;
32 import java.awt.Cursor;
33 import java.awt.Dimension;
34 import java.awt.FlowLayout;
35 import java.awt.FontMetrics;
36 import java.awt.Frame;
37 import java.awt.Graphics;
38 import java.awt.Graphics2D;
39 import java.awt.GridBagConstraints;
40 import java.awt.GridBagLayout;
41 import java.awt.Insets;
42 import java.awt.Point;
43 import java.awt.Rectangle;
44 import java.awt.event.ActionEvent;
45 import java.awt.event.ActionListener;
46 import java.awt.event.AdjustmentEvent;
47 import java.awt.event.AdjustmentListener;
48 import java.awt.event.MouseAdapter;
49 import java.awt.event.MouseEvent;
50 import java.awt.event.MouseMotionListener;
51 import java.awt.image.BufferedImage;
52 import java.io.File;
53 import java.io.FileInputStream;
54 import java.io.FileOutputStream;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.net.URL;
58 import java.util.HashMap;
59 import java.util.Hashtable;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.Vector;
63 import java.util.regex.Pattern;
64 
65 import javax.swing.BorderFactory;
66 import javax.swing.Box;
67 import javax.swing.ButtonGroup;
68 import javax.swing.ImageIcon;
69 import javax.swing.JButton;
70 import javax.swing.JCheckBox;
71 import javax.swing.JCheckBoxMenuItem;
72 import javax.swing.JComponent;
73 import javax.swing.JFrame;
74 import javax.swing.JLabel;
75 import javax.swing.JMenu;
76 import javax.swing.JMenuBar;
77 import javax.swing.JMenuItem;
78 import javax.swing.JOptionPane;
79 import javax.swing.JPanel;
80 import javax.swing.JPopupMenu;
81 import javax.swing.JRadioButton;
82 import javax.swing.JRadioButtonMenuItem;
83 import javax.swing.JScrollBar;
84 import javax.swing.JScrollPane;
85 import javax.swing.JSeparator;
86 import javax.swing.border.Border;
87 import javax.swing.border.EmptyBorder;
88 
89 import htsjdk.samtools.util.BlockCompressedInputStream;
90 
91 import org.apache.log4j.Level;
92 
93 import uk.ac.sanger.artemis.Entry;
94 import uk.ac.sanger.artemis.EntryGroup;
95 import uk.ac.sanger.artemis.Feature;
96 import uk.ac.sanger.artemis.FeatureKeyPredicate;
97 import uk.ac.sanger.artemis.FeatureVector;
98 import uk.ac.sanger.artemis.Options;
99 import uk.ac.sanger.artemis.Selection;
100 import uk.ac.sanger.artemis.SelectionChangeEvent;
101 import uk.ac.sanger.artemis.SelectionChangeListener;
102 import uk.ac.sanger.artemis.SimpleEntryGroup;
103 import uk.ac.sanger.artemis.components.DisplayAdjustmentEvent;
104 import uk.ac.sanger.artemis.components.DisplayAdjustmentListener;
105 import uk.ac.sanger.artemis.components.EntryEdit;
106 import uk.ac.sanger.artemis.components.EntryFileDialog;
107 import uk.ac.sanger.artemis.components.FeatureDisplay;
108 import uk.ac.sanger.artemis.components.FileViewer;
109 import uk.ac.sanger.artemis.components.IndexReferenceEvent;
110 import uk.ac.sanger.artemis.components.MessageDialog;
111 import uk.ac.sanger.artemis.components.MultiComparator;
112 import uk.ac.sanger.artemis.components.SequenceComboBox;
113 import uk.ac.sanger.artemis.components.Utilities;
114 import uk.ac.sanger.artemis.components.alignment.FileSelectionDialog;
115 import uk.ac.sanger.artemis.components.alignment.LineAttributes;
116 import uk.ac.sanger.artemis.editor.MultiLineToolTipUI;
117 import uk.ac.sanger.artemis.io.EntryInformation;
118 import uk.ac.sanger.artemis.io.Key;
119 import uk.ac.sanger.artemis.io.Range;
120 import uk.ac.sanger.artemis.io.RangeVector;
121 import uk.ac.sanger.artemis.sequence.Bases;
122 import uk.ac.sanger.artemis.sequence.MarkerRange;
123 import uk.ac.sanger.artemis.sequence.NoSequenceException;
124 import uk.ac.sanger.artemis.util.Document;
125 import uk.ac.sanger.artemis.util.DocumentFactory;
126 import uk.ac.sanger.artemis.util.FTPSeekableStream;
127 import uk.ac.sanger.artemis.util.OutOfRangeException;
128 
129 
130 public class VCFview extends JPanel
131              implements DisplayAdjustmentListener, SelectionChangeListener
132 {
133 
134   private static final long serialVersionUID = 1L;
135 
136   private JScrollPane jspView;
137 
138   private JScrollBar scrollBar;
139   private JPanel vcfPanel;
140   private AbstractVCFReader vcfReaders[];
141   private List<String> vcfFiles;
142   private List<Integer> hideVcfList = new Vector<Integer>();
143 
144   private FeatureDisplay feature_display;
145   private Selection selection;
146   private int nbasesInView;
147   protected int seqLength;
148   private EntryGroup entryGroup;
149   private String chr;
150   private Point lastMousePoint;
151   private VCFRecord mouseVCF;
152   private int mouseOverIndex = -1;
153   private int mouseOverSampleIndex = -1;
154 
155   private GraphPanel graphPanel;
156 
157 //record of where a mouse drag starts
158   private int dragStart = -1;
159   private JPopupMenu popup;
160   private JMenu vcfFilesMenu = new JMenu("VCF files");
161   private int LINE_HEIGHT = 14;
162 
163   protected boolean showSynonymous = true;
164   protected boolean showNonSynonymous = true;
165   protected boolean showDeletions = true;
166   protected boolean showInsertions = true;
167   protected boolean showMultiAlleles = true;
168   protected boolean showHomozygous = true;
169   // show variants that do not overlap CDS
170   protected boolean showNonOverlappings = true;
171   protected boolean showNonVariants = false;
172 
173   private Map<String, Boolean> manualHash = new HashMap<String, Boolean>();
174 
175   //private boolean markAsNewStop = false;
176 
177   private boolean showLabels = false;
178 
179   private JCheckBoxMenuItem markNewStops =
180     new JCheckBoxMenuItem("Mark new stops within CDS features", true);
181 
182   private static int VARIANT_COLOUR_SCHEME = 0;
183   private static int SYN_COLOUR_SCHEME     = 1;
184   private static int QUAL_COLOUR_SCHEME    = 2;
185 
186   private int colourScheme = 0;
187   private Color colMap[] = makeColours(Color.RED, 255);
188   private Color lighterGrey = new Color(220,220,220);
189 
190   private VCFFilter filter;
191   Hashtable<String, Integer> offsetLengths = null;
192   private boolean concatSequences = false;
193   private boolean splitSamples = true;
194 
195   protected static Pattern tabPattern = Pattern.compile("\t");
196 
197   public static String VCFFILE_SUFFIX = ".*\\.[bv]{1}cf(\\.gz)*$";
198   private static String FILE_SUFFIX = "\\.[bv]{1}cf(\\.gz)*$";
199 
200   private List<Integer> cacheVariantLines;
201   private SequenceComboBox combo;
202 
203   public static org.apache.log4j.Logger logger4j =
204     org.apache.log4j.Logger.getLogger(VCFview.class);
205 
VCFview(final JFrame frame, final JPanel vcfPanel, final List<String> vcfFiles, final int nbasesInView, final int seqLength, final String chr, final String reference, final EntryEdit entry_edit, final FeatureDisplay feature_display)206   public VCFview(final JFrame frame,
207                  final JPanel vcfPanel,
208                  final List<String> vcfFiles,
209                  final int nbasesInView,
210                  final int seqLength,
211                  final String chr,
212                  final String reference,
213                  final EntryEdit entry_edit,
214                  final FeatureDisplay feature_display)
215   {
216     super();
217 
218     this.nbasesInView = nbasesInView;
219     this.seqLength = seqLength;
220     this.chr = chr;
221 
222     this.feature_display = feature_display;
223     this.vcfPanel = vcfPanel;
224     this.vcfFiles = vcfFiles;
225 
226     jspView = new JScrollPane(this,
227         JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
228         JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
229 
230     setBackground(Color.white);
231     MultiLineToolTipUI.initialize();
232     setToolTipText("");
233     vcfPanel.setPreferredSize(new Dimension(900,
234         (vcfFiles.size()+1)*(LINE_HEIGHT+5)));
235 
236     if(feature_display != null)
237       this.entryGroup = feature_display.getEntryGroup();
238     else if(reference != null)
239       this.entryGroup = getReference(reference);
240     if(entryGroup != null)
241       this.seqLength = entryGroup.getSequenceEntry().getBases().getLength();
242 
243     try
244     {
245       vcfReaders = new AbstractVCFReader[vcfFiles.size()];
246 
247       for(int i=0; i<vcfFiles.size(); i++)
248       {
249         readHeader(vcfFiles.get(i), i);
250       }
251     }
252     catch(java.lang.UnsupportedClassVersionError err)
253     {
254       JOptionPane.showMessageDialog(null,
255           "This requires Java 1.8 or higher.",
256           "Check Java Version", JOptionPane.WARNING_MESSAGE);
257     }
258 
259     vcfPanel.setLayout(new BorderLayout());
260     vcfPanel.add(jspView, BorderLayout.CENTER);
261 
262     JPanel bottomPanel = new JPanel(new BorderLayout());
263     graphPanel = new GraphPanel(this);
264     graphPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.gray));
265     graphPanel.setVisible(false);
266 
267     bottomPanel.add(graphPanel, BorderLayout.CENTER);
268     vcfPanel.add(bottomPanel, BorderLayout.SOUTH);
269 
270     if(this.nbasesInView > this.seqLength)
271       this.nbasesInView = this.seqLength/2;
272 
273     scrollBar = new JScrollBar(JScrollBar.HORIZONTAL, 1, this.nbasesInView, 1, this.seqLength);
274     scrollBar.setUnitIncrement(nbasesInView/20);
275     scrollBar.addAdjustmentListener(new AdjustmentListener()
276     {
277       public void adjustmentValueChanged(AdjustmentEvent e)
278       {
279         repaint();
280       }
281     });
282 
283     //
284     //
285     addMouseListener(new PopupListener());
286 
287     //
288     createTopPanel(frame, entry_edit);
289     createMenus();
290     setDisplay();
291 
292     if(feature_display == null)
293     {
294       bottomPanel.add(scrollBar, BorderLayout.SOUTH);
295       selection = new Selection(null);
296     }
297     else
298     {
299       Border empty = new EmptyBorder(0,0,0,0);
300       jspView.setBorder(empty);
301       selection = feature_display.getSelection();
302     }
303   }
304 
createMenus()305   private void createMenus()
306   {
307     // popup menu
308     popup = new JPopupMenu();
309 
310     JMenuItem addVCFMenu = new JMenuItem("Add VCF ...");
311     addVCFMenu.addActionListener(new ActionListener()
312     {
313       public void actionPerformed(ActionEvent e)
314       {
315         FileSelectionDialog fileSelection = new FileSelectionDialog(
316             null, true, "VCFview", "VCF");
317         List<String> vcfFileList = fileSelection.getFiles(VCFFILE_SUFFIX);
318         vcfFiles.addAll(vcfFileList);
319 
320         int count = vcfFileList.size();
321         int oldSize = vcfReaders.length;
322 
323         AbstractVCFReader[] trTmp = new AbstractVCFReader[count + vcfReaders.length];
324         System.arraycopy(vcfReaders, 0, trTmp, 0, vcfReaders.length);
325         vcfReaders = trTmp;
326 
327         for (int i = 0; i < vcfFileList.size(); i++)
328           readHeader(vcfFileList.get(i), i+oldSize);
329 
330         for(int i=0; i<vcfFileList.size(); i++)
331           addToViewMenu(i+oldSize);
332 
333         setDisplay();
334         repaint();
335         jspView.revalidate();
336       }
337     });
338     popup.add(addVCFMenu);
339     popup.add(vcfFilesMenu);
340 
341     for(int i=0; i<vcfFiles.size(); i++)
342       addToViewMenu(i);
343 
344     final JMenu lineHgt = new JMenu("Row Height");
345     popup.add(lineHgt);
346     final ButtonGroup groupLnHgt = new ButtonGroup();
347     for(int i=8; i<37; i+=2)
348     {
349       final int ii = i;
350       final JCheckBoxMenuItem hgtMenu = new JCheckBoxMenuItem(
351           Integer.toString(i), (i == LINE_HEIGHT));
352       groupLnHgt.add(hgtMenu);
353       hgtMenu.addActionListener(new ActionListener()
354       {
355         public void actionPerformed(ActionEvent e)
356         {
357           if(hgtMenu.isSelected())
358           {
359             LINE_HEIGHT = ii;
360             setDisplay();
361             revalidate();
362           }
363         }
364       });
365       lineHgt.add(hgtMenu);
366     }
367 
368     popup.addSeparator();
369 
370     markNewStops.addActionListener(new ActionListener()
371     {
372       public void actionPerformed(ActionEvent e)
373       {
374         repaint();
375       }
376     });
377     popup.add(markNewStops);
378 
379 
380     final JCheckBoxMenuItem split = new JCheckBoxMenuItem("Separate out into samples", splitSamples);
381     split.addActionListener(new ActionListener()
382     {
383       public void actionPerformed(ActionEvent e)
384       {
385         splitSamples = split.isSelected();
386         setDisplay();
387         revalidate();
388       }
389     });
390     popup.add(split);
391 
392 
393     final JMenuItem byQuality = new JMenuItem("Filter ...");
394     if(!Options.getOptions().getPropertyTruthValue("java.awt.headless"))
395       filter = new VCFFilter(VCFview.this);
396 
397     byQuality.addActionListener(new ActionListener(){
398       public void actionPerformed(ActionEvent e)
399       {
400         filter.setVisible(true);
401       }
402     });
403     popup.add(byQuality);
404 
405     final JMenu colourBy = new JMenu("Colour By");
406     popup.add(colourBy);
407     ButtonGroup group = new ButtonGroup();
408     final JRadioButtonMenuItem colByAlt   = new JRadioButtonMenuItem("Variant");
409     colByAlt.addActionListener(new ActionListener(){
410       public void actionPerformed(ActionEvent e)
411       {
412         if(colByAlt.isSelected())
413           colourScheme = 0;
414         repaint();
415       }
416     });
417     colourBy.add(colByAlt);
418 
419     final JRadioButtonMenuItem colBySyn   = new JRadioButtonMenuItem("Synonymous/Non-synonymous");
420     colBySyn.addActionListener(new ActionListener(){
421       public void actionPerformed(ActionEvent e)
422       {
423         if(colBySyn.isSelected())
424           colourScheme = 1;
425         repaint();
426       }
427     });
428     colourBy.add(colBySyn);
429 
430     final JRadioButtonMenuItem colByScore = new JRadioButtonMenuItem("Score");
431     colByScore.addActionListener(new ActionListener(){
432       public void actionPerformed(ActionEvent e)
433       {
434         if(colByScore.isSelected())
435           colourScheme = 2;
436         repaint();
437       }
438     });
439     colourBy.add(colByScore);
440 
441     group.add(colByAlt);
442     group.add(colBySyn);
443     group.add(colByScore);
444     colByAlt.setSelected(true);
445 
446     popup.addSeparator();
447 
448     if (feature_display != null)
449     {
450       final JMenu create = new JMenu("Create");
451       final JMenuItem createTab = new JMenuItem(
452           "Features from variants");
453       popup.add(create);
454       create.add(createTab);
455       createTab.addActionListener(new ActionListener()
456       {
457         public void actionPerformed(ActionEvent e)
458         {
459           Container f = getVcfContainer();
460           try
461           {
462             f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
463             IOUtils.createFeatures(VCFview.this, entryGroup);
464           }
465           finally
466           {
467             f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
468           }
469         }
470       });
471     }
472 
473     final JMenu export = new JMenu("Write");
474     popup.add(export);
475 
476     final JMenuItem exportVCF = new JMenuItem("Filtered VCF");
477     exportVCF.addActionListener(new ActionListener(){
478       public void actionPerformed(ActionEvent e)
479       {
480         Container f = getVcfContainer();
481         try
482         {
483           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
484           IOUtils.export(manualHash, vcfFiles, VCFview.this);
485         }
486         finally
487         {
488           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
489         }
490       }
491     });
492     export.add(exportVCF);
493 
494     export.add(new JSeparator());
495 
496     final JMenuItem exportFastaSelected = new JMenuItem("FASTA of selected feature(s) ...");
497     exportFastaSelected.addActionListener(new ActionListener(){
498       public void actionPerformed(ActionEvent e)
499       {
500         Container f = getVcfContainer();
501         try
502         {
503           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
504           IOUtils.exportFasta(VCFview.this, selection.getAllFeatures(), false, null);
505         }
506         finally
507         {
508           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
509         }
510       }
511     });
512     export.add(exportFastaSelected);
513 
514     final JMenuItem exportFasta = new JMenuItem("FASTA of selected base range ...");
515     exportFasta.addActionListener(new ActionListener(){
516       public void actionPerformed(ActionEvent e)
517       {
518         Container f = getVcfContainer();
519         try
520         {
521           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
522           IOUtils.exportFastaByRange(VCFview.this, selection, false, null);
523         }
524         finally
525         {
526           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
527         }
528       }
529     });
530     export.add(exportFasta);
531 
532     final JMenuItem viewMinimalFasta = new JMenuItem("FASTA of variant sites only ...");
533     viewMinimalFasta.addActionListener(new ActionListener(){
534       public void actionPerformed(ActionEvent e)
535       {
536         Container f = getVcfContainer();
537         try
538         {
539           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
540           IOUtils.exportVariantFasta(VCFview.this);
541         }
542         finally
543         {
544           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
545         }
546       }
547     });
548     export.addSeparator();
549     export.add(viewMinimalFasta);
550 
551 
552     final JMenu view = new JMenu("View");
553     popup.add(view);
554     final JMenuItem viewFastaSelected = new JMenuItem("FASTA of selected feature(s) ...");
555     viewFastaSelected.addActionListener(new ActionListener(){
556       public void actionPerformed(ActionEvent e)
557       {
558         Container f = getVcfContainer();
559         try
560         {
561           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
562           IOUtils.exportFasta(VCFview.this, selection.getAllFeatures(), true, null);
563         }
564         finally
565         {
566           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
567         }
568       }
569     });
570     view.add(viewFastaSelected);
571 
572     final JMenuItem viewFasta = new JMenuItem("FASTA of selected base range ...");
573     viewFasta.addActionListener(new ActionListener(){
574       public void actionPerformed(ActionEvent e)
575       {
576         Container f = getVcfContainer();
577         try
578         {
579           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
580           IOUtils.exportFastaByRange(VCFview.this, selection, true, null);
581         }
582         finally
583         {
584           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
585         }
586       }
587     });
588     view.add(viewFasta);
589 
590 
591     JMenu graph = new JMenu("Graph");
592     popup.add(graph);
593 
594     final JCheckBoxMenuItem graphSNP = new JCheckBoxMenuItem("SNP");
595     final JCheckBoxMenuItem graphDP = new JCheckBoxMenuItem("Depth (DP)");
596     final JCheckBoxMenuItem graphSim = new JCheckBoxMenuItem("Base Similarity (%)");
597     graph.add(graphSNP);
598     graphSNP.addActionListener(new ActionListener(){
599       public void actionPerformed(ActionEvent e)
600       {
601         graphPanel.setVisible(graphSNP.isSelected());
602         graphDP.setSelected(false);
603         graphSim.setSelected(false);
604         graphPanel.setType(0);
605         setGraphSize();
606       }
607     });
608 
609     graph.add(graphDP);
610     graphDP.addActionListener(new ActionListener(){
611       public void actionPerformed(ActionEvent e)
612       {
613         graphPanel.setVisible(graphDP.isSelected());
614         graphSNP.setSelected(false);
615         graphSim.setSelected(false);
616         graphPanel.setType(1);
617         setGraphSize();
618       }
619     });
620 
621     graph.add(graphSim);
622     graphSim.addActionListener(new ActionListener(){
623       public void actionPerformed(ActionEvent e)
624       {
625         graphPanel.setVisible(graphSim.isSelected());
626         graphSNP.setSelected(false);
627         graphDP.setSelected(false);
628         graphPanel.setType(2);
629         setGraphSize();
630       }
631     });
632 
633     final JMenuItem snpOverview = new JMenuItem("Overview for selected features");
634     popup.add(snpOverview);
635     snpOverview.addActionListener(new ActionListener()
636     {
637       public void actionPerformed(ActionEvent e)
638       {
639         Container f = getVcfContainer();
640         try
641         {
642           f.setCursor(new Cursor(Cursor.WAIT_CURSOR));
643           IOUtils.countVariants(VCFview.this, selection.getAllFeatures());
644         }
645         catch (IOException e1)
646         {
647           JOptionPane.showMessageDialog(null, e1.getMessage());
648         }
649         finally
650         {
651           f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
652         }
653       }
654     });
655 
656     final JCheckBoxMenuItem labels = new JCheckBoxMenuItem("Show Labels", showLabels);
657     labels.addActionListener(new ActionListener(){
658       public void actionPerformed(ActionEvent e)
659       {
660         showLabels = labels.isSelected();
661         repaint();
662       }
663     });
664     popup.add(new JSeparator());
665     popup.add(labels);
666   }
667 
setGraphSize()668   private void setGraphSize()
669   {
670     repaint();
671     if(graphPanel.isVisible())
672       graphPanel.setPreferredSize(new Dimension(900, 70));
673     else
674       graphPanel.setPreferredSize(new Dimension(900, 1));
675 
676     vcfPanel.setPreferredSize(new Dimension(900,
677         graphPanel.getPreferredSize().height+getPreferredSize().height));
678     vcfPanel.revalidate();
679   }
680 
createTopPanel(final JFrame frame, final EntryEdit entry_edit)681   private void createTopPanel(final JFrame frame, final EntryEdit entry_edit)
682   {
683     final JComponent topPanel;
684     if(feature_display != null)
685       topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
686     else
687     {
688       markNewStops.setSelected(false);
689       markNewStops.setEnabled(false);
690       topPanel = new JMenuBar();
691       if(frame != null)
692         frame.setJMenuBar((JMenuBar)topPanel);
693 
694       JMenu fileMenu = new JMenu("File");
695       topPanel.add(fileMenu);
696 
697       JMenuItem printImage = new JMenuItem("Save As Image Files (png/jpeg)...");
698       printImage.addActionListener(new ActionListener()
699       {
700         public void actionPerformed(ActionEvent e)
701         {
702           PrintVCFview part = new PrintVCFview(VCFview.this);
703           part.print();
704         }
705       });
706       fileMenu.add(printImage);
707 
708       JMenuItem printPS = new JMenuItem("Print...");
709       printPS.addActionListener(new ActionListener()
710       {
711         public void actionPerformed(ActionEvent e)
712         {
713           PrintVCFview part = new PrintVCFview(VCFview.this);
714           part.validate();
715           part.doPrintActions();
716         }
717       });
718       fileMenu.add(printPS);
719 
720 
721       JMenuItem close = new JMenuItem("Close");
722       fileMenu.add(close);
723       close.addActionListener(new ActionListener()
724       {
725         public void actionPerformed(ActionEvent e)
726         {
727           VCFview.this.setVisible(false);
728           Component comp = VCFview.this;
729 
730           while( !(comp instanceof JFrame) )
731             comp = comp.getParent();
732           ((JFrame)comp).dispose();
733         }
734       });
735 
736       JButton zoomIn = new JButton("-");
737       Insets ins = new Insets(1,1,1,1);
738       zoomIn.setMargin(ins);
739       zoomIn.addActionListener(new ActionListener()
740       {
741         public void actionPerformed(ActionEvent e)
742         {
743           setZoomLevel((int) (VCFview.this.nbasesInView * 1.1));
744         }
745       });
746       topPanel.add(zoomIn);
747 
748       JButton zoomOut = new JButton("+");
749       zoomOut.setMargin(ins);
750       zoomOut.addActionListener(new ActionListener()
751       {
752         public void actionPerformed(ActionEvent e)
753         {
754           setZoomLevel((int) (VCFview.this.nbasesInView * .9));
755         }
756       });
757       topPanel.add(zoomOut);
758     }
759 
760     combo = new SequenceComboBox(vcfReaders[0].getSeqNames()){
761       private static final long serialVersionUID = 1L;
762       public void update(IndexReferenceEvent event)
763       {
764         if(combo.getSelectedItem().equals("Combine References"))
765           concatSequences = true;
766         else
767         {
768           VCFview.this.chr = (String) combo.getSelectedItem();
769           concatSequences = false;
770         }
771         repaint();
772       }
773     };
774 
775     if(vcfReaders[0].getSeqNames().length > 1)
776       combo.addItem("Combine References");
777 
778     if(chr == null)
779       this.chr = vcfReaders[0].getSeqNames()[0];
780     combo.setSelectedItem(this.chr);
781 
782     topPanel.add(combo);
783     if(topPanel instanceof JPanel)
784       vcfPanel.add(topPanel, BorderLayout.NORTH);
785 
786     // auto hide top panel
787     final JCheckBox buttonAutoHide = new JCheckBox("Hide", true);
788     buttonAutoHide.setToolTipText("Auto-Hide");
789     topPanel.add(buttonAutoHide);
790     final MouseMotionListener mouseMotionListener = new MouseMotionListener()
791     {
792       public void mouseDragged(MouseEvent event)
793       {
794         handleCanvasMouseDrag(event);
795       }
796 
797       public void mouseMoved(MouseEvent e)
798       {
799         lastMousePoint = e.getPoint();
800 
801         int thisHgt = HEIGHT;
802         if (thisHgt < 5)
803           thisHgt = 15;
804 
805         int y = (int) (e.getY() - jspView.getViewport().getViewRect().getY());
806         if (y < thisHgt)
807           topPanel.setVisible(true);
808         else
809         {
810           if (buttonAutoHide.isSelected())
811             topPanel.setVisible(false);
812         }
813 
814       }
815     };
816     addMouseMotionListener(mouseMotionListener);
817 
818 
819     if(feature_display != null)
820     {
821       JButton close = new JButton("Close");
822       topPanel.add(close);
823       close.addActionListener(new ActionListener()
824       {
825         public void actionPerformed(ActionEvent e)
826         {
827           setVisible(false);
828           if(entry_edit != null)
829             entry_edit.setNGDivider();
830           else
831             vcfPanel.setVisible(false);
832         }
833       });
834     }
835   }
836 
837   /**
838    * Create an icon of a box using the given colour.
839    * @param c
840    * @return
841    */
getImageIcon(Color c)842   protected ImageIcon getImageIcon(Color c)
843   {
844     BufferedImage image = (BufferedImage)this.createImage(10, 10);
845     if(image == null)
846       return null;
847     Graphics2D g2 = image.createGraphics();
848     g2.setColor(c);
849     g2.fillRect(0, 0, 10, 10);
850     return new ImageIcon(image);
851   }
852 
addToViewMenu(final int thisBamIndex)853   private void addToViewMenu(final int thisBamIndex)
854   {
855     LineAttributes ln[] = GraphPanel.getLineAttributes(vcfReaders.length);
856     final JCheckBoxMenuItem cbBam = new JCheckBoxMenuItem(
857         getLabel(thisBamIndex),
858         getImageIcon(ln[thisBamIndex].getLineColour()),
859         true);
860 
861     vcfFilesMenu.add(cbBam);
862     cbBam.addActionListener(new ActionListener()
863     {
864       public void actionPerformed(ActionEvent e)
865       {
866         if(cbBam.isSelected())
867           hideVcfList.remove(new Integer(thisBamIndex));
868         else
869           hideVcfList.add(new Integer(thisBamIndex));
870         repaint();
871       }
872     });
873   }
874 
875   /**
876    * Test and download if on a http server
877    * @param fileName
878    * @return
879    */
testForURL(String fileName, boolean isBCF)880   private String testForURL(String fileName, boolean isBCF)
881   {
882     if(!fileName.startsWith("http:") && !fileName.startsWith("ftp:"))
883       return fileName;
884 
885     return download(fileName+".tbi", ".tbi");
886   }
887 
download(String f, String suffix)888   protected String download(String f, String suffix)
889   {
890     try
891     {
892       final URL urlFile = new URL(f);
893       InputStream is = urlFile.openStream();
894 
895       // Create temp file.
896       String name = urlFile.getFile();
897       int ind = name.lastIndexOf('/');
898       if(ind > -1)
899         name = name.substring(ind+1);
900       File bcfFile = File.createTempFile(name.replaceAll("[\\/\\s]", "_"), suffix);
901 
902       bcfFile.deleteOnExit();
903 
904       FileOutputStream out = new FileOutputStream(bcfFile);
905       int c;
906       while ((c = is.read()) != -1)
907         out.write(c);
908       out.flush();
909       out.close();
910       is.close();
911       return bcfFile.getAbsolutePath();
912     }
913     catch(IOException ioe)
914     {
915       JOptionPane.showMessageDialog(null,
916           "Problem downloading\n"+f,
917           "Problem", JOptionPane.WARNING_MESSAGE);
918     }
919     return null;
920   }
921 
getReference(String reference)922   private static EntryGroup getReference(String reference)
923   {
924     EntryGroup entryGroup = new SimpleEntryGroup();
925     final Document entry_document = DocumentFactory.makeDocument(reference);
926     final EntryInformation artemis_entry_information =
927       Options.getArtemisEntryInformation();
928 
929     final uk.ac.sanger.artemis.io.Entry new_embl_entry =
930       EntryFileDialog.getEntryFromFile(null, entry_document,
931                                        artemis_entry_information,
932                                        false);
933     if(new_embl_entry != null) // the read failed
934     {
935       Entry entry = null;
936       Bases bases = null;
937       try
938       {
939         if (entryGroup.getSequenceEntry() != null)
940           bases = entryGroup.getSequenceEntry().getBases();
941         if (bases == null)
942         {
943           entry = new Entry(new_embl_entry);
944           bases = entry.getBases();
945         }
946         else
947           entry = new Entry(bases, new_embl_entry);
948         entryGroup.add(entry);
949       }
950       catch (OutOfRangeException e)
951       {
952         new MessageDialog(null, "read failed: one of the features in "
953             + reference + " has an out of range " + "location: "
954             + e.getMessage());
955       }
956       catch (NoSequenceException e)
957       {
958         // TODO Auto-generated catch block
959         e.printStackTrace();
960       }
961     }
962     return entryGroup;
963   }
964 
965   /**
966    * Read the vcf header
967    * @param fileName
968    * @return
969    */
readHeader(String fileName, int index)970   private void readHeader(String fileName, int index)
971   {
972     StringBuffer buff = new StringBuffer();
973     //buff.append(fileName+"\n");
974     try
975     {
976       if(IOUtils.isBCF(fileName))
977       {
978         vcfReaders[index] = new BCFReader(fileName);
979         String hdr = ((BCFReader)vcfReaders[index]).headerToString();
980         if(hdr.indexOf("VCFv4") > -1)
981           vcfReaders[index].setVcf_v4(true);
982 
983         vcfReaders[index].setHeader(hdr);
984         return;
985       }
986 
987       String indexfileName = testForURL(fileName, false);
988       BlockCompressedInputStream is;
989       if(fileName.startsWith("http")|| fileName.startsWith("ftp"))
990       {
991         URL url = new URL(fileName);
992         if(fileName.startsWith("ftp"))
993           vcfReaders[index] = new TabixReader(indexfileName.substring(0, indexfileName.length()-4), new FTPSeekableStream(url));
994         else
995           vcfReaders[index] = new TabixReader(indexfileName.substring(0, indexfileName.length()-4), url);
996         is = new BlockCompressedInputStream(url);
997       }
998       else
999       {
1000         vcfReaders[index] = new TabixReader(fileName);
1001         is = new BlockCompressedInputStream(new FileInputStream(fileName));
1002       }
1003 
1004       String line;
1005       while( (line = TabixReader.readLine(is) ) != null )
1006       {
1007         if(!line.startsWith("#"))
1008           break;
1009 
1010         if(line.indexOf("VCFv4") > -1)
1011           vcfReaders[index].setVcf_v4(true);
1012         buff.append(line+"\n");
1013       }
1014       is.close();
1015     }
1016     catch (IOException e)
1017     {
1018       e.printStackTrace();
1019     }
1020 
1021     vcfReaders[index].setHeader(buff.toString());
1022     return;
1023   }
1024 
1025   /**
1026    * Set the number of bases being displayed
1027    * @param nbasesInView
1028    */
setZoomLevel(final int nbasesInView)1029   private void setZoomLevel(final int nbasesInView)
1030   {
1031     int startValue = scrollBar.getValue();
1032     this.nbasesInView = nbasesInView;
1033     float pixPerBase = getPixPerBaseByWidth();
1034     this.nbasesInView = (int)(getWidth()/pixPerBase);
1035 
1036     if(scrollBar != null)
1037     {
1038       scrollBar.setValues(startValue, nbasesInView, 1, seqLength);
1039       scrollBar.setUnitIncrement(nbasesInView/20);
1040       scrollBar.setBlockIncrement(nbasesInView);
1041     }
1042   }
1043 
getToolTipText()1044   public String getToolTipText()
1045   {
1046     if(vcfReaders == null)
1047       return null;
1048 
1049     mouseVCF = null;
1050     findVariantAtPoint(lastMousePoint);
1051     if(mouseVCF == null)
1052       return null;
1053 
1054     String msg =
1055            "Seq: "+mouseVCF.getChrom()+"\n";
1056     msg += "Pos: "+mouseVCF.getPos()+"\n";
1057     msg += "ID:  "+mouseVCF.getID()+"\n";
1058     msg += "Variant: "+mouseVCF.getRef()+" -> "+mouseVCF.getAlt().toString()+"\n";
1059     msg += "Qual: "+mouseVCF.getQuality()+"\n";
1060     String dp;
1061 
1062     if(splitSamples && mouseOverSampleIndex >= 0)
1063     {
1064       msg += "Genotype ";
1065       msg += mouseVCF.getFormat();
1066       msg += "\n";
1067       msg += mouseVCF.getFormatValueForSample(mouseOverSampleIndex);
1068     }
1069     else if((dp = mouseVCF.getInfoValue("DP")) != null)
1070     {
1071       msg += "DP:"+dp;
1072     }
1073     return msg;
1074   }
1075 
1076 
1077   /**
1078    * For VCF files with multiple references sequences, calculate
1079    * the offset from the start of the concatenated sequence for
1080    * a given reference.
1081    * @param refName
1082    * @return
1083    */
getSequenceOffset(String refName)1084   protected int getSequenceOffset(String refName)
1085   {
1086     if(!concatSequences)
1087       return 0;
1088 
1089     if(offsetLengths == null)
1090     {
1091       String[] contigs = vcfReaders[0].getSeqNames();
1092       FeatureVector features = entryGroup.getAllFeatures();
1093       offsetLengths = new Hashtable<String, Integer>(contigs.length);
1094       for(int i=0; i<contigs.length; i++)
1095       {
1096         FeatureContigPredicate predicate = new FeatureContigPredicate(contigs[i]);
1097         for(int j=0; j<features.size(); j++)
1098         {
1099           if(predicate.testPredicate(features.elementAt(j)))
1100           {
1101             offsetLengths.put(contigs[i], features.elementAt(j).getFirstBase()-1);
1102             break;
1103           }
1104         }
1105       }
1106 
1107       if(offsetLengths.size() != contigs.length)
1108       {
1109         System.err.println("Number of contigs found : "+offsetLengths.size() +
1110                          "\nNumber of contigs in VCF: "+contigs.length);
1111         JOptionPane.showMessageDialog(this,
1112             "There is a problem matching the reference sequences\n"+
1113             "to the names in the VCF file. This may mean the labels\n"+
1114             "on the reference features do not match those in the in\n"+
1115             "the VCF file.",
1116             "Problem Found", JOptionPane.WARNING_MESSAGE);
1117         concatSequences = false;
1118         return 0;
1119       }
1120     }
1121     return offsetLengths.get(refName);
1122   }
1123 
repaint()1124   public void repaint()
1125   {
1126     super.repaint();
1127     if(graphPanel != null && graphPanel.isVisible())
1128       graphPanel.repaint();
1129   }
1130 
paintComponent(Graphics g)1131   protected void paintComponent(Graphics g)
1132   {
1133     super.paintComponent(g);
1134 
1135     Graphics2D g2d = (Graphics2D)g;
1136     mouseVCF = null;
1137 
1138     float pixPerBase = getPixPerBaseByWidth();
1139     int start = getBaseAtStartOfView();
1140     int end   = start+nbasesInView;
1141 
1142     drawSelectionRange((Graphics2D)g, pixPerBase, start, end);
1143 
1144     int sumSamples = 0;
1145     FeatureVector features = getCDSFeaturesInRange(start, end);
1146 
1147     for (int i = 0; i < vcfReaders.length; i++)
1148     {
1149       if(hideVcfList.contains(i))
1150         continue;
1151 
1152       if(concatSequences)
1153       {
1154         String[] contigs = vcfReaders[0].getSeqNames();
1155         for(int j=0; j<contigs.length; j++)
1156         {
1157           int offset = getSequenceOffset(contigs[j]);
1158           int nextOffset;
1159           if(j<contigs.length-1)
1160             nextOffset = getSequenceOffset(contigs[j+1]);
1161           else
1162             nextOffset = seqLength;
1163 
1164           if( (offset >= start && offset < end) ||
1165               (offset < start && start < nextOffset) )
1166           {
1167             int thisStart = start - offset;
1168             if(thisStart < 1)
1169               thisStart = 1;
1170             int thisEnd   = end - offset;
1171 
1172             drawRegion(g2d, contigs[j], thisStart, thisEnd, i, sumSamples, start, pixPerBase, features);
1173 
1174           }
1175         }
1176 
1177       }
1178       else
1179       {
1180         int thisStart = start;
1181         if(thisStart < 1)
1182           thisStart = 1;
1183         drawRegion(g2d, chr, thisStart, end, i, sumSamples, start, pixPerBase, features);
1184       }
1185       sumSamples += vcfReaders[i].getNumberOfSamples();
1186     }
1187 
1188     if(feature_display == null)
1189       drawScale(g2d, start, end, pixPerBase, getHeight());
1190 
1191     // show labels for each VCF
1192     if(showLabels)
1193        showLabels(g2d);
1194   }
1195 
showLabels(Graphics2D g2d)1196   private void showLabels(Graphics2D g2d)
1197   {
1198     int max = 0;
1199     final FontMetrics fm = getFontMetrics(getFont());
1200 
1201     for (int i = 0; i < vcfReaders.length; i++)
1202     {
1203       if(hideVcfList.contains(i))
1204         continue;
1205 
1206       if(splitSamples)
1207       {
1208         for(int sampleIdx = 0; sampleIdx < vcfReaders[i].getNumberOfSamples(); sampleIdx++)
1209         {
1210           if(vcfReaders[i].sampleNames == null)
1211           {
1212             int width = fm.stringWidth(getLabel(i));
1213             if (max < width)
1214               max = width;
1215             break;
1216           }
1217 
1218           String labStr = vcfReaders[i].sampleNames[sampleIdx];
1219           int width = fm.stringWidth(labStr);
1220           if (max < width)
1221             max = width;
1222         }
1223       }
1224       else
1225       {
1226         String labStr = getLabel(i);
1227         int width = fm.stringWidth(labStr);
1228         if (max < width)
1229           max = width;
1230       }
1231     }
1232 
1233     Rectangle square = new Rectangle(0, 0, max, getHeight());
1234     Composite originalComposite = g2d.getComposite();
1235     g2d.setPaint(Color.lightGray);
1236     g2d.setComposite(makeComposite(0.75f));
1237     g2d.fill(square);
1238     g2d.setComposite(originalComposite);
1239 
1240     g2d.setColor(Color.black);
1241     g2d.drawLine(max+1, 0, max+1, getHeight());
1242 
1243     int sumSample = 0;
1244     for (int i = 0; i < vcfReaders.length; i++)
1245     {
1246       if(hideVcfList.contains(i))
1247         continue;
1248 
1249       if(splitSamples)
1250       {
1251         for(int sampleIdx=0; sampleIdx < vcfReaders[i].getNumberOfSamples(); sampleIdx++)
1252         {
1253           if(vcfReaders[i].sampleNames == null)
1254             g2d.drawString(getLabel(i), 1, getYPostion(sumSample+sampleIdx));
1255           else
1256             g2d.drawString(vcfReaders[i].sampleNames[sampleIdx], 1, getYPostion(sumSample+sampleIdx));
1257         }
1258         sumSample += vcfReaders[i].getNumberOfSamples();
1259       }
1260       else
1261         g2d.drawString(getLabel(i), 1, getYPostion(i));
1262     }
1263   }
1264 
getLabel(int index)1265   private String getLabel(int index)
1266   {
1267     return vcfReaders[index].getName().replaceAll(FILE_SUFFIX, "");
1268   }
1269 
makeComposite(float alpha)1270   private AlphaComposite makeComposite(float alpha)
1271   {
1272     return(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
1273   }
1274 
1275 
drawRegion(final Graphics2D g, final String chr, final int sbeg, final int send, final int vcfFileIndex, final int sumSamples, final int start, final float pixPerBase, final FeatureVector features)1276   private void drawRegion(final Graphics2D g,
1277                           final String chr,
1278                           final int sbeg,
1279                           final int send,
1280                           final int vcfFileIndex,
1281                           final int sumSamples,
1282                           final int start,
1283                           final float pixPerBase,
1284                           final FeatureVector features)
1285   {
1286     cacheVariantLines = new Vector<Integer>(5);
1287     try
1288     {
1289       VCFRecord record;
1290 
1291       // viewport position and height
1292       int viewIndex = getHeight()/(LINE_HEIGHT+5) - jspView.getViewport().getViewPosition().y/(LINE_HEIGHT+5);
1293       int viewHgt = jspView.getViewport().getExtentSize().height/(LINE_HEIGHT+5);
1294 
1295       while((record = vcfReaders[vcfFileIndex].getNextRecord(chr, sbeg, send)) != null)
1296       {
1297         int basePosition = record.getPos() + getSequenceOffset(record.getChrom());
1298         if(!splitSamples)
1299         {
1300           drawVariantCall(g, record, start, vcfFileIndex, -1, -1, pixPerBase, features,
1301               vcfReaders[vcfFileIndex], basePosition);
1302           continue;
1303         }
1304 
1305         for(int sampleIndex = 0; sampleIndex < vcfReaders[vcfFileIndex].getNumberOfSamples(); sampleIndex++)
1306         {
1307           if(sampleIndex+sumSamples <= viewIndex+2 && sampleIndex+sumSamples >= viewIndex-viewHgt-2)
1308           {
1309             drawVariantCall(g, record, start, vcfFileIndex, sampleIndex, sumSamples, pixPerBase, features,
1310               vcfReaders[vcfFileIndex], basePosition);
1311           }
1312         }
1313       }
1314     }
1315     catch (IOException e)
1316     {
1317       logger4j.warn(chr+":"+sbeg+"-"+send+"\n"+e.getMessage());
1318       e.printStackTrace();
1319     }
1320   }
1321 
getCDSFeaturesInRange(int start, int end)1322   protected FeatureVector getCDSFeaturesInRange(int start, int end)
1323   {
1324     if(entryGroup == null)
1325       return null;
1326     try
1327     {
1328       Range range = new Range(start, end);
1329       FeatureVector features = entryGroup.getFeaturesInRange(range);
1330 
1331       FeatureKeyPredicate predicate = new FeatureKeyPredicate(Key.CDS);
1332       final FeatureVector cdsFeatures = new FeatureVector();
1333 
1334       for(int i=0; i<features.size(); i++)
1335       {
1336         final Feature this_feature = features.elementAt(i);
1337         if(predicate.testPredicate(this_feature))
1338           cdsFeatures.add(this_feature);
1339       }
1340       return cdsFeatures;
1341     }
1342     catch (OutOfRangeException e1)
1343     {
1344       e1.printStackTrace();
1345     }
1346     return null;
1347   }
1348 
1349   /**
1350    * Highlight a selected range
1351    * @param g2
1352    * @param pixPerBase
1353    * @param start
1354    * @param end
1355    */
drawSelectionRange(Graphics2D g2, float pixPerBase, int start, int end)1356   private void drawSelectionRange(Graphics2D g2, float pixPerBase, int start, int end)
1357   {
1358     if(getSelection() != null)
1359     {
1360       Range selectedRange = getSelection().getSelectionRange();
1361 
1362       if(selectedRange != null)
1363       {
1364         int rangeStart = selectedRange.getStart();
1365         int rangeEnd   = selectedRange.getEnd();
1366 
1367         if(end < rangeStart || start > rangeEnd)
1368           return;
1369 
1370         int x = (int) (pixPerBase*(rangeStart-getBaseAtStartOfView()));
1371         int width = (int) (pixPerBase*(rangeEnd-rangeStart+1));
1372 
1373         g2.setColor(Color.pink);
1374         g2.fillRect(x, 0, width, getHeight());
1375       }
1376     }
1377   }
1378 
getSelection()1379   private Selection getSelection()
1380   {
1381     return selection;
1382   }
1383 
getBaseAtStartOfView()1384   protected int getBaseAtStartOfView()
1385   {
1386     if(feature_display != null)
1387       return feature_display.getForwardBaseAtLeftEdge();
1388     else
1389       return scrollBar.getValue();
1390   }
1391 
showVariant(final VCFRecord record, final FeatureVector features, final int basePosition, final AbstractVCFReader vcfReader, final int nsample, final int vcfIndex)1392   protected boolean showVariant(final VCFRecord record, final FeatureVector features, final int basePosition,
1393       final AbstractVCFReader vcfReader, final int nsample, final int vcfIndex)
1394   {
1395     return VCFFilter.passFilter(manualHash, record, vcfReader, features, basePosition, nsample, vcfIndex);
1396   }
1397 
setAsStop(VCFRecord record, FeatureVector features, int basePosition, AbstractVCFReader vcfReader)1398   private void setAsStop(VCFRecord record, FeatureVector features, int basePosition, AbstractVCFReader vcfReader)
1399   {
1400     if(!record.isMarkAsNewStop() &&
1401         markNewStops.isSelected() &&
1402        !record.getAlt().isDeletion(vcfReader.isVcf_v4()) &&
1403        !record.getAlt().isInsertion(vcfReader.isVcf_v4()) &&
1404         record.getAlt().length() == 1 &&
1405         record.getRef().length() == 1)
1406     {
1407       short isSyn = record.getSynFlag(features, basePosition);
1408       if(isSyn == 2)
1409         record.setMarkAsNewStop(true);
1410     }
1411   }
1412 
isOverlappingFeature(FeatureVector features, int basePosition)1413   protected static boolean isOverlappingFeature(FeatureVector features, int basePosition)
1414   {
1415     for(int i = 0; i<features.size(); i++)
1416     {
1417       Feature feature = features.elementAt(i);
1418       if(feature.getRawFirstBase() < basePosition && feature.getRawLastBase() > basePosition)
1419       {
1420         RangeVector ranges = feature.getLocation().getRanges();
1421         for(int j=0; j< ranges.size(); j++)
1422         {
1423           Range range = (Range) ranges.get(j);
1424           if(range.getStart() < basePosition && range.getEnd() > basePosition)
1425             return true;
1426         }
1427       }
1428     }
1429     return false;
1430   }
1431 
isOverlappingFeature(List<CDSFeature> cdsFeatures, int basePosition)1432   protected static boolean isOverlappingFeature(List<CDSFeature> cdsFeatures, int basePosition) {
1433       for (CDSFeature cdsFeature : cdsFeatures) {
1434           if (cdsFeature.firstBase < basePosition && cdsFeature.lastBase > basePosition)
1435           {
1436               for(int i = 0 ; i < cdsFeature.ranges.size()  ; ++i)
1437               {
1438                    Range range = (Range)cdsFeature.ranges.elementAt(i);
1439                    if (range.getStart() < basePosition && range.getEnd() > basePosition)
1440                        return true;
1441               }
1442           }
1443       }
1444       return false;
1445   }
1446 
1447   /**
1448    * Draw the VCF record
1449    * @param g
1450    * @param record
1451    * @param start
1452    * @param vcfIndex
1453    * @param sampleIndex
1454    * @param sumSamples
1455    * @param pixPerBase
1456    * @param features
1457    * @param vcfReader
1458    * @param basePosition
1459    */
drawVariantCall(final Graphics2D g, final VCFRecord record, final int start, final int vcfIndex, final int sampleIndex, final int sumSamples, final float pixPerBase, final FeatureVector features, final AbstractVCFReader vcfReader, final int basePosition)1460   private void drawVariantCall(final Graphics2D g,
1461                                final VCFRecord record,
1462                                final int start,
1463                                final int vcfIndex,
1464                                final int sampleIndex,
1465                                final int sumSamples,
1466                                final float pixPerBase,
1467                                final FeatureVector features,
1468                                final AbstractVCFReader vcfReader,
1469                                final int basePosition)
1470   {
1471     boolean show = showVariant(record, features, basePosition, vcfReader, sampleIndex, vcfIndex);
1472     if( !show )
1473       return;
1474 
1475     setAsStop(record, features, basePosition, vcfReader);
1476     final int pos[];
1477     if(sampleIndex < 0)
1478       pos = getScreenPosition(basePosition, pixPerBase, start, vcfIndex);
1479     else
1480       pos = getScreenPosition(basePosition, pixPerBase, start, sampleIndex+sumSamples);
1481 
1482     if (colourScheme == QUAL_COLOUR_SCHEME)
1483       g.setColor(getQualityColour(record));
1484     else if (record.getAlt().isDeletion(vcfReader.isVcf_v4()))
1485       g.setColor(Color.gray);
1486     else if (record.getAlt().isInsertion(vcfReader.isVcf_v4()))
1487       g.setColor(Color.magenta);
1488     else if (record.getAlt().isMultiAllele(sampleIndex))
1489     {
1490       g.setColor(Color.orange);
1491       g.fillArc(pos[0] - 3, pos[1] - LINE_HEIGHT - 3, 6, 6, 0, 360);
1492     }
1493     else if (record.getAlt().length() == 1 && record.getRef().length() == 1)
1494     {
1495       g.setColor(getColourForSNP(record, features, basePosition));
1496       if (record.getAlt().isNonVariant())
1497       {
1498         // use the cache to avoid drawing over a variant with a non-variant
1499         if (!cacheVariantLines.contains(pos[0]))
1500           g.drawLine(pos[0], pos[1], pos[0], pos[1] - LINE_HEIGHT + 6);
1501         return;
1502       }
1503     }
1504     else
1505       g.setColor(Color.pink);
1506 
1507     if (record.isMarkAsNewStop())
1508       g.fillArc(pos[0] - 3, pos[1] - (LINE_HEIGHT / 2) - 3, 6, 6, 0, 360);
1509 
1510     if (cacheVariantLines.size() == 5)
1511       cacheVariantLines.clear();
1512     cacheVariantLines.add(pos[0]);
1513 
1514     g.drawLine(pos[0], pos[1], pos[0], pos[1] - LINE_HEIGHT);
1515   }
1516 
1517   /**
1518    * Determine the colour depending on the colour scheme in use.
1519    * @param record
1520    * @param features
1521    * @param basePosition
1522    * @return
1523    */
getColourForSNP(VCFRecord record, FeatureVector features, int basePosition)1524   private Color getColourForSNP(VCFRecord record, FeatureVector features, int basePosition)
1525   {
1526     if(colourScheme == VARIANT_COLOUR_SCHEME)
1527       return getVariantColour(record.getAlt().toString());
1528     else if(colourScheme == SYN_COLOUR_SCHEME)  // synonymous / non-synonymous
1529     {
1530       if(!record.getAlt().isNonVariant())
1531       {
1532         short synFlag = record.getSynFlag(features, basePosition);
1533         if(synFlag == 1)
1534           return Color.red;
1535         else if(synFlag == 0 || synFlag == 2)
1536           return Color.blue;
1537       }
1538       return getVariantColour(record.getAlt().toString());
1539     }
1540     else // score
1541       return getQualityColour(record);
1542   }
1543 
getQualityColour(VCFRecord record)1544   private Color getQualityColour(VCFRecord record)
1545   {
1546     if(colMap == null)
1547       colMap = makeColours(Color.RED, 255);
1548     int idx = (int) record.getQuality()-1;
1549     if(idx > colMap.length-1)
1550       idx = colMap.length-1;
1551     else if(idx < 0)
1552       idx = 0;
1553     return colMap[idx];
1554   }
1555 
getVariantColour(String variant)1556   private Color getVariantColour(String variant)
1557   {
1558     if(variant.equals("C"))
1559       return Color.red;
1560     else if(variant.equals("A"))
1561       return Color.green;
1562     else if(variant.equals("G"))
1563       return Color.blue;
1564     else if(variant.equals("T"))
1565       return Color.black;
1566     else
1567       return lighterGrey; // non-variant
1568   }
1569 
1570   /**
1571    * Generate the colours for heat map plots.
1572    * @param col
1573    * @param NUMBER_OF_SHADES
1574    * @return
1575    */
makeColours(Color col, int NUMBER_OF_SHADES)1576   private Color[] makeColours(Color col, int NUMBER_OF_SHADES)
1577   {
1578     Color definedColour[] = new Color[NUMBER_OF_SHADES];
1579     for(int i = 0; i < NUMBER_OF_SHADES; ++i)
1580     {
1581       int R = col.getRed();
1582       int G = col.getGreen();
1583       int B = col.getBlue();
1584 
1585       float scale = ((float)(NUMBER_OF_SHADES-i) * (float)(255 / NUMBER_OF_SHADES )) ;
1586 
1587       if((R+scale) <= 255)
1588         R += scale;
1589       else
1590         R = 254;
1591       if((G+scale) <= 255)
1592         G += scale;
1593       else
1594         G = 254;
1595       if((B+scale) <= 255)
1596         B += scale;
1597       else
1598         B = 254;
1599 
1600       definedColour[i] = new Color(R,G,B);
1601     }
1602     return definedColour;
1603   }
1604 
getScreenPosition(int base, float pixPerBase, int start, int vcfFileIndex)1605   private int[] getScreenPosition(int base, float pixPerBase, int start, int vcfFileIndex)
1606   {
1607     int pos[] = new int[2];
1608     pos[0] = Math.round((base - start)*pixPerBase);
1609     pos[1] = getYPostion(vcfFileIndex);
1610     return pos;
1611   }
1612 
getYPostion(int vcfFileIndex)1613   private int getYPostion(int vcfFileIndex)
1614   {
1615     int pos = 0;
1616     if(hideVcfList.size() == 0 || splitSamples)
1617       pos = vcfFileIndex;
1618     else
1619     {
1620       for(int i=0; i<vcfFileIndex; i++)
1621         if(!hideVcfList.contains(i))
1622           pos++;
1623     }
1624 
1625     return getHeight() - 15 - (pos*(LINE_HEIGHT+5));
1626   }
1627 
findVariantAtPoint(Point mousePoint)1628   private void findVariantAtPoint(Point mousePoint)
1629   {
1630     float pixPerBase = getPixPerBaseByWidth();
1631     int startBase = getBaseAtStartOfView();
1632     int start = startBase + (int)(mousePoint.getX()/pixPerBase) - 20;
1633     int end   = start+20;
1634     FeatureVector features = getCDSFeaturesInRange(start, end);
1635     int sumSamples = 0;
1636 
1637     for (int i = 0; i < vcfReaders.length; i++)
1638     {
1639 
1640         if(concatSequences)
1641         {
1642           String[] contigs = vcfReaders[0].getSeqNames();
1643           for(int k=0; k<contigs.length; k++)
1644           {
1645             int offset = getSequenceOffset(contigs[k]);
1646             int nextOffset;
1647             if(k<contigs.length-1)
1648               nextOffset = getSequenceOffset(contigs[k+1]);
1649             else
1650               nextOffset = seqLength;
1651 
1652             if( (offset >= start && offset < end) ||
1653                 (offset < start && start < nextOffset) )
1654             {
1655               int thisStart = start - offset;
1656               if(thisStart < 1)
1657                 thisStart = 1;
1658               int thisEnd   = end - offset;
1659               searchRegion(contigs[k], thisStart, thisEnd, i, sumSamples, mousePoint, features, startBase, pixPerBase);
1660             }
1661           }
1662         }
1663         else
1664         {
1665           int thisStart = start;
1666           if(thisStart < 1)
1667             thisStart = 1;
1668           searchRegion(chr, thisStart, end, i, sumSamples, mousePoint, features, startBase, pixPerBase);
1669         }
1670 
1671 
1672       sumSamples += vcfReaders[i].getNumberOfSamples();
1673     }
1674   }
1675 
searchRegion(final String chr, final int sbeg, final int send, final int fileIndex, final int sumSamples, final Point mousePoint, FeatureVector features, int start, float pixPerBase)1676   private void searchRegion(final String chr,
1677                             final int sbeg, final int send,
1678                             final int fileIndex,
1679                             final int sumSamples,
1680                             final Point mousePoint, FeatureVector features,
1681                             int start, float pixPerBase)
1682   {
1683     try
1684     {
1685       VCFRecord bcfRecord;
1686       while((bcfRecord = vcfReaders[fileIndex].getNextRecord(chr, sbeg, send)) != null)
1687       {
1688 
1689         if(splitSamples)
1690         {
1691           for(int sampleIndex=0; sampleIndex<vcfReaders[fileIndex].getNumberOfSamples(); sampleIndex++)
1692           {
1693             int ypos = getYPostion(sampleIndex+sumSamples);
1694             if(mousePoint.getY() > ypos &&
1695                mousePoint.getY() < ypos-LINE_HEIGHT)
1696               continue;
1697 
1698             isMouseOver(mousePoint, bcfRecord, features, fileIndex, sampleIndex, sumSamples, start, pixPerBase, vcfReaders[fileIndex]);
1699           }
1700         }
1701         else
1702         {
1703           int ypos = getYPostion(fileIndex);
1704           if(mousePoint.getY() > ypos &&
1705              mousePoint.getY() < ypos-LINE_HEIGHT)
1706             continue;
1707 
1708           isMouseOver(mousePoint, bcfRecord, features, fileIndex, -1, sumSamples, start, pixPerBase, vcfReaders[fileIndex]);
1709         }
1710 
1711 
1712       }
1713     }
1714     catch (IOException e)
1715     {
1716       logger4j.warn(chr+":"+sbeg+"-"+send+"\n"+e.getMessage());
1717       e.printStackTrace();
1718     }
1719   }
1720 
isMouseOver(final Point mousePoint, final VCFRecord record, final FeatureVector features, final int vcfFileIndex, final int sampleIndex, final int sumSamples, final int start, final float pixPerBase, final AbstractVCFReader vcfReader)1721   private void isMouseOver(final Point mousePoint,
1722                            final VCFRecord record,
1723                            final FeatureVector features,
1724                            final int vcfFileIndex,
1725                            final int sampleIndex,
1726                            final int sumSamples,
1727                            final int start, final float pixPerBase,
1728                            final AbstractVCFReader vcfReader)
1729   {
1730     int basePosition = record.getPos() + getSequenceOffset(record.getChrom());
1731     if( !showVariant(record, features, basePosition, vcfReader, sampleIndex, vcfFileIndex) )
1732       return;
1733 
1734     int pos[];
1735     if(!splitSamples)
1736       pos = getScreenPosition(basePosition, pixPerBase, start, vcfFileIndex);
1737     else
1738       pos = getScreenPosition(basePosition, pixPerBase, start, sampleIndex+sumSamples);
1739 
1740     if(mousePoint != null &&
1741        mousePoint.getY() < pos[1] &&
1742        mousePoint.getY() > pos[1]-LINE_HEIGHT &&
1743        mousePoint.getX() > pos[0]-3 &&
1744        mousePoint.getX() < pos[0]+3)
1745      {
1746        mouseVCF = record;
1747        mouseOverIndex = vcfFileIndex;
1748        mouseOverSampleIndex = sampleIndex;
1749      }
1750   }
1751 
drawScale(Graphics2D g2, int start, int end, float pixPerBase, int ypos)1752   private void drawScale(Graphics2D g2, int start, int end, float pixPerBase, int ypos)
1753   {
1754     g2.setColor(Color.black);
1755     g2.drawLine( 0, ypos-14,
1756                  (int)((end - start)*pixPerBase),   ypos-14);
1757     int interval = end-start;
1758 
1759     if(interval > 20000000)
1760       drawTicks(g2, start, end, pixPerBase, 10000000, ypos);
1761     else if(interval > 4000000)
1762       drawTicks(g2, start, end, pixPerBase, 2000000, ypos);
1763     else if(interval > 800000)
1764       drawTicks(g2, start, end, pixPerBase, 400000, ypos);
1765     else if(interval > 160000)
1766       drawTicks(g2, start, end, pixPerBase, 80000, ypos);
1767     else if(interval > 50000)
1768       drawTicks(g2, start, end, pixPerBase, 25000, ypos);
1769     else if(interval > 16000)
1770       drawTicks(g2, start, end, pixPerBase, 8000, ypos);
1771     else if(interval > 4000)
1772       drawTicks(g2, start, end, pixPerBase, 2000, ypos);
1773     else if(interval > 1000)
1774       drawTicks(g2, start, end, pixPerBase, 500, ypos);
1775     else
1776       drawTicks(g2, start, end, pixPerBase, 100, ypos);
1777   }
1778 
1779   /**
1780    *  Handle a mouse drag event on the drawing canvas.
1781    **/
handleCanvasMouseDrag(final MouseEvent event)1782   private void handleCanvasMouseDrag(final MouseEvent event)
1783   {
1784     if(event.getButton() == MouseEvent.BUTTON3)
1785       return;
1786 
1787     if(event.getClickCount() > 1)
1788     {
1789       getSelection().clear();
1790       repaint();
1791       return;
1792     }
1793 
1794     highlightRange(event,
1795         MouseEvent.BUTTON1_DOWN_MASK & MouseEvent.BUTTON2_DOWN_MASK);
1796   }
1797 
1798   /**
1799    *
1800    * @param event
1801    * @param onmask
1802    */
highlightRange(MouseEvent event, int onmask)1803   private void highlightRange(MouseEvent event, int onmask)
1804   {
1805     if(entryGroup == null)
1806       return;
1807     float pixPerBase = getPixPerBaseByWidth();
1808     int start = (int) ( ( (event.getPoint().getX())/pixPerBase) + getBaseAtStartOfView() );
1809 
1810     if(start < 1)
1811       start = 1;
1812     if(start > seqLength)
1813       start = seqLength;
1814 
1815     if (dragStart < 0 && (event.getModifiersEx() & onmask) == onmask)
1816       dragStart = start;
1817     else if((event.getModifiersEx() & onmask) != onmask)
1818       dragStart = -1;
1819 
1820     MarkerRange drag_range;
1821     try
1822     {
1823       if(dragStart < 0)
1824         drag_range = new MarkerRange (entryGroup.getSequenceEntry().getBases().getForwardStrand(), start, start);
1825       else
1826         drag_range = new MarkerRange (entryGroup.getSequenceEntry().getBases().getForwardStrand(), dragStart, start);
1827       getSelection().setMarkerRange(drag_range);
1828       repaint();
1829     }
1830     catch (OutOfRangeException e)
1831     {
1832       e.printStackTrace();
1833     }
1834   }
1835 
drawTicks(Graphics2D g2, int start, int end, float pixPerBase, int division, int ypos)1836   private void drawTicks(Graphics2D g2, int start, int end,
1837                          float pixPerBase, int division, int ypos)
1838   {
1839     int markStart = (Math.round(start/division)*division);
1840 
1841     if(markStart < 1)
1842       markStart = 1;
1843 
1844     int sm = markStart-(division/2);
1845     float x;
1846     if(sm > start)
1847     {
1848       x = (sm-start)*pixPerBase;
1849       g2.drawLine((int)x, ypos-14,(int)x, ypos-12);
1850     }
1851 
1852     for(int m=markStart; m<end; m+=division)
1853     {
1854       x = (m-start)*pixPerBase;
1855       g2.drawString(Integer.toString(m), x, ypos-1);
1856       g2.drawLine((int)x, ypos-14,(int)x, ypos-11);
1857 
1858       sm = m+(division/2);
1859 
1860       if(sm < end)
1861       {
1862         x = (sm-start)*pixPerBase;
1863         g2.drawLine((int)x, ypos-14,(int)x, ypos-12);
1864       }
1865 
1866       if(m == 1)
1867         m = 0;
1868     }
1869   }
1870 
getPixPerBaseByWidth()1871   protected float getPixPerBaseByWidth()
1872   {
1873     return (float)vcfPanel.getWidth() / (float)nbasesInView;
1874   }
1875 
getBasesInView()1876   protected int getBasesInView()
1877   {
1878     return nbasesInView;
1879   }
1880 
1881 
getEntryGroup()1882   protected EntryGroup getEntryGroup()
1883   {
1884     return entryGroup;
1885   }
1886 
getChr()1887   protected String getChr()
1888   {
1889     return chr;
1890   }
1891 
isConcatenate()1892   protected boolean isConcatenate()
1893   {
1894     return concatSequences;
1895   }
1896 
1897   /**
1898    * @return the combo
1899    */
getCombo()1900   public SequenceComboBox getCombo()
1901   {
1902     return combo;
1903   }
1904 
1905   /**
1906    * @return the vcfReaders
1907    */
getVcfReaders()1908   protected AbstractVCFReader[] getVcfReaders()
1909   {
1910     return vcfReaders;
1911   }
1912 
1913 
getVcfContainer()1914   private Container getVcfContainer()
1915   {
1916     try
1917     {
1918       Frame fs[] = JFrame.getFrames();
1919       for(Frame f: fs)
1920       {
1921         if( f instanceof JFrame &&
1922            ((JFrame)f) instanceof EntryEdit ||
1923            ((JFrame)f) instanceof MultiComparator)
1924           return ((JFrame)f).getContentPane();
1925       }
1926     }
1927     catch(Exception e){}
1928     return VCFview.this;
1929   }
1930 
1931   /**
1932    * Popup menu listener
1933    */
1934    class PopupListener extends MouseAdapter
1935    {
1936      JMenuItem showDetails;
1937      JMenuItem annotate;
1938 
mouseClicked(MouseEvent e)1939      public void mouseClicked(MouseEvent e)
1940      {
1941        if(e.isPopupTrigger() ||
1942           e.getButton() == MouseEvent.BUTTON3)
1943          return;
1944 
1945        if(e.getClickCount() > 1)
1946        {
1947          getSelection().clear();
1948          repaint();
1949        }
1950      }
1951 
mousePressed(MouseEvent e)1952      public void mousePressed(MouseEvent e)
1953      {
1954        maybeShowPopup(e);
1955      }
1956 
mouseReleased(MouseEvent e)1957      public void mouseReleased(MouseEvent e)
1958      {
1959        dragStart = -1;
1960        maybeShowPopup(e);
1961      }
1962 
maybeShowPopup(MouseEvent e)1963      private void maybeShowPopup(MouseEvent e)
1964      {
1965        if(e.isPopupTrigger())
1966        {
1967          if(showDetails != null)
1968          {
1969            popup.remove(showDetails);
1970            popup.remove(annotate);
1971          }
1972 
1973          mouseVCF = null;
1974          findVariantAtPoint(e.getPoint());
1975          final VCFRecord thisMouseVCF = mouseVCF;
1976          final int thisMouseOverIndex = mouseOverIndex;
1977          if( thisMouseVCF != null )
1978          {
1979            showDetails = new JMenuItem("Show details of : "+
1980                thisMouseVCF.getChrom()+":"+thisMouseVCF.getPos()+" "+thisMouseVCF.getID());
1981            showDetails.addActionListener(new ActionListener()
1982            {
1983              public void actionPerformed(ActionEvent e)
1984              {
1985                FileViewer viewDetail = new FileViewer(
1986                    thisMouseVCF.getChrom()+":"+thisMouseVCF.getPos()+" "+thisMouseVCF.getID(), true, false, true);
1987 
1988                viewDetail.appendString(vcfReaders[mouseOverIndex].getHeader()+"\n", Level.INFO);
1989 
1990                viewDetail.appendString("Seq   : "+thisMouseVCF.getChrom()+"\n", Level.DEBUG);
1991                viewDetail.appendString("Pos   : "+thisMouseVCF.getPos()+"\n", Level.DEBUG);
1992                viewDetail.appendString("ID    : "+thisMouseVCF.getID()+"\n", Level.DEBUG);
1993                viewDetail.appendString("Ref   : "+thisMouseVCF.getRef()+"\n", Level.DEBUG);
1994                viewDetail.appendString("Alt   : "+thisMouseVCF.getAlt().toString()+"\n", Level.DEBUG);
1995                viewDetail.appendString("Qual  : "+thisMouseVCF.getQuality()+"\n", Level.DEBUG);
1996                viewDetail.appendString("Filter: "+thisMouseVCF.getFilter()+"\n", Level.DEBUG);
1997                viewDetail.appendString("Info  : "+thisMouseVCF.getInfo()+"\n", Level.DEBUG);
1998 
1999                if(thisMouseVCF.getFormat() != null)
2000                {
2001                  viewDetail.appendString("\nGenotype information:\n", Level.INFO);
2002                  viewDetail.appendString("Format: "+thisMouseVCF.getFormat()+"\n", Level.DEBUG);
2003                  viewDetail.appendString(thisMouseVCF.getSampleDataString()+"\n", Level.DEBUG);
2004                }
2005 
2006                viewDetail.getTextPane().setCaretPosition(0);
2007              }
2008            });
2009            popup.add(showDetails);
2010 
2011            annotate = new JMenuItem("Manual PASS / FAIL");
2012            annotate.addActionListener(new ActionListener()
2013            {
2014              public void actionPerformed(ActionEvent e)
2015              {
2016                new ManualAnnotation(thisMouseVCF, thisMouseOverIndex);
2017              }
2018            });
2019           popup.add(annotate);
2020          }
2021          popup.show(e.getComponent(),
2022              e.getX(), e.getY());
2023        }
2024      }
2025    }
2026 
setDisplay()2027    private void setDisplay()
2028    {
2029      Dimension d = new Dimension();
2030 
2031      if(splitSamples)
2032      {
2033        int count = 0;
2034        for(int i=0; i<vcfReaders.length; i++)
2035          count += vcfReaders[i].getNumberOfSamples();
2036        d.setSize(nbasesInView*getPixPerBaseByWidth(), (count+1)*(LINE_HEIGHT+5));
2037      }
2038      else
2039        d.setSize(nbasesInView*getPixPerBaseByWidth(), (vcfReaders.length+1)*(LINE_HEIGHT+5));
2040      setPreferredSize(d);
2041    }
2042 
displayAdjustmentValueChanged(DisplayAdjustmentEvent event)2043    public void displayAdjustmentValueChanged(DisplayAdjustmentEvent event)
2044    {
2045      nbasesInView = feature_display.getMaxVisibleBases();
2046      setDisplay();
2047      repaint();
2048    }
2049 
selectionChanged(SelectionChangeEvent event)2050    public void selectionChanged(SelectionChangeEvent event)
2051    {
2052      repaint();
2053    }
2054 
2055    /**
2056     * Manual annotation of a variant record.
2057     */
2058    class ManualAnnotation extends JFrame
2059    {
2060      private static final long serialVersionUID = 1L;
2061 
ManualAnnotation(final VCFRecord thisMouseVCF, final int thisMouseOverIndex)2062     ManualAnnotation(final VCFRecord thisMouseVCF, final int thisMouseOverIndex)
2063      {
2064        super("Manual PASS / FAIL");
2065        final JPanel pane = (JPanel) getContentPane();
2066        pane.setLayout(new BorderLayout());
2067        final JPanel panel = new JPanel(new GridBagLayout());
2068        final JScrollPane jsp = new JScrollPane(panel);
2069        jsp.setPreferredSize(new Dimension(350, 180));
2070        pane.add(jsp, BorderLayout.NORTH);
2071 
2072        final GridBagConstraints c = new GridBagConstraints();
2073        c.gridx = 0;
2074        c.gridy = 0;
2075        c.gridwidth = 3;
2076        c.anchor = GridBagConstraints.NORTHWEST;
2077        panel.add(new JLabel("Seq   : "+thisMouseVCF.getChrom()), c);
2078        c.gridy++;
2079        panel.add(new JLabel("Pos   : "+thisMouseVCF.getPos()), c);
2080        c.gridy++;
2081        panel.add(new JLabel("ID    : "+thisMouseVCF.getPos()), c);
2082        c.gridy++;
2083        panel.add(new JLabel("Ref   : "+thisMouseVCF.getRef()), c);
2084        c.gridy++;
2085        panel.add(new JLabel("Alt   : "+thisMouseVCF.getAlt().toString()), c);
2086        c.gridy++;
2087        panel.add(new JLabel("Qual  : "+thisMouseVCF.getQuality()), c);
2088        c.gridy++;
2089        panel.add(new JLabel("Filter: "+thisMouseVCF.getFilter()), c);
2090        c.gridy++;
2091        panel.add(new JLabel("Info  : "+thisMouseVCF.getInfo()), c);
2092 
2093        final JRadioButton passB = new JRadioButton("PASS");
2094        final JRadioButton failB = new JRadioButton("FAIL");
2095        final JRadioButton noManualB = new JRadioButton("NO MANUAL FILTER", true);
2096 
2097        final ButtonGroup group = new ButtonGroup();
2098        group.add(passB);
2099        group.add(failB);
2100        group.add(noManualB);
2101 
2102        int res = VCFFilter.checkManualHash(manualHash, thisMouseVCF, thisMouseOverIndex, false);
2103        switch(res)
2104        {
2105          case 1:  passB.setSelected(true);
2106                   break;
2107          case 2:  failB.setSelected(true);
2108                   break;
2109          default: noManualB.setSelected(true);
2110                   break;
2111        }
2112 
2113        c.gridy++;
2114        panel.add(Box.createVerticalStrut(10), c);
2115 
2116        c.gridwidth = 1;
2117        c.gridy++;
2118        panel.add(passB, c);
2119        c.gridx++;
2120        panel.add(failB, c);
2121        c.gridx++;
2122        panel.add(noManualB, c);
2123 
2124        final JButton apply = new JButton("Apply");
2125        apply.addActionListener(new ActionListener()
2126        {
2127          public void actionPerformed(ActionEvent arg0)
2128          {
2129            setVisible(false);
2130            if(passB.isSelected())
2131              manualHash.put(thisMouseVCF.getPos()+":"+thisMouseVCF.getChrom()+":"+thisMouseOverIndex, true);
2132            else if(failB.isSelected())
2133              manualHash.put(thisMouseVCF.getPos()+":"+thisMouseVCF.getChrom()+":"+thisMouseOverIndex, false);
2134            else
2135              manualHash.remove(thisMouseVCF.getPos()+":"+thisMouseVCF.getChrom()+":"+thisMouseOverIndex);
2136            VCFview.this.repaint();
2137            ManualAnnotation.this.dispose();
2138          }
2139        });
2140        pane.add(apply, BorderLayout.SOUTH);
2141        pack();
2142        Utilities.centreFrame(this);
2143        setVisible(true);
2144      }
2145    }
2146 
main(String args[])2147   public static void main(String args[])
2148   {
2149     List<String> vcfFileList = new Vector<String>();
2150     String reference = null;
2151     if(args.length == 0)
2152     {
2153       System.setProperty("default_directory", System.getProperty("user.dir"));
2154       FileSelectionDialog fileSelection = new FileSelectionDialog(
2155           null, true, "VCFview", "VCF");
2156       vcfFileList = fileSelection.getFiles(VCFFILE_SUFFIX);
2157       reference = fileSelection.getReferenceFile();
2158       if(reference.equals(""))
2159         reference = null;
2160 
2161       if(vcfFileList == null || vcfFileList.size() < 1)
2162         System.exit(0);
2163     }
2164     else if(!args[0].startsWith("-"))
2165     {
2166       for(int i=0; i< args.length; i++)
2167         vcfFileList.add(args[i]);
2168     }
2169 
2170     int nbasesInView = 5000000;
2171 
2172     for(int i=0;i<args.length; i++)
2173     {
2174       if(args[i].equals("-f"))
2175       {
2176         while(i < args.length-1 && !args[++i].startsWith("-"))
2177         {
2178           String filename = args[i];
2179           if(FileSelectionDialog.isListOfFiles(filename))
2180             vcfFileList.addAll(FileSelectionDialog.getListOfFiles(filename));
2181           else
2182             vcfFileList.add(filename);
2183         }
2184         --i;
2185       }
2186       else if(args[i].equals("-r"))
2187         reference = args[++i];
2188       else if(args[i].equals("-v"))
2189         nbasesInView = Integer.parseInt(args[++i]);
2190       else if(args[i].startsWith("-h"))
2191       {
2192         System.out.println("-h\t show help");
2193 
2194         System.out.println("-f\t VCF file to display");
2195         System.out.println("-r\t reference file (optional)");
2196         System.out.println("-v\t number of bases to display in the view (optional)");
2197         //System.out.println("-t\t chr:start-end - this writes out the given region");
2198 
2199         System.exit(0);
2200       }
2201     }
2202 
2203     JFrame f = new JFrame();
2204     new VCFview(f, (JPanel) f.getContentPane(), vcfFileList,
2205           nbasesInView, 100000000, null, reference, null, null);
2206 
2207     f.pack();
2208     f.setVisible(true);
2209   }
2210 }