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