Changeset 2407 in josm for trunk


Ignore:
Timestamp:
2009-11-08T13:38:44+01:00 (12 years ago)
Author:
jttt
Message:

Added support for referrers

Location:
trunk
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

    r2402 r2407  
    543543
    544544            newSelection.add(n);
    545             ds.setSelected(n);
    546545        } else if (!newNode) {
    547546            title = tr("Connect existing way to node");
  • trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r2357 r2407  
    3939        this.regexSearch = regexSearch;
    4040        this.tokenizer = tokenizer;
    41         childBackRefs = new CollectBackReferencesVisitor(Main.main.getCurrentDataSet());
     41        childBackRefs = new CollectBackReferencesVisitor(true);
    4242    }
    4343
     
    230230
    231231            switch (mode) {
    232                 case NONE:
    233                     return false;
    234                 case MISSING_KEY:
    235                     return osm.get(key) == null;
    236                 case ANY:
    237                     return true;
    238                 case ANY_VALUE:
    239                     return osm.get(key) != null;
    240                 case ANY_KEY:
    241                     for (String v:osm.getKeys().values()) {
    242                         if (v.equals(value))
     232            case NONE:
     233                return false;
     234            case MISSING_KEY:
     235                return osm.get(key) == null;
     236            case ANY:
     237                return true;
     238            case ANY_VALUE:
     239                return osm.get(key) != null;
     240            case ANY_KEY:
     241                for (String v:osm.getKeys().values()) {
     242                    if (v.equals(value))
     243                        return true;
     244                }
     245                return false;
     246            case EXACT:
     247                return value.equals(osm.get(key));
     248            case ANY_KEY_REGEXP:
     249                for (String v:osm.getKeys().values()) {
     250                    if (valuePattern.matcher(v).matches())
     251                        return true;
     252                }
     253                return false;
     254            case ANY_VALUE_REGEXP:
     255            case EXACT_REGEXP:
     256                for (Entry<String, String> entry:osm.entrySet()) {
     257                    if (keyPattern.matcher(entry.getKey()).matches()) {
     258                        if (mode == Mode.ANY_VALUE_REGEXP
     259                                || valuePattern.matcher(entry.getValue()).matches())
    243260                            return true;
    244261                    }
    245                     return false;
    246                 case EXACT:
    247                     return value.equals(osm.get(key));
    248                 case ANY_KEY_REGEXP:
    249                     for (String v:osm.getKeys().values()) {
    250                         if (valuePattern.matcher(v).matches())
    251                             return true;
    252                     }
    253                     return false;
    254                 case ANY_VALUE_REGEXP:
    255                 case EXACT_REGEXP:
    256                     for (Entry<String, String> entry:osm.entrySet()) {
    257                         if (keyPattern.matcher(entry.getKey()).matches()) {
    258                             if (mode == Mode.ANY_VALUE_REGEXP
    259                                     || valuePattern.matcher(entry.getValue()).matches())
    260                                 return true;
    261                         }
    262                     }
    263                     return false;
    264                 case MISSING_KEY_REGEXP:
    265                     for (String k:osm.keySet()) {
    266                         if (keyPattern.matcher(k).matches())
    267                             return false;
    268                     }
    269                     return true;
     262                }
     263                return false;
     264            case MISSING_KEY_REGEXP:
     265                for (String k:osm.keySet()) {
     266                    if (keyPattern.matcher(k).matches())
     267                        return false;
     268                }
     269                return true;
    270270            }
    271271            throw new AssertionError("Missed state");
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r2405 r2407  
    147147     *
    148148     * @return DataSet this primitive is part of.
    149      * @throws DataIntegrityProblemException when primitive is not part of any dataset
    150149     */
    151150    public DataSet getDataSet() {
     151        return dataSet;
     152    }
     153
     154    /**
     155     * Throws exception if primitive is not part of the dataset
     156     */
     157    public void checkDataset() {
    152158        if (dataSet == null)
    153             throw new DataIntegrityProblemException("Primitive must be part of the dataset");
    154         return dataSet;
     159            throw new DataIntegrityProblemException("Primitive  must be part of the dataset: " + toString());
    155160    }
    156161
     
    648653        return keys.keySet();
    649654    }
     655
     656
     657    /*------------
     658     * Referrers
     659     ------------*/
     660
     661    private Object referrers;
     662
     663
     664    /**
     665     * Add new referrer. If referrer is already included then no action is taken
     666     * @param referrer
     667     */
     668    protected void addReferrer(OsmPrimitive referrer) {
     669        // Based on methods from josm-ng
     670        if (referrers == null) {
     671            referrers = referrer;
     672        } else if (referrers instanceof OsmPrimitive) {
     673            if (referrers != referrer) {
     674                referrers = new OsmPrimitive[] { (OsmPrimitive)referrers, referrer };
     675            }
     676        } else {
     677            for (OsmPrimitive primitive:(OsmPrimitive[])referrers) {
     678                if (primitive == referrer)
     679                    return;
     680            }
     681            OsmPrimitive[] orig = (OsmPrimitive[])referrers;
     682            OsmPrimitive[] bigger = new OsmPrimitive[orig.length+1];
     683            System.arraycopy(orig, 0, bigger, 0, orig.length);
     684            bigger[orig.length] = referrer;
     685            referrers = bigger;
     686        }
     687    }
     688
     689    /**
     690     * Remove referrer. No action is taken if referrer is not registered
     691     * @param referrer
     692     */
     693    protected void removeReferrer(OsmPrimitive referrer) {
     694        // Based on methods from josm-ng
     695        if (referrers instanceof OsmPrimitive) {
     696            if (referrers == referrer) {
     697                referrers = null;
     698            }
     699        } else if (referrers instanceof OsmPrimitive[]) {
     700            OsmPrimitive[] orig = (OsmPrimitive[])referrers;
     701            int idx = -1;
     702            for (int i=0; i<orig.length; i++) {
     703                if (orig[i] == referrer) {
     704                    idx = i;
     705                    break;
     706                }
     707            }
     708            if (idx == -1)
     709                return;
     710
     711            if (orig.length == 2) {
     712                referrers = orig[1-idx]; // idx is either 0 or 1, take the other
     713            } else { // downsize the array
     714                OsmPrimitive[] smaller = new OsmPrimitive[orig.length-1];
     715                System.arraycopy(orig, 0, smaller, 0, idx);
     716                System.arraycopy(orig, idx+1, smaller, idx, smaller.length-idx);
     717                referrers = smaller;
     718            }
     719        }
     720    }
     721    /**
     722     * Find primitives that reference this primitive. Returns only primitives that are included in the same
     723     * dataset as this primitive. <br>
     724     *
     725     * For example following code will add wnew as referer to all nodes of existingWay, but this method will
     726     * not return wnew because it's not part of the dataset <br>
     727     *
     728     * <code>Way wnew = new Way(existingWay)</code>
     729     *
     730     * @return a collection of all primitives that reference this primitive.
     731     */
     732
     733    public final List<OsmPrimitive> getReferrers() {
     734        checkDataset();
     735        // Method copied from OsmPrimitive in josm-ng
     736        // Returns only referrers that are members of the same dataset (primitive can have some fake references, for example
     737        // when way is cloned
     738        if (referrers == null)
     739            return Collections.emptyList();
     740
     741        if (referrers instanceof OsmPrimitive) {
     742            if (((OsmPrimitive)referrers).dataSet == dataSet)
     743                return Collections.singletonList((OsmPrimitive)referrers);
     744            else
     745                return Collections.emptyList();
     746        }
     747
     748        List<OsmPrimitive> result = new ArrayList<OsmPrimitive>();
     749        for (OsmPrimitive o:(OsmPrimitive[])referrers) {
     750            if (dataSet == o.dataSet) {
     751                result.add(o);
     752            }
     753        }
     754
     755        return result;
     756    }
     757
    650758
    651759    /**
  • trunk/src/org/openstreetmap/josm/data/osm/Relation.java

    r2405 r2407  
    3939     */
    4040    public void setMembers(List<RelationMember> members) {
     41        for (RelationMember rm:this.members) {
     42            rm.getMember().removeReferrer(this);
     43        }
     44
    4145        this.members.clear();
    4246        if (members != null) {
    4347            this.members.addAll(members);
    4448        }
     49        for (RelationMember rm:this.members) {
     50            rm.getMember().addReferrer(this);
     51        }
     52
    4553    }
    4654
     
    7078    public void addMember(RelationMember member) {
    7179        members.add(member);
     80        member.getMember().addReferrer(this);
    7281    }
    7382
     
    8089    public void addMember(int index, RelationMember member) {
    8190        members.add(index, member);
     91        member.getMember().addReferrer(this);
    8292    }
    8393
     
    90100     */
    91101    public RelationMember setMember(int index, RelationMember member) {
    92         return members.set(index, member);
     102        RelationMember result = members.set(index, member);
     103        if (result.getMember() != member.getMember()) {
     104            member.getMember().addReferrer(this);
     105            result.getMember().removeReferrer(this);
     106        }
     107        return result;
    93108    }
    94109
     
    100115     */
    101116    public RelationMember removeMember(int index) {
    102         return members.remove(index);
     117        RelationMember result = members.remove(index);
     118        for (RelationMember rm:members) {
     119            // Do not remove referrer if this primitive is used in relation twice
     120            if (rm.getMember() == result.getMember())
     121                return result;
     122        }
     123        result.getMember().removeReferrer(this);
     124        return result;
    103125    }
    104126
     
    139161    @Override public void cloneFrom(OsmPrimitive osm) {
    140162        super.cloneFrom(osm);
    141         members.clear();
    142         // we must not add the members themselves, but instead
    143         // add clones of the members
    144         for (RelationMember em : ((Relation)osm).getMembers()) {
    145             members.add(new RelationMember(em));
    146         }
     163        // It's not necessary to clone members as RelationMember class is immutable
     164        setMembers(((Relation)osm).getMembers());
    147165    }
    148166
     
    236254            }
    237255        }
     256        primitive.removeReferrer(this);
    238257        members.removeAll(todelete);
    239258    }
     259
     260    @Override
     261    public void setDeleted(boolean deleted) {
     262        for (RelationMember rm:members) {
     263            if (deleted) {
     264                rm.getMember().removeReferrer(this);
     265            } else {
     266                rm.getMember().addReferrer(this);
     267            }
     268        }
     269        super.setDeleted(deleted);
     270    }
     271
    240272
    241273    /**
     
    255287        }
    256288        members.removeAll(todelete);
     289        for (OsmPrimitive primitive:primitives) {
     290            primitive.removeReferrer(this);
     291        }
    257292    }
    258293
  • trunk/src/org/openstreetmap/josm/data/osm/Way.java

    r2405 r2407  
    4545     */
    4646    public void setNodes(List<Node> nodes) {
     47        for (Node node:this.nodes) {
     48            node.removeReferrer(this);
     49        }
     50
    4751        if (nodes == null) {
    4852            this.nodes = new Node[0];
     
    5054            this.nodes = nodes.toArray(new Node[nodes.size()]);
    5155        }
     56        for (Node node:this.nodes) {
     57            node.addReferrer(this);
     58        }
     59
    5260        clearCached();
    5361    }
     
    194202        super.cloneFrom(osm);
    195203        Way otherWay = (Way)osm;
    196         nodes = new Node[otherWay.nodes.length];
    197         System.arraycopy(otherWay.nodes, 0, nodes, 0, otherWay.nodes.length);
     204        setNodes(otherWay.getNodes());
    198205    }
    199206
     
    229236        i = copy.size();
    230237        if (closed && i > 2) {
     238            // TODO Should this be copy.addNode(firstNode)?
    231239            addNode(firstNode());
    232240        } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
     
    257265            throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
    258266        clearCached();
     267        n.addReferrer(this);
    259268        Node[] newNodes = new Node[nodes.length + 1];
    260269        System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
     
    277286            throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
    278287        clearCached();
     288        n.addReferrer(this);
    279289        Node[] newNodes = new Node[nodes.length + 1];
    280290        System.arraycopy(nodes, 0, newNodes, 0, offs);
     
    284294    }
    285295
     296    @Override
     297    public void setDeleted(boolean deleted) {
     298        for (Node n:nodes) {
     299            if (deleted) {
     300                n.removeReferrer(this);
     301            } else {
     302                n.addReferrer(this);
     303            }
     304        }
     305        super.setDeleted(deleted);
     306    }
     307
     308
    286309    public boolean isClosed() {
    287310        if (incomplete) return false;
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/CollectBackReferencesVisitor.java

    r2381 r2407  
    44import java.util.Collection;
    55import java.util.HashSet;
    6 import java.util.HashMap;
    7 import java.util.Map;
    86
    97import org.openstreetmap.josm.data.osm.DataSet;
     
    119import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1210import org.openstreetmap.josm.data.osm.Relation;
    13 import org.openstreetmap.josm.data.osm.RelationMember;
    1411import org.openstreetmap.josm.data.osm.Way;
    1512
     
    2320public class CollectBackReferencesVisitor extends AbstractVisitor {
    2421
    25     private final DataSet ds;
    2622    private final boolean indirectRefs;
    2723
    2824    private Collection<OsmPrimitive> data = new HashSet<OsmPrimitive>();
    29     private Map<OsmPrimitive, Collection<OsmPrimitive>> lookupTable = new HashMap<OsmPrimitive, Collection<OsmPrimitive>>();
    3025
    3126
    3227    /**
    33      * Construct a back reference counter.
    34      * has time complexity O(n) - so it is appropriate not to call it in cycle
    35      * @param ds The dataset to operate on.
     28     * @param ds This parameter is ignored
    3629     */
    3730    public CollectBackReferencesVisitor(DataSet ds) {
    38        this(ds, true);
     31        this(true);
    3932    }
    4033
    4134    /**
    42      * Construct a back reference counter.
    43      * has time complexity O(n) - so it is appropriate not to call it in cycle
    44      * @param ds The dataset to operate on.
     35     * @param ds This parameter is ignored
    4536     * @param indirectRefs Make also indirect references?
    4637     */
    4738    public CollectBackReferencesVisitor(DataSet ds, boolean indirectRefs) {
    48        this.ds = ds;
    49        this.indirectRefs = indirectRefs;
    50        if(ds != null)
    51           makeLookupTable();
     39        this.indirectRefs = indirectRefs;
    5240    }
    53    
    54     private void makeLookupTable() {
    55         for (Way w : ds.getWays()) {
    56             for (Node n : w.getNodes()) {
    57                 if (!lookupTable.containsKey(n)) lookupTable.put(n, new HashSet<OsmPrimitive>());
    58                 lookupTable.get(n).add(w);
    59             }
    60         }
    61         for (Relation r : ds.getRelations()) {
    62             for (RelationMember m : r.getMembers()) {
    63                 OsmPrimitive o = m.getMember();
    64                 if (!lookupTable.containsKey(o)) lookupTable.put(o, new HashSet<OsmPrimitive>());
    65                 lookupTable.get(o).add(r);
    66             }
    67         }
     41
     42    public CollectBackReferencesVisitor(boolean indirectRefs) {
     43        this.indirectRefs = indirectRefs;
    6844    }
     45
    6946
    7047    /**
     
    7249     */
    7350    public Collection<OsmPrimitive> getData(){
    74        return data;
     51        return data;
    7552    }
    7653
    7754    /**
    78      * Initialize data before associated visit calls 
     55     * Initialize data before associated visit calls
    7956     */
    8057    public void initialize(){
    81        data = new HashSet<OsmPrimitive>();
     58        data = new HashSet<OsmPrimitive>();
    8259    }
    8360
    8461    public void visit(OsmPrimitive o) {
    85        if(lookupTable.containsKey(o)){
    86           Collection<OsmPrimitive> c = lookupTable.get(o);
    87           Collection<OsmPrimitive> oldData = new HashSet<OsmPrimitive>(data);
    88           data.addAll(c);
    89           if(indirectRefs)
    90              for(OsmPrimitive oo : c)
    91                 if(!oldData.contains(oo))
    92                    visit(oo);
    93        }
     62        Collection<OsmPrimitive> c = o.getReferrers();
     63        Collection<OsmPrimitive> oldData = new HashSet<OsmPrimitive>(data);
     64        data.addAll(c);
     65        if(indirectRefs) {
     66            for(OsmPrimitive oo : c)
     67                if(!oldData.contains(oo)) {
     68                    visit(oo);
     69                }
     70        }
     71
    9472    }
    95    
     73
    9674    public void visit(Node n) {
    97        visit((OsmPrimitive)n);
     75        visit((OsmPrimitive)n);
    9876    }
    9977
    10078    public void visit(Way w) {
    101        visit((OsmPrimitive)w);
     79        visit((OsmPrimitive)w);
    10280    }
    10381
    10482    public void visit(Relation r) {
    105        visit((OsmPrimitive)r);
     83        visit((OsmPrimitive)r);
    10684    }
    10785}
Note: See TracChangeset for help on using the changeset viewer.