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