patch to fix occasional arrayoutofbounds exception when working with hidden columns...
[jalview.git] / src / jalview / appletgui / SequenceRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.appletgui;
20
21 import java.awt.*;
22
23 import jalview.datamodel.*;
24 import jalview.schemes.*;
25
26 public class SequenceRenderer
27 {
28   AlignViewport av;
29
30   FontMetrics fm;
31
32   boolean renderGaps = true;
33
34   SequenceGroup currentSequenceGroup = null;
35
36   SequenceGroup[] allGroups = null;
37
38   Color resBoxColour;
39
40   Graphics graphics;
41
42   boolean forOverview = false;
43
44   public SequenceRenderer(AlignViewport av)
45   {
46     this.av = av;
47   }
48
49   /**
50    * DOCUMENT ME!
51    * 
52    * @param b
53    *                DOCUMENT ME!
54    */
55   public void prepare(Graphics g, boolean renderGaps)
56   {
57     graphics = g;
58     fm = g.getFontMetrics();
59
60     this.renderGaps = renderGaps;
61   }
62
63   public Color getResidueBoxColour(SequenceI seq, int i)
64   {
65     allGroups = av.alignment.findAllGroups(seq);
66
67     if (inCurrentSequenceGroup(i))
68     {
69       if (currentSequenceGroup.getDisplayBoxes())
70       {
71         getBoxColour(currentSequenceGroup.cs, seq, i);
72       }
73     }
74     else if (av.getShowBoxes())
75     {
76       getBoxColour(av.globalColourScheme, seq, i);
77     }
78
79     return resBoxColour;
80   }
81
82   void getBoxColour(ColourSchemeI cs, SequenceI seq, int i)
83   {
84     if (cs != null)
85     {
86       resBoxColour = cs.findColour(seq.getCharAt(i), i);
87     }
88     else if (forOverview
89             && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
90     {
91       resBoxColour = Color.lightGray;
92     }
93     else
94     {
95       resBoxColour = Color.white;
96     }
97
98   }
99   
100   public Color findSequenceColour(SequenceI seq, int i)
101   {
102     allGroups = av.alignment.findAllGroups(seq);
103     drawBoxes(seq, i, i, 0);
104     return resBoxColour;
105   }
106
107   public void drawSequence(SequenceI seq, SequenceGroup[] sg, int start,
108           int end, int y1)
109   {
110     if (seq == null)
111     {
112       return;
113     }
114
115     allGroups = sg;
116
117     drawBoxes(seq, start, end, y1);
118
119     if (av.validCharWidth)
120     {
121       drawText(seq, start, end, y1);
122     }
123   }
124
125   public void drawBoxes(SequenceI seq, int start, int end, int y1)
126   {
127     int i = start;
128     int length = seq.getLength();
129
130     int curStart = -1;
131     int curWidth = av.charWidth;
132
133     Color tempColour = null;
134     while (i <= end)
135     {
136       resBoxColour = Color.white;
137       if (i < length)
138       {
139         if (inCurrentSequenceGroup(i))
140         {
141           if (currentSequenceGroup.getDisplayBoxes())
142           {
143             getBoxColour(currentSequenceGroup.cs, seq, i);
144           }
145         }
146         else if (av.getShowBoxes())
147         {
148           getBoxColour(av.getGlobalColourScheme(), seq, i);
149         }
150       }
151
152       if (resBoxColour != tempColour)
153       {
154         if (tempColour != null)
155         {
156           graphics.fillRect(av.charWidth * (curStart - start), y1,
157                   curWidth, av.charHeight);
158         }
159         graphics.setColor(resBoxColour);
160
161         curStart = i;
162         curWidth = av.charWidth;
163         tempColour = resBoxColour;
164
165       }
166       else
167       {
168         curWidth += av.charWidth;
169       }
170
171       i++;
172     }
173
174     graphics.fillRect(av.charWidth * (curStart - start), y1, curWidth,
175             av.charHeight);
176   }
177
178   public void drawText(SequenceI seq, int start, int end, int y1)
179   {
180     Font boldFont = null;
181     boolean bold = false;
182     if (av.upperCasebold)
183     {
184       boldFont = new Font(av.getFont().getName(), Font.BOLD, av.charHeight);
185
186       graphics.setFont(av.getFont());
187     }
188
189     y1 += av.charHeight - av.charHeight / 5; // height/5 replaces pady
190
191     int charOffset = 0;
192
193     // Need to find the sequence position here.
194     if (end + 1 >= seq.getLength())
195     {
196       end = seq.getLength() - 1;
197     }
198
199     char s = ' ';
200
201     for (int i = start; i <= end; i++)
202     {
203       graphics.setColor(Color.black);
204
205       s = seq.getCharAt(i);
206       if (!renderGaps && jalview.util.Comparison.isGap(s))
207       {
208         continue;
209       }
210
211       if (inCurrentSequenceGroup(i))
212       {
213         if (!currentSequenceGroup.getDisplayText())
214         {
215           continue;
216         }
217
218         if (currentSequenceGroup.getColourText())
219         {
220           getBoxColour(currentSequenceGroup.cs, seq, i);
221           graphics.setColor(resBoxColour.darker());
222         }
223         if (currentSequenceGroup.getShowunconserved())
224         {
225           // cheat - use this if we have a consensus for each group: s = getDisplayChar(currentSequenceGroup.getConsensus(), i, s, '.');
226           s = getDisplayChar(av.consensus, i, s, '.');
227         }
228       }
229       else
230       {
231         if (!av.getShowText())
232         {
233           continue;
234         }
235
236         if (av.getColourText())
237         {
238           getBoxColour(av.getGlobalColourScheme(), seq, i);
239           if (av.getShowBoxes())
240           {
241             graphics.setColor(resBoxColour.darker());
242           }
243           else
244           {
245             graphics.setColor(resBoxColour);
246           }
247         }
248         if (av.getShowunconserved())
249         {
250           s = getDisplayChar(av.consensus, i, s, '.');                       
251  
252         }
253       }
254
255       if (av.upperCasebold)
256       {
257         fm = graphics.getFontMetrics();
258         if ('A' <= s && s <= 'Z')
259         {
260           if (!bold)
261           {
262
263             graphics.setFont(boldFont);
264           }
265           bold = true;
266         }
267         else if (bold)
268         {
269           graphics.setFont(av.font);
270           bold = false;
271         }
272
273       }
274       
275       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
276       graphics.drawString(String.valueOf(s), charOffset + av.charWidth
277               * (i - start), y1);
278     }
279
280   }
281
282   
283   private char getDisplayChar(AlignmentAnnotation consensus, int position, char s, char c)
284   {
285     char conschar = consensus.annotations[position].displayCharacter.charAt(0);
286     if (conschar!='-' && s==conschar)
287     {
288       s= c;
289     }
290     return s;
291   }
292
293   boolean inCurrentSequenceGroup(int res)
294   {
295     if (allGroups == null)
296     {
297       return false;
298     }
299
300     for (int i = 0; i < allGroups.length; i++)
301     {
302       if (allGroups[i].getStartRes() <= res
303               && allGroups[i].getEndRes() >= res)
304       {
305         currentSequenceGroup = allGroups[i];
306         return true;
307       }
308     }
309
310     return false;
311   }
312
313   public void drawHighlightedText(SequenceI seq, int start, int end,
314           int x1, int y1)
315   {
316     int pady = av.charHeight / 5;
317     int charOffset = 0;
318     graphics.setColor(Color.black);
319     graphics.fillRect(x1, y1, av.charWidth * (end - start + 1),
320             av.charHeight);
321     graphics.setColor(Color.white);
322
323     char s = '~';
324     // Need to find the sequence position here.
325     if (av.validCharWidth)
326     {
327       for (int i = start; i <= end; i++)
328       {
329         if (i < seq.getLength())
330         {
331           s = seq.getCharAt(i);
332         }
333
334         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
335         graphics.drawString(String.valueOf(s), charOffset + x1
336                 + av.charWidth * (i - start), y1 + av.charHeight - pady);
337       }
338     }
339   }
340
341   public void drawCursor(SequenceI seq, int res, int x1, int y1)
342   {
343     int pady = av.charHeight / 5;
344     int charOffset = 0;
345     graphics.setColor(Color.black);
346     graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
347     graphics.setColor(Color.white);
348
349     graphics.setColor(Color.white);
350
351     char s = seq.getCharAt(res);
352     if (av.validCharWidth)
353     {
354
355       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
356       graphics.drawString(String.valueOf(s), charOffset + x1,
357               (y1 + av.charHeight) - pady);
358     }
359   }
360
361 }