+ /**
+ * @return a simple list of feature group names or null
+ */
+ public String[] getGroups()
+ {
+ buildGroupHash();
+ if (featureGroups != null)
+ {
+ String[] gps = new String[featureGroups.size()];
+ Enumeration gn = featureGroups.keys();
+ int i = 0;
+ while (gn.hasMoreElements())
+ {
+ gps[i++] = (String) gn.nextElement();
+ }
+ return gps;
+ }
+ return null;
+ }
+
+ /**
+ * get visible or invisible groups
+ *
+ * @param visible
+ * true to return visible groups, false to return hidden ones.
+ * @return list of groups
+ */
+ public String[] getGroups(boolean visible)
+ {
+ buildGroupHash();
+ if (featureGroups != null)
+ {
+ Vector gp = new Vector();
+
+ Enumeration gn = featureGroups.keys();
+ while (gn.hasMoreElements())
+ {
+ String nm = (String) gn.nextElement();
+ Boolean state = (Boolean) featureGroups.get(nm);
+ if (state.booleanValue() == visible)
+ {
+ gp.addElement(nm);
+ }
+ }
+ String[] gps = new String[gp.size()];
+ gp.copyInto(gps);
+
+ int i = 0;
+ while (gn.hasMoreElements())
+ {
+ gps[i++] = (String) gn.nextElement();
+ }
+ return gps;
+ }
+ return null;
+ }
+
+ /**
+ * set all feature groups in toset to be visible or invisible
+ *
+ * @param toset
+ * group names
+ * @param visible
+ * the state of the named groups to set
+ */
+ public void setGroupState(String[] toset, boolean visible)
+ {
+ buildGroupHash();
+ if (toset != null && toset.length > 0 && featureGroups != null)
+ {
+ boolean rdrw = false;
+ for (int i = 0; i < toset.length; i++)
+ {
+ Object st = featureGroups.get(toset[i]);
+ if (st != null)
+ {
+ featureGroups.put(toset[i], new Boolean(visible));
+ rdrw = rdrw || (visible != ((Boolean) st).booleanValue());
+ }
+ }
+ if (rdrw)
+ {
+ if (this.av != null)
+ if (this.av.featureSettings != null)
+ {
+ av.featureSettings.rebuildGroups();
+ this.av.featureSettings.resetTable(true);
+ }
+ else
+ {
+ buildFeatureHash();
+ }
+ if (av != null)
+ {
+ av.alignmentChanged(null);
+ }
+ }
+ }
+ }
+
+ /**
+ * analyse alignment for groups and hash tables (used to be embedded in
+ * FeatureSettings.setTableData)
+ *
+ * @return true if features are on the alignment
+ */
+ public boolean buildGroupHash()
+ {
+ boolean alignmentHasFeatures = false;
+ if (featureGroups == null)
+ {
+ featureGroups = new Hashtable();
+ }
+ Vector allFeatures = new Vector();
+ Vector allGroups = new Vector();
+ SequenceFeature[] tmpfeatures;
+ String group;
+ for (int i = 0; i < av.alignment.getHeight(); i++)
+ {
+ if (av.alignment.getSequenceAt(i).getSequenceFeatures() == null)
+ {
+ continue;
+ }
+
+ alignmentHasFeatures = true;
+
+ tmpfeatures = av.alignment.getSequenceAt(i).getSequenceFeatures();
+ int index = 0;
+ while (index < tmpfeatures.length)
+ {
+ if (tmpfeatures[index].getFeatureGroup() != null)
+ {
+ group = tmpfeatures[index].featureGroup;
+ if (!allGroups.contains(group))
+ {
+ allGroups.addElement(group);
+
+ boolean visible = true;
+ if (featureGroups.containsKey(group))
+ {
+ visible = ((Boolean) featureGroups.get(group)).booleanValue();
+ }
+ else
+ {
+ featureGroups.put(group, new Boolean(visible));
+ }
+ }
+ }
+
+ if (!allFeatures.contains(tmpfeatures[index].getType()))
+ {
+ allFeatures.addElement(tmpfeatures[index].getType());
+ }
+ index++;
+ }
+ }
+
+ return alignmentHasFeatures;
+ }
+
+ /**
+ * rebuild the featuresDisplayed and renderorder list based on the
+ * featureGroups hash and any existing display state and force a repaint if
+ * necessary
+ *
+ * @return true if alignment has visible features
+ */
+ public boolean buildFeatureHash()