Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 13136)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 13210)
@@ -5,13 +5,17 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.DoubleSummaryStatistics;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -22,4 +26,6 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.gpx.GpxTrack.GpxTrackChangeListener;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.tools.ListenerList;
 import org.openstreetmap.josm.tools.ListeningCollection;
@@ -141,4 +147,21 @@
 
     /**
+     * Get Stream<> of track segments as introduced in Java 8.
+     * @return {@code Stream<GPXTrack>}
+     */
+    private synchronized Stream<GpxTrackSegment> getTrackSegmentsStream() {
+        return getTracks().stream().flatMap(trk -> trk.getSegments().stream());
+    }
+
+    /**
+     * Clear all tracks, empties the current privateTracks container,
+     * helper method for some gpx manipulations.
+     */
+    private synchronized void clearTracks() {
+        privateTracks.forEach(t -> t.removeListener(proxy));
+        privateTracks.clear();
+    }
+
+    /**
      * Add a new track
      * @param track The new track
@@ -165,4 +188,102 @@
         track.removeListener(proxy);
         fireInvalidate();
+    }
+
+    /**
+     * Combine tracks into a single, segmented track.
+     * The attributes of the first track are used, the rest discarded.
+     *
+     * @since 13210
+     */
+    public synchronized void combineTracksToSegmentedTrack() {
+        List<GpxTrackSegment> segs = getTrackSegmentsStream()
+                .collect(Collectors.toCollection(ArrayList<GpxTrackSegment>::new));
+        Map<String, Object> attrs = new HashMap<>(privateTracks.get(0).getAttributes());
+
+        // do not let the name grow if split / combine operations are called iteratively
+        attrs.put("name", attrs.get("name").toString().replaceFirst(" #\\d+$", ""));
+
+        clearTracks();
+        addTrack(new ImmutableGpxTrack(segs, attrs));
+    }
+
+    /**
+     * @param attrs attributes of/for an gpx track, written to if the name appeared previously in {@code counts}.
+     * @param counts a {@code HashMap} of previously seen names, associated with their count.
+     * @return the unique name for the gpx track.
+     *
+     * @since 13210
+     */
+    public static String ensureUniqueName(Map<String, Object> attrs, Map<String, Integer> counts) {
+        String name = attrs.getOrDefault("name", "GPX split result").toString();
+        Integer count = counts.getOrDefault(name, 0) + 1;
+        counts.put(name, count);
+
+        attrs.put("name", MessageFormat.format("{0}{1}", name, (count > 1) ? " #"+count : ""));
+        return attrs.get("name").toString();
+    }
+
+    /**
+     * Split tracks so that only single-segment tracks remain.
+     * Each segment will make up one individual track after this operation.
+     *
+     * @since 13210
+     */
+    public synchronized void splitTrackSegmentsToTracks() {
+        final HashMap<String, Integer> counts = new HashMap<>();
+
+        List<GpxTrack> trks = getTracks().stream()
+            .flatMap(trk -> {
+                return trk.getSegments().stream().map(seg -> {
+                    HashMap<String, Object> attrs = new HashMap<>(trk.getAttributes());
+                    ensureUniqueName(attrs, counts);
+                    return new ImmutableGpxTrack(Arrays.asList(seg), attrs);
+                });
+            })
+            .collect(Collectors.toCollection(ArrayList<GpxTrack>::new));
+
+        clearTracks();
+        trks.stream().forEachOrdered(trk -> addTrack(trk));
+    }
+
+    /**
+     * Split tracks into layers, the result is one layer for each track.
+     * If this layer currently has only one GpxTrack this is a no-operation.
+     *
+     * The new GpxLayers are added to the LayerManager, the original GpxLayer
+     * is untouched as to preserve potential route or wpt parts.
+     *
+     * @since 13210
+     */
+    public synchronized void splitTracksToLayers() {
+        final HashMap<String, Integer> counts = new HashMap<>();
+
+        getTracks().stream()
+            .filter(trk -> privateTracks.size() > 1)
+            .map(trk -> {
+                HashMap<String, Object> attrs = new HashMap<>(trk.getAttributes());
+                GpxData d = new GpxData();
+                d.addTrack(trk);
+                return new GpxLayer(d, ensureUniqueName(attrs, counts)); })
+            .forEachOrdered(layer -> MainApplication.getLayerManager().addLayer(layer));
+    }
+
+    /**
+     * Replies the current number of tracks in this GpxData
+     * @return track count
+     * @since 13210
+     */
+    public synchronized int getTrackCount() {
+        return privateTracks.size();
+    }
+
+    /**
+     * Replies the accumulated total of all track segments,
+     * the sum of segment counts for each track present.
+     * @return track segments count
+     * @since 13210
+     */
+    public synchronized int getTrackSegsCount() {
+        return privateTracks.stream().collect(Collectors.summingInt(t -> t.getSegments().size()));
     }
 
Index: trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java	(revision 13136)
+++ trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java	(revision 13210)
@@ -35,4 +35,20 @@
         this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
         this.segments = Collections.unmodifiableList(newSegments);
+        this.length = calculateLength();
+        this.bounds = calculateBounds();
+    }
+
+    /**
+     * Constructs a new {@code ImmutableGpxTrack} from {@code GpxTrackSegment} objects.
+     * @param segments The segments to build the track from.  Input is not deep-copied,
+     *                 which means the caller may reuse the same segments to build
+     *                 multiple ImmutableGpxTrack instances from.  This should not be
+     *                 a problem, since this object cannot modify {@code this.segments}.
+     * @param attributes Attributes for the GpxTrack, the input map is copied.
+     * @since 13210
+     */
+    public ImmutableGpxTrack(List<GpxTrackSegment> segments, Map<String, Object> attributes) {
+        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
+        this.segments = Collections.unmodifiableList(segments);
         this.length = calculateLength();
         this.bounds = calculateBounds();
Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 13136)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 13210)
@@ -143,4 +143,13 @@
     public void setTime() {
         setTimeFromAttribute();
+    }
+
+    /**
+     * Set the the time stamp of the waypoint into seconds from the epoch,
+     * @param time millisecond from the epoch
+     * @since 13210
+     */
+    public void setTime(long time) {
+        this.time = time / 1000.;
     }
 
