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