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