Changeset 2305 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2009-10-24T21:22:49+02:00 (15 years ago)
Author:
jttt
Message:

Use PrimitiveData for Copy, Paste and Paste tags actions

Location:
trunk/src/org/openstreetmap/josm
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/Main.java

    r2274 r2305  
    3939import org.openstreetmap.josm.data.coor.CoordinateFormat;
    4040import org.openstreetmap.josm.data.osm.DataSet;
    41 import org.openstreetmap.josm.data.projection.Mercator;
     41import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    4242import org.openstreetmap.josm.data.projection.Projection;
    4343import org.openstreetmap.josm.gui.GettingStarted;
     
    8989     * The global paste buffer.
    9090     */
    91     public static DataSet pasteBuffer = new DataSet();
     91    public static PrimitiveDeepCopy pasteBuffer = new PrimitiveDeepCopy();
    9292    public static Layer pasteSource;
    9393    /**
     
    377377    /**
    378378     * Run any cleanup operation before exit
    379      * 
     379     *
    380380     */
    381381    public static  void cleanupBeforeExit() {
  • trunk/src/org/openstreetmap/josm/actions/CopyAction.java

    r2283 r2305  
    77import java.awt.event.ActionEvent;
    88import java.awt.event.KeyEvent;
    9 import java.util.ArrayList;
    109import java.util.Collection;
    11 import java.util.HashMap;
    1210import java.util.LinkedList;
    13 import java.util.List;
    1411
    1512import javax.swing.JOptionPane;
    1613
    1714import org.openstreetmap.josm.Main;
    18 import org.openstreetmap.josm.data.osm.DataSet;
    19 import org.openstreetmap.josm.data.osm.Node;
    2015import org.openstreetmap.josm.data.osm.OsmPrimitive;
    21 import org.openstreetmap.josm.data.osm.Relation;
    22 import org.openstreetmap.josm.data.osm.RelationMember;
    23 import org.openstreetmap.josm.data.osm.Way;
    24 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
    2516import org.openstreetmap.josm.tools.Shortcut;
    2617
     
    4334        if(isEmptySelection()) return;
    4435
    45         Main.pasteBuffer = copyData();
     36        Main.pasteBuffer.makeCopy(getCurrentDataSet().getSelected());
    4637        Main.pasteSource = getEditLayer();
    4738        Main.main.menu.paste.setEnabled(true); /* now we have a paste buffer we can make paste available */
     
    5041            a.pasteBufferChanged(Main.pasteBuffer);
    5142        }
    52     }
    53 
    54     public DataSet copyData() {
    55         /* New pasteBuffer - will be assigned to the global one at the end */
    56         final DataSet pasteBuffer = new DataSet();
    57         final HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
    58         /* temporarily maps old nodes to new so we can do a true deep copy */
    59 
    60         if(isEmptySelection()) return pasteBuffer;
    61 
    62         /* scan the selected objects, mapping them to copies; when copying a way or relation,
    63          * the copy references the copies of their child objects */
    64         new AbstractVisitor() {
    65             public void visit(Node n) {
    66                 /* check if already in pasteBuffer - e.g. two ways are selected which share a node;
    67                  * or a way and a node in that way is selected, we'll see it twice, once via the
    68                  * way and once directly; and so on. */
    69                 if (map.containsKey(n))
    70                     return;
    71                 Node nnew = new Node(n);
    72                 map.put(n, nnew);
    73                 pasteBuffer.addPrimitive(nnew);
    74             }
    75             public void visit(Way w) {
    76                 /* check if already in pasteBuffer - could have come from a relation, and directly etc. */
    77                 if (map.containsKey(w))
    78                     return;
    79                 Way wnew = new Way();
    80                 wnew.cloneFrom(w);
    81                 map.put(w, wnew);
    82                 List<Node> nodes = new ArrayList<Node>();
    83                 for (Node n : w.getNodes()) {
    84                     if (! map.containsKey(n)) {
    85                         n.visit(this);
    86                     }
    87                     nodes.add((Node)map.get(n));
    88                 }
    89                 wnew.setNodes(nodes);
    90                 pasteBuffer.addPrimitive(wnew);
    91             }
    92             public void visit(Relation e) {
    93                 if (map.containsKey(e))
    94                     return;
    95                 Relation enew = new Relation(e);
    96                 map.put(e, enew);
    97                 List<RelationMember> members = new ArrayList<RelationMember>();
    98                 for (RelationMember m : e.getMembers()) {
    99                     if (! map.containsKey(m.getMember())) {
    100                         m.getMember().visit(this);
    101                     }
    102                     RelationMember mnew = new RelationMember(m.getRole(), map.get(m.getMember()));
    103                     members.add(mnew);
    104                 }
    105                 enew.setMembers(members);
    106                 pasteBuffer.addPrimitive(enew);
    107             }
    108             public void visitAll() {
    109                 for (OsmPrimitive osm : getCurrentDataSet().getSelected()) {
    110                     osm.visit(this);
    111                 }
    112             }
    113         }.visitAll();
    114 
    115         return pasteBuffer;
    11643    }
    11744
  • trunk/src/org/openstreetmap/josm/actions/DuplicateAction.java

    r2256 r2305  
    1010
    1111import org.openstreetmap.josm.data.osm.OsmPrimitive;
     12import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    1213import org.openstreetmap.josm.tools.Shortcut;
    1314
     
    2122
    2223    public void actionPerformed(ActionEvent e) {
    23         new PasteAction().pasteData(new CopyAction().copyData(), getEditLayer(), e);
     24        new PasteAction().pasteData(new PrimitiveDeepCopy(getCurrentDataSet().getSelected()), getEditLayer(), e);
    2425    }
    2526
  • trunk/src/org/openstreetmap/josm/actions/JosmAction.java

    r2260 r2305  
    1313import org.openstreetmap.josm.data.osm.DataSet;
    1414import org.openstreetmap.josm.data.osm.OsmPrimitive;
     15import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    1516import org.openstreetmap.josm.gui.layer.Layer;
    1617import org.openstreetmap.josm.gui.layer.OsmDataLayer;
     
    2223/**
    2324 * Base class helper for all Actions in JOSM. Just to make the life easier.
    24  * 
     25 *
    2526 * A JosmAction is a {@see LayerChangeListener} and a {@see SelectionChangedListener}. Upon
    2627 * a layer change event or a selection change event it invokes {@see #updateEnabled()}.
     
    2829 * of a JosmAction depending on the {@see #getCurrentDataSet()} and the current layers
    2930 * (see also {@see #getEditLayer()}).
    30  * 
     31 *
    3132 * destroy() from interface Destroyable is called e.g. for MapModes, when the last layer has
    3233 * been removed and so the mapframe will be destroyed. For other JosmActions, destroy() may never
     
    105106     * needs to be overridden to be useful
    106107     */
    107     public void pasteBufferChanged(DataSet newPasteBuffer) {
     108    public void pasteBufferChanged(PrimitiveDeepCopy newPasteBuffer) {
    108109        return;
    109110    }
     
    126127    /**
    127128     * Replies the current edit layer
    128      * 
     129     *
    129130     * @return the current edit layer. null, if no edit layer exists
    130131     */
     
    135136    /**
    136137     * Replies the current dataset
    137      * 
     138     *
    138139     * @return the current dataset. null, if no current dataset exists
    139140     */
     
    155156     * Override in subclasses to init the enabled state of an action when it is
    156157     * created. Default behaviour is to call {@see #updateEnabledState()}
    157      * 
     158     *
    158159     * @see #updateEnabledState()
    159160     * @see #updateEnabledState(Collection)
     
    166167     * Override in subclasses to update the enabled state of the action when
    167168     * something in the JOSM state changes, i.e. when a layer is removed or added.
    168      * 
     169     *
    169170     * See {@see #updateEnabledState(Collection)} to respond to changes in the collection
    170171     * of selected primitives.
    171      * 
     172     *
    172173     * Default behavior is empty.
    173      * 
     174     *
    174175     * @see #updateEnabledState(Collection)
    175176     * @see #initEnabledState()
     
    183184     * new selection. Avoid calling getCurrentDataSet().getSelected() because this
    184185     * loops over the complete data set.
    185      * 
     186     *
    186187     * @param selection the collection of selected primitives
    187      * 
     188     *
    188189     * @see #updateEnabledState()
    189190     * @see #initEnabledState()
  • trunk/src/org/openstreetmap/josm/actions/MoveAction.java

    r2256 r2305  
    8181                disty = 0;
    8282                distx = -distx;
     83                break;
    8384            default:
    8485                disty = 0;
  • trunk/src/org/openstreetmap/josm/actions/PasteAction.java

    r2070 r2305  
    88import java.awt.event.KeyEvent;
    99import java.util.ArrayList;
    10 import java.util.Collection;
    1110import java.util.HashMap;
    12 import java.util.LinkedList;
    1311import java.util.List;
     12import java.util.ListIterator;
     13import java.util.Map;
    1414
    1515import org.openstreetmap.josm.Main;
    16 import org.openstreetmap.josm.command.AddCommand;
    17 import org.openstreetmap.josm.command.Command;
    18 import org.openstreetmap.josm.command.SequenceCommand;
     16import org.openstreetmap.josm.command.AddPrimitivesCommand;
    1917import org.openstreetmap.josm.data.coor.EastNorth;
    20 import org.openstreetmap.josm.data.osm.DataSet;
    21 import org.openstreetmap.josm.data.osm.Node;
    22 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    23 import org.openstreetmap.josm.data.osm.Relation;
    24 import org.openstreetmap.josm.data.osm.RelationMember;
    25 import org.openstreetmap.josm.data.osm.Way;
     18import org.openstreetmap.josm.data.osm.NodeData;
     19import org.openstreetmap.josm.data.osm.PrimitiveData;
     20import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
     21import org.openstreetmap.josm.data.osm.RelationData;
     22import org.openstreetmap.josm.data.osm.RelationMemberData;
     23import org.openstreetmap.josm.data.osm.WayData;
    2624import org.openstreetmap.josm.gui.layer.Layer;
    2725import org.openstreetmap.josm.tools.Shortcut;
     
    4038    }
    4139
    42     public  void pasteData(DataSet pasteBuffer, Layer source, ActionEvent e) {
     40    public  void pasteData(PrimitiveDeepCopy pasteBuffer, Layer source, ActionEvent e) {
    4341        /* Find the middle of the pasteBuffer area */
    4442        double maxEast = -1E100, minEast = 1E100, maxNorth = -1E100, minNorth = 1E100;
    45         for (Node n : pasteBuffer.nodes) {
    46             double east = n.getEastNorth().east();
    47             double north = n.getEastNorth().north();
    48             if (east > maxEast) { maxEast = east; }
    49             if (east < minEast) { minEast = east; }
    50             if (north > maxNorth) { maxNorth = north; }
    51             if (north < minNorth) { minNorth = north; }
     43        for (PrimitiveData data : pasteBuffer.getAll()) {
     44            if (data instanceof NodeData) {
     45                NodeData n = (NodeData)data;
     46                double east = n.getEastNorth().east();
     47                double north = n.getEastNorth().north();
     48                if (east > maxEast) { maxEast = east; }
     49                if (east < minEast) { minEast = east; }
     50                if (north > maxNorth) { maxNorth = north; }
     51                if (north < minNorth) { minNorth = north; }
     52            }
    5253        }
    5354
     
    6364        double offsetNorth = mPosition.north() - (maxNorth + minNorth)/2.0;
    6465
    65         HashMap<OsmPrimitive,OsmPrimitive> map = new HashMap<OsmPrimitive,OsmPrimitive>();
    66         /* temporarily maps old nodes to new so we can do a true deep copy */
    6766
    68         /* do the deep copy of the paste buffer contents, leaving the pasteBuffer unchanged */
    69         for (Node n : pasteBuffer.nodes) {
    70             Node nnew = new Node(n);
    71             nnew.clearOsmId();
    72             if (Main.map.mapView.getEditLayer() == source) {
    73                 nnew.setEastNorth(nnew.getEastNorth().add(offsetEast, offsetNorth));
    74             }
    75             map.put(n, nnew);
     67
     68        // Make a copy of pasteBuffer and map from old id to copied data id
     69        List<PrimitiveData> bufferCopy = new ArrayList<PrimitiveData>();
     70        Map<Long, Long> newIds = new HashMap<Long, Long>();
     71        for (PrimitiveData data:pasteBuffer.getAll()) {
     72            PrimitiveData copy = data.makeCopy();
     73            copy.clearOsmId();
     74            newIds.put(data.getId(), copy.getId());
     75            bufferCopy.add(copy);
    7676        }
    77         for (Way w : pasteBuffer.ways) {
    78             Way wnew = new Way();
    79             wnew.cloneFrom(w);
    80             wnew.clearOsmId();
    81             /* make sure we reference the new nodes corresponding to the old ones */
    82             List<Node> nodes = new ArrayList<Node>();
    83             for (Node n : w.getNodes()) {
    84                 nodes.add((Node)map.get(n));
    85             }
    86             wnew.setNodes(nodes);
    87             map.put(w, wnew);
    88         }
    89         for (Relation r : pasteBuffer.relations) {
    90             Relation rnew = new Relation(r);
    91             r.clearOsmId();
    92             List<RelationMember> members = new ArrayList<RelationMember>();
    93             for (RelationMember m : r.getMembers()) {
    94                 OsmPrimitive mo = map.get(m.getMember());
    95                 if(mo != null) /* FIXME - This only prevents illegal data, but kills the relation */
    96                 {
    97                     RelationMember mnew = new RelationMember(m.getRole(), map.get(m.getMember()));
    98                     members.add(mnew);
     77
     78        // Update references in copied buffer
     79        for (PrimitiveData data:bufferCopy) {
     80            if (data instanceof NodeData) {
     81                NodeData nodeData = (NodeData)data;
     82                if (Main.map.mapView.getEditLayer() == source) {
     83                    nodeData.setEastNorth(nodeData.getEastNorth().add(offsetEast, offsetNorth));
     84                }
     85            } else if (data instanceof WayData) {
     86                ListIterator<Long> it = ((WayData)data).getNodes().listIterator();
     87                while (it.hasNext()) {
     88                    it.set(newIds.get(it.next()));
     89                }
     90            } else if (data instanceof RelationData) {
     91                ListIterator<RelationMemberData> it = ((RelationData)data).getMembers().listIterator();
     92                while (it.hasNext()) {
     93                    RelationMemberData member = it.next();
     94                    it.set(new RelationMemberData(member.getRole(), member.getMemberType(), newIds.get(member.getMemberId())));
    9995                }
    10096            }
    101             rnew.setMembers(members);
    102             map.put(r, rnew);
    10397        }
    10498
    105         /* Now execute the commands to add the dupicated contents of the paste buffer to the map */
    106         Collection<OsmPrimitive> osms = map.values();
    107         Collection<Command> clist = new LinkedList<Command>();
    108         for (OsmPrimitive osm : osms) {
    109             clist.add(new AddCommand(osm));
    110         }
     99        /* Now execute the commands to add the duplicated contents of the paste buffer to the map */
    111100
    112         Main.main.undoRedo.add(new SequenceCommand(tr("Paste"), clist));
    113         getCurrentDataSet().setSelected(osms);
     101        Main.main.undoRedo.add(new AddPrimitivesCommand(bufferCopy));
     102        //getCurrentDataSet().setSelected(osms);
    114103        Main.map.mapView.repaint();
    115104    }
     
    121110            return;
    122111        }
    123         setEnabled(
    124                 !Main.pasteBuffer.nodes.isEmpty()
    125                 || !Main.pasteBuffer.ways.isEmpty()
    126                 || !Main.pasteBuffer.relations.isEmpty()
    127         );
     112        setEnabled(!Main.pasteBuffer.isEmpty());
    128113    }
    129114}
  • trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java

    r2256 r2305  
    1818import org.openstreetmap.josm.command.Command;
    1919import org.openstreetmap.josm.command.SequenceCommand;
    20 import org.openstreetmap.josm.data.osm.DataSet;
    21 import org.openstreetmap.josm.data.osm.Node;
    2220import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2321import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    24 import org.openstreetmap.josm.data.osm.Relation;
     22import org.openstreetmap.josm.data.osm.PrimitiveData;
     23import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
    2524import org.openstreetmap.josm.data.osm.TagCollection;
    26 import org.openstreetmap.josm.data.osm.Way;
    2725import org.openstreetmap.josm.gui.conflict.tags.PasteTagsConflictResolverDialog;
    2826import org.openstreetmap.josm.tools.Shortcut;
     
    3735    }
    3836
    39     static private List<Class<? extends OsmPrimitive>> osmPrimitiveClasses;
    40     static {
    41         osmPrimitiveClasses = new ArrayList<Class<? extends OsmPrimitive>>();
    42         osmPrimitiveClasses.add(Node.class);
    43         osmPrimitiveClasses.add(Way.class);
    44         osmPrimitiveClasses.add(Relation.class);
    45     }
    46 
    47     /**
    48      * Replies true if the source for tag pasting is heterogeneous, i.e. if it doesn't consist of
    49      * {@see OsmPrimitive}s of exactly one type
    50      *
    51      * @return
    52      */
    53     protected boolean isHeteogeneousSource() {
    54         int count = 0;
    55         count = !getSourcePrimitivesByType(Node.class).isEmpty() ? count + 1 : count;
    56         count = !getSourcePrimitivesByType(Way.class).isEmpty() ? count + 1 : count;
    57         count = !getSourcePrimitivesByType(Relation.class).isEmpty() ? count + 1 : count;
    58         return count > 1;
    59     }
    60 
    61     /**
    62      * Replies all primitives of type <code>type</code> in the current selection.
    63      *
    64      * @param <T>
    65      * @param type  the type
    66      * @return all primitives of type <code>type</code> in the current selection.
    67      */
    68     protected <T extends OsmPrimitive> Collection<? extends OsmPrimitive> getSourcePrimitivesByType(Class<T> type) {
    69         return OsmPrimitive.getFilteredList(Main.pasteBuffer.getSelected(), type);
    70     }
    71 
    72     /**
    73      * Replies the collection of tags for all primitives of type <code>type</code> in the current
    74      * selection
    75      *
    76      * @param <T>
    77      * @param type  the type
    78      * @return the collection of tags for all primitives of type <code>type</code> in the current
    79      * selection
    80      */
    81     protected <T extends OsmPrimitive> TagCollection getSourceTagsByType(Class<T> type) {
    82         return TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(type));
    83     }
    84 
    85     /**
    86      * Replies true if there is at least one tag in the current selection for primitives of
    87      * type <code>type</code>
    88      *
    89      * @param <T>
    90      * @param type the type
    91      * @return true if there is at least one tag in the current selection for primitives of
    92      * type <code>type</code>
    93      */
    94     protected <T extends OsmPrimitive> boolean hasSourceTagsByType(Class<T> type) {
    95         return ! getSourceTagsByType(type).isEmpty();
    96     }
    97 
    98     protected Command buildChangeCommand(Collection<? extends OsmPrimitive> selection, TagCollection tc) {
    99         List<Command> commands = new ArrayList<Command>();
    100         for (String key : tc.getKeys()) {
    101             String value = tc.getValues(key).iterator().next();
    102             value = value.equals("") ? null : value;
    103             commands.add(new ChangePropertyCommand(selection,key,value));
    104         }
    105         if (!commands.isEmpty()) {
    106             String title1 = trn("Pasting {0} tag", "Pasting {0} tags", tc.getKeys().size(), tc.getKeys().size());
    107             String title2 = trn("to {0} primitive", "to {0} primtives", selection.size(), selection.size());
    108             return new SequenceCommand(
    109                     title1 + " " + title2,
    110                     commands
    111             );
    112         }
    113         return null;
    114     }
    115 
    116     protected Map<OsmPrimitiveType, Integer> getSourceStatistics() {
    117         HashMap<OsmPrimitiveType, Integer> ret = new HashMap<OsmPrimitiveType, Integer>();
    118         for (Class<? extends OsmPrimitive> type: osmPrimitiveClasses) {
    119             if (!getSourceTagsByType(type).isEmpty()) {
    120                 ret.put(OsmPrimitiveType.from(type), getSourcePrimitivesByType(type).size());
    121             }
    122         }
    123         return ret;
    124     }
    125 
    126     protected Map<OsmPrimitiveType, Integer> getTargetStatistics() {
    127         HashMap<OsmPrimitiveType, Integer> ret = new HashMap<OsmPrimitiveType, Integer>();
    128         for (Class<? extends OsmPrimitive> type: osmPrimitiveClasses) {
    129             int count = OsmPrimitive.getFilteredList(getEditLayer().data.getSelected(), type).size();
    130             if (count > 0) {
    131                 ret.put(OsmPrimitiveType.from(type), count);
    132             }
    133         }
    134         return ret;
    135     }
    136 
    137     /**
    138      * Pastes the tags from a homogeneous source (i.e. the {@see Main#pasteBuffer}s selection consisting
    139      * of one type of {@see OsmPrimitive}s only.
    140      *
    141      * Tags from a homogeneous source can be pasted to a heterogeneous target. All target primitives,
    142      * regardless of their type, receive the same tags.
    143      *
    144      * @param targets the collection of target primitives
    145      */
    146     protected void pasteFromHomogeneousSource(Collection<? extends OsmPrimitive> targets) {
    147         TagCollection tc = null;
    148         for (Class<? extends OsmPrimitive> type : osmPrimitiveClasses) {
    149             TagCollection tc1 = getSourceTagsByType(type);
    150             if (!tc1.isEmpty()) {
    151                 tc = tc1;
    152             }
    153         }
    154         if (tc == null)
    155             // no tags found to paste. Abort.
    156             return;
    157 
    158         if (!tc.isApplicableToPrimitive()) {
    159             PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
    160             dialog.populate(tc, getSourceStatistics(), getTargetStatistics());
    161             dialog.setVisible(true);
    162             if (dialog.isCanceled())
     37    public static class TagPaster {
     38
     39        private final Collection<PrimitiveData> source;
     40        private final Collection<OsmPrimitive> target;
     41        private final List<Command> commands = new ArrayList<Command>();
     42
     43        public TagPaster(Collection<PrimitiveData> source, Collection<OsmPrimitive> target) {
     44            this.source = source;
     45            this.target = target;
     46        }
     47
     48        /**
     49         * Replies true if the source for tag pasting is heterogeneous, i.e. if it doesn't consist of
     50         * {@see OsmPrimitive}s of exactly one type
     51         *
     52         * @return
     53         */
     54        protected boolean isHeteogeneousSource() {
     55            int count = 0;
     56            count = !getSourcePrimitivesByType(OsmPrimitiveType.NODE).isEmpty() ? count + 1 : count;
     57            count = !getSourcePrimitivesByType(OsmPrimitiveType.WAY).isEmpty() ? count + 1 : count;
     58            count = !getSourcePrimitivesByType(OsmPrimitiveType.RELATION).isEmpty() ? count + 1 : count;
     59            return count > 1;
     60        }
     61
     62        /**
     63         * Replies all primitives of type <code>type</code> in the current selection.
     64         *
     65         * @param <T>
     66         * @param type  the type
     67         * @return all primitives of type <code>type</code> in the current selection.
     68         */
     69        protected <T extends PrimitiveData> Collection<? extends PrimitiveData> getSourcePrimitivesByType(OsmPrimitiveType type) {
     70            return PrimitiveData.getFilteredList(source, type);
     71        }
     72
     73        /**
     74         * Replies the collection of tags for all primitives of type <code>type</code> in the current
     75         * selection
     76         *
     77         * @param <T>
     78         * @param type  the type
     79         * @return the collection of tags for all primitives of type <code>type</code> in the current
     80         * selection
     81         */
     82        protected <T extends OsmPrimitive> TagCollection getSourceTagsByType(OsmPrimitiveType type) {
     83            return TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(type));
     84        }
     85
     86        /**
     87         * Replies true if there is at least one tag in the current selection for primitives of
     88         * type <code>type</code>
     89         *
     90         * @param <T>
     91         * @param type the type
     92         * @return true if there is at least one tag in the current selection for primitives of
     93         * type <code>type</code>
     94         */
     95        protected <T extends OsmPrimitive> boolean hasSourceTagsByType(OsmPrimitiveType type) {
     96            return ! getSourceTagsByType(type).isEmpty();
     97        }
     98
     99        protected Command buildChangeCommand(Collection<? extends OsmPrimitive> selection, TagCollection tc) {
     100            List<Command> commands = new ArrayList<Command>();
     101            for (String key : tc.getKeys()) {
     102                String value = tc.getValues(key).iterator().next();
     103                value = value.equals("") ? null : value;
     104                commands.add(new ChangePropertyCommand(selection,key,value));
     105            }
     106            if (!commands.isEmpty()) {
     107                String title1 = trn("Pasting {0} tag", "Pasting {0} tags", tc.getKeys().size(), tc.getKeys().size());
     108                String title2 = trn("to {0} primitive", "to {0} primtives", selection.size(), selection.size());
     109                return new SequenceCommand(
     110                        title1 + " " + title2,
     111                        commands
     112                );
     113            }
     114            return null;
     115        }
     116
     117        protected Map<OsmPrimitiveType, Integer> getSourceStatistics() {
     118            HashMap<OsmPrimitiveType, Integer> ret = new HashMap<OsmPrimitiveType, Integer>();
     119            for (OsmPrimitiveType type: OsmPrimitiveType.values()) {
     120                if (!getSourceTagsByType(type).isEmpty()) {
     121                    ret.put(type, getSourcePrimitivesByType(type).size());
     122                }
     123            }
     124            return ret;
     125        }
     126
     127        protected Map<OsmPrimitiveType, Integer> getTargetStatistics() {
     128            HashMap<OsmPrimitiveType, Integer> ret = new HashMap<OsmPrimitiveType, Integer>();
     129            for (OsmPrimitiveType type: OsmPrimitiveType.values()) {
     130                int count = OsmPrimitive.getFilteredList(target, type.getOsmClass()).size();
     131                if (count > 0) {
     132                    ret.put(type, count);
     133                }
     134            }
     135            return ret;
     136        }
     137
     138        /**
     139         * Pastes the tags from a homogeneous source (i.e. the {@see Main#pasteBuffer}s selection consisting
     140         * of one type of {@see OsmPrimitive}s only.
     141         *
     142         * Tags from a homogeneous source can be pasted to a heterogeneous target. All target primitives,
     143         * regardless of their type, receive the same tags.
     144         *
     145         * @param targets the collection of target primitives
     146         */
     147        protected void pasteFromHomogeneousSource() {
     148            TagCollection tc = null;
     149            for (OsmPrimitiveType type : OsmPrimitiveType.values()) {
     150                TagCollection tc1 = getSourceTagsByType(type);
     151                if (!tc1.isEmpty()) {
     152                    tc = tc1;
     153                }
     154            }
     155            if (tc == null)
     156                // no tags found to paste. Abort.
    163157                return;
    164             Command cmd = buildChangeCommand(targets, dialog.getResolution());
    165             Main.main.undoRedo.add(cmd);
    166         } else {
    167             // no conflicts in the source tags to resolve. Just apply the tags
    168             // to the target primitives
    169             //
    170             Command cmd = buildChangeCommand(targets, tc);
    171             Main.main.undoRedo.add(cmd);
    172         }
    173     }
    174 
    175     /**
    176      * Replies true if there is at least one primitive of type <code>type</code> in the collection
    177      * <code>selection</code>
    178      *
    179      * @param <T>
    180      * @param selection  the collection of primitives
    181      * @param type  the type to look for
    182      * @return true if there is at least one primitive of type <code>type</code> in the collection
    183      * <code>selection</code>
    184      */
    185     protected <T extends OsmPrimitive> boolean hasTargetPrimitives(Collection<OsmPrimitive> selection, Class<T> type) {
    186         return !OsmPrimitive.getFilteredList(selection, type).isEmpty();
    187     }
    188 
    189     /**
    190      * Replies true if this a heterogeneous source can be pasted without conflict to targets
    191      *
    192      * @param targets the collection of target primitives
    193      * @return true if this a heterogeneous source can be pasted without conflicts to targets
    194      */
    195     protected boolean canPasteFromHeterogeneousSourceWithoutConflict(Collection<OsmPrimitive> targets) {
    196         if (hasTargetPrimitives(targets, Node.class)) {
    197             TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(Node.class));
    198             if (!tc.isEmpty() && ! tc.isApplicableToPrimitive())
    199                 return false;
    200         }
    201         if (hasTargetPrimitives(targets, Way.class)) {
    202             TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(Way.class));
    203             if (!tc.isEmpty() && ! tc.isApplicableToPrimitive())
    204                 return false;
    205         }
    206         if (hasTargetPrimitives(targets, Relation.class)) {
    207             TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(Relation.class));
    208             if (!tc.isEmpty() && ! tc.isApplicableToPrimitive())
    209                 return false;
    210         }
    211         return true;
    212     }
    213 
    214     /**
    215      * Pastes the tags in the current selection of the paste buffer to a set of target
    216      * primitives.
    217      *
    218      * @param targets the collection of target primitives
    219      */
    220     protected void pasteFromHeterogeneousSource(Collection<OsmPrimitive> targets) {
    221         if (canPasteFromHeterogeneousSourceWithoutConflict(targets)) {
    222             if (hasSourceTagsByType(Node.class) && hasTargetPrimitives(targets, Node.class)) {
    223                 Command cmd = buildChangeCommand(targets, getSourceTagsByType(Node.class));
    224                 Main.main.undoRedo.add(cmd);
    225             }
    226             if (hasSourceTagsByType(Way.class) && hasTargetPrimitives(targets, Way.class)) {
    227                 Command cmd = buildChangeCommand(targets, getSourceTagsByType(Way.class));
    228                 Main.main.undoRedo.add(cmd);
    229             }
    230             if (hasSourceTagsByType(Relation.class) && hasTargetPrimitives(targets, Relation.class)) {
    231                 Command cmd = buildChangeCommand(targets,getSourceTagsByType(Relation.class));
    232                 Main.main.undoRedo.add(cmd);
    233             }
    234         } else {
    235             PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
    236             dialog.populate(
    237                     getSourceTagsByType(Node.class),
    238                     getSourceTagsByType(Way.class),
    239                     getSourceTagsByType(Relation.class),
    240                     getSourceStatistics(),
    241                     getTargetStatistics()
    242             );
    243             dialog.setVisible(true);
    244             if (dialog.isCanceled())
    245                 return;
    246             if (hasSourceTagsByType(Node.class) && hasTargetPrimitives(targets, Node.class)) {
    247                 Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Node.class), dialog.getResolution(OsmPrimitiveType.NODE));
    248                 Main.main.undoRedo.add(cmd);
    249             }
    250             if (hasSourceTagsByType(Way.class) && hasTargetPrimitives(targets, Way.class)) {
    251                 Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Way.class), dialog.getResolution(OsmPrimitiveType.WAY));
    252                 Main.main.undoRedo.add(cmd);
    253             }
    254             if (hasSourceTagsByType(Relation.class) && hasTargetPrimitives(targets, Relation.class)) {
    255                 Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Relation.class), dialog.getResolution(OsmPrimitiveType.RELATION));
    256                 Main.main.undoRedo.add(cmd);
    257             }
    258         }
    259     }
     158
     159            if (!tc.isApplicableToPrimitive()) {
     160                PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
     161                dialog.populate(tc, getSourceStatistics(), getTargetStatistics());
     162                dialog.setVisible(true);
     163                if (dialog.isCanceled())
     164                    return;
     165                Command cmd = buildChangeCommand(target, dialog.getResolution());
     166                commands.add(cmd);
     167            } else {
     168                // no conflicts in the source tags to resolve. Just apply the tags
     169                // to the target primitives
     170                //
     171                Command cmd = buildChangeCommand(target, tc);
     172                commands.add(cmd);
     173            }
     174        }
     175
     176        /**
     177         * Replies true if there is at least one primitive of type <code>type</code> in the collection
     178         * <code>selection</code>
     179         *
     180         * @param <T>
     181         * @param selection  the collection of primitives
     182         * @param type  the type to look for
     183         * @return true if there is at least one primitive of type <code>type</code> in the collection
     184         * <code>selection</code>
     185         */
     186        protected <T extends OsmPrimitive> boolean hasTargetPrimitives(Class<T> type) {
     187            return !OsmPrimitive.getFilteredList(target, type).isEmpty();
     188        }
     189
     190        /**
     191         * Replies true if this a heterogeneous source can be pasted without conflict to targets
     192         *
     193         * @param targets the collection of target primitives
     194         * @return true if this a heterogeneous source can be pasted without conflicts to targets
     195         */
     196        protected boolean canPasteFromHeterogeneousSourceWithoutConflict(Collection<OsmPrimitive> targets) {
     197            for (OsmPrimitiveType type:OsmPrimitiveType.values()) {
     198                if (hasTargetPrimitives(type.getOsmClass())) {
     199                    TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(type));
     200                    if (!tc.isEmpty() && ! tc.isApplicableToPrimitive())
     201                        return false;
     202                }
     203            }
     204            return true;
     205        }
     206
     207        /**
     208         * Pastes the tags in the current selection of the paste buffer to a set of target
     209         * primitives.
     210         *
     211         * @param targets the collection of target primitives
     212         */
     213        protected void pasteFromHeterogeneousSource() {
     214            if (canPasteFromHeterogeneousSourceWithoutConflict(target)) {
     215                for (OsmPrimitiveType type:OsmPrimitiveType.values()) {
     216                    if (hasSourceTagsByType(type) && hasTargetPrimitives(type.getOsmClass())) {
     217                        Command cmd = buildChangeCommand(target, getSourceTagsByType(type));
     218                        commands.add(cmd);
     219                    }
     220                }
     221            } else {
     222                PasteTagsConflictResolverDialog dialog = new PasteTagsConflictResolverDialog(Main.parent);
     223                dialog.populate(
     224                        getSourceTagsByType(OsmPrimitiveType.NODE),
     225                        getSourceTagsByType(OsmPrimitiveType.WAY),
     226                        getSourceTagsByType(OsmPrimitiveType.RELATION),
     227                        getSourceStatistics(),
     228                        getTargetStatistics()
     229                );
     230                dialog.setVisible(true);
     231                if (dialog.isCanceled())
     232                    return;
     233                for (OsmPrimitiveType type:OsmPrimitiveType.values()) {
     234                    if (hasSourceTagsByType(type) && hasTargetPrimitives(type.getOsmClass())) {
     235                        Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(target, type.getOsmClass()), dialog.getResolution(type));
     236                        commands.add(cmd);
     237                    }
     238                }
     239            }
     240        }
     241
     242        public List<Command> execute() {
     243            commands.clear();
     244            if (isHeteogeneousSource()) {
     245                pasteFromHeterogeneousSource();
     246            } else {
     247                pasteFromHomogeneousSource();
     248            }
     249            return commands;
     250        }
     251
     252    }
     253
    260254
    261255    public void actionPerformed(ActionEvent e) {
    262256        if (getCurrentDataSet().getSelected().isEmpty())
    263257            return;
    264         if (isHeteogeneousSource()) {
    265             pasteFromHeterogeneousSource(getCurrentDataSet().getSelected());
    266         } else {
    267             pasteFromHomogeneousSource(getCurrentDataSet().getSelected());
    268         }
    269     }
    270 
    271     @Override public void pasteBufferChanged(DataSet newPasteBuffer) {
     258        TagPaster tagPaster = new TagPaster(Main.pasteBuffer.getDirectlyAdded(), getCurrentDataSet().getSelected());
     259        for (Command c:tagPaster.execute()) {
     260            Main.main.undoRedo.add(c);
     261        }
     262    }
     263
     264    @Override public void pasteBufferChanged(PrimitiveDeepCopy newPasteBuffer) {
    272265        updateEnabledState();
    273266    }
     
    281274        setEnabled(
    282275                !getCurrentDataSet().getSelected().isEmpty()
    283                 && !TagCollection.unionOfAllPrimitives(Main.pasteBuffer.getSelected()).isEmpty()
     276                && !TagCollection.unionOfAllPrimitives(Main.pasteBuffer.getDirectlyAdded()).isEmpty()
    284277        );
    285278    }
     
    289282        setEnabled(
    290283                selection!= null && !selection.isEmpty()
    291                 && !TagCollection.unionOfAllPrimitives(Main.pasteBuffer.getSelected()).isEmpty()
     284                && !TagCollection.unionOfAllPrimitives(Main.pasteBuffer.getDirectlyAdded()).isEmpty()
    292285        );
    293286    }
  • trunk/src/org/openstreetmap/josm/data/osm/Changeset.java

    r2115 r2305  
    5050    /**
    5151     * Creates a changeset with id <code>id</code>. If id > 0, sets incomplete to true.
    52      * 
     52     *
    5353     * @param id the id
    5454     */
     
    6161    /**
    6262     * Creates a clone of <code>other</code>
    63      * 
     63     *
    6464     * @param other the other changeset. If null, creates a new changeset with id 0.
    6565     */
     
    192192        this.tags.remove(key);
    193193    }
     194
     195    public void removeAll() {
     196        this.tags.clear();
     197    }
     198
    194199
    195200    public boolean hasEqualSemanticAttributes(Changeset other) {
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r2282 r2305  
    11// License: GPL. Copyright 2007 by Immanuel Scholz and others
    22package org.openstreetmap.josm.data.osm;
    3 import static org.openstreetmap.josm.tools.I18n.tr;
    4 
    53import java.awt.geom.Area;
    64import java.util.ArrayList;
     
    1614
    1715import org.openstreetmap.josm.data.SelectionChangedListener;
    18 import org.openstreetmap.josm.data.osm.QuadBuckets;
    1916
    2017/**
     
    113110     */
    114111    public void addPrimitive(OsmPrimitive primitive) {
    115         if (primitive == null)
    116             return;
    117112        if (primitive instanceof Node) {
    118113            nodes.add((Node) primitive);
     
    121116        } else if (primitive instanceof Relation) {
    122117            relations.add((Relation) primitive);
     118        }
     119    }
     120
     121    public OsmPrimitive addPrimitive(PrimitiveData data) {
     122        if (data instanceof NodeData) {
     123            Node node = new Node((NodeData)data, this);
     124            nodes.add(node);
     125            return node;
     126        } else if (data instanceof WayData) {
     127            Way way = new Way((WayData)data, this);
     128            ways.add(way);
     129            return way;
     130        } else if (data instanceof RelationData) {
     131            Relation relation = new Relation((RelationData)data, this);
     132            relations.add(relation);
     133            return relation;
     134        } else {
     135            throw new AssertionError();
    123136        }
    124137    }
     
    145158    }
    146159
     160    public void removePrimitive(long id, OsmPrimitiveType type) {
     161        removePrimitive(getPrimitiveById(id, type));
     162    }
     163
    147164    public Collection<OsmPrimitive> getSelectedNodesAndWays() {
    148165        Collection<OsmPrimitive> sel = getSelected(nodes);
     
    246263     * Sets the current selection to the primitives in <code>selection</code>.
    247264     * Notifies all {@see SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true.
    248      * 
     265     *
    249266     * @param selection the selection
    250267     * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise
     
    265282     * Sets the current selection to the primitives in <code>selection</code>
    266283     * and notifies all {@see SelectionChangedListener}.
    267      * 
     284     *
    268285     * @param selection the selection
    269286     */
     
    275292     * Adds   the primitives in <code>selection</code> to the current selection
    276293     * and notifies all {@see SelectionChangedListener}.
    277      * 
     294     *
    278295     * @param selection the selection
    279296     */
     
    285302     * Adds the primitives in <code>selection</code> to the current selection.
    286303     * Notifies all {@see SelectionChangedListener} if <code>fireSelectionChangeEvent</code> is true.
    287      * 
     304     *
    288305     * @param selection the selection
    289306     * @param fireSelectionChangeEvent true, if the selection change listeners are to be notified; false, otherwise
     
    443460     * exists
    444461     *
    445      * @param id  the id, > 0 required
     462     * @param id  uniqueId of the primitive. Might be < 0 for newly created primitives
    446463     * @param type the type of  the primitive. Must not be null.
    447464     * @return the primitive
    448      * @exception IllegalArgumentException thrown, if id <= 0
    449      * @exception IllegalArgumentException thrown, if type is null
    450      * @exception IllegalArgumentException thrown, if type is neither NODE, or WAY or RELATION
     465     * @exception NullPointerException thrown, if type is null
    451466     */
    452467    public OsmPrimitive getPrimitiveById(long id, OsmPrimitiveType type) {
    453         if (id <= 0)
    454             throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));
    455         if (id <= 0)
    456             throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "type"));
     468        return getPrimitiveById(id, type, false);
     469    }
     470
     471    public OsmPrimitive getPrimitiveById(long id, OsmPrimitiveType type, boolean createNew) {
    457472        Collection<? extends OsmPrimitive> primitives = null;
    458473        switch(type) {
     
    462477        }
    463478        for (OsmPrimitive primitive : primitives) {
    464             if (primitive.getId() == id) return primitive;
    465         }
    466         return null;
     479            if (primitive.getUniqueId() == id) return primitive;
     480        }
     481
     482        if (createNew) {
     483            OsmPrimitive result = null;
     484            switch (type) {
     485            case NODE: result = new Node(id, true); break;
     486            case WAY: result = new Way(id, true); break;
     487            case RELATION: result = new Relation(id, true); break;
     488            }
     489            addPrimitive(result);
     490            return result;
     491        } else {
     492            return null;
     493        }
    467494    }
    468495
     
    565592     * Replies true if there is at least one primitive in this dataset with
    566593     * {@see OsmPrimitive#isModified()} == <code>true</code>.
    567      * 
     594     *
    568595     * @return true if there is at least one primitive in this dataset with
    569596     * {@see OsmPrimitive#isModified()} == <code>true</code>.
  • trunk/src/org/openstreetmap/josm/data/osm/NodeData.java

    r2299 r2305  
    22package org.openstreetmap.josm.data.osm;
    33
     4import org.openstreetmap.josm.data.coor.CachedLatLon;
     5import org.openstreetmap.josm.data.coor.EastNorth;
    46import org.openstreetmap.josm.data.coor.LatLon;
    57
    68public class NodeData extends PrimitiveData {
    79
    8     private LatLon coor;
     10    private final CachedLatLon coor = new CachedLatLon(0, 0);
     11
     12    public NodeData() {
     13
     14    }
     15
     16    public NodeData(double lat, double lon, String... keys) {
     17        setCoor(new LatLon(lat, lon));
     18        setKeysAsList(keys);
     19    }
     20
     21    public NodeData(String... keys) {
     22        setKeysAsList(keys);
     23    }
     24
     25    public NodeData(NodeData data) {
     26        super(data);
     27        setCoor(data.getCoor());
     28    }
    929
    1030    public LatLon getCoor() {
     
    1333
    1434    public void setCoor(LatLon coor) {
    15         this.coor = coor;
     35        this.coor.setCoor(coor);
     36    }
     37
     38    public EastNorth getEastNorth() {
     39        return this.coor.getEastNorth();
     40    }
     41
     42    public void setEastNorth(EastNorth eastNorth) {
     43        this.coor.setEastNorth(eastNorth);
     44    }
     45
     46    @Override
     47    public NodeData makeCopy() {
     48        return new NodeData(this);
     49    }
     50
     51    @Override
     52    public Node makePrimitive(DataSet dataSet) {
     53        return new Node(this, dataSet);
    1654    }
    1755
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r2300 r2305  
    3636abstract public class OsmPrimitive implements Comparable<OsmPrimitive>, Tagged {
    3737
    38     static final AtomicLong idCounter = new AtomicLong(0);
     38    private static final AtomicLong idCounter = new AtomicLong(0);
     39
     40    static long generateUniqueId() {
     41        return idCounter.decrementAndGet();
     42    }
    3943
    4044    private static final int FLAG_MODIFIED = 1 << 0;
     
    164168                throw new IllegalArgumentException(tr("Expected ID >= 0. Got {0}.", id));
    165169            else if (id == 0) {
    166                 this.id = idCounter.decrementAndGet();
     170                this.id = generateUniqueId();
    167171            } else {
    168172                this.id = id;
     
    400404     */
    401405    public void clearOsmId() {
    402         this.id = idCounter.decrementAndGet();
     406        this.id = generateUniqueId();
    403407        this.version = 0;
    404408        this.incomplete = false;
     
    456460        if(directionKeys == null) {
    457461            directionKeys = Main.pref.getCollection("tags.direction",
    458                     Arrays.asList(new String[]{"oneway","incline","incline_steep","aerialway"}));
     462                    Arrays.asList("oneway","incline","incline_steep","aerialway"));
    459463        }
    460464        return directionKeys;
     
    841845
    842846    protected void saveCommonAttributes(PrimitiveData data) {
    843         data.setId(data.getId());
     847        data.setId(id);
    844848        data.getKeys().clear();
    845849        data.getKeys().putAll(getKeys());
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java

    r2181 r2305  
    55public enum OsmPrimitiveType {
    66
    7     NODE ("node"),
    8     WAY  ("way"),
    9     RELATION ("relation");
     7    NODE ("node", Node.class, NodeData.class),
     8    WAY  ("way", Way.class, WayData.class),
     9    RELATION ("relation", Relation.class, RelationData.class);
    1010
    11     private String apiTypeName;
     11    private final String apiTypeName;
     12    private final Class<? extends OsmPrimitive> osmClass;
     13    private final Class<? extends PrimitiveData> dataClass;
    1214
    13     OsmPrimitiveType(String apiTypeName) {
     15    OsmPrimitiveType(String apiTypeName, Class<? extends OsmPrimitive> osmClass, Class<? extends PrimitiveData> dataClass) {
    1416        this.apiTypeName = apiTypeName;
     17        this.osmClass = osmClass;
     18        this.dataClass = dataClass;
    1519    }
    1620
    1721    public String getAPIName() {
    1822        return apiTypeName;
     23    }
     24
     25    public Class<? extends OsmPrimitive> getOsmClass() {
     26        return osmClass;
     27    }
     28
     29    public Class<? extends PrimitiveData> getDataClass() {
     30        return dataClass;
    1931    }
    2032
     
    3042    }
    3143
    32     public static OsmPrimitiveType from(Class cls) {
     44    public static OsmPrimitiveType from(Class<? extends OsmPrimitive> cls) {
    3345        if (cls.equals(Node.class)) return NODE;
    3446        if (cls.equals(Way.class)) return WAY;
    3547        if (cls.equals(Relation.class)) return RELATION;
    3648        throw new IllegalArgumentException(tr("Parameter ''{0}'' is not an acceptable class. Got ''{1}''.", "cls", cls.toString()));
     49    }
     50
     51    public static OsmPrimitiveType fromData(Class<? extends PrimitiveData> cls) {
     52        if (cls.equals(NodeData.class)) return NODE;
     53        if (cls.equals(WayData.class)) return WAY;
     54        if (cls.equals(RelationData.class)) return RELATION;
     55        throw new IllegalArgumentException(tr("Parameter ''{0}'' is not an acceptable class. Got ''{1}''.", "cls", cls.toString()));
     56    }
     57
     58    public static OsmPrimitiveType fromData(PrimitiveData data) {
     59        return fromData(data.getClass());
    3760    }
    3861
  • trunk/src/org/openstreetmap/josm/data/osm/PrimitiveData.java

    r2299 r2305  
    22package org.openstreetmap.josm.data.osm;
    33
     4import java.util.ArrayList;
     5import java.util.Collection;
    46import java.util.HashMap;
     7import java.util.List;
    58import java.util.Map;
    69
     
    1215 *
    1316 */
    14 public abstract class PrimitiveData {
     17public abstract class PrimitiveData implements Tagged {
    1518
    1619    // Useful?
     
    1922    //private boolean selected;
    2023    //private boolean highlighted;
     24
     25    public PrimitiveData() {
     26        id = OsmPrimitive.generateUniqueId();
     27    }
     28
     29    public PrimitiveData(PrimitiveData data) {
     30        this.keys.putAll(data.keys);
     31        this.modified = data.modified;
     32        this.visible = data.visible;
     33        this.deleted = data.deleted;
     34        this.id = data.id;
     35        this.user = data.user;
     36        this.version = data.version;
     37        this.timestamp = data.timestamp;
     38    }
    2139
    2240    private final Map<String, String> keys = new HashMap<String, String>();
     
    7593    }
    7694
     95    public void clearOsmId() {
     96        id = OsmPrimitive.generateUniqueId();
     97    }
     98
     99    public abstract PrimitiveData makeCopy();
     100
     101    public abstract OsmPrimitive makePrimitive(DataSet dataSet);
    77102
    78103    @Override
     
    94119    }
    95120
     121    // Tagged implementation
     122
     123    public String get(String key) {
     124        return keys.get(key);
     125    }
     126
     127    public boolean hasKeys() {
     128        return !keys.isEmpty();
     129    }
     130
     131    public Collection<String> keySet() {
     132        return keys.keySet();
     133    }
     134
     135    public void put(String key, String value) {
     136        keys.put(key, value);
     137    }
     138
     139    public void remove(String key) {
     140        keys.remove(key);
     141    }
     142
     143    public void removeAll() {
     144        keys.clear();
     145    }
     146
     147    public void setKeys(Map<String, String> keys) {
     148        this.keys.clear();
     149        this.keys.putAll(keys);
     150    }
     151
     152
     153    @SuppressWarnings("unchecked")
     154    static public <T extends PrimitiveData>  List<T> getFilteredList(Collection<T> list, OsmPrimitiveType type) {
     155        List<T> ret = new ArrayList<T>();
     156        for(PrimitiveData p: list) {
     157            if (type.getDataClass().isInstance(p)) {
     158                ret.add((T)p);
     159            }
     160        }
     161        return ret;
     162    }
     163
     164    protected void setKeysAsList(String... keys) {
     165        assert keys.length % 2 == 0;
     166        for (int i=0; i<keys.length/2; i++) {
     167            this.keys.put(keys[i * 2], keys[i * 2 + 1]);
     168        }
     169    }
     170
     171
    96172
    97173}
  • trunk/src/org/openstreetmap/josm/data/osm/Relation.java

    r2284 r2305  
    205205                foundMember = nodes.get(member.getMemberId());
    206206                if (foundMember == nodeMarker) {
    207                     foundMember = new Node(member.getMemberId(), true);
     207                    throw new AssertionError("Data consistency problem - relation with missing member detected");
    208208                }
    209209                break;
     
    211211                foundMember = ways.get(member.getMemberId());
    212212                if (foundMember == wayMarker) {
    213                     foundMember = new Way(member.getMemberId(), true);
     213                    throw new AssertionError("Data consistency problem - relation with missing member detected");
    214214                }
    215215                break;
     
    217217                foundMember = relations.get(member.getMemberId());
    218218                if (foundMember == relationMarker) {
    219                     foundMember = new Relation(member.getMemberId(), true);
     219                    throw new AssertionError("Data consistency problem - relation with missing member detected");
    220220                }
    221221                break;
  • trunk/src/org/openstreetmap/josm/data/osm/RelationData.java

    r2299 r2305  
    99    private final List<RelationMemberData> members = new ArrayList<RelationMemberData>();
    1010
     11    public RelationData() {
     12
     13    }
     14
     15    public RelationData(RelationData data) {
     16        super(data);
     17        members.addAll(data.members);
     18    }
     19
    1120    public List<RelationMemberData> getMembers() {
    1221        return members;
     22    }
     23
     24    @Override
     25    public RelationData makeCopy() {
     26        return new RelationData(this);
     27    }
     28
     29    @Override
     30    public Relation makePrimitive(DataSet dataSet) {
     31        return new Relation(this, dataSet);
    1332    }
    1433
  • trunk/src/org/openstreetmap/josm/data/osm/RelationMemberData.java

    r2299 r2305  
    44public class RelationMemberData {
    55
    6     private String role;
    7     private long memberId;
    8     private OsmPrimitiveType memberType;
     6    private final String role;
     7    private final long memberId;
     8    private final OsmPrimitiveType memberType;
    99
    10     public RelationMemberData() {
    11 
     10    public RelationMemberData(String role, OsmPrimitiveType type, long id) {
     11        this.role = role;
     12        this.memberType = type;
     13        this.memberId = id;
    1214    }
    1315
    1416    public RelationMemberData(String role, OsmPrimitive primitive) {
    15         this.role = role;
    16         this.memberId = primitive.getUniqueId();
    17         this.memberType = OsmPrimitiveType.from(primitive);
     17        this(role, OsmPrimitiveType.from(primitive), primitive.getUniqueId());
    1818    }
    1919
     
    2121        return memberId;
    2222    }
    23     public void setMemberId(long memberId) {
    24         this.memberId = memberId;
    25     }
    2623    public String getRole() {
    2724        return role;
    2825    }
    29     public void setRole(String role) {
    30         this.role = role;
    31     }
    3226    public OsmPrimitiveType getMemberType() {
    3327        return memberType;
    34     }
    35     public void setMemberType(OsmPrimitiveType memberType) {
    36         this.memberType = memberType;
    3728    }
    3829
  • trunk/src/org/openstreetmap/josm/data/osm/Tag.java

    r2070 r2305  
    22package org.openstreetmap.josm.data.osm;
    33
    4 import java.util.ArrayList;
    5 import java.util.Collections;
    6 import java.util.Iterator;
    7 import java.util.List;
    84
    95/**
     
    2117     */
    2218    public Tag(){
    23         this.key = "";
    24         this.value = "";
     19        this("", "");
    2520    }
    2621
     
    2823     * Create a tag whose key is <code>key</code> and whose value is
    2924     * empty.
    30      * 
     25     *
    3126     * @param key the key. If null, it is set to the empty key.
    3227     */
    3328    public Tag(String key) {
    34         this();
    35         this.key = key == null ? "" : key;
     29        this(key, "");
    3630    }
    3731
     
    3933     * Creates a tag for a key and a value. If key and/or value are null,
    4034     * the empty value "" is assumed.
    41      * 
     35     *
    4236     * @param key the key
    4337     * @param value  the value
     
    5044    /**
    5145     * Creates clone of the tag <code>tag</code>.
    52      * 
    53      * @param tag the tag. If null, creates an empty tag.
     46     *
     47     * @param tag the tag.
    5448     */
    5549    public Tag(Tag tag) {
    56         if (tag != null) {
    57             key = tag.getKey();
    58             value = tag.getValue();
    59         }
     50        this(tag.getKey(), tag.getValue());
    6051    }
    6152
    6253    /**
    6354     * Replies the key of the tag. This is never null.
    64      * 
     55     *
    6556     * @return the key of the tag
    6657     */
     
    7162    /**
    7263     * Replies the value of the tag. This is never null.
    73      * 
     64     *
    7465     * @return the value of the tag
    7566     */
     
    8677     * Replies true if the key of this tag is equal to <code>key</code>.
    8778     * If <code>key</code> is null, assumes the empty key.
    88      * 
     79     *
    8980     * @param key the key
    9081     * @return true if the key of this tag is equal to <code>key</code>
    9182     */
    9283    public boolean matchesKey(String key) {
    93         if (key == null) {
    94             key = "";
    95         }
    9684        return this.key.equals(key);
    9785    }
     
    10290     *   <li>removing leading and trailing white space</li>
    10391     * <ul>
    104      * 
     92     *
    10593     */
    10694    public void normalize() {
     
    113101        final int prime = 31;
    114102        int result = 1;
    115         result = prime * result + ((key == null) ? 0 : key.hashCode());
    116         result = prime * result + ((value == null) ? 0 : value.hashCode());
     103        result = prime * result + key.hashCode();
     104        result = prime * result + value.hashCode();
    117105        return result;
    118106    }
     
    120108    @Override
    121109    public boolean equals(Object obj) {
    122         if (this == obj)
    123             return true;
    124         if (obj == null)
     110        if (obj instanceof Tag) {
     111            Tag other = (Tag) obj;
     112            return key.equals(other.getKey()) && value.equals(other.getValue());
     113        } else {
    125114            return false;
    126         if (getClass() != obj.getClass())
    127             return false;
    128         Tag other = (Tag) obj;
    129         if (key == null) {
    130             if (other.key != null)
    131                 return false;
    132         } else if (!key.equals(other.key))
    133             return false;
    134         if (value == null) {
    135             if (other.value != null)
    136                 return false;
    137         } else if (!value.equals(other.value))
    138             return false;
    139         return true;
     115        }
     116    }
     117
     118    @Override
     119    public String toString() {
     120        return key + "=" + value;
    140121    }
    141122}
  • trunk/src/org/openstreetmap/josm/data/osm/TagCollection.java

    r2181 r2305  
    1717 * TagCollection is a collection of tags which can be used to manipulate
    1818 * tags managed by {@see OsmPrimitive}s.
    19  * 
     19 *
    2020 * A TagCollection can be created:
    2121 * <ul>
     
    2525 *  <li>from the intersection of all tags managed by a collection of primitives with {@see #commonToAllPrimitives(Collection)}</li>
    2626 * </ul>
    27  * 
     27 *
    2828 * It  provides methods to query the collection, like {@see #size()}, {@see #hasTagsFor(String)}, etc.
    29  * 
     29 *
    3030 * Basic set operations allow to create the union, the intersection and  the difference
    3131 * of tag collections, see {@see #union(TagCollection)}, {@see #intersect(TagCollection)},
    3232 * and {@see #minus(TagCollection)}.
    33  * 
     33 *
    3434 *
    3535 */
     
    4040     * {@see OsmPrimitive}. If <code>primitive</code> is null, replies
    4141     * an empty tag collection.
    42      * 
     42     *
    4343     * @param primitive  the primitive
    4444     * @return a tag collection with the tags managed by a specific
    4545     * {@see OsmPrimitive}
    4646     */
    47     public static TagCollection from(OsmPrimitive primitive) {
     47    public static TagCollection from(Tagged primitive) {
    4848        TagCollection tags = new TagCollection();
    4949        for (String key: primitive.keySet()) {
     
    6262     * a collection of primitives
    6363     */
    64     public static TagCollection unionOfAllPrimitives(Collection<? extends OsmPrimitive> primitives) {
     64    public static TagCollection unionOfAllPrimitives(Collection<? extends Tagged> primitives) {
    6565        TagCollection tags = new TagCollection();
    6666        if (primitives == null) return tags;
    67         for (OsmPrimitive primitive: primitives) {
     67        for (Tagged primitive: primitives) {
    6868            if (primitive == null) {
    6969                continue;
     
    7878     * <code>primitives</code>. Replies an empty tag collection of <code>primitives</code>
    7979     * is null.
    80      * 
     80     *
    8181     * @param primitives the primitives
    8282     * @return  a tag collection with the tags which are common to all primitives
    8383     */
    84     public static TagCollection commonToAllPrimitives(Collection<? extends OsmPrimitive> primitives) {
     84    public static TagCollection commonToAllPrimitives(Collection<? extends Tagged> primitives) {
    8585        TagCollection tags = new TagCollection();
    8686        if (primitives == null || primitives.isEmpty()) return tags;
     
    9191        // intersect with the others
    9292        //
    93         for (OsmPrimitive primitive: primitives) {
     93        for (Tagged primitive: primitives) {
    9494            if (primitive == null) {
    9595                continue;
     
    103103     * Replies a tag collection with the union of the tags which are common to all primitives in
    104104     * the dataset <code>ds</code>. Returns an empty tag collection of <code>ds</code> is null.
    105      * 
     105     *
    106106     * @param ds the dataset
    107107     * @return a tag collection with the union of the tags which are common to all primitives in
     
    129129     * Creates a clone of the tag collection <code>other</code>. Creats an empty
    130130     * tag collection if <code>other</code> is null.
    131      * 
     131     *
    132132     * @param other the other collection
    133133     */
     
    141141    /**
    142142     * Replies the number of tags in this tag collection
    143      * 
     143     *
    144144     * @return the number of tags in this tag collection
    145145     */
     
    150150    /**
    151151     * Replies true if this tag collection is empty
    152      * 
     152     *
    153153     * @return true if this tag collection is empty; false, otherwise
    154154     */
     
    159159    /**
    160160     * Adds a tag to the tag collection. If <code>tag</code> is null, nothing is added.
    161      * 
     161     *
    162162     * @param tag the tag to add
    163163     */
     
    171171     * Adds a collection of tags to the tag collection. If <code>tags</code> is null, nothing
    172172     * is added. null values in the collection are ignored.
    173      * 
     173     *
    174174     * @param tags the collection of tags
    175175     */
     
    184184     * Adds the tags of another tag collection to this collection. Adds nothing, if
    185185     * <code>tags</code> is null.
    186      * 
     186     *
    187187     * @param tags the other tag collection
    188188     */
     
    195195     * Removes a specific tag from the tag collection. Does nothing if <code>tag</code> is
    196196     * null.
    197      * 
     197     *
    198198     * @param tag the tag to be removed
    199199     */
     
    206206     * Removes a collection of tags from the tag collection. Does nothing if <code>tags</code> is
    207207     * null.
    208      * 
     208     *
    209209     * @param tags the tags to be removed
    210210     */
     
    217217     * Removes all tags in the tag collection <code>tags</code> from the current tag collection.
    218218     * Does nothing if <code>tags</code> is null.
    219      * 
     219     *
    220220     * @param tags the tag collection to be removed.
    221221     */
     
    228228     * Removes all tags whose keys are equal to  <code>key</code>. Does nothing if <code>key</code>
    229229     * is null.
    230      * 
     230     *
    231231     * @param key the key to be removed
    232232     */
     
    244244     * Removes all tags whose key is in the collection <code>keys</code>. Does nothing if
    245245     * <code>keys</code> is null.
    246      * 
     246     *
    247247     * @param keys the collection of keys to be removed
    248248     */
     
    256256    /**
    257257     * Replies true if the this tag collection contains <code>tag</code>.
    258      * 
     258     *
    259259     * @param tag the tag to look up
    260260     * @return true if the this tag collection contains <code>tag</code>; false, otherwise
     
    266266    /**
    267267     * Replies true if this tag collection contains at least one tag with key <code>key</code>.
    268      * 
     268     *
    269269     * @param key the key to look up
    270270     * @return true if this tag collection contains at least one tag with key <code>key</code>; false, otherwise
     
    281281     * Replies true if this tag collection contains all tags in <code>tags</code>. Replies
    282282     * false, if tags is null.
    283      * 
     283     *
    284284     * @param tags the tags to look up
    285285     * @return true if this tag collection contains all tags in <code>tags</code>. Replies
     
    288288    public boolean containsAll(Collection<Tag> tags) {
    289289        if (tags == null) return false;
    290         return tags.containsAll(tags);
     290        return this.tags.containsAll(tags);
    291291    }
    292292
     
    294294     * Replies true if this tag collection at least one tag for every key in <code>keys</code>.
    295295     * Replies false, if <code>keys</code> is null. null values in <code>keys</code> are ignored.
    296      * 
     296     *
    297297     * @param keys the keys to lookup
    298298     * @return true if this tag collection at least one tag for every key in <code>keys</code>.
     
    311311    /**
    312312     * Replies the number of tags with key <code>key</code>
    313      * 
     313     *
    314314     * @param key the key to look up
    315315     * @return the number of tags with key <code>key</code>. 0, if key is null.
     
    328328    /**
    329329     * Replies true if there is at least one tag for the given key.
    330      * 
     330     *
    331331     * @param key the key to look up
    332332     * @return true if there is at least one tag for the given key. false, if key is null.
     
    339339     * Replies true it there is at least one tag with a non empty value for key.
    340340     * Replies false if key is null.
    341      * 
     341     *
    342342     * @param key the key
    343343     * @return true it there is at least one tag with a non empty value for key.
     
    354354     * if the value of this tag is not empty. Replies false if key is
    355355     * null.
    356      * 
     356     *
    357357     * @param key the key
    358358     * @return true if there is exactly one tag for <code>key</code> and
     
    368368     * Replies true if there is a tag with an empty value for <code>key</code>.
    369369     * Replies false, if key is null.
    370      * 
     370     *
    371371     * @param key the key
    372372     * @return true if there is a tag with an empty value for <code>key</code>
     
    381381     * Replies true if there is exactly one tag for <code>key</code> and if
    382382     * the value for this tag is empty. Replies false if key is null.
    383      * 
     383     *
    384384     * @param key the key
    385385     * @return  true if there is exactly one tag for <code>key</code> and if
     
    395395     * Replies a tag collection with the tags for a given key. Replies an empty collection
    396396     * if key is null.
    397      * 
     397     *
    398398     * @param key the key to look up
    399399     * @return a tag collection with the tags for a given key. Replies an empty collection
     
    415415     * Replies a tag collection with all tags whose key is equal to one of the keys in
    416416     * <code>keys</code>. Replies an empty collection if keys is null.
    417      * 
     417     *
    418418     * @param keys the keys to look up
    419419     * @return a tag collection with all tags whose key is equal to one of the keys in
     
    434434    /**
    435435     * Replies the tags of this tag collection as set
    436      * 
     436     *
    437437     * @return the tags of this tag collection as set
    438438     */
     
    444444     * Replies the tags of this tag collection as list.
    445445     * Note that the order of the list is not preserved between method invocations.
    446      * 
     446     *
    447447     * @return the tags of this tag collection as list.
    448448     */
     
    453453    /**
    454454     * Replies an iterator to iterate over the tags in this collection
    455      * 
     455     *
    456456     * @return the iterator
    457457     */
     
    462462    /**
    463463     * Replies the set of keys of this tag collection.
    464      * 
     464     *
    465465     * @return the set of keys of this tag collection
    466466     */
     
    475475    /**
    476476     * Replies the set of keys which have at least 2 matching tags.
    477      * 
     477     *
    478478     * @return the set of keys which have at least 2 matching tags.
    479479     */
     
    496496     * Sets a unique tag for the key of this tag. All other tags with the same key are
    497497     * removed from the collection. Does nothing if tag is null.
    498      * 
     498     *
    499499     * @param tag the tag to set
    500500     */
     
    509509     * removed from the collection. Assume the empty string for key and value if either
    510510     * key or value is null.
    511      * 
     511     *
    512512     * @param key the key
    513513     * @param value the value
     
    520520    /**
    521521     * Replies the set of values in this tag collection
    522      * 
     522     *
    523523     * @return the set of values
    524524     */
     
    534534     * Replies the set of values for a given key. Replies an empty collection if there
    535535     * are no values for the given key.
    536      * 
     536     *
    537537     * @param key the key to look up
    538538     * @return the set of values for a given key. Replies an empty collection if there
     
    552552    /**
    553553     * Replies true if for every key there is one tag only, i.e. exactly one value.
    554      * 
     554     *
    555555     * @return
    556556     */
     
    562562     * Applies this tag collection to an {@see OsmPrimitive}. Does nothing if
    563563     * primitive is null
    564      * 
     564     *
    565565     * @param primitive  the primitive
    566566     * @throws IllegalStateException thrown if this tag collection can't be applied
    567567     * because there are keys with multiple values
    568568     */
    569     public void applyTo(OsmPrimitive primitive) throws IllegalStateException {
     569    public void applyTo(Tagged primitive) throws IllegalStateException {
    570570        if (primitive == null) return;
    571571        if (! isApplicableToPrimitive())
     
    583583     * Applies this tag collection to a collection of {@see OsmPrimitive}s. Does nothing if
    584584     * primitives is null
    585      * 
     585     *
    586586     * @param primitives  the collection of primitives
    587587     * @throws IllegalStateException thrown if this tag collection can't be applied
    588588     * because there are keys with multiple values
    589589     */
    590     public void applyTo(Collection<? extends OsmPrimitive> primitives) throws IllegalStateException{
     590    public void applyTo(Collection<? extends Tagged> primitives) throws IllegalStateException{
    591591        if (primitives == null) return;
    592592        if (! isApplicableToPrimitive())
    593593            throw new IllegalStateException(tr("Tag collection can't be applied to a primitive because there are keys with multiple values."));
    594         for (OsmPrimitive primitive: primitives) {
     594        for (Tagged primitive: primitives) {
    595595            applyTo(primitive);
    596596        }
     
    600600     * Replaces the tags of an {@see OsmPrimitive} by the tags in this collection . Does nothing if
    601601     * primitive is null
    602      * 
     602     *
    603603     * @param primitive  the primitive
    604604     * @throws IllegalStateException thrown if this tag collection can't be applied
    605605     * because there are keys with multiple values
    606606     */
    607     public void replaceTagsOf(OsmPrimitive primitive) throws IllegalStateException {
     607    public void replaceTagsOf(Tagged primitive) throws IllegalStateException {
    608608        if (primitive == null) return;
    609609        if (! isApplicableToPrimitive())
     
    618618     * Replaces the tags of a collection of{@see OsmPrimitive}s by the tags in this collection.
    619619     * Does nothing if primitives is null
    620      * 
     620     *
    621621     * @param primitive  the collection of primitives
    622622     * @throws IllegalStateException thrown if this tag collection can't be applied
    623623     * because there are keys with multiple values
    624624     */
    625     public void replaceTagsOf(Collection<? extends OsmPrimitive> primitives) throws IllegalStateException {
     625    public void replaceTagsOf(Collection<? extends Tagged> primitives) throws IllegalStateException {
    626626        if (primitives == null) return;
    627627        if (! isApplicableToPrimitive())
    628628            throw new IllegalStateException(tr("Tag collection can't be applied to a primitive because there are keys with multiple values."));
    629         for (OsmPrimitive primitive: primitives) {
     629        for (Tagged primitive: primitives) {
    630630            replaceTagsOf(primitive);
    631631        }
     
    634634    /**
    635635     * Builds the intersection of this tag collection and another tag collection
    636      * 
     636     *
    637637     * @param other the other tag collection. If null, replies an empty tag collection.
    638638     * @return the intersection of this tag collection and another tag collection
     
    653653    /**
    654654     * Replies the difference of this tag collection and another tag collection
    655      * 
     655     *
    656656     * @param other the other tag collection. May be null.
    657657     * @return the difference of this tag collection and another tag collection
     
    667667    /**
    668668     * Replies the union of this tag collection and another tag collection
    669      * 
     669     *
    670670     * @param other the other tag collection. May be null.
    671671     * @return the union of this tag collection and another tag collection
     
    690690    /**
    691691     * Replies the concatenation of all tag values (concatenated by a semicolon)
    692      * 
     692     *
    693693     * @return the concatenation of all tag values
    694694     */
     
    707707        return buffer.toString();
    708708    }
     709
     710    @Override
     711    public String toString() {
     712        return tags.toString();
     713    }
    709714}
  • trunk/src/org/openstreetmap/josm/data/osm/Tagged.java

    r2115 r2305  
    66/**
    77 * Objects implement Tagged if they provide a map of key/value pairs.
    8  * 
    9  * 
     8 *
     9 *
    1010 */
    1111// FIXME: better naming? setTags(), getTags(), getKeys() instead of keySet() ?
     
    1414    /**
    1515     * Sets the map of key/value pairs
    16      * 
     16     *
    1717     * @param keys the map of key value pairs. If null, reset to the empty map.
    1818     */
     
    2121    /**
    2222     * Replies the map of key/value pairs. Never null, but may be the empty map.
    23      * 
     23     *
    2424     * @return the map of key/value pairs
    2525     */
     
    2828    /**
    2929     * Sets a key/value pairs
    30      * 
     30     *
    3131     * @param key the key
    3232     * @param value the value. If null, removes the key/value pair.
     
    3636    /**
    3737     * Replies the value of the given key; null, if there is no value for this key
    38      * 
     38     *
    3939     * @param key the key
    4040     * @return the value
     
    4444    /**
    4545     * Removes a given key/value pair
    46      * 
     46     *
    4747     * @param key the key
    4848     */
     
    5151    /**
    5252     * Replies true, if there is at least one key/value pair; false, otherwise
    53      * 
     53     *
    5454     * @return true, if there is at least one key/value pair; false, otherwise
    5555     */
     
    5858    /**
    5959     * Replies the set of keys
    60      * 
     60     *
    6161     * @return the set of keys
    6262     */
    6363    Collection<String> keySet();
     64
     65    /**
     66     * Removes all tags
     67     */
     68    void removeAll();
    6469}
  • trunk/src/org/openstreetmap/josm/data/osm/Way.java

    r2284 r2305  
    196196                newNodes.add(foundNodes.get(nodeId));
    197197            } else {
    198                 newNodes.add(new Node(nodeId, true));
     198                throw new AssertionError("Data consistency problem - way with missing node detected");
    199199            }
    200200        }
  • trunk/src/org/openstreetmap/josm/data/osm/WayData.java

    r2299 r2305  
    99    private final List<Long> nodes = new ArrayList<Long>();
    1010
     11    public WayData() {
     12
     13    }
     14
     15    public WayData(WayData data) {
     16        super(data);
     17        nodes.addAll(data.getNodes());
     18    }
     19
    1120    public List<Long> getNodes() {
    1221        return nodes;
     22    }
     23
     24    @Override
     25    public WayData makeCopy() {
     26        return new WayData(this);
     27    }
     28
     29    @Override
     30    public OsmPrimitive makePrimitive(DataSet dataSet) {
     31        return new Way(this, dataSet);
    1332    }
    1433
Note: See TracChangeset for help on using the changeset viewer.