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