updated to jalview 2.1 and begun ArchiveClient/VamsasClient/VamsasStore updates.
[jalview.git] / src / jalview / appletgui / FeatureRenderer.java
1
2 /*
3  * Jalview - A Sequence Alignment Editor and Viewer
4  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20 package jalview.appletgui;
21
22 import jalview.datamodel.*;
23
24 import java.awt.*;
25
26 import java.util.*;
27
28 /**
29  * DOCUMENT ME!
30  *
31  * @author $author$
32  * @version $Revision$
33  */
34 public class FeatureRenderer
35 {
36     AlignViewport av;
37
38     Hashtable featureColours = new Hashtable();
39
40     // A higher level for grouping features of a
41     // particular type
42     Hashtable featureGroups = null;
43
44     // Holds web links for feature groups and feature types
45     // in the form label|link
46     Hashtable featureLinks = null;
47
48
49     // This is actually an Integer held in the hashtable,
50     // Retrieved using the key feature type
51     Object currentColour;
52
53     String [] renderOrder;
54
55     FontMetrics fm;
56     int charOffset;
57
58     float transparency = 1f;
59
60     TransparencySetter transparencySetter = null;
61
62     /**
63      * Creates a new FeatureRenderer object.
64      *
65      * @param av DOCUMENT ME!
66      */
67     public FeatureRenderer(AlignViewport av)
68     {
69         this.av = av;
70
71         if(!System.getProperty("java.version").startsWith("1.1"))
72              transparencySetter = new TransparencySetter();
73     }
74
75
76     public void transferSettings(FeatureRenderer fr)
77     {
78       renderOrder = fr.renderOrder;
79       featureGroups = fr.featureGroups;
80       featureColours = fr.featureColours;
81       transparency =  fr.transparency;
82     }
83
84
85     public Color findFeatureColour(Color initialCol, SequenceI seq, int i)
86     {
87       overview = true;
88       if(!av.showSequenceFeatures)
89         return initialCol;
90
91         lastSequence = seq;
92         sequenceFeatures = lastSequence.getSequenceFeatures();
93         if(sequenceFeatures==null)
94           return initialCol;
95
96         sfSize = sequenceFeatures.length;
97
98       if(jalview.util.Comparison.isGap(lastSequence.getCharAt(i)))
99         return Color.white;
100
101       currentColour = null;
102
103       drawSequence(null, lastSequence, lastSequence.findPosition(i), -1,-1);
104
105       if(currentColour==null)
106         return initialCol;
107
108       return new Color( ((Integer)currentColour).intValue() );
109     }
110
111     /**
112      * This is used by the Molecule Viewer to get the accurate colour
113      * of the rendered sequence
114      */
115     boolean overview = false;
116
117     int white = Color.white.getRGB();
118     public int findFeatureColour(int initialCol, int seqIndex, int column)
119     {
120       if(!av.showSequenceFeatures)
121         return initialCol;
122
123       if(seqIndex!=lastSequenceIndex)
124       {
125         lastSequence = av.alignment.getSequenceAt(seqIndex);
126         lastSequenceIndex = seqIndex;
127         sequenceFeatures = lastSequence.getSequenceFeatures();
128         if(sequenceFeatures==null)
129           return initialCol;
130
131         sfSize = sequenceFeatures.length;
132       }
133
134
135       if(jalview.util.Comparison.isGap(lastSequence.getCharAt(column)))
136         return Color.white.getRGB();
137
138       currentColour = null;
139
140       drawSequence(null, lastSequence, lastSequence.findPosition(column), -1,-1);
141
142       if(currentColour==null)
143         return initialCol;
144
145       return  ((Integer)currentColour).intValue();
146     }
147
148
149     /**
150      * DOCUMENT ME!
151      *
152      * @param g DOCUMENT ME!
153      * @param seq DOCUMENT ME!
154      * @param sg DOCUMENT ME!
155      * @param start DOCUMENT ME!
156      * @param end DOCUMENT ME!
157      * @param x1 DOCUMENT ME!
158      * @param y1 DOCUMENT ME!
159      * @param width DOCUMENT ME!
160      * @param height DOCUMENT ME!
161      */
162    // String type;
163    // SequenceFeature sf;
164     int lastSequenceIndex=-1;
165     SequenceI lastSequence;
166     SequenceFeature [] sequenceFeatures;
167     int sfSize, sfindex, spos, epos;
168
169     public void drawSequence(Graphics g, SequenceI seq,
170                              int start, int end, int y1)
171     {
172       if (   seq.getSequenceFeatures() == null
173           || seq.getSequenceFeatures().length==0)
174         return;
175
176       if(transparencySetter!=null && g!=null)
177       {
178         transparencySetter.setTransparency(g, transparency);
179       }
180
181       if (av.featuresDisplayed == null || renderOrder==null)
182        {
183          findAllFeatures();
184          if(av.featuresDisplayed.size()<1)
185            return;
186
187          sequenceFeatures = seq.getSequenceFeatures();
188          sfSize = sequenceFeatures.length;
189        }
190        if(lastSequence==null || seq!=lastSequence)
191       {
192         lastSequence = seq;
193         sequenceFeatures = seq.getSequenceFeatures();
194         sfSize = sequenceFeatures.length;
195       }
196       if(!overview)
197       {
198         spos = lastSequence.findPosition(start);
199         epos = lastSequence.findPosition(end);
200         if(g!=null)
201           fm = g.getFontMetrics();
202       }
203       String type;
204       for(int renderIndex=0; renderIndex<renderOrder.length; renderIndex++)
205        {
206         type =  renderOrder[renderIndex];
207         if(!av.featuresDisplayed.containsKey(type))
208           continue;
209
210         // loop through all features in sequence to find
211         // current feature to render
212         for (sfindex = 0; sfindex < sfSize; sfindex++)
213         {
214           if (!sequenceFeatures[sfindex].type.equals(type))
215             continue;
216
217           if (featureGroups != null
218               && sequenceFeatures[sfindex].featureGroup != null
219               &&
220               featureGroups.containsKey(sequenceFeatures[sfindex].featureGroup)
221               &&
222               ! ( (Boolean) featureGroups.get(sequenceFeatures[sfindex].featureGroup)).
223               booleanValue())
224           {
225             continue;
226           }
227
228           if (!overview && (sequenceFeatures[sfindex].getBegin() > epos
229                             || sequenceFeatures[sfindex].getEnd() < spos))
230             continue;
231
232           if (overview)
233           {
234             if (sequenceFeatures[sfindex].begin <= start &&
235                 sequenceFeatures[sfindex].end >= start)
236             {
237               currentColour = av.featuresDisplayed.get(sequenceFeatures[sfindex].
238                   type);
239             }
240
241           }
242           else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
243           {
244
245             renderFeature(g, seq,
246                           seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
247                           seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
248                           new Color( ( (Integer) av.featuresDisplayed.get(
249                 sequenceFeatures[sfindex].type)).intValue()),
250                           start, end, y1);
251             renderFeature(g, seq,
252                           seq.findIndex(sequenceFeatures[sfindex].end) - 1,
253                           seq.findIndex(sequenceFeatures[sfindex].end) - 1,
254                           new Color( ( (Integer) av.featuresDisplayed.get(
255                 sequenceFeatures[sfindex].type)).intValue()),
256                           start, end, y1);
257
258           }
259           else
260             renderFeature(g, seq,
261                           seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
262                           seq.findIndex(sequenceFeatures[sfindex].end) - 1,
263                           getColour(sequenceFeatures[sfindex].type),
264                           start, end, y1);
265
266         }
267       }
268
269       if(transparencySetter!=null && g!=null)
270       {
271         transparencySetter.setTransparency(g, 1.0f);
272       }
273     }
274
275
276     char s;
277     int i;
278     void renderFeature(Graphics g, SequenceI seq,
279                        int fstart, int fend, Color featureColour, int start, int end,  int y1)
280     {
281
282       if (((fstart <= end) && (fend >= start)))
283       {
284         if (fstart < start)
285         { // fix for if the feature we have starts before the sequence start,
286           fstart = start; // but the feature end is still valid!!
287         }
288
289         if (fend >= end)
290         {
291           fend = end;
292         }
293
294           for (i = fstart; i <= fend; i++)
295           {
296             s = seq.getSequence().charAt(i);
297
298             if (jalview.util.Comparison.isGap(s))
299             {
300               continue;
301             }
302
303             g.setColor(featureColour);
304
305             g.fillRect( (i - start) * av.charWidth, y1, av.charWidth, av.charHeight);
306
307             if(!av.validCharWidth)
308               continue;
309
310             g.setColor(Color.white);
311             charOffset = (av.charWidth - fm.charWidth(s)) / 2;
312             g.drawString(String.valueOf(s),
313                          charOffset + (av.charWidth * (i - start)),
314                          (y1 + av.charHeight) - av.charHeight / 5); //pady = height / 5;
315
316           }
317       }
318     }
319
320     void findAllFeatures()
321     {
322       jalview.schemes.UserColourScheme ucs = new
323           jalview.schemes.UserColourScheme();
324
325       av.featuresDisplayed = new Hashtable();
326       Vector allfeatures = new Vector();
327       for (int i = 0; i < av.alignment.getHeight(); i++)
328       {
329         SequenceFeature [] features = av.alignment.getSequenceAt(i).getSequenceFeatures();
330
331         if (features == null)
332           continue;
333
334         int index = 0;
335         while (index < features.length)
336         {
337           if (!av.featuresDisplayed.containsKey(features[index].getType()))
338           {
339             if (getColour(features[index].getType()) == null)
340             {
341               featureColours.put(features[index].getType(),
342                                  ucs.createColourFromName(features[index].
343                   getType()));
344             }
345
346
347             av.featuresDisplayed.put(features[index].getType(),
348                                   new Integer( getColour(features[index].getType()).getRGB()) );
349             allfeatures.addElement(features[index].getType());
350           }
351           index++;
352         }
353       }
354
355       renderOrder = new String[allfeatures.size()];
356       Enumeration en = allfeatures.elements();
357       int i = allfeatures.size()-1;
358       while(en.hasMoreElements())
359       {
360         renderOrder[i] = en.nextElement().toString();
361         i--;
362       }
363     }
364
365     public Color getColour(String featureType)
366     {
367       return (Color)featureColours.get(featureType);
368     }
369
370     public void addNewFeature(String name, Color col)
371     {
372
373       setColour(name, col);
374       if(av.featuresDisplayed==null)
375         av.featuresDisplayed = new Hashtable();
376
377
378       av.featuresDisplayed.put(name, "NOGROUP");
379     }
380
381     public void setColour(String featureType, Color col)
382     {
383       featureColours.put(featureType, col);
384     }
385
386     public void setFeaturePriority(Object [][] data)
387     {
388         // The feature table will display high priority
389         // features at the top, but theses are the ones
390         // we need to render last, so invert the data
391         if(av.featuresDisplayed!=null)
392           av.featuresDisplayed.clear();
393
394         renderOrder = new String[data.length];
395
396         if (data.length > 0)
397           for (int i = 0; i < data.length; i++)
398           {
399             String type = data[i][0].toString();
400             setColour(type, (Color) data[i][1]);
401             if ( ( (Boolean) data[i][2]).booleanValue())
402             {
403               av.featuresDisplayed.put(type, new Integer(getColour(type).getRGB()));
404             }
405
406             renderOrder[data.length - i - 1] = type;
407           }
408     }
409 }
410
411   class TransparencySetter
412   {
413     void setTransparency(Graphics g, float value)
414     {
415      Graphics2D g2 = (Graphics2D) g;
416      g2.setComposite(
417         AlphaComposite.getInstance(
418              AlphaComposite.SRC_OVER, value));
419     }
420   }
421
422
423
424