Changeset 18287 in josm


Ignore:
Timestamp:
2021-10-19T01:26:15+02:00 (3 months ago)
Author:
Don-vip
Message:

fix #20913 - fix handling of GPX files in sessions (patch by Bjoeni)

  • revert r17659 (except for unit tests) - see #20233
    • don't save GPX track and marker colors in session file anymore, but in the GPX files as extensions (like before)
    • don't ask to save unmodified GPX file
    • don't override global color settings when individual track doesn't have a color
  • ask user to save changes to GPX file when any drawing settings or marker colors have changed (currently only happens for track colors)
  • save marker color values to session even when corresponding GPX layer has already been deleted
  • save alpha values for GPX marker colors
  • added explanation to the "overwrite GPX file" dialog
  • inform user if not all files referenced by the session file are saved yet
  • allow user to save all files that are not included in the *.jos/*.joz but are only referenced in the session file
  • display * next to GPX layers that need to be saved (move isDirty() logic from OsmDataLayer to AbstractModifiableLayer)
Location:
trunk
Files:
3 added
24 edited

Legend:

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

    r16913 r18287  
    1515import javax.swing.SwingConstants;
    1616
    17 import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener;
     17import org.openstreetmap.josm.data.gpx.GpxConstants;
    1818import org.openstreetmap.josm.gui.ExtendedDialog;
    1919import org.openstreetmap.josm.gui.MainApplication;
     20import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
    2021import org.openstreetmap.josm.gui.layer.GpxLayer;
    2122import org.openstreetmap.josm.gui.layer.Layer;
    2223import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
    2324import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
    24 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2525import org.openstreetmap.josm.gui.layer.SaveToFile;
    2626import org.openstreetmap.josm.gui.util.GuiHelper;
     
    3838
    3939    private final PropertyChangeListener updateOnRequireSaveChange = evt -> {
    40         if (OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP.equals(evt.getPropertyName())) {
     40        if (AbstractModifiableLayer.REQUIRES_SAVE_TO_DISK_PROP.equals(evt.getPropertyName())) {
    4141            updateEnabledState();
    4242        }
    4343    };
    44 
    45     private final GpxDataChangeListener updateOnRequireSaveChangeGpx = evt -> updateEnabledState();
    4644
    4745    /**
     
    6967            public void layerAdded(LayerAddEvent e) {
    7068                Layer l = e.getAddedLayer();
    71                 if (l instanceof OsmDataLayer) {
     69                if (l instanceof AbstractModifiableLayer) {
    7270                    l.addPropertyChangeListener(updateOnRequireSaveChange);
    73                 }
    74                 if (l instanceof GpxLayer) {
    75                     ((GpxLayer) l).data.addWeakChangeListener(updateOnRequireSaveChangeGpx);
    7671                }
    7772                super.layerAdded(e);
     
    8176            public void layerRemoving(LayerRemoveEvent e) {
    8277                Layer l = e.getRemovedLayer();
    83                 if (l instanceof OsmDataLayer) {
     78                if (l instanceof AbstractModifiableLayer) {
    8479                    l.removePropertyChangeListener(updateOnRequireSaveChange);
    85                 }
    86                 if (l instanceof GpxLayer) {
    87                     ((GpxLayer) l).data.removeChangeListener(updateOnRequireSaveChangeGpx);
    8880                }
    8981                super.layerRemoving(e);
     
    114106
    115107        // Ask for overwrite in case of GpxLayer
    116         if (f != null && layer instanceof GpxLayer && !Config.getPref().getBoolean("gpx.export.overwrite", false)) {
     108        if (f != null
     109                && layer instanceof GpxLayer
     110                && (((GpxLayer) layer).data == null
     111                || !GpxConstants.JOSM_CREATOR_NAME.equals(((GpxLayer) layer).data.creator))
     112                && !Config.getPref().getBoolean("gpx.export.overwrite", false)) {
     113
    117114            JPanel p = new JPanel(new GridBagLayout());
    118             JLabel label = new JLabel(tr("File {0} exists. Overwrite?", f.getName()));
     115            JLabel label = new JLabel("<html>"
     116                    + tr("The file \"{0}\" will be modified.<br>Would you like to overwrite the existing file?", f.getName())
     117                    + "</html>");
    119118            label.setHorizontalAlignment(SwingConstants.CENTER);
    120             JCheckBox remember = new JCheckBox(tr("Remember choice"));
     119            JCheckBox remember = new JCheckBox(tr("Always overwrite GPX files without asking"));
    121120            remember.setHorizontalAlignment(SwingConstants.CENTER);
    122121            p.add(label, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 10));
     
    125124                    MainApplication.getMainFrame(),
    126125                    tr("Overwrite"),
    127                     tr("Overwrite"), tr("Cancel"))
    128                 .setButtonIcons("save_as", "cancel")
     126                    tr("Overwrite"), tr("Save As..."), tr("Cancel"))
     127                .setButtonIcons("save", "save_as", "cancel")
    129128                .setContent(p);
    130             if (dialog.showDialog().getValue() != 1) {
     129            int val = dialog.showDialog().getValue();
     130            if (val == 1) {
     131                Config.getPref().putBoolean("gpx.export.overwrite", remember.isSelected());
     132            } else if (val == 2) {
    131133                f = null;
    132             } else if (remember.isSelected()) {
    133                 Config.getPref().putBoolean("gpx.export.overwrite", true);
     134            } else {
     135                return null;
    134136            }
    135137        }
  • trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java

    r18135 r18287  
    2020import java.util.Set;
    2121import java.util.stream.Collectors;
     22import java.util.stream.Stream;
    2223
    2324import javax.swing.BorderFactory;
     
    3334import javax.swing.filechooser.FileFilter;
    3435
     36import org.openstreetmap.josm.data.preferences.BooleanProperty;
    3537import org.openstreetmap.josm.gui.ExtendedDialog;
    3638import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     
    3941import org.openstreetmap.josm.gui.MapFrameListener;
    4042import org.openstreetmap.josm.gui.Notification;
     43import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
    4144import org.openstreetmap.josm.gui.layer.Layer;
    4245import org.openstreetmap.josm.gui.util.WindowGeometry;
     
    6164    private transient MultiMap<Layer, Layer> dependencies;
    6265
     66    private static final BooleanProperty SAVE_LOCAL_FILES_PROPERTY = new BooleanProperty("session.savelocal", true);
     67
    6368    /**
    6469     * Constructs a new {@code SessionSaveAsAction}.
     
    158163                .filter(layer -> exporters.get(layer) != null && exporters.get(layer).shallExport())
    159164                .collect(Collectors.toList());
     165
     166        Stream<Layer> layersToSaveStream = layersOut.stream()
     167                .filter(layer -> layer.isSavable()
     168                        && layer instanceof AbstractModifiableLayer
     169                        && ((AbstractModifiableLayer) layer).requiresSaveToFile()
     170                        && exporters.get(layer) != null
     171                        && !exporters.get(layer).requiresZip());
     172
     173        if (SAVE_LOCAL_FILES_PROPERTY.get()) {
     174            // individual files must be saved before the session file as the location may change
     175            if (layersToSaveStream
     176                .map(layer -> SaveAction.getInstance().doSave(layer, true))
     177                .collect(Collectors.toList()) // force evaluation of all elements
     178                .contains(false)) {
     179
     180                new Notification(tr("Not all local files referenced by the session file could be saved."
     181                        + "<br>Make sure you save them before closing JOSM."))
     182                    .setIcon(JOptionPane.WARNING_MESSAGE)
     183                    .setDuration(Notification.TIME_LONG)
     184                    .show();
     185            }
     186        } else if (layersToSaveStream.anyMatch(l -> true)) {
     187            new Notification(tr("Not all local files referenced by the session file are saved yet."
     188                    + "<br>Make sure you save them before closing JOSM."))
     189                .setIcon(JOptionPane.INFORMATION_MESSAGE)
     190                .setDuration(Notification.TIME_LONG)
     191                .show();
     192        }
    160193
    161194        int active = -1;
     
    251284
    252285        protected final Component build() {
     286            JPanel op = new JPanel(new GridBagLayout());
    253287            JPanel ip = new JPanel(new GridBagLayout());
    254288            for (Layer layer : layers) {
     
    273307            final JTabbedPane tabs = new JTabbedPane();
    274308            tabs.addTab(tr("Layers"), p);
    275             return tabs;
     309            op.add(tabs, GBC.eol().fill());
     310            JCheckBox chkSaveLocal = new JCheckBox(tr("Save all local files to disk"), SAVE_LOCAL_FILES_PROPERTY.get());
     311            chkSaveLocal.addChangeListener(l -> {
     312                SAVE_LOCAL_FILES_PROPERTY.put(chkSaveLocal.isSelected());
     313            });
     314            op.add(chkSaveLocal);
     315            return op;
    276316        }
    277317
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxConstants.java

    r17333 r18287  
    9999     */
    100100    String META_BOUNDS = META_PREFIX + "bounds";
     101
     102    /**
     103     * The creator element that will be written when exporting a GPX file
     104     * @since 18287
     105     */
     106    String JOSM_CREATOR_NAME = "JOSM GPX export";
    101107
    102108    /**
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java

    r18207 r18287  
    4444 * @author Raphael Mack &lt;ramack@raphael-mack.de&gt;
    4545 */
    46 public class GpxData extends WithAttributes implements Data {
     46public class GpxData extends WithAttributes implements Data, IGpxLayerPrefs {
    4747
    4848    /**
     
    6868     */
    6969    public boolean fromServer;
     70    /**
     71     * A boolean flag indicating if the data was read from a session file.
     72     * @since 18287
     73     */
     74    public boolean fromSession;
    7075
    7176    /**
     
    10171022    }
    10181023
    1019     /**
    1020      * The layer specific prefs formerly saved in the preferences, e.g. drawing options.
    1021      * NOT the track specific settings (e.g. color, width)
    1022      * @return Modifiable map
    1023      * @since 15496
    1024      */
     1024    @Override
    10251025    public Map<String, String> getLayerPrefs() {
    10261026        return layerPrefs;
     
    11371137        } else {
    11381138            if (setModified) {
    1139                 modified = true;
     1139                setModified(true);
    11401140            }
    11411141            if (listeners.hasListeners()) {
     
    11791179         */
    11801180        void gpxDataChanged(GpxDataChangeEvent e);
     1181
     1182        /**
     1183         * Called when the modified state of the data changed
     1184         * @param modified the new modified state
     1185         */
     1186        default void modifiedStateChanged(boolean modified) {
     1187            // Override if needed
     1188        }
    11811189    }
    11821190
     
    12171225     * @since 15496
    12181226     */
     1227    @Override
    12191228    public void setModified(boolean value) {
    1220         modified = value;
     1229        if (!initializing && modified != value) {
     1230            modified = value;
     1231            if (listeners.hasListeners()) {
     1232                listeners.fireEvent(l -> l.modifiedStateChanged(modified));
     1233            }
     1234        }
    12211235    }
    12221236
  • trunk/src/org/openstreetmap/josm/gui/MainFrame.java

    r17730 r18287  
    2626
    2727import org.openstreetmap.josm.data.UserIdentityManager;
     28import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
    2829import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
    2930import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
     
    4647
    4748    private final transient PropertyChangeListener updateTitleOnSaveChange = evt -> {
    48         if (evt.getPropertyName().equals(OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP)
     49        if (evt.getPropertyName().equals(AbstractModifiableLayer.REQUIRES_SAVE_TO_DISK_PROP)
    4950                || evt.getPropertyName().equals(OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP)) {
    50             OsmDataLayer layer = (OsmDataLayer) evt.getSource();
     51            AbstractModifiableLayer layer = (AbstractModifiableLayer) evt.getSource();
    5152            onLayerChange(layer);
    5253        }
     
    187188    }
    188189
    189     private void onLayerChange(OsmDataLayer layer) {
     190    private void onLayerChange(AbstractModifiableLayer layer) {
    190191        if (layer == MainApplication.getLayerManager().getEditLayer()) {
    191192            refreshTitle();
  • trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxImporter.java

    r16877 r18287  
    148148            if (data.gpxLayer != null) {
    149149                MainApplication.getLayerManager().addLayer(data.gpxLayer);
     150                MainApplication.getLayerManager().setActiveLayer(data.gpxLayer);
    150151            }
    151152            data.postLayerTask.run();
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java

    r16553 r18287  
    1616 */
    1717public abstract class AbstractModifiableLayer extends Layer implements DownloadFromServer, UploadToServer, SaveToFile, Lockable {
     18
     19    /**
     20     * Property used to know if this layer has to be saved on disk.
     21     * @since 18287
     22     */
     23    public static final String REQUIRES_SAVE_TO_DISK_PROP = AbstractModifiableLayer.class.getName() + ".requiresSaveToDisk";
     24    static final String IS_DIRTY_SYMBOL = "*";
    1825
    1926    /**
     
    5360        // Override if needed
    5461        return false;
     62    }
     63
     64    /**
     65     * Determines if this layer is "dirty", i.e. requires save or upload
     66     * @return if this layer is "dirty"
     67     * @since 18287
     68     */
     69    public boolean isDirty() {
     70        // Override if needed
     71        return requiresSaveToFile() || (requiresUploadToServer() && !isUploadDiscouraged());
    5572    }
    5673
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r18078 r18287  
    3434import org.openstreetmap.josm.data.gpx.GpxConstants;
    3535import org.openstreetmap.josm.data.gpx.GpxData;
     36import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeEvent;
     37import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener;
    3638import org.openstreetmap.josm.data.gpx.GpxDataContainer;
    37 import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener;
    3839import org.openstreetmap.josm.data.gpx.IGpxTrack;
    3940import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
     
    5960import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
    6061import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
     62import org.openstreetmap.josm.gui.util.GuiHelper;
    6163import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    6264import org.openstreetmap.josm.tools.ImageProvider;
     
    8688     * Added as field to be kept as reference.
    8789     */
    88     private final GpxDataChangeListener dataChangeListener = e -> this.invalidate();
     90    private final GpxDataChangeListener dataChangeListener = new GpxDataChangeListener() {
     91        @Override
     92        public void gpxDataChanged(GpxDataChangeEvent e) {
     93            invalidate();
     94        }
     95
     96        @Override
     97        public void modifiedStateChanged(boolean modified) {
     98            GuiHelper.runInEDT(() -> propertyChangeSupport.firePropertyChange(REQUIRES_SAVE_TO_DISK_PROP, !modified, modified));
     99        }
     100    };
    89101    /**
    90102     * The MarkerLayer imported from the same file.
     
    376388
    377389    @Override
     390    public String getLabel() {
     391        return isDirty() ? super.getLabel() + ' ' + IS_DIRTY_SYMBOL : super.getLabel();
     392    }
     393
     394    @Override
    378395    public void visitBoundingBox(BoundingXYVisitor v) {
    379396        if (data != null) {
     
    555572    @Override
    556573    public boolean requiresSaveToFile() {
    557         return isModified() && isLocalFile();
     574        return data != null && isModified() && (isLocalFile() || data.fromSession);
    558575    }
    559576
     
    622639    @Override
    623640    public synchronized void destroy() {
     641        if (linkedMarkerLayer != null && MainApplication.getLayerManager().containsLayer(linkedMarkerLayer)) {
     642            linkedMarkerLayer.data.transferLayerPrefs(data.getLayerPrefs());
     643        }
    624644        data.clear();
    625645        data = null;
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r18233 r18287  
    149149    // U+2205 EMPTY SET
    150150    private static final String IS_EMPTY_SYMBOL = "\u2205";
    151     private static final String IS_DIRTY_SYMBOL = "*";
    152     /** Property used to know if this layer has to be saved on disk */
    153     public static final String REQUIRES_SAVE_TO_DISK_PROP = OsmDataLayer.class.getName() + ".requiresSaveToDisk";
    154151    /** Property used to know if this layer has to be uploaded */
    155152    public static final String REQUIRES_UPLOAD_TO_SERVER_PROP = OsmDataLayer.class.getName() + ".requiresUploadToServer";
     
    10731070    }
    10741071
    1075     /**
    1076      * Determines if this layer is "dirty", i.e., requires save or upload
    1077      * @return if this layer is "dirty"
    1078      * @since 17626
    1079      */
    1080     public boolean isDirty() {
    1081         return requiresSaveToFile() || (requiresUploadToServer() && !isUploadDiscouraged());
    1082     }
    1083 
    10841072    @Override
    10851073    public String getLabel() {
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java

    r17047 r18287  
    190190    public WayPoint convertToWayPoint() {
    191191        WayPoint wpt = new WayPoint(getCoor());
    192         wpt.setTimeInMillis((long) (time * 1000));
     192        if (time > 0d) {
     193            wpt.setTimeInMillis((long) (time * 1000));
     194        }
    193195        if (text != null) {
    194196            wpt.getExtensions().add("josm", "text", text);
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java

    r17047 r18287  
    2121import java.util.Collection;
    2222import java.util.Comparator;
     23import java.util.HashMap;
    2324import java.util.List;
     25import java.util.Map;
    2426import java.util.Optional;
    2527
     
    3840import org.openstreetmap.josm.data.gpx.GpxExtension;
    3941import org.openstreetmap.josm.data.gpx.GpxLink;
     42import org.openstreetmap.josm.data.gpx.IGpxLayerPrefs;
    4043import org.openstreetmap.josm.data.gpx.WayPoint;
    4144import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     
    5760import org.openstreetmap.josm.io.audio.AudioPlayer;
    5861import org.openstreetmap.josm.spi.preferences.Config;
     62import org.openstreetmap.josm.tools.ColorHelper;
    5963import org.openstreetmap.josm.tools.ImageProvider;
    6064import org.openstreetmap.josm.tools.Logging;
     
    7781     * A list of markers.
    7882     */
    79     public final List<Marker> data;
     83    public final MarkerData data;
    8084    private boolean mousePressed;
    8185    public GpxLayer fromLayer;
     
    101105        super(name);
    102106        this.setAssociatedFile(associatedFile);
    103         this.data = new ArrayList<>();
     107        this.data = new MarkerData();
    104108        this.fromLayer = fromLayer;
    105109        double firstTime = -1.0;
    106110        String lastLinkedFile = "";
    107111
     112        if (fromLayer == null || fromLayer.data == null) {
     113            data.ownLayerPrefs = indata.getLayerPrefs();
     114        }
     115
     116        String cs = GPXSettingsPanel.tryGetDataPrefLocal(data, "markers.color");
    108117        Color c = null;
    109         String cs = GPXSettingsPanel.tryGetLayerPrefLocal(indata, "markers.color");
    110118        if (cs != null) {
    111             try {
    112                 c = Color.decode(cs);
    113             } catch (NumberFormatException ex) {
     119            c = ColorHelper.html2color(cs);
     120            if (c == null) {
    114121                Logging.warn("Could not read marker color: " + cs);
    115122            }
     
    460467     */
    461468    private boolean isTextOrIconShown() {
    462         return Boolean.parseBoolean(GPXSettingsPanel.getLayerPref(fromLayer, "markers.show-text"));
     469        return Boolean.parseBoolean(GPXSettingsPanel.getDataPref(data, "markers.show-text"));
    463470    }
    464471
     
    476483    public void setColor(Color color) {
    477484        setPrivateColors(color);
    478         if (fromLayer != null) {
    479             String cs = null;
    480             if (color != null) {
    481                 cs = String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue());
    482             }
    483             GPXSettingsPanel.putLayerPrefLocal(fromLayer, "markers.color", cs);
    484         }
     485        String cs = null;
     486        if (color != null) {
     487            cs = ColorHelper.color2html(color);
     488        }
     489        GPXSettingsPanel.putDataPrefLocal(data, "markers.color", cs);
    485490        invalidate();
    486491    }
     
    534539        @Override
    535540        public void actionPerformed(ActionEvent e) {
    536             GPXSettingsPanel.putLayerPrefLocal(layer.fromLayer, "markers.show-text", Boolean.toString(!layer.isTextOrIconShown()));
     541            GPXSettingsPanel.putDataPrefLocal(layer.data, "markers.show-text", Boolean.toString(!layer.isTextOrIconShown()));
    537542            layer.invalidate();
    538543        }
     
    618623        }
    619624    }
     625
     626    /**
     627     * the data of a MarkerLayer
     628     * @since 18287
     629     */
     630    public class MarkerData extends ArrayList<Marker> implements IGpxLayerPrefs {
     631
     632        private Map<String, String> ownLayerPrefs;
     633
     634        @Override
     635        public Map<String, String> getLayerPrefs() {
     636            if (ownLayerPrefs == null && fromLayer != null && fromLayer.data != null) {
     637                return fromLayer.data.getLayerPrefs();
     638            }
     639            // fallback to own layerPrefs if the corresponding gpxLayer has already been deleted
     640            // by the user or never existed when loaded from a session file
     641            if (ownLayerPrefs == null) {
     642                ownLayerPrefs = new HashMap<>();
     643            }
     644            return ownLayerPrefs;
     645        }
     646
     647        /**
     648         * Transfers the layerPrefs from the GpxData to MarkerData (when GpxData is deleted)
     649         * @param gpxLayerPrefs the layerPrefs from the GpxData object
     650         */
     651        public void transferLayerPrefs(Map<String, String> gpxLayerPrefs) {
     652            ownLayerPrefs = new HashMap<>(gpxLayerPrefs);
     653        }
     654
     655        @Override
     656        public void setModified(boolean value) {
     657            if (fromLayer != null && fromLayer.data != null) {
     658                fromLayer.data.setModified(value);
     659            }
     660        }
     661    }
    620662}
  • trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java

    r18211 r18287  
    3030import org.openstreetmap.josm.actions.ExpertToggleAction;
    3131import org.openstreetmap.josm.data.gpx.GpxData;
     32import org.openstreetmap.josm.data.gpx.IGpxLayerPrefs;
    3233import org.openstreetmap.josm.gui.MainApplication;
    3334import org.openstreetmap.josm.gui.layer.GpxLayer;
     
    174175     */
    175176    public static String getLayerPref(GpxLayer layer, String key) {
     177        GpxData data = layer != null ? layer.data : null;
     178        return getDataPref(data, key);
     179    }
     180
     181    /**
     182     * Reads the preference for the given layer or the default preference if not available
     183     * @param data the data. Can be <code>null</code>, default preference will be returned then
     184     * @param key the drawing key to be read, without "draw.rawgps."
     185     * @return the value
     186     * @since 18287
     187     */
     188    public static String getDataPref(IGpxLayerPrefs data, String key) {
    176189        Object d = DEFAULT_PREFS.get(key);
    177190        String ds;
     
    182195            ds = null;
    183196        }
    184         return Optional.ofNullable(tryGetLayerPrefLocal(layer, key)).orElse(Config.getPref().get("draw.rawgps." + key, ds));
     197        return Optional.ofNullable(tryGetDataPrefLocal(data, key)).orElse(Config.getPref().get("draw.rawgps." + key, ds));
    185198    }
    186199
     
    192205     */
    193206    public static int getLayerPrefInt(GpxLayer layer, String key) {
    194         String s = getLayerPref(layer, key);
     207        GpxData data = layer != null ? layer.data : null;
     208        return getDataPrefInt(data, key);
     209    }
     210
     211    /**
     212     * Reads the integer preference for the given data or the default preference if not available
     213     * @param data the data. Can be <code>null</code>, default preference will be returned then
     214     * @param key the drawing key to be read, without "draw.rawgps."
     215     * @return the integer value
     216     * @since 18287
     217     */
     218    public static int getDataPrefInt(IGpxLayerPrefs data, String key) {
     219        String s = getDataPref(data, key);
    195220        if (s != null) {
    196221            try {
     
    215240     */
    216241    public static String tryGetLayerPrefLocal(GpxLayer layer, String key) {
    217         return layer != null ? tryGetLayerPrefLocal(layer.data, key) : null;
     242        return layer != null ? tryGetDataPrefLocal(layer.data, key) : null;
    218243    }
    219244
     
    224249     * @return the value or <code>null</code> if not found
    225250     */
    226     public static String tryGetLayerPrefLocal(GpxData data, String key) {
     251    public static String tryGetDataPrefLocal(IGpxLayerPrefs data, String key) {
    227252        return data != null ? data.getLayerPrefs().get(key) : null;
    228253    }
     
    238263        if (layers != null) {
    239264            for (GpxLayer l : layers) {
    240                 putLayerPrefLocal(l.data, key, v);
     265                putDataPrefLocal(l.data, key, v);
    241266            }
    242267        } else {
     
    253278    public static void putLayerPrefLocal(GpxLayer layer, String key, String value) {
    254279        if (layer == null || layer.data == null) return;
    255         putLayerPrefLocal(layer.data, key, value);
     280        putDataPrefLocal(layer.data, key, value);
    256281    }
    257282
     
    261286     * @param key the drawing key to be written, without "draw.rawgps."
    262287     * @param value the value or <code>null</code> to remove key
    263      */
    264     public static void putLayerPrefLocal(GpxData data, String key, String value) {
     288     * @since 18287
     289     */
     290    public static void putDataPrefLocal(IGpxLayerPrefs data, String key, String value) {
     291        if (data == null) return;
     292        data.setModified(true);
    265293        if (Utils.isBlank(value) ||
    266294                (getLayerPref(null, key).equals(value) && DEFAULT_PREFS.get(key) != null && DEFAULT_PREFS.get(key).toString().equals(value))) {
  • trunk/src/org/openstreetmap/josm/io/GpxWriter.java

    r18219 r18287  
    149149        validprefixes = namespaces.stream().map(n -> n.getPrefix()).collect(Collectors.toList());
    150150
     151        data.creator = JOSM_CREATOR_NAME;
    151152        out.println("<?xml version='1.0' encoding='UTF-8'?>");
    152         out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"");
     153
     154        out.print("<gpx version=\"1.1\" creator=\"");
     155        out.print(JOSM_CREATOR_NAME);
     156        out.println("\" xmlns=\"http://www.topografix.com/GPX/1/1\"");
    153157
    154158        StringBuilder schemaLocations = new StringBuilder("http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd");
  • trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionExporter.java

    r18133 r18287  
    77import java.io.Writer;
    88import java.nio.charset.StandardCharsets;
     9import java.time.Instant;
    910
    1011import org.openstreetmap.josm.gui.layer.GpxLayer;
     
    1617 */
    1718public class GpxTracksSessionExporter extends GenericSessionExporter<GpxLayer> {
     19
     20    private Instant metaTime;
    1821
    1922    /**
     
    3740        Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
    3841        GpxWriter w = new GpxWriter(new PrintWriter(writer));
     42        if (metaTime != null) {
     43            w.setMetaTime(metaTime);
     44        }
    3945        w.write(layer.data);
    4046        w.flush();
    4147    }
     48
     49    protected void setMetaTime(Instant metaTime) {
     50        this.metaTime = metaTime;
     51    }
    4252}
  • trunk/src/org/openstreetmap/josm/io/session/GpxTracksSessionImporter.java

    r18208 r18287  
    5555                    importData = GpxImporter.loadLayers(in, support.getFile(fileStr), support.getLayerName(), progressMonitor);
    5656                }
     57                if (importData.getGpxLayer() != null && importData.getGpxLayer().data != null) {
     58                    importData.getGpxLayer().data.fromSession = true;
     59                }
    5760
    5861                support.addPostLayersTask(importData.getPostLayerTask());
  • trunk/src/org/openstreetmap/josm/io/session/MarkerSessionExporter.java

    r17733 r18287  
    1010import java.io.Writer;
    1111import java.nio.charset.StandardCharsets;
     12import java.time.Instant;
    1213import java.util.Collection;
    1314import java.util.Collections;
     
    3233 */
    3334public class MarkerSessionExporter extends AbstractSessionExporter<MarkerLayer> {
     35
     36    private Instant metaTime;
    3437
    3538    /**
     
    8790        Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
    8891        MarkerWriter w = new MarkerWriter(new PrintWriter(writer));
     92        if (metaTime != null) {
     93            w.setMetaTime(metaTime);
     94        }
    8995        w.write(layer);
    9096        w.flush();
     97    }
     98
     99    protected void setMetaTime(Instant metaTime) {
     100        this.metaTime = metaTime;
    91101    }
    92102
     
    110120        public void write(MarkerLayer layer) {
    111121            GpxData data = new GpxData();
     122            layer.data.getLayerPrefs().forEach((k, v) -> {
     123                if (k != null && k.indexOf("markers.") == 0) {
     124                    data.getLayerPrefs().put(k, v);
     125                }
     126            });
    112127            data.put(GpxData.META_DESC, "exported JOSM marker layer");
    113128            for (Marker m : layer.data) {
  • trunk/src/org/openstreetmap/josm/io/session/MarkerSessionImporter.java

    r18208 r18287  
    66import java.io.IOException;
    77import java.io.InputStream;
    8 import java.util.List;
    98
    109import javax.xml.xpath.XPath;
     
    1514
    1615import org.openstreetmap.josm.gui.io.importexport.GpxImporter;
    17 import org.openstreetmap.josm.gui.layer.GpxLayer;
    1816import org.openstreetmap.josm.gui.layer.Layer;
    1917import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
     
    5149                support.addPostLayersTask(importData.getPostLayerTask());
    5250
    53                 GpxLayer gpxLayer = null;
    54                 List<SessionReader.LayerDependency> deps = support.getLayerDependencies();
    55                 if (!deps.isEmpty()) {
    56                     Layer layer = deps.get(0).getLayer();
    57                     if (layer instanceof GpxLayer) {
    58                         gpxLayer = (GpxLayer) layer;
    59                     }
    60                 }
    61 
    62                 MarkerLayer markerLayer = importData.getMarkerLayer();
    63                 if (markerLayer != null) {
    64                     markerLayer.fromLayer = gpxLayer;
    65                 }
    66 
    67                 return markerLayer;
     51                return importData.getMarkerLayer();
    6852            }
    6953        } catch (XPathExpressionException e) {
  • trunk/src/org/openstreetmap/josm/io/session/SessionReader.java

    r17659 r18287  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Color;
    76import java.awt.GraphicsEnvironment;
    87import java.io.BufferedInputStream;
     
    4746import org.openstreetmap.josm.io.IllegalDataException;
    4847import org.openstreetmap.josm.tools.CheckParameterUtil;
    49 import org.openstreetmap.josm.tools.ColorHelper;
    5048import org.openstreetmap.josm.tools.JosmRuntimeException;
    5149import org.openstreetmap.josm.tools.Logging;
     
    620618                }
    621619            }
    622             String colorString = el.getAttribute("color");
    623             if (colorString != null) {
    624                 try {
    625                     Color color = ColorHelper.html2color(colorString);
    626                     layer.setColor(color);
    627                 } catch (RuntimeException ex) {
    628                     Logging.warn("Cannot parse color " + colorString);
    629                 }
    630             }
    631620            layer.setName(names.get(entry.getKey()));
    632621            layers.add(layer);
  • trunk/src/org/openstreetmap/josm/io/session/SessionWriter.java

    r18133 r18287  
    4444import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
    4545import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
    46 import org.openstreetmap.josm.tools.ColorHelper;
    4746import org.openstreetmap.josm.tools.JosmRuntimeException;
    4847import org.openstreetmap.josm.tools.Logging;
     
    241240            if (!Utils.equalsEpsilon(layer.getOpacity(), 1.0)) {
    242241                el.setAttribute("opacity", Double.toString(layer.getOpacity()));
    243             }
    244             if (layer.getColor() != null) {
    245                 el.setAttribute("color", ColorHelper.color2html(layer.getColor()));
    246242            }
    247243            Set<Layer> deps = dependencies.get(layer);
  • trunk/test/data/sessions/gpx_markers.jos

    r17659 r18287  
    1616            <file>layers/01/data.gpx</file>
    1717        </layer>
    18         <layer color="#34567812" index="2" name="Marker layer name" opacity="0.5" type="markers" version="0.1" visible="true">
     18        <layer index="2" name="Marker layer name" opacity="0.5" type="markers" version="0.1" visible="true">
    1919            <file>layers/02/data.gpx</file>
    2020        </layer>
  • trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java

    r18207 r18287  
    504504        EqualsVerifier.forClass(GpxData.class).usingGetClass()
    505505            .suppress(Warning.NONFINAL_FIELDS)
    506             .withIgnoredFields("creator", "fromServer", "storageFile", "initializing", "updating",
     506            .withIgnoredFields("creator", "fromServer", "fromSession", "storageFile", "initializing", "updating",
    507507                    "suppressedInvalidate", "listeners", "tracks", "routes", "waypoints", "proxy", "segSpans", "modified")
    508508            .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
  • trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackTest.java

    r17275 r18287  
    99import java.util.HashMap;
    1010
     11import org.junit.jupiter.api.Test;
    1112import org.junit.jupiter.api.extension.RegisterExtension;
    12 import org.junit.jupiter.api.Test;
    1313import org.openstreetmap.josm.TestUtils;
    1414import org.openstreetmap.josm.testutils.JOSMTestRules;
     
    3232
    3333    /**
    34      * Tests weather the track can read and write colors.
     34     * Tests whether the track can read and write colors.
    3535     */
    3636    @Test
  • trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java

    r17659 r18287  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.io.session;
     3
     4import static org.junit.jupiter.api.Assertions.assertEquals;
     5import static org.junit.jupiter.api.Assertions.fail;
    36
    47import java.awt.Color;
    58import java.io.File;
    69import java.io.IOException;
    7 import java.io.InputStream;
    810import java.nio.charset.StandardCharsets;
    911import java.nio.file.Files;
    1012import java.nio.file.Path;
    1113import java.nio.file.Paths;
     14import java.time.Instant;
    1215import java.util.Arrays;
    1316import java.util.Collections;
     
    1518import java.util.List;
    1619import java.util.Map;
     20import java.util.stream.Collectors;
     21import java.util.zip.ZipEntry;
    1722import java.util.zip.ZipFile;
    1823
     
    4348import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    4449
    45 import static org.junit.jupiter.api.Assertions.assertEquals;
    46 
    4750/**
    4851 * Unit tests for Session writing.
     
    109112    }
    110113
    111     private byte[] testWrite(List<Layer> layers, final boolean zip) throws IOException {
     114    private Map<String, byte[]> testWrite(List<Layer> layers, final boolean zip) throws IOException {
    112115        Map<Layer, SessionLayerExporter> exporters = new HashMap<>();
    113116        if (zip) {
     
    119122        }
    120123        for (final Layer l : layers) {
    121             exporters.put(l, SessionWriter.getSessionLayerExporter(l));
     124            SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l);
     125            exporters.put(l, s);
     126            if (s instanceof GpxTracksSessionExporter) {
     127                ((GpxTracksSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
     128            } else if (s instanceof MarkerSessionExporter) {
     129                ((MarkerSessionExporter) s).setMetaTime(Instant.parse("2021-10-16T18:27:12.351Z"));
     130            }
    122131        }
    123132        SessionWriter sw = new SessionWriter(layers, -1, exporters, new MultiMap<Layer, Layer>(), zip);
     
    128137                return null;
    129138            }
    130             try (ZipFile zipFile = new ZipFile(file);
    131                  InputStream input = zipFile.getInputStream(zipFile.getEntry("session.jos"))) {
    132                 return Utils.readBytesFromStream(input);
     139            try (ZipFile zipFile = new ZipFile(file)) {
     140                return Collections.list(zipFile.entries()).stream().collect(Collectors.toMap(ZipEntry::getName, e -> {
     141                    try {
     142                        return Utils.readBytesFromStream(zipFile.getInputStream(e));
     143                    } catch (IOException ex) {
     144                        fail(ex);
     145                    }
     146                    return null;
     147                }));
    133148            }
    134149        } finally {
     
    147162    private GpxLayer createGpxLayer() {
    148163        GpxData data = new GpxData();
    149         data.waypoints.add(new WayPoint(new LatLon(42.72665, -0.00747)));
     164        WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747));
     165        wp.setInstant(Instant.parse("2021-01-01T10:15:30.00Z"));
     166        data.waypoints.add(wp);
    150167        data.waypoints.add(new WayPoint(new LatLon(42.72659, -0.00749)));
    151168        GpxLayer layer = new GpxLayer(data, "GPX layer name");
     
    233250    void testWriteGpxAndMarkerJoz() throws IOException {
    234251        GpxLayer gpx = createGpxLayer();
    235         byte[] bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
     252        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
     253
    236254        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
    237255        String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
    238         String actual = new String(bytes, StandardCharsets.UTF_8).replace("\r", "");
     256        String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
     257        assertEquals(expected, actual);
     258
     259        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/data_export.gpx");
     260        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
     261        actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
     262        assertEquals(expected, actual);
     263
     264        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx");
     265        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
     266        actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
    239267        assertEquals(expected, actual);
    240268    }
Note: See TracChangeset for help on using the changeset viewer.