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