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