9a15e109c841164e69830f47ad36e5c12f97f45d
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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.util.*;
24
25 import java.awt.*;
26
27 import jalview.analysis.*;
28 import jalview.api.AlignViewportI;
29 import jalview.bin.*;
30 import jalview.datamodel.*;
31 import jalview.schemes.*;
32 import jalview.structure.SelectionSource;
33 import jalview.structure.VamsasSource;
34 import jalview.viewmodel.AlignmentViewport;
35
36 public class AlignViewport extends AlignmentViewport implements
37         AlignViewportI, SelectionSource, VamsasSource
38 {
39   int startRes;
40
41   int endRes;
42
43   int startSeq;
44
45   int endSeq;
46
47   boolean cursorMode = false;
48
49   boolean showJVSuffix = true;
50
51   boolean showText = true;
52
53   boolean showColourText = false;
54
55   boolean showBoxes = true;
56
57   boolean wrapAlignment = false;
58
59   boolean renderGaps = true;
60
61   boolean showAnnotation = true;
62
63   boolean upperCasebold = false;
64
65   int charHeight;
66
67   int charWidth;
68
69   int wrappedWidth;
70
71   Font font = new Font("SansSerif", Font.PLAIN, 10);
72
73   boolean validCharWidth = true;
74
75   int threshold;
76
77   int increment;
78
79   NJTree currentTree = null;
80
81   boolean scaleAboveWrapped = true;
82
83   boolean scaleLeftWrapped = true;
84
85   boolean scaleRightWrapped = true;
86
87   boolean showHiddenMarkers = true;
88
89   public jalview.bin.JalviewLite applet;
90
91   boolean MAC = false;
92
93   Stack historyList = new Stack();
94
95   Stack redoList = new Stack();
96
97   public void finalize()
98   {
99     applet = null;
100     quality = null;
101     alignment = null;
102     colSel = null;
103   }
104
105   public AlignViewport(AlignmentI al, JalviewLite applet)
106   {
107     calculator = new jalview.workers.AlignCalcManager();
108     this.applet = applet;
109     setAlignment(al);
110     // we always pad gaps
111     this.setPadGaps(true);
112     this.startRes = 0;
113     this.endRes = al.getWidth() - 1;
114     this.startSeq = 0;
115     this.endSeq = al.getHeight() - 1;
116     if (applet != null)
117     {
118       // get the width and height scaling factors if they were specified
119       String param = applet.getParameter("widthScale");
120       if (param != null)
121       {
122         try
123         {
124           widthScale = new Float(param).floatValue();
125         } catch (Exception e)
126         {
127         }
128         if (widthScale <= 1.0)
129         {
130           System.err
131                   .println("Invalid alignment character width scaling factor ("
132                           + widthScale + "). Ignoring.");
133           widthScale = 1;
134         }
135         if (applet.debug)
136         {
137           System.err
138                   .println("Alignment character width scaling factor is now "
139                           + widthScale);
140         }
141       }
142       param = applet.getParameter("heightScale");
143       if (param != null)
144       {
145         try
146         {
147           heightScale = new Float(param).floatValue();
148         } catch (Exception e)
149         {
150         }
151         if (heightScale <= 1.0)
152         {
153           System.err
154                   .println("Invalid alignment character height scaling factor ("
155                           + heightScale + "). Ignoring.");
156           heightScale = 1;
157         }
158         if (applet.debug)
159         {
160           System.err
161                   .println("Alignment character height scaling factor is now "
162                           + heightScale);
163         }
164       }
165     }
166     setFont(font);
167
168     MAC = new jalview.util.Platform().isAMac();
169
170     if (applet != null)
171     {
172       showJVSuffix = applet.getDefaultParameter("showFullId", showJVSuffix);
173
174       showAnnotation = applet.getDefaultParameter("showAnnotation",
175               showAnnotation);
176
177       showConservation = applet.getDefaultParameter("showConservation",
178               showConservation);
179
180       showQuality = applet.getDefaultParameter("showQuality", showQuality);
181
182       showConsensus = applet.getDefaultParameter("showConsensus",
183               showConsensus);
184
185       showUnconserved = applet.getDefaultParameter("showUnconserved",
186               showUnconserved);
187
188       String param = applet.getParameter("upperCase");
189       if (param != null)
190       {
191         if (param.equalsIgnoreCase("bold"))
192         {
193           upperCasebold = true;
194         }
195       }
196       sortByTree = applet.getDefaultParameter("sortByTree", sortByTree);
197
198       followHighlight = applet.getDefaultParameter("automaticScrolling",
199               followHighlight);
200       followSelection = followHighlight;
201
202       showSequenceLogo = applet.getDefaultParameter("showSequenceLogo",
203               showSequenceLogo);
204
205       normaliseSequenceLogo = applet.getDefaultParameter(
206               "normaliseSequenceLogo", applet.getDefaultParameter(
207                       "normaliseLogo", normaliseSequenceLogo));
208
209       showGroupConsensus = applet.getDefaultParameter("showGroupConsensus",
210               showGroupConsensus);
211
212       showGroupConservation = applet.getDefaultParameter(
213               "showGroupConservation", showGroupConservation);
214
215       showConsensusHistogram = applet.getDefaultParameter(
216               "showConsensusHistogram", showConsensusHistogram);
217
218     }
219
220     if (applet != null)
221     {
222       String colour = applet.getParameter("defaultColour");
223
224       if (colour == null)
225       {
226         colour = applet.getParameter("userDefinedColour");
227         if (colour != null)
228         {
229           colour = "User Defined";
230         }
231       }
232
233       if (colour != null)
234       {
235         globalColourScheme = ColourSchemeProperty.getColour(alignment,
236                 colour);
237         if (globalColourScheme != null)
238         {
239           globalColourScheme.setConsensus(hconsensus);
240         }
241       }
242
243       if (applet.getParameter("userDefinedColour") != null)
244       {
245         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
246                 .getParameter("userDefinedColour"));
247       }
248     }
249     initAutoAnnotation();
250
251   }
252
253   /**
254    * get the consensus sequence as displayed under the PID consensus annotation
255    * row.
256    * 
257    * @return consensus sequence as a new sequence object
258    */
259   public SequenceI getConsensusSeq()
260   {
261     if (consensus == null)
262     {
263       updateConsensus(null);
264     }
265     if (consensus == null)
266     {
267       return null;
268     }
269     StringBuffer seqs = new StringBuffer();
270     for (int i = 0; i < consensus.annotations.length; i++)
271     {
272       if (consensus.annotations[i] != null)
273       {
274         if (consensus.annotations[i].description.charAt(0) == '[')
275         {
276           seqs.append(consensus.annotations[i].description.charAt(1));
277         }
278         else
279         {
280           seqs.append(consensus.annotations[i].displayCharacter);
281         }
282       }
283     }
284     SequenceI sq = new Sequence("Consensus", seqs.toString());
285     sq.setDescription("Percentage Identity Consensus "
286             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
287     return sq;
288   }
289
290   public int getStartRes()
291   {
292     return startRes;
293   }
294
295   public int getEndRes()
296   {
297     return endRes;
298   }
299
300   public int getStartSeq()
301   {
302     return startSeq;
303   }
304
305   public void setStartRes(int res)
306   {
307     this.startRes = res;
308   }
309
310   public void setStartSeq(int seq)
311   {
312     this.startSeq = seq;
313   }
314
315   public void setEndRes(int res)
316   {
317     if (res > alignment.getWidth() - 1)
318     {
319       // log.System.out.println(" Corrected res from " + res + " to maximum " +
320       // (alignment.getWidth()-1));
321       res = alignment.getWidth() - 1;
322     }
323     if (res < 0)
324     {
325       res = 0;
326     }
327     this.endRes = res;
328   }
329
330   public void setEndSeq(int seq)
331   {
332     if (seq > alignment.getHeight())
333     {
334       seq = alignment.getHeight();
335     }
336     if (seq < 0)
337     {
338       seq = 0;
339     }
340     this.endSeq = seq;
341   }
342
343   public int getEndSeq()
344   {
345     return endSeq;
346   }
347
348   java.awt.Frame nullFrame;
349
350   protected FeatureSettings featureSettings = null;
351
352   private float heightScale = 1, widthScale = 1;
353
354   public void setFont(Font f)
355   {
356     font = f;
357     if (nullFrame == null)
358     {
359       nullFrame = new java.awt.Frame();
360       nullFrame.addNotify();
361     }
362
363     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
364     setCharHeight((int) (heightScale * fm.getHeight()));
365     charWidth = (int) (widthScale * fm.charWidth('M'));
366
367     if (upperCasebold)
368     {
369       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
370       fm = nullFrame.getGraphics().getFontMetrics(f2);
371       charWidth = (int) (widthScale * (fm.stringWidth("MMMMMMMMMMM") / 10));
372     }
373   }
374
375   public Font getFont()
376   {
377     return font;
378   }
379
380   public int getCharWidth()
381   {
382     return charWidth;
383   }
384
385   public void setCharHeight(int h)
386   {
387     this.charHeight = h;
388   }
389
390   public int getCharHeight()
391   {
392     return charHeight;
393   }
394
395   public void setWrappedWidth(int w)
396   {
397     this.wrappedWidth = w;
398   }
399
400   public int getwrappedWidth()
401   {
402     return wrappedWidth;
403   }
404
405   public AlignmentI getAlignment()
406   {
407     return alignment;
408   }
409
410   public void setAlignment(AlignmentI align)
411   {
412     this.alignment = align;
413   }
414
415   public void setWrapAlignment(boolean state)
416   {
417     wrapAlignment = state;
418   }
419
420   public void setShowText(boolean state)
421   {
422     showText = state;
423   }
424
425   public void setRenderGaps(boolean state)
426   {
427     renderGaps = state;
428   }
429
430   public boolean getColourText()
431   {
432     return showColourText;
433   }
434
435   public void setColourText(boolean state)
436   {
437     showColourText = state;
438   }
439
440   public void setShowBoxes(boolean state)
441   {
442     showBoxes = state;
443   }
444
445   public boolean getWrapAlignment()
446   {
447     return wrapAlignment;
448   }
449
450   public boolean getShowText()
451   {
452     return showText;
453   }
454
455   public boolean getShowBoxes()
456   {
457     return showBoxes;
458   }
459
460   public char getGapCharacter()
461   {
462     return getAlignment().getGapCharacter();
463   }
464
465   public void setGapCharacter(char gap)
466   {
467     if (getAlignment() != null)
468     {
469       getAlignment().setGapCharacter(gap);
470     }
471   }
472
473   public void resetSeqLimits(int height)
474   {
475     setEndSeq(height / getCharHeight());
476   }
477
478   public void setCurrentTree(NJTree tree)
479   {
480     currentTree = tree;
481   }
482
483   public NJTree getCurrentTree()
484   {
485     return currentTree;
486   }
487
488   public boolean getShowJVSuffix()
489   {
490     return showJVSuffix;
491   }
492
493   public void setShowJVSuffix(boolean b)
494   {
495     showJVSuffix = b;
496   }
497
498   public boolean getShowAnnotation()
499   {
500     return showAnnotation;
501   }
502
503   public void setShowAnnotation(boolean b)
504   {
505     showAnnotation = b;
506   }
507
508   public boolean getScaleAboveWrapped()
509   {
510     return scaleAboveWrapped;
511   }
512
513   public boolean getScaleLeftWrapped()
514   {
515     return scaleLeftWrapped;
516   }
517
518   public boolean getScaleRightWrapped()
519   {
520     return scaleRightWrapped;
521   }
522
523   public void setScaleAboveWrapped(boolean b)
524   {
525     scaleAboveWrapped = b;
526   }
527
528   public void setScaleLeftWrapped(boolean b)
529   {
530     scaleLeftWrapped = b;
531   }
532
533   public void setScaleRightWrapped(boolean b)
534   {
535     scaleRightWrapped = b;
536   }
537
538   public void setIgnoreGapsConsensus(boolean b)
539   {
540     ignoreGapsInConsensusCalculation = b;
541     updateConsensus(null);
542     if (globalColourScheme != null)
543     {
544       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
545               ignoreGapsInConsensusCalculation);
546
547     }
548   }
549
550   public boolean getShowHiddenMarkers()
551   {
552     return showHiddenMarkers;
553   }
554
555   public void setShowHiddenMarkers(boolean show)
556   {
557     showHiddenMarkers = show;
558   }
559
560   boolean centreColumnLabels;
561
562   public boolean getCentreColumnLabels()
563   {
564     return centreColumnLabels;
565   }
566
567   public boolean followHighlight = true;
568
569   public boolean getFollowHighlight()
570   {
571     return followHighlight;
572   }
573
574   public boolean followSelection = true;
575
576   /**
577    * @return true if view selection should always follow the selections
578    *         broadcast by other selection sources
579    */
580   public boolean getFollowSelection()
581   {
582     return followSelection;
583   }
584
585   public void sendSelection()
586   {
587     jalview.structure.StructureSelectionManager
588             .getStructureSelectionManager(applet).sendSelection(
589                     new SequenceGroup(getSelectionGroup()),
590                     new ColumnSelection(getColumnSelection()), this);
591   }
592
593   /**
594    * synthesize a column selection if none exists so it covers the given
595    * selection group. if wholewidth is false, no column selection is made if the
596    * selection group covers the whole alignment width.
597    * 
598    * @param sg
599    * @param wholewidth
600    */
601   public void expandColSelection(SequenceGroup sg, boolean wholewidth)
602   {
603     int sgs, sge;
604     if (sg != null
605             && (sgs = sg.getStartRes()) >= 0
606             && sg.getStartRes() <= (sge = sg.getEndRes())
607             && (colSel == null || colSel.getSelected() == null || colSel
608                     .getSelected().size() == 0))
609     {
610       if (!wholewidth && alignment.getWidth() == (1 + sge - sgs))
611       {
612         // do nothing
613         return;
614       }
615       if (colSel == null)
616       {
617         colSel = new ColumnSelection();
618       }
619       for (int cspos = sg.getStartRes(); cspos <= sg.getEndRes(); cspos++)
620       {
621         colSel.addElement(cspos);
622       }
623     }
624   }
625
626   @Override
627   public boolean hasHiddenColumns()
628   {
629     return hasHiddenColumns;
630   }
631
632   public boolean isNormaliseSequenceLogo()
633   {
634     return normaliseSequenceLogo;
635   }
636
637   public void setNormaliseSequenceLogo(boolean state)
638   {
639     normaliseSequenceLogo = state;
640   }
641
642   /**
643    * 
644    * @return true if alignment characters should be displayed
645    */
646   public boolean isValidCharWidth()
647   {
648     return validCharWidth;
649   }
650
651 }