+
+ /**
+ * @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]);
+ featureGroups.put(toset[i], new Boolean(visible));
+ if (st != null)
+ {
+ 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);
+ }
+ }
+ }
+ }
+
+ ArrayList<String> hiddenGroups = new ArrayList<String>();
+
+ /**
+ * 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();
+ }
+ hiddenGroups = new ArrayList<String>();
+ hiddenGroups.addAll(featureGroups.keySet());
+ ArrayList allFeatures = new ArrayList();
+ ArrayList allGroups = new ArrayList();
+ SequenceFeature[] tmpfeatures;
+ String group;
+ AlignmentI alignment = av.getAlignment();
+ for (int i = 0; i < alignment.getHeight(); i++)
+ {
+ if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
+ {
+ continue;
+ }
+
+ alignmentHasFeatures = true;
+
+ tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
+ int index = 0;
+ while (index < tmpfeatures.length)
+ {
+ if (tmpfeatures[index].getFeatureGroup() != null)
+ {
+ group = tmpfeatures[index].featureGroup;
+ // Remove group from the hiddenGroup list
+ hiddenGroups.remove(group);
+ if (!allGroups.contains(group))
+ {
+ allGroups.add(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.add(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()
+ {
+ boolean alignmentHasFeatures = false;
+ if (featureGroups == null)
+ {
+ alignmentHasFeatures = buildGroupHash();
+ }
+ if (!alignmentHasFeatures)
+ return false;
+ Hashtable fdisp = av.featuresDisplayed;
+ Vector allFeatures = new Vector();
+ SequenceFeature[] tmpfeatures;
+ String group;
+ AlignmentI alignment = av.getAlignment();
+ for (int i = 0; i < alignment.getHeight(); i++)
+ {
+ if (alignment.getSequenceAt(i).getSequenceFeatures() == null)
+ {
+ continue;
+ }
+
+ alignmentHasFeatures = true;
+
+ tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures();
+ int index = 0;
+ while (index < tmpfeatures.length)
+ {
+ boolean visible = true;
+ if (tmpfeatures[index].getFeatureGroup() != null)
+ {
+ group = tmpfeatures[index].featureGroup;
+ if (featureGroups.containsKey(group))
+ {
+ visible = ((Boolean) featureGroups.get(group)).booleanValue();
+ }
+ }
+
+ if (visible && !allFeatures.contains(tmpfeatures[index].getType()))
+ {
+ allFeatures.addElement(tmpfeatures[index].getType());
+ }
+ index++;
+ }
+ }
+ if (allFeatures.size() > 0)
+ {
+ String[] neworder = new String[allFeatures.size()];
+ int p = neworder.length - 1;
+ for (int i = renderOrder.length - 1; i >= 0; i--)
+ {
+ if (allFeatures.contains(renderOrder[i]))
+ {
+ neworder[p--] = renderOrder[i];
+ allFeatures.removeElement(renderOrder[i]);
+ }
+ else
+ {
+ av.featuresDisplayed.remove(renderOrder[i]);
+ }
+ }
+ for (int i = allFeatures.size() - 1; i > 0; i++)
+ {
+ Object e = allFeatures.elementAt(i);
+ if (e != null)
+ {
+ neworder[p--] = (String) e;
+ av.featuresDisplayed.put(e, getColour((String) e));
+ }
+ }
+ renderOrder = neworder;
+ return true;
+ }
+
+ return alignmentHasFeatures;
+ }
+
+ /**
+ *
+ * @return the displayed feature type as an array of strings
+ */
+ protected String[] getDisplayedFeatureTypes()
+ {
+ String[] typ = null;
+ synchronized (renderOrder)
+ {
+ typ = new String[renderOrder.length];
+ System.arraycopy(renderOrder, 0, typ, 0, typ.length);
+ for (int i = 0; i < typ.length; i++)
+ {
+ if (av.featuresDisplayed.get(typ[i]) == null)
+ {
+ typ[i] = null;
+ }
+ }
+ }
+ return typ;
+ }