2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
19 package jalview.appletgui;
\r
25 import java.awt.event.*;
\r
28 import jalview.datamodel.*;
\r
34 * @version $Revision$
\r
36 public class FeatureRenderer
\r
40 Hashtable featureColours = new Hashtable();
\r
42 // A higher level for grouping features of a
\r
44 Hashtable featureGroups = null;
\r
46 // Holds web links for feature groups and feature types
\r
47 // in the form label|link
\r
48 Hashtable featureLinks = null;
\r
50 // This is actually an Integer held in the hashtable,
\r
51 // Retrieved using the key feature type
\r
52 Object currentColour;
\r
54 String[] renderOrder;
\r
59 float transparency = 1f;
\r
61 TransparencySetter transparencySetter = null;
\r
64 * Creates a new FeatureRenderer object.
\r
66 * @param av DOCUMENT ME!
\r
68 public FeatureRenderer(AlignViewport av)
\r
72 if (!System.getProperty("java.version").startsWith("1.1"))
\r
74 transparencySetter = new TransparencySetter();
\r
78 public void transferSettings(FeatureRenderer fr)
\r
80 renderOrder = fr.renderOrder;
\r
81 featureGroups = fr.featureGroups;
\r
82 featureColours = fr.featureColours;
\r
83 transparency = fr.transparency;
\r
87 static String lastFeatureAdded;
\r
88 static String lastFeatureGroupAdded;
\r
89 static String lastDescriptionAdded;
\r
91 public boolean createNewFeatures(SequenceI[] sequences,
\r
92 SequenceFeature[] features,
\r
95 return amendFeatures(sequences, features, true, ap);
\r
99 int featureIndex = 0;
\r
100 boolean deleteFeature = false;
\r
102 boolean amendFeatures(final SequenceI[] sequences,
\r
103 final SequenceFeature[] features,
\r
104 boolean newFeatures,
\r
105 final AlignmentPanel ap)
\r
107 Panel bigPanel = new Panel(new BorderLayout());
\r
108 final TextField name = new TextField(16);
\r
109 final TextField source = new TextField(16);
\r
110 final TextArea description = new TextArea(3, 35);
\r
111 final TextField start = new TextField(8);
\r
112 final TextField end = new TextField(8);
\r
113 final Choice overlaps;
\r
114 Button deleteButton = new Button("Delete");
\r
115 deleteFeature = false;
\r
117 colourPanel = new Panel(null);
\r
118 colourPanel.setSize(110,15);
\r
119 final FeatureRenderer fr = this;
\r
121 Panel panel = new Panel(new GridLayout(3, 1));
\r
125 ///////////////////////////////////////
\r
126 ///MULTIPLE FEATURES AT SELECTED RESIDUE
\r
127 if(!newFeatures && features.length>1)
\r
129 panel = new Panel(new GridLayout(4, 1));
\r
131 tmp.add(new Label("Select Feature: "));
\r
132 overlaps = new Choice();
\r
133 for(int i=0; i<features.length; i++)
\r
135 String item = features[i].getType()
\r
136 +"/"+features[i].getBegin()+"-"+features[i].getEnd();
\r
138 if(features[i].getFeatureGroup()!=null)
\r
139 item += " ("+features[i].getFeatureGroup()+")";
\r
141 overlaps.addItem(item);
\r
146 overlaps.addItemListener(new java.awt.event.ItemListener()
\r
148 public void itemStateChanged(java.awt.event.ItemEvent e)
\r
150 int index = overlaps.getSelectedIndex();
\r
153 featureIndex = index;
\r
154 name.setText(features[index].getType());
\r
155 description.setText(features[index].getDescription());
\r
156 source.setText(features[index].getFeatureGroup());
\r
157 start.setText(features[index].getBegin()+"");
\r
158 end.setText(features[index].getEnd()+"");
\r
160 SearchResults highlight = new SearchResults();
\r
161 highlight.addResult(sequences[0],
\r
162 features[index].getBegin(),
\r
163 features[index].getEnd());
\r
165 ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
\r
168 Color col = getColour(name.getText());
\r
172 jalview.schemes.UserColourScheme()
\r
173 .createColourFromName(name.getText());
\r
176 colourPanel.setBackground(col);
\r
184 //////////////////////////////////////
\r
189 tmp.add(new Label("Name: ", Label.RIGHT));
\r
194 tmp.add(new Label("Group: ",Label.RIGHT));
\r
199 tmp.add(new Label("Colour: ", Label.RIGHT));
\r
200 tmp.add(colourPanel);
\r
202 bigPanel.add(panel, BorderLayout.NORTH);
\r
204 panel = new Panel();
\r
205 panel.add(new Label("Description: ", Label.RIGHT));
\r
206 panel.add(new ScrollPane().add(description));
\r
210 bigPanel.add(panel, BorderLayout.SOUTH);
\r
212 panel = new Panel();
\r
213 panel.add(new Label(" Start:", Label.RIGHT));
\r
215 panel.add(new Label(" End:", Label.RIGHT));
\r
217 bigPanel.add(panel, BorderLayout.CENTER);
\r
221 bigPanel.add(panel, BorderLayout.CENTER);
\r
224 if (lastFeatureAdded == null)
\r
226 if (features[0].type != null)
\r
228 lastFeatureAdded = features[0].type;
\r
232 lastFeatureAdded = "feature_1";
\r
236 if (lastFeatureGroupAdded == null)
\r
238 if (features[0].featureGroup != null)
\r
240 lastFeatureGroupAdded = features[0].featureGroup;
\r
244 lastFeatureAdded = "Jalview";
\r
249 String title = newFeatures ? "Create New Sequence Feature(s)" :
\r
250 "Amend/Delete Features for "
\r
251 + sequences[0].getName();
\r
253 final JVDialog dialog = new JVDialog(ap.alignFrame,
\r
258 dialog.setMainPanel(bigPanel);
\r
262 name.setText(lastFeatureAdded);
\r
263 source.setText(lastFeatureGroupAdded);
\r
267 dialog.ok.setLabel("Amend");
\r
268 dialog.buttonPanel.add(deleteButton, 1);
\r
269 deleteButton.addActionListener(new ActionListener()
\r
271 public void actionPerformed(ActionEvent evt)
\r
273 deleteFeature = true;
\r
274 dialog.setVisible(false);
\r
277 name.setText(features[0].getType());
\r
278 source.setText(features[0].getFeatureGroup());
\r
281 start.setText(features[0].getBegin()+"");
\r
282 end.setText(features[0].getEnd()+"");
\r
283 description.setText(features[0].getDescription());
\r
285 Color col = getColour(name.getText());
\r
289 jalview.schemes.UserColourScheme()
\r
290 .createColourFromName(name.getText());
\r
293 colourPanel.setBackground(col);
\r
295 dialog.setResizable(true);
\r
298 colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
\r
300 public void mousePressed(java.awt.event.MouseEvent evt)
\r
302 new UserDefinedColours(fr, ap.alignFrame);
\r
308 jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
\r
312 //This ensures that the last sequence
\r
313 //is refreshed and new features are rendered
\r
315 lastFeatureAdded = name.getText().trim();
\r
316 lastFeatureGroupAdded = source.getText().trim();
\r
317 lastDescriptionAdded = description.getText().replace('\n', ' ');
\r
320 if(lastFeatureGroupAdded !=null && lastFeatureGroupAdded.length()<1)
\r
321 lastFeatureGroupAdded = null;
\r
326 SequenceFeature sf = features[featureIndex];
\r
330 sf.type = lastFeatureAdded;
\r
331 sf.featureGroup = lastFeatureGroupAdded;
\r
332 sf.description = lastDescriptionAdded;
\r
333 setColour(sf.type, colourPanel.getBackground());
\r
336 sf.begin = Integer.parseInt(start.getText());
\r
337 sf.end = Integer.parseInt(end.getText());
\r
339 catch (NumberFormatException ex)
\r
342 ffile.parseDescriptionHTML(sf, false);
\r
346 sequences[0].deleteFeature(sf);
\r
352 if (dialog.accept && name.getText().length()>0)
\r
354 for (int i = 0; i < sequences.length; i++)
\r
356 features[i].type = lastFeatureAdded;
\r
357 features[i].featureGroup = lastFeatureGroupAdded;
\r
358 features[i].description = lastDescriptionAdded;
\r
359 sequences[i].addSequenceFeature(features[i]);
\r
360 ffile.parseDescriptionHTML(features[i], false);
\r
363 if (av.featuresDisplayed == null)
\r
365 av.featuresDisplayed = new Hashtable();
\r
368 if (featureGroups == null)
\r
370 featureGroups = new Hashtable();
\r
375 col = colourPanel.getBackground();
\r
376 setColour(lastFeatureAdded, col);
\r
378 if(lastFeatureGroupAdded!=null)
\r
380 featureGroups.put(lastFeatureGroupAdded, new Boolean(true));
\r
381 av.featuresDisplayed.put(lastFeatureGroupAdded,
\r
382 new Integer(col.getRGB()));
\r
400 public Color findFeatureColour(Color initialCol, SequenceI seq, int i)
\r
403 if (!av.showSequenceFeatures)
\r
409 sequenceFeatures = lastSeq.getSequenceFeatures();
\r
410 if (sequenceFeatures == null)
\r
415 sfSize = sequenceFeatures.length;
\r
417 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(i)))
\r
419 return Color.white;
\r
422 currentColour = null;
\r
424 drawSequence(null, lastSeq, lastSeq.findPosition(i), -1, -1);
\r
426 if (currentColour == null)
\r
431 return new Color( ( (Integer) currentColour).intValue());
\r
435 * This is used by the Molecule Viewer to get the accurate colour
\r
436 * of the rendered sequence
\r
438 boolean overview = false;
\r
444 * @param g DOCUMENT ME!
\r
445 * @param seq DOCUMENT ME!
\r
446 * @param sg DOCUMENT ME!
\r
447 * @param start DOCUMENT ME!
\r
448 * @param end DOCUMENT ME!
\r
449 * @param x1 DOCUMENT ME!
\r
450 * @param y1 DOCUMENT ME!
\r
451 * @param width DOCUMENT ME!
\r
452 * @param height DOCUMENT ME!
\r
455 // SequenceFeature sf;
\r
458 SequenceFeature[] sequenceFeatures;
\r
459 int sfSize, sfindex, spos, epos;
\r
461 synchronized public void drawSequence(Graphics g, SequenceI seq,
\r
462 int start, int end, int y1)
\r
464 if (seq.getSequenceFeatures() == null
\r
465 || seq.getSequenceFeatures().length == 0)
\r
470 if (transparencySetter != null && g != null)
\r
472 transparencySetter.setTransparency(g, transparency);
\r
475 if (lastSeq == null || seq != lastSeq || sequenceFeatures!=seq.getSequenceFeatures())
\r
478 sequenceFeatures = seq.getSequenceFeatures();
\r
479 sfSize = sequenceFeatures.length;
\r
482 if (av.featuresDisplayed == null || renderOrder == null)
\r
485 if (av.featuresDisplayed.size() < 1)
\r
490 sequenceFeatures = seq.getSequenceFeatures();
\r
491 sfSize = sequenceFeatures.length;
\r
495 spos = lastSeq.findPosition(start);
\r
496 epos = lastSeq.findPosition(end);
\r
499 fm = g.getFontMetrics();
\r
503 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
\r
505 type = renderOrder[renderIndex];
\r
506 if (!av.featuresDisplayed.containsKey(type))
\r
511 // loop through all features in sequence to find
\r
512 // current feature to render
\r
513 for (sfindex = 0; sfindex < sfSize; sfindex++)
\r
515 if (!sequenceFeatures[sfindex].type.equals(type))
\r
520 if (featureGroups != null
\r
521 && sequenceFeatures[sfindex].featureGroup != null
\r
523 featureGroups.containsKey(sequenceFeatures[sfindex].featureGroup)
\r
525 ! ( (Boolean) featureGroups.get(sequenceFeatures[sfindex].
\r
532 if (!overview && (sequenceFeatures[sfindex].getBegin() > epos
\r
533 || sequenceFeatures[sfindex].getEnd() < spos))
\r
540 if (sequenceFeatures[sfindex].begin <= start &&
\r
541 sequenceFeatures[sfindex].end >= start)
\r
543 currentColour = av.featuresDisplayed.get(sequenceFeatures[sfindex].
\r
548 else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
\r
551 renderFeature(g, seq,
\r
552 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
553 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
554 new Color( ( (Integer) av.featuresDisplayed.get(
\r
555 sequenceFeatures[sfindex].type)).intValue()),
\r
557 renderFeature(g, seq,
\r
558 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
559 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
560 new Color( ( (Integer) av.featuresDisplayed.get(
\r
561 sequenceFeatures[sfindex].type)).intValue()),
\r
567 renderFeature(g, seq,
\r
568 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
569 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
570 getColour(sequenceFeatures[sfindex].type),
\r
577 if (transparencySetter != null && g != null)
\r
579 transparencySetter.setTransparency(g, 1.0f);
\r
585 void renderFeature(Graphics g, SequenceI seq,
\r
586 int fstart, int fend, Color featureColour, int start,
\r
590 if ( ( (fstart <= end) && (fend >= start)))
\r
592 if (fstart < start)
\r
593 { // fix for if the feature we have starts before the sequence start,
\r
594 fstart = start; // but the feature end is still valid!!
\r
602 for (i = fstart; i <= fend; i++)
\r
604 s = seq.getCharAt(i);
\r
606 if (jalview.util.Comparison.isGap(s))
\r
611 g.setColor(featureColour);
\r
613 g.fillRect( (i - start) * av.charWidth, y1, av.charWidth, av.charHeight);
\r
615 if (!av.validCharWidth)
\r
620 g.setColor(Color.white);
\r
621 charOffset = (av.charWidth - fm.charWidth(s)) / 2;
\r
622 g.drawString(String.valueOf(s),
\r
623 charOffset + (av.charWidth * (i - start)),
\r
624 (y1 + av.charHeight) - av.charHeight / 5); //pady = height / 5;
\r
630 void findAllFeatures()
\r
632 jalview.schemes.UserColourScheme ucs = new
\r
633 jalview.schemes.UserColourScheme();
\r
635 av.featuresDisplayed = new Hashtable();
\r
636 Vector allfeatures = new Vector();
\r
637 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
639 SequenceFeature[] features = av.alignment.getSequenceAt(i).
\r
640 getSequenceFeatures();
\r
642 if (features == null)
\r
648 while (index < features.length)
\r
650 if (!av.featuresDisplayed.containsKey(features[index].getType()))
\r
652 if (getColour(features[index].getType()) == null)
\r
654 featureColours.put(features[index].getType(),
\r
655 ucs.createColourFromName(features[index].
\r
659 av.featuresDisplayed.put(features[index].getType(),
\r
660 new Integer(getColour(features[index].
\r
661 getType()).getRGB()));
\r
662 allfeatures.addElement(features[index].getType());
\r
668 renderOrder = new String[allfeatures.size()];
\r
669 Enumeration en = allfeatures.elements();
\r
670 int i = allfeatures.size() - 1;
\r
671 while (en.hasMoreElements())
\r
673 renderOrder[i] = en.nextElement().toString();
\r
678 public Color getColour(String featureType)
\r
680 return (Color) featureColours.get(featureType);
\r
683 public void addNewFeature(String name, Color col)
\r
686 setColour(name, col);
\r
687 if (av.featuresDisplayed == null)
\r
689 av.featuresDisplayed = new Hashtable();
\r
692 av.featuresDisplayed.put(name, "NOGROUP");
\r
695 public void setColour(String featureType, Color col)
\r
697 featureColours.put(featureType, col);
\r
700 public void setFeaturePriority(Object[][] data)
\r
702 // The feature table will display high priority
\r
703 // features at the top, but theses are the ones
\r
704 // we need to render last, so invert the data
\r
705 if (av.featuresDisplayed != null)
\r
707 av.featuresDisplayed.clear();
\r
710 renderOrder = new String[data.length];
\r
712 if (data.length > 0)
\r
714 for (int i = 0; i < data.length; i++)
\r
716 String type = data[i][0].toString();
\r
717 setColour(type, (Color) data[i][1]);
\r
718 if ( ( (Boolean) data[i][2]).booleanValue())
\r
720 av.featuresDisplayed.put(type, new Integer(getColour(type).getRGB()));
\r
723 renderOrder[data.length - i - 1] = type;
\r
729 class TransparencySetter
\r
731 void setTransparency(Graphics g, float value)
\r
733 Graphics2D g2 = (Graphics2D) g;
\r
735 AlphaComposite.getInstance(
\r
736 AlphaComposite.SRC_OVER, value));
\r