JAL-1517 source formatting
[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    * enable or disable the display of Database Cross References in the sequence
1021    * ID tooltip
1022    */
1023   public void setShowDbRefs(boolean show)
1024   {
1025     showdbrefs = show;
1026   }
1027
1028   /**
1029    * 
1030    * @return true if Database References are to be displayed on tooltips.
1031    */
1032   public boolean isShowDbRefs()
1033   {
1034     return showdbrefs;
1035   }
1036
1037   /**
1038    * 
1039    * @return true if Non-positional features are to be displayed on tooltips.
1040    */
1041   public boolean isShowNpFeats()
1042   {
1043     return shownpfeats;
1044   }
1045
1046   /**
1047    * enable or disable the display of Non-Positional sequence features in the
1048    * sequence ID tooltip
1049    * 
1050    * @param show
1051    */
1052   public void setShowNpFeats(boolean show)
1053   {
1054     shownpfeats = show;
1055   }
1056
1057   /**
1058    * 
1059    * @return true if view has hidden rows
1060    */
1061   public boolean hasHiddenRows()
1062   {
1063     return hasHiddenRows;
1064   }
1065
1066   /**
1067    * 
1068    * @return true if view has hidden columns
1069    */
1070   public boolean hasHiddenColumns()
1071   {
1072     return hasHiddenColumns;
1073   }
1074
1075   /**
1076    * when set, view will scroll to show the highlighted position
1077    */
1078   public boolean followHighlight = true;
1079
1080   /**
1081    * @return true if view should scroll to show the highlighted region of a
1082    *         sequence
1083    * @return
1084    */
1085   public boolean getFollowHighlight()
1086   {
1087     return followHighlight;
1088   }
1089
1090   public boolean followSelection = true;
1091
1092   /**
1093    * @return true if view selection should always follow the selections
1094    *         broadcast by other selection sources
1095    */
1096   public boolean getFollowSelection()
1097   {
1098     return followSelection;
1099   }
1100
1101   boolean showSeqFeaturesHeight;
1102
1103   public void sendSelection()
1104   {
1105     jalview.structure.StructureSelectionManager
1106             .getStructureSelectionManager(Desktop.instance).sendSelection(
1107                     new SequenceGroup(getSelectionGroup()),
1108                     new ColumnSelection(getColumnSelection()), this);
1109   }
1110
1111   public void setShowSequenceFeaturesHeight(boolean selected)
1112   {
1113     showSeqFeaturesHeight = selected;
1114   }
1115
1116   public boolean getShowSequenceFeaturesHeight()
1117   {
1118     return showSeqFeaturesHeight;
1119   }
1120
1121   /**
1122    * return the alignPanel containing the given viewport. Use this to get the
1123    * components currently handling the given viewport.
1124    * 
1125    * @param av
1126    * @return null or an alignPanel guaranteed to have non-null alignFrame
1127    *         reference
1128    */
1129   public AlignmentPanel getAlignPanel()
1130   {
1131     AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this
1132             .getSequenceSetId());
1133     AlignmentPanel ap = null;
1134     for (int p = 0; aps != null && p < aps.length; p++)
1135     {
1136       if (aps[p].av == this)
1137       {
1138         return aps[p];
1139       }
1140     }
1141     return null;
1142   }
1143
1144   public boolean getSortByTree()
1145   {
1146     return sortByTree;
1147   }
1148
1149   public void setSortByTree(boolean sort)
1150   {
1151     sortByTree = sort;
1152   }
1153
1154   /**
1155    * synthesize a column selection if none exists so it covers the given
1156    * selection group. if wholewidth is false, no column selection is made if the
1157    * selection group covers the whole alignment width.
1158    * 
1159    * @param sg
1160    * @param wholewidth
1161    */
1162   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
1163   {
1164     int sgs, sge;
1165     if (sg != null
1166             && (sgs = sg.getStartRes()) >= 0
1167             && sg.getStartRes() <= (sge = sg.getEndRes())
1168             && (colSel == null || colSel.getSelected() == null || colSel
1169                     .getSelected().size() == 0))
1170     {
1171       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
1172       {
1173         // do nothing
1174         return;
1175       }
1176       if (colSel == null)
1177       {
1178         colSel = new ColumnSelection();
1179       }
1180       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
1181       {
1182         colSel.addElement(cspos);
1183       }
1184     }
1185   }
1186
1187   public StructureSelectionManager getStructureSelectionManager()
1188   {
1189     return StructureSelectionManager
1190             .getStructureSelectionManager(Desktop.instance);
1191   }
1192
1193   /**
1194    * 
1195    * @param pdbEntries
1196    * @return a series of SequenceI arrays, one for each PDBEntry, listing which
1197    *         sequence in the alignment holds a reference to it
1198    */
1199   public SequenceI[][] collateForPDB(PDBEntry[] pdbEntries)
1200   {
1201     ArrayList<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
1202     for (PDBEntry pdb : pdbEntries)
1203     {
1204       ArrayList<SequenceI> seqs = new ArrayList<SequenceI>();
1205       for (int i = 0; i < alignment.getHeight(); i++)
1206       {
1207         Vector pdbs = alignment.getSequenceAt(i).getDatasetSequence()
1208                 .getPDBId();
1209         if (pdbs == null)
1210           continue;
1211         SequenceI sq;
1212         for (int p = 0; p < pdbs.size(); p++)
1213         {
1214           PDBEntry p1 = (PDBEntry) pdbs.elementAt(p);
1215           if (p1.getId().equals(pdb.getId()))
1216           {
1217             if (!seqs.contains(sq = alignment.getSequenceAt(i)))
1218               seqs.add(sq);
1219
1220             continue;
1221           }
1222         }
1223       }
1224       seqvectors.add(seqs.toArray(new SequenceI[seqs.size()]));
1225     }
1226     return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
1227   }
1228
1229   public boolean isNormaliseSequenceLogo()
1230   {
1231     return normaliseSequenceLogo;
1232   }
1233
1234   public void setNormaliseSequenceLogo(boolean state)
1235   {
1236     normaliseSequenceLogo = state;
1237   }
1238
1239   /**
1240    * 
1241    * @return true if alignment characters should be displayed
1242    */
1243   public boolean isValidCharWidth()
1244   {
1245     return validCharWidth;
1246   }
1247
1248   private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<String, AutoCalcSetting>();
1249
1250   public AutoCalcSetting getCalcIdSettingsFor(String calcId)
1251   {
1252     return calcIdParams.get(calcId);
1253   }
1254
1255   public void setCalcIdSettingsFor(String calcId, AutoCalcSetting settings,
1256           boolean needsUpdate)
1257   {
1258     calcIdParams.put(calcId, settings);
1259     // TODO: create a restart list to trigger any calculations that need to be
1260     // restarted after load
1261     // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
1262     if (needsUpdate)
1263     {
1264       Cache.log.debug("trigger update for " + calcId);
1265     }
1266   }
1267 }