JAL-2388 Made ViewportRanges final
[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 jalview.analysis.NJTree;
24 import jalview.api.AlignViewportI;
25 import jalview.api.FeatureSettingsModelI;
26 import jalview.bin.JalviewLite;
27 import jalview.commands.CommandI;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.ColumnSelection;
30 import jalview.datamodel.SearchResults;
31 import jalview.datamodel.SearchResultsI;
32 import jalview.datamodel.Sequence;
33 import jalview.datamodel.SequenceGroup;
34 import jalview.datamodel.SequenceI;
35 import jalview.renderer.ResidueShader;
36 import jalview.schemes.ColourSchemeProperty;
37 import jalview.schemes.UserColourScheme;
38 import jalview.structure.SelectionSource;
39 import jalview.structure.StructureSelectionManager;
40 import jalview.structure.VamsasSource;
41 import jalview.viewmodel.AlignmentViewport;
42
43 import java.awt.Font;
44
45 public class AlignViewport extends AlignmentViewport implements
46         SelectionSource
47 {
48   boolean cursorMode = false;
49
50   Font font = new Font("SansSerif", Font.PLAIN, 10);
51
52   boolean validCharWidth = true;
53
54   NJTree currentTree = null;
55
56   public jalview.bin.JalviewLite applet;
57
58   boolean MAC = false;
59
60   private AnnotationColumnChooser annotationColumnSelectionState;
61
62   @Override
63   public void finalize()
64   {
65     applet = null;
66     quality = null;
67     alignment = null;
68     colSel = null;
69   }
70
71   public AlignViewport(AlignmentI al, JalviewLite applet)
72   {
73     super(al);
74     calculator = new jalview.workers.AlignCalcManager();
75     this.applet = applet;
76
77     // we always pad gaps
78     this.setPadGaps(true);
79
80     if (applet != null)
81     {
82       // get the width and height scaling factors if they were specified
83       String param = applet.getParameter("widthScale");
84       if (param != null)
85       {
86         try
87         {
88           widthScale = new Float(param).floatValue();
89         } catch (Exception e)
90         {
91         }
92         if (widthScale <= 1.0)
93         {
94           System.err
95                   .println("Invalid alignment character width scaling factor ("
96                           + widthScale + "). Ignoring.");
97           widthScale = 1;
98         }
99         if (JalviewLite.debug)
100         {
101           System.err
102                   .println("Alignment character width scaling factor is now "
103                           + widthScale);
104         }
105       }
106       param = applet.getParameter("heightScale");
107       if (param != null)
108       {
109         try
110         {
111           heightScale = new Float(param).floatValue();
112         } catch (Exception e)
113         {
114         }
115         if (heightScale <= 1.0)
116         {
117           System.err
118                   .println("Invalid alignment character height scaling factor ("
119                           + heightScale + "). Ignoring.");
120           heightScale = 1;
121         }
122         if (JalviewLite.debug)
123         {
124           System.err
125                   .println("Alignment character height scaling factor is now "
126                           + heightScale);
127         }
128       }
129     }
130     setFont(font);
131
132     MAC = new jalview.util.Platform().isAMac();
133
134     if (applet != null)
135     {
136       setShowJVSuffix(applet.getDefaultParameter("showFullId",
137               getShowJVSuffix()));
138
139       setShowAnnotation(applet.getDefaultParameter("showAnnotation",
140               isShowAnnotation()));
141
142       showConservation = applet.getDefaultParameter("showConservation",
143               showConservation);
144
145       showQuality = applet.getDefaultParameter("showQuality", showQuality);
146
147       showConsensus = applet.getDefaultParameter("showConsensus",
148               showConsensus);
149
150       setShowUnconserved(applet.getDefaultParameter("showUnconserved",
151               getShowUnconserved()));
152
153       setScaleProteinAsCdna(applet.getDefaultParameter(
154               "scaleProteinAsCdna", isScaleProteinAsCdna()));
155
156       String param = applet.getParameter("upperCase");
157       if (param != null)
158       {
159         if (param.equalsIgnoreCase("bold"))
160         {
161           setUpperCasebold(true);
162         }
163       }
164       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
165
166       setFollowHighlight(applet.getDefaultParameter("automaticScrolling",
167               isFollowHighlight()));
168       followSelection = isFollowHighlight();
169
170       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
171               showSequenceLogo);
172
173       normaliseSequenceLogo = applet.getDefaultParameter(
174               "normaliseSequenceLogo", applet.getDefaultParameter(
175                       "normaliseLogo", normaliseSequenceLogo));
176
177       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
178               showGroupConsensus);
179
180       showGroupConservation = applet.getDefaultParameter(
181               "showGroupConservation", showGroupConservation);
182
183       showConsensusHistogram = applet.getDefaultParameter(
184               "showConsensusHistogram", showConsensusHistogram);
185
186     }
187
188     if (applet != null)
189     {
190       String colour = al.isNucleotide() ? applet
191               .getParameter("defaultColourNuc") : applet
192               .getParameter("defaultColourProt");
193       if (colour == null)
194       {
195         colour = applet.getParameter("defaultColour");
196       }
197       if (colour == null)
198       {
199         colour = applet.getParameter("userDefinedColour");
200         if (colour != null)
201         {
202           colour = "User Defined";
203         }
204       }
205
206       if (colour != null)
207       {
208         residueShading = new ResidueShader(
209                 ColourSchemeProperty.getColourScheme(alignment, colour));
210         if (residueShading != null)
211         {
212           residueShading.setConsensus(hconsensus);
213         }
214       }
215
216       if (applet.getParameter("userDefinedColour") != null)
217       {
218         residueShading = new ResidueShader(
219                 new UserColourScheme(
220                         applet.getParameter("userDefinedColour")));
221       }
222     }
223     initAutoAnnotation();
224
225   }
226
227   /**
228    * get the consensus sequence as displayed under the PID consensus annotation
229    * row.
230    * 
231    * @return consensus sequence as a new sequence object
232    */
233   public SequenceI getConsensusSeq()
234   {
235     if (consensus == null)
236     {
237       updateConsensus(null);
238     }
239     if (consensus == null)
240     {
241       return null;
242     }
243     StringBuilder seqs = new StringBuilder(consensus.annotations.length);
244     for (int i = 0; i < consensus.annotations.length; i++)
245     {
246       if (consensus.annotations[i] != null)
247       {
248         if (consensus.annotations[i].description.charAt(0) == '[')
249         {
250           seqs.append(consensus.annotations[i].description.charAt(1));
251         }
252         else
253         {
254           seqs.append(consensus.annotations[i].displayCharacter);
255         }
256       }
257     }
258     SequenceI sq = new Sequence("Consensus", seqs.toString());
259     sq.setDescription("Percentage Identity Consensus "
260             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
261     return sq;
262   }
263
264   java.awt.Frame nullFrame;
265
266   protected FeatureSettings featureSettings = null;
267
268   private float heightScale = 1, widthScale = 1;
269
270   public void setFont(Font f)
271   {
272     font = f;
273     if (nullFrame == null)
274     {
275       nullFrame = new java.awt.Frame();
276       nullFrame.addNotify();
277     }
278
279     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
280     setCharHeight((int) (heightScale * fm.getHeight()));
281     setCharWidth((int) (widthScale * fm.charWidth('M')));
282
283     if (isUpperCasebold())
284     {
285       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
286       fm = nullFrame.getGraphics().getFontMetrics(f2);
287       setCharWidth((int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10)));
288     }
289   }
290
291   public Font getFont()
292   {
293     return font;
294   }
295
296   public void resetSeqLimits(int height)
297   {
298     ranges.setEndSeq(height / getCharHeight());
299   }
300
301   public void setCurrentTree(NJTree tree)
302   {
303     currentTree = tree;
304   }
305
306   public NJTree getCurrentTree()
307   {
308     return currentTree;
309   }
310
311   boolean centreColumnLabels;
312
313   public boolean getCentreColumnLabels()
314   {
315     return centreColumnLabels;
316   }
317
318   public boolean followSelection = true;
319
320   /**
321    * @return true if view selection should always follow the selections
322    *         broadcast by other selection sources
323    */
324   public boolean getFollowSelection()
325   {
326     return followSelection;
327   }
328
329   @Override
330   public void sendSelection()
331   {
332     getStructureSelectionManager().sendSelection(
333             new SequenceGroup(getSelectionGroup()),
334             new ColumnSelection(getColumnSelection()), this);
335   }
336
337   /**
338    * Returns an instance of the StructureSelectionManager scoped to this applet
339    * instance.
340    * 
341    * @return
342    */
343   @Override
344   public StructureSelectionManager getStructureSelectionManager()
345   {
346     return jalview.structure.StructureSelectionManager
347             .getStructureSelectionManager(applet);
348   }
349
350   @Override
351   public boolean isNormaliseSequenceLogo()
352   {
353     return normaliseSequenceLogo;
354   }
355
356   public void setNormaliseSequenceLogo(boolean state)
357   {
358     normaliseSequenceLogo = state;
359   }
360
361   /**
362    * 
363    * @return true if alignment characters should be displayed
364    */
365   @Override
366   public boolean isValidCharWidth()
367   {
368     return validCharWidth;
369   }
370
371   public AnnotationColumnChooser getAnnotationColumnSelectionState()
372   {
373     return annotationColumnSelectionState;
374   }
375
376   public void setAnnotationColumnSelectionState(
377           AnnotationColumnChooser annotationColumnSelectionState)
378   {
379     this.annotationColumnSelectionState = annotationColumnSelectionState;
380   }
381
382   @Override
383   public void mirrorCommand(CommandI command, boolean undo,
384           StructureSelectionManager ssm, VamsasSource source)
385   {
386     // TODO refactor so this can be pulled up to superclass or controller
387     /*
388      * Do nothing unless we are a 'complement' of the source. May replace this
389      * with direct calls not via SSM.
390      */
391     if (source instanceof AlignViewportI
392             && ((AlignViewportI) source).getCodingComplement() == this)
393     {
394       // ok to continue;
395     }
396     else
397     {
398       return;
399     }
400
401     CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
402             getGapCharacter());
403     if (mappedCommand != null)
404     {
405       mappedCommand.doCommand(null);
406       firePropertyChange("alignment", null, getAlignment().getSequences());
407
408       // ap.scalePanelHolder.repaint();
409       // ap.repaint();
410     }
411   }
412
413   @Override
414   public VamsasSource getVamsasSource()
415   {
416     return this;
417   }
418
419   /**
420    * If this viewport has a (Protein/cDNA) complement, then scroll the
421    * complementary alignment to match this one.
422    */
423   public void scrollComplementaryAlignment(AlignmentPanel complementPanel)
424   {
425     if (complementPanel == null)
426     {
427       return;
428     }
429
430     /*
431      * Populate a SearchResults object with the mapped location to scroll to. If
432      * there is no complement, or it is not following highlights, or no mapping
433      * is found, the result will be empty.
434      */
435     SearchResultsI sr = new SearchResults();
436     int seqOffset = findComplementScrollTarget(sr);
437     if (!sr.isEmpty())
438     {
439       complementPanel.setFollowingComplementScroll(true);
440       complementPanel.scrollToCentre(sr, seqOffset);
441     }
442   }
443
444   /**
445    * Applies the supplied feature settings descriptor to currently known
446    * features. This supports an 'initial configuration' of feature colouring
447    * based on a preset or user favourite. This may then be modified in the usual
448    * way using the Feature Settings dialogue.
449    * 
450    * @param featureSettings
451    */
452   @Override
453   public void applyFeaturesStyle(FeatureSettingsModelI featureSettings)
454   {
455     // TODO implement for applet
456   }
457
458 }