Merge branch 'Release_2_8_0b1_Branch' into try_r20b1_merge
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.appletgui;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.analysis.*;
26 import jalview.api.AlignViewportI;
27 import jalview.bin.*;
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30 import jalview.structure.SelectionSource;
31 import jalview.structure.VamsasSource;
32 import jalview.viewmodel.AlignmentViewport;
33
34 public class AlignViewport extends AlignmentViewport implements
35         AlignViewportI, SelectionSource, VamsasSource
36 {
37   int startRes;
38
39   int endRes;
40
41   int startSeq;
42
43   int endSeq;
44
45   boolean cursorMode = false;
46
47   boolean showJVSuffix = true;
48
49   boolean showText = true;
50
51   boolean showColourText = false;
52
53   boolean showBoxes = true;
54
55   boolean wrapAlignment = false;
56
57   boolean renderGaps = true;
58
59   boolean showSequenceFeatures = false;
60
61   boolean showAnnotation = true;
62
63   boolean upperCasebold = false;
64
65   int charHeight;
66
67   int charWidth;
68
69   int wrappedWidth;
70
71   Font font = new Font("SansSerif", Font.PLAIN, 10);
72
73   boolean validCharWidth = true;
74
75   int threshold;
76
77   int increment;
78
79   NJTree currentTree = null;
80
81   boolean scaleAboveWrapped = true;
82
83   boolean scaleLeftWrapped = true;
84
85   boolean scaleRightWrapped = true;
86
87   // The following vector holds the features which are
88   // currently visible, in the correct order or rendering
89   public Hashtable featuresDisplayed;
90
91   boolean showHiddenMarkers = true;
92
93   public jalview.bin.JalviewLite applet;
94
95   boolean MAC = false;
96
97   Stack historyList = new Stack();
98
99   Stack redoList = new Stack();
100
101   public void finalize()
102   {
103     applet = null;
104     quality = null;
105     alignment = null;
106     colSel = null;
107   }
108
109   public AlignViewport(AlignmentI al, JalviewLite applet)
110   {
111     calculator = new jalview.workers.AlignCalcManager();
112     this.applet = applet;
113     setAlignment(al);
114     // we always pad gaps
115     this.setPadGaps(true);
116     this.startRes = 0;
117     this.endRes = al.getWidth() - 1;
118     this.startSeq = 0;
119     this.endSeq = al.getHeight() - 1;
120     if (applet != null)
121     {
122       // get the width and height scaling factors if they were specified
123       String param = applet.getParameter("widthScale");
124       if (param != null)
125       {
126         try
127         {
128           widthScale = new Float(param).floatValue();
129         } catch (Exception e)
130         {
131         }
132         if (widthScale <= 1.0)
133         {
134           System.err
135                   .println("Invalid alignment character width scaling factor ("
136                           + widthScale + "). Ignoring.");
137           widthScale = 1;
138         }
139         if (applet.debug)
140         {
141           System.err
142                   .println("Alignment character width scaling factor is now "
143                           + widthScale);
144         }
145       }
146       param = applet.getParameter("heightScale");
147       if (param != null)
148       {
149         try
150         {
151           heightScale = new Float(param).floatValue();
152         } catch (Exception e)
153         {
154         }
155         if (heightScale <= 1.0)
156         {
157           System.err
158                   .println("Invalid alignment character height scaling factor ("
159                           + heightScale + "). Ignoring.");
160           heightScale = 1;
161         }
162         if (applet.debug)
163         {
164           System.err
165                   .println("Alignment character height scaling factor is now "
166                           + heightScale);
167         }
168       }
169     }
170     setFont(font);
171
172     MAC = new jalview.util.Platform().isAMac();
173
174     if (applet != null)
175     {
176       showJVSuffix = applet.getDefaultParameter("showFullId", showJVSuffix);
177
178       showAnnotation = applet.getDefaultParameter("showAnnotation",
179               showAnnotation);
180
181       showConservation = applet.getDefaultParameter("showConservation",
182               showConservation);
183
184       showQuality = applet.getDefaultParameter("showQuality", showQuality);
185
186       showConsensus = applet.getDefaultParameter("showConsensus",
187               showConsensus);
188
189       showUnconserved = applet.getDefaultParameter("showUnconserved",
190               showUnconserved);
191
192       String param = applet.getParameter("upperCase");
193       if (param != null)
194       {
195         if (param.equalsIgnoreCase("bold"))
196         {
197           upperCasebold = true;
198         }
199       }
200       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
201
202       followHighlight = applet.getDefaultParameter("automaticScrolling",
203               followHighlight);
204       followSelection = followHighlight;
205
206       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
207               showSequenceLogo);
208
209       normaliseSequenceLogo = applet.getDefaultParameter(
210               "normaliseSequenceLogo", applet.getDefaultParameter(
211                       "normaliseLogo", normaliseSequenceLogo));
212
213       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
214               showGroupConsensus);
215
216       showGroupConservation = applet.getDefaultParameter(
217               "showGroupConservation", showGroupConservation);
218
219       showConsensusHistogram = applet.getDefaultParameter(
220               "showConsensusHistogram", showConsensusHistogram);
221
222     }
223
224     if (applet != null)
225     {
226       String colour = applet.getParameter("defaultColour");
227
228       if (colour == null)
229       {
230         colour = applet.getParameter("userDefinedColour");
231         if (colour != null)
232         {
233           colour = "User Defined";
234         }
235       }
236
237       if (colour != null)
238       {
239         globalColourScheme = ColourSchemeProperty.getColour(alignment,
240                 colour);
241         if (globalColourScheme != null)
242         {
243           globalColourScheme.setConsensus(hconsensus);
244         }
245       }
246
247       if (applet.getParameter("userDefinedColour") != null)
248       {
249         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
250                 .getParameter("userDefinedColour"));
251       }
252     }
253     initAutoAnnotation();
254
255   }
256
257   public void showSequenceFeatures(boolean b)
258   {
259     showSequenceFeatures = b;
260   }
261
262   public boolean getShowSequenceFeatures()
263   {
264     return showSequenceFeatures;
265   }
266
267   /**
268    * get the consensus sequence as displayed under the PID consensus annotation
269    * row.
270    * 
271    * @return consensus sequence as a new sequence object
272    */
273   public SequenceI getConsensusSeq()
274   {
275     if (consensus == null)
276     {
277       updateConsensus(null);
278     }
279     if (consensus == null)
280     {
281       return null;
282     }
283     StringBuffer seqs = new StringBuffer();
284     for (int i = 0; i < consensus.annotations.length; i++)
285     {
286       if (consensus.annotations[i] != null)
287       {
288         if (consensus.annotations[i].description.charAt(0) == '[')
289         {
290           seqs.append(consensus.annotations[i].description.charAt(1));
291         }
292         else
293         {
294           seqs.append(consensus.annotations[i].displayCharacter);
295         }
296       }
297     }
298     SequenceI sq = new Sequence("Consensus", seqs.toString());
299     sq.setDescription("Percentage Identity Consensus "
300             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
301     return sq;
302   }
303
304   public int getStartRes()
305   {
306     return startRes;
307   }
308
309   public int getEndRes()
310   {
311     return endRes;
312   }
313
314   public int getStartSeq()
315   {
316     return startSeq;
317   }
318
319   public void setStartRes(int res)
320   {
321     this.startRes = res;
322   }
323
324   public void setStartSeq(int seq)
325   {
326     this.startSeq = seq;
327   }
328
329   public void setEndRes(int res)
330   {
331     if (res > alignment.getWidth() - 1)
332     {
333       // log.System.out.println(" Corrected res from " + res + " to maximum " +
334       // (alignment.getWidth()-1));
335       res = alignment.getWidth() - 1;
336     }
337     if (res < 0)
338     {
339       res = 0;
340     }
341     this.endRes = res;
342   }
343
344   public void setEndSeq(int seq)
345   {
346     if (seq > alignment.getHeight())
347     {
348       seq = alignment.getHeight();
349     }
350     if (seq < 0)
351     {
352       seq = 0;
353     }
354     this.endSeq = seq;
355   }
356
357   public int getEndSeq()
358   {
359     return endSeq;
360   }
361
362   java.awt.Frame nullFrame;
363
364   protected FeatureSettings featureSettings = null;
365
366   private float heightScale = 1, widthScale = 1;
367
368   public void setFont(Font f)
369   {
370     font = f;
371     if (nullFrame == null)
372     {
373       nullFrame = new java.awt.Frame();
374       nullFrame.addNotify();
375     }
376
377     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
378     setCharHeight((int) (heightScale * fm.getHeight()));
379     charWidth = (int) (widthScale * fm.charWidth('M'));
380
381     if (upperCasebold)
382     {
383       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
384       fm = nullFrame.getGraphics().getFontMetrics(f2);
385       charWidth = (int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10));
386     }
387   }
388
389   public Font getFont()
390   {
391     return font;
392   }
393
394   public int getCharWidth()
395   {
396     return charWidth;
397   }
398
399   public void setCharHeight(int h)
400   {
401     this.charHeight = h;
402   }
403
404   public int getCharHeight()
405   {
406     return charHeight;
407   }
408
409   public void setWrappedWidth(int w)
410   {
411     this.wrappedWidth = w;
412   }
413
414   public int getwrappedWidth()
415   {
416     return wrappedWidth;
417   }
418
419   public AlignmentI getAlignment()
420   {
421     return alignment;
422   }
423
424   public void setAlignment(AlignmentI align)
425   {
426     this.alignment = align;
427   }
428
429   public void setWrapAlignment(boolean state)
430   {
431     wrapAlignment = state;
432   }
433
434   public void setShowText(boolean state)
435   {
436     showText = state;
437   }
438
439   public void setRenderGaps(boolean state)
440   {
441     renderGaps = state;
442   }
443
444   public boolean getColourText()
445   {
446     return showColourText;
447   }
448
449   public void setColourText(boolean state)
450   {
451     showColourText = state;
452   }
453
454   public void setShowBoxes(boolean state)
455   {
456     showBoxes = state;
457   }
458
459   public boolean getWrapAlignment()
460   {
461     return wrapAlignment;
462   }
463
464   public boolean getShowText()
465   {
466     return showText;
467   }
468
469   public boolean getShowBoxes()
470   {
471     return showBoxes;
472   }
473
474   public char getGapCharacter()
475   {
476     return getAlignment().getGapCharacter();
477   }
478
479   public void setGapCharacter(char gap)
480   {
481     if (getAlignment() != null)
482     {
483       getAlignment().setGapCharacter(gap);
484     }
485   }
486
487   public void setThreshold(int thresh)
488   {
489     threshold = thresh;
490   }
491
492   public int getThreshold()
493   {
494     return threshold;
495   }
496
497   public void setIncrement(int inc)
498   {
499     increment = inc;
500   }
501
502   public int getIncrement()
503   {
504     return increment;
505   }
506
507   public void resetSeqLimits(int height)
508   {
509     setEndSeq(height / getCharHeight());
510   }
511
512   public void setCurrentTree(NJTree tree)
513   {
514     currentTree = tree;
515   }
516
517   public NJTree getCurrentTree()
518   {
519     return currentTree;
520   }
521
522   public boolean getShowJVSuffix()
523   {
524     return showJVSuffix;
525   }
526
527   public void setShowJVSuffix(boolean b)
528   {
529     showJVSuffix = b;
530   }
531
532   public boolean getShowAnnotation()
533   {
534     return showAnnotation;
535   }
536
537   public void setShowAnnotation(boolean b)
538   {
539     showAnnotation = b;
540   }
541
542   public boolean getScaleAboveWrapped()
543   {
544     return scaleAboveWrapped;
545   }
546
547   public boolean getScaleLeftWrapped()
548   {
549     return scaleLeftWrapped;
550   }
551
552   public boolean getScaleRightWrapped()
553   {
554     return scaleRightWrapped;
555   }
556
557   public void setScaleAboveWrapped(boolean b)
558   {
559     scaleAboveWrapped = b;
560   }
561
562   public void setScaleLeftWrapped(boolean b)
563   {
564     scaleLeftWrapped = b;
565   }
566
567   public void setScaleRightWrapped(boolean b)
568   {
569     scaleRightWrapped = b;
570   }
571
572   public void setIgnoreGapsConsensus(boolean b)
573   {
574     ignoreGapsInConsensusCalculation = b;
575     updateConsensus(null);
576     if (globalColourScheme != null)
577     {
578       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
579               ignoreGapsInConsensusCalculation);
580
581     }
582   }
583
584   public boolean getShowHiddenMarkers()
585   {
586     return showHiddenMarkers;
587   }
588
589   public void setShowHiddenMarkers(boolean show)
590   {
591     showHiddenMarkers = show;
592   }
593
594   boolean centreColumnLabels;
595
596   public boolean getCentreColumnLabels()
597   {
598     return centreColumnLabels;
599   }
600
601   public boolean followHighlight = true;
602
603   public boolean getFollowHighlight()
604   {
605     return followHighlight;
606   }
607
608   public boolean followSelection = true;
609
610   /**
611    * @return true if view selection should always follow the selections
612    *         broadcast by other selection sources
613    */
614   public boolean getFollowSelection()
615   {
616     return followSelection;
617   }
618
619   public void sendSelection()
620   {
621     jalview.structure.StructureSelectionManager
622             .getStructureSelectionManager(applet).sendSelection(
623                     new SequenceGroup(getSelectionGroup()),
624                     new ColumnSelection(getColumnSelection()), this);
625   }
626
627   /**
628    * synthesize a column selection if none exists so it covers the given
629    * selection group. if wholewidth is false, no column selection is made if the
630    * selection group covers the whole alignment width.
631    * 
632    * @param sg
633    * @param wholewidth
634    */
635   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
636   {
637     int sgs, sge;
638     if (sg != null
639             && (sgs = sg.getStartRes()) >= 0
640             && sg.getStartRes() <= (sge = sg.getEndRes())
641             && (colSel == null || colSel.getSelected() == null || colSel
642                     .getSelected().size() == 0))
643     {
644       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
645       {
646         // do nothing
647         return;
648       }
649       if (colSel == null)
650       {
651         colSel = new ColumnSelection();
652       }
653       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
654       {
655         colSel.addElement(cspos);
656       }
657     }
658   }
659
660   @Override
661   public boolean hasHiddenColumns()
662   {
663     return hasHiddenColumns;
664   }
665
666   public boolean isNormaliseSequenceLogo()
667   {
668     return normaliseSequenceLogo;
669   }
670
671   public void setNormaliseSequenceLogo(boolean state)
672   {
673     normaliseSequenceLogo = state;
674   }
675
676   /**
677    * 
678    * @return true if alignment characters should be displayed
679    */
680   public boolean isValidCharWidth()
681   {
682     return validCharWidth;
683   }
684
685 }