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