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