2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, 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.appletgui.FeatureSettings.MyCheckbox;
27 import jalview.datamodel.*;
28 import jalview.schemes.AnnotationColourGradient;
29 import jalview.schemes.GraduatedColor;
37 public class FeatureRenderer implements jalview.api.FeatureRenderer
41 Hashtable featureColours = new Hashtable();
43 // A higher level for grouping features of a
45 Hashtable featureGroups = null;
47 // Holds web links for feature groups and feature types
48 // in the form label|link
49 Hashtable featureLinks = null;
51 // This is actually an Integer held in the hashtable,
52 // Retrieved using the key feature type
61 float transparency = 1f;
63 TransparencySetter transparencySetter = null;
66 * Creates a new FeatureRenderer object.
71 public FeatureRenderer(AlignViewport av)
75 if (!System.getProperty("java.version").startsWith("1.1"))
77 transparencySetter = new TransparencySetter();
81 public void transferSettings(FeatureRenderer fr)
83 renderOrder = fr.renderOrder;
84 featureGroups = fr.featureGroups;
85 featureColours = fr.featureColours;
86 transparency = fr.transparency;
87 if (av!=null && fr.av!=null && fr.av!=av)
89 if (fr.av.featuresDisplayed!=null)
91 if (av.featuresDisplayed==null)
93 av.featuresDisplayed = new Hashtable();
95 av.featuresDisplayed.clear();
97 Enumeration en=fr.av.featuresDisplayed.keys();
98 while (en.hasMoreElements())
100 av.featuresDisplayed.put(en.nextElement(), Boolean.TRUE);
106 static String lastFeatureAdded;
108 static String lastFeatureGroupAdded;
110 static String lastDescriptionAdded;
112 int featureIndex = 0;
114 boolean deleteFeature = false;
116 FeatureColourPanel colourPanel;
118 class FeatureColourPanel extends Panel
122 private Color maxCol;
124 private boolean isColourByLabel, isGcol;
127 * render a feature style in the amend feature dialog box
129 public void updateColor(Object newcol)
132 Color bg, col = null;
133 GraduatedColor gcol = null;
135 if (newcol instanceof Color)
138 col = (Color) newcol;
141 else if (newcol instanceof GraduatedColor)
144 gcol = (GraduatedColor) newcol;
149 throw new Error("Invalid color for MyCheckBox");
153 setBackground(bg = col);
157 if (gcol.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
160 + ((gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD) ? "(>)"
163 if (isColourByLabel = gcol.isColourByLabel())
165 setBackground(bg = Color.white);
166 vlabel += " (by Label)";
170 setBackground(bg = gcol.getMinColor());
171 maxCol = gcol.getMaxColor();
184 public void paint(Graphics g)
186 Dimension d = getSize();
191 g.setColor(Color.white);
192 g.fillRect(d.width / 2, 0, d.width / 2, d.height);
193 g.setColor(Color.black);
194 Font f = new Font("Verdana", Font.PLAIN, 10);
196 g.drawString("Label", 0, 0);
201 g.fillRect(d.width / 2, 0, d.width / 2, d.height);
209 boolean amendFeatures(final SequenceI[] sequences,
210 final SequenceFeature[] features, boolean newFeatures,
211 final AlignmentPanel ap)
213 Panel bigPanel = new Panel(new BorderLayout());
214 final TextField name = new TextField(16);
215 final TextField source = new TextField(16);
216 final TextArea description = new TextArea(3, 35);
217 final TextField start = new TextField(8);
218 final TextField end = new TextField(8);
219 final Choice overlaps;
220 Button deleteButton = new Button("Delete");
221 deleteFeature = false;
223 colourPanel = new FeatureColourPanel();
224 colourPanel.setSize(110, 15);
225 final FeatureRenderer fr = this;
227 Panel panel = new Panel(new GridLayout(3, 1));
229 featureIndex = 0; // feature to be amended.
232 // /////////////////////////////////////
233 // /MULTIPLE FEATURES AT SELECTED RESIDUE
234 if (!newFeatures && features.length > 1)
236 panel = new Panel(new GridLayout(4, 1));
238 tmp.add(new Label("Select Feature: "));
239 overlaps = new Choice();
240 for (int i = 0; i < features.length; i++)
242 String item = features[i].getType() + "/" + features[i].getBegin()
243 + "-" + features[i].getEnd();
245 if (features[i].getFeatureGroup() != null)
246 item += " (" + features[i].getFeatureGroup() + ")";
248 overlaps.addItem(item);
253 overlaps.addItemListener(new java.awt.event.ItemListener()
255 public void itemStateChanged(java.awt.event.ItemEvent e)
257 int index = overlaps.getSelectedIndex();
260 featureIndex = index;
261 name.setText(features[index].getType());
262 description.setText(features[index].getDescription());
263 source.setText(features[index].getFeatureGroup());
264 start.setText(features[index].getBegin() + "");
265 end.setText(features[index].getEnd() + "");
267 SearchResults highlight = new SearchResults();
268 highlight.addResult(sequences[0], features[index].getBegin(),
269 features[index].getEnd());
271 ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
274 Object col = getFeatureStyle(name.getText());
277 col = new jalview.schemes.UserColourScheme()
278 .createColourFromName(name.getText());
281 colourPanel.updateColor(col);
288 // ////////////////////////////////////
292 tmp.add(new Label("Name: ", Label.RIGHT));
297 tmp.add(new Label("Group: ", Label.RIGHT));
302 tmp.add(new Label("Colour: ", Label.RIGHT));
303 tmp.add(colourPanel);
305 bigPanel.add(panel, BorderLayout.NORTH);
308 panel.add(new Label("Description: ", Label.RIGHT));
309 panel.add(new ScrollPane().add(description));
313 bigPanel.add(panel, BorderLayout.SOUTH);
316 panel.add(new Label(" Start:", Label.RIGHT));
318 panel.add(new Label(" End:", Label.RIGHT));
320 bigPanel.add(panel, BorderLayout.CENTER);
324 bigPanel.add(panel, BorderLayout.CENTER);
327 if (lastFeatureAdded == null)
329 if (features[0].type != null)
331 lastFeatureAdded = features[0].type;
335 lastFeatureAdded = "feature_1";
339 if (lastFeatureGroupAdded == null)
341 if (features[0].featureGroup != null)
343 lastFeatureGroupAdded = features[0].featureGroup;
347 lastFeatureAdded = "Jalview";
351 String title = newFeatures ? "Create New Sequence Feature(s)"
352 : "Amend/Delete Features for " + sequences[0].getName();
354 final JVDialog dialog = new JVDialog(ap.alignFrame, title, true, 385,
357 dialog.setMainPanel(bigPanel);
361 name.setText(lastFeatureAdded);
362 source.setText(lastFeatureGroupAdded);
366 dialog.ok.setLabel("Amend");
367 dialog.buttonPanel.add(deleteButton, 1);
368 deleteButton.addActionListener(new ActionListener()
370 public void actionPerformed(ActionEvent evt)
372 deleteFeature = true;
373 dialog.setVisible(false);
376 name.setText(features[0].getType());
377 source.setText(features[0].getFeatureGroup());
380 start.setText(features[0].getBegin() + "");
381 end.setText(features[0].getEnd() + "");
382 description.setText(features[0].getDescription());
383 Color col = getColour(name.getText());
386 col = new jalview.schemes.UserColourScheme()
387 .createColourFromName(name.getText());
389 Object fcol = getFeatureStyle(name.getText());
390 // simply display the feature color in a box
391 colourPanel.updateColor(fcol);
392 dialog.setResizable(true);
393 // TODO: render the graduated color in the box.
394 colourPanel.addMouseListener(new java.awt.event.MouseAdapter()
396 public void mousePressed(java.awt.event.MouseEvent evt)
398 if (!colourPanel.isGcol)
400 new UserDefinedColours(fr, ap.alignFrame);
404 FeatureColourChooser fcc = new FeatureColourChooser(
405 ap.alignFrame, name.getText());
406 dialog.transferFocus();
410 dialog.setVisible(true);
412 jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
416 // This ensures that the last sequence
417 // is refreshed and new features are rendered
419 lastFeatureAdded = name.getText().trim();
420 lastFeatureGroupAdded = source.getText().trim();
421 lastDescriptionAdded = description.getText().replace('\n', ' ');
424 if (lastFeatureGroupAdded != null && lastFeatureGroupAdded.length() < 1)
425 lastFeatureGroupAdded = null;
430 SequenceFeature sf = features[featureIndex];
433 sf.type = lastFeatureAdded;
434 sf.featureGroup = lastFeatureGroupAdded;
435 sf.description = lastDescriptionAdded;
436 if (!colourPanel.isGcol)
438 // update colour - otherwise its already done.
439 setColour(sf.type, colourPanel.getBackground());
443 sf.begin = Integer.parseInt(start.getText());
444 sf.end = Integer.parseInt(end.getText());
445 } catch (NumberFormatException ex)
449 ffile.parseDescriptionHTML(sf, false);
453 sequences[0].deleteFeature(sf);
459 if (dialog.accept && name.getText().length() > 0)
461 for (int i = 0; i < sequences.length; i++)
463 features[i].type = lastFeatureAdded;
464 features[i].featureGroup = lastFeatureGroupAdded;
465 features[i].description = lastDescriptionAdded;
466 sequences[i].addSequenceFeature(features[i]);
467 ffile.parseDescriptionHTML(features[i], false);
470 if (av.featuresDisplayed == null)
472 av.featuresDisplayed = new Hashtable();
475 if (featureGroups == null)
477 featureGroups = new Hashtable();
480 col = colourPanel.getBackground();
481 // setColour(lastFeatureAdded, fcol);
483 if (lastFeatureGroupAdded != null)
485 featureGroups.put(lastFeatureGroupAdded, new Boolean(true));
487 if (fcol instanceof Color)
489 setColour(lastFeatureAdded, fcol);
491 av.featuresDisplayed.put(lastFeatureAdded,
492 getFeatureStyle(lastFeatureAdded));
496 String[] tro = new String[renderOrder.length];
497 tro[0] = renderOrder[renderOrder.length - 1];
498 System.arraycopy(renderOrder, 0, tro, 1, renderOrder.length - 1);
503 // no update to the alignment
507 // refresh the alignment and the feature settings dialog
508 if (av.featureSettings != null)
510 av.featureSettings.refreshTable();
512 // findAllFeatures();
514 ap.paintAlignment(true);
519 public Color findFeatureColour(Color initialCol, SequenceI seq, int i)
522 if (!av.showSequenceFeatures)
528 sequenceFeatures = lastSeq.getSequenceFeatures();
529 if (sequenceFeatures == null)
534 sfSize = sequenceFeatures.length;
536 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(i)))
541 currentColour = null;
543 drawSequence(null, lastSeq, lastSeq.findPosition(i), -1, -1);
545 if (currentColour == null)
550 return new Color(((Integer) currentColour).intValue());
554 * This is used by the Molecule Viewer to get the accurate colour of the
557 boolean overview = false;
582 // SequenceFeature sf;
585 SequenceFeature[] sequenceFeatures;
587 int sfSize, sfindex, spos, epos;
589 synchronized public void drawSequence(Graphics g, SequenceI seq,
590 int start, int end, int y1)
592 if (seq.getSequenceFeatures() == null
593 || seq.getSequenceFeatures().length == 0)
598 if (transparencySetter != null && g != null)
600 transparencySetter.setTransparency(g, transparency);
603 if (lastSeq == null || seq != lastSeq
604 || sequenceFeatures != seq.getSequenceFeatures())
607 sequenceFeatures = seq.getSequenceFeatures();
608 sfSize = sequenceFeatures.length;
611 if (av.featuresDisplayed == null || renderOrder == null)
614 if (av.featuresDisplayed.size() < 1)
619 sequenceFeatures = seq.getSequenceFeatures();
620 sfSize = sequenceFeatures.length;
624 spos = lastSeq.findPosition(start);
625 epos = lastSeq.findPosition(end);
628 fm = g.getFontMetrics();
632 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
634 type = renderOrder[renderIndex];
635 if (!av.featuresDisplayed.containsKey(type))
640 // loop through all features in sequence to find
641 // current feature to render
642 for (sfindex = 0; sfindex < sfSize; sfindex++)
644 if (!sequenceFeatures[sfindex].type.equals(type))
649 if (featureGroups != null
650 && sequenceFeatures[sfindex].featureGroup != null
652 .containsKey(sequenceFeatures[sfindex].featureGroup)
653 && !((Boolean) featureGroups
654 .get(sequenceFeatures[sfindex].featureGroup))
661 && (sequenceFeatures[sfindex].getBegin() > epos || sequenceFeatures[sfindex]
669 if (sequenceFeatures[sfindex].begin <= start
670 && sequenceFeatures[sfindex].end >= start)
672 currentColour = new Integer(
673 getColour(sequenceFeatures[sfindex]).getRGB());// av.featuresDisplayed
674 // .get(sequenceFeatures[sfindex].type);
678 else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
681 renderFeature(g, seq,
682 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
683 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
684 getColour(sequenceFeatures[sfindex])
685 // new Color(((Integer) av.featuresDisplayed
686 // .get(sequenceFeatures[sfindex].type)).intValue())
688 renderFeature(g, seq,
689 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
690 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
691 getColour(sequenceFeatures[sfindex])
692 // new Color(((Integer) av.featuresDisplayed
693 // .get(sequenceFeatures[sfindex].type)).intValue())
699 if (showFeature(sequenceFeatures[sfindex]))
701 renderFeature(g, seq,
702 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
703 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
704 getColour(sequenceFeatures[sfindex]), start, end, y1);
711 if (transparencySetter != null && g != null)
713 transparencySetter.setTransparency(g, 1.0f);
721 void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
722 Color featureColour, int start, int end, int y1)
725 if (((fstart <= end) && (fend >= start)))
728 { // fix for if the feature we have starts before the sequence start,
729 fstart = start; // but the feature end is still valid!!
737 for (i = fstart; i <= fend; i++)
739 s = seq.getCharAt(i);
741 if (jalview.util.Comparison.isGap(s))
746 g.setColor(featureColour);
748 g.fillRect((i - start) * av.charWidth, y1, av.charWidth,
751 if (!av.validCharWidth)
756 g.setColor(Color.white);
757 charOffset = (av.charWidth - fm.charWidth(s)) / 2;
758 g.drawString(String.valueOf(s), charOffset
759 + (av.charWidth * (i - start)), (y1 + av.charHeight)
760 - av.charHeight / 5); // pady = height / 5;
766 Hashtable minmax = null;
769 * Called when alignment in associated view has new/modified features to
770 * discover and display.
773 public void featuresAdded()
780 * find all features on the alignment
782 void findAllFeatures()
784 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
786 av.featuresDisplayed = new Hashtable();
787 Vector allfeatures = new Vector();
788 minmax = new Hashtable();
789 AlignmentI alignment=av.getAlignment();
790 for (int i = 0; i < alignment.getHeight(); i++)
792 SequenceFeature[] features = alignment.getSequenceAt(i)
793 .getSequenceFeatures();
795 if (features == null)
801 while (index < features.length)
803 if (features[index].begin == 0 && features[index].end == 0)
808 if (!av.featuresDisplayed.containsKey(features[index].getType()))
810 if (getColour(features[index].getType()) == null)
812 featureColours.put(features[index].getType(),
813 ucs.createColourFromName(features[index].getType()));
816 av.featuresDisplayed.put(features[index].getType(), new Integer(
817 getColour(features[index].getType()).getRGB()));
818 allfeatures.addElement(features[index].getType());
820 if (features[index].score != Float.NaN)
822 int nonpos = features[index].getBegin() >= 1 ? 0 : 1;
823 float[][] mm = (float[][]) minmax.get(features[index].getType());
828 minmax.put(features[index].getType(), mm);
830 if (mm[nonpos] == null)
832 mm[nonpos] = new float[]
833 { features[index].score, features[index].score };
838 if (mm[nonpos][0] > features[index].score)
840 mm[nonpos][0] = features[index].score;
842 if (mm[nonpos][1] < features[index].score)
844 mm[nonpos][1] = features[index].score;
853 renderOrder = new String[allfeatures.size()];
854 Enumeration en = allfeatures.elements();
855 int i = allfeatures.size() - 1;
856 while (en.hasMoreElements())
858 renderOrder[i] = en.nextElement().toString();
864 * get a feature style object for the given type string. Creates a
865 * java.awt.Color for a featureType with no existing colourscheme. TODO:
866 * replace return type with object implementing standard abstract colour/style
870 * @return java.awt.Color or GraduatedColor
872 public Object getFeatureStyle(String featureType)
874 Object fc = featureColours.get(featureType);
877 jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
878 Color col = ucs.createColourFromName(featureType);
879 featureColours.put(featureType, fc = col);
884 public Color getColour(String featureType)
886 Object fc = getFeatureStyle(featureType);
888 if (fc instanceof Color)
894 if (fc instanceof GraduatedColor)
896 return ((GraduatedColor) fc).getMaxColor();
899 throw new Error("Implementation Error: Unrecognised render object "
900 + fc.getClass() + " for features of type " + featureType);
905 * @param sequenceFeature
906 * @return true if feature is visible.
908 private boolean showFeature(SequenceFeature sequenceFeature)
910 Object fc = getFeatureStyle(sequenceFeature.type);
911 if (fc instanceof GraduatedColor)
913 return ((GraduatedColor) fc).isColored(sequenceFeature);
922 * implement graduated colouring for features with scores
925 * @return render colour for the given feature
927 public Color getColour(SequenceFeature feature)
929 Object fc = getFeatureStyle(feature.getType());
930 if (fc instanceof Color)
936 if (fc instanceof GraduatedColor)
938 return ((GraduatedColor) fc).findColor(feature);
941 throw new Error("Implementation Error: Unrecognised render object "
942 + fc.getClass() + " for features of type " + feature.getType());
945 public void setColour(String featureType, Object col)
948 // Color _col = (col instanceof Color) ? ((Color) col) : (col instanceof
949 // GraduatedColor) ? ((GraduatedColor) col).getMaxColor() : null;
950 // Object c = featureColours.get(featureType);
951 // if (c == null || c instanceof Color || (c instanceof GraduatedColor &&
952 // !((GraduatedColor)c).getMaxColor().equals(_col)))
954 featureColours.put(featureType, col);
958 public void setFeaturePriority(Object[][] data)
960 // The feature table will display high priority
961 // features at the top, but theses are the ones
962 // we need to render last, so invert the data
963 if (av.featuresDisplayed != null)
965 av.featuresDisplayed.clear();
969 * if (visibleNew) { if (av.featuresDisplayed != null) {
970 * av.featuresDisplayed.clear(); } else { av.featuresDisplayed = new
971 * Hashtable(); } } if (data == null) { return; }
974 renderOrder = new String[data.length];
978 for (int i = 0; i < data.length; i++)
980 String type = data[i][0].toString();
981 setColour(type, data[i][1]);
982 if (((Boolean) data[i][2]).booleanValue())
984 av.featuresDisplayed.put(type, new Integer(getColour(type)
988 renderOrder[data.length - i - 1] = type;
994 * @return a simple list of feature group names or null
996 public String[] getGroups()
999 if (featureGroups != null)
1001 String[] gps = new String[featureGroups.size()];
1002 Enumeration gn = featureGroups.keys();
1004 while (gn.hasMoreElements())
1006 gps[i++] = (String) gn.nextElement();
1014 * get visible or invisible groups
1017 * true to return visible groups, false to return hidden ones.
1018 * @return list of groups
1020 public String[] getGroups(boolean visible)
1023 if (featureGroups != null)
1025 Vector gp = new Vector();
1027 Enumeration gn = featureGroups.keys();
1028 while (gn.hasMoreElements())
1030 String nm = (String) gn.nextElement();
1031 Boolean state = (Boolean) featureGroups.get(nm);
1032 if (state.booleanValue() == visible)
1037 String[] gps = new String[gp.size()];
1041 while (gn.hasMoreElements())
1043 gps[i++] = (String) gn.nextElement();
1051 * set all feature groups in toset to be visible or invisible
1056 * the state of the named groups to set
1058 public void setGroupState(String[] toset, boolean visible)
1061 if (toset != null && toset.length > 0 && featureGroups != null)
1063 boolean rdrw = false;
1064 for (int i = 0; i < toset.length; i++)
1066 Object st = featureGroups.get(toset[i]);
1067 featureGroups.put(toset[i], new Boolean(visible));
1070 rdrw = rdrw || (visible != ((Boolean) st).booleanValue());
1075 if (this.av != null)
1076 if (this.av.featureSettings != null)
1078 av.featureSettings.rebuildGroups();
1079 this.av.featureSettings.resetTable(true);
1087 av.alignmentChanged(null);
1093 ArrayList<String> hiddenGroups=new ArrayList<String>();
1095 * analyse alignment for groups and hash tables (used to be embedded in
1096 * FeatureSettings.setTableData)
1098 * @return true if features are on the alignment
1100 public boolean buildGroupHash()
1102 boolean alignmentHasFeatures = false;
1103 if (featureGroups == null)
1105 featureGroups = new Hashtable();
1107 hiddenGroups =new ArrayList<String>();
1108 hiddenGroups.addAll(featureGroups.keySet());
1109 ArrayList allFeatures = new ArrayList();
1110 ArrayList allGroups = new ArrayList();
1111 SequenceFeature[] tmpfeatures;
1113 AlignmentI alignment=av.getAlignment();
1114 for (int i = 0; i < alignment.getHeight(); i++)
1116 if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
1121 alignmentHasFeatures = true;
1123 tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
1125 while (index < tmpfeatures.length)
1127 if (tmpfeatures[index].getFeatureGroup() != null)
1129 group = tmpfeatures[index].featureGroup;
1130 // Remove group from the hiddenGroup list
1131 hiddenGroups.remove(group);
1132 if (!allGroups.contains(group))
1134 allGroups.add(group);
1136 boolean visible = true;
1137 if (featureGroups.containsKey(group))
1139 visible = ((Boolean) featureGroups.get(group)).booleanValue();
1143 featureGroups.put(group, new Boolean(visible));
1148 if (!allFeatures.contains(tmpfeatures[index].getType()))
1150 allFeatures.add(tmpfeatures[index].getType());
1156 return alignmentHasFeatures;
1160 * rebuild the featuresDisplayed and renderorder list based on the
1161 * featureGroups hash and any existing display state and force a repaint if
1164 * @return true if alignment has visible features
1166 public boolean buildFeatureHash()
1168 boolean alignmentHasFeatures = false;
1169 if (featureGroups == null)
1171 alignmentHasFeatures = buildGroupHash();
1173 if (!alignmentHasFeatures)
1175 Hashtable fdisp = av.featuresDisplayed;
1176 Vector allFeatures = new Vector();
1177 SequenceFeature[] tmpfeatures;
1179 AlignmentI alignment=av.getAlignment();
1180 for (int i = 0; i < alignment.getHeight(); i++)
1182 if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
1187 alignmentHasFeatures = true;
1189 tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
1191 while (index < tmpfeatures.length)
1193 boolean visible = true;
1194 if (tmpfeatures[index].getFeatureGroup() != null)
1196 group = tmpfeatures[index].featureGroup;
1197 if (featureGroups.containsKey(group))
1199 visible = ((Boolean) featureGroups.get(group)).booleanValue();
1203 if (visible && !allFeatures.contains(tmpfeatures[index].getType()))
1205 allFeatures.addElement(tmpfeatures[index].getType());
1210 if (allFeatures.size() > 0)
1212 String[] neworder = new String[allFeatures.size()];
1213 int p = neworder.length - 1;
1214 for (int i = renderOrder.length - 1; i >= 0; i--)
1216 if (allFeatures.contains(renderOrder[i]))
1218 neworder[p--] = renderOrder[i];
1219 allFeatures.removeElement(renderOrder[i]);
1223 av.featuresDisplayed.remove(renderOrder[i]);
1226 for (int i = allFeatures.size() - 1; i > 0; i++)
1228 Object e = allFeatures.elementAt(i);
1231 neworder[p--] = (String) e;
1232 av.featuresDisplayed.put(e, getColour((String) e));
1235 renderOrder = neworder;
1239 return alignmentHasFeatures;
1244 * @return the displayed feature type as an array of strings
1246 protected String[] getDisplayedFeatureTypes()
1248 String[] typ = null;
1249 synchronized (renderOrder)
1251 typ = new String[renderOrder.length];
1252 System.arraycopy(renderOrder, 0, typ, 0, typ.length);
1253 for (int i = 0; i < typ.length; i++)
1255 if (av.featuresDisplayed.get(typ[i]) == null)
1265 class TransparencySetter
1267 void setTransparency(Graphics g, float value)
1269 Graphics2D g2 = (Graphics2D) g;
1270 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,