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