7a01b274520cd95d72c9b0f51bf84d77555bb332
[jalview.git] / src / jalview / gui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /*
19  * Jalview - A Sequence Alignment Editor and Viewer
20  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
21  *
22  * This program is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU General Public License
24  * as published by the Free Software Foundation; either version 2
25  * of the License, or (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
35  */
36 package jalview.gui;
37
38 import jalview.analysis.NJTree;
39 import jalview.api.AlignViewportI;
40 import jalview.bin.Cache;
41 import jalview.datamodel.AlignmentAnnotation;
42 import jalview.datamodel.AlignmentI;
43 import jalview.datamodel.Annotation;
44 import jalview.datamodel.ColumnSelection;
45 import jalview.datamodel.PDBEntry;
46 import jalview.datamodel.Sequence;
47 import jalview.datamodel.SequenceGroup;
48 import jalview.datamodel.SequenceI;
49 import jalview.schemes.ColourSchemeProperty;
50 import jalview.schemes.UserColourScheme;
51 import jalview.structure.SelectionSource;
52 import jalview.structure.StructureSelectionManager;
53 import jalview.structure.VamsasSource;
54 import jalview.viewmodel.AlignmentViewport;
55 import jalview.ws.params.AutoCalcSetting;
56
57 import java.awt.Color;
58 import java.awt.Container;
59 import java.awt.Font;
60 import java.awt.Rectangle;
61 import java.util.ArrayList;
62 import java.util.Hashtable;
63 import java.util.Stack;
64 import java.util.Vector;
65
66 /**
67  * DOCUMENT ME!
68  * 
69  * @author $author$
70  * @version $Revision: 1.141 $
71  */
72 public class AlignViewport extends AlignmentViewport implements
73         SelectionSource, VamsasSource, AlignViewportI
74 {
75   int startRes;
76
77   int endRes;
78
79   int startSeq;
80
81   int endSeq;
82
83   boolean showJVSuffix = true;
84
85   boolean showText = true;
86
87   boolean showColourText = false;
88
89   boolean showBoxes = true;
90
91   boolean wrapAlignment = false;
92
93   boolean renderGaps = true;
94
95   boolean showSequenceFeatures = false;
96
97   boolean showAnnotation = true;
98
99   int charHeight;
100
101   int charWidth;
102
103   boolean validCharWidth;
104
105   int wrappedWidth;
106
107   Font font;
108
109   boolean seqNameItalics;
110
111   NJTree currentTree = null;
112
113   boolean scaleAboveWrapped = false;
114
115   boolean scaleLeftWrapped = true;
116
117   boolean scaleRightWrapped = true;
118
119   boolean showHiddenMarkers = true;
120
121   boolean cursorMode = false;
122
123   /**
124    * Keys are the feature types which are currently visible. Note: Values are
125    * not used!
126    */
127   Hashtable featuresDisplayed = null;
128
129   boolean antiAlias = false;
130
131   Rectangle explodedPosition;
132
133   String viewName;
134
135   boolean gatherViewsHere = false;
136
137   Stack historyList = new Stack();
138
139   Stack redoList = new Stack();
140
141   Hashtable sequenceColours;
142
143   int thresholdTextColour = 0;
144
145   Color textColour = Color.black;
146
147   Color textColour2 = Color.white;
148
149   boolean rightAlignIds = false;
150
151   /**
152    * Creates a new AlignViewport object.
153    * 
154    * @param al
155    *          alignment to view
156    */
157   public AlignViewport(AlignmentI al)
158   {
159     setAlignment(al);
160     init();
161   }
162
163   /**
164    * Create a new AlignViewport object with a specific sequence set ID
165    * 
166    * @param al
167    * @param seqsetid
168    *          (may be null - but potential for ambiguous constructor exception)
169    */
170   public AlignViewport(AlignmentI al, String seqsetid)
171   {
172     this(al, seqsetid, null);
173   }
174
175   public AlignViewport(AlignmentI al, String seqsetid, String viewid)
176   {
177     sequenceSetID = seqsetid;
178     viewId = viewid;
179     // TODO remove these once 2.4.VAMSAS release finished
180     if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
181     {
182       Cache.log.debug("Setting viewport's sequence set id : "
183               + sequenceSetID);
184     }
185     if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
186     {
187       Cache.log.debug("Setting viewport's view id : " + viewId);
188     }
189     setAlignment(al);
190     init();
191   }
192
193   /**
194    * Create a new AlignViewport with hidden regions
195    * 
196    * @param al
197    *          AlignmentI
198    * @param hiddenColumns
199    *          ColumnSelection
200    */
201   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
202   {
203     setAlignment(al);
204     if (hiddenColumns != null)
205     {
206       this.colSel = hiddenColumns;
207       if (hiddenColumns.getHiddenColumns() != null
208               && hiddenColumns.getHiddenColumns().size() > 0)
209       {
210         hasHiddenColumns = true;
211       }
212       else
213       {
214         hasHiddenColumns = false;
215       }
216     }
217     init();
218   }
219
220   /**
221    * New viewport with hidden columns and an existing sequence set id
222    * 
223    * @param al
224    * @param hiddenColumns
225    * @param seqsetid
226    *          (may be null)
227    */
228   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
229           String seqsetid)
230   {
231     this(al, hiddenColumns, seqsetid, null);
232   }
233
234   /**
235    * New viewport with hidden columns and an existing sequence set id and viewid
236    * 
237    * @param al
238    * @param hiddenColumns
239    * @param seqsetid
240    *          (may be null)
241    * @param viewid
242    *          (may be null)
243    */
244   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
245           String seqsetid, String viewid)
246   {
247     sequenceSetID = seqsetid;
248     viewId = viewid;
249     // TODO remove these once 2.4.VAMSAS release finished
250     if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
251     {
252       Cache.log.debug("Setting viewport's sequence set id : "
253               + sequenceSetID);
254     }
255     if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
256     {
257       Cache.log.debug("Setting viewport's view id : " + viewId);
258     }
259     setAlignment(al);
260     if (hiddenColumns != null)
261     {
262       this.colSel = hiddenColumns;
263       if (hiddenColumns.getHiddenColumns() != null
264               && hiddenColumns.getHiddenColumns().size() > 0)
265       {
266         hasHiddenColumns = true;
267       }
268       else
269       {
270         hasHiddenColumns = false;
271       }
272     }
273     init();
274   }
275
276   void init()
277   {
278     this.startRes = 0;
279     this.endRes = alignment.getWidth() - 1;
280     this.startSeq = 0;
281     this.endSeq = alignment.getHeight() - 1;
282
283     antiAlias = Cache.getDefault("ANTI_ALIAS", false);
284
285     showJVSuffix = Cache.getDefault("SHOW_JVSUFFIX", true);
286     showAnnotation = Cache.getDefault("SHOW_ANNOTATIONS", true);
287
288     rightAlignIds = Cache.getDefault("RIGHT_ALIGN_IDS", false);
289     centreColumnLabels = Cache.getDefault("CENTRE_COLUMN_LABELS", false);
290     autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true);
291
292     setPadGaps(Cache.getDefault("PAD_GAPS", true));
293     shownpfeats = Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true);
294     showdbrefs = Cache.getDefault("SHOW_DBREFS_TOOLTIP", true);
295
296     String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
297     String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + "");
298     String fontSize = Cache.getDefault("FONT_SIZE", "10");
299
300     seqNameItalics = Cache.getDefault("ID_ITALICS", true);
301
302     int style = 0;
303
304     if (fontStyle.equals("bold"))
305     {
306       style = 1;
307     }
308     else if (fontStyle.equals("italic"))
309     {
310       style = 2;
311     }
312
313     setFont(new Font(fontName, style, Integer.parseInt(fontSize)));
314
315     alignment
316             .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
317
318     // We must set conservation and consensus before setting colour,
319     // as Blosum and Clustal require this to be done
320     if (hconsensus == null && !isDataset)
321     {
322       if (!alignment.isNucleotide())
323       {
324         showConservation = Cache.getDefault("SHOW_CONSERVATION", true);
325         showQuality = Cache.getDefault("SHOW_QUALITY", true);
326         showGroupConservation = Cache.getDefault("SHOW_GROUP_CONSERVATION",
327                 false);
328       }
329       showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM",
330               true);
331       showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
332       normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
333               false);
334       showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
335       showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
336       consensus = new AlignmentAnnotation("Consensus", "PID",
337               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
338       consensus.hasText = true;
339       consensus.autoCalculated = true;
340     }
341     initAutoAnnotation();
342     if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null)
343     {
344       globalColourScheme = ColourSchemeProperty.getColour(alignment,
345               jalview.bin.Cache.getProperty("DEFAULT_COLOUR"));
346
347       if (globalColourScheme instanceof UserColourScheme)
348       {
349         globalColourScheme = UserDefinedColours.loadDefaultColours();
350         ((UserColourScheme) globalColourScheme).setThreshold(0,
351                 getIgnoreGapsConsensus());
352       }
353
354       if (globalColourScheme != null)
355       {
356         globalColourScheme.setConsensus(hconsensus);
357       }
358     }
359
360     wrapAlignment = jalview.bin.Cache.getDefault("WRAP_ALIGNMENT", false);
361     showUnconserved = jalview.bin.Cache.getDefault("SHOW_UNCONSERVED",
362             false);
363     sortByTree = jalview.bin.Cache.getDefault("SORT_BY_TREE", false);
364     followSelection = jalview.bin.Cache.getDefault("FOLLOW_SELECTIONS",
365             true);
366   }
367
368   /**
369    * set the flag
370    * 
371    * @param b
372    *          features are displayed if true
373    */
374   public void setShowSequenceFeatures(boolean b)
375   {
376     showSequenceFeatures = b;
377   }
378
379   public boolean getShowSequenceFeatures()
380   {
381     return showSequenceFeatures;
382   }
383
384   /**
385    * centre columnar annotation labels in displayed alignment annotation TODO:
386    * add to jalviewXML and annotation display settings
387    */
388   boolean centreColumnLabels = false;
389
390   private boolean showdbrefs;
391
392   private boolean shownpfeats;
393
394   // --------END Structure Conservation
395
396   /**
397    * get the consensus sequence as displayed under the PID consensus annotation
398    * row.
399    * 
400    * @return consensus sequence as a new sequence object
401    */
402   public SequenceI getConsensusSeq()
403   {
404     if (consensus == null)
405     {
406       updateConsensus(null);
407     }
408     if (consensus == null)
409     {
410       return null;
411     }
412     StringBuffer seqs = new StringBuffer();
413     for (int i = 0; i < consensus.annotations.length; i++)
414     {
415       if (consensus.annotations[i] != null)
416       {
417         if (consensus.annotations[i].description.charAt(0) == '[')
418         {
419           seqs.append(consensus.annotations[i].description.charAt(1));
420         }
421         else
422         {
423           seqs.append(consensus.annotations[i].displayCharacter);
424         }
425       }
426     }
427
428     SequenceI sq = new Sequence("Consensus", seqs.toString());
429     sq.setDescription("Percentage Identity Consensus "
430             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
431     return sq;
432   }
433
434   /**
435    * DOCUMENT ME!
436    * 
437    * @return DOCUMENT ME!
438    */
439   public int getStartRes()
440   {
441     return startRes;
442   }
443
444   /**
445    * DOCUMENT ME!
446    * 
447    * @return DOCUMENT ME!
448    */
449   public int getEndRes()
450   {
451     return endRes;
452   }
453
454   /**
455    * DOCUMENT ME!
456    * 
457    * @return DOCUMENT ME!
458    */
459   public int getStartSeq()
460   {
461     return startSeq;
462   }
463
464   /**
465    * DOCUMENT ME!
466    * 
467    * @param res
468    *          DOCUMENT ME!
469    */
470   public void setStartRes(int res)
471   {
472     this.startRes = res;
473   }
474
475   /**
476    * DOCUMENT ME!
477    * 
478    * @param seq
479    *          DOCUMENT ME!
480    */
481   public void setStartSeq(int seq)
482   {
483     this.startSeq = seq;
484   }
485
486   /**
487    * DOCUMENT ME!
488    * 
489    * @param res
490    *          DOCUMENT ME!
491    */
492   public void setEndRes(int res)
493   {
494     if (res > (alignment.getWidth() - 1))
495     {
496       // log.System.out.println(" Corrected res from " + res + " to maximum " +
497       // (alignment.getWidth()-1));
498       res = alignment.getWidth() - 1;
499     }
500
501     if (res < 0)
502     {
503       res = 0;
504     }
505
506     this.endRes = res;
507   }
508
509   /**
510    * DOCUMENT ME!
511    * 
512    * @param seq
513    *          DOCUMENT ME!
514    */
515   public void setEndSeq(int seq)
516   {
517     if (seq > alignment.getHeight())
518     {
519       seq = alignment.getHeight();
520     }
521
522     if (seq < 0)
523     {
524       seq = 0;
525     }
526
527     this.endSeq = seq;
528   }
529
530   /**
531    * DOCUMENT ME!
532    * 
533    * @return DOCUMENT ME!
534    */
535   public int getEndSeq()
536   {
537     return endSeq;
538   }
539
540   /**
541    * DOCUMENT ME!
542    * 
543    * @param f
544    *          DOCUMENT ME!
545    */
546   public void setFont(Font f)
547   {
548     font = f;
549
550     Container c = new Container();
551
552     java.awt.FontMetrics fm = c.getFontMetrics(font);
553     setCharHeight(fm.getHeight());
554     setCharWidth(fm.charWidth('M'));
555     validCharWidth = true;
556   }
557
558   /**
559    * DOCUMENT ME!
560    * 
561    * @return DOCUMENT ME!
562    */
563   public Font getFont()
564   {
565     return font;
566   }
567
568   /**
569    * DOCUMENT ME!
570    * 
571    * @param w
572    *          DOCUMENT ME!
573    */
574   public void setCharWidth(int w)
575   {
576     this.charWidth = w;
577   }
578
579   /**
580    * DOCUMENT ME!
581    * 
582    * @return DOCUMENT ME!
583    */
584   public int getCharWidth()
585   {
586     return charWidth;
587   }
588
589   /**
590    * DOCUMENT ME!
591    * 
592    * @param h
593    *          DOCUMENT ME!
594    */
595   public void setCharHeight(int h)
596   {
597     this.charHeight = h;
598   }
599
600   /**
601    * DOCUMENT ME!
602    * 
603    * @return DOCUMENT ME!
604    */
605   public int getCharHeight()
606   {
607     return charHeight;
608   }
609
610   /**
611    * DOCUMENT ME!
612    * 
613    * @param w
614    *          DOCUMENT ME!
615    */
616   public void setWrappedWidth(int w)
617   {
618     this.wrappedWidth = w;
619   }
620
621   /**
622    * DOCUMENT ME!
623    * 
624    * @return DOCUMENT ME!
625    */
626   public int getWrappedWidth()
627   {
628     return wrappedWidth;
629   }
630
631   /**
632    * DOCUMENT ME!
633    * 
634    * @return DOCUMENT ME!
635    */
636   public AlignmentI getAlignment()
637   {
638     return alignment;
639   }
640
641   /**
642    * DOCUMENT ME!
643    * 
644    * @param align
645    *          DOCUMENT ME!
646    */
647   public void setAlignment(AlignmentI align)
648   {
649     if (alignment != null && alignment.getCodonFrames() != null)
650     {
651       StructureSelectionManager.getStructureSelectionManager(
652               Desktop.instance).removeMappings(alignment.getCodonFrames());
653     }
654     this.alignment = align;
655     if (alignment != null && alignment.getCodonFrames() != null)
656     {
657       StructureSelectionManager.getStructureSelectionManager(
658               Desktop.instance).addMappings(alignment.getCodonFrames());
659     }
660   }
661
662   /**
663    * DOCUMENT ME!
664    * 
665    * @param state
666    *          DOCUMENT ME!
667    */
668   public void setWrapAlignment(boolean state)
669   {
670     wrapAlignment = state;
671   }
672
673   /**
674    * DOCUMENT ME!
675    * 
676    * @param state
677    *          DOCUMENT ME!
678    */
679   public void setShowText(boolean state)
680   {
681     showText = state;
682   }
683
684   /**
685    * DOCUMENT ME!
686    * 
687    * @param state
688    *          DOCUMENT ME!
689    */
690   public void setRenderGaps(boolean state)
691   {
692     renderGaps = state;
693   }
694
695   /**
696    * DOCUMENT ME!
697    * 
698    * @return DOCUMENT ME!
699    */
700   public boolean getColourText()
701   {
702     return showColourText;
703   }
704
705   /**
706    * DOCUMENT ME!
707    * 
708    * @param state
709    *          DOCUMENT ME!
710    */
711   public void setColourText(boolean state)
712   {
713     showColourText = state;
714   }
715
716   /**
717    * DOCUMENT ME!
718    * 
719    * @param state
720    *          DOCUMENT ME!
721    */
722   public void setShowBoxes(boolean state)
723   {
724     showBoxes = state;
725   }
726
727   /**
728    * DOCUMENT ME!
729    * 
730    * @return DOCUMENT ME!
731    */
732   public boolean getWrapAlignment()
733   {
734     return wrapAlignment;
735   }
736
737   /**
738    * DOCUMENT ME!
739    * 
740    * @return DOCUMENT ME!
741    */
742   public boolean getShowText()
743   {
744     return showText;
745   }
746
747   /**
748    * DOCUMENT ME!
749    * 
750    * @return DOCUMENT ME!
751    */
752   public boolean getShowBoxes()
753   {
754     return showBoxes;
755   }
756
757   /**
758    * DOCUMENT ME!
759    * 
760    * @return DOCUMENT ME!
761    */
762   public char getGapCharacter()
763   {
764     return getAlignment().getGapCharacter();
765   }
766
767   /**
768    * DOCUMENT ME!
769    * 
770    * @param gap
771    *          DOCUMENT ME!
772    */
773   public void setGapCharacter(char gap)
774   {
775     if (getAlignment() != null)
776     {
777       getAlignment().setGapCharacter(gap);
778     }
779   }
780
781   /**
782    * DOCUMENT ME!
783    * 
784    * @return DOCUMENT ME!
785    */
786   public ColumnSelection getColumnSelection()
787   {
788     return colSel;
789   }
790
791   /**
792    * DOCUMENT ME!
793    * 
794    * @param tree
795    *          DOCUMENT ME!
796    */
797   public void setCurrentTree(NJTree tree)
798   {
799     currentTree = tree;
800   }
801
802   /**
803    * DOCUMENT ME!
804    * 
805    * @return DOCUMENT ME!
806    */
807   public NJTree getCurrentTree()
808   {
809     return currentTree;
810   }
811
812   /**
813    * DOCUMENT ME!
814    * 
815    * @return DOCUMENT ME!
816    */
817   public boolean getShowJVSuffix()
818   {
819     return showJVSuffix;
820   }
821
822   /**
823    * DOCUMENT ME!
824    * 
825    * @param b
826    *          DOCUMENT ME!
827    */
828   public void setShowJVSuffix(boolean b)
829   {
830     showJVSuffix = b;
831   }
832
833   /**
834    * DOCUMENT ME!
835    * 
836    * @return DOCUMENT ME!
837    */
838   public boolean getShowAnnotation()
839   {
840     return showAnnotation;
841   }
842
843   /**
844    * DOCUMENT ME!
845    * 
846    * @param b
847    *          DOCUMENT ME!
848    */
849   public void setShowAnnotation(boolean b)
850   {
851     showAnnotation = b;
852   }
853
854   /**
855    * DOCUMENT ME!
856    * 
857    * @return DOCUMENT ME!
858    */
859   public boolean getScaleAboveWrapped()
860   {
861     return scaleAboveWrapped;
862   }
863
864   /**
865    * DOCUMENT ME!
866    * 
867    * @return DOCUMENT ME!
868    */
869   public boolean getScaleLeftWrapped()
870   {
871     return scaleLeftWrapped;
872   }
873
874   /**
875    * DOCUMENT ME!
876    * 
877    * @return DOCUMENT ME!
878    */
879   public boolean getScaleRightWrapped()
880   {
881     return scaleRightWrapped;
882   }
883
884   /**
885    * DOCUMENT ME!
886    * 
887    * @param b
888    *          DOCUMENT ME!
889    */
890   public void setScaleAboveWrapped(boolean b)
891   {
892     scaleAboveWrapped = b;
893   }
894
895   /**
896    * DOCUMENT ME!
897    * 
898    * @param b
899    *          DOCUMENT ME!
900    */
901   public void setScaleLeftWrapped(boolean b)
902   {
903     scaleLeftWrapped = b;
904   }
905
906   /**
907    * DOCUMENT ME!
908    * 
909    * @param b
910    *          DOCUMENT ME!
911    */
912   public void setScaleRightWrapped(boolean b)
913   {
914     scaleRightWrapped = b;
915   }
916
917   public void setDataset(boolean b)
918   {
919     isDataset = b;
920   }
921
922   public boolean isDataset()
923   {
924     return isDataset;
925   }
926
927   public boolean getShowHiddenMarkers()
928   {
929     return showHiddenMarkers;
930   }
931
932   public void setShowHiddenMarkers(boolean show)
933   {
934     showHiddenMarkers = show;
935   }
936
937   public Color getSequenceColour(SequenceI seq)
938   {
939     if (sequenceColours == null || !sequenceColours.containsKey(seq))
940     {
941       return Color.white;
942     }
943     else
944     {
945       return (Color) sequenceColours.get(seq);
946     }
947   }
948
949   public void setSequenceColour(SequenceI seq, Color col)
950   {
951     if (sequenceColours == null)
952     {
953       sequenceColours = new Hashtable();
954     }
955
956     if (col == null)
957     {
958       sequenceColours.remove(seq);
959     }
960     else
961     {
962       sequenceColours.put(seq, col);
963     }
964   }
965
966   /**
967    * returns the visible column regions of the alignment
968    * 
969    * @param selectedRegionOnly
970    *          true to just return the contigs intersecting with the selected
971    *          area
972    * @return
973    */
974   public int[] getViewAsVisibleContigs(boolean selectedRegionOnly)
975   {
976     int[] viscontigs = null;
977     int start = 0, end = 0;
978     if (selectedRegionOnly && selectionGroup != null)
979     {
980       start = selectionGroup.getStartRes();
981       end = selectionGroup.getEndRes() + 1;
982     }
983     else
984     {
985       end = alignment.getWidth();
986     }
987     viscontigs = colSel.getVisibleContigs(start, end);
988     return viscontigs;
989   }
990
991   /**
992    * get hash of undo and redo list for the alignment
993    * 
994    * @return long[] { historyList.hashCode, redoList.hashCode };
995    */
996   public long[] getUndoRedoHash()
997   {
998     // TODO: JAL-1126
999     if (historyList == null || redoList == null)
1000       return new long[]
1001       { -1, -1 };
1002     return new long[]
1003     { historyList.hashCode(), this.redoList.hashCode() };
1004   }
1005
1006   /**
1007    * test if a particular set of hashcodes are different to the hashcodes for
1008    * the undo and redo list.
1009    * 
1010    * @param undoredo
1011    *          the stored set of hashcodes as returned by getUndoRedoHash
1012    * @return true if the hashcodes differ (ie the alignment has been edited) or
1013    *         the stored hashcode array differs in size
1014    */
1015   public boolean isUndoRedoHashModified(long[] undoredo)
1016   {
1017     if (undoredo == null)
1018     {
1019       return true;
1020     }
1021     long[] cstate = getUndoRedoHash();
1022     if (cstate.length != undoredo.length)
1023     {
1024       return true;
1025     }
1026
1027     for (int i = 0; i < cstate.length; i++)
1028     {
1029       if (cstate[i] != undoredo[i])
1030       {
1031         return true;
1032       }
1033     }
1034     return false;
1035   }
1036
1037   public boolean getCentreColumnLabels()
1038   {
1039     return centreColumnLabels;
1040   }
1041
1042   public void setCentreColumnLabels(boolean centrecolumnlabels)
1043   {
1044     centreColumnLabels = centrecolumnlabels;
1045   }
1046
1047   public void updateSequenceIdColours()
1048   {
1049     if (sequenceColours == null)
1050     {
1051       sequenceColours = new Hashtable();
1052     }
1053     for (SequenceGroup sg : alignment.getGroups())
1054     {
1055       if (sg.idColour != null)
1056       {
1057         for (SequenceI s : sg.getSequences(getHiddenRepSequences()))
1058         {
1059           sequenceColours.put(s, sg.idColour);
1060         }
1061       }
1062     }
1063   }
1064
1065   /**
1066    * enable or disable the display of Database Cross References in the sequence
1067    * ID tooltip
1068    */
1069   public void setShowDbRefs(boolean show)
1070   {
1071     showdbrefs = show;
1072   }
1073
1074   /**
1075    * 
1076    * @return true if Database References are to be displayed on tooltips.
1077    */
1078   public boolean isShowDbRefs()
1079   {
1080     return showdbrefs;
1081   }
1082
1083   /**
1084    * 
1085    * @return true if Non-positional features are to be displayed on tooltips.
1086    */
1087   public boolean isShowNpFeats()
1088   {
1089     return shownpfeats;
1090   }
1091
1092   /**
1093    * enable or disable the display of Non-Positional sequence features in the
1094    * sequence ID tooltip
1095    * 
1096    * @param show
1097    */
1098   public void setShowNpFeats(boolean show)
1099   {
1100     shownpfeats = show;
1101   }
1102
1103   /**
1104    * 
1105    * @return true if view has hidden rows
1106    */
1107   public boolean hasHiddenRows()
1108   {
1109     return hasHiddenRows;
1110   }
1111
1112   /**
1113    * 
1114    * @return true if view has hidden columns
1115    */
1116   public boolean hasHiddenColumns()
1117   {
1118     return hasHiddenColumns;
1119   }
1120
1121   /**
1122    * when set, view will scroll to show the highlighted position
1123    */
1124   public boolean followHighlight = true;
1125
1126   /**
1127    * @return true if view should scroll to show the highlighted region of a
1128    *         sequence
1129    * @return
1130    */
1131   public boolean getFollowHighlight()
1132   {
1133     return followHighlight;
1134   }
1135
1136   public boolean followSelection = true;
1137
1138   /**
1139    * @return true if view selection should always follow the selections
1140    *         broadcast by other selection sources
1141    */
1142   public boolean getFollowSelection()
1143   {
1144     return followSelection;
1145   }
1146
1147   boolean showSeqFeaturesHeight;
1148
1149   public void sendSelection()
1150   {
1151     jalview.structure.StructureSelectionManager
1152             .getStructureSelectionManager(Desktop.instance).sendSelection(
1153                     new SequenceGroup(getSelectionGroup()),
1154                     new ColumnSelection(getColumnSelection()), this);
1155   }
1156
1157   public void setShowSequenceFeaturesHeight(boolean selected)
1158   {
1159     showSeqFeaturesHeight = selected;
1160   }
1161
1162   public boolean getShowSequenceFeaturesHeight()
1163   {
1164     return showSeqFeaturesHeight;
1165   }
1166
1167   /**
1168    * return the alignPanel containing the given viewport. Use this to get the
1169    * components currently handling the given viewport.
1170    * 
1171    * @param av
1172    * @return null or an alignPanel guaranteed to have non-null alignFrame
1173    *         reference
1174    */
1175   public AlignmentPanel getAlignPanel()
1176   {
1177     AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this
1178             .getSequenceSetId());
1179     AlignmentPanel ap = null;
1180     for (int p = 0; aps != null && p < aps.length; p++)
1181     {
1182       if (aps[p].av == this)
1183       {
1184         return aps[p];
1185       }
1186     }
1187     return null;
1188   }
1189
1190   public boolean getSortByTree()
1191   {
1192     return sortByTree;
1193   }
1194
1195   public void setSortByTree(boolean sort)
1196   {
1197     sortByTree = sort;
1198   }
1199
1200   /**
1201    * synthesize a column selection if none exists so it covers the given
1202    * selection group. if wholewidth is false, no column selection is made if the
1203    * selection group covers the whole alignment width.
1204    * 
1205    * @param sg
1206    * @param wholewidth
1207    */
1208   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
1209   {
1210     int sgs, sge;
1211     if (sg != null
1212             && (sgs = sg.getStartRes()) >= 0
1213             && sg.getStartRes() <= (sge = sg.getEndRes())
1214             && (colSel == null || colSel.getSelected() == null || colSel
1215                     .getSelected().size() == 0))
1216     {
1217       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
1218       {
1219         // do nothing
1220         return;
1221       }
1222       if (colSel == null)
1223       {
1224         colSel = new ColumnSelection();
1225       }
1226       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
1227       {
1228         colSel.addElement(cspos);
1229       }
1230     }
1231   }
1232
1233   public StructureSelectionManager getStructureSelectionManager()
1234   {
1235     return StructureSelectionManager
1236             .getStructureSelectionManager(Desktop.instance);
1237   }
1238
1239   /**
1240    * 
1241    * @param pdbEntries
1242    * @return a series of SequenceI arrays, one for each PDBEntry, listing which
1243    *         sequence in the alignment holds a reference to it
1244    */
1245   public SequenceI[][] collateForPDB(PDBEntry[] pdbEntries)
1246   {
1247     ArrayList<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
1248     for (PDBEntry pdb : pdbEntries)
1249     {
1250       ArrayList<SequenceI> seqs = new ArrayList<SequenceI>();
1251       for (int i = 0; i < alignment.getHeight(); i++)
1252       {
1253         Vector pdbs = alignment.getSequenceAt(i).getDatasetSequence()
1254                 .getPDBId();
1255         if (pdbs == null)
1256           continue;
1257         SequenceI sq;
1258         for (int p = 0; p < pdbs.size(); p++)
1259         {
1260           PDBEntry p1 = (PDBEntry) pdbs.elementAt(p);
1261           if (p1.getId().equals(pdb.getId()))
1262           {
1263             if (!seqs.contains(sq = alignment.getSequenceAt(i)))
1264               seqs.add(sq);
1265
1266             continue;
1267           }
1268         }
1269       }
1270       seqvectors.add(seqs.toArray(new SequenceI[seqs.size()]));
1271     }
1272     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
1273   }
1274
1275   public boolean isNormaliseSequenceLogo()
1276   {
1277     return normaliseSequenceLogo;
1278   }
1279
1280   public void setNormaliseSequenceLogo(boolean state)
1281   {
1282     normaliseSequenceLogo = state;
1283   }
1284
1285   /**
1286    * 
1287    * @return true if alignment characters should be displayed
1288    */
1289   public boolean isValidCharWidth()
1290   {
1291     return validCharWidth;
1292   }
1293
1294   private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<String, AutoCalcSetting>();
1295
1296   public AutoCalcSetting getCalcIdSettingsFor(String calcId)
1297   {
1298     return calcIdParams.get(calcId);
1299   }
1300
1301   public void setCalcIdSettingsFor(String calcId, AutoCalcSetting settings,
1302           boolean needsUpdate)
1303   {
1304     calcIdParams.put(calcId, settings);
1305     // TODO: create a restart list to trigger any calculations that need to be
1306     // restarted after load
1307     // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
1308     if (needsUpdate)
1309     {
1310       Cache.log.debug("trigger update for " + calcId);
1311     }
1312   }
1313 }