Changeset 1078 in josm for trunk/src/org


Ignore:
Timestamp:
2008-11-14T01:09:29+01:00 (15 years ago)
Author:
framm
Message:
  • If you have "display the boundary of downloaded data" enabled you will now, instead of various yellow rectangles, find the non-downloaded area hatched, and the downloaded area clear. Please report if this slows down things or is otherwise undesirable.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r999 r1078  
    1010import java.awt.Component;
    1111import java.awt.Graphics;
     12import java.awt.Graphics2D;
    1213import java.awt.GridBagLayout;
    1314import java.awt.Point;
     15import java.awt.Rectangle;
     16import java.awt.TexturePaint;
    1417import java.awt.event.ActionEvent;
     18import java.awt.geom.Area;
     19import java.awt.image.BufferedImage;
    1520import java.io.File;
    1621import java.util.Collection;
     
    6671public class OsmDataLayer extends Layer {
    6772
    68         public final static class DataCountVisitor implements Visitor {
    69                 public final int[] normal = new int[3];         
    70                 public final int[] deleted = new int[3];
    71                 public final String[] names = {"node", "way", "relation"};
    72 
    73                 private void inc(final OsmPrimitive osm, final int i) {
    74                         normal[i]++;
    75                         if (osm.deleted)
    76                                 deleted[i]++;
    77                 }
    78 
    79                 public void visit(final Node n) {
    80                         inc(n, 0);
    81                 }
    82 
    83                 public void visit(final Way w) {
    84                         inc(w, 1);
    85                 }
    86                 public void visit(final Relation w) {
    87                         inc(w, 2);
    88                 }
    89         }
    90 
    91         public interface ModifiedChangedListener {
    92                 void modifiedChanged(boolean value, OsmDataLayer source);
    93         }
    94         public interface CommandQueueListener {
    95                 void commandChanged(int queueSize, int redoSize);
    96         }
    97 
    98         /**
    99          * @deprecated Use Main.main.undoRedo.add(...) instead.
    100          */
    101         @Deprecated public void add(final Command c) {
    102                 Main.main.undoRedo.add(c);
    103         }
    104 
    105         /**
    106          * The data behind this layer.
    107          */
    108         public final DataSet data;
    109 
    110         /**
    111          * Whether the data of this layer was modified during the session.
    112          */
    113         private boolean modified = false;
    114         /**
    115          * Whether the data was modified due an upload of the data to the server.
    116          */
    117         public boolean uploadedModified = false;
    118 
    119         public final LinkedList<ModifiedChangedListener> listenerModified = new LinkedList<ModifiedChangedListener>();
    120         public final LinkedList<DataChangeListener> listenerDataChanged = new LinkedList<DataChangeListener>();
    121 
    122         /**
    123          * Construct a OsmDataLayer.
    124          */
    125         public OsmDataLayer(final DataSet data, final String name, final File associatedFile) {
    126                 super(name);
    127                 this.data = data;
    128                 this.associatedFile = associatedFile;
    129         }
    130 
    131         /**
    132          * TODO: @return Return a dynamic drawn icon of the map data. The icon is
    133          *              updated by a background thread to not disturb the running programm.
    134          */
    135         @Override public Icon getIcon() {
    136                 return ImageProvider.get("layer", "osmdata_small");
    137         }
    138 
    139         /**
    140          * Draw all primitives in this layer but do not draw modified ones (they
    141          * are drawn by the edit layer).
    142          * Draw nodes last to overlap the ways they belong to.
    143          */
    144         @Override public void paint(final Graphics g, final MapView mv) {
    145                 boolean inactive = Main.map.mapView.getActiveLayer() != this && Main.pref.getBoolean("draw.data.inactive_color", true);
    146                 boolean virtual = !inactive && Main.map.mapView.useVirtualNodes();
    147                 if (Main.pref.getBoolean("draw.data.downloaded_area", true)) {
    148                         // FIXME this is inefficient; instead a proper polygon has to be built, and instead
    149                         // of drawing the outline, the outlying areas should perhaps be shaded.
    150                         for (DataSource src : data.dataSources) {
    151                                 if (src.bounds != null && !src.bounds.min.equals(src.bounds.max)) {
    152                                         EastNorth en1 = Main.proj.latlon2eastNorth(src.bounds.min);
    153                                         EastNorth en2 = Main.proj.latlon2eastNorth(src.bounds.max);
    154                                         Point p1 = mv.getPoint(en1);
    155                                         Point p2 = mv.getPoint(en2);
    156                                         Color color = inactive ? Main.pref.getColor(marktr("inactive"), Color.DARK_GRAY) :
    157                                                         Main.pref.getColor(marktr("downloaded Area"), Color.YELLOW);
    158                                         g.setColor(color);
    159                                         g.drawRect(Math.min(p1.x,p2.x), Math.min(p1.y, p2.y), Math.abs(p2.x-p1.x), Math.abs(p2.y-p1.y));
    160                                 }
    161                         }
    162                 }
    163                
    164        
    165                 SimplePaintVisitor painter;
    166                 if (Main.pref.getBoolean("draw.wireframe"))
    167                         painter = new SimplePaintVisitor();
    168                 else
    169                         painter = new MapPaintVisitor();
    170                 painter.setGraphics(g);
    171                 painter.setNavigatableComponent(mv);
    172                 painter.inactive = inactive;
    173                 painter.visitAll(data, virtual);
    174                 Main.map.conflictDialog.paintConflicts(g, mv);
    175         }
    176 
    177         @Override public String getToolTipText() {
    178                 String tool = "";
    179                 tool += undeletedSize(data.nodes)+" "+trn("node", "nodes", undeletedSize(data.nodes))+", ";
    180                 tool += undeletedSize(data.ways)+" "+trn("way", "ways", undeletedSize(data.ways));
    181                 if (associatedFile != null)
    182                         tool = "<html>"+tool+"<br>"+associatedFile.getPath()+"</html>";
    183                 return tool;
    184         }
    185 
    186         @Override public void mergeFrom(final Layer from) {
    187                 final MergeVisitor visitor = new MergeVisitor(data,((OsmDataLayer)from).data);
    188                 for (final OsmPrimitive osm : ((OsmDataLayer)from).data.allPrimitives())
    189                         osm.visit(visitor);
    190                 visitor.fixReferences();
    191 
    192                 // copy the merged layer's data source info
    193                 for (DataSource src : ((OsmDataLayer)from).data.dataSources)
    194                         data.dataSources.add(src);
    195                 fireDataChange();
    196                 // repaint to make sure new data is displayed properly.
    197                 Main.map.mapView.repaint();
    198                
    199                 if (visitor.conflicts.isEmpty())
    200                         return;
    201                 final ConflictDialog dlg = Main.map.conflictDialog;
    202                 dlg.add(visitor.conflicts);
    203                 JOptionPane.showMessageDialog(Main.parent,tr("There were conflicts during import."));
    204                 if (!dlg.isVisible())
    205                         dlg.action.actionPerformed(new ActionEvent(this, 0, ""));
    206         }
    207 
    208         @Override public boolean isMergable(final Layer other) {
    209                 return other instanceof OsmDataLayer;
    210         }
    211 
    212         @Override public void visitBoundingBox(final BoundingXYVisitor v) {
    213                 for (final Node n : data.nodes)
    214                         if (!n.deleted && !n.incomplete)
    215                                 v.visit(n);
    216         }
    217 
    218         /**
    219          * Clean out the data behind the layer. This means clearing the redo/undo lists,
    220          * really deleting all deleted objects and reset the modified flags. This is done
    221          * after a successfull upload.
    222          *
    223          * @param processed A list of all objects that were actually uploaded.
    224          *              May be <code>null</code>, which means nothing has been uploaded but
    225          *              saved to disk instead. Note that an empty collection for "processed"
    226          *      means that an upload has been attempted but failed.
    227          */
    228         public void cleanData(final Collection<OsmPrimitive> processed, boolean dataAdded) {
    229 
    230                 // return immediately if an upload attempt failed
    231                 if (processed != null && processed.isEmpty() && !dataAdded)
    232                         return;
    233                
    234                 Main.main.undoRedo.clean();
    235 
    236                 // if uploaded, clean the modified flags as well
    237                 if (processed != null) {
    238                         final Set<OsmPrimitive> processedSet = new HashSet<OsmPrimitive>(processed);
    239                         for (final Iterator<Node> it = data.nodes.iterator(); it.hasNext();)
    240                                 cleanIterator(it, processedSet);
    241                         for (final Iterator<Way> it = data.ways.iterator(); it.hasNext();)
    242                                 cleanIterator(it, processedSet);
    243                         for (final Iterator<Relation> it = data.relations.iterator(); it.hasNext();)
    244                                 cleanIterator(it, processedSet);
    245                 }
    246 
    247                 // update the modified flag
    248                 if (associatedFile != null && processed != null && !dataAdded)
    249                         return; // do nothing when uploading non-harmful changes.
    250 
    251                 // modified if server changed the data (esp. the id).
    252                 uploadedModified = associatedFile != null && processed != null && dataAdded;
    253                 setModified(uploadedModified);
    254         }
    255 
    256         /**
    257          * Clean the modified flag for the given iterator over a collection if it is in the
    258          * list of processed entries.
    259          *
    260          * @param it The iterator to change the modified and remove the items if deleted.
    261          * @param processed A list of all objects that have been successfully progressed.
    262          *              If the object in the iterator is not in the list, nothing will be changed on it.
    263          */
    264         private void cleanIterator(final Iterator<? extends OsmPrimitive> it, final Collection<OsmPrimitive> processed) {
    265                 final OsmPrimitive osm = it.next();
    266                 if (!processed.remove(osm))
    267                         return;
    268                 osm.modified = false;
    269                 if (osm.deleted)
    270                         it.remove();
    271         }
    272 
    273         public boolean isModified() {
    274                 return modified;
    275         }
    276 
    277         public void setModified(final boolean modified) {
    278                 if (modified == this.modified)
    279                         return;
    280                 this.modified = modified;
    281                 for (final ModifiedChangedListener l : listenerModified)
    282                         l.modifiedChanged(modified, this);
    283         }
    284 
    285         /**
    286          * @return The number of not-deleted primitives in the list.
    287          */
    288         private int undeletedSize(final Collection<? extends OsmPrimitive> list) {
    289                 int size = 0;
    290                 for (final OsmPrimitive osm : list)
    291                         if (!osm.deleted)
    292                                 size++;
    293                 return size;
    294         }
    295 
    296         @Override public Object getInfoComponent() {
    297                 final DataCountVisitor counter = new DataCountVisitor();
    298                 for (final OsmPrimitive osm : data.allPrimitives())
    299                         osm.visit(counter);
    300                 final JPanel p = new JPanel(new GridBagLayout());
    301                 p.add(new JLabel(tr("{0} consists of:", name)), GBC.eol());
    302                 for (int i = 0; i < counter.normal.length; ++i) {
    303                         String s = counter.normal[i]+" "+trn(counter.names[i],counter.names[i]+"s",counter.normal[i]);
    304                         if (counter.deleted[i] > 0)
    305                                 s += tr(" ({0} deleted.)",counter.deleted[i]);
    306                         p.add(new JLabel(s, ImageProvider.get("data", counter.names[i]), JLabel.HORIZONTAL), GBC.eop().insets(15,0,0,0));
    307                 }
    308                 return p;
    309         }
    310 
    311         @Override public Component[] getMenuEntries() {
    312                 if (Main.applet) {
    313                         return new Component[]{
    314                                         new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
    315                                         new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
    316                                         new JSeparator(),
    317                                         new JMenuItem(new RenameLayerAction(associatedFile, this)),
    318                                         new JSeparator(),
    319                                         new JMenuItem(new LayerListPopup.InfoAction(this))};
    320                 }
    321                 return new Component[]{
    322                                 new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
    323                                 new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
    324                                 new JSeparator(),
    325                                 new JMenuItem(new SaveAction(this)),
    326                                 new JMenuItem(new SaveAsAction(this)),
    327                                 new JMenuItem(new GpxExportAction(this)),
    328                                 new JMenuItem(new ConvertToGpxLayerAction()),
    329                                 new JSeparator(),
    330                                 new JMenuItem(new RenameLayerAction(associatedFile, this)),
    331                                 new JSeparator(),
    332                                 new JMenuItem(new LayerListPopup.InfoAction(this))};
    333         }
    334 
    335         public void fireDataChange() {
    336                 for (DataChangeListener dcl : listenerDataChanged) {
    337                         dcl.dataChanged(this);
    338                 }
    339         }
    340 
    341         public static GpxData toGpxData(DataSet data) {
    342                 GpxData gpxData = new GpxData();
    343                 HashSet<Node> doneNodes = new HashSet<Node>();
    344                 for (Way w : data.ways) {
    345                         if (w.incomplete || w.deleted) continue;
    346                         GpxTrack trk = new GpxTrack();
    347                         gpxData.tracks.add(trk);
    348 
    349                         if (w.get("name") != null)
    350                                 trk.attr.put("name", w.get("name"));
    351 
    352                         ArrayList<WayPoint> trkseg = null;
    353                         for (Node n : w.nodes) {
    354                                 if (n.incomplete || n.deleted) {
    355                                         trkseg = null;
    356                                         continue;
    357                                 }
    358                                 if (trkseg == null) {
    359                                         trkseg = new ArrayList<WayPoint>();
    360                                         trk.trackSegs.add(trkseg);
    361                                 }
    362                                 if (!n.tagged) {
    363                                         doneNodes.add(n);
    364                                 }
    365                                 WayPoint wpt = new WayPoint(n.coor);
    366                                 if (n.timestamp != null)
    367                                 {
    368                                         wpt.attr.put("time", n.timestamp);
    369                                         wpt.setTime();
    370                                 }
    371                                 trkseg.add(wpt);
    372                         }
    373                 }
    374                
    375                 // what is this loop meant to do? it creates waypoints but never
    376                 // records them?
    377                 for (Node n : data.nodes) {
    378                         if (n.incomplete || n.deleted || doneNodes.contains(n)) continue;
    379                         WayPoint wpt = new WayPoint(n.coor);
    380                         if (n.timestamp != null) {
    381                                 wpt.attr.put("time", n.timestamp);
    382                                 wpt.setTime();
    383                         }
    384                         if (n.keys != null && n.keys.containsKey("name")) {
    385                                 wpt.attr.put("name", n.keys.get("name"));
    386                         }
    387                 }
    388                 return gpxData;
    389         }
    390 
    391         public GpxData toGpxData() {
    392                 return toGpxData(data);
    393         }
    394 
    395         public class ConvertToGpxLayerAction extends AbstractAction {
    396                 public ConvertToGpxLayerAction() {
    397                         super(tr("Convert to GPX layer"), ImageProvider.get("converttogpx"));
    398                 }
    399                 public void actionPerformed(ActionEvent e) {
    400                         Main.main.addLayer(new GpxLayer(toGpxData(), tr("Converted from: {0}", name)));
    401                         Main.main.removeLayer(OsmDataLayer.this);
    402                 }
    403         }
     73    public final static class DataCountVisitor implements Visitor {
     74        public final int[] normal = new int[3];       
     75        public final int[] deleted = new int[3];
     76        public final String[] names = {"node", "way", "relation"};
     77
     78        private void inc(final OsmPrimitive osm, final int i) {
     79            normal[i]++;
     80            if (osm.deleted)
     81                deleted[i]++;
     82        }
     83
     84        public void visit(final Node n) {
     85            inc(n, 0);
     86        }
     87
     88        public void visit(final Way w) {
     89            inc(w, 1);
     90        }
     91        public void visit(final Relation w) {
     92            inc(w, 2);
     93        }
     94    }
     95
     96    public interface ModifiedChangedListener {
     97        void modifiedChanged(boolean value, OsmDataLayer source);
     98    }
     99    public interface CommandQueueListener {
     100        void commandChanged(int queueSize, int redoSize);
     101    }
     102
     103    /**
     104     * @deprecated Use Main.main.undoRedo.add(...) instead.
     105     */
     106    @Deprecated public void add(final Command c) {
     107        Main.main.undoRedo.add(c);
     108    }
     109
     110    /**
     111     * The data behind this layer.
     112     */
     113    public final DataSet data;
     114
     115    /**
     116     * Whether the data of this layer was modified during the session.
     117     */
     118    private boolean modified = false;
     119    /**
     120     * Whether the data was modified due an upload of the data to the server.
     121     */
     122    public boolean uploadedModified = false;
     123
     124    public final LinkedList<ModifiedChangedListener> listenerModified = new LinkedList<ModifiedChangedListener>();
     125    public final LinkedList<DataChangeListener> listenerDataChanged = new LinkedList<DataChangeListener>();
     126
     127    /**
     128     * a paint texture for non-downloaded area
     129     */
     130    private TexturePaint hatched;
     131   
     132    /**
     133     * Construct a OsmDataLayer.
     134     */
     135    public OsmDataLayer(final DataSet data, final String name, final File associatedFile) {
     136        super(name);
     137        this.data = data;
     138        this.associatedFile = associatedFile;
     139       
     140        BufferedImage bi = new BufferedImage(15, 15, BufferedImage.TYPE_INT_RGB);
     141        Graphics2D big = bi.createGraphics();
     142        big.setColor(Main.pref.getColor(marktr("background"), Color.BLACK));
     143        big.fillRect(0,0,15,15);
     144        big.setColor(Main.pref.getColor(marktr("downloaded Area"), Color.YELLOW));
     145        big.drawLine(0,15,15,0);
     146        Rectangle r = new Rectangle(0, 0, 15,15);
     147        hatched = new TexturePaint(bi, r);
     148    }
     149
     150    /**
     151     * TODO: @return Return a dynamic drawn icon of the map data. The icon is
     152     *         updated by a background thread to not disturb the running programm.
     153     */
     154    @Override public Icon getIcon() {
     155        return ImageProvider.get("layer", "osmdata_small");
     156    }
     157
     158    /**
     159     * Draw all primitives in this layer but do not draw modified ones (they
     160     * are drawn by the edit layer).
     161     * Draw nodes last to overlap the ways they belong to.
     162     */
     163    @Override public void paint(final Graphics g, final MapView mv) {
     164        boolean inactive = Main.map.mapView.getActiveLayer() != this && Main.pref.getBoolean("draw.data.inactive_color", true);
     165        boolean virtual = !inactive && Main.map.mapView.useVirtualNodes();
     166        if (Main.pref.getBoolean("draw.data.downloaded_area", true)) {
     167            // initialize area with current viewport
     168            Area b = new Area(Main.map.mapView.getBounds());
     169
     170            // now succesively subtract downloaded areas
     171            for (DataSource src : data.dataSources) {
     172                if (src.bounds != null && !src.bounds.min.equals(src.bounds.max)) {
     173                    EastNorth en1 = Main.proj.latlon2eastNorth(src.bounds.min);
     174                    EastNorth en2 = Main.proj.latlon2eastNorth(src.bounds.max);
     175                    Point p1 = mv.getPoint(en1);
     176                    Point p2 = mv.getPoint(en2);
     177                    Rectangle r = new Rectangle(Math.min(p1.x, p2.x),Math.min(p1.y, p2.y),Math.abs(p2.x-p1.x),Math.abs(p2.y-p1.y));
     178                    b.subtract(new Area(r));
     179                }
     180            }
     181           
     182            // paint remainder
     183            ((Graphics2D)g).setPaint(hatched);
     184            ((Graphics2D)g).fill(b);
     185        }
     186   
     187        SimplePaintVisitor painter;
     188        if (Main.pref.getBoolean("draw.wireframe"))
     189            painter = new SimplePaintVisitor();
     190        else
     191            painter = new MapPaintVisitor();
     192        painter.setGraphics(g);
     193        painter.setNavigatableComponent(mv);
     194        painter.inactive = inactive;
     195        painter.visitAll(data, virtual);
     196        Main.map.conflictDialog.paintConflicts(g, mv);
     197    }
     198
     199    @Override public String getToolTipText() {
     200        String tool = "";
     201        tool += undeletedSize(data.nodes)+" "+trn("node", "nodes", undeletedSize(data.nodes))+", ";
     202        tool += undeletedSize(data.ways)+" "+trn("way", "ways", undeletedSize(data.ways));
     203        if (associatedFile != null)
     204            tool = "<html>"+tool+"<br>"+associatedFile.getPath()+"</html>";
     205        return tool;
     206    }
     207
     208    @Override public void mergeFrom(final Layer from) {
     209        final MergeVisitor visitor = new MergeVisitor(data,((OsmDataLayer)from).data);
     210        for (final OsmPrimitive osm : ((OsmDataLayer)from).data.allPrimitives())
     211            osm.visit(visitor);
     212        visitor.fixReferences();
     213
     214        // copy the merged layer's data source info
     215        for (DataSource src : ((OsmDataLayer)from).data.dataSources)
     216            data.dataSources.add(src);
     217        fireDataChange();
     218        // repaint to make sure new data is displayed properly.
     219        Main.map.mapView.repaint();
     220       
     221        if (visitor.conflicts.isEmpty())
     222            return;
     223        final ConflictDialog dlg = Main.map.conflictDialog;
     224        dlg.add(visitor.conflicts);
     225        JOptionPane.showMessageDialog(Main.parent,tr("There were conflicts during import."));
     226        if (!dlg.isVisible())
     227            dlg.action.actionPerformed(new ActionEvent(this, 0, ""));
     228    }
     229
     230    @Override public boolean isMergable(final Layer other) {
     231        return other instanceof OsmDataLayer;
     232    }
     233
     234    @Override public void visitBoundingBox(final BoundingXYVisitor v) {
     235        for (final Node n : data.nodes)
     236            if (!n.deleted && !n.incomplete)
     237                v.visit(n);
     238    }
     239
     240    /**
     241     * Clean out the data behind the layer. This means clearing the redo/undo lists,
     242     * really deleting all deleted objects and reset the modified flags. This is done
     243     * after a successfull upload.
     244     *
     245     * @param processed A list of all objects that were actually uploaded.
     246     *         May be <code>null</code>, which means nothing has been uploaded but
     247     *         saved to disk instead. Note that an empty collection for "processed"
     248     *      means that an upload has been attempted but failed.
     249     */
     250    public void cleanData(final Collection<OsmPrimitive> processed, boolean dataAdded) {
     251
     252        // return immediately if an upload attempt failed
     253        if (processed != null && processed.isEmpty() && !dataAdded)
     254            return;
     255       
     256        Main.main.undoRedo.clean();
     257
     258        // if uploaded, clean the modified flags as well
     259        if (processed != null) {
     260            final Set<OsmPrimitive> processedSet = new HashSet<OsmPrimitive>(processed);
     261            for (final Iterator<Node> it = data.nodes.iterator(); it.hasNext();)
     262                cleanIterator(it, processedSet);
     263            for (final Iterator<Way> it = data.ways.iterator(); it.hasNext();)
     264                cleanIterator(it, processedSet);
     265            for (final Iterator<Relation> it = data.relations.iterator(); it.hasNext();)
     266                cleanIterator(it, processedSet);
     267        }
     268
     269        // update the modified flag
     270        if (associatedFile != null && processed != null && !dataAdded)
     271            return; // do nothing when uploading non-harmful changes.
     272
     273        // modified if server changed the data (esp. the id).
     274        uploadedModified = associatedFile != null && processed != null && dataAdded;
     275        setModified(uploadedModified);
     276    }
     277
     278    /**
     279     * Clean the modified flag for the given iterator over a collection if it is in the
     280     * list of processed entries.
     281     *
     282     * @param it The iterator to change the modified and remove the items if deleted.
     283     * @param processed A list of all objects that have been successfully progressed.
     284     *         If the object in the iterator is not in the list, nothing will be changed on it.
     285     */
     286    private void cleanIterator(final Iterator<? extends OsmPrimitive> it, final Collection<OsmPrimitive> processed) {
     287        final OsmPrimitive osm = it.next();
     288        if (!processed.remove(osm))
     289            return;
     290        osm.modified = false;
     291        if (osm.deleted)
     292            it.remove();
     293    }
     294
     295    public boolean isModified() {
     296        return modified;
     297    }
     298
     299    public void setModified(final boolean modified) {
     300        if (modified == this.modified)
     301            return;
     302        this.modified = modified;
     303        for (final ModifiedChangedListener l : listenerModified)
     304            l.modifiedChanged(modified, this);
     305    }
     306
     307    /**
     308     * @return The number of not-deleted primitives in the list.
     309     */
     310    private int undeletedSize(final Collection<? extends OsmPrimitive> list) {
     311        int size = 0;
     312        for (final OsmPrimitive osm : list)
     313            if (!osm.deleted)
     314                size++;
     315        return size;
     316    }
     317
     318    @Override public Object getInfoComponent() {
     319        final DataCountVisitor counter = new DataCountVisitor();
     320        for (final OsmPrimitive osm : data.allPrimitives())
     321            osm.visit(counter);
     322        final JPanel p = new JPanel(new GridBagLayout());
     323        p.add(new JLabel(tr("{0} consists of:", name)), GBC.eol());
     324        for (int i = 0; i < counter.normal.length; ++i) {
     325            String s = counter.normal[i]+" "+trn(counter.names[i],counter.names[i]+"s",counter.normal[i]);
     326            if (counter.deleted[i] > 0)
     327                s += tr(" ({0} deleted.)",counter.deleted[i]);
     328            p.add(new JLabel(s, ImageProvider.get("data", counter.names[i]), JLabel.HORIZONTAL), GBC.eop().insets(15,0,0,0));
     329        }
     330        return p;
     331    }
     332
     333    @Override public Component[] getMenuEntries() {
     334        if (Main.applet) {
     335            return new Component[]{
     336                    new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
     337                    new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
     338                    new JSeparator(),
     339                    new JMenuItem(new RenameLayerAction(associatedFile, this)),
     340                    new JSeparator(),
     341                    new JMenuItem(new LayerListPopup.InfoAction(this))};
     342        }
     343        return new Component[]{
     344                new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)),
     345                new JMenuItem(new LayerListDialog.DeleteLayerAction(this)),
     346                new JSeparator(),
     347                new JMenuItem(new SaveAction(this)),
     348                new JMenuItem(new SaveAsAction(this)),
     349                new JMenuItem(new GpxExportAction(this)),
     350                new JMenuItem(new ConvertToGpxLayerAction()),
     351                new JSeparator(),
     352                new JMenuItem(new RenameLayerAction(associatedFile, this)),
     353                new JSeparator(),
     354                new JMenuItem(new LayerListPopup.InfoAction(this))};
     355    }
     356
     357    public void fireDataChange() {
     358        for (DataChangeListener dcl : listenerDataChanged) {
     359            dcl.dataChanged(this);
     360        }
     361    }
     362
     363    public static GpxData toGpxData(DataSet data) {
     364        GpxData gpxData = new GpxData();
     365        HashSet<Node> doneNodes = new HashSet<Node>();
     366        for (Way w : data.ways) {
     367            if (w.incomplete || w.deleted) continue;
     368            GpxTrack trk = new GpxTrack();
     369            gpxData.tracks.add(trk);
     370
     371            if (w.get("name") != null)
     372                trk.attr.put("name", w.get("name"));
     373
     374            ArrayList<WayPoint> trkseg = null;
     375            for (Node n : w.nodes) {
     376                if (n.incomplete || n.deleted) {
     377                    trkseg = null;
     378                    continue;
     379                }
     380                if (trkseg == null) {
     381                    trkseg = new ArrayList<WayPoint>();
     382                    trk.trackSegs.add(trkseg);
     383                }
     384                if (!n.tagged) {
     385                    doneNodes.add(n);
     386                }
     387                WayPoint wpt = new WayPoint(n.coor);
     388                if (n.timestamp != null)
     389                {
     390                    wpt.attr.put("time", n.timestamp);
     391                    wpt.setTime();
     392                }
     393                trkseg.add(wpt);
     394            }
     395        }
     396       
     397        // what is this loop meant to do? it creates waypoints but never
     398        // records them?
     399        for (Node n : data.nodes) {
     400            if (n.incomplete || n.deleted || doneNodes.contains(n)) continue;
     401            WayPoint wpt = new WayPoint(n.coor);
     402            if (n.timestamp != null) {
     403                wpt.attr.put("time", n.timestamp);
     404                wpt.setTime();
     405            }
     406            if (n.keys != null && n.keys.containsKey("name")) {
     407                wpt.attr.put("name", n.keys.get("name"));
     408            }
     409        }
     410        return gpxData;
     411    }
     412
     413    public GpxData toGpxData() {
     414        return toGpxData(data);
     415    }
     416
     417    public class ConvertToGpxLayerAction extends AbstractAction {
     418        public ConvertToGpxLayerAction() {
     419            super(tr("Convert to GPX layer"), ImageProvider.get("converttogpx"));
     420        }
     421        public void actionPerformed(ActionEvent e) {
     422            Main.main.addLayer(new GpxLayer(toGpxData(), tr("Converted from: {0}", name)));
     423            Main.main.removeLayer(OsmDataLayer.this);
     424        }
     425    }
    404426
    405427    public boolean containsPoint(LatLon coor)
Note: See TracChangeset for help on using the changeset viewer.