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