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