5c383d868edd485616e413a6f1cfe042f421fbbe
[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.datamodel.AlignmentAnnotation;
46 import jalview.datamodel.AlignmentI;
47 import jalview.datamodel.Annotation;
48 import jalview.datamodel.ColumnSelection;
49 import jalview.datamodel.PDBEntry;
50 import jalview.datamodel.Sequence;
51 import jalview.datamodel.SequenceGroup;
52 import jalview.datamodel.SequenceI;
53 import jalview.schemes.ColourSchemeProperty;
54 import jalview.schemes.UserColourScheme;
55 import jalview.structure.SelectionSource;
56 import jalview.structure.StructureSelectionManager;
57 import jalview.structure.VamsasSource;
58 import jalview.viewmodel.AlignmentViewport;
59 import jalview.ws.params.AutoCalcSetting;
60
61 import java.awt.Color;
62 import java.awt.Container;
63 import java.awt.Font;
64 import java.awt.Rectangle;
65 import java.util.ArrayList;
66 import java.util.Hashtable;
67 import java.util.Stack;
68 import java.util.Vector;
69
70 /**
71  * DOCUMENT ME!
72  * 
73  * @author $author$
74  * @version $Revision: 1.141 $
75  */
76 public class AlignViewport extends AlignmentViewport implements
77         SelectionSource, VamsasSource, AlignViewportI
78 {
79   int startRes;
80
81   int endRes;
82
83   int startSeq;
84
85   int endSeq;
86
87   boolean showJVSuffix = true;
88
89   boolean showText = true;
90
91   boolean showColourText = false;
92
93   boolean showBoxes = true;
94
95   boolean wrapAlignment = false;
96
97   boolean renderGaps = true;
98
99   boolean showSequenceFeatures = false;
100
101   boolean showAnnotation = true;
102
103   SequenceAnnotationOrder sortAnnotationsBy = null;
104
105   int charHeight;
106
107   int charWidth;
108
109   boolean validCharWidth;
110
111   int wrappedWidth;
112
113   Font font;
114
115   boolean seqNameItalics;
116
117   NJTree currentTree = null;
118
119   boolean scaleAboveWrapped = false;
120
121   boolean scaleLeftWrapped = true;
122
123   boolean scaleRightWrapped = true;
124
125   boolean showHiddenMarkers = true;
126
127   boolean cursorMode = false;
128
129   /**
130    * Keys are the feature types which are currently visible. Note: Values are
131    * not used!
132    */
133   Hashtable featuresDisplayed = null;
134
135   boolean antiAlias = false;
136
137   Rectangle explodedPosition;
138
139   String viewName;
140
141   boolean gatherViewsHere = false;
142
143   Stack historyList = new Stack();
144
145   Stack redoList = new Stack();
146
147   int thresholdTextColour = 0;
148
149   Color textColour = Color.black;
150
151   Color textColour2 = Color.white;
152
153   boolean rightAlignIds = false;
154
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     showAnnotation = Cache.getDefault("SHOW_ANNOTATIONS", true);
291
292     rightAlignIds = 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       consensus = new AlignmentAnnotation("Consensus", "PID",
341               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
342       consensus.hasText = true;
343       consensus.autoCalculated = true;
344     }
345     initAutoAnnotation();
346     if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null)
347     {
348       globalColourScheme = ColourSchemeProperty.getColour(alignment,
349               jalview.bin.Cache.getProperty("DEFAULT_COLOUR"));
350
351       if (globalColourScheme instanceof UserColourScheme)
352       {
353         globalColourScheme = UserDefinedColours.loadDefaultColours();
354         ((UserColourScheme) globalColourScheme).setThreshold(0,
355                 getIgnoreGapsConsensus());
356       }
357
358       if (globalColourScheme != null)
359       {
360         globalColourScheme.setConsensus(hconsensus);
361       }
362     }
363
364     wrapAlignment = Cache.getDefault("WRAP_ALIGNMENT", false);
365     showUnconserved = Cache.getDefault("SHOW_UNCONSERVED", false);
366     sortByTree = Cache.getDefault("SORT_BY_TREE", false);
367     followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true);
368     sortAnnotationsBy = SequenceAnnotationOrder.valueOf(Cache.getDefault(
369             Preferences.SORT_ANNOTATIONS,
370             SequenceAnnotationOrder.NONE.name()));
371     showAutocalculatedAbove = Cache.getDefault(
372             Preferences.SHOW_AUTOCALC_ABOVE, false);
373   }
374
375   /**
376    * set the flag
377    * 
378    * @param b
379    *          features are displayed if true
380    */
381   public void setShowSequenceFeatures(boolean b)
382   {
383     showSequenceFeatures = b;
384   }
385
386   public boolean getShowSequenceFeatures()
387   {
388     return showSequenceFeatures;
389   }
390
391   /**
392    * centre columnar annotation labels in displayed alignment annotation TODO:
393    * add to jalviewXML and annotation display settings
394    */
395   boolean centreColumnLabels = false;
396
397   private boolean showdbrefs;
398
399   private boolean shownpfeats;
400
401   // --------END Structure Conservation
402
403   /**
404    * get the consensus sequence as displayed under the PID consensus annotation
405    * row.
406    * 
407    * @return consensus sequence as a new sequence object
408    */
409   public SequenceI getConsensusSeq()
410   {
411     if (consensus == null)
412     {
413       updateConsensus(null);
414     }
415     if (consensus == null)
416     {
417       return null;
418     }
419     StringBuffer seqs = new StringBuffer();
420     for (int i = 0; i < consensus.annotations.length; i++)
421     {
422       if (consensus.annotations[i] != null)
423       {
424         if (consensus.annotations[i].description.charAt(0) == '[')
425         {
426           seqs.append(consensus.annotations[i].description.charAt(1));
427         }
428         else
429         {
430           seqs.append(consensus.annotations[i].displayCharacter);
431         }
432       }
433     }
434
435     SequenceI sq = new Sequence("Consensus", seqs.toString());
436     sq.setDescription("Percentage Identity Consensus "
437             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
438     return sq;
439   }
440
441   /**
442    * DOCUMENT ME!
443    * 
444    * @return DOCUMENT ME!
445    */
446   public int getStartRes()
447   {
448     return startRes;
449   }
450
451   /**
452    * DOCUMENT ME!
453    * 
454    * @return DOCUMENT ME!
455    */
456   public int getEndRes()
457   {
458     return endRes;
459   }
460
461   /**
462    * DOCUMENT ME!
463    * 
464    * @return DOCUMENT ME!
465    */
466   public int getStartSeq()
467   {
468     return startSeq;
469   }
470
471   /**
472    * DOCUMENT ME!
473    * 
474    * @param res
475    *          DOCUMENT ME!
476    */
477   public void setStartRes(int res)
478   {
479     this.startRes = res;
480   }
481
482   /**
483    * DOCUMENT ME!
484    * 
485    * @param seq
486    *          DOCUMENT ME!
487    */
488   public void setStartSeq(int seq)
489   {
490     this.startSeq = seq;
491   }
492
493   /**
494    * DOCUMENT ME!
495    * 
496    * @param res
497    *          DOCUMENT ME!
498    */
499   public void setEndRes(int res)
500   {
501     if (res > (alignment.getWidth() - 1))
502     {
503       // log.System.out.println(" Corrected res from " + res + " to maximum " +
504       // (alignment.getWidth()-1));
505       res = alignment.getWidth() - 1;
506     }
507
508     if (res < 0)
509     {
510       res = 0;
511     }
512
513     this.endRes = res;
514   }
515
516   /**
517    * DOCUMENT ME!
518    * 
519    * @param seq
520    *          DOCUMENT ME!
521    */
522   public void setEndSeq(int seq)
523   {
524     if (seq > alignment.getHeight())
525     {
526       seq = alignment.getHeight();
527     }
528
529     if (seq < 0)
530     {
531       seq = 0;
532     }
533
534     this.endSeq = seq;
535   }
536
537   /**
538    * DOCUMENT ME!
539    * 
540    * @return DOCUMENT ME!
541    */
542   public int getEndSeq()
543   {
544     return endSeq;
545   }
546
547   /**
548    * DOCUMENT ME!
549    * 
550    * @param f
551    *          DOCUMENT ME!
552    */
553   public void setFont(Font f)
554   {
555     font = f;
556
557     Container c = new Container();
558
559     java.awt.FontMetrics fm = c.getFontMetrics(font);
560     setCharHeight(fm.getHeight());
561     setCharWidth(fm.charWidth('M'));
562     validCharWidth = true;
563   }
564
565   /**
566    * DOCUMENT ME!
567    * 
568    * @return DOCUMENT ME!
569    */
570   public Font getFont()
571   {
572     return font;
573   }
574
575   /**
576    * DOCUMENT ME!
577    * 
578    * @param w
579    *          DOCUMENT ME!
580    */
581   public void setCharWidth(int w)
582   {
583     this.charWidth = w;
584   }
585
586   /**
587    * DOCUMENT ME!
588    * 
589    * @return DOCUMENT ME!
590    */
591   public int getCharWidth()
592   {
593     return charWidth;
594   }
595
596   /**
597    * DOCUMENT ME!
598    * 
599    * @param h
600    *          DOCUMENT ME!
601    */
602   public void setCharHeight(int h)
603   {
604     this.charHeight = h;
605   }
606
607   /**
608    * DOCUMENT ME!
609    * 
610    * @return DOCUMENT ME!
611    */
612   public int getCharHeight()
613   {
614     return charHeight;
615   }
616
617   /**
618    * DOCUMENT ME!
619    * 
620    * @param w
621    *          DOCUMENT ME!
622    */
623   public void setWrappedWidth(int w)
624   {
625     this.wrappedWidth = w;
626   }
627
628   /**
629    * DOCUMENT ME!
630    * 
631    * @return DOCUMENT ME!
632    */
633   public int getWrappedWidth()
634   {
635     return wrappedWidth;
636   }
637
638   /**
639    * DOCUMENT ME!
640    * 
641    * @return DOCUMENT ME!
642    */
643   public AlignmentI getAlignment()
644   {
645     return alignment;
646   }
647
648   /**
649    * DOCUMENT ME!
650    * 
651    * @param align
652    *          DOCUMENT ME!
653    */
654   public void setAlignment(AlignmentI align)
655   {
656     if (alignment != null && alignment.getCodonFrames() != null)
657     {
658       StructureSelectionManager.getStructureSelectionManager(
659               Desktop.instance).removeMappings(alignment.getCodonFrames());
660     }
661     this.alignment = align;
662     if (alignment != null && alignment.getCodonFrames() != null)
663     {
664       StructureSelectionManager.getStructureSelectionManager(
665               Desktop.instance).addMappings(alignment.getCodonFrames());
666     }
667   }
668
669   /**
670    * DOCUMENT ME!
671    * 
672    * @param state
673    *          DOCUMENT ME!
674    */
675   public void setWrapAlignment(boolean state)
676   {
677     wrapAlignment = state;
678   }
679
680   /**
681    * DOCUMENT ME!
682    * 
683    * @param state
684    *          DOCUMENT ME!
685    */
686   public void setShowText(boolean state)
687   {
688     showText = state;
689   }
690
691   /**
692    * DOCUMENT ME!
693    * 
694    * @param state
695    *          DOCUMENT ME!
696    */
697   public void setRenderGaps(boolean state)
698   {
699     renderGaps = state;
700   }
701
702   /**
703    * DOCUMENT ME!
704    * 
705    * @return DOCUMENT ME!
706    */
707   public boolean getColourText()
708   {
709     return showColourText;
710   }
711
712   /**
713    * DOCUMENT ME!
714    * 
715    * @param state
716    *          DOCUMENT ME!
717    */
718   public void setColourText(boolean state)
719   {
720     showColourText = state;
721   }
722
723   /**
724    * DOCUMENT ME!
725    * 
726    * @param state
727    *          DOCUMENT ME!
728    */
729   public void setShowBoxes(boolean state)
730   {
731     showBoxes = state;
732   }
733
734   /**
735    * DOCUMENT ME!
736    * 
737    * @return DOCUMENT ME!
738    */
739   public boolean getWrapAlignment()
740   {
741     return wrapAlignment;
742   }
743
744   /**
745    * DOCUMENT ME!
746    * 
747    * @return DOCUMENT ME!
748    */
749   public boolean getShowText()
750   {
751     return showText;
752   }
753
754   /**
755    * DOCUMENT ME!
756    * 
757    * @return DOCUMENT ME!
758    */
759   public boolean getShowBoxes()
760   {
761     return showBoxes;
762   }
763
764   /**
765    * DOCUMENT ME!
766    * 
767    * @return DOCUMENT ME!
768    */
769   public char getGapCharacter()
770   {
771     return getAlignment().getGapCharacter();
772   }
773
774   /**
775    * DOCUMENT ME!
776    * 
777    * @param gap
778    *          DOCUMENT ME!
779    */
780   public void setGapCharacter(char gap)
781   {
782     if (getAlignment() != null)
783     {
784       getAlignment().setGapCharacter(gap);
785     }
786   }
787
788   /**
789    * DOCUMENT ME!
790    * 
791    * @return DOCUMENT ME!
792    */
793   public ColumnSelection getColumnSelection()
794   {
795     return colSel;
796   }
797
798   /**
799    * DOCUMENT ME!
800    * 
801    * @param tree
802    *          DOCUMENT ME!
803    */
804   public void setCurrentTree(NJTree tree)
805   {
806     currentTree = tree;
807   }
808
809   /**
810    * DOCUMENT ME!
811    * 
812    * @return DOCUMENT ME!
813    */
814   public NJTree getCurrentTree()
815   {
816     return currentTree;
817   }
818
819   /**
820    * DOCUMENT ME!
821    * 
822    * @return DOCUMENT ME!
823    */
824   public boolean getShowJVSuffix()
825   {
826     return showJVSuffix;
827   }
828
829   /**
830    * DOCUMENT ME!
831    * 
832    * @param b
833    *          DOCUMENT ME!
834    */
835   public void setShowJVSuffix(boolean b)
836   {
837     showJVSuffix = b;
838   }
839
840   /**
841    * DOCUMENT ME!
842    * 
843    * @return DOCUMENT ME!
844    */
845   public boolean getShowAnnotation()
846   {
847     return showAnnotation;
848   }
849
850   /**
851    * DOCUMENT ME!
852    * 
853    * @param b
854    *          DOCUMENT ME!
855    */
856   public void setShowAnnotation(boolean b)
857   {
858     showAnnotation = b;
859   }
860
861   /**
862    * DOCUMENT ME!
863    * 
864    * @return DOCUMENT ME!
865    */
866   public boolean getScaleAboveWrapped()
867   {
868     return scaleAboveWrapped;
869   }
870
871   /**
872    * DOCUMENT ME!
873    * 
874    * @return DOCUMENT ME!
875    */
876   public boolean getScaleLeftWrapped()
877   {
878     return scaleLeftWrapped;
879   }
880
881   /**
882    * DOCUMENT ME!
883    * 
884    * @return DOCUMENT ME!
885    */
886   public boolean getScaleRightWrapped()
887   {
888     return scaleRightWrapped;
889   }
890
891   /**
892    * DOCUMENT ME!
893    * 
894    * @param b
895    *          DOCUMENT ME!
896    */
897   public void setScaleAboveWrapped(boolean b)
898   {
899     scaleAboveWrapped = b;
900   }
901
902   /**
903    * DOCUMENT ME!
904    * 
905    * @param b
906    *          DOCUMENT ME!
907    */
908   public void setScaleLeftWrapped(boolean b)
909   {
910     scaleLeftWrapped = b;
911   }
912
913   /**
914    * DOCUMENT ME!
915    * 
916    * @param b
917    *          DOCUMENT ME!
918    */
919   public void setScaleRightWrapped(boolean b)
920   {
921     scaleRightWrapped = b;
922   }
923
924   public void setDataset(boolean b)
925   {
926     isDataset = b;
927   }
928
929   public boolean isDataset()
930   {
931     return isDataset;
932   }
933
934   public boolean getShowHiddenMarkers()
935   {
936     return showHiddenMarkers;
937   }
938
939   public void setShowHiddenMarkers(boolean show)
940   {
941     showHiddenMarkers = show;
942   }
943
944   /**
945    * returns the visible column regions of the alignment
946    * 
947    * @param selectedRegionOnly
948    *          true to just return the contigs intersecting with the selected
949    *          area
950    * @return
951    */
952   public int[] getViewAsVisibleContigs(boolean selectedRegionOnly)
953   {
954     int[] viscontigs = null;
955     int start = 0, end = 0;
956     if (selectedRegionOnly && selectionGroup != null)
957     {
958       start = selectionGroup.getStartRes();
959       end = selectionGroup.getEndRes() + 1;
960     }
961     else
962     {
963       end = alignment.getWidth();
964     }
965     viscontigs = colSel.getVisibleContigs(start, end);
966     return viscontigs;
967   }
968
969   /**
970    * get hash of undo and redo list for the alignment
971    * 
972    * @return long[] { historyList.hashCode, redoList.hashCode };
973    */
974   public long[] getUndoRedoHash()
975   {
976     // TODO: JAL-1126
977     if (historyList == null || redoList == null)
978     {
979       return new long[]
980       { -1, -1 };
981     }
982     return new long[]
983     { historyList.hashCode(), this.redoList.hashCode() };
984   }
985
986   /**
987    * test if a particular set of hashcodes are different to the hashcodes for
988    * the undo and redo list.
989    * 
990    * @param undoredo
991    *          the stored set of hashcodes as returned by getUndoRedoHash
992    * @return true if the hashcodes differ (ie the alignment has been edited) or
993    *         the stored hashcode array differs in size
994    */
995   public boolean isUndoRedoHashModified(long[] undoredo)
996   {
997     if (undoredo == null)
998     {
999       return true;
1000     }
1001     long[] cstate = getUndoRedoHash();
1002     if (cstate.length != undoredo.length)
1003     {
1004       return true;
1005     }
1006
1007     for (int i = 0; i < cstate.length; i++)
1008     {
1009       if (cstate[i] != undoredo[i])
1010       {
1011         return true;
1012       }
1013     }
1014     return false;
1015   }
1016
1017   public boolean getCentreColumnLabels()
1018   {
1019     return centreColumnLabels;
1020   }
1021
1022   public void setCentreColumnLabels(boolean centrecolumnlabels)
1023   {
1024     centreColumnLabels = centrecolumnlabels;
1025   }
1026
1027   /**
1028    * enable or disable the display of Database Cross References in the sequence
1029    * ID tooltip
1030    */
1031   public void setShowDbRefs(boolean show)
1032   {
1033     showdbrefs = show;
1034   }
1035
1036   /**
1037    * 
1038    * @return true if Database References are to be displayed on tooltips.
1039    */
1040   public boolean isShowDbRefs()
1041   {
1042     return showdbrefs;
1043   }
1044
1045   /**
1046    * 
1047    * @return true if Non-positional features are to be displayed on tooltips.
1048    */
1049   public boolean isShowNpFeats()
1050   {
1051     return shownpfeats;
1052   }
1053
1054   /**
1055    * enable or disable the display of Non-Positional sequence features in the
1056    * sequence ID tooltip
1057    * 
1058    * @param show
1059    */
1060   public void setShowNpFeats(boolean show)
1061   {
1062     shownpfeats = show;
1063   }
1064
1065   /**
1066    * 
1067    * @return true if view has hidden rows
1068    */
1069   public boolean hasHiddenRows()
1070   {
1071     return hasHiddenRows;
1072   }
1073
1074   /**
1075    * 
1076    * @return true if view has hidden columns
1077    */
1078   public boolean hasHiddenColumns()
1079   {
1080     return hasHiddenColumns;
1081   }
1082
1083   /**
1084    * when set, view will scroll to show the highlighted position
1085    */
1086   public boolean followHighlight = true;
1087
1088   /**
1089    * @return true if view should scroll to show the highlighted region of a
1090    *         sequence
1091    * @return
1092    */
1093   public boolean getFollowHighlight()
1094   {
1095     return followHighlight;
1096   }
1097
1098   public boolean followSelection = true;
1099
1100   /**
1101    * @return true if view selection should always follow the selections
1102    *         broadcast by other selection sources
1103    */
1104   public boolean getFollowSelection()
1105   {
1106     return followSelection;
1107   }
1108
1109   boolean showSeqFeaturesHeight;
1110
1111   public void sendSelection()
1112   {
1113     jalview.structure.StructureSelectionManager
1114             .getStructureSelectionManager(Desktop.instance).sendSelection(
1115                     new SequenceGroup(getSelectionGroup()),
1116                     new ColumnSelection(getColumnSelection()), this);
1117   }
1118
1119   public void setShowSequenceFeaturesHeight(boolean selected)
1120   {
1121     showSeqFeaturesHeight = selected;
1122   }
1123
1124   public boolean getShowSequenceFeaturesHeight()
1125   {
1126     return showSeqFeaturesHeight;
1127   }
1128
1129   /**
1130    * return the alignPanel containing the given viewport. Use this to get the
1131    * components currently handling the given viewport.
1132    * 
1133    * @param av
1134    * @return null or an alignPanel guaranteed to have non-null alignFrame
1135    *         reference
1136    */
1137   public AlignmentPanel getAlignPanel()
1138   {
1139     AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this
1140             .getSequenceSetId());
1141     AlignmentPanel ap = null;
1142     for (int p = 0; aps != null && p < aps.length; p++)
1143     {
1144       if (aps[p].av == this)
1145       {
1146         return aps[p];
1147       }
1148     }
1149     return null;
1150   }
1151
1152   public boolean getSortByTree()
1153   {
1154     return sortByTree;
1155   }
1156
1157   public void setSortByTree(boolean sort)
1158   {
1159     sortByTree = sort;
1160   }
1161
1162   /**
1163    * synthesize a column selection if none exists so it covers the given
1164    * selection group. if wholewidth is false, no column selection is made if the
1165    * selection group covers the whole alignment width.
1166    * 
1167    * @param sg
1168    * @param wholewidth
1169    */
1170   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
1171   {
1172     int sgs, sge;
1173     if (sg != null
1174             && (sgs = sg.getStartRes()) >= 0
1175             && sg.getStartRes() <= (sge = sg.getEndRes())
1176             && (colSel == null || colSel.getSelected() == null || colSel
1177                     .getSelected().size() == 0))
1178     {
1179       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
1180       {
1181         // do nothing
1182         return;
1183       }
1184       if (colSel == null)
1185       {
1186         colSel = new ColumnSelection();
1187       }
1188       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
1189       {
1190         colSel.addElement(cspos);
1191       }
1192     }
1193   }
1194
1195   public StructureSelectionManager getStructureSelectionManager()
1196   {
1197     return StructureSelectionManager
1198             .getStructureSelectionManager(Desktop.instance);
1199   }
1200
1201   /**
1202    * 
1203    * @param pdbEntries
1204    * @return a series of SequenceI arrays, one for each PDBEntry, listing which
1205    *         sequence in the alignment holds a reference to it
1206    */
1207   public SequenceI[][] collateForPDB(PDBEntry[] pdbEntries)
1208   {
1209     ArrayList<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
1210     for (PDBEntry pdb : pdbEntries)
1211     {
1212       ArrayList<SequenceI> seqs = new ArrayList<SequenceI>();
1213       for (int i = 0; i < alignment.getHeight(); i++)
1214       {
1215         Vector pdbs = alignment.getSequenceAt(i).getDatasetSequence()
1216                 .getPDBId();
1217         if (pdbs == null)
1218         {
1219           continue;
1220         }
1221         SequenceI sq;
1222         for (int p = 0; p < pdbs.size(); p++)
1223         {
1224           PDBEntry p1 = (PDBEntry) pdbs.elementAt(p);
1225           if (p1.getId().equals(pdb.getId()))
1226           {
1227             if (!seqs.contains(sq = alignment.getSequenceAt(i)))
1228             {
1229               seqs.add(sq);
1230             }
1231
1232             continue;
1233           }
1234         }
1235       }
1236       seqvectors.add(seqs.toArray(new SequenceI[seqs.size()]));
1237     }
1238     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
1239   }
1240
1241   public boolean isNormaliseSequenceLogo()
1242   {
1243     return normaliseSequenceLogo;
1244   }
1245
1246   public void setNormaliseSequenceLogo(boolean state)
1247   {
1248     normaliseSequenceLogo = state;
1249   }
1250
1251   /**
1252    * 
1253    * @return true if alignment characters should be displayed
1254    */
1255   public boolean isValidCharWidth()
1256   {
1257     return validCharWidth;
1258   }
1259
1260   private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<String, AutoCalcSetting>();
1261
1262   private boolean showAutocalculatedAbove;
1263
1264   public AutoCalcSetting getCalcIdSettingsFor(String calcId)
1265   {
1266     return calcIdParams.get(calcId);
1267   }
1268
1269   public void setCalcIdSettingsFor(String calcId, AutoCalcSetting settings,
1270           boolean needsUpdate)
1271   {
1272     calcIdParams.put(calcId, settings);
1273     // TODO: create a restart list to trigger any calculations that need to be
1274     // restarted after load
1275     // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
1276     if (needsUpdate)
1277     {
1278       Cache.log.debug("trigger update for " + calcId);
1279     }
1280   }
1281
1282   protected SequenceAnnotationOrder getSortAnnotationsBy()
1283   {
1284     return sortAnnotationsBy;
1285   }
1286
1287   protected void setSortAnnotationsBy(SequenceAnnotationOrder sortAnnotationsBy)
1288   {
1289     this.sortAnnotationsBy = sortAnnotationsBy;
1290   }
1291
1292   protected boolean isShowAutocalculatedAbove()
1293   {
1294     return showAutocalculatedAbove;
1295   }
1296
1297   protected void setShowAutocalculatedAbove(boolean showAutocalculatedAbove)
1298   {
1299     this.showAutocalculatedAbove = showAutocalculatedAbove;
1300   }
1301 }