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