X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fdatamodel%2Ffeatures%2FFeatureStore.java;h=4e70dda2bc5bec6b8c538ae7b5b190bf50eddd3a;hb=b546da446212452cf85d78b5052a7a8aef2dd2f5;hp=f7757be4af2e45900c3febf034646b53408c3312;hpb=30355a6f53c842429f4ca2e31f60a7c5de167f1a;p=jalview.git diff --git a/src/jalview/datamodel/features/FeatureStore.java b/src/jalview/datamodel/features/FeatureStore.java index f7757be..4e70dda 100644 --- a/src/jalview/datamodel/features/FeatureStore.java +++ b/src/jalview/datamodel/features/FeatureStore.java @@ -23,6 +23,7 @@ public class FeatureStore /* * Non-positional features have no (zero) start/end position. + * Kept as a separate list in case this criterion changes in future. */ List nonPositionalFeatures; @@ -59,66 +60,84 @@ public class FeatureStore public FeatureStore() { nonNestedFeatures = new ArrayList(); - // we only construct contactFeatures and the NCList if we need to + // we only construct nonPositionalFeatures, contactFeatures + // or the NCList if we need to } /** - * Add one entry to the data store + * Adds one sequence feature to the store, and returns true, unless the + * feature is already contained in the store, in which case this method + * returns false. Containment is determined by SequenceFeature.equals() + * comparison. * * @param feature */ - public void addFeature(SequenceFeature feature) + public boolean addFeature(SequenceFeature feature) { + boolean added = false; + if (feature.isContactFeature()) { - addContactFeature(feature); + added = addContactFeature(feature); } else if (feature.isNonPositional()) { - addNonPositionalFeature(feature); + added = addNonPositionalFeature(feature); } else { - boolean added = addNonNestedFeature(feature); - if (!added) + if (!nonNestedFeatures.contains(feature)) { - /* - * detected a nested feature - put it in the NCList structure - */ - addNestedFeature(feature); + added = addNonNestedFeature(feature); + if (!added) + { + /* + * detected a nested feature - put it in the NCList structure + */ + added = addNestedFeature(feature); + } } } + + return added; } /** * Adds the feature to the list of non-positional features (with lazy - * instantiation of the list if it is null) + * instantiation of the list if it is null), and returns true. If the + * non-positional features already include the new feature (by equality test), + * then it is not added, and this method returns false. * * @param feature */ - protected void addNonPositionalFeature(SequenceFeature feature) + protected boolean addNonPositionalFeature(SequenceFeature feature) { if (nonPositionalFeatures == null) { nonPositionalFeatures = new ArrayList(); } + if (nonPositionalFeatures.contains(feature)) + { + return false; + } nonPositionalFeatures.add(feature); + return true; } /** * Adds one feature to the NCList that can manage nested features (creating - * the NCList if necessary) + * the NCList if necessary), and returns true. If the feature is already + * stored in the NCList (by equality test), then it is not added, and this + * method returns false. */ - protected synchronized void addNestedFeature(SequenceFeature feature) + protected synchronized boolean addNestedFeature(SequenceFeature feature) { if (nestedFeatures == null) { nestedFeatures = new NCList(feature); + return true; } - else - { - nestedFeatures.add(feature); - } + return nestedFeatures.add(feature, false); } /** @@ -225,13 +244,14 @@ public class FeatureStore /** * Add a contact feature to the lists that hold them ordered by start (first * contact) and by end (second contact) position, ensuring the lists remain - * ordered + * ordered, and returns true. If the contact feature lists already contain the + * given feature (by test for equality), does not add it and returns false. * * @param feature + * @return */ - protected synchronized void addContactFeature(SequenceFeature feature) + protected synchronized boolean addContactFeature(SequenceFeature feature) { - // TODO binary search for insertion points! if (contactFeatureStarts == null) { contactFeatureStarts = new ArrayList(); @@ -240,10 +260,19 @@ public class FeatureStore { contactFeatureEnds = new ArrayList(); } + + // TODO binary search for insertion points! + if (contactFeatureStarts.contains(feature)) + { + return false; + } + contactFeatureStarts.add(feature); Collections.sort(contactFeatureStarts, startOrdering); contactFeatureEnds.add(feature); Collections.sort(contactFeatureEnds, endOrdering); + + return true; } /** @@ -534,4 +563,68 @@ public class FeatureStore } return new ArrayList(nonPositionalFeatures); } + + /** + * Deletes the given feature from the store, returning true if it was found + * (and deleted), else false. This method makes no assumption that the feature + * is in the 'expected' place in the store, in case it has been modified since + * it was added. + * + * @param sf + */ + public boolean delete(SequenceFeature sf) + { + /* + * try the non-nested positional features first + */ + boolean removed = nonNestedFeatures.remove(sf); + + /* + * if not found, try contact positions (and if found, delete + * from both lists of contact positions) + */ + if (!removed && contactFeatureStarts != null) + { + removed = contactFeatureStarts.remove(sf); + if (removed) + { + contactFeatureEnds.remove(sf); + } + } + + /* + * if not found, try non-positional features + */ + if (!removed && nonPositionalFeatures != null) + { + removed = nonPositionalFeatures.remove(sf); + } + + /* + * if not found, try nested features + */ + if (!removed && nestedFeatures != null) + { + removed = nestedFeatures.delete(sf); + } + + return removed; + } + + /** + * Answers true if this store has no features, else false + * + * @return + */ + public boolean isEmpty() + { + boolean hasFeatures = !nonNestedFeatures.isEmpty() + || (contactFeatureStarts != null && !contactFeatureStarts + .isEmpty()) + || (nonPositionalFeatures != null && !nonPositionalFeatures + .isEmpty()) + || (nestedFeatures != null && nestedFeatures.size() > 0); + + return !hasFeatures; + } }