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