7400122c5a4203973e07fe1d1289e888749f08dc
[jalview.git] / src / jalview / appletgui / 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 package jalview.appletgui;
22
23 import java.util.*;
24
25 import java.awt.*;
26
27 import jalview.analysis.*;
28 import jalview.api.AlignViewportI;
29 import jalview.bin.*;
30 import jalview.datamodel.*;
31 import jalview.schemes.*;
32 import jalview.structure.SelectionSource;
33 import jalview.structure.VamsasSource;
34 import jalview.viewmodel.AlignmentViewport;
35
36 public class AlignViewport extends AlignmentViewport implements
37         AlignViewportI, SelectionSource, VamsasSource
38 {
39   int startRes;
40
41   int endRes;
42
43   int startSeq;
44
45   int endSeq;
46
47   boolean cursorMode = false;
48
49   boolean showJVSuffix = true;
50
51   boolean showText = true;
52
53   boolean showColourText = false;
54
55   boolean showBoxes = true;
56
57   boolean wrapAlignment = false;
58
59   boolean renderGaps = true;
60
61   boolean showSequenceFeatures = false;
62
63   boolean showAnnotation = true;
64
65   boolean upperCasebold = false;
66
67   int charHeight;
68
69   int charWidth;
70
71   int wrappedWidth;
72
73   Font font = new Font("SansSerif", Font.PLAIN, 10);
74
75   boolean validCharWidth = true;
76
77   int threshold;
78
79   int increment;
80
81   NJTree currentTree = null;
82
83   boolean scaleAboveWrapped = true;
84
85   boolean scaleLeftWrapped = true;
86
87   boolean scaleRightWrapped = true;
88
89   // The following vector holds the features which are
90   // currently visible, in the correct order or rendering
91   public Hashtable featuresDisplayed;
92
93   boolean showHiddenMarkers = true;
94
95   public jalview.bin.JalviewLite applet;
96
97   boolean MAC = false;
98
99   Stack historyList = new Stack();
100
101   Stack redoList = new Stack();
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   public void showSequenceFeatures(boolean b)
260   {
261     showSequenceFeatures = b;
262   }
263
264   public boolean getShowSequenceFeatures()
265   {
266     return showSequenceFeatures;
267   }
268
269   /**
270    * get the consensus sequence as displayed under the PID consensus annotation
271    * row.
272    * 
273    * @return consensus sequence as a new sequence object
274    */
275   public SequenceI getConsensusSeq()
276   {
277     if (consensus == null)
278     {
279       updateConsensus(null);
280     }
281     if (consensus == null)
282     {
283       return null;
284     }
285     StringBuffer seqs = new StringBuffer();
286     for (int i = 0; i < consensus.annotations.length; i++)
287     {
288       if (consensus.annotations[i] != null)
289       {
290         if (consensus.annotations[i].description.charAt(0) == '[')
291         {
292           seqs.append(consensus.annotations[i].description.charAt(1));
293         }
294         else
295         {
296           seqs.append(consensus.annotations[i].displayCharacter);
297         }
298       }
299     }
300     SequenceI sq = new Sequence("Consensus", seqs.toString());
301     sq.setDescription("Percentage Identity Consensus "
302             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
303     return sq;
304   }
305
306   public int getStartRes()
307   {
308     return startRes;
309   }
310
311   public int getEndRes()
312   {
313     return endRes;
314   }
315
316   public int getStartSeq()
317   {
318     return startSeq;
319   }
320
321   public void setStartRes(int res)
322   {
323     this.startRes = res;
324   }
325
326   public void setStartSeq(int seq)
327   {
328     this.startSeq = seq;
329   }
330
331   public void setEndRes(int res)
332   {
333     if (res > alignment.getWidth() - 1)
334     {
335       // log.System.out.println(" Corrected res from " + res + " to maximum " +
336       // (alignment.getWidth()-1));
337       res = alignment.getWidth() - 1;
338     }
339     if (res < 0)
340     {
341       res = 0;
342     }
343     this.endRes = res;
344   }
345
346   public void setEndSeq(int seq)
347   {
348     if (seq > alignment.getHeight())
349     {
350       seq = alignment.getHeight();
351     }
352     if (seq < 0)
353     {
354       seq = 0;
355     }
356     this.endSeq = seq;
357   }
358
359   public int getEndSeq()
360   {
361     return endSeq;
362   }
363
364   java.awt.Frame nullFrame;
365
366   protected FeatureSettings featureSettings = null;
367
368   private float heightScale = 1, widthScale = 1;
369
370   public void setFont(Font f)
371   {
372     font = f;
373     if (nullFrame == null)
374     {
375       nullFrame = new java.awt.Frame();
376       nullFrame.addNotify();
377     }
378
379     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
380     setCharHeight((int) (heightScale * fm.getHeight()));
381     charWidth = (int) (widthScale * fm.charWidth('M'));
382
383     if (upperCasebold)
384     {
385       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
386       fm = nullFrame.getGraphics().getFontMetrics(f2);
387       charWidth = (int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10));
388     }
389   }
390
391   public Font getFont()
392   {
393     return font;
394   }
395
396   public int getCharWidth()
397   {
398     return charWidth;
399   }
400
401   public void setCharHeight(int h)
402   {
403     this.charHeight = h;
404   }
405
406   public int getCharHeight()
407   {
408     return charHeight;
409   }
410
411   public void setWrappedWidth(int w)
412   {
413     this.wrappedWidth = w;
414   }
415
416   public int getwrappedWidth()
417   {
418     return wrappedWidth;
419   }
420
421   public AlignmentI getAlignment()
422   {
423     return alignment;
424   }
425
426   public void setAlignment(AlignmentI align)
427   {
428     this.alignment = align;
429   }
430
431   public void setWrapAlignment(boolean state)
432   {
433     wrapAlignment = state;
434   }
435
436   public void setShowText(boolean state)
437   {
438     showText = state;
439   }
440
441   public void setRenderGaps(boolean state)
442   {
443     renderGaps = state;
444   }
445
446   public boolean getColourText()
447   {
448     return showColourText;
449   }
450
451   public void setColourText(boolean state)
452   {
453     showColourText = state;
454   }
455
456   public void setShowBoxes(boolean state)
457   {
458     showBoxes = state;
459   }
460
461   public boolean getWrapAlignment()
462   {
463     return wrapAlignment;
464   }
465
466   public boolean getShowText()
467   {
468     return showText;
469   }
470
471   public boolean getShowBoxes()
472   {
473     return showBoxes;
474   }
475
476   public char getGapCharacter()
477   {
478     return getAlignment().getGapCharacter();
479   }
480
481   public void setGapCharacter(char gap)
482   {
483     if (getAlignment() != null)
484     {
485       getAlignment().setGapCharacter(gap);
486     }
487   }
488
489   public void resetSeqLimits(int height)
490   {
491     setEndSeq(height / getCharHeight());
492   }
493
494   public void setCurrentTree(NJTree tree)
495   {
496     currentTree = tree;
497   }
498
499   public NJTree getCurrentTree()
500   {
501     return currentTree;
502   }
503
504   public boolean getShowJVSuffix()
505   {
506     return showJVSuffix;
507   }
508
509   public void setShowJVSuffix(boolean b)
510   {
511     showJVSuffix = b;
512   }
513
514   public boolean getShowAnnotation()
515   {
516     return showAnnotation;
517   }
518
519   public void setShowAnnotation(boolean b)
520   {
521     showAnnotation = b;
522   }
523
524   public boolean getScaleAboveWrapped()
525   {
526     return scaleAboveWrapped;
527   }
528
529   public boolean getScaleLeftWrapped()
530   {
531     return scaleLeftWrapped;
532   }
533
534   public boolean getScaleRightWrapped()
535   {
536     return scaleRightWrapped;
537   }
538
539   public void setScaleAboveWrapped(boolean b)
540   {
541     scaleAboveWrapped = b;
542   }
543
544   public void setScaleLeftWrapped(boolean b)
545   {
546     scaleLeftWrapped = b;
547   }
548
549   public void setScaleRightWrapped(boolean b)
550   {
551     scaleRightWrapped = b;
552   }
553
554   public void setIgnoreGapsConsensus(boolean b)
555   {
556     ignoreGapsInConsensusCalculation = b;
557     updateConsensus(null);
558     if (globalColourScheme != null)
559     {
560       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
561               ignoreGapsInConsensusCalculation);
562
563     }
564   }
565
566   public boolean getShowHiddenMarkers()
567   {
568     return showHiddenMarkers;
569   }
570
571   public void setShowHiddenMarkers(boolean show)
572   {
573     showHiddenMarkers = show;
574   }
575
576   boolean centreColumnLabels;
577
578   public boolean getCentreColumnLabels()
579   {
580     return centreColumnLabels;
581   }
582
583   public boolean followHighlight = true;
584
585   public boolean getFollowHighlight()
586   {
587     return followHighlight;
588   }
589
590   public boolean followSelection = true;
591
592   /**
593    * @return true if view selection should always follow the selections
594    *         broadcast by other selection sources
595    */
596   public boolean getFollowSelection()
597   {
598     return followSelection;
599   }
600
601   public void sendSelection()
602   {
603     jalview.structure.StructureSelectionManager
604             .getStructureSelectionManager(applet).sendSelection(
605                     new SequenceGroup(getSelectionGroup()),
606                     new ColumnSelection(getColumnSelection()), this);
607   }
608
609   /**
610    * synthesize a column selection if none exists so it covers the given
611    * selection group. if wholewidth is false, no column selection is made if the
612    * selection group covers the whole alignment width.
613    * 
614    * @param sg
615    * @param wholewidth
616    */
617   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
618   {
619     int sgs, sge;
620     if (sg != null
621             && (sgs = sg.getStartRes()) >= 0
622             && sg.getStartRes() <= (sge = sg.getEndRes())
623             && (colSel == null || colSel.getSelected() == null || colSel
624                     .getSelected().size() == 0))
625     {
626       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
627       {
628         // do nothing
629         return;
630       }
631       if (colSel == null)
632       {
633         colSel = new ColumnSelection();
634       }
635       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
636       {
637         colSel.addElement(cspos);
638       }
639     }
640   }
641
642   @Override
643   public boolean hasHiddenColumns()
644   {
645     return hasHiddenColumns;
646   }
647
648   public boolean isNormaliseSequenceLogo()
649   {
650     return normaliseSequenceLogo;
651   }
652
653   public void setNormaliseSequenceLogo(boolean state)
654   {
655     normaliseSequenceLogo = state;
656   }
657
658   /**
659    * 
660    * @return true if alignment characters should be displayed
661    */
662   public boolean isValidCharWidth()
663   {
664     return validCharWidth;
665   }
666
667 }