Merge develop to Release_2_8_3_Branch
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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.awt.Font;
24
25 import jalview.analysis.NJTree;
26 import jalview.api.AlignViewportI;
27 import jalview.bin.JalviewLite;
28 import jalview.commands.CommandI;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.ColumnSelection;
31 import jalview.datamodel.Sequence;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.schemes.ColourSchemeProperty;
35 import jalview.schemes.UserColourScheme;
36 import jalview.structure.CommandListener;
37 import jalview.structure.SelectionSource;
38 import jalview.structure.StructureSelectionManager;
39 import jalview.structure.VamsasSource;
40 import jalview.viewmodel.AlignmentViewport;
41
42 public class AlignViewport extends AlignmentViewport implements
43         AlignViewportI, SelectionSource, VamsasSource, CommandListener
44 {
45   int startRes;
46
47   int endRes;
48
49   int startSeq;
50
51   int endSeq;
52
53   boolean cursorMode = false;
54
55   Font font = new Font("SansSerif", Font.PLAIN, 10);
56
57   boolean validCharWidth = true;
58
59   NJTree currentTree = null;
60
61   public jalview.bin.JalviewLite applet;
62
63   boolean MAC = false;
64
65   private AnnotationColumnChooser annotationColumnSelectionState;
66
67   public void finalize()
68   {
69     applet = null;
70     quality = null;
71     alignment = null;
72     colSel = null;
73   }
74
75   public AlignViewport(AlignmentI al, JalviewLite applet)
76   {
77     super();
78     calculator = new jalview.workers.AlignCalcManager();
79     this.applet = applet;
80     alignment = al;
81     // we always pad gaps
82     this.setPadGaps(true);
83     this.startRes = 0;
84     this.endRes = al.getWidth() - 1;
85     this.startSeq = 0;
86     this.endSeq = al.getHeight() - 1;
87     if (applet != null)
88     {
89       // get the width and height scaling factors if they were specified
90       String param = applet.getParameter("widthScale");
91       if (param != null)
92       {
93         try
94         {
95           widthScale = new Float(param).floatValue();
96         } catch (Exception e)
97         {
98         }
99         if (widthScale <= 1.0)
100         {
101           System.err
102                   .println("Invalid alignment character width scaling factor ("
103                           + widthScale + "). Ignoring.");
104           widthScale = 1;
105         }
106         if (applet.debug)
107         {
108           System.err
109                   .println("Alignment character width scaling factor is now "
110                           + widthScale);
111         }
112       }
113       param = applet.getParameter("heightScale");
114       if (param != null)
115       {
116         try
117         {
118           heightScale = new Float(param).floatValue();
119         } catch (Exception e)
120         {
121         }
122         if (heightScale <= 1.0)
123         {
124           System.err
125                   .println("Invalid alignment character height scaling factor ("
126                           + heightScale + "). Ignoring.");
127           heightScale = 1;
128         }
129         if (applet.debug)
130         {
131           System.err
132                   .println("Alignment character height scaling factor is now "
133                           + heightScale);
134         }
135       }
136     }
137     setFont(font);
138
139     MAC = new jalview.util.Platform().isAMac();
140
141     if (applet != null)
142     {
143       setShowJVSuffix(applet.getDefaultParameter("showFullId",
144               getShowJVSuffix()));
145
146       setShowAnnotation(applet.getDefaultParameter("showAnnotation",
147               isShowAnnotation()));
148
149       showConservation = applet.getDefaultParameter("showConservation",
150               showConservation);
151
152       showQuality = applet.getDefaultParameter("showQuality", showQuality);
153
154       showConsensus = applet.getDefaultParameter("showConsensus",
155               showConsensus);
156
157       setShowUnconserved(applet.getDefaultParameter("showUnconserved",
158               getShowUnconserved()));
159
160       String param = applet.getParameter("upperCase");
161       if (param != null)
162       {
163         if (param.equalsIgnoreCase("bold"))
164         {
165           setUpperCasebold(true);
166         }
167       }
168       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
169
170       followHighlight = applet.getDefaultParameter("automaticScrolling",
171               followHighlight);
172       followSelection = followHighlight;
173
174       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
175               showSequenceLogo);
176
177       normaliseSequenceLogo = applet.getDefaultParameter(
178               "normaliseSequenceLogo", applet.getDefaultParameter(
179                       "normaliseLogo", normaliseSequenceLogo));
180
181       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
182               showGroupConsensus);
183
184       showGroupConservation = applet.getDefaultParameter(
185               "showGroupConservation", showGroupConservation);
186
187       showConsensusHistogram = applet.getDefaultParameter(
188               "showConsensusHistogram", showConsensusHistogram);
189
190     }
191
192     if (applet != null)
193     {
194       String colour = applet.getParameter("defaultColour");
195
196       if (colour == null)
197       {
198         colour = applet.getParameter("userDefinedColour");
199         if (colour != null)
200         {
201           colour = "User Defined";
202         }
203       }
204
205       if (colour != null)
206       {
207         globalColourScheme = ColourSchemeProperty.getColour(alignment,
208                 colour);
209         if (globalColourScheme != null)
210         {
211           globalColourScheme.setConsensus(hconsensus);
212         }
213       }
214
215       if (applet.getParameter("userDefinedColour") != null)
216       {
217         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
218                 .getParameter("userDefinedColour"));
219       }
220     }
221     initAutoAnnotation();
222
223   }
224
225   /**
226    * get the consensus sequence as displayed under the PID consensus annotation
227    * row.
228    * 
229    * @return consensus sequence as a new sequence object
230    */
231   public SequenceI getConsensusSeq()
232   {
233     if (consensus == null)
234     {
235       updateConsensus(null);
236     }
237     if (consensus == null)
238     {
239       return null;
240     }
241     StringBuilder seqs = new StringBuilder(consensus.annotations.length);
242     for (int i = 0; i < consensus.annotations.length; i++)
243     {
244       if (consensus.annotations[i] != null)
245       {
246         if (consensus.annotations[i].description.charAt(0) == '[')
247         {
248           seqs.append(consensus.annotations[i].description.charAt(1));
249         }
250         else
251         {
252           seqs.append(consensus.annotations[i].displayCharacter);
253         }
254       }
255     }
256     SequenceI sq = new Sequence("Consensus", seqs.toString());
257     sq.setDescription("Percentage Identity Consensus "
258             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
259     return sq;
260   }
261
262   public int getStartRes()
263   {
264     return startRes;
265   }
266
267   public int getEndRes()
268   {
269     return endRes;
270   }
271
272   public int getStartSeq()
273   {
274     return startSeq;
275   }
276
277   public void setStartRes(int res)
278   {
279     this.startRes = res;
280   }
281
282   public void setStartSeq(int seq)
283   {
284     this.startSeq = seq;
285   }
286
287   public void setEndRes(int res)
288   {
289     if (res > alignment.getWidth() - 1)
290     {
291       // log.System.out.println(" Corrected res from " + res + " to maximum " +
292       // (alignment.getWidth()-1));
293       res = alignment.getWidth() - 1;
294     }
295     if (res < 0)
296     {
297       res = 0;
298     }
299     this.endRes = res;
300   }
301
302   public void setEndSeq(int seq)
303   {
304     if (seq > alignment.getHeight())
305     {
306       seq = alignment.getHeight();
307     }
308     if (seq < 0)
309     {
310       seq = 0;
311     }
312     this.endSeq = seq;
313   }
314
315   public int getEndSeq()
316   {
317     return endSeq;
318   }
319
320   java.awt.Frame nullFrame;
321
322   protected FeatureSettings featureSettings = null;
323
324   private float heightScale = 1, widthScale = 1;
325
326   public void setFont(Font f)
327   {
328     font = f;
329     if (nullFrame == null)
330     {
331       nullFrame = new java.awt.Frame();
332       nullFrame.addNotify();
333     }
334
335     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
336     setCharHeight((int) (heightScale * fm.getHeight()));
337     setCharWidth((int) (widthScale * fm.charWidth('M')));
338
339     if (isUpperCasebold())
340     {
341       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
342       fm = nullFrame.getGraphics().getFontMetrics(f2);
343       setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
344     }
345   }
346
347   public Font getFont()
348   {
349     return font;
350   }
351
352
353   public void resetSeqLimits(int height)
354   {
355     setEndSeq(height / getCharHeight());
356   }
357
358   public void setCurrentTree(NJTree tree)
359   {
360     currentTree = tree;
361   }
362
363   public NJTree getCurrentTree()
364   {
365     return currentTree;
366   }
367
368
369   boolean centreColumnLabels;
370
371   public boolean getCentreColumnLabels()
372   {
373     return centreColumnLabels;
374   }
375
376   public boolean followHighlight = true;
377
378   public boolean getFollowHighlight()
379   {
380     return followHighlight;
381   }
382
383   public boolean followSelection = true;
384
385   /**
386    * @return true if view selection should always follow the selections
387    *         broadcast by other selection sources
388    */
389   public boolean getFollowSelection()
390   {
391     return followSelection;
392   }
393
394   public void sendSelection()
395   {
396     getStructureSelectionManager().sendSelection(
397                     new SequenceGroup(getSelectionGroup()),
398                     new ColumnSelection(getColumnSelection()), this);
399   }
400
401   /**
402    * Returns an instance of the StructureSelectionManager scoped to this applet
403    * instance.
404    * 
405    * @return
406    */
407   @Override
408   public StructureSelectionManager getStructureSelectionManager()
409   {
410     return jalview.structure.StructureSelectionManager
411             .getStructureSelectionManager(applet);
412   }
413
414   /**
415    * synthesize a column selection if none exists so it covers the given
416    * selection group. if wholewidth is false, no column selection is made if the
417    * selection group covers the whole alignment width.
418    * 
419    * @param sg
420    * @param wholewidth
421    */
422   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
423   {
424     int sgs, sge;
425     if (sg != null
426             && (sgs = sg.getStartRes()) >= 0
427             && sg.getStartRes() <= (sge = sg.getEndRes())
428             && (colSel == null || colSel.getSelected() == null || colSel
429                     .getSelected().size() == 0))
430     {
431       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
432       {
433         // do nothing
434         return;
435       }
436       if (colSel == null)
437       {
438         colSel = new ColumnSelection();
439       }
440       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
441       {
442         colSel.addElement(cspos);
443       }
444     }
445   }
446
447   public boolean isNormaliseSequenceLogo()
448   {
449     return normaliseSequenceLogo;
450   }
451
452   public void setNormaliseSequenceLogo(boolean state)
453   {
454     normaliseSequenceLogo = state;
455   }
456
457   /**
458    * 
459    * @return true if alignment characters should be displayed
460    */
461   public boolean isValidCharWidth()
462   {
463     return validCharWidth;
464   }
465
466   public AnnotationColumnChooser getAnnotationColumnSelectionState()
467   {
468     return annotationColumnSelectionState;
469   }
470
471   public void setAnnotationColumnSelectionState(
472           AnnotationColumnChooser annotationColumnSelectionState)
473   {
474     this.annotationColumnSelectionState = annotationColumnSelectionState;
475   }
476
477   @Override
478   public void mirrorCommand(CommandI command, boolean undo,
479           StructureSelectionManager ssm, VamsasSource source)
480   {
481     // TODO refactor so this can be pulled up to superclass or controller
482     /*
483      * Do nothing unless we are a 'complement' of the source. May replace this
484      * with direct calls not via SSM.
485      */
486     if (source instanceof AlignViewportI
487             && ((AlignViewportI) source).getCodingComplement() == this)
488     {
489       // ok to continue;
490     }
491     else
492     {
493       return;
494     }
495
496     CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
497             getGapCharacter());
498     if (mappedCommand != null)
499     {
500       mappedCommand.doCommand(null);
501       firePropertyChange("alignment", null, getAlignment().getSequences());
502
503       // ap.scalePanelHolder.repaint();
504       // ap.repaint();
505     }
506   }
507
508   @Override
509   public VamsasSource getVamsasSource()
510   {
511     return this;
512   }
513
514 }