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