Ticket #12726: 12726_alpha1.diff
| File 12726_alpha1.diff, 35.4 KB (added by , 7 years ago) |
|---|
-
src/org/openstreetmap/josm/io/session/CommandSessionExporters.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import java.util.Collection; 5 6 import org.openstreetmap.josm.command.AddCommand; 7 import org.openstreetmap.josm.command.ChangeCommand; 8 import org.openstreetmap.josm.command.Command; 9 import org.openstreetmap.josm.command.PseudoCommand; 10 import org.openstreetmap.josm.command.SequenceCommand; 11 import org.openstreetmap.josm.data.osm.OsmPrimitive; 12 import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 13 import org.openstreetmap.josm.tools.Logging; 14 import org.w3c.dom.Element; 15 16 /** 17 * Command session exporters. 18 * @since xxx 19 */ 20 public final class CommandSessionExporters { 21 22 private CommandSessionExporters() { 23 // Hide default constructor 24 } 25 26 abstract static class AbstractCommandSessionExporter<T extends Command> implements SessionCommandExporter { 27 protected final T command; 28 29 AbstractCommandSessionExporter(T command) { 30 this.command = command; 31 } 32 33 @Override 34 public final Element export(ExportSupport support) { 35 Element el = support.createElement("command"); 36 el.setAttribute("class", command.getClass().getName()); 37 el.setAttribute("layer", Integer.toString(support.getLayerIndex())); 38 doExport(el, support); 39 if (includeParticipatingOsmPrimitives()) { 40 for (OsmPrimitive osm : command.getParticipatingPrimitives()) { 41 Element osmEl = support.createElement(osm.getType().getAPIName()); 42 osmEl.setAttribute("id", Long.toString(osm.getUniqueId())); 43 el.appendChild(osmEl); 44 } 45 } 46 return el; 47 } 48 49 protected void doExport(Element el, ExportSupport support) { 50 // To be overriden if needed 51 } 52 } 53 54 /** 55 * A special command exporter used when no exporter can be found for a given command. 56 * This allows us to export as many commands as possible but:<ul> 57 * <li>log errors directly in the session file, for troubleshooting</li> 58 * <li>include an error flag preventing session import action to load commands to ensure data integrity</li> 59 * </ul> 60 */ 61 public static class ErrorCommandExporter extends AbstractCommandSessionExporter<Command> { 62 63 /** 64 * Constructs a new {@code ErrorCommandExporter} 65 * @param command unsupported command 66 */ 67 public ErrorCommandExporter(Command command) { 68 super(command); 69 } 70 71 @Override 72 protected void doExport(Element el, ExportSupport support) { 73 String message = "No exporter found for " + command; 74 Logging.error(message); 75 el.setAttribute("error", message); 76 } 77 } 78 79 /** 80 * Command exporter for {@link AddCommand}. 81 */ 82 public static class AddCommandExporter extends AbstractCommandSessionExporter<AddCommand> { 83 84 /** 85 * Constructs a new {@code AddCommandExporter} 86 * @param command add command 87 */ 88 public AddCommandExporter(AddCommand command) { 89 super(command); 90 } 91 } 92 93 /** 94 * Command exporter for {@link ChangeCommand}. 95 */ 96 public static class ChangeCommandExporter extends AbstractCommandSessionExporter<ChangeCommand> { 97 98 /** 99 * Constructs a new {@code ChangeCommandExporter} 100 * @param command change command 101 */ 102 public ChangeCommandExporter(ChangeCommand command) { 103 super(command); 104 } 105 106 @Override 107 protected void doExport(Element el, ExportSupport support) { 108 // TODO Auto-generated method stub 109 } 110 } 111 112 /** 113 * Command exporter for {@link SequenceCommand}. 114 */ 115 public static class SequenceCommandExporter extends AbstractCommandSessionExporter<SequenceCommand> { 116 117 /** 118 * Constructs a new {@code SequenceCommandExporter} 119 * @param command sequence command 120 */ 121 public SequenceCommandExporter(SequenceCommand command) { 122 super(command); 123 } 124 125 @Override 126 public boolean includeParticipatingOsmPrimitives() { 127 return false; 128 } 129 130 @Override 131 protected void doExport(Element el, ExportSupport support) { 132 el.setAttribute("name", command.getName()); 133 for (PseudoCommand pc : command.getChildren()) { 134 if (pc instanceof Command) { 135 SessionWriter.addCommand(el, (Command) pc, support); 136 } else { 137 // Include a fake command to issue an error in the session file (PseudoCommand not supported) 138 SessionWriter.addCommand(el, new Command(command.getAffectedDataSet()) { 139 140 @Override 141 public String getDescriptionText() { 142 return null; 143 } 144 145 @Override 146 public void fillModifiedData(Collection<OsmPrimitive> modified, 147 Collection<OsmPrimitive> deleted, Collection<OsmPrimitive> added) { 148 // Do nothing 149 } 150 151 @Override 152 public String toString() { 153 return "No exporter found for " + pc; 154 } 155 }, support); 156 } 157 } 158 } 159 } 160 } -
src/org/openstreetmap/josm/io/session/CommandSessionImporters.java
Property changes on: src\org\openstreetmap\josm\io\session\CommandSessionExporters.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.List; 7 8 import org.openstreetmap.josm.command.AddCommand; 9 import org.openstreetmap.josm.command.ChangeCommand; 10 import org.openstreetmap.josm.command.Command; 11 import org.openstreetmap.josm.command.SequenceCommand; 12 import org.openstreetmap.josm.data.osm.DataSet; 13 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 14 import org.openstreetmap.josm.gui.layer.Layer; 15 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 16 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 17 import org.openstreetmap.josm.io.IllegalDataException; 18 import org.openstreetmap.josm.tools.XmlUtils; 19 import org.w3c.dom.Element; 20 21 /** 22 * Command session importers. 23 * @since xxx 24 */ 25 public final class CommandSessionImporters { 26 27 private CommandSessionImporters() { 28 // Hide default constructor 29 } 30 31 abstract static class AbstractCommandSessionImporter<T extends Command> implements SessionCommandImporter { 32 33 @Override 34 public Command load(Element elem, OsmDataLayer dataLayer, ProgressMonitor progressMonitor) throws IllegalDataException { 35 return doImport(elem, dataLayer, elem.getAttribute("name")); 36 } 37 38 /** 39 * @param el Command element 40 * @param dataLayer data layer 41 * @param name command name 42 * @return the resulting command 43 * @throws IllegalDataException in case of illegal data 44 */ 45 protected abstract Command doImport(Element el, OsmDataLayer dataLayer, String name) throws IllegalDataException; 46 } 47 48 /** 49 * A special command importer used when no exporter was found for a given command. 50 * This allows us to export as many commands as possible but:<ul> 51 * <li>log errors directly in the session file, for troubleshooting</li> 52 * <li>include an error flag preventing session import action to load commands to ensure data integrity</li> 53 * </ul> 54 */ 55 public static class ErrorCommandImporter extends AbstractCommandSessionImporter<Command> { 56 57 @Override 58 protected Command doImport(Element el, OsmDataLayer dataLayer, String name) throws IllegalDataException { 59 throw new IllegalDataException(name + ": " + el.getAttribute("error")); 60 } 61 } 62 63 /** 64 * Command importer for {@link AddCommand}. 65 */ 66 public static class AddCommandImporter extends AbstractCommandSessionImporter<AddCommand> { 67 68 @Override 69 protected Command doImport(Element el, OsmDataLayer dataLayer, String name) throws IllegalDataException { 70 DataSet dataSet = dataLayer.data; 71 Element osm = XmlUtils.getFirstChildElement(el); 72 return new AddCommand(dataSet, dataSet.getPrimitiveById( 73 Long.parseLong(osm.getAttribute("id")), 74 OsmPrimitiveType.from(osm.getLocalName()))); 75 } 76 } 77 78 /** 79 * Command importer for {@link ChangeCommand}. 80 */ 81 public static class ChangeCommandImporter extends AbstractCommandSessionImporter<ChangeCommand> { 82 83 @Override 84 protected Command doImport(Element el, OsmDataLayer dataLayer, String name) throws IllegalDataException { 85 // TODO Auto-generated method stub 86 return null; 87 } 88 } 89 90 /** 91 * Command importer for {@link SequenceCommand}. 92 */ 93 public static class SequenceCommandImporter extends AbstractCommandSessionImporter<SequenceCommand> { 94 95 @Override 96 protected Command doImport(Element el, OsmDataLayer dataLayer, String name) throws IllegalDataException { 97 try { 98 int layerIndex = Integer.parseInt(el.getAttribute("layer")); 99 List<Layer> layers = Collections.nCopies(layerIndex, dataLayer); 100 return new SequenceCommand(name, SessionReader.readCommands(el, new ArrayList<>(), layers)); 101 } catch (ClassNotFoundException e) { 102 throw new IllegalDataException(e); 103 } 104 } 105 } 106 } -
src/org/openstreetmap/josm/io/session/GenericSessionExporter.java
Property changes on: src\org\openstreetmap\josm\io\session\CommandSessionImporters.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native
35 35 import org.w3c.dom.Element; 36 36 37 37 /** 38 * Generic superclass of {@link OsmDataSessionExporter} and {@link GpxTracksSessionExporter} layer exporters.38 * Generic superclass of {@link OsmDataSessionExporter}, {@link GpxTracksSessionExporter} and {@code NoteSessionExporter} layer exporters. 39 39 * @param <T> Type of exported layer 40 40 * @since 9470 41 41 */ -
src/org/openstreetmap/josm/io/session/SessionCommandExporter.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import org.openstreetmap.josm.command.Command; 5 import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 6 import org.w3c.dom.Element; 7 8 /** 9 * Session command exporter. 10 * @since xxx 11 */ 12 public interface SessionCommandExporter { 13 14 /** 15 * Save meta data to the .jos file. Return a command XML element. 16 * Use <code>support</code> to save files in the zip archive as needed. 17 * @param support support class providing export utilities 18 * @return the resulting XML element 19 */ 20 Element export(ExportSupport support); 21 22 /** 23 * Whether to include participating OSM primitives as inner child elements. 24 * @return {@code true} to include participating OSM primitives 25 * @see Command#getParticipatingPrimitives 26 */ 27 default boolean includeParticipatingOsmPrimitives() { 28 return true; 29 } 30 } -
src/org/openstreetmap/josm/io/session/SessionCommandImporter.java
Property changes on: src\org\openstreetmap\josm\io\session\SessionCommandExporter.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import org.openstreetmap.josm.command.Command; 5 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 6 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 7 import org.openstreetmap.josm.io.IllegalDataException; 8 import org.w3c.dom.Element; 9 10 /** 11 * Session command importer. 12 * @since xxx 13 */ 14 @FunctionalInterface 15 public interface SessionCommandImporter { 16 17 /** 18 * Load the command from xml meta-data. 19 * @param elem XML element 20 * @param dataLayer data layer 21 * @param progressMonitor progress monitor 22 * @return the resulting command 23 * @throws IllegalDataException in case of illegal data 24 */ 25 Command load(Element elem, OsmDataLayer dataLayer, ProgressMonitor progressMonitor) throws IllegalDataException; 26 } -
src/org/openstreetmap/josm/io/session/SessionReader.java
Property changes on: src\org\openstreetmap\josm\io\session\SessionCommandImporter.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native
31 31 import javax.swing.SwingUtilities; 32 32 import javax.xml.parsers.ParserConfigurationException; 33 33 34 import org.openstreetmap.josm.command.AddCommand; 35 import org.openstreetmap.josm.command.AddPrimitivesCommand; 36 import org.openstreetmap.josm.command.ChangeCommand; 37 import org.openstreetmap.josm.command.ChangeNodesCommand; 38 import org.openstreetmap.josm.command.ChangePropertyCommand; 39 import org.openstreetmap.josm.command.ChangePropertyKeyCommand; 40 import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand; 41 import org.openstreetmap.josm.command.Command; 42 import org.openstreetmap.josm.command.DeleteCommand; 43 import org.openstreetmap.josm.command.MoveCommand; 44 import org.openstreetmap.josm.command.RemoveNodesCommand; 45 import org.openstreetmap.josm.command.RotateCommand; 46 import org.openstreetmap.josm.command.ScaleCommand; 47 import org.openstreetmap.josm.command.SelectCommand; 48 import org.openstreetmap.josm.command.SequenceCommand; 49 import org.openstreetmap.josm.command.SplitWayCommand; 50 import org.openstreetmap.josm.command.TransformNodesCommand; 34 51 import org.openstreetmap.josm.data.ViewportData; 35 52 import org.openstreetmap.josm.data.coor.EastNorth; 36 53 import org.openstreetmap.josm.data.coor.LatLon; … … 38 55 import org.openstreetmap.josm.gui.ExtendedDialog; 39 56 import org.openstreetmap.josm.gui.MainApplication; 40 57 import org.openstreetmap.josm.gui.layer.Layer; 58 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 41 59 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 42 60 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 43 61 import org.openstreetmap.josm.io.Compression; 44 62 import org.openstreetmap.josm.io.IllegalDataException; 63 import org.openstreetmap.josm.io.session.CommandSessionImporters.AddCommandImporter; 64 import org.openstreetmap.josm.io.session.CommandSessionImporters.ChangeCommandImporter; 65 import org.openstreetmap.josm.io.session.CommandSessionImporters.SequenceCommandImporter; 45 66 import org.openstreetmap.josm.tools.CheckParameterUtil; 46 67 import org.openstreetmap.josm.tools.JosmRuntimeException; 47 68 import org.openstreetmap.josm.tools.Logging; … … 148 169 } 149 170 } 150 171 151 private static final Map<String, Class<? extends SessionLayerImporter>> sessionLayerImporters = new HashMap<>(); 172 /** 173 * Data class for commands saved in the session file. 174 * @since xxx 175 */ 176 public static class CommandStackData { 177 private final List<Command> undo = new ArrayList<>(); 178 private final List<Command> redo = new ArrayList<>(); 179 180 /** 181 * Returns the undo commands. 182 * @return the undo commands 183 */ 184 public final List<Command> getUndo() { 185 return undo; 186 } 187 188 /** 189 * Returns the redo commands. 190 * @return the redo commands 191 */ 192 public final List<Command> getRedo() { 193 return redo; 194 } 195 } 196 197 private static final Map<String, Class<? extends SessionLayerImporter>> sessionLayerImporters 198 = new HashMap<>(); 199 private static final Map<Class<? extends Command>, Class<? extends SessionCommandImporter>> sessionCommandImporters 200 = new HashMap<>(); 152 201 153 202 private URI sessionFileURI; 154 203 private boolean zip; // true, if session file is a .joz file; false if it is a .jos file … … 156 205 private List<Layer> layers = new ArrayList<>(); 157 206 private int active = -1; 158 207 private final List<Runnable> postLoadTasks = new ArrayList<>(); 208 //private final Map<Integer, ImportSupport> supports = new HashMap<>(); 159 209 private SessionViewportData viewport; 160 210 private SessionProjectionChoiceData projectionChoice; 211 private CommandStackData commandStack; 161 212 162 213 static { 214 // Layers 163 215 registerSessionLayerImporter("osm-data", OsmDataSessionImporter.class); 164 216 registerSessionLayerImporter("imagery", ImagerySessionImporter.class); 165 217 registerSessionLayerImporter("tracks", GpxTracksSessionImporter.class); 166 218 registerSessionLayerImporter("geoimage", GeoImageSessionImporter.class); 167 219 registerSessionLayerImporter("markers", MarkerSessionImporter.class); 168 220 registerSessionLayerImporter("osm-notes", NoteSessionImporter.class); 221 // Commands TODO 222 registerSessionCommandImporter(AddCommand.class, AddCommandImporter.class); 223 registerSessionCommandImporter(AddPrimitivesCommand.class, null); 224 registerSessionCommandImporter(ChangeCommand.class, ChangeCommandImporter.class); 225 registerSessionCommandImporter(ChangeNodesCommand.class, null); 226 registerSessionCommandImporter(ChangePropertyCommand.class, null); 227 registerSessionCommandImporter(ChangePropertyKeyCommand.class, null); 228 registerSessionCommandImporter(ChangeRelationMemberRoleCommand.class, null); 229 registerSessionCommandImporter(DeleteCommand.class, null); 230 registerSessionCommandImporter(MoveCommand.class, null); 231 registerSessionCommandImporter(RemoveNodesCommand.class, null); 232 registerSessionCommandImporter(RotateCommand.class, null); 233 registerSessionCommandImporter(ScaleCommand.class, null); 234 registerSessionCommandImporter(SelectCommand.class, null); 235 registerSessionCommandImporter(SequenceCommand.class, SequenceCommandImporter.class); 236 registerSessionCommandImporter(SplitWayCommand.class, null); 237 registerSessionCommandImporter(TransformNodesCommand.class, null); 169 238 } 170 239 171 240 /** … … 179 248 } 180 249 181 250 /** 251 * Register a session command importer. 252 * 253 * @param commandClass command class 254 * @param importer importer for this command class 255 * @since xxx 256 */ 257 public static void registerSessionCommandImporter(Class<? extends Command> commandClass, Class<? extends SessionCommandImporter> importer) { 258 sessionCommandImporters.put(commandClass, importer); 259 } 260 261 /** 182 262 * Returns the session layer importer for the given layer type. 183 263 * @param layerType layer type to import 184 264 * @return session layer importer for the given layer 185 265 */ 186 266 public static SessionLayerImporter getSessionLayerImporter(String layerType) { 187 Class<? extends SessionLayerImporter> importerClass = sessionLayerImporters.get(layerType); 267 return getSessionImporter(sessionLayerImporters, layerType); 268 } 269 270 /** 271 * Returns the session command importer for the given command. 272 * @param commandClass command class to import 273 * @return session command importer for the given command, or null 274 * @since xxx 275 */ 276 public static SessionCommandImporter getSessionCommandImporter(Class<? extends Command> commandClass) { 277 return getSessionImporter(sessionCommandImporters, commandClass); 278 } 279 280 private static <E, T> E getSessionImporter(Map<T, Class<? extends E>> importers, T key) { 281 Class<? extends E> importerClass = importers.get(key); 188 282 if (importerClass == null) 189 283 return null; 190 SessionLayerImporter importer = null;191 284 try { 192 importer =importerClass.getConstructor().newInstance();285 return importerClass.getConstructor().newInstance(); 193 286 } catch (ReflectiveOperationException e) { 194 throw new JosmRuntimeException(e); 287 Logging.error(e); 288 return null; 195 289 } 196 return importer;197 290 } 198 291 199 292 /** … … 236 329 } 237 330 238 331 /** 332 * Return the command stack data. 333 * @return the command stack; can be null when no command is found in the file 334 * @since xxx 335 */ 336 public CommandStackData getCommandStack() { 337 return commandStack; 338 } 339 340 /** 239 341 * A class that provides some context for the individual {@link SessionLayerImporter} 240 342 * when doing the import. 241 343 */ … … 400 502 } 401 503 } 402 504 505 /** 506 * Layer dependency. 507 */ 403 508 public static class LayerDependency { 404 509 private final Integer index; 405 510 private final Layer layer; 406 511 private final SessionLayerImporter importer; 407 512 513 /** 514 * Constructs a new {@code LayerDependency}. 515 * @param index layer index 516 * @param layer layer 517 * @param importer layer importer 518 */ 408 519 public LayerDependency(Integer index, Layer layer, SessionLayerImporter importer) { 409 520 this.index = index; 410 521 this.layer = layer; 411 522 this.importer = importer; 412 523 } 413 524 525 /** 526 * Returns the layer importer. 527 * @return the layer importer 528 */ 414 529 public SessionLayerImporter getImporter() { 415 530 return importer; 416 531 } 417 532 533 /** 534 * Returns the layer index. 535 * @return the layer index 536 */ 418 537 public Integer getIndex() { 419 538 return index; 420 539 } 421 540 541 /** 542 * Returns the layer. 543 * @return the layer 544 */ 422 545 public Layer getLayer() { 423 546 return layer; 424 547 } … … 557 680 depsImp.add(new LayerDependency(d, layersMap.get(d), dImp)); 558 681 } 559 682 ImportSupport support = new ImportSupport(name, idx, depsImp); 683 //supports.put(idx, support); 560 684 Layer layer = null; 561 685 Exception exception = null; 562 686 try { … … 614 738 layer.setName(names.get(entry.getKey())); 615 739 layers.add(layer); 616 740 } 741 commandStack = readCommandStackData(root); 742 //supports.clear(); 743 } 744 745 private CommandStackData readCommandStackData(Element root) { 746 Element commandsEl = getElementByTagName(root, "commands"); 747 if (commandsEl == null) return null; 748 CommandStackData result = new CommandStackData(); 749 try { 750 readCommands(commandsEl, result.undo, "undo"); 751 readCommands(commandsEl, result.redo, "redo"); 752 } catch (ClassNotFoundException | IllegalDataException | RuntimeException e) { 753 Logging.error(e); 754 return null; 755 } 756 return result; 757 } 758 759 private void readCommands(Element commandsEl, List<Command> result, String type) 760 throws ClassNotFoundException, IllegalDataException { 761 Element typeEl = getElementByTagName(commandsEl, type); 762 if (typeEl != null) { 763 readCommands(typeEl, result/*, supports*/, layers); 764 } 765 } 766 767 static List<Command> readCommands(Element parentEl, List<Command> result/*, Map<Integer, ImportSupport> supports*/, List<Layer> layers) 768 throws ClassNotFoundException, IllegalDataException { 769 NodeList commandNl = parentEl.getElementsByTagName("command"); 770 int length = commandNl.getLength(); 771 for (int i = 0; i < length; i++) { 772 Element commandEl = (Element) commandNl.item(i); 773 String klass = commandEl.getAttribute("class"); 774 @SuppressWarnings("unchecked") 775 SessionCommandImporter importer = getSessionCommandImporter((Class<? extends Command>) Class.forName(klass)); 776 if (importer == null) 777 throw new IllegalStateException("No importer found for " + klass); 778 int layerIndex = Integer.parseInt(commandEl.getAttribute("layer")); 779 OsmDataLayer dataLayer = ((OsmDataLayer) layers.get(layerIndex - 1)); 780 result.add(importer.load(commandEl, dataLayer, /*supports.get(layerIndex),*/ NullProgressMonitor.INSTANCE)); 781 } 782 return result; 617 783 } 618 784 619 785 private static SessionViewportData readViewportData(Element root) { -
src/org/openstreetmap/josm/io/session/SessionWriter.java
25 25 import javax.xml.transform.dom.DOMSource; 26 26 import javax.xml.transform.stream.StreamResult; 27 27 28 import org.openstreetmap.josm.command.AddCommand; 29 import org.openstreetmap.josm.command.AddPrimitivesCommand; 30 import org.openstreetmap.josm.command.ChangeCommand; 31 import org.openstreetmap.josm.command.ChangeNodesCommand; 32 import org.openstreetmap.josm.command.ChangePropertyCommand; 33 import org.openstreetmap.josm.command.ChangePropertyKeyCommand; 34 import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand; 35 import org.openstreetmap.josm.command.Command; 36 import org.openstreetmap.josm.command.DeleteCommand; 37 import org.openstreetmap.josm.command.MoveCommand; 38 import org.openstreetmap.josm.command.RemoveNodesCommand; 39 import org.openstreetmap.josm.command.RotateCommand; 40 import org.openstreetmap.josm.command.ScaleCommand; 41 import org.openstreetmap.josm.command.SelectCommand; 42 import org.openstreetmap.josm.command.SequenceCommand; 43 import org.openstreetmap.josm.command.SplitWayCommand; 44 import org.openstreetmap.josm.command.TransformNodesCommand; 45 import org.openstreetmap.josm.data.UndoRedoHandler; 28 46 import org.openstreetmap.josm.data.coor.EastNorth; 29 47 import org.openstreetmap.josm.data.coor.LatLon; 48 import org.openstreetmap.josm.data.osm.DataSet; 30 49 import org.openstreetmap.josm.data.projection.ProjectionRegistry; 31 50 import org.openstreetmap.josm.gui.MainApplication; 32 51 import org.openstreetmap.josm.gui.MapView; … … 40 59 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; 41 60 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 42 61 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference; 62 import org.openstreetmap.josm.io.session.CommandSessionExporters.AddCommandExporter; 63 import org.openstreetmap.josm.io.session.CommandSessionExporters.ChangeCommandExporter; 64 import org.openstreetmap.josm.io.session.CommandSessionExporters.ErrorCommandExporter; 65 import org.openstreetmap.josm.io.session.CommandSessionExporters.SequenceCommandExporter; 43 66 import org.openstreetmap.josm.tools.JosmRuntimeException; 44 67 import org.openstreetmap.josm.tools.Logging; 45 68 import org.openstreetmap.josm.tools.MultiMap; … … 47 70 import org.openstreetmap.josm.tools.XmlUtils; 48 71 import org.w3c.dom.Document; 49 72 import org.w3c.dom.Element; 73 import org.w3c.dom.Node; 50 74 import org.w3c.dom.Text; 51 75 52 76 /** … … 55 79 */ 56 80 public class SessionWriter { 57 81 58 private static Map<Class<? extends Layer>, Class<? extends SessionLayerExporter>> sessionLayerExporters = new HashMap<>(); 82 private static final Map<Class<? extends Layer>, Class<? extends SessionLayerExporter>> sessionLayerExporters 83 = new HashMap<>(); 84 private static final Map<Class<? extends Command>, Class<? extends SessionCommandExporter>> sessionCommandExporters 85 = new HashMap<>(); 59 86 60 87 private final List<Layer> layers; 61 88 private final int active; … … 66 93 private ZipOutputStream zipOut; 67 94 68 95 static { 96 // Layers 69 97 registerSessionLayerExporter(OsmDataLayer.class, OsmDataSessionExporter.class); 70 98 registerSessionLayerExporter(TMSLayer.class, ImagerySessionExporter.class); 71 99 registerSessionLayerExporter(WMSLayer.class, ImagerySessionExporter.class); … … 74 102 registerSessionLayerExporter(GeoImageLayer.class, GeoImageSessionExporter.class); 75 103 registerSessionLayerExporter(MarkerLayer.class, MarkerSessionExporter.class); 76 104 registerSessionLayerExporter(NoteLayer.class, NoteSessionExporter.class); 105 // Commands TODO 106 registerSessionCommandExporter(AddCommand.class, AddCommandExporter.class); 107 registerSessionCommandExporter(AddPrimitivesCommand.class, null); 108 registerSessionCommandExporter(ChangeCommand.class, ChangeCommandExporter.class); 109 registerSessionCommandExporter(ChangeNodesCommand.class, null); 110 registerSessionCommandExporter(ChangePropertyCommand.class, null); 111 registerSessionCommandExporter(ChangePropertyKeyCommand.class, null); 112 registerSessionCommandExporter(ChangeRelationMemberRoleCommand.class, null); 113 registerSessionCommandExporter(DeleteCommand.class, null); 114 registerSessionCommandExporter(MoveCommand.class, null); 115 registerSessionCommandExporter(RemoveNodesCommand.class, null); 116 registerSessionCommandExporter(RotateCommand.class, null); 117 registerSessionCommandExporter(ScaleCommand.class, null); 118 registerSessionCommandExporter(SelectCommand.class, null); 119 registerSessionCommandExporter(SequenceCommand.class, SequenceCommandExporter.class); 120 registerSessionCommandExporter(SplitWayCommand.class, null); 121 registerSessionCommandExporter(TransformNodesCommand.class, null); 77 122 } 78 123 79 124 /** … … 88 133 } 89 134 90 135 /** 136 * Register a session layer exporter. 137 * 138 * The exporter class must have a one-argument constructor with commandClass as formal parameter type. 139 * @param commandClass command class 140 * @param exporter exporter for this command class 141 * @since xxx 142 */ 143 public static void registerSessionCommandExporter(Class<? extends Command> commandClass, Class<? extends SessionCommandExporter> exporter) { 144 sessionCommandExporters.put(commandClass, exporter); 145 } 146 147 /** 91 148 * Returns the session layer exporter for the given layer. 92 149 * @param layer layer to export 93 * @return session layer exporter for the given layer 150 * @return session layer exporter for the given layer, or null 94 151 */ 95 152 public static SessionLayerExporter getSessionLayerExporter(Layer layer) { 96 Class<? extends Layer> layerClass = layer.getClass(); 97 Class<? extends SessionLayerExporter> exporterClass = sessionLayerExporters.get(layerClass); 153 return getSessionExporter(sessionLayerExporters, layer.getClass(), layer); 154 } 155 156 /** 157 * Returns the session command exporter for the given command. 158 * @param command command to export 159 * @return session command exporter for the given command, or null 160 * @since xxx 161 */ 162 public static SessionCommandExporter getSessionCommandExporter(Command command) { 163 return getSessionExporter(sessionCommandExporters, command.getClass(), command); 164 } 165 166 private static <E, T> E getSessionExporter(Map<Class<? extends T>, Class<? extends E>> exporters, Class<? extends T> klass, T obj) { 167 Class<? extends E> exporterClass = exporters.get(klass); 98 168 if (exporterClass == null) 99 169 return null; 100 170 try { 101 return exporterClass.getConstructor( layerClass).newInstance(layer);171 return exporterClass.getConstructor(klass).newInstance(obj); 102 172 } catch (ReflectiveOperationException e) { 103 throw new JosmRuntimeException(e); 173 Logging.error(e); 174 return null; 104 175 } 105 176 } 106 177 … … 252 323 } 253 324 layersEl.appendChild(el); 254 325 } 326 writeCommandStack(root); 255 327 return doc; 256 328 } 257 329 330 private void writeCommandStack(Element root) { 331 Document doc = root.getOwnerDocument(); 332 Element commandsEl = doc.createElement("commands"); 333 root.appendChild(commandsEl); 334 addCommands(doc, commandsEl.appendChild(doc.createElement("undo")), UndoRedoHandler.getInstance().getUndoCommands()); 335 addCommands(doc, commandsEl.appendChild(doc.createElement("redo")), UndoRedoHandler.getInstance().getRedoCommands()); 336 } 337 338 private void addCommands(Document doc, Node commandsEl, List<Command> commands) { 339 Map<DataSet, Integer> layerIndexMap = new HashMap<>(); 340 for (Command c : commands) { 341 DataSet ds = c.getAffectedDataSet(); 342 Integer layerIndex = layerIndexMap.computeIfAbsent(ds, x -> { 343 for (int i = 0; i < layers.size(); i++) { 344 Layer l = layers.get(i); 345 if (l instanceof OsmDataLayer && ((OsmDataLayer) l).getDataSet() == ds) { 346 return i + 1; 347 } 348 } 349 return -1; 350 }); 351 addCommand(commandsEl, c, new ExportSupport(doc, layerIndex)); 352 } 353 } 354 355 static Node addCommand(Node commandsEl, Command c, ExportSupport support) { 356 SessionCommandExporter exporter = getSessionCommandExporter(c); 357 if (exporter == null) { 358 exporter = new ErrorCommandExporter(c); 359 } 360 return commandsEl.appendChild(exporter.export(support)); 361 } 362 258 363 private static void writeViewPort(Element root) { 259 364 Document doc = root.getOwnerDocument(); 260 365 Element viewportEl = doc.createElement("viewport");
