JAL-1503 update version in GPL header
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
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 resetSeqLimits(int height)
488   {
489     setEndSeq(height / getCharHeight());
490   }
491
492   public void setCurrentTree(NJTree tree)
493   {
494     currentTree = tree;
495   }
496
497   public NJTree getCurrentTree()
498   {
499     return currentTree;
500   }
501
502   public boolean getShowJVSuffix()
503   {
504     return showJVSuffix;
505   }
506
507   public void setShowJVSuffix(boolean b)
508   {
509     showJVSuffix = b;
510   }
511
512   public boolean getShowAnnotation()
513   {
514     return showAnnotation;
515   }
516
517   public void setShowAnnotation(boolean b)
518   {
519     showAnnotation = b;
520   }
521
522   public boolean getScaleAboveWrapped()
523   {
524     return scaleAboveWrapped;
525   }
526
527   public boolean getScaleLeftWrapped()
528   {
529     return scaleLeftWrapped;
530   }
531
532   public boolean getScaleRightWrapped()
533   {
534     return scaleRightWrapped;
535   }
536
537   public void setScaleAboveWrapped(boolean b)
538   {
539     scaleAboveWrapped = b;
540   }
541
542   public void setScaleLeftWrapped(boolean b)
543   {
544     scaleLeftWrapped = b;
545   }
546
547   public void setScaleRightWrapped(boolean b)
548   {
549     scaleRightWrapped = b;
550   }
551
552   public void setIgnoreGapsConsensus(boolean b)
553   {
554     ignoreGapsInConsensusCalculation = b;
555     updateConsensus(null);
556     if (globalColourScheme != null)
557     {
558       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
559               ignoreGapsInConsensusCalculation);
560
561     }
562   }
563
564   public boolean getShowHiddenMarkers()
565   {
566     return showHiddenMarkers;
567   }
568
569   public void setShowHiddenMarkers(boolean show)
570   {
571     showHiddenMarkers = show;
572   }
573
574   boolean centreColumnLabels;
575
576   public boolean getCentreColumnLabels()
577   {
578     return centreColumnLabels;
579   }
580
581   public boolean followHighlight = true;
582
583   public boolean getFollowHighlight()
584   {
585     return followHighlight;
586   }
587
588   public boolean followSelection = true;
589
590   /**
591    * @return true if view selection should always follow the selections
592    *         broadcast by other selection sources
593    */
594   public boolean getFollowSelection()
595   {
596     return followSelection;
597   }
598
599   public void sendSelection()
600   {
601     jalview.structure.StructureSelectionManager
602             .getStructureSelectionManager(applet).sendSelection(
603                     new SequenceGroup(getSelectionGroup()),
604                     new ColumnSelection(getColumnSelection()), this);
605   }
606
607   /**
608    * synthesize a column selection if none exists so it covers the given
609    * selection group. if wholewidth is false, no column selection is made if the
610    * selection group covers the whole alignment width.
611    * 
612    * @param sg
613    * @param wholewidth
614    */
615   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
616   {
617     int sgs, sge;
618     if (sg != null
619             && (sgs = sg.getStartRes()) >= 0
620             && sg.getStartRes() <= (sge = sg.getEndRes())
621             && (colSel == null || colSel.getSelected() == null || colSel
622                     .getSelected().size() == 0))
623     {
624       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
625       {
626         // do nothing
627         return;
628       }
629       if (colSel == null)
630       {
631         colSel = new ColumnSelection();
632       }
633       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
634       {
635         colSel.addElement(cspos);
636       }
637     }
638   }
639
640   @Override
641   public boolean hasHiddenColumns()
642   {
643     return hasHiddenColumns;
644   }
645
646   public boolean isNormaliseSequenceLogo()
647   {
648     return normaliseSequenceLogo;
649   }
650
651   public void setNormaliseSequenceLogo(boolean state)
652   {
653     normaliseSequenceLogo = state;
654   }
655
656   /**
657    * 
658    * @return true if alignment characters should be displayed
659    */
660   public boolean isValidCharWidth()
661   {
662     return validCharWidth;
663   }
664
665 }