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