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 int featureIndex = 0;
\r
92 boolean deleteFeature = false;
\r
94 boolean amendFeatures(final SequenceI[] sequences,
\r
95 final SequenceFeature[] features,
\r
96 boolean newFeatures,
\r
97 final AlignmentPanel ap)
\r
99 Panel bigPanel = new Panel(new BorderLayout());
\r
100 final TextField name = new TextField(16);
\r
101 final TextField source = new TextField(16);
\r
102 final TextArea description = new TextArea(3, 35);
\r
103 final TextField start = new TextField(8);
\r
104 final TextField end = new TextField(8);
\r
105 final Choice overlaps;
\r
106 Button deleteButton = new Button("Delete");
\r
107 deleteFeature = false;
\r
109 colourPanel = new Panel(null);
\r
110 colourPanel.setSize(110,15);
\r
111 final FeatureRenderer fr = this;
\r
113 Panel panel = new Panel(new GridLayout(3, 1));
\r
117 ///////////////////////////////////////
\r
118 ///MULTIPLE FEATURES AT SELECTED RESIDUE
\r
119 if(!newFeatures && features.length>1)
\r
121 panel = new Panel(new GridLayout(4, 1));
\r
123 tmp.add(new Label("Select Feature: "));
\r
124 overlaps = new Choice();
\r
125 for(int i=0; i<features.length; i++)
\r
127 String item = features[i].getType()
\r
128 +"/"+features[i].getBegin()+"-"+features[i].getEnd();
\r
130 if(features[i].getFeatureGroup()!=null)
\r
131 item += " ("+features[i].getFeatureGroup()+")";
\r
133 overlaps.addItem(item);
\r
138 overlaps.addItemListener(new java.awt.event.ItemListener()
\r
140 public void itemStateChanged(java.awt.event.ItemEvent e)
\r
142 int index = overlaps.getSelectedIndex();
\r
145 featureIndex = index;
\r
146 name.setText(features[index].getType());
\r
147 description.setText(features[index].getDescription());
\r
148 source.setText(features[index].getFeatureGroup());
\r
149 start.setText(features[index].getBegin()+"");
\r
150 end.setText(features[index].getEnd()+"");
\r
152 SearchResults highlight = new SearchResults();
\r
153 highlight.addResult(sequences[0],
\r
154 features[index].getBegin(),
\r
155 features[index].getEnd());
\r
157 ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
\r
160 Color col = getColour(name.getText());
\r
164 jalview.schemes.UserColourScheme()
\r
165 .createColourFromName(name.getText());
\r
168 colourPanel.setBackground(col);
\r
176 //////////////////////////////////////
\r
181 tmp.add(new Label("Name: ", Label.RIGHT));
\r
186 tmp.add(new Label("Group: ",Label.RIGHT));
\r
191 tmp.add(new Label("Colour: ", Label.RIGHT));
\r
192 tmp.add(colourPanel);
\r
194 bigPanel.add(panel, BorderLayout.NORTH);
\r
196 panel = new Panel();
\r
197 panel.add(new Label("Description: ", Label.RIGHT));
\r
198 panel.add(new ScrollPane().add(description));
\r
202 bigPanel.add(panel, BorderLayout.SOUTH);
\r
204 panel = new Panel();
\r
205 panel.add(new Label(" Start:", Label.RIGHT));
\r
207 panel.add(new Label(" End:", Label.RIGHT));
\r
209 bigPanel.add(panel, BorderLayout.CENTER);
\r
213 bigPanel.add(panel, BorderLayout.CENTER);
\r
216 if (lastFeatureAdded == null)
\r
218 if (features[0].type != null)
\r
220 lastFeatureAdded = features[0].type;
\r
224 lastFeatureAdded = "feature_1";
\r
228 if (lastFeatureGroupAdded == null)
\r
230 if (features[0].featureGroup != null)
\r
232 lastFeatureGroupAdded = features[0].featureGroup;
\r
236 lastFeatureAdded = "Jalview";
\r
241 String title = newFeatures ? "Create New Sequence Feature(s)" :
\r
242 "Amend/Delete Features for "
\r
243 + sequences[0].getName();
\r
245 final JVDialog dialog = new JVDialog(ap.alignFrame,
\r
250 dialog.setMainPanel(bigPanel);
\r
254 name.setText(lastFeatureAdded);
\r
255 source.setText(lastFeatureGroupAdded);
\r
259 dialog.ok.setLabel("Amend");
\r
260 dialog.buttonPanel.add(deleteButton, 1);
\r
261 deleteButton.addActionListener(new ActionListener()
\r
263 public void actionPerformed(ActionEvent evt)
\r
265 deleteFeature = true;
\r
266 dialog.setVisible(false);
\r
269 name.setText(features[0].getType());
\r
270 source.setText(features[0].getFeatureGroup());
\r
273 start.setText(features[0].getBegin()+"");
\r
274 end.setText(features[0].getEnd()+"");
\r
275 description.setText(features[0].getDescription());
\r
277 Color col = getColour(name.getText());
\r
281 jalview.schemes.UserColourScheme()
\r
282 .createColourFromName(name.getText());
\r
285 colourPanel.setBackground(col);
\r
287 dialog.setResizable(true);
\r
290 colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
\r
292 public void mousePressed(java.awt.event.MouseEvent evt)
\r
294 new UserDefinedColours(fr, ap.alignFrame);
\r
298 dialog.setVisible(true);
\r
300 jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
\r
304 //This ensures that the last sequence
\r
305 //is refreshed and new features are rendered
\r
307 lastFeatureAdded = name.getText().trim();
\r
308 lastFeatureGroupAdded = source.getText().trim();
\r
309 lastDescriptionAdded = description.getText().replace('\n', ' ');
\r
312 if(lastFeatureGroupAdded !=null && lastFeatureGroupAdded.length()<1)
\r
313 lastFeatureGroupAdded = null;
\r
318 SequenceFeature sf = features[featureIndex];
\r
322 sf.type = lastFeatureAdded;
\r
323 sf.featureGroup = lastFeatureGroupAdded;
\r
324 sf.description = lastDescriptionAdded;
\r
325 setColour(sf.type, colourPanel.getBackground());
\r
328 sf.begin = Integer.parseInt(start.getText());
\r
329 sf.end = Integer.parseInt(end.getText());
\r
331 catch (NumberFormatException ex)
\r
334 ffile.parseDescriptionHTML(sf, false);
\r
338 sequences[0].deleteFeature(sf);
\r
344 if (dialog.accept && name.getText().length()>0)
\r
346 for (int i = 0; i < sequences.length; i++)
\r
348 features[i].type = lastFeatureAdded;
\r
349 features[i].featureGroup = lastFeatureGroupAdded;
\r
350 features[i].description = lastDescriptionAdded;
\r
351 sequences[i].addSequenceFeature(features[i]);
\r
352 ffile.parseDescriptionHTML(features[i], false);
\r
355 if (av.featuresDisplayed == null)
\r
357 av.featuresDisplayed = new Hashtable();
\r
360 if (featureGroups == null)
\r
362 featureGroups = new Hashtable();
\r
365 col = colourPanel.getBackground();
\r
366 setColour(lastFeatureAdded, col);
\r
368 if(lastFeatureGroupAdded!=null)
\r
370 featureGroups.put(lastFeatureGroupAdded, new Boolean(true));
\r
371 av.featuresDisplayed.put(lastFeatureGroupAdded,
\r
372 new Integer(col.getRGB()));
\r
376 String [] tro = new String[renderOrder.length];
\r
377 tro[0] = renderOrder[renderOrder.length-1];
\r
378 System.arraycopy(renderOrder,0,tro,1,renderOrder.length-1);
\r
381 ap.paintAlignment(true);
\r
393 ap.paintAlignment(true);
\r
399 public Color findFeatureColour(Color initialCol, SequenceI seq, int i)
\r
402 if (!av.showSequenceFeatures)
\r
408 sequenceFeatures = lastSeq.getSequenceFeatures();
\r
409 if (sequenceFeatures == null)
\r
414 sfSize = sequenceFeatures.length;
\r
416 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(i)))
\r
418 return Color.white;
\r
421 currentColour = null;
\r
423 drawSequence(null, lastSeq, lastSeq.findPosition(i), -1, -1);
\r
425 if (currentColour == null)
\r
430 return new Color( ( (Integer) currentColour).intValue());
\r
434 * This is used by the Molecule Viewer to get the accurate colour
\r
435 * of the rendered sequence
\r
437 boolean overview = false;
\r
443 * @param g DOCUMENT ME!
\r
444 * @param seq DOCUMENT ME!
\r
445 * @param sg DOCUMENT ME!
\r
446 * @param start DOCUMENT ME!
\r
447 * @param end DOCUMENT ME!
\r
448 * @param x1 DOCUMENT ME!
\r
449 * @param y1 DOCUMENT ME!
\r
450 * @param width DOCUMENT ME!
\r
451 * @param height DOCUMENT ME!
\r
454 // SequenceFeature sf;
\r
457 SequenceFeature[] sequenceFeatures;
\r
458 int sfSize, sfindex, spos, epos;
\r
460 synchronized public void drawSequence(Graphics g, SequenceI seq,
\r
461 int start, int end, int y1)
\r
463 if (seq.getSequenceFeatures() == null
\r
464 || seq.getSequenceFeatures().length == 0)
\r
469 if (transparencySetter != null && g != null)
\r
471 transparencySetter.setTransparency(g, transparency);
\r
474 if (lastSeq == null || seq != lastSeq || sequenceFeatures!=seq.getSequenceFeatures())
\r
477 sequenceFeatures = seq.getSequenceFeatures();
\r
478 sfSize = sequenceFeatures.length;
\r
481 if (av.featuresDisplayed == null || renderOrder == null)
\r
484 if (av.featuresDisplayed.size() < 1)
\r
489 sequenceFeatures = seq.getSequenceFeatures();
\r
490 sfSize = sequenceFeatures.length;
\r
494 spos = lastSeq.findPosition(start);
\r
495 epos = lastSeq.findPosition(end);
\r
498 fm = g.getFontMetrics();
\r
502 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
\r
504 type = renderOrder[renderIndex];
\r
505 if (!av.featuresDisplayed.containsKey(type))
\r
510 // loop through all features in sequence to find
\r
511 // current feature to render
\r
512 for (sfindex = 0; sfindex < sfSize; sfindex++)
\r
514 if (!sequenceFeatures[sfindex].type.equals(type))
\r
519 if (featureGroups != null
\r
520 && sequenceFeatures[sfindex].featureGroup != null
\r
522 featureGroups.containsKey(sequenceFeatures[sfindex].featureGroup)
\r
524 ! ( (Boolean) featureGroups.get(sequenceFeatures[sfindex].
\r
531 if (!overview && (sequenceFeatures[sfindex].getBegin() > epos
\r
532 || sequenceFeatures[sfindex].getEnd() < spos))
\r
539 if (sequenceFeatures[sfindex].begin <= start &&
\r
540 sequenceFeatures[sfindex].end >= start)
\r
542 currentColour = av.featuresDisplayed.get(sequenceFeatures[sfindex].
\r
547 else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
\r
550 renderFeature(g, seq,
\r
551 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
552 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
553 new Color( ( (Integer) av.featuresDisplayed.get(
\r
554 sequenceFeatures[sfindex].type)).intValue()),
\r
556 renderFeature(g, seq,
\r
557 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
558 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
559 new Color( ( (Integer) av.featuresDisplayed.get(
\r
560 sequenceFeatures[sfindex].type)).intValue()),
\r
566 renderFeature(g, seq,
\r
567 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
\r
568 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
\r
569 getColour(sequenceFeatures[sfindex].type),
\r
576 if (transparencySetter != null && g != null)
\r
578 transparencySetter.setTransparency(g, 1.0f);
\r
584 void renderFeature(Graphics g, SequenceI seq,
\r
585 int fstart, int fend, Color featureColour, int start,
\r
589 if ( ( (fstart <= end) && (fend >= start)))
\r
591 if (fstart < start)
\r
592 { // fix for if the feature we have starts before the sequence start,
\r
593 fstart = start; // but the feature end is still valid!!
\r
601 for (i = fstart; i <= fend; i++)
\r
603 s = seq.getCharAt(i);
\r
605 if (jalview.util.Comparison.isGap(s))
\r
610 g.setColor(featureColour);
\r
612 g.fillRect( (i - start) * av.charWidth, y1, av.charWidth, av.charHeight);
\r
614 if (!av.validCharWidth)
\r
619 g.setColor(Color.white);
\r
620 charOffset = (av.charWidth - fm.charWidth(s)) / 2;
\r
621 g.drawString(String.valueOf(s),
\r
622 charOffset + (av.charWidth * (i - start)),
\r
623 (y1 + av.charHeight) - av.charHeight / 5); //pady = height / 5;
\r
629 void findAllFeatures()
\r
631 jalview.schemes.UserColourScheme ucs = new
\r
632 jalview.schemes.UserColourScheme();
\r
634 av.featuresDisplayed = new Hashtable();
\r
635 Vector allfeatures = new Vector();
\r
636 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
638 SequenceFeature[] features = av.alignment.getSequenceAt(i).
\r
639 getSequenceFeatures();
\r
641 if (features == null)
\r
647 while (index < features.length)
\r
649 if (!av.featuresDisplayed.containsKey(features[index].getType()))
\r
651 if (getColour(features[index].getType()) == null)
\r
653 featureColours.put(features[index].getType(),
\r
654 ucs.createColourFromName(features[index].
\r
658 av.featuresDisplayed.put(features[index].getType(),
\r
659 new Integer(getColour(features[index].
\r
660 getType()).getRGB()));
\r
661 allfeatures.addElement(features[index].getType());
\r
667 renderOrder = new String[allfeatures.size()];
\r
668 Enumeration en = allfeatures.elements();
\r
669 int i = allfeatures.size() - 1;
\r
670 while (en.hasMoreElements())
\r
672 renderOrder[i] = en.nextElement().toString();
\r
677 public Color getColour(String featureType)
\r
679 if (!featureColours.containsKey(featureType))
\r
681 jalview.schemes.UserColourScheme ucs = new
\r
682 jalview.schemes.UserColourScheme();
\r
683 Color col = ucs.createColourFromName(featureType);
\r
684 featureColours.put(featureType, col);
\r
688 return (Color) featureColours.get(featureType);
\r
692 public void setColour(String featureType, Color col)
\r
694 featureColours.put(featureType, col);
\r
697 public void setFeaturePriority(Object[][] data)
\r
699 // The feature table will display high priority
\r
700 // features at the top, but theses are the ones
\r
701 // we need to render last, so invert the data
\r
702 if (av.featuresDisplayed != null)
\r
704 av.featuresDisplayed.clear();
\r
709 if (av.featuresDisplayed != null)
\r
711 av.featuresDisplayed.clear();
\r
715 av.featuresDisplayed = new Hashtable();
\r
724 renderOrder = new String[data.length];
\r
726 if (data.length > 0)
\r
728 for (int i = 0; i < data.length; i++)
\r
730 String type = data[i][0].toString();
\r
731 setColour(type, (Color) data[i][1]);
\r
732 if ( ( (Boolean) data[i][2]).booleanValue())
\r
734 av.featuresDisplayed.put(type, new Integer(getColour(type).getRGB()));
\r
737 renderOrder[data.length - i - 1] = type;
\r
743 class TransparencySetter
\r
745 void setTransparency(Graphics g, float value)
\r
747 Graphics2D g2 = (Graphics2D) g;
\r
749 AlphaComposite.getInstance(
\r
750 AlphaComposite.SRC_OVER, value));
\r