7fc240f4d84cd8d76114fdf2db961d68012ece14
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 \r
26 import jalview.analysis.*;\r
27 import jalview.bin.*;\r
28 import jalview.datamodel.*;\r
29 import jalview.schemes.*;\r
30 \r
31 public class AlignViewport\r
32 {\r
33   int startRes;\r
34   int endRes;\r
35 \r
36   int startSeq;\r
37   int endSeq;\r
38 \r
39 \r
40   boolean cursorMode = false;\r
41 \r
42   boolean showJVSuffix = true;\r
43   boolean showText = true;\r
44   boolean showColourText = false;\r
45   boolean showBoxes = true;\r
46   boolean wrapAlignment = false;\r
47   boolean renderGaps = true;\r
48   boolean showSequenceFeatures = false;\r
49   boolean showAnnotation = true;\r
50   boolean showConservation = true;\r
51   boolean showQuality = true;\r
52   boolean showConsensus = true;\r
53   boolean upperCasebold = false;\r
54 \r
55   boolean colourAppliesToAllGroups = true;\r
56   ColourSchemeI globalColourScheme = null;\r
57   boolean conservationColourSelected = false;\r
58   boolean abovePIDThreshold = false;\r
59 \r
60   SequenceGroup selectionGroup;\r
61 \r
62   int charHeight;\r
63   int charWidth;\r
64   int wrappedWidth;\r
65 \r
66   Font font = new Font("SansSerif", Font.PLAIN, 10);\r
67   boolean validCharWidth = true;\r
68   AlignmentI alignment;\r
69 \r
70   ColumnSelection colSel = new ColumnSelection();\r
71 \r
72   int threshold;\r
73   int increment;\r
74 \r
75   NJTree currentTree = null;\r
76 \r
77   boolean scaleAboveWrapped = true;\r
78   boolean scaleLeftWrapped = true;\r
79   boolean scaleRightWrapped = true;\r
80 \r
81   // The following vector holds the features which are\r
82  // currently visible, in the correct order or rendering\r
83   public Hashtable featuresDisplayed;\r
84 \r
85   boolean hasHiddenColumns = false;\r
86   boolean hasHiddenRows = false;\r
87   boolean showHiddenMarkers = true;\r
88 \r
89 \r
90   public Hashtable [] hconsensus;\r
91   AlignmentAnnotation consensus;\r
92   AlignmentAnnotation conservation;\r
93   AlignmentAnnotation quality;\r
94 \r
95   boolean autocalculateConsensus = true;\r
96 \r
97   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!\r
98 \r
99   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this);\r
100 \r
101   boolean ignoreGapsInConsensusCalculation = false;\r
102 \r
103   jalview.bin.JalviewLite applet;\r
104 \r
105   Hashtable sequenceColours;\r
106 \r
107   boolean MAC = false;\r
108 \r
109   Stack historyList = new Stack();\r
110   Stack redoList = new Stack();\r
111 \r
112   String sequenceSetID;\r
113 \r
114   Hashtable hiddenRepSequences;\r
115 \r
116   public AlignViewport(AlignmentI al, JalviewLite applet)\r
117   {\r
118     this.applet = applet;\r
119     setAlignment(al);\r
120     this.startRes = 0;\r
121     this.endRes = al.getWidth() - 1;\r
122     this.startSeq = 0;\r
123     this.endSeq = al.getHeight() - 1;\r
124     setFont(font);\r
125 \r
126     if(System.getProperty("os.name").startsWith("Mac"))\r
127       MAC = true;\r
128 \r
129     if (applet != null)\r
130     {\r
131       String param = applet.getParameter("showFullId");\r
132       if (param != null)\r
133       {\r
134         showJVSuffix = Boolean.valueOf(param).booleanValue();\r
135       }\r
136 \r
137       param = applet.getParameter("showAnnotation");\r
138       if (param != null)\r
139       {\r
140         showAnnotation = Boolean.valueOf(param).booleanValue();\r
141       }\r
142 \r
143       param = applet.getParameter("showConservation");\r
144       if (param != null)\r
145       {\r
146         showConservation = Boolean.valueOf(param).booleanValue();\r
147       }\r
148 \r
149       param = applet.getParameter("showQuality");\r
150       if (param != null)\r
151       {\r
152         showQuality = Boolean.valueOf(param).booleanValue();\r
153       }\r
154 \r
155       param = applet.getParameter("showConsensus");\r
156       if (param != null)\r
157       {\r
158         showConsensus = Boolean.valueOf(param).booleanValue();\r
159       }\r
160 \r
161       param = applet.getParameter("upperCase");\r
162       if (param != null)\r
163       {\r
164         if(param.equalsIgnoreCase("bold"))\r
165           upperCasebold = true;\r
166       }\r
167 \r
168     }\r
169 \r
170     if (applet != null)\r
171     {\r
172       String colour = applet.getParameter("defaultColour");\r
173 \r
174       if(colour == null)\r
175       {\r
176         colour = applet.getParameter("userDefinedColour");\r
177         if(colour !=null)\r
178           colour = "User Defined";\r
179       }\r
180 \r
181       if(colour != null)\r
182       {\r
183         globalColourScheme = ColourSchemeProperty.getColour(alignment, colour);\r
184         if (globalColourScheme != null)\r
185         {\r
186           globalColourScheme.setConsensus(hconsensus);\r
187         }\r
188       }\r
189 \r
190       if(applet.getParameter("userDefinedColour")!=null)\r
191       {\r
192         ((UserColourScheme)globalColourScheme).parseAppletParameter(\r
193             applet.getParameter("userDefinedColour"));\r
194       }\r
195 \r
196       if(hconsensus==null)\r
197       {\r
198         if(!alignment.isNucleotide())\r
199         {\r
200           conservation = new AlignmentAnnotation("Conservation",\r
201               "Conservation of total alignment less than " +\r
202               ConsPercGaps + "% gaps",\r
203               new Annotation[1], 0f,\r
204               11f,\r
205               AlignmentAnnotation.BAR_GRAPH);\r
206           conservation.hasText = true;\r
207           conservation.autoCalculated = true;\r
208 \r
209 \r
210 \r
211           if (showConservation)\r
212           {\r
213             alignment.addAnnotation(conservation);\r
214           }\r
215 \r
216           if (showQuality)\r
217           {\r
218             quality = new AlignmentAnnotation("Quality",\r
219                                               "Alignment Quality based on Blosum62 scores",\r
220                                               new Annotation[1],\r
221                                               0f,\r
222                                               11f,\r
223                                               AlignmentAnnotation.BAR_GRAPH);\r
224             quality.hasText = true;\r
225             quality.autoCalculated = true;\r
226 \r
227             alignment.addAnnotation(quality);\r
228           }\r
229         }\r
230 \r
231         consensus = new AlignmentAnnotation("Consensus", "PID",\r
232                                              new Annotation[1], 0f, 100f,\r
233                                              AlignmentAnnotation.BAR_GRAPH);\r
234         consensus.hasText = true;\r
235         consensus.autoCalculated = true;\r
236 \r
237          if (showConsensus)\r
238          {\r
239            alignment.addAnnotation(consensus);\r
240          }\r
241       }\r
242     }\r
243   }\r
244 \r
245   public void showSequenceFeatures(boolean b)\r
246   {\r
247     showSequenceFeatures = b;\r
248   }\r
249 \r
250   public boolean getShowSequenceFeatures()\r
251   {\r
252     return showSequenceFeatures;\r
253   }\r
254 \r
255 \r
256   class ConservationThread extends Thread\r
257   {\r
258     AlignmentPanel ap;\r
259     public ConservationThread(AlignmentPanel ap)\r
260     {\r
261       this.ap = ap;\r
262     }\r
263 \r
264     public void run()\r
265     {\r
266       try\r
267       {\r
268         updatingConservation = true;\r
269 \r
270         while (UPDATING_CONSERVATION)\r
271         {\r
272           try\r
273           {\r
274             if (ap != null)\r
275             {\r
276               ap.repaint();\r
277             }\r
278             Thread.sleep(200);\r
279           }\r
280           catch (Exception ex)\r
281           {\r
282             ex.printStackTrace();\r
283           }\r
284         }\r
285 \r
286         UPDATING_CONSERVATION = true;\r
287 \r
288 \r
289         int alWidth = alignment.getWidth();\r
290         if(alWidth<0)\r
291           return;\r
292 \r
293         Conservation cons = new jalview.analysis.Conservation("All",\r
294             jalview.schemes.ResidueProperties.propHash, 3,\r
295             alignment.getSequences(), 0, alWidth -1);\r
296 \r
297         cons.calculate();\r
298         cons.verdict(false, ConsPercGaps);\r
299 \r
300         if (quality!=null)\r
301         {\r
302           cons.findQuality();\r
303         }\r
304 \r
305         char [] sequence = cons.getConsSequence().getSequence();\r
306         float minR;\r
307         float minG;\r
308         float minB;\r
309         float maxR;\r
310         float maxG;\r
311         float maxB;\r
312         minR = 0.3f;\r
313         minG = 0.0f;\r
314         minB = 0f;\r
315         maxR = 1.0f - minR;\r
316         maxG = 0.9f - minG;\r
317         maxB = 0f - minB; // scalable range for colouring both Conservation and Quality\r
318 \r
319         float min = 0f;\r
320         float max = 11f;\r
321         float qmin = 0f;\r
322         float qmax = 0f;\r
323 \r
324         char c;\r
325 \r
326         conservation.annotations = new Annotation[alWidth];\r
327 \r
328         if (quality!=null)\r
329         {\r
330           quality.graphMax = cons.qualityRange[1].floatValue();\r
331           quality.annotations = new Annotation[alWidth];\r
332           qmin = cons.qualityRange[0].floatValue();\r
333           qmax = cons.qualityRange[1].floatValue();\r
334         }\r
335 \r
336         for (int i = 0; i < alWidth; i++)\r
337         {\r
338           float value = 0;\r
339 \r
340           c = sequence[i];\r
341 \r
342           if (Character.isDigit(c))\r
343             value = (int) (c - '0');\r
344           else if (c == '*')\r
345             value = 11;\r
346           else if (c == '+')\r
347             value = 10;\r
348 \r
349           float vprop = value - min;\r
350           vprop /= max;\r
351           conservation.annotations[i] =\r
352               new Annotation(String.valueOf(c),\r
353                              String.valueOf(value), ' ', value,\r
354                              new Color(minR + (maxR * vprop),\r
355                                        minG + (maxG * vprop),\r
356                                        minB + (maxB * vprop)));\r
357 \r
358           // Quality calc\r
359           if (quality!=null)\r
360           {\r
361             value = ( (Double) cons.quality.elementAt(i)).floatValue();\r
362             vprop = value - qmin;\r
363             vprop /= qmax;\r
364             quality.annotations[i] = new Annotation(" ", String.valueOf(value), ' ',\r
365                                              value,\r
366                                              new Color(minR + (maxR * vprop),\r
367                 minG + (maxG * vprop),\r
368                 minB + (maxB * vprop)));\r
369           }\r
370         }\r
371       }\r
372       catch (OutOfMemoryError error)\r
373       {\r
374         System.out.println("Out of memory calculating conservation!!");\r
375         conservation = null;\r
376         quality = null;\r
377         System.gc();\r
378       }\r
379 \r
380       UPDATING_CONSERVATION = false;\r
381       updatingConservation = false;\r
382 \r
383       if(ap!=null)\r
384       {\r
385         ap.repaint();\r
386       }\r
387 \r
388     }\r
389   }\r
390 \r
391 \r
392   ConservationThread conservationThread;\r
393 \r
394   ConsensusThread consensusThread;\r
395 \r
396   boolean consUpdateNeeded = false;\r
397 \r
398   static boolean UPDATING_CONSENSUS = false;\r
399 \r
400   static boolean UPDATING_CONSERVATION = false;\r
401 \r
402   boolean updatingConsensus = false;\r
403 \r
404   boolean updatingConservation = false;\r
405 \r
406   /**\r
407    * DOCUMENT ME!\r
408    */\r
409   public void updateConservation(final AlignmentPanel ap)\r
410   {\r
411     if (alignment.isNucleotide() || conservation==null)\r
412       return;\r
413 \r
414     conservationThread = new ConservationThread(ap);\r
415     conservationThread.start();\r
416   }\r
417 \r
418   /**\r
419    * DOCUMENT ME!\r
420    */\r
421   public void updateConsensus(final AlignmentPanel ap)\r
422   {\r
423     consensusThread = new ConsensusThread(ap);\r
424     consensusThread.start();\r
425   }\r
426 \r
427 \r
428   class ConsensusThread extends Thread\r
429   {\r
430     AlignmentPanel ap;\r
431     public ConsensusThread(AlignmentPanel ap)\r
432     {\r
433       this.ap = ap;\r
434     }\r
435     public void run()\r
436     {\r
437       updatingConsensus = true;\r
438       while (UPDATING_CONSENSUS)\r
439       {\r
440         try\r
441         {\r
442           if (ap != null)\r
443           {\r
444             ap.repaint();\r
445           }\r
446 \r
447           Thread.sleep(200);\r
448         }\r
449         catch (Exception ex)\r
450         {\r
451           ex.printStackTrace();\r
452         }\r
453       }\r
454 \r
455 \r
456       UPDATING_CONSENSUS = true;\r
457 \r
458       try\r
459       {\r
460         int aWidth = alignment.getWidth();\r
461         if(aWidth<0)\r
462           return;\r
463 \r
464         consensus.annotations = null;\r
465         consensus.annotations = new Annotation[aWidth];\r
466 \r
467 \r
468         hconsensus = new Hashtable[aWidth];\r
469         AAFrequency.calculate(alignment.getSequencesArray(),\r
470                               0,\r
471                               alignment.getWidth(),\r
472                               hconsensus);\r
473 \r
474         for (int i = 0; i < aWidth; i++)\r
475         {\r
476           float value = 0;\r
477           if (ignoreGapsInConsensusCalculation)\r
478             value = ( (Float) hconsensus[i].get(AAFrequency.PID_NOGAPS)).\r
479                 floatValue();\r
480           else\r
481             value = ( (Float) hconsensus[i].get(AAFrequency.PID_GAPS)).\r
482                 floatValue();\r
483 \r
484           String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE).toString();\r
485           String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE) + " ";\r
486 \r
487           if (maxRes.length() > 1)\r
488           {\r
489             mouseOver = "[" + maxRes + "] ";\r
490             maxRes = "+";\r
491           }\r
492 \r
493           mouseOver += ( (int) value + "%");\r
494           consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);\r
495         }\r
496 \r
497 \r
498         if (globalColourScheme != null)\r
499           globalColourScheme.setConsensus(hconsensus);\r
500 \r
501       }\r
502       catch (OutOfMemoryError error)\r
503       {\r
504         alignment.deleteAnnotation(consensus);\r
505 \r
506         consensus = null;\r
507         hconsensus = null;\r
508         System.out.println("Out of memory calculating consensus!!");\r
509         System.gc();\r
510       }\r
511       UPDATING_CONSENSUS = false;\r
512       updatingConsensus = false;\r
513 \r
514       if (ap != null)\r
515       {\r
516         ap.repaint();\r
517       }\r
518     }\r
519   }\r
520 \r
521   /**\r
522    * get the consensus sequence as displayed under the PID consensus annotation row.\r
523    * @return consensus sequence as a new sequence object\r
524    */\r
525   /**\r
526    * get the consensus sequence as displayed under the PID consensus annotation row.\r
527    * @return consensus sequence as a new sequence object\r
528    */\r
529   public SequenceI getConsensusSeq()\r
530   {\r
531     if (consensus==null)\r
532       return null;\r
533     StringBuffer seqs=new StringBuffer();\r
534     for (int i=0; i<consensus.annotations.length; i++) {\r
535       if (consensus.annotations[i]!=null) {\r
536         if (consensus.annotations[i].description.charAt(0) == '[')\r
537           seqs.append(consensus.annotations[i].description.charAt(1));\r
538         else\r
539           seqs.append(consensus.annotations[i].displayCharacter);\r
540       }\r
541     }\r
542     SequenceI sq = new Sequence("Consensus", seqs.toString());\r
543     sq.setDescription("Percentage Identity Consensus "+((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));\r
544     return sq;\r
545   }\r
546   public SequenceGroup getSelectionGroup()\r
547   {\r
548     return selectionGroup;\r
549   }\r
550 \r
551   public void setSelectionGroup(SequenceGroup sg)\r
552   {\r
553     selectionGroup = sg;\r
554   }\r
555 \r
556   public boolean getConservationSelected()\r
557   {\r
558     return conservationColourSelected;\r
559   }\r
560 \r
561   public void setConservationSelected(boolean b)\r
562   {\r
563     conservationColourSelected = b;\r
564   }\r
565 \r
566   public boolean getAbovePIDThreshold()\r
567   {\r
568     return abovePIDThreshold;\r
569   }\r
570 \r
571   public void setAbovePIDThreshold(boolean b)\r
572   {\r
573     abovePIDThreshold = b;\r
574   }\r
575 \r
576   public int getStartRes()\r
577   {\r
578     return startRes;\r
579   }\r
580 \r
581   public int getEndRes()\r
582   {\r
583     return endRes;\r
584   }\r
585 \r
586   public int getStartSeq()\r
587   {\r
588     return startSeq;\r
589   }\r
590 \r
591   public void setGlobalColourScheme(ColourSchemeI cs)\r
592   {\r
593     globalColourScheme = cs;\r
594   }\r
595 \r
596   public ColourSchemeI getGlobalColourScheme()\r
597   {\r
598     return globalColourScheme;\r
599   }\r
600 \r
601   public void setStartRes(int res)\r
602   {\r
603     this.startRes = res;\r
604   }\r
605 \r
606   public void setStartSeq(int seq)\r
607   {\r
608     this.startSeq = seq;\r
609   }\r
610 \r
611   public void setEndRes(int res)\r
612   {\r
613     if (res > alignment.getWidth() - 1)\r
614     {\r
615       // log.System.out.println(" Corrected res from " + res + " to maximum " + (alignment.getWidth()-1));\r
616       res = alignment.getWidth() - 1;\r
617     }\r
618     if (res < 0)\r
619     {\r
620       res = 0;\r
621     }\r
622     this.endRes = res;\r
623   }\r
624 \r
625   public void setEndSeq(int seq)\r
626   {\r
627     if (seq > alignment.getHeight())\r
628     {\r
629       seq = alignment.getHeight();\r
630     }\r
631     if (seq < 0)\r
632     {\r
633       seq = 0;\r
634     }\r
635     this.endSeq = seq;\r
636   }\r
637 \r
638   public int getEndSeq()\r
639   {\r
640     return endSeq;\r
641   }\r
642 \r
643   java.awt.Frame nullFrame;\r
644   public void setFont(Font f)\r
645   {\r
646     font = f;\r
647     if(nullFrame == null)\r
648     {\r
649       nullFrame = new java.awt.Frame();\r
650       nullFrame.addNotify();\r
651     }\r
652 \r
653     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);\r
654     setCharHeight(fm.getHeight());\r
655     charWidth = fm.charWidth('M');\r
656 \r
657     if(upperCasebold)\r
658     {\r
659       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());\r
660       fm = nullFrame.getGraphics().getFontMetrics(f2);\r
661       charWidth = fm.stringWidth("MMMMMMMMMMM") / 10;\r
662     }\r
663   }\r
664 \r
665   public Font getFont()\r
666   {\r
667     return font;\r
668   }\r
669 \r
670   public int getCharWidth()\r
671   {\r
672     return charWidth;\r
673   }\r
674 \r
675   public void setCharHeight(int h)\r
676   {\r
677     this.charHeight = h;\r
678   }\r
679 \r
680   public int getCharHeight()\r
681   {\r
682     return charHeight;\r
683   }\r
684 \r
685   public void setWrappedWidth(int w)\r
686   {\r
687     this.wrappedWidth = w;\r
688   }\r
689 \r
690   public int getwrappedWidth()\r
691   {\r
692     return wrappedWidth;\r
693   }\r
694 \r
695   public AlignmentI getAlignment()\r
696   {\r
697     return alignment;\r
698   }\r
699 \r
700   public void setAlignment(AlignmentI align)\r
701   {\r
702     this.alignment = align;\r
703   }\r
704 \r
705   public void setWrapAlignment(boolean state)\r
706   {\r
707     wrapAlignment = state;\r
708   }\r
709 \r
710   public void setShowText(boolean state)\r
711   {\r
712     showText = state;\r
713   }\r
714 \r
715   public void setRenderGaps(boolean state)\r
716   {\r
717     renderGaps = state;\r
718   }\r
719 \r
720   public boolean getColourText()\r
721   {\r
722     return showColourText;\r
723   }\r
724 \r
725   public void setColourText(boolean state)\r
726   {\r
727     showColourText = state;\r
728   }\r
729 \r
730   public void setShowBoxes(boolean state)\r
731   {\r
732     showBoxes = state;\r
733   }\r
734 \r
735   public boolean getWrapAlignment()\r
736   {\r
737     return wrapAlignment;\r
738   }\r
739 \r
740   public boolean getShowText()\r
741   {\r
742     return showText;\r
743   }\r
744 \r
745   public boolean getShowBoxes()\r
746   {\r
747     return showBoxes;\r
748   }\r
749 \r
750   public char getGapCharacter()\r
751   {\r
752     return getAlignment().getGapCharacter();\r
753   }\r
754 \r
755   public void setGapCharacter(char gap)\r
756   {\r
757     if (getAlignment() != null)\r
758     {\r
759       getAlignment().setGapCharacter(gap);\r
760     }\r
761   }\r
762 \r
763   public void setThreshold(int thresh)\r
764   {\r
765     threshold = thresh;\r
766   }\r
767 \r
768   public int getThreshold()\r
769   {\r
770     return threshold;\r
771   }\r
772 \r
773   public void setIncrement(int inc)\r
774   {\r
775     increment = inc;\r
776   }\r
777 \r
778   public int getIncrement()\r
779   {\r
780     return increment;\r
781   }\r
782 \r
783   public void setHiddenColumns(ColumnSelection colsel)\r
784   {\r
785     this.colSel = colsel;\r
786     if(colSel.getHiddenColumns()!=null)\r
787       hasHiddenColumns = true;\r
788   }\r
789 \r
790   public ColumnSelection getColumnSelection()\r
791   {\r
792     return colSel;\r
793   }\r
794 \r
795   public void resetSeqLimits(int height)\r
796   {\r
797     setEndSeq(height / getCharHeight());\r
798   }\r
799 \r
800   public void setCurrentTree(NJTree tree)\r
801   {\r
802     currentTree = tree;\r
803   }\r
804 \r
805   public NJTree getCurrentTree()\r
806   {\r
807     return currentTree;\r
808   }\r
809 \r
810   public void setColourAppliesToAllGroups(boolean b)\r
811   {\r
812     colourAppliesToAllGroups = b;\r
813   }\r
814 \r
815   public boolean getColourAppliesToAllGroups()\r
816   {\r
817     return colourAppliesToAllGroups;\r
818   }\r
819 \r
820   public boolean getShowJVSuffix()\r
821   {\r
822     return showJVSuffix;\r
823   }\r
824 \r
825   public void setShowJVSuffix(boolean b)\r
826   {\r
827     showJVSuffix = b;\r
828   }\r
829 \r
830   public boolean getShowAnnotation()\r
831   {\r
832     return showAnnotation;\r
833   }\r
834 \r
835   public void setShowAnnotation(boolean b)\r
836   {\r
837     showAnnotation = b;\r
838   }\r
839 \r
840   public boolean getScaleAboveWrapped()\r
841   {\r
842     return scaleAboveWrapped;\r
843   }\r
844 \r
845   public boolean getScaleLeftWrapped()\r
846   {\r
847     return scaleLeftWrapped;\r
848   }\r
849 \r
850   public boolean getScaleRightWrapped()\r
851   {\r
852     return scaleRightWrapped;\r
853   }\r
854 \r
855   public void setScaleAboveWrapped(boolean b)\r
856   {\r
857     scaleAboveWrapped = b;\r
858   }\r
859 \r
860   public void setScaleLeftWrapped(boolean b)\r
861   {\r
862     scaleLeftWrapped = b;\r
863   }\r
864 \r
865   public void setScaleRightWrapped(boolean b)\r
866   {\r
867     scaleRightWrapped = b;\r
868   }\r
869 \r
870   public void setIgnoreGapsConsensus(boolean b)\r
871   {\r
872     ignoreGapsInConsensusCalculation = b;\r
873     updateConsensus(null);\r
874     if (globalColourScheme!=null)\r
875     {\r
876       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),\r
877           ignoreGapsInConsensusCalculation);\r
878 \r
879     }\r
880   }\r
881 \r
882   /**\r
883    * Property change listener for changes in alignment\r
884    *\r
885    * @param listener DOCUMENT ME!\r
886    */\r
887   public void addPropertyChangeListener(\r
888       java.beans.PropertyChangeListener listener)\r
889   {\r
890       changeSupport.addPropertyChangeListener(listener);\r
891   }\r
892 \r
893   /**\r
894    * DOCUMENT ME!\r
895    *\r
896    * @param listener DOCUMENT ME!\r
897    */\r
898   public void removePropertyChangeListener(\r
899       java.beans.PropertyChangeListener listener)\r
900   {\r
901       changeSupport.removePropertyChangeListener(listener);\r
902   }\r
903 \r
904   /**\r
905    * Property change listener for changes in alignment\r
906    *\r
907    * @param prop DOCUMENT ME!\r
908    * @param oldvalue DOCUMENT ME!\r
909    * @param newvalue DOCUMENT ME!\r
910    */\r
911   public void firePropertyChange(String prop, Object oldvalue, Object newvalue)\r
912   {\r
913       changeSupport.firePropertyChange(prop, oldvalue, newvalue);\r
914   }\r
915 \r
916 \r
917 \r
918   public boolean getIgnoreGapsConsensus()\r
919   {\r
920     return ignoreGapsInConsensusCalculation;\r
921   }\r
922   public void hideSelectedColumns()\r
923   {\r
924     if (colSel.size() < 1)\r
925       return;\r
926 \r
927     colSel.hideSelectedColumns();\r
928     setSelectionGroup(null);\r
929 \r
930     hasHiddenColumns = true;\r
931   }\r
932 \r
933   public void invertColumnSelection()\r
934   {\r
935     for (int i = 0; i < alignment.getWidth(); i++)\r
936     {\r
937       if (colSel.contains(i))\r
938         colSel.removeElement(i);\r
939       else\r
940       {\r
941         if (!hasHiddenColumns || colSel.isVisible(i))\r
942         {\r
943           colSel.addElement(i);\r
944         }\r
945       }\r
946     }\r
947   }\r
948 \r
949 \r
950   public void hideColumns(int start, int end)\r
951   {\r
952     if(start==end)\r
953       colSel.hideColumns(start);\r
954     else\r
955       colSel.hideColumns(start, end);\r
956 \r
957     hasHiddenColumns = true;\r
958   }\r
959 \r
960   public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)\r
961   {\r
962     int sSize = sg.getSize();\r
963     if(sSize < 2)\r
964       return;\r
965 \r
966     if(hiddenRepSequences==null)\r
967       hiddenRepSequences = new Hashtable();\r
968 \r
969      hiddenRepSequences.put(repSequence, sg);\r
970 \r
971     //Hide all sequences except the repSequence\r
972     SequenceI [] seqs = new SequenceI[sSize-1];\r
973     int index = 0;\r
974     for(int i=0; i<sSize; i++)\r
975       if(sg.getSequenceAt(i)!=repSequence)\r
976       {\r
977         if(index==sSize-1)\r
978           return;\r
979 \r
980         seqs[index++] = sg.getSequenceAt(i);\r
981       }\r
982 \r
983     hideSequence(seqs);\r
984 \r
985     }\r
986 \r
987   public void hideAllSelectedSeqs()\r
988   {\r
989     if (selectionGroup == null)\r
990       return;\r
991 \r
992     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);\r
993 \r
994     hideSequence(seqs);\r
995 \r
996     setSelectionGroup(null);\r
997   }\r
998 \r
999   public void hideSequence(SequenceI [] seq)\r
1000   {\r
1001     if(seq!=null)\r
1002     {\r
1003       for (int i = 0; i < seq.length; i++)\r
1004         alignment.getHiddenSequences().hideSequence(seq[i]);\r
1005 \r
1006       hasHiddenRows = true;\r
1007       firePropertyChange("alignment", null, alignment.getSequences());\r
1008     }\r
1009   }\r
1010 \r
1011   public void showColumn(int col)\r
1012   {\r
1013     colSel.revealHiddenColumns(col);\r
1014     if(colSel.getHiddenColumns()==null)\r
1015       hasHiddenColumns = false;\r
1016   }\r
1017 \r
1018   public void showAllHiddenColumns()\r
1019   {\r
1020     colSel.revealAllHiddenColumns();\r
1021     hasHiddenColumns = false;\r
1022   }\r
1023 \r
1024   public void showAllHiddenSeqs()\r
1025   {\r
1026     if(alignment.getHiddenSequences().getSize()>0)\r
1027     {\r
1028       if(selectionGroup==null)\r
1029       {\r
1030         selectionGroup = new SequenceGroup();\r
1031         selectionGroup.setEndRes(alignment.getWidth()-1);\r
1032       }\r
1033       Vector tmp = alignment.getHiddenSequences().showAll(hiddenRepSequences);\r
1034       for(int t=0; t<tmp.size(); t++)\r
1035       {\r
1036         selectionGroup.addSequence(\r
1037             (SequenceI)tmp.elementAt(t), false\r
1038             );\r
1039       }\r
1040       firePropertyChange("alignment", null, alignment.getSequences());\r
1041       hasHiddenRows = false;\r
1042       hiddenRepSequences = null;\r
1043       }\r
1044   }\r
1045 \r
1046   public int adjustForHiddenSeqs(int alignmentIndex)\r
1047   {\r
1048     return alignment.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex);\r
1049   }\r
1050 \r
1051   /**\r
1052    * This method returns the a new SequenceI [] with\r
1053    * the selection sequence and start and end points adjusted\r
1054    * @return String[]\r
1055    */\r
1056   public SequenceI[] getSelectionAsNewSequence()\r
1057   {\r
1058     SequenceI[] sequences;\r
1059 \r
1060     if (selectionGroup == null)\r
1061       sequences = alignment.getSequencesArray();\r
1062     else\r
1063       sequences = selectionGroup.getSelectionAsNewSequences(alignment);\r
1064 \r
1065     return sequences;\r
1066   }\r
1067 \r
1068   /**\r
1069    * This method returns the visible alignment as text, as\r
1070    * seen on the GUI, ie if columns are hidden they will not\r
1071    * be returned in the result.\r
1072    * Use this for calculating trees, PCA, redundancy etc on views\r
1073    * which contain hidden columns.\r
1074    * @return String[]\r
1075    */\r
1076   public jalview.datamodel.CigarArray getViewAsCigars(boolean selectedRegionOnly)\r
1077   {\r
1078     CigarArray selection=null;\r
1079     SequenceI [] seqs= null;\r
1080     int i, iSize;\r
1081     int start = 0, end = 0;\r
1082     if(selectedRegionOnly && selectionGroup!=null)\r
1083     {\r
1084       iSize = selectionGroup.getSize();\r
1085       seqs = selectionGroup.getSequencesInOrder(alignment);\r
1086       start = selectionGroup.getStartRes();\r
1087       end = selectionGroup.getEndRes(); // inclusive for start and end in SeqCigar constructor\r
1088     }\r
1089     else\r
1090     {\r
1091       iSize = alignment.getHeight();\r
1092       seqs = alignment.getSequencesArray();\r
1093       end = alignment.getWidth()-1;\r
1094     }\r
1095     SeqCigar[] selseqs = new SeqCigar[iSize];\r
1096     for(i=0; i<iSize; i++)\r
1097     {\r
1098       selseqs[i] = new SeqCigar(seqs[i], start, end);\r
1099     }\r
1100     selection=new CigarArray(selseqs);\r
1101     // now construct the CigarArray operations\r
1102     if (hasHiddenColumns) {\r
1103       Vector regions = colSel.getHiddenColumns();\r
1104       int [] region;\r
1105       int hideStart, hideEnd;\r
1106       int last=start;\r
1107       for (int j = 0; last<end & j < regions.size(); j++)\r
1108       {\r
1109         region = (int[]) regions.elementAt(j);\r
1110         hideStart = region[0];\r
1111         hideEnd = region[1];\r
1112         // edit hidden regions to selection range\r
1113         if(hideStart<last) {\r
1114           if (hideEnd > last)\r
1115           {\r
1116             hideStart = last;\r
1117           } else\r
1118             continue;\r
1119         }\r
1120 \r
1121         if (hideStart>end)\r
1122           break;\r
1123 \r
1124         if (hideEnd>end)\r
1125           hideEnd=end;\r
1126 \r
1127         if (hideStart>hideEnd)\r
1128           break;\r
1129         /**\r
1130          * form operations...\r
1131          */\r
1132         if (last<hideStart)\r
1133           selection.addOperation(CigarArray.M, hideStart-last);\r
1134         selection.addOperation(CigarArray.D, 1+hideEnd-hideStart);\r
1135         last = hideEnd+1;\r
1136       }\r
1137       // Final match if necessary.\r
1138       if (last<end)\r
1139         selection.addOperation(CigarArray.M, end-last+1);\r
1140     } else {\r
1141       selection.addOperation(CigarArray.M, end-start+1);\r
1142     }\r
1143     return selection;\r
1144   }\r
1145   /**\r
1146    * return a compact representation of the current alignment selection to\r
1147    * pass to an analysis function\r
1148    * @param selectedOnly boolean true to just return the selected view\r
1149    * @return AlignmentView\r
1150    */\r
1151   jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly) {\r
1152     // JBPNote:\r
1153     // this is here because the AlignmentView constructor modifies the CigarArray\r
1154     // object. Refactoring of Cigar and alignment view representation should\r
1155     // be done to remove redundancy.\r
1156     CigarArray aligview = getViewAsCigars(selectedOnly);\r
1157     if (aligview!=null) {\r
1158       return new AlignmentView(aligview,\r
1159           (selectedOnly && selectionGroup!=null) ? selectionGroup.getStartRes() : 0);\r
1160     }\r
1161     return null;\r
1162   }\r
1163   /**\r
1164    * This method returns the visible alignment as text, as\r
1165    * seen on the GUI, ie if columns are hidden they will not\r
1166    * be returned in the result.\r
1167    * Use this for calculating trees, PCA, redundancy etc on views\r
1168    * which contain hidden columns.\r
1169    * @return String[]\r
1170    */\r
1171   public String [] getViewAsString(boolean selectedRegionOnly)\r
1172   {\r
1173     String [] selection = null;\r
1174     SequenceI [] seqs= null;\r
1175     int i, iSize;\r
1176     int start = 0, end = 0;\r
1177     if(selectedRegionOnly && selectionGroup!=null)\r
1178     {\r
1179       iSize = selectionGroup.getSize();\r
1180       seqs = selectionGroup.getSequencesInOrder(alignment);\r
1181       start = selectionGroup.getStartRes();\r
1182       end = selectionGroup.getEndRes()+1;\r
1183     }\r
1184     else\r
1185     {\r
1186       iSize = alignment.getHeight();\r
1187       seqs = alignment.getSequencesArray();\r
1188       end = alignment.getWidth();\r
1189     }\r
1190 \r
1191     selection = new String[iSize];\r
1192 \r
1193 \r
1194     for(i=0; i<iSize; i++)\r
1195     {\r
1196       if (hasHiddenColumns)\r
1197       {\r
1198            StringBuffer visibleSeq = new StringBuffer();\r
1199            Vector regions = colSel.getHiddenColumns();\r
1200 \r
1201            int blockStart = start, blockEnd=end;\r
1202            int [] region;\r
1203            int hideStart, hideEnd;\r
1204 \r
1205            for (int j = 0; j < regions.size(); j++)\r
1206            {\r
1207              region = (int[]) regions.elementAt(j);\r
1208              hideStart = region[0];\r
1209              hideEnd = region[1];\r
1210 \r
1211              if(hideStart < start)\r
1212              {\r
1213                continue;\r
1214              }\r
1215 \r
1216              blockStart = Math.min(blockStart, hideEnd+1);\r
1217              blockEnd = Math.min(blockEnd, hideStart);\r
1218 \r
1219              if(blockStart>blockEnd)\r
1220              {\r
1221                 break;\r
1222              }\r
1223 \r
1224 \r
1225              visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));\r
1226 \r
1227              blockStart = hideEnd+1;\r
1228              blockEnd = end;\r
1229            }\r
1230 \r
1231            if(end>blockStart)\r
1232              visibleSeq.append(seqs[i].getSequence(blockStart, end));\r
1233 \r
1234            selection[i] = visibleSeq.toString();\r
1235       }\r
1236       else\r
1237       {\r
1238         selection[i] = seqs[i].getSequenceAsString(start, end);\r
1239       }\r
1240     }\r
1241 \r
1242     return selection;\r
1243   }\r
1244 \r
1245   public boolean getShowHiddenMarkers()\r
1246   {\r
1247     return showHiddenMarkers;\r
1248   }\r
1249 \r
1250   public void setShowHiddenMarkers(boolean show)\r
1251   {\r
1252     showHiddenMarkers = show;\r
1253   }\r
1254 \r
1255   public Color getSequenceColour(SequenceI seq)\r
1256   {\r
1257     if (sequenceColours == null || !sequenceColours.containsKey(seq))\r
1258       return Color.white;\r
1259     else\r
1260       return (Color) sequenceColours.get(seq);\r
1261   }\r
1262 \r
1263   public void setSequenceColour(SequenceI seq, Color col)\r
1264   {\r
1265     if (sequenceColours == null)\r
1266       sequenceColours = new Hashtable();\r
1267 \r
1268     if (col == null)\r
1269       sequenceColours.remove(seq);\r
1270     else\r
1271       sequenceColours.put(seq, col);\r
1272   }\r
1273 \r
1274   public String getSequenceSetId()\r
1275   {\r
1276     if (sequenceSetID == null)\r
1277       sequenceSetID = alignment.hashCode() + "";\r
1278 \r
1279     return sequenceSetID;\r
1280   }\r
1281 \r
1282   public void alignmentChanged(AlignmentPanel ap)\r
1283   {\r
1284     alignment.padGaps();\r
1285 \r
1286     if (hconsensus != null && autocalculateConsensus)\r
1287     {\r
1288       updateConsensus(ap);\r
1289       updateConservation(ap);\r
1290     }\r
1291 \r
1292     //Reset endRes of groups if beyond alignment width\r
1293     int alWidth = alignment.getWidth();\r
1294     Vector groups = alignment.getGroups();\r
1295     if(groups!=null)\r
1296     {\r
1297       for(int i=0; i<groups.size(); i++)\r
1298       {\r
1299         SequenceGroup sg = (SequenceGroup)groups.elementAt(i);\r
1300         if(sg.getEndRes()>alWidth)\r
1301           sg.setEndRes(alWidth-1);\r
1302       }\r
1303     }\r
1304 \r
1305     if(selectionGroup!=null && selectionGroup.getEndRes()>alWidth)\r
1306       selectionGroup.setEndRes(alWidth-1);\r
1307 \r
1308     resetAllColourSchemes();\r
1309 \r
1310   //AW  alignment.adjustSequenceAnnotations();\r
1311   }\r
1312 \r
1313   void resetAllColourSchemes()\r
1314   {\r
1315     ColourSchemeI cs = globalColourScheme;\r
1316     if(cs!=null)\r
1317     {\r
1318       if (cs instanceof ClustalxColourScheme)\r
1319       {\r
1320         ( (ClustalxColourScheme) cs).\r
1321             resetClustalX(alignment.getSequences(),\r
1322                           alignment.getWidth());\r
1323       }\r
1324 \r
1325       cs.setConsensus(hconsensus);\r
1326       if (cs.conservationApplied())\r
1327       {\r
1328         Alignment al = (Alignment) alignment;\r
1329         Conservation c = new Conservation("All",\r
1330                                           ResidueProperties.propHash, 3,\r
1331                                           al.getSequences(), 0,\r
1332                                           al.getWidth() - 1);\r
1333         c.calculate();\r
1334         c.verdict(false, ConsPercGaps);\r
1335 \r
1336         cs.setConservation(c);\r
1337       }\r
1338     }\r
1339 \r
1340     int s, sSize = alignment.getGroups().size();\r
1341     for(s=0; s<sSize; s++)\r
1342     {\r
1343       SequenceGroup sg = (SequenceGroup)alignment.getGroups().elementAt(s);\r
1344       if(sg.cs!=null && sg.cs instanceof ClustalxColourScheme)\r
1345       {\r
1346         ((ClustalxColourScheme)sg.cs).resetClustalX(\r
1347             sg.getSequences(hiddenRepSequences), sg.getWidth());\r
1348       }\r
1349       sg.recalcConservation();\r
1350     }\r
1351   }\r
1352 \r
1353 \r
1354 }\r