1 /***************************************************************
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 *
17 *  @author: Copyright (C) Tim Carver
18 *
19 ***************************************************************/
20 
21 package org.emboss.jemboss.editor;
22 
23 import java.awt.*;
24 import java.awt.print.PageFormat;
25 import java.awt.print.Printable;
26 import java.awt.print.PrinterException;
27 import java.io.File;
28 import java.util.*;
29 
30 import javax.swing.*;
31 
32 import org.emboss.jemboss.gui.form.MultiLineToolTipUI;
33 
34 /**
35 *
36 * This class can be used to get a grapical representation
37 * of a collection of sequences.
38 *
39 */
40 public class GraphicSequenceCollection extends JPanel
41                                        implements Printable, Scrollable
42 {
43 
44   /** Vector of sequences removed from panel */
45   private Vector removedSeqs = new Vector();
46   /** Vector containing Sequence objects     */
47   protected Vector seqs;
48   /** Vector containing graphical sequences  */
49   protected Vector graphicSequence;
50   /** Vector containing graphical names of sequences */
51   protected Vector graphicName;
52   /** Colour scheme to use                   */
53   protected Hashtable colorScheme;
54   /** Consensus plot  */
55   private PlotConsensus pc = null;
56   private int hgt;
57   private int len;
58   /** longest sequence length */
59   protected int MAXSEQLENGTH = 0;
60   /** number of residues on each line for print */
61   private int numResiduePerLine = 0;
62   /** panel for sequence numbers */
63   protected SequenceJPanel numberDraw;
64   /** sequence scrollpane */
65   protected JScrollPane jspSequence;
66   /** sequence name panel */
67   private JPanel seqNamePanel;
68   /** container for sequences */
69   protected Box seqBox;
70   /** container for sequence names */
71   protected Box seqNameBox;
72   /** container for consensus plot */
73   private Box plotconsSeqBox = null;
74   /** draw the sequence */
75   protected boolean drawSequence;
76   /** draw black square around residues */
77   protected boolean drawBlackBox;
78   /** colour residues   */
79   protected boolean drawColorBox;
80   /** draw sequence position number */
81   protected boolean drawNumber;
82   /** draw as per prettplot */
83   //private boolean prettPlot = false;
84   /** gap between sequences and consensus plot */
85   private int plotConStrut = 20;
86   /** pretty plot values */
87   private PrettyPlotJFrame prettyPlot;
88   /** scoring matrix */
89   private Matrix mat;
90 
91   /**
92   *
93   * @param seqs		vector of sequences
94   * @param colorScheme	sequence colour scheme
95   * @param jspSequence 	sequence scrollpane
96   * @param drawSequence true to draw the sequence
97   * @param drawBlackBox true to draw black square around residues
98   * @param drawColorBox true to colour residues
99   * @param drawNumber   true to draw sequence position number
100   * @param statusField	status field in the editor
101   *
102   */
GraphicSequenceCollection(Vector seqs, Hashtable colorScheme, JScrollPane jspSequence, boolean drawSequence, boolean drawBlackBox, boolean drawColorBox, boolean drawNumber, JTextField statusField)103   public GraphicSequenceCollection(Vector seqs, Hashtable colorScheme,
104                          JScrollPane jspSequence,
105                          boolean drawSequence, boolean drawBlackBox,
106                          boolean drawColorBox, boolean drawNumber,
107                          JTextField statusField)
108   {
109     super(new BorderLayout());
110     this.seqs = seqs;
111     this.colorScheme = colorScheme;
112     this.jspSequence = jspSequence;
113     this.drawSequence = drawSequence;
114     this.drawBlackBox = drawBlackBox;
115     this.drawColorBox = drawColorBox;
116     this.drawNumber = drawNumber;
117 
118     jspSequence.getViewport().setBackground(Color.white);
119     setBackground(Color.white);
120     MultiLineToolTipUI.initialize();
121     graphicSequence = new Vector();
122     graphicName = new Vector();
123 
124 // find maximum seq length
125     setMaxSeqLength();
126 
127     Box centerBox = new Box(BoxLayout.Y_AXIS);
128     seqBox = new Box(BoxLayout.Y_AXIS);
129     centerBox.add(seqBox);
130 
131     Box westBox = new Box(BoxLayout.Y_AXIS);
132     seqNameBox = new Box(BoxLayout.Y_AXIS);
133     westBox.add(seqNameBox);
134     seqNamePanel = new JPanel(new BorderLayout());
135     seqNamePanel.add(westBox,BorderLayout.CENTER);
136     seqNamePanel.setBackground(Color.white);
137     jspSequence.setRowHeaderView(seqNamePanel);
138 
139 // draw residue/base numbering
140     if(drawNumber)
141       drawNumber();
142 
143 // draw names and sequences
144     Enumeration enumer = seqs.elements();
145     while(enumer.hasMoreElements())
146       addSequence((Sequence)enumer.nextElement(),false,0,0);
147 
148     westBox.add(Box.createVerticalGlue());
149     centerBox.add(Box.createVerticalGlue());
150     plotconsSeqBox = new Box(BoxLayout.Y_AXIS);
151     centerBox.add(plotconsSeqBox);
152     add(centerBox,BorderLayout.CENTER);
153 
154     int xfill = getNameWidth();
155     seqNamePanel.setPreferredSize(new Dimension(xfill,2000));
156   }
157 
158 
159   /**
160   *
161   * @param seqs         vector of sequences
162   * @param jspSequence  sequence scrollpane
163   * @param drawSequence true to draw the sequence
164   * @param drawBlackBox true to draw black square around residues
165   * @param drawColorBox true to colour residues
166   * @param drawNumber   true to draw sequence position number
167   * @param statusField  status field in the editor
168   *
169   */
GraphicSequenceCollection(Vector seqs, JScrollPane jspSequence, boolean drawSequence, boolean drawBlackBox, boolean drawColorBox, boolean drawNumber, JTextField statusField)170   public GraphicSequenceCollection(Vector seqs, JScrollPane jspSequence,
171                          boolean drawSequence, boolean drawBlackBox,
172                          boolean drawColorBox, boolean drawNumber,
173                          JTextField statusField)
174   {
175     this(seqs,null,jspSequence,drawSequence,
176          drawBlackBox,drawColorBox,drawNumber,statusField);
177   }
178 
179   /**
180   *
181   * Get the vector of Sequences
182   * @return 	vector of Sequences
183   *
184   */
getSequenceCollection()185   protected Vector getSequenceCollection()
186   {
187     return seqs;
188   }
189 
190 
191   /**
192   *
193   * Get the consensus sequence
194   * @return     consensus sequence
195   *
196   */
getConsensusSequence()197   protected Sequence getConsensusSequence()
198   {
199     Enumeration enumer = seqs.elements();
200     while(enumer.hasMoreElements())
201     {
202       Sequence s = (Sequence)enumer.nextElement();
203       String name = s.getName();
204       if(name.equals(Consensus.DEFAULT_SEQUENCE_NAME))
205         return s;
206     }
207     return null;
208   }
209 
210 
211   /**
212   *
213   * Get the number of sequences
214   * @return     vector of Sequences
215   *
216   */
getNumberSequences()217   protected int getNumberSequences()
218   {
219     return seqs.size();
220   }
221 
222 
223   /**
224   *
225   * Get the position of the sequence JViewPort
226   * @return 	position of the sequence JViewPort
227   *
228   */
getViewPosition()229   protected Point getViewPosition()
230   {
231     return jspSequence.getViewport().getViewPosition();
232   }
233 
234   /**
235   *
236   * Get the Rectangle being displayed by the sequence JViewPort
237   * @return     rectangle being displayed by the sequence JViewPort
238   *
239   */
getViewRect()240   protected Rectangle getViewRect()
241   {
242     Rectangle r = jspSequence.getViewport().getViewRect();
243 
244 // adjustment for the sequence names on the west
245 //  r.x = r.x - westBox.getWidth();
246 //  if(r.x < 0)
247 //    r.x = 0;
248     return r;
249   }
250 
251   /**
252   *
253   * Calculate and display the consensus plot
254   * @param File matrix - scoring matrix
255   * @param int wsize window size to average scores over
256   *
257   */
showConsensusPlot(File matrix, int wsize)258   protected void showConsensusPlot(File matrix, int wsize)
259   {
260     deleteConsensusPlot();
261     SequenceJPanel sj = (SequenceJPanel)graphicSequence.get(0);
262     int interval = sj.getSequenceResidueWidth();
263 
264     pc =  new PlotConsensus(matrix,seqs,wsize,interval,this);
265     pc.setBackground(Color.white);
266 
267     Box XBox = new Box(BoxLayout.X_AXIS);
268     XBox.add(pc);
269     XBox.add(Box.createHorizontalGlue());
270     plotconsSeqBox.add(Box.createVerticalStrut(plotConStrut));
271     plotconsSeqBox.add(XBox);
272     plotconsSeqBox.add(Box.createVerticalGlue());
273     Dimension dpane = getPanelSize();
274     setMinimumSize(dpane);
275     setPreferredSize(dpane);
276     setJScrollPaneViewportView();
277   }
278 
279   /**
280   *
281   * Calculate and display the consensus plot
282   * @param File matrix - scoring matrix
283   * @param int wsize window size to average scores over
284   *
285   */
showConsensusPlot(Matrix mat, int wsize)286   protected void showConsensusPlot(Matrix mat, int wsize)
287   {
288     deleteConsensusPlot();
289     SequenceJPanel sj = (SequenceJPanel)graphicSequence.get(0);
290     int interval = sj.getSequenceResidueWidth();
291 
292     Vector seqs_ = new Vector(seqs);
293     Sequence seq = (Sequence)seqs.lastElement();
294     if (seq.getName().equals(Consensus.DEFAULT_SEQUENCE_NAME))
295        seqs_.removeElementAt(seqs.size()-1);
296     pc =  new PlotConsensus(mat,seqs_,wsize,interval,this);
297     pc.setBackground(Color.white);
298 
299     Box XBox = new Box(BoxLayout.X_AXIS);
300     XBox.add(pc);
301     XBox.add(Box.createHorizontalGlue());
302     plotconsSeqBox.add(Box.createVerticalStrut(20));
303     plotconsSeqBox.add(XBox);
304     plotconsSeqBox.add(Box.createVerticalGlue());
305     Dimension dpane = getPanelSize();
306     setMinimumSize(dpane);
307     setPreferredSize(dpane);
308     setJScrollPaneViewportView();
309   }
310 
311   /**
312   *
313   * Remove the consensus plot from the sequence editor
314   *
315   */
deleteConsensusPlot()316   protected void deleteConsensusPlot()
317   {
318     plotconsSeqBox.removeAll();
319   }
320 
321   /**
322   *
323   * Set the longest sequence length
324   * @param max 	longest sequence length
325   *
326   */
setMaxSequenceLength(int max)327   protected void setMaxSequenceLength(int max)
328   {
329     if(max > MAXSEQLENGTH)
330       MAXSEQLENGTH = max;
331   }
332 
333   /**
334   *
335   * Calculate the longest sequence length
336   *
337   */
setMaxSeqLength()338   protected void setMaxSeqLength()
339   {
340     MAXSEQLENGTH = 0;
341     Enumeration enumer = seqs.elements();
342     while(enumer.hasMoreElements())
343     {
344       Sequence seq = (Sequence)(enumer.nextElement());
345       if(seq.getSequence().length()>MAXSEQLENGTH)
346         MAXSEQLENGTH = seq.getSequence().length();
347     }
348   }
349 
350   /**
351   *
352   * Get the longest sequence length
353   * @return 	longest sequence length
354   *
355   */
getMaxSeqLength()356   public int getMaxSeqLength()
357   {
358     return MAXSEQLENGTH;
359   }
360 
361   /**
362   *
363   * Lock/group the sequences
364   * @param 	true to lock sequences
365   *
366   */
setSequenceLock(boolean llock)367   protected void setSequenceLock(boolean llock)
368   {
369     Enumeration enumer = graphicName.elements();
370     if(!llock)
371     {
372       while(enumer.hasMoreElements())
373         ((SequenceNameJButton)enumer.nextElement()).setSelected(false);
374       enumer = graphicSequence.elements();
375       while(enumer.hasMoreElements())
376         ((SequenceJPanel)enumer.nextElement()).detachAll();
377 
378       return;
379     }
380 
381     int i = 0;
382     Vector selected = new Vector();
383     while(enumer.hasMoreElements())
384     {
385       SequenceNameJButton sbutt = (SequenceNameJButton)enumer.nextElement();
386       if(sbutt.isSelected())
387         selected.add((SequenceJPanel)graphicSequence.get(i));
388       i++;
389     }
390 
391     // group sequences
392     for(i=0;i<selected.size();i++)
393     {
394       SequenceJPanel si = (SequenceJPanel)selected.get(i);
395       for(int j=0;j<selected.size();j++)
396         if(i!=j)
397           ((SequenceJPanel)selected.get(j)).attach(si);
398     }
399   }
400 
401   /**
402   *
403   * Set the size of the sequence number panel
404   *
405   */
setNumberSize()406   protected void setNumberSize()
407   {
408     Dimension actual = numberDraw.getMaximumSize();
409     int slen = numberDraw.getResidueWidth()*(int)(MAXSEQLENGTH*1.5);
410     numberDraw.setMaximumSize(new Dimension(slen,(int)actual.getHeight()));
411   }
412 
413 
setMatrix(Matrix mat)414   protected void setMatrix(Matrix mat)
415   {
416     this.mat = mat;
417   }
418 
419   /**
420   *
421   * Determine the colour of a residue at a given position. If
422   * the residues at that position in all the sequences are identical
423   * then return red otherwise return black.
424   * @param s		residue at position pos
425   * @param pos		residue position
426   * @param seqName	sequence name
427   * @return 	red if all identical otherwise return black
428   *
429   */
getColor(String s, int pos, String seqName)430   protected Color getColor(String s, int pos, String seqName)
431   {
432     if(s.equals("-") || s.equals("."))
433       return Color.black;
434 
435     int identical = 1;
436     int nseqs = 0;
437     Enumeration enumer = seqs.elements();
438     while(enumer.hasMoreElements())
439     {
440       nseqs++;
441       Sequence seq = (Sequence)(enumer.nextElement());
442       if(!seqName.equals(seq.getName()))
443       {
444         SequenceJPanel seqPanel = (SequenceJPanel)graphicSequence.get(nseqs);
445         if(pos < seq.getLength() && seqPanel.isPrettyPlot())
446           if(seq.getResidue(pos).equalsIgnoreCase(s))
447             identical++;
448       }
449     }
450 
451     if(identical >= prettyPlot.getMinimumIdentity(nseqs))
452       return prettyPlot.getIDColour();
453 
454     else if(mat != null)
455     {
456       double threshold = prettyPlot.getMatchThreshold();
457       int m1 = mat.getMatrixIndex(s);
458       int matrix[][] = mat.getMatrix();
459       float matching = 0.f;
460       nseqs = 0;
461 
462       enumer = seqs.elements();
463       while(enumer.hasMoreElements())
464       {
465         nseqs++;
466         Sequence seq = (Sequence)(enumer.nextElement());
467         SequenceJPanel seqPanel = (SequenceJPanel)graphicSequence.get(nseqs);
468 //      if(!seqName.equals(seq.getName()))
469 //      {
470           if(pos < seq.getLength() && seqPanel.isPrettyPlot())
471           {
472             int m2 = mat.getMatrixIndex(seq.getResidue(pos));
473             if(m1 >= 0 && m2 >= 0 && matrix[m1][m2]>0)
474               matching += seq.getWeight();
475           }
476 //      }
477       }
478       if(matching >= threshold)
479         return prettyPlot.getMatchColour();
480     }
481     return Color.black;
482   }
483 
484 
485   /**
486   *
487   * Determine the colour of a residue background
488   *
489   */
getPrettyBackground(Color textColour)490   protected Color getPrettyBackground(Color textColour)
491   {
492     if(textColour.equals(prettyPlot.getIDColour()))
493       return prettyPlot.getIDBackgroundColour();
494     else if(textColour.equals(prettyPlot.getMatchColour()))
495       return prettyPlot.getMatchBackgroundColour();
496     else
497       return null;
498   }
499 
500 
501   /**
502   *
503   * Determine if the identities are to be boxed
504   * @return 	true if to draw boxes
505   *
506   */
isPrettyBox()507   protected boolean isPrettyBox()
508   {
509     return prettyPlot.isPrettyBox();
510   }
511 
512 
513   /**
514   *
515   *
516   *
517   */
testUpAndDown(int pos, Sequence seq)518   protected int testUpAndDown(int pos, Sequence seq)
519   {
520     int seqIndex = seqs.indexOf(seq);
521 
522     int testUp = -1;
523     if(seqIndex == 0)
524       testUp = 1;
525     else
526     {
527       Sequence seqUp = (Sequence)seqs.get(seqIndex-1);
528       String res = seqUp.getSequence().substring(pos,pos+1);
529       Color col = getColor(res,pos,seqUp.getName());
530       if(col.equals(Color.black))
531         testUp = 1;
532     }
533 
534     int testDown = -1;
535     if(seqIndex+1 == seqs.size())
536       testDown= 1;
537     else
538     {
539       Sequence seqDown = (Sequence)seqs.get(seqIndex+1);
540       SequenceJPanel seqPanelDown = (SequenceJPanel)graphicSequence.get(seqIndex+2);
541       String res = seqDown.getSequence().substring(pos,pos+1);
542       Color col = getColor(res,pos,seqDown.getName());
543       if(col.equals(Color.black) || !seqPanelDown.isPrettyPlot())
544         testDown = 1;
545     }
546 
547     if(testUp > -1 && testDown > -1)
548       return 3;
549     else if(testDown > -1)
550       return 2;
551     else if(testUp > -1)
552       return 1;
553     return -1;
554   }
555 
556 
557   /**
558   *
559   * Remove a sequence from the editor display
560   * @param name		name of sequence to remove
561   *
562   */
removeSequence(String name)563   private Sequence removeSequence(String name)
564   {
565     boolean removed = false;
566     int index = 0;
567     Enumeration enumer = seqs.elements();
568     Sequence seq = null;
569 
570     while(enumer.hasMoreElements())
571     {
572       seq = (Sequence)enumer.nextElement();
573       if(seq.getName().equals(name))
574       {
575         removedSeqs.add(seq);
576         removed = true;
577         seqs.remove(seq);
578         break;
579       }
580       index++;
581     }
582 
583     if(!removed)
584       return null;
585     if(drawNumber)
586       index++;
587 
588     seqBox.remove(index);
589     seqNameBox.remove(index);
590     graphicName.removeElementAt(index);
591     graphicSequence.removeElementAt(index);
592     return seq;
593   }
594 
595   /**
596   *
597   *  Delete a sequence from the sequence collection display
598   *  and resize the sequence panel display
599   *  @param name	name of sequence to remove
600   *
601   */
deleteSequence(String name)602   protected void deleteSequence(String name)
603   {
604     removeSequence(name);
605     setMaxSeqLength();
606     numberDraw.setSequenceLength(MAXSEQLENGTH);
607     Dimension dpane = getPanelSize();
608     setMinimumSize(dpane);
609     setPreferredSize(dpane);
610     numberDraw.setMaximumSize(numberDraw.getPreferredSize());
611     numberDraw.setMinimumSize(numberDraw.getPreferredSize());
612     setJScrollPaneViewportView();
613   }
614 
615   /**
616   *
617   * Move a sequence to a new position
618   * @param name		name of sequence to remove
619   * @param i		new position in the sequence editor
620   *
621   */
moveSequence(String name, int i)622   protected void moveSequence(String name, int i)
623   {
624     Sequence seq = removeSequence(name);
625     addSequence(seq,true,0,0,i);
626   }
627 
628   /**
629   *
630   * Sorts the sequences and displays them by their id's
631   *
632   */
idSort()633   protected void idSort()
634   {
635     int nseqs = 0;
636 
637 // get no. of sequences excl. consensus
638     Enumeration enumer = seqs.elements();
639     while(enumer.hasMoreElements())
640     {
641       String name = ((Sequence)enumer.nextElement()).getName();
642       if(!name.equals(Consensus.DEFAULT_SEQUENCE_NAME))
643         nseqs++;
644     }
645 
646     String seqName[] = new String[nseqs];
647     int i = 0;
648     enumer = seqs.elements();
649     while(enumer.hasMoreElements())
650     {
651       String name = ((Sequence)enumer.nextElement()).getName();
652       if(!name.equals(Consensus.DEFAULT_SEQUENCE_NAME))
653       {
654         seqName[i] = new String(name);
655         i++;
656       }
657     }
658 
659     Arrays.sort(seqName);
660     for(i=0;i<nseqs;i++)
661       moveSequence(seqName[i],i);
662   }
663 
664   /**
665   *
666   *  Add a sequence at a particular index to the sequence
667   *  collection display and to the collection of sequences
668   *  (seqs) with a specified y-padding.
669   *  @param seq			sequence to add to the editor display
670   *  @param addToSequences	true to add seq to the vector of sequences
671   *  @param ypad		sequence panel height padding
672   *  @param fontSize		font size
673   *  @param index		sequence index
674   *
675   */
addSequence(Sequence seq, boolean addToSequences, int ypad, int fontSize, int index)676   protected void addSequence(Sequence seq, boolean addToSequences,
677                              int ypad, int fontSize, int index)
678   {
679     if(addToSequences)
680       seqs.add(index,seq);
681     if(drawNumber)
682       index++;
683 
684     SequenceJPanel gs = new SequenceJPanel(seq,this,
685                            drawSequence,drawBlackBox,drawColorBox,
686                            colorScheme,ypad);
687     graphicSequence.add(index,gs);
688 
689     Box XBox = new Box(BoxLayout.X_AXIS);
690     XBox.add(gs);
691     XBox.add(Box.createHorizontalGlue());
692     seqBox.add(XBox,index);
693     gs.setToolTipText("");   //enable tooltip display
694 
695     SequenceNameJButton snj = new SequenceNameJButton(seq,ypad);
696     graphicName.add(index,snj);
697     XBox = new Box(BoxLayout.X_AXIS);
698     XBox.add(Box.createHorizontalGlue());
699     XBox.add(snj);
700     seqNameBox.add(XBox,index);
701 
702     if(seq.getLength()>MAXSEQLENGTH)
703       MAXSEQLENGTH = seq.getLength();
704 
705     Dimension actual = gs.getMaximumSize();
706     int slen = gs.getResidueWidth()*(int)(MAXSEQLENGTH*1.2);
707     gs.setMaximumSize(new Dimension(slen,(int)actual.getHeight()));
708   }
709 
710 
711 
712   /**
713   *
714   *  Add a sequence to the sequence collection display and
715   *  to the collection of sequences (seqs) with a specified
716   *  y-padding.
717   *  @param seq                 sequence to add to the editor display
718   *  @param addToSequences      true to add seq to the vector of sequences
719   *  @param ypad                sequence panel height padding
720   *  @param fontSize            font size
721   *
722   */
addSequence(Sequence seq, boolean addToSequences, int ypad, int fontSize)723   protected void addSequence(Sequence seq, boolean addToSequences,
724                              int ypad, int fontSize)
725   {
726     if(addToSequences)
727       seqs.add(seq);
728     SequenceJPanel gs = new SequenceJPanel(seq,this,
729                            drawSequence,drawBlackBox,drawColorBox,
730                            colorScheme,fontSize,ypad);
731     graphicSequence.add(gs);
732 
733     Box XBox = new Box(BoxLayout.X_AXIS);
734     XBox.add(gs);
735     XBox.add(Box.createHorizontalGlue());
736     seqBox.add(XBox);
737     gs.setToolTipText("");   //enable tooltip display
738 
739     SequenceNameJButton snj = new SequenceNameJButton(seq,ypad);
740     graphicName.add(snj);
741     XBox = new Box(BoxLayout.X_AXIS);
742     XBox.add(Box.createHorizontalGlue());
743     XBox.add(snj);
744     seqNameBox.add(XBox);
745 
746     if(seq.getLength()>MAXSEQLENGTH)
747       MAXSEQLENGTH = seq.getLength();
748 
749     Dimension actual = gs.getMaximumSize();
750     int slen = gs.getResidueWidth()*(int)(MAXSEQLENGTH*1.2);
751     gs.setMaximumSize(new Dimension(slen,(int)actual.getHeight()));
752   }
753 
754 
755   /**
756   *
757   * Get the sequence view size
758   * @return 	sequence view dimension
759   *
760   */
getViewSize()761   public Dimension getViewSize()
762   {
763     hgt = 1;
764     len = 0;
765     Enumeration enumer = graphicSequence.elements();
766     while(enumer.hasMoreElements())
767     {
768       SequenceJPanel gs = (SequenceJPanel)enumer.nextElement();
769       hgt = hgt+gs.getSequenceHeight();
770       if(len<gs.getSequenceWidth())
771         len = gs.getSequenceWidth();
772     }
773 
774     if(pc !=null)
775     {
776       Dimension dplot = pc.getPreferredSize();
777       hgt = hgt + (int)dplot.getHeight() + plotConStrut;
778     }
779     return new Dimension(len,hgt);
780   }
781 
782 
getName(int i)783   public String getName(int i)
784   {
785     return ((Sequence)seqs.get(i)).getName();
786   }
787 
788   /**
789   *
790   * Get the sequence name view size
791   * @return	sequence name dimension
792   *
793   */
getNameViewSize()794   public Dimension getNameViewSize()
795   {
796     int hgtName = getNameHeight();
797     int lenName = getNameWidth();
798     return new Dimension(lenName,hgtName);
799   }
800 
801   /**
802   *
803   * Get the sequence view size
804   * @return     sequence view dimension
805   *
806   */
getPanelSize()807   public Dimension getPanelSize()
808   {
809     getViewSize();
810     return new Dimension(len,hgt);
811   }
812 
813   /**
814   *
815   * Get the sequence name panel height
816   * @return     sequence name panel height
817   *
818   */
getNameHeight()819   public int getNameHeight()
820   {
821     int hgtName = 0;
822     Enumeration enumer = graphicName.elements();
823     while(enumer.hasMoreElements())
824       hgtName = hgtName+
825           ((SequenceNameJButton)enumer.nextElement()).getPanelHeight();
826     return hgtName;
827   }
828 
829   /**
830   *
831   * Get the sequence name panel width
832   * @return     sequence name panel width
833   *
834   */
getNameWidth()835   public int getNameWidth()
836   {
837     int lenName = 0;
838     Enumeration enumer = graphicName.elements();
839     while(enumer.hasMoreElements())
840     {
841       SequenceNameJButton gs = (SequenceNameJButton)enumer.nextElement();
842       if(lenName<gs.getPanelWidth())
843         lenName = gs.getPanelWidth();
844     }
845     return lenName;
846   }
847 
848   /**
849   *
850   * Set the sequence name panel width
851   * @param x	sequence name panel  width
852   *
853   */
setNamePanelWidth(int x)854   public void setNamePanelWidth(int x)
855   {
856     seqNamePanel.setPreferredSize(new Dimension(x,1000));
857   }
858 
859   /**
860   *
861   * Get the sequence panel height
862   * @return     sequence panel height
863   *
864   */
getPanelHeight()865   public int getPanelHeight()
866   {
867     getViewSize();
868     return hgt;
869   }
870 
871   /**
872   *
873   * Get the sequence panel width
874   * @return     sequence panel width
875   *
876   */
getPanelWidth()877   public int getPanelWidth()
878   {
879 //  getNameViewSize();
880     getViewSize();
881     return len;
882   }
883 
884   /**
885   *
886   * Get the vector containing the SequenceJPanel objects
887   * @return	vector containing the SequenceJPanel objects
888   *
889   */
getGraphicSequence()890   public Vector getGraphicSequence()
891   {
892     return graphicSequence;
893   }
894 
895   /**
896   *
897   * Draw the boxes around the residues of each sequence
898   * @param	true to draw boxes, false not to display
899   *		boxes
900   *
901   */
setDrawBoxes(boolean drawBlackBox)902   public void setDrawBoxes(boolean drawBlackBox)
903   {
904     this.drawBlackBox = drawBlackBox;
905     Enumeration enumer = graphicSequence.elements();
906     while(enumer.hasMoreElements())
907       ((SequenceJPanel)(enumer.nextElement())).setDrawBoxes(drawBlackBox);
908     setJScrollPaneViewportView();
909   }
910 
911   /**
912   *
913   * Draw the residue colours in each sequence
914   * @param      true to display colour, false not to display
915   *             colour
916   *
917   */
setDrawColor(boolean drawColorBox)918   public void setDrawColor(boolean drawColorBox)
919   {
920     this.drawColorBox = drawColorBox;
921     Enumeration enumer = graphicSequence.elements();
922     while(enumer.hasMoreElements())
923       ((SequenceJPanel)(enumer.nextElement())).setDrawColor(drawColorBox);
924     setJScrollPaneViewportView();
925   }
926 
927   /**
928   *
929   * Set the font size of the sequences in the editor
930   * @param	font size to use
931   *
932   */
setFontSizeForCollection(int fs)933   public void setFontSizeForCollection(int fs)
934   {
935     Enumeration enumer = graphicSequence.elements();
936 
937     while(enumer.hasMoreElements())
938     {
939       SequenceJPanel gs = (SequenceJPanel)enumer.nextElement();
940       gs.setFontSize(fs);
941       Dimension actual = gs.getMaximumSize();
942       int slen = gs.getResidueWidth()*(int)(MAXSEQLENGTH*1.2);
943       gs.setMaximumSize(new Dimension(slen,(int)actual.getHeight()));
944     }
945 
946     Enumeration enumName = graphicName.elements();
947     while(enumName.hasMoreElements())
948     {
949       SequenceNameJButton snjp = (SequenceNameJButton)enumName.nextElement();
950       snjp.setFontSize(fs);
951       snjp.setMaximumSize(snjp.getPreferredSize());
952     }
953 
954 // rescale consensus plot
955     if(pc != null)
956     {
957       SequenceJPanel sj = (SequenceJPanel)graphicSequence.get(0);
958       int interval = sj.getSequenceResidueWidth();
959       pc.setInterval(interval);
960       pc.setPlotSize();
961     }
962 
963 //
964     Dimension dpane = getPanelSize();
965     setMinimumSize(dpane);
966     setPreferredSize(dpane);
967 
968     setNamePanelWidth(getNameWidth());
969     setJScrollPaneViewportView();
970   }
971 
972   /**
973   *
974   * Get the font size used to display the sequences in the
975   * editor
976   * return 	font size
977   *
978   */
getFontSize()979   public int getFontSize()
980   {
981     return ((SequenceJPanel)graphicSequence.get(0)).getFontSize();
982   }
983 
984   /**
985   *
986   * Search sequences for a pattern and highlight matches. Set the
987   * viewport to that position.
988   *
989   * @param String pat pattern to match
990   * @param int oldResPosition if this is a repeat of a search
991   *        this is the position the old search finished at
992   * @param boolean wrapAround true if the search should wrap
993   *        around the sequences
994   * @return int the matching position found (or -1 if none found)
995   *
996   */
findPattern(String pat, int oldResPosition, boolean wrapAround)997   public int findPattern(String pat, int oldResPosition,
998                          boolean wrapAround)
999   {
1000     int resWidth = ((SequenceJPanel)graphicSequence.get(0)).
1001                                            getSequenceResidueWidth();
1002     Rectangle r = getViewRect();
1003     int ypos = r.y;
1004     int xpos = r.x/resWidth;
1005     int viewWidth = r.width/resWidth;
1006     pat = pat.toLowerCase();
1007 
1008 // highlight matching segments of seqs
1009     Enumeration enumer = graphicSequence.elements();
1010     while(enumer.hasMoreElements())
1011     {
1012       SequenceJPanel sjp = (SequenceJPanel)enumer.nextElement();
1013       sjp.showPattern(pat);
1014     }
1015 
1016 // move view to the next occurence of that pattern
1017     if(oldResPosition > -1)      // possibly this as well: (&& xpos < oldResPosition)
1018       xpos = oldResPosition;
1019 
1020     int newResPos = searchSequences(xpos,pat);
1021 
1022     if(newResPos > -1)
1023     {
1024       int mid = findMiddle(newResPos,viewWidth,pat);
1025       jspSequence.getViewport().setViewPosition(
1026                         new Point(mid*resWidth,ypos));
1027 //    System.out.println("xpos "+xpos+" newResPos "+newResPos+
1028 //                       " viewWidth "+viewWidth+" mid "+mid+
1029 //                       " oldResPosition "+oldResPosition);
1030     }
1031     else if(wrapAround)     // search from start of seqs
1032     {
1033 //    JOptionPane.show
1034       newResPos = searchSequences(0,pat);
1035 //    System.out.println("SEARCH FROM START OF SEQUENCE");
1036       if(newResPos > -1)
1037       {
1038         int mid = findMiddle(newResPos,viewWidth,pat);
1039         jspSequence.getViewport().setViewPosition(
1040                          new Point(mid*resWidth,ypos));
1041       }
1042     }
1043     else if(!wrapAround)
1044       newResPos = oldResPosition;
1045 
1046     return newResPos+1;
1047   }
1048 
1049   /**
1050   *
1051   * Search the sequences for the position in that matches
1052   * the given pattern to search for.
1053   *
1054   * @param int startSearch position at which the search is started
1055   * @param String pat is the pattern to search
1056   * @return int position in a sequence that next matches the pattern
1057   *         (or -1 if none found)
1058   *
1059   */
searchSequences(int startSearch, String pat)1060   private int searchSequences(int startSearch, String pat)
1061   {
1062     int newResPos = 0;
1063     int nfound = 0;
1064 
1065     Enumeration enumer = seqs.elements();
1066     while(enumer.hasMoreElements())
1067     {
1068       Sequence seq = (Sequence)enumer.nextElement();
1069       int index = seq.getSequence().toLowerCase().indexOf(pat,startSearch);
1070       if(index > -1)
1071       {
1072         if(nfound == 0 || index < newResPos)
1073           newResPos = index;
1074         nfound++;
1075       }
1076     }
1077     if(nfound == 0)
1078       return -1;
1079     return newResPos;
1080   }
1081 
1082   /**
1083   *
1084   * Locate the center of a vieport view that contains the
1085   * defined position to display
1086   *
1087   * @param int newResPos position in the sequence to display
1088   * @param int viewWidth width of the viewport
1089   * @param String pat matching pattern
1090   * @return int position to set the viewport to so that the
1091   *         pattern is displayed in the middle of it
1092   *
1093   */
findMiddle(int newResPos, int viewWidth, String pat)1094   private int findMiddle(int newResPos, int viewWidth, String pat)
1095   {
1096     int mid;
1097     int viewWidth2 = viewWidth/2;
1098     if(newResPos <= viewWidth2)
1099       mid = 0;
1100     else
1101       mid = newResPos-viewWidth2+(pat.length()/2);
1102     return mid;
1103   }
1104 
1105   /**
1106   *
1107   * Set the colour scheme to use
1108   * @param colourTable	colour scheme as a hashtable
1109   *
1110   */
setColorScheme(Hashtable colourTable)1111   public void setColorScheme(Hashtable colourTable)
1112   {
1113     this.colorScheme  = colourTable;
1114     this.drawColorBox = true;
1115 
1116     Enumeration enumer = graphicSequence.elements();
1117     while(enumer.hasMoreElements())
1118     {
1119       SequenceJPanel sjp = (SequenceJPanel)enumer.nextElement();
1120       sjp.setColorScheme(colourTable);
1121       sjp.setDrawColor(drawColorBox);
1122     }
1123   }
1124 
1125   /**
1126   *
1127   * Display the sequences as per emboss prettyplot colours
1128   * @param bpretty	true if displaying as prettyplot
1129   *
1130   */
setPrettyPlot(boolean bpretty, PrettyPlotJFrame prettyPlot)1131   public void setPrettyPlot(boolean bpretty, PrettyPlotJFrame prettyPlot)
1132   {
1133     this.prettyPlot = prettyPlot;
1134     Enumeration enumer = graphicSequence.elements();
1135     while(enumer.hasMoreElements())
1136       ((SequenceJPanel)(enumer.nextElement())).setPrettyPlot(bpretty);
1137   }
1138 
1139   /**
1140   *
1141   * Force display in the viewport
1142   *
1143   */
setJScrollPaneViewportView()1144   public void setJScrollPaneViewportView()
1145   {
1146     jspSequence.setViewportView(this);
1147   }
1148 
1149   /**
1150   *
1151   * Get the number of pages to print the alignment in
1152   * a given format
1153   * @param format	format for printing
1154   * @return		number of pages
1155   *
1156   */
getNumberPages(PageFormat format)1157   public int getNumberPages(PageFormat format)
1158   {
1159     return getNumberPages(format,getResiduesPerLine(format));
1160   }
1161 
1162   /**
1163   *
1164   * Get the number of pages to print the alignment in
1165   * a given format and with a given number of residues per line
1166   * @param format         format for printing
1167   * @param numResPerLine  number of residues per line
1168   * @return               number of pages
1169   *
1170   */
getNumberPages(PageFormat format, int numResPerLine)1171   public int getNumberPages(PageFormat format, int numResPerLine)
1172   {
1173     double pageHeight = format.getImageableHeight();
1174     int residueWidth  = ((SequenceJPanel)graphicSequence.get(0)).getSequenceHeight();
1175     int nblockPerPage = (int)(pageHeight/((graphicSequence.size()+2)*residueWidth));
1176     int npage         = MAXSEQLENGTH/(nblockPerPage*numResPerLine)+1;
1177     return npage;
1178   }
1179 
1180   /**
1181   *
1182   * Get the imageable size. This is for fitting the image
1183   * to one page.
1184   * @return               image size
1185   *
1186   */
getImageableSize(int numResPerLine)1187   public Dimension getImageableSize(int numResPerLine)
1188   {
1189     SequenceJPanel seq = (SequenceJPanel)graphicSequence.get(0);
1190     int residueHeight = seq.getSequenceHeight();
1191     int alignHeight   = (graphicSequence.size()+1)*residueHeight;
1192     int nalign = Math.round(((float)MAXSEQLENGTH/
1193                              (float)numResPerLine)+.5f)*alignHeight;
1194 //  System.out.println("nalign "+
1195 //                     Math.round(((float)MAXSEQLENGTH/(float)numResPerLine)+.5f)+
1196 //                     "  alignHeight "+alignHeight+"  nalign "+nalign+"
1197 //                     residueHeight "+residueHeight+
1198 //                     "  graphicSequence.size()+1 "+(graphicSequence.size()+1));
1199     int width  = (seq.getResidueWidth()*(numResPerLine+2))+getNameWidth();
1200     return new Dimension(width,nalign);
1201   }
1202 
1203   /**
1204   *
1205   * Get the number residues per line
1206   * @param format    	format for printing
1207   * @return		number residues per line
1208   *
1209   */
getResiduesPerLine(PageFormat format)1210   public int getResiduesPerLine(PageFormat format)
1211   {
1212     double pwidth = format.getImageableWidth()-(double)getNameWidth();
1213 //  int resWidth = ((SequenceJPanel)graphicSequence.get(0)).getSequenceHeight();
1214     int resWidth = ((SequenceJPanel)graphicSequence.get(0)).getSequenceResidueWidth();
1215     return (int)(pwidth/(double)resWidth);
1216   }
1217 
1218   /**
1219   *
1220   * Get the number residues per page
1221   * @param format         format for printing
1222   * @param numResPerLine  number residues per line
1223   * @return 		  number residues per page
1224   *
1225   */
getResiduesPerPage(PageFormat format, int numResPerLine)1226   public int getResiduesPerPage(PageFormat format, int numResPerLine)
1227   {
1228     double pageHeight = format.getImageableHeight();
1229     int residueWidth  = ((SequenceJPanel)graphicSequence.get(0)).getSequenceHeight();
1230     int nblockPerPage = (int)(pageHeight/(residueWidth*(graphicSequence.size()+2)));
1231     return nblockPerPage*numResPerLine;
1232   }
1233 
1234   /**
1235   *
1236   * Used to print the sequence alignment
1237   * @param g		graphics
1238   * @param format	page format
1239   * @param pageIndex 	page number to print
1240   * @throws PrinterException
1241   *
1242   */
print(Graphics g, PageFormat format, int pageIndex)1243   public int print(Graphics g, PageFormat format, int pageIndex)
1244                                              throws PrinterException
1245   {
1246     Graphics2D g2d = (Graphics2D) g.create();
1247     drawSequences(g2d,format,pageIndex,numResiduePerLine);
1248     return Printable.PAGE_EXISTS;
1249   }
1250 
1251   /**
1252   *
1253   * Set the number of residues per line to user setting
1254   * @param numResiduePerLine 	number of residues per line
1255   *
1256   */
setNumberOfResiduesPerLine(int numResiduePerLine)1257   protected void setNumberOfResiduesPerLine(int numResiduePerLine)
1258   {
1259     this.numResiduePerLine = numResiduePerLine;
1260   }
1261 
1262   /**
1263   *
1264   * Draws the sequences for printing
1265   * @param g2d		graphics
1266   * @param format	page format
1267   * @param pageIndex	page number to print
1268   *
1269   */
drawSequences(Graphics2D g2d, PageFormat format, int pageIndex)1270   public void drawSequences(Graphics2D g2d, PageFormat format,
1271                             int pageIndex)
1272   {
1273     int numResPerLine = getResiduesPerLine(format);
1274     drawSequences(g2d,format,pageIndex,numResPerLine);
1275   }
1276 
1277   /**
1278   *
1279   * Draws the sequences for printing
1280   * @param g2d          	graphics
1281   * @param format       	page format
1282   * @param pageIndex    	page number to print
1283   * @param numResPerLine 	number of residues per line
1284   */
drawSequences(Graphics2D g2d, PageFormat format, int pageIndex, int numResPerLine)1285   public void drawSequences(Graphics2D g2d, PageFormat format,
1286                             int pageIndex, int numResPerLine)
1287   {
1288     // move origin from the corner of the Paper to the corner of imageable area
1289     g2d.translate(format.getImageableX(), format.getImageableY());
1290 
1291     int resPerPage  = getResiduesPerPage(format,numResPerLine);
1292     int istart = resPerPage*pageIndex;
1293     int istop  = istart+resPerPage;
1294 
1295     if(istop > MAXSEQLENGTH)
1296       istop = MAXSEQLENGTH;
1297 
1298 //  System.out.println("pageIndex "+pageIndex+" numResPerLine "+numResPerLine);
1299     for(int i=istart;i<istop;i+=numResPerLine)
1300     {
1301       Enumeration enumer = graphicSequence.elements();
1302       SequenceJPanel gs = null;
1303       int iend;
1304 
1305       while(enumer.hasMoreElements())
1306       {
1307         iend = i+numResPerLine;
1308         if(iend > istop)
1309           iend = istop;
1310 
1311         gs = (SequenceJPanel)(enumer.nextElement());
1312         gs.getSequencePrintGraphic(g2d,getNameWidth(),i,iend);
1313 //                                 i+numResPerLine);
1314         gs.getNamePrintGraphic(g2d);
1315         g2d.translate(0,gs.getSequenceHeight());
1316       }
1317       g2d.translate(0,gs.getSequenceHeight());
1318     }
1319   }
1320 
1321 //scrollable interface methods
1322 
1323   /**
1324   *
1325   * Override for scrollable interface
1326   *
1327   */
getPreferredScrollableViewportSize()1328   public Dimension getPreferredScrollableViewportSize()
1329   {
1330     return getPreferredSize();
1331   }
1332 
1333   /**
1334   *
1335   * Override for scrollable interface
1336   *
1337   */
getScrollableTracksViewportHeight()1338   public boolean getScrollableTracksViewportHeight()
1339   {
1340     return false;
1341   }
1342 
1343   /**
1344   *
1345   * Override for scrollable interface
1346   *
1347   */
getScrollableTracksViewportWidth()1348   public boolean getScrollableTracksViewportWidth()
1349   {
1350     return false;
1351   }
1352 
1353   /**
1354   *
1355   * Override for scrollable interface
1356   *
1357   */
getScrollableBlockIncrement(Rectangle r, int orientation, int direction)1358   public int getScrollableBlockIncrement(Rectangle r,
1359                     int orientation, int direction)
1360   {
1361     return 60;
1362   }
1363 
1364   /**
1365   *
1366   * Override for scrollable interface
1367   *
1368   */
getScrollableUnitIncrement(Rectangle r, int orientation, int direction)1369   public int getScrollableUnitIncrement(Rectangle r,
1370                     int orientation, int direction)
1371   {
1372     return 60;
1373   }
1374 
1375 
main(String args[])1376   public static void main(String args[])
1377   {
1378     Vector seqs = new Vector();
1379     seqs.add(new Sequence("Seq1","ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"+
1380              "ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"+
1381              "ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"));
1382     seqs.add(new Sequence("Seq2","ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"+
1383              "ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"+
1384              "ACCaaaaaaaaaaaaaaaaaaaaTAGAtTAT"));
1385 
1386     JScrollPane jspSequence = new JScrollPane();
1387     GraphicSequenceCollection gsc = new GraphicSequenceCollection(
1388                                           seqs,null,jspSequence,
1389                                           true,true,true,false,null);
1390     jspSequence.setViewportView(gsc);
1391     JFrame f = new JFrame("Sequence Panel");
1392     JPanel pane = (JPanel)f.getContentPane();
1393 
1394     pane.add(jspSequence);
1395     f.pack();
1396     f.setVisible(true);
1397 
1398   }
1399 
drawNumber()1400   protected void drawNumber()
1401   {
1402     numberDraw = new SequenceJPanel(10,MAXSEQLENGTH);
1403     graphicSequence.add(numberDraw);
1404     Box XBox = new Box(BoxLayout.X_AXIS);
1405     XBox.add(numberDraw);
1406     XBox.add(Box.createHorizontalGlue());
1407     seqBox.add(XBox);
1408 
1409     setNumberSize();
1410     SequenceNameJButton snjBlank =
1411         new SequenceNameJButton(new Sequence("seq-id:",""),0);
1412     snjBlank.setEnabled(false);
1413     graphicName.add(snjBlank);
1414     XBox = new Box(BoxLayout.X_AXIS);
1415     XBox.add(Box.createHorizontalGlue());
1416     XBox.add(snjBlank);
1417     seqNameBox.add(XBox);
1418   }
1419 
addAnnotationSequence(Sequence s)1420   protected void addAnnotationSequence(Sequence s)
1421   {
1422     addSequence(s,true,0,getFontSize());
1423   }
1424 
1425 }
1426 
1427