JAL-1780 more support for export setting for flatfile output
[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.AlignExportSettingI;
27 import jalview.api.AlignViewportI;
28 import jalview.api.FeatureRenderer;
29 import jalview.bin.JalviewLite;
30 import jalview.commands.CommandI;
31 import jalview.datamodel.AlignmentI;
32 import jalview.datamodel.ColumnSelection;
33 import jalview.datamodel.SearchResults;
34 import jalview.datamodel.Sequence;
35 import jalview.datamodel.SequenceGroup;
36 import jalview.datamodel.SequenceI;
37 import jalview.schemes.ColourSchemeProperty;
38 import jalview.schemes.UserColourScheme;
39 import jalview.structure.CommandListener;
40 import jalview.structure.SelectionSource;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.structure.VamsasSource;
43 import jalview.viewmodel.AlignmentViewport;
44
45 public class AlignViewport extends AlignmentViewport implements
46         SelectionSource, VamsasSource, CommandListener
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   private FeatureRenderer featureRenderer;
63
64   private AlignExportSettingI exportSettings;
65
66   public void finalize()
67   {
68     applet = null;
69     quality = null;
70     alignment = null;
71     colSel = null;
72   }
73
74   public AlignViewport(AlignmentI al, JalviewLite applet)
75   {
76     super();
77     calculator = new jalview.workers.AlignCalcManager();
78     this.applet = applet;
79     alignment = al;
80     // we always pad gaps
81     this.setPadGaps(true);
82     this.startRes = 0;
83     this.endRes = al.getWidth() - 1;
84     this.startSeq = 0;
85     this.endSeq = al.getHeight() - 1;
86     if (applet != null)
87     {
88       // get the width and height scaling factors if they were specified
89       String param = applet.getParameter("widthScale");
90       if (param != null)
91       {
92         try
93         {
94           widthScale = new Float(param).floatValue();
95         } catch (Exception e)
96         {
97         }
98         if (widthScale <= 1.0)
99         {
100           System.err
101                   .println("Invalid alignment character width scaling factor ("
102                           + widthScale + "). Ignoring.");
103           widthScale = 1;
104         }
105         if (JalviewLite.debug)
106         {
107           System.err
108                   .println("Alignment character width scaling factor is now "
109                           + widthScale);
110         }
111       }
112       param = applet.getParameter("heightScale");
113       if (param != null)
114       {
115         try
116         {
117           heightScale = new Float(param).floatValue();
118         } catch (Exception e)
119         {
120         }
121         if (heightScale <= 1.0)
122         {
123           System.err
124                   .println("Invalid alignment character height scaling factor ("
125                           + heightScale + "). Ignoring.");
126           heightScale = 1;
127         }
128         if (JalviewLite.debug)
129         {
130           System.err
131                   .println("Alignment character height scaling factor is now "
132                           + heightScale);
133         }
134       }
135     }
136     setFont(font);
137
138     MAC = new jalview.util.Platform().isAMac();
139
140     if (applet != null)
141     {
142       setShowJVSuffix(applet.getDefaultParameter("showFullId",
143               getShowJVSuffix()));
144
145       setShowAnnotation(applet.getDefaultParameter("showAnnotation",
146               isShowAnnotation()));
147
148       showConservation = applet.getDefaultParameter("showConservation",
149               showConservation);
150
151       showQuality = applet.getDefaultParameter("showQuality", showQuality);
152
153       showConsensus = applet.getDefaultParameter("showConsensus",
154               showConsensus);
155
156       setShowUnconserved(applet.getDefaultParameter("showUnconserved",
157               getShowUnconserved()));
158
159       setScaleProteinAsCdna(applet.getDefaultParameter(
160               "scaleProteinAsCdna", isScaleProteinAsCdna()));
161
162       String param = applet.getParameter("upperCase");
163       if (param != null)
164       {
165         if (param.equalsIgnoreCase("bold"))
166         {
167           setUpperCasebold(true);
168         }
169       }
170       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
171
172       setFollowHighlight(applet.getDefaultParameter("automaticScrolling",
173               isFollowHighlight()));
174       followSelection = isFollowHighlight();
175
176       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
177               showSequenceLogo);
178
179       normaliseSequenceLogo = applet.getDefaultParameter(
180               "normaliseSequenceLogo", applet.getDefaultParameter(
181                       "normaliseLogo", normaliseSequenceLogo));
182
183       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
184               showGroupConsensus);
185
186       showGroupConservation = applet.getDefaultParameter(
187               "showGroupConservation", showGroupConservation);
188
189       showConsensusHistogram = applet.getDefaultParameter(
190               "showConsensusHistogram", showConsensusHistogram);
191
192     }
193
194     if (applet != null)
195     {
196       String colour = applet.getParameter("defaultColour");
197
198       if (colour == null)
199       {
200         colour = applet.getParameter("userDefinedColour");
201         if (colour != null)
202         {
203           colour = "User Defined";
204         }
205       }
206
207       if (colour != null)
208       {
209         globalColourScheme = ColourSchemeProperty.getColour(alignment,
210                 colour);
211         if (globalColourScheme != null)
212         {
213           globalColourScheme.setConsensus(hconsensus);
214         }
215       }
216
217       if (applet.getParameter("userDefinedColour") != null)
218       {
219         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
220                 .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
297   public void resetSeqLimits(int height)
298   {
299     setEndSeq(height / getCharHeight());
300   }
301
302   public void setCurrentTree(NJTree tree)
303   {
304     currentTree = tree;
305   }
306
307   public NJTree getCurrentTree()
308   {
309     return currentTree;
310   }
311
312
313   boolean centreColumnLabels;
314
315   public boolean getCentreColumnLabels()
316   {
317     return centreColumnLabels;
318   }
319
320   public boolean followSelection = true;
321
322   /**
323    * @return true if view selection should always follow the selections
324    *         broadcast by other selection sources
325    */
326   public boolean getFollowSelection()
327   {
328     return followSelection;
329   }
330
331   public void sendSelection()
332   {
333     getStructureSelectionManager().sendSelection(
334                     new SequenceGroup(getSelectionGroup()),
335                     new ColumnSelection(getColumnSelection()), this);
336   }
337
338   /**
339    * Returns an instance of the StructureSelectionManager scoped to this applet
340    * instance.
341    * 
342    * @return
343    */
344   @Override
345   public StructureSelectionManager getStructureSelectionManager()
346   {
347     return jalview.structure.StructureSelectionManager
348             .getStructureSelectionManager(applet);
349   }
350
351   /**
352    * synthesize a column selection if none exists so it covers the given
353    * selection group. if wholewidth is false, no column selection is made if the
354    * selection group covers the whole alignment width.
355    * 
356    * @param sg
357    * @param wholewidth
358    */
359   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
360   {
361     int sgs, sge;
362     if (sg != null
363             && (sgs = sg.getStartRes()) >= 0
364             && sg.getStartRes() <= (sge = sg.getEndRes())
365             && (colSel == null || colSel.getSelected() == null || colSel
366                     .getSelected().size() == 0))
367     {
368       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
369       {
370         // do nothing
371         return;
372       }
373       if (colSel == null)
374       {
375         colSel = new ColumnSelection();
376       }
377       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
378       {
379         colSel.addElement(cspos);
380       }
381     }
382   }
383
384   public boolean isNormaliseSequenceLogo()
385   {
386     return normaliseSequenceLogo;
387   }
388
389   public void setNormaliseSequenceLogo(boolean state)
390   {
391     normaliseSequenceLogo = state;
392   }
393
394   /**
395    * 
396    * @return true if alignment characters should be displayed
397    */
398   public boolean isValidCharWidth()
399   {
400     return validCharWidth;
401   }
402
403   public AnnotationColumnChooser getAnnotationColumnSelectionState()
404   {
405     return annotationColumnSelectionState;
406   }
407
408   public void setAnnotationColumnSelectionState(
409           AnnotationColumnChooser annotationColumnSelectionState)
410   {
411     this.annotationColumnSelectionState = annotationColumnSelectionState;
412   }
413
414   @Override
415   public void mirrorCommand(CommandI command, boolean undo,
416           StructureSelectionManager ssm, VamsasSource source)
417   {
418     // TODO refactor so this can be pulled up to superclass or controller
419     /*
420      * Do nothing unless we are a 'complement' of the source. May replace this
421      * with direct calls not via SSM.
422      */
423     if (source instanceof AlignViewportI
424             && ((AlignViewportI) source).getCodingComplement() == this)
425     {
426       // ok to continue;
427     }
428     else
429     {
430       return;
431     }
432
433     CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
434             getGapCharacter());
435     if (mappedCommand != null)
436     {
437       mappedCommand.doCommand(null);
438       firePropertyChange("alignment", null, getAlignment().getSequences());
439
440       // ap.scalePanelHolder.repaint();
441       // ap.repaint();
442     }
443   }
444
445   @Override
446   public VamsasSource getVamsasSource()
447   {
448     return this;
449   }
450
451   /**
452    * If this viewport has a (Protein/cDNA) complement, then scroll the
453    * complementary alignment to match this one.
454    */
455   public void scrollComplementaryAlignment(AlignmentPanel complementPanel)
456   {
457     if (complementPanel == null)
458     {
459       return;
460     }
461
462     /*
463      * Populate a SearchResults object with the mapped location to scroll to. If
464      * there is no complement, or it is not following highlights, or no mapping
465      * is found, the result will be empty.
466      */
467     SearchResults sr = new SearchResults();
468     int seqOffset = findComplementScrollTarget(sr);
469     if (!sr.isEmpty())
470     {
471       complementPanel.setFollowingComplementScroll(true);
472       complementPanel.scrollToCentre(sr, seqOffset);
473     }
474   }
475
476   @Override
477   public FeatureRenderer getFeatureRenderer()
478   {
479     return featureRenderer;
480   }
481
482   @Override
483   public void setFeatureRenderer(FeatureRenderer featureRenderer)
484   {
485     this.featureRenderer = featureRenderer;
486
487   }
488
489   public AlignExportSettingI getExportSettings()
490   {
491     return exportSettings;
492   }
493
494   public void setExportSettings(AlignExportSettingI exportSettings)
495   {
496     this.exportSettings = exportSettings;
497   }
498
499
500 }