2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
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 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.appletgui;
24 import java.awt.event.*;
26 import jalview.datamodel.*;
27 import jalview.schemes.AnnotationColourGradient;
28 import jalview.schemes.GraduatedColor;
36 public class FeatureRenderer implements jalview.api.FeatureRenderer
40 Hashtable featureColours = new Hashtable();
42 // A higher level for grouping features of a
44 Hashtable featureGroups = null;
46 // Holds web links for feature groups and feature types
47 // in the form label|link
48 Hashtable featureLinks = null;
50 // This is actually an Integer held in the hashtable,
51 // Retrieved using the key feature type
60 float transparency = 1f;
62 TransparencySetter transparencySetter = null;
65 * Creates a new FeatureRenderer object.
70 public FeatureRenderer(AlignViewport av)
74 if (!System.getProperty("java.version").startsWith("1.1"))
76 transparencySetter = new TransparencySetter();
80 public void transferSettings(FeatureRenderer fr)
82 renderOrder = fr.renderOrder;
83 featureGroups = fr.featureGroups;
84 featureColours = fr.featureColours;
85 transparency = fr.transparency;
86 if (av != null && fr.av != null && fr.av != av)
88 if (fr.av.featuresDisplayed != null)
90 if (av.featuresDisplayed == null)
92 av.featuresDisplayed = new Hashtable();
96 av.featuresDisplayed.clear();
98 Enumeration en = fr.av.featuresDisplayed.keys();
99 while (en.hasMoreElements())
101 av.featuresDisplayed.put(en.nextElement(), Boolean.TRUE);
107 static String lastFeatureAdded;
109 static String lastFeatureGroupAdded;
111 static String lastDescriptionAdded;
113 int featureIndex = 0;
115 boolean deleteFeature = false;
117 FeatureColourPanel colourPanel;
119 class FeatureColourPanel extends Panel
123 private Color maxCol;
125 private boolean isColourByLabel, isGcol;
128 * render a feature style in the amend feature dialog box
130 public void updateColor(Object newcol)
133 Color bg, col = null;
134 GraduatedColor gcol = null;
136 if (newcol instanceof Color)
139 col = (Color) newcol;
142 else if (newcol instanceof GraduatedColor)
145 gcol = (GraduatedColor) newcol;
150 throw new Error("Invalid color for MyCheckBox");
154 setBackground(bg = col);
158 if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
161 + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
164 if (isColourByLabel = gcol.isColourByLabel())
166 setBackground(bg = Color.white);
167 vlabel += " (by Label)";
171 setBackground(bg = gcol.getMinColor());
172 maxCol = gcol.getMaxColor();
185 public void paint(Graphics g)
187 Dimension d = getSize();
192 g.setColor(Color.white);
193 g.fillRect(d.width / 2, 0, d.width / 2, d.height);
194 g.setColor(Color.black);
195 Font f = new Font("Verdana", Font.PLAIN, 10);
197 g.drawString("Label", 0, 0);
202 g.fillRect(d.width / 2, 0, d.width / 2, d.height);
210 boolean amendFeatures(final SequenceI[] sequences,
211 final SequenceFeature[] features, boolean newFeatures,
212 final AlignmentPanel ap)
214 Panel bigPanel = new Panel(new BorderLayout());
215 final TextField name = new TextField(16);
216 final TextField source = new TextField(16);
217 final TextArea description = new TextArea(3, 35);
218 final TextField start = new TextField(8);
219 final TextField end = new TextField(8);
220 final Choice overlaps;
221 Button deleteButton = new Button("Delete");
222 deleteFeature = false;
224 colourPanel = new FeatureColourPanel();
225 colourPanel.setSize(110, 15);
226 final FeatureRenderer fr = this;
228 Panel panel = new Panel(new GridLayout(3, 1));
230 featureIndex = 0; // feature to be amended.
233 // /////////////////////////////////////
234 // /MULTIPLE FEATURES AT SELECTED RESIDUE
235 if (!newFeatures && features.length > 1)
237 panel = new Panel(new GridLayout(4, 1));
239 tmp.add(new Label("Select Feature: "));
240 overlaps = new Choice();
241 for (int i = 0; i < features.length; i++)
243 String item = features[i].getType() + "/" + features[i].getBegin()
244 + "-" + features[i].getEnd();
246 if (features[i].getFeatureGroup() != null)
247 item += " (" + features[i].getFeatureGroup() + ")";
249 overlaps.addItem(item);
254 overlaps.addItemListener(new java.awt.event.ItemListener()
256 public void itemStateChanged(java.awt.event.ItemEvent e)
258 int index = overlaps.getSelectedIndex();
261 featureIndex = index;
262 name.setText(features[index].getType());
263 description.setText(features[index].getDescription());
264 source.setText(features[index].getFeatureGroup());
265 start.setText(features[index].getBegin() + "");
266 end.setText(features[index].getEnd() + "");
268 SearchResults highlight = new SearchResults();
269 highlight.addResult(sequences[0], features[index].getBegin(),
270 features[index].getEnd());
272 ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
275 Object col = getFeatureStyle(name.getText());
278 col = new jalview.schemes.UserColourScheme()
279 .createColourFromName(name.getText());
282 colourPanel.updateColor(col);
289 // ////////////////////////////////////
293 tmp.add(new Label("Name: ", Label.RIGHT));
298 tmp.add(new Label("Group: ", Label.RIGHT));
303 tmp.add(new Label("Colour: ", Label.RIGHT));
304 tmp.add(colourPanel);
306 bigPanel.add(panel, BorderLayout.NORTH);
309 panel.add(new Label("Description: ", Label.RIGHT));
310 panel.add(new ScrollPane().add(description));
314 bigPanel.add(panel, BorderLayout.SOUTH);
317 panel.add(new Label(" Start:", Label.RIGHT));
319 panel.add(new Label(" End:", Label.RIGHT));
321 bigPanel.add(panel, BorderLayout.CENTER);
325 bigPanel.add(panel, BorderLayout.CENTER);
328 if (lastFeatureAdded == null)
330 if (features[0].type != null)
332 lastFeatureAdded = features[0].type;
336 lastFeatureAdded = "feature_1";
340 if (lastFeatureGroupAdded == null)
342 if (features[0].featureGroup != null)
344 lastFeatureGroupAdded = features[0].featureGroup;
348 lastFeatureAdded = "Jalview";
352 String title = newFeatures ? "Create New Sequence Feature(s)"
353 : "Amend/Delete Features for " + sequences[0].getName();
355 final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385,
358 dialog.setMainPanel(bigPanel);
362 name.setText(lastFeatureAdded);
363 source.setText(lastFeatureGroupAdded);
367 dialog.ok.setLabel("Amend");
368 dialog.buttonPanel.add(deleteButton, 1);
369 deleteButton.addActionListener(new ActionListener()
371 public void actionPerformed(ActionEvent evt)
373 deleteFeature = true;
374 dialog.setVisible(false);
377 name.setText(features[0].getType());
378 source.setText(features[0].getFeatureGroup());
381 start.setText(features[0].getBegin() + "");
382 end.setText(features[0].getEnd() + "");
383 description.setText(features[0].getDescription());
384 Color col = getColour(name.getText());
387 col = new jalview.schemes.UserColourScheme()
388 .createColourFromName(name.getText());
390 Object fcol = getFeatureStyle(name.getText());
391 // simply display the feature color in a box
392 colourPanel.updateColor(fcol);
393 dialog.setResizable(true);
394 // TODO: render the graduated color in the box.
395 colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
397 public void mousePressed(java.awt.event.MouseEvent evt)
399 if (!colourPanel.isGcol)
401 new UserDefinedColours(fr, ap.alignFrame);
405 FeatureColourChooser fcc = new FeatureColourChooser(
406 ap.alignFrame, name.getText());
407 dialog.transferFocus();
411 dialog.setVisible(true);
413 jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
417 // This ensures that the last sequence
418 // is refreshed and new features are rendered
420 lastFeatureAdded = name.getText().trim();
421 lastFeatureGroupAdded = source.getText().trim();
422 lastDescriptionAdded = description.getText().replace('\n', ' ');
425 if (lastFeatureGroupAdded != null && lastFeatureGroupAdded.length() < 1)
426 lastFeatureGroupAdded = null;
431 SequenceFeature sf = features[featureIndex];
434 sf.type = lastFeatureAdded;
435 sf.featureGroup = lastFeatureGroupAdded;
436 sf.description = lastDescriptionAdded;
437 if (!colourPanel.isGcol)
439 // update colour - otherwise its already done.
440 setColour(sf.type, colourPanel.getBackground());
444 sf.begin = Integer.parseInt(start.getText());
445 sf.end = Integer.parseInt(end.getText());
446 } catch (NumberFormatException ex)
450 ffile.parseDescriptionHTML(sf, false);
454 sequences[0].deleteFeature(sf);
460 if (dialog.accept && name.getText().length() > 0)
462 for (int i = 0; i < sequences.length; i++)
464 features[i].type = lastFeatureAdded;
465 features[i].featureGroup = lastFeatureGroupAdded;
466 features[i].description = lastDescriptionAdded;
467 sequences[i].addSequenceFeature(features[i]);
468 ffile.parseDescriptionHTML(features[i], false);
471 if (av.featuresDisplayed == null)
473 av.featuresDisplayed = new Hashtable();
476 if (featureGroups == null)
478 featureGroups = new Hashtable();
481 col = colourPanel.getBackground();
482 // setColour(lastFeatureAdded, fcol);
484 if (lastFeatureGroupAdded != null)
486 featureGroups.put(lastFeatureGroupAdded, new Boolean(true));
488 if (fcol instanceof Color)
490 setColour(lastFeatureAdded, fcol);
492 av.featuresDisplayed.put(lastFeatureAdded,
493 getFeatureStyle(lastFeatureAdded));
497 String[] tro = new String[renderOrder.length];
498 tro[0] = renderOrder[renderOrder.length - 1];
499 System.arraycopy(renderOrder, 0, tro, 1, renderOrder.length - 1);
504 // no update to the alignment
508 // refresh the alignment and the feature settings dialog
509 if (av.featureSettings != null)
511 av.featureSettings.refreshTable();
513 // findAllFeatures();
515 ap.paintAlignment(true);
520 public Color findFeatureColour(Color initialCol, SequenceI seq, int i)
523 if (!av.showSequenceFeatures)
529 sequenceFeatures = lastSeq.getSequenceFeatures();
530 if (sequenceFeatures == null)
535 sfSize = sequenceFeatures.length;
537 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(i)))
542 currentColour = null;
544 drawSequence(null, lastSeq, lastSeq.findPosition(i), -1, -1);
546 if (currentColour == null)
551 return new Color(((Integer) currentColour).intValue());
555 * This is used by the Molecule Viewer to get the accurate colour of the
558 boolean overview = false;
583 // SequenceFeature sf;
586 SequenceFeature[] sequenceFeatures;
588 int sfSize, sfindex, spos, epos;
590 synchronized public void drawSequence(Graphics g, SequenceI seq,
591 int start, int end, int y1)
593 if (seq.getSequenceFeatures() == null
594 || seq.getSequenceFeatures().length == 0)
599 if (transparencySetter != null && g != null)
601 transparencySetter.setTransparency(g, transparency);
604 if (lastSeq == null || seq != lastSeq
605 || sequenceFeatures != seq.getSequenceFeatures())
608 sequenceFeatures = seq.getSequenceFeatures();
609 sfSize = sequenceFeatures.length;
612 if (av.featuresDisplayed == null || renderOrder == null)
615 if (av.featuresDisplayed.size() < 1)
620 sequenceFeatures = seq.getSequenceFeatures();
621 sfSize = sequenceFeatures.length;
625 spos = lastSeq.findPosition(start);
626 epos = lastSeq.findPosition(end);
629 fm = g.getFontMetrics();
633 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
635 type = renderOrder[renderIndex];
636 if (!av.featuresDisplayed.containsKey(type))
641 // loop through all features in sequence to find
642 // current feature to render
643 for (sfindex = 0; sfindex < sfSize; sfindex++)
645 if (!sequenceFeatures[sfindex].type.equals(type))
650 if (featureGroups != null
651 && sequenceFeatures[sfindex].featureGroup != null
653 .containsKey(sequenceFeatures[sfindex].featureGroup)
654 && !((Boolean) featureGroups
655 .get(sequenceFeatures[sfindex].featureGroup))
662 && (sequenceFeatures[sfindex].getBegin() > epos || sequenceFeatures[sfindex]
670 if (sequenceFeatures[sfindex].begin <= start
671 && sequenceFeatures[sfindex].end >= start)
673 currentColour = new Integer(
674 getColour(sequenceFeatures[sfindex]).getRGB());// av.featuresDisplayed
675 // .get(sequenceFeatures[sfindex].type);
679 else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
682 renderFeature(g, seq,
683 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
684 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
685 getColour(sequenceFeatures[sfindex])
686 // new Color(((Integer) av.featuresDisplayed
687 // .get(sequenceFeatures[sfindex].type)).intValue())
689 renderFeature(g, seq,
690 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
691 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
692 getColour(sequenceFeatures[sfindex])
693 // new Color(((Integer) av.featuresDisplayed
694 // .get(sequenceFeatures[sfindex].type)).intValue())
700 if (showFeature(sequenceFeatures[sfindex]))
702 renderFeature(g, seq,
703 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
704 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
705 getColour(sequenceFeatures[sfindex]), start, end, y1);
712 if (transparencySetter != null && g != null)
714 transparencySetter.setTransparency(g, 1.0f);
722 void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
723 Color featureColour, int start, int end, int y1)
726 if (((fstart <= end) && (fend >= start)))
729 { // fix for if the feature we have starts before the sequence start,
730 fstart = start; // but the feature end is still valid!!
738 for (i = fstart; i <= fend; i++)
740 s = seq.getCharAt(i);
742 if (jalview.util.Comparison.isGap(s))
747 g.setColor(featureColour);
749 g.fillRect((i - start) * av.charWidth, y1, av.charWidth,
752 if (!av.validCharWidth)
757 g.setColor(Color.white);
758 charOffset = (av.charWidth - fm.charWidth(s)) / 2;
759 g.drawString(String.valueOf(s), charOffset
760 + (av.charWidth * (i - start)), (y1 + av.charHeight)
761 - av.charHeight / 5); // pady = height / 5;
767 Hashtable minmax = null;
770 * Called when alignment in associated view has new/modified features to
771 * discover and display.
774 public void featuresAdded()
781 * find all features on the alignment
783 void findAllFeatures()
785 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
787 av.featuresDisplayed = new Hashtable();
788 Vector allfeatures = new Vector();
789 minmax = new Hashtable();
790 AlignmentI alignment = av.getAlignment();
791 for (int i = 0; i < alignment.getHeight(); i++)
793 SequenceFeature[] features = alignment.getSequenceAt(i)
794 .getSequenceFeatures();
796 if (features == null)
802 while (index < features.length)
804 if (features[index].begin == 0 && features[index].end == 0)
809 if (!av.featuresDisplayed.containsKey(features[index].getType()))
811 if (getColour(features[index].getType()) == null)
813 featureColours.put(features[index].getType(),
814 ucs.createColourFromName(features[index].getType()));
817 av.featuresDisplayed.put(features[index].getType(), new Integer(
818 getColour(features[index].getType()).getRGB()));
819 allfeatures.addElement(features[index].getType());
821 if (features[index].score != Float.NaN)
823 int nonpos = features[index].getBegin() >= 1 ? 0 : 1;
824 float[][] mm = (float[][]) minmax.get(features[index].getType());
829 minmax.put(features[index].getType(), mm);
831 if (mm[nonpos] == null)
833 mm[nonpos] = new float[]
834 { features[index].score, features[index].score };
839 if (mm[nonpos][0] > features[index].score)
841 mm[nonpos][0] = features[index].score;
843 if (mm[nonpos][1] < features[index].score)
845 mm[nonpos][1] = features[index].score;
854 renderOrder = new String[allfeatures.size()];
855 Enumeration en = allfeatures.elements();
856 int i = allfeatures.size() - 1;
857 while (en.hasMoreElements())
859 renderOrder[i] = en.nextElement().toString();
865 * get a feature style object for the given type string. Creates a
866 * java.awt.Color for a featureType with no existing colourscheme. TODO:
867 * replace return type with object implementing standard abstract colour/style
871 * @return java.awt.Color or GraduatedColor
873 public Object getFeatureStyle(String featureType)
875 Object fc = featureColours.get(featureType);
878 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
879 Color col = ucs.createColourFromName(featureType);
880 featureColours.put(featureType, fc = col);
885 public Color getColour(String featureType)
887 Object fc = getFeatureStyle(featureType);
889 if (fc instanceof Color)
895 if (fc instanceof GraduatedColor)
897 return ((GraduatedColor) fc).getMaxColor();
900 throw new Error("Implementation Error: Unrecognised render object "
901 + fc.getClass() + " for features of type " + featureType);
906 * @param sequenceFeature
907 * @return true if feature is visible.
909 private boolean showFeature(SequenceFeature sequenceFeature)
911 Object fc = getFeatureStyle(sequenceFeature.type);
912 if (fc instanceof GraduatedColor)
914 return ((GraduatedColor) fc).isColored(sequenceFeature);
923 * implement graduated colouring for features with scores
926 * @return render colour for the given feature
928 public Color getColour(SequenceFeature feature)
930 Object fc = getFeatureStyle(feature.getType());
931 if (fc instanceof Color)
937 if (fc instanceof GraduatedColor)
939 return ((GraduatedColor) fc).findColor(feature);
942 throw new Error("Implementation Error: Unrecognised render object "
943 + fc.getClass() + " for features of type " + feature.getType());
946 public void setColour(String featureType, Object col)
949 // Color _col = (col instanceof Color) ? ((Color) col) : (col instanceof
950 // GraduatedColor) ? ((GraduatedColor) col).getMaxColor() : null;
951 // Object c = featureColours.get(featureType);
952 // if (c == null || c instanceof Color || (c instanceof GraduatedColor &&
953 // !((GraduatedColor)c).getMaxColor().equals(_col)))
955 featureColours.put(featureType, col);
959 public void setFeaturePriority(Object[][] data)
961 // The feature table will display high priority
962 // features at the top, but theses are the ones
963 // we need to render last, so invert the data
964 if (av.featuresDisplayed != null)
966 av.featuresDisplayed.clear();
970 * if (visibleNew) { if (av.featuresDisplayed != null) {
971 * av.featuresDisplayed.clear(); } else { av.featuresDisplayed = new
972 * Hashtable(); } } if (data == null) { return; }
975 renderOrder = new String[data.length];
979 for (int i = 0; i < data.length; i++)
981 String type = data[i][0].toString();
982 setColour(type, data[i][1]);
983 if (((Boolean) data[i][2]).booleanValue())
985 av.featuresDisplayed.put(type, new Integer(getColour(type)
989 renderOrder[data.length - i - 1] = type;
995 * @return a simple list of feature group names or null
997 public String[] getGroups()
1000 if (featureGroups != null)
1002 String[] gps = new String[featureGroups.size()];
1003 Enumeration gn = featureGroups.keys();
1005 while (gn.hasMoreElements())
1007 gps[i++] = (String) gn.nextElement();
1015 * get visible or invisible groups
1018 * true to return visible groups, false to return hidden ones.
1019 * @return list of groups
1021 public String[] getGroups(boolean visible)
1024 if (featureGroups != null)
1026 Vector gp = new Vector();
1028 Enumeration gn = featureGroups.keys();
1029 while (gn.hasMoreElements())
1031 String nm = (String) gn.nextElement();
1032 Boolean state = (Boolean) featureGroups.get(nm);
1033 if (state.booleanValue() == visible)
1038 String[] gps = new String[gp.size()];
1042 while (gn.hasMoreElements())
1044 gps[i++] = (String) gn.nextElement();
1052 * set all feature groups in toset to be visible or invisible
1057 * the state of the named groups to set
1059 public void setGroupState(String[] toset, boolean visible)
1062 if (toset != null && toset.length > 0 && featureGroups != null)
1064 boolean rdrw = false;
1065 for (int i = 0; i < toset.length; i++)
1067 Object st = featureGroups.get(toset[i]);
1068 featureGroups.put(toset[i], new Boolean(visible));
1071 rdrw = rdrw || (visible != ((Boolean) st).booleanValue());
1076 if (this.av != null)
1077 if (this.av.featureSettings != null)
1079 av.featureSettings.rebuildGroups();
1080 this.av.featureSettings.resetTable(true);
1088 av.alignmentChanged(null);
1094 ArrayList<String> hiddenGroups = new ArrayList<String>();
1097 * analyse alignment for groups and hash tables (used to be embedded in
1098 * FeatureSettings.setTableData)
1100 * @return true if features are on the alignment
1102 public boolean buildGroupHash()
1104 boolean alignmentHasFeatures = false;
1105 if (featureGroups == null)
1107 featureGroups = new Hashtable();
1109 hiddenGroups = new ArrayList<String>();
1110 hiddenGroups.addAll(featureGroups.keySet());
1111 ArrayList allFeatures = new ArrayList();
1112 ArrayList allGroups = new ArrayList();
1113 SequenceFeature[] tmpfeatures;
1115 AlignmentI alignment = av.getAlignment();
1116 for (int i = 0; i < alignment.getHeight(); i++)
1118 if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
1123 alignmentHasFeatures = true;
1125 tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
1127 while (index < tmpfeatures.length)
1129 if (tmpfeatures[index].getFeatureGroup() != null)
1131 group = tmpfeatures[index].featureGroup;
1132 // Remove group from the hiddenGroup list
1133 hiddenGroups.remove(group);
1134 if (!allGroups.contains(group))
1136 allGroups.add(group);
1138 boolean visible = true;
1139 if (featureGroups.containsKey(group))
1141 visible = ((Boolean) featureGroups.get(group)).booleanValue();
1145 featureGroups.put(group, new Boolean(visible));
1150 if (!allFeatures.contains(tmpfeatures[index].getType()))
1152 allFeatures.add(tmpfeatures[index].getType());
1158 return alignmentHasFeatures;
1162 * rebuild the featuresDisplayed and renderorder list based on the
1163 * featureGroups hash and any existing display state and force a repaint if
1166 * @return true if alignment has visible features
1168 public boolean buildFeatureHash()
1170 boolean alignmentHasFeatures = false;
1171 if (featureGroups == null)
1173 alignmentHasFeatures = buildGroupHash();
1175 if (!alignmentHasFeatures)
1177 Hashtable fdisp = av.featuresDisplayed;
1178 Vector allFeatures = new Vector();
1179 SequenceFeature[] tmpfeatures;
1181 AlignmentI alignment = av.getAlignment();
1182 for (int i = 0; i < alignment.getHeight(); i++)
1184 if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
1189 alignmentHasFeatures = true;
1191 tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
1193 while (index < tmpfeatures.length)
1195 boolean visible = true;
1196 if (tmpfeatures[index].getFeatureGroup() != null)
1198 group = tmpfeatures[index].featureGroup;
1199 if (featureGroups.containsKey(group))
1201 visible = ((Boolean) featureGroups.get(group)).booleanValue();
1205 if (visible && !allFeatures.contains(tmpfeatures[index].getType()))
1207 allFeatures.addElement(tmpfeatures[index].getType());
1212 if (allFeatures.size() > 0)
1214 String[] neworder = new String[allFeatures.size()];
1215 int p = neworder.length - 1;
1216 for (int i = renderOrder.length - 1; i >= 0; i--)
1218 if (allFeatures.contains(renderOrder[i]))
1220 neworder[p--] = renderOrder[i];
1221 allFeatures.removeElement(renderOrder[i]);
1225 av.featuresDisplayed.remove(renderOrder[i]);
1228 for (int i = allFeatures.size() - 1; i > 0; i++)
1230 Object e = allFeatures.elementAt(i);
1233 neworder[p--] = (String) e;
1234 av.featuresDisplayed.put(e, getColour((String) e));
1237 renderOrder = neworder;
1241 return alignmentHasFeatures;
1246 * @return the displayed feature type as an array of strings
1248 protected String[] getDisplayedFeatureTypes()
1250 String[] typ = null;
1251 synchronized (renderOrder)
1253 typ = new String[renderOrder.length];
1254 System.arraycopy(renderOrder, 0, typ, 0, typ.length);
1255 for (int i = 0; i < typ.length; i++)
1257 if (av.featuresDisplayed.get(typ[i]) == null)
1267 class TransparencySetter
1269 void setTransparency(Graphics g, float value)
1271 Graphics2D g2 = (Graphics2D) g;
1272 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,