b0e29dae54974c77995d359f182e021ec852e103
[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       setScaleProteinAsCdna(applet.getDefaultParameter(
161               "scaleProteinAsCdna", isScaleProteinAsCdna()));
162
163       String param = applet.getParameter("upperCase");
164       if (param != null)
165       {
166         if (param.equalsIgnoreCase("bold"))
167         {
168           setUpperCasebold(true);
169         }
170       }
171       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
172
173       followHighlight = applet.getDefaultParameter("automaticScrolling",
174               followHighlight);
175       followSelection = followHighlight;
176
177       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
178               showSequenceLogo);
179
180       normaliseSequenceLogo = applet.getDefaultParameter(
181               "normaliseSequenceLogo", applet.getDefaultParameter(
182                       "normaliseLogo", normaliseSequenceLogo));
183
184       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
185               showGroupConsensus);
186
187       showGroupConservation = applet.getDefaultParameter(
188               "showGroupConservation", showGroupConservation);
189
190       showConsensusHistogram = applet.getDefaultParameter(
191               "showConsensusHistogram", showConsensusHistogram);
192
193     }
194
195     if (applet != null)
196     {
197       String colour = applet.getParameter("defaultColour");
198
199       if (colour == null)
200       {
201         colour = applet.getParameter("userDefinedColour");
202         if (colour != null)
203         {
204           colour = "User Defined";
205         }
206       }
207
208       if (colour != null)
209       {
210         globalColourScheme = ColourSchemeProperty.getColour(alignment,
211                 colour);
212         if (globalColourScheme != null)
213         {
214           globalColourScheme.setConsensus(hconsensus);
215         }
216       }
217
218       if (applet.getParameter("userDefinedColour") != null)
219       {
220         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
221                 .getParameter("userDefinedColour"));
222       }
223     }
224     initAutoAnnotation();
225
226   }
227
228   /**
229    * get the consensus sequence as displayed under the PID consensus annotation
230    * row.
231    * 
232    * @return consensus sequence as a new sequence object
233    */
234   public SequenceI getConsensusSeq()
235   {
236     if (consensus == null)
237     {
238       updateConsensus(null);
239     }
240     if (consensus == null)
241     {
242       return null;
243     }
244     StringBuilder seqs = new StringBuilder(consensus.annotations.length);
245     for (int i = 0; i < consensus.annotations.length; i++)
246     {
247       if (consensus.annotations[i] != null)
248       {
249         if (consensus.annotations[i].description.charAt(0) == '[')
250         {
251           seqs.append(consensus.annotations[i].description.charAt(1));
252         }
253         else
254         {
255           seqs.append(consensus.annotations[i].displayCharacter);
256         }
257       }
258     }
259     SequenceI sq = new Sequence("Consensus", seqs.toString());
260     sq.setDescription("Percentage Identity Consensus "
261             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
262     return sq;
263   }
264
265   public int getStartRes()
266   {
267     return startRes;
268   }
269
270   public int getEndRes()
271   {
272     return endRes;
273   }
274
275   public int getStartSeq()
276   {
277     return startSeq;
278   }
279
280   public void setStartRes(int res)
281   {
282     this.startRes = res;
283   }
284
285   public void setStartSeq(int seq)
286   {
287     this.startSeq = seq;
288   }
289
290   public void setEndRes(int res)
291   {
292     if (res > alignment.getWidth() - 1)
293     {
294       // log.System.out.println(" Corrected res from " + res + " to maximum " +
295       // (alignment.getWidth()-1));
296       res = alignment.getWidth() - 1;
297     }
298     if (res < 0)
299     {
300       res = 0;
301     }
302     this.endRes = res;
303   }
304
305   public void setEndSeq(int seq)
306   {
307     if (seq > alignment.getHeight())
308     {
309       seq = alignment.getHeight();
310     }
311     if (seq < 0)
312     {
313       seq = 0;
314     }
315     this.endSeq = seq;
316   }
317
318   public int getEndSeq()
319   {
320     return endSeq;
321   }
322
323   java.awt.Frame nullFrame;
324
325   protected FeatureSettings featureSettings = null;
326
327   private float heightScale = 1, widthScale = 1;
328
329   public void setFont(Font f)
330   {
331     font = f;
332     if (nullFrame == null)
333     {
334       nullFrame = new java.awt.Frame();
335       nullFrame.addNotify();
336     }
337
338     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
339     setCharHeight((int) (heightScale * fm.getHeight()));
340     setCharWidth((int) (widthScale * fm.charWidth('M')));
341
342     if (isUpperCasebold())
343     {
344       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
345       fm = nullFrame.getGraphics().getFontMetrics(f2);
346       setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
347     }
348   }
349
350   public Font getFont()
351   {
352     return font;
353   }
354
355
356   public void resetSeqLimits(int height)
357   {
358     setEndSeq(height / getCharHeight());
359   }
360
361   public void setCurrentTree(NJTree tree)
362   {
363     currentTree = tree;
364   }
365
366   public NJTree getCurrentTree()
367   {
368     return currentTree;
369   }
370
371
372   boolean centreColumnLabels;
373
374   public boolean getCentreColumnLabels()
375   {
376     return centreColumnLabels;
377   }
378
379   public boolean followHighlight = true;
380
381   public boolean getFollowHighlight()
382   {
383     return followHighlight;
384   }
385
386   public boolean followSelection = true;
387
388   /**
389    * @return true if view selection should always follow the selections
390    *         broadcast by other selection sources
391    */
392   public boolean getFollowSelection()
393   {
394     return followSelection;
395   }
396
397   public void sendSelection()
398   {
399     getStructureSelectionManager().sendSelection(
400                     new SequenceGroup(getSelectionGroup()),
401                     new ColumnSelection(getColumnSelection()), this);
402   }
403
404   /**
405    * Returns an instance of the StructureSelectionManager scoped to this applet
406    * instance.
407    * 
408    * @return
409    */
410   @Override
411   public StructureSelectionManager getStructureSelectionManager()
412   {
413     return jalview.structure.StructureSelectionManager
414             .getStructureSelectionManager(applet);
415   }
416
417   /**
418    * synthesize a column selection if none exists so it covers the given
419    * selection group. if wholewidth is false, no column selection is made if the
420    * selection group covers the whole alignment width.
421    * 
422    * @param sg
423    * @param wholewidth
424    */
425   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
426   {
427     int sgs, sge;
428     if (sg != null
429             && (sgs = sg.getStartRes()) >= 0
430             && sg.getStartRes() <= (sge = sg.getEndRes())
431             && (colSel == null || colSel.getSelected() == null || colSel
432                     .getSelected().size() == 0))
433     {
434       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
435       {
436         // do nothing
437         return;
438       }
439       if (colSel == null)
440       {
441         colSel = new ColumnSelection();
442       }
443       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
444       {
445         colSel.addElement(cspos);
446       }
447     }
448   }
449
450   public boolean isNormaliseSequenceLogo()
451   {
452     return normaliseSequenceLogo;
453   }
454
455   public void setNormaliseSequenceLogo(boolean state)
456   {
457     normaliseSequenceLogo = state;
458   }
459
460   /**
461    * 
462    * @return true if alignment characters should be displayed
463    */
464   public boolean isValidCharWidth()
465   {
466     return validCharWidth;
467   }
468
469   public AnnotationColumnChooser getAnnotationColumnSelectionState()
470   {
471     return annotationColumnSelectionState;
472   }
473
474   public void setAnnotationColumnSelectionState(
475           AnnotationColumnChooser annotationColumnSelectionState)
476   {
477     this.annotationColumnSelectionState = annotationColumnSelectionState;
478   }
479
480   @Override
481   public void mirrorCommand(CommandI command, boolean undo,
482           StructureSelectionManager ssm, VamsasSource source)
483   {
484     // TODO refactor so this can be pulled up to superclass or controller
485     /*
486      * Do nothing unless we are a 'complement' of the source. May replace this
487      * with direct calls not via SSM.
488      */
489     if (source instanceof AlignViewportI
490             && ((AlignViewportI) source).getCodingComplement() == this)
491     {
492       // ok to continue;
493     }
494     else
495     {
496       return;
497     }
498
499     CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
500             getGapCharacter());
501     if (mappedCommand != null)
502     {
503       mappedCommand.doCommand(null);
504       firePropertyChange("alignment", null, getAlignment().getSequences());
505
506       // ap.scalePanelHolder.repaint();
507       // ap.repaint();
508     }
509   }
510
511   @Override
512   public VamsasSource getVamsasSource()
513   {
514     return this;
515   }
516
517 }