JAL-1683 replace year/version strings with tokens in source
[jalview.git] / src / jalview / appletgui / SequenceRenderer.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 jalview.api.FeatureRenderer;
24 import jalview.datamodel.AlignmentAnnotation;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.datamodel.SequenceI;
27 import jalview.schemes.ColourSchemeI;
28
29 import java.awt.Color;
30 import java.awt.Font;
31 import java.awt.FontMetrics;
32 import java.awt.Graphics;
33
34 public class SequenceRenderer implements jalview.api.SequenceRenderer
35 {
36   AlignViewport av;
37
38   FontMetrics fm;
39
40   boolean renderGaps = true;
41
42   SequenceGroup currentSequenceGroup = null;
43
44   SequenceGroup[] allGroups = null;
45
46   Color resBoxColour;
47
48   Graphics graphics;
49
50   boolean forOverview = false;
51
52   public SequenceRenderer(AlignViewport av)
53   {
54     this.av = av;
55   }
56
57   /**
58    * DOCUMENT ME!
59    * 
60    * @param b
61    *          DOCUMENT ME!
62    */
63   public void prepare(Graphics g, boolean renderGaps)
64   {
65     graphics = g;
66     fm = g.getFontMetrics();
67
68     this.renderGaps = renderGaps;
69   }
70
71   public Color getResidueBoxColour(SequenceI seq, int i)
72   {
73     allGroups = av.getAlignment().findAllGroups(seq);
74
75     if (inCurrentSequenceGroup(i))
76     {
77       if (currentSequenceGroup.getDisplayBoxes())
78       {
79         getBoxColour(currentSequenceGroup.cs, seq, i);
80       }
81     }
82     else if (av.getShowBoxes())
83     {
84       getBoxColour(av.getGlobalColourScheme(), seq, i);
85     }
86
87     return resBoxColour;
88   }
89
90   /**
91    * Get the residue colour at the given sequence position - as determined by
92    * the sequence group colour (if any), else the colour scheme, possibly
93    * overridden by a feature colour.
94    * 
95    * @param seq
96    * @param position
97    * @param fr
98    * @return
99    */
100   @Override
101   public Color getResidueColour(final SequenceI seq, int position,
102           FeatureRenderer fr)
103   {
104     // TODO replace 8 or so code duplications with calls to this method
105     // (refactored as needed)
106     Color col = getResidueBoxColour(seq, position);
107
108     if (fr != null)
109     {
110       col = fr.findFeatureColour(col, seq, position);
111     }
112     return col;
113   }
114
115   void getBoxColour(ColourSchemeI cs, SequenceI seq, int i)
116   {
117     if (cs != null)
118     {
119       resBoxColour = cs.findColour(seq.getCharAt(i), i, seq);
120     }
121     else if (forOverview
122             && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
123     {
124       resBoxColour = Color.lightGray;
125     }
126     else
127     {
128       resBoxColour = Color.white;
129     }
130
131   }
132
133   public Color findSequenceColour(SequenceI seq, int i)
134   {
135     allGroups = av.getAlignment().findAllGroups(seq);
136     drawBoxes(seq, i, i, 0);
137     return resBoxColour;
138   }
139
140   public void drawSequence(SequenceI seq, SequenceGroup[] sg, int start,
141           int end, int y1)
142   {
143     if (seq == null)
144     {
145       return;
146     }
147
148     allGroups = sg;
149
150     drawBoxes(seq, start, end, y1);
151
152     if (av.validCharWidth)
153     {
154       drawText(seq, start, end, y1);
155     }
156   }
157
158   public void drawBoxes(SequenceI seq, int start, int end, int y1)
159   {
160     int i = start;
161     int length = seq.getLength();
162
163     int curStart = -1;
164     int curWidth = av.charWidth;
165
166     Color tempColour = null;
167     while (i <= end)
168     {
169       resBoxColour = Color.white;
170       if (i < length)
171       {
172         if (inCurrentSequenceGroup(i))
173         {
174           if (currentSequenceGroup.getDisplayBoxes())
175           {
176             getBoxColour(currentSequenceGroup.cs, seq, i);
177           }
178         }
179         else if (av.getShowBoxes())
180         {
181           getBoxColour(av.getGlobalColourScheme(), seq, i);
182         }
183       }
184
185       if (resBoxColour != tempColour)
186       {
187         if (tempColour != null)
188         {
189           graphics.fillRect(av.charWidth * (curStart - start), y1,
190                   curWidth, av.charHeight);
191         }
192         graphics.setColor(resBoxColour);
193
194         curStart = i;
195         curWidth = av.charWidth;
196         tempColour = resBoxColour;
197
198       }
199       else
200       {
201         curWidth += av.charWidth;
202       }
203
204       i++;
205     }
206
207     graphics.fillRect(av.charWidth * (curStart - start), y1, curWidth,
208             av.charHeight);
209   }
210
211   public void drawText(SequenceI seq, int start, int end, int y1)
212   {
213     Font boldFont = null;
214     boolean bold = false;
215     if (av.upperCasebold)
216     {
217       boldFont = new Font(av.getFont().getName(), Font.BOLD, av.charHeight);
218
219       graphics.setFont(av.getFont());
220     }
221
222     y1 += av.charHeight - av.charHeight / 5; // height/5 replaces pady
223
224     int charOffset = 0;
225
226     // Need to find the sequence position here.
227     if (end + 1 >= seq.getLength())
228     {
229       end = seq.getLength() - 1;
230     }
231
232     char s = ' ';
233     boolean srep = av.isDisplayReferenceSeq();
234     for (int i = start; i <= end; i++)
235     {
236       graphics.setColor(Color.black);
237
238       s = seq.getCharAt(i);
239       if (!renderGaps && jalview.util.Comparison.isGap(s))
240       {
241         continue;
242       }
243
244       if (inCurrentSequenceGroup(i))
245       {
246         if (!currentSequenceGroup.getDisplayText())
247         {
248           continue;
249         }
250
251         if (currentSequenceGroup.getColourText())
252         {
253           getBoxColour(currentSequenceGroup.cs, seq, i);
254           graphics.setColor(resBoxColour.darker());
255         }
256         if (currentSequenceGroup.getShowNonconserved())
257         {
258           s = getDisplayChar(srep, i, s,
259                   '.');
260         }
261       }
262       else
263       {
264         if (!av.getShowText())
265         {
266           continue;
267         }
268
269         if (av.getColourText())
270         {
271           getBoxColour(av.getGlobalColourScheme(), seq, i);
272           if (av.getShowBoxes())
273           {
274             graphics.setColor(resBoxColour.darker());
275           }
276           else
277           {
278             graphics.setColor(resBoxColour);
279           }
280         }
281         if (av.getShowUnconserved())
282         {
283           s = getDisplayChar(srep, i, s,
284                   '.');
285
286         }
287       }
288
289       if (av.upperCasebold)
290       {
291         fm = graphics.getFontMetrics();
292         if ('A' <= s && s <= 'Z')
293         {
294           if (!bold)
295           {
296
297             graphics.setFont(boldFont);
298           }
299           bold = true;
300         }
301         else if (bold)
302         {
303           graphics.setFont(av.font);
304           bold = false;
305         }
306
307       }
308
309       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
310       graphics.drawString(String.valueOf(s), charOffset + av.charWidth
311               * (i - start), y1);
312     }
313
314   }
315
316   private char getDisplayChar(final boolean usesrep, int position,
317           char s, char c)
318   {
319     // TODO - use currentSequenceGroup rather than alignemnt 
320     // currentSequenceGroup.getConsensus()
321     char conschar = (usesrep) ? av.getAlignment().getSeqrep().getCharAt(position) : av.getAlignmentConsensusAnnotation().annotations[position].displayCharacter
322             .charAt(0);
323     if (conschar != '-' && s == conschar)
324     {
325       s = c;
326     }
327     return s;
328   }
329
330   boolean inCurrentSequenceGroup(int res)
331   {
332     if (allGroups == null)
333     {
334       return false;
335     }
336
337     for (int i = 0; i < allGroups.length; i++)
338     {
339       if (allGroups[i].getStartRes() <= res
340               && allGroups[i].getEndRes() >= res)
341       {
342         currentSequenceGroup = allGroups[i];
343         return true;
344       }
345     }
346
347     return false;
348   }
349
350   public void drawHighlightedText(SequenceI seq, int start, int end,
351           int x1, int y1)
352   {
353     int pady = av.charHeight / 5;
354     int charOffset = 0;
355     graphics.setColor(Color.black);
356     graphics.fillRect(x1, y1, av.charWidth * (end - start + 1),
357             av.charHeight);
358     graphics.setColor(Color.white);
359
360     char s = '~';
361     // Need to find the sequence position here.
362     if (av.validCharWidth)
363     {
364       for (int i = start; i <= end; i++)
365       {
366         if (i < seq.getLength())
367         {
368           s = seq.getCharAt(i);
369         }
370
371         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
372         graphics.drawString(String.valueOf(s), charOffset + x1
373                 + av.charWidth * (i - start), y1 + av.charHeight - pady);
374       }
375     }
376   }
377
378   public void drawCursor(SequenceI seq, int res, int x1, int y1)
379   {
380     int pady = av.charHeight / 5;
381     int charOffset = 0;
382     graphics.setColor(Color.black);
383     graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
384     graphics.setColor(Color.white);
385
386     graphics.setColor(Color.white);
387
388     char s = seq.getCharAt(res);
389     if (av.validCharWidth)
390     {
391
392       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
393       graphics.drawString(String.valueOf(s), charOffset + x1,
394               (y1 + av.charHeight) - pady);
395     }
396   }
397
398 }