Ticket #17052: 17052.core.patch
| File 17052.core.patch, 24.4 KB (added by , 3 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/SessionLoadAction.java
Subject: [PATCH] ImportExportPlugins --- IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/actions/SessionLoadAction.java b/src/org/openstreetmap/josm/actions/SessionLoadAction.java
a b 12 12 import java.nio.file.Files; 13 13 import java.nio.file.StandardCopyOption; 14 14 import java.util.Arrays; 15 import java.util.EnumSet; 15 16 import java.util.List; 16 17 17 18 import javax.swing.JFileChooser; … … 33 34 import org.openstreetmap.josm.io.session.SessionReader; 34 35 import org.openstreetmap.josm.io.session.SessionReader.SessionProjectionChoiceData; 35 36 import org.openstreetmap.josm.io.session.SessionReader.SessionViewportData; 37 import org.openstreetmap.josm.io.session.SessionWriter; 36 38 import org.openstreetmap.josm.tools.CheckParameterUtil; 37 39 import org.openstreetmap.josm.tools.JosmRuntimeException; 38 40 import org.openstreetmap.josm.tools.Logging; … … 205 207 postLoadTasks = reader.getPostLoadTasks(); 206 208 viewport = reader.getViewport(); 207 209 projectionChoice = reader.getProjectionChoice(); 208 SessionSaveAction.setCurrentSession(file, zip, reader.getLayers()); 210 final EnumSet<SessionWriter.SessionWriterFlags> flagSet = EnumSet.noneOf(SessionWriter.SessionWriterFlags.class); 211 if (zip) { 212 flagSet.add(SessionWriter.SessionWriterFlags.IS_ZIP); 213 } 214 if (reader.loadedPluginData()) { 215 flagSet.add(SessionWriter.SessionWriterFlags.SAVE_PLUGIN_INFORMATION); 216 } 217 SessionSaveAction.setCurrentSession(file, reader.getLayers(), flagSet); 209 218 } finally { 210 219 if (tempFile) { 211 220 Utils.deleteFile(file); -
src/org/openstreetmap/josm/actions/SessionSaveAction.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/actions/SessionSaveAction.java b/src/org/openstreetmap/josm/actions/SessionSaveAction.java
a b 17 17 import java.util.ArrayList; 18 18 import java.util.Arrays; 19 19 import java.util.Collection; 20 import java.util.EnumSet; 20 21 import java.util.HashMap; 21 22 import java.util.HashSet; 22 23 import java.util.List; … … 56 57 import org.openstreetmap.josm.gui.util.GuiHelper; 57 58 import org.openstreetmap.josm.gui.util.WindowGeometry; 58 59 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser; 60 import org.openstreetmap.josm.io.session.PluginSessionExporter; 59 61 import org.openstreetmap.josm.io.session.SessionLayerExporter; 60 62 import org.openstreetmap.josm.io.session.SessionWriter; 63 import org.openstreetmap.josm.plugins.PluginHandler; 61 64 import org.openstreetmap.josm.spi.preferences.Config; 62 65 import org.openstreetmap.josm.tools.GBC; 63 66 import org.openstreetmap.josm.tools.JosmRuntimeException; … … 78 81 private transient MultiMap<Layer, Layer> dependencies; 79 82 80 83 private static final BooleanProperty SAVE_LOCAL_FILES_PROPERTY = new BooleanProperty("session.savelocal", true); 84 private static final BooleanProperty SAVE_PLUGIN_INFORMATION_PROPERTY = new BooleanProperty("session.saveplugins", false); 81 85 private static final String TOOLTIP_DEFAULT = tr("Save the current session."); 82 86 83 87 protected transient FileFilter joz = new ExtensionFileFilter("joz", "joz", tr("Session file (archive) (*.joz)")); … … 88 92 private static String tooltip = TOOLTIP_DEFAULT; 89 93 static File sessionFile; 90 94 static boolean isZipSessionFile; 95 private static boolean pluginData; 91 96 static List<WeakReference<Layer>> layersInSessionFile; 92 97 93 98 private static final SessionSaveAction instance = new SessionSaveAction(); … … 170 175 .collect(Collectors.toList()); 171 176 172 177 boolean zipRequired = layersOut.stream().map(l -> exporters.get(l)) 173 .anyMatch(ex -> ex != null && ex.requiresZip()) ;178 .anyMatch(ex -> ex != null && ex.requiresZip()) || pluginsWantToSave(); 174 179 175 180 saveAs = !doGetFile(saveAs, zipRequired); 176 181 … … 240 245 active = layersOut.indexOf(activeLayer); 241 246 } 242 247 243 SessionWriter sw = new SessionWriter(layersOut, active, exporters, dependencies, isZipSessionFile); 248 final EnumSet<SessionWriter.SessionWriterFlags> flags = EnumSet.noneOf(SessionWriter.SessionWriterFlags.class); 249 if (pluginData || Boolean.TRUE.equals(SAVE_PLUGIN_INFORMATION_PROPERTY.get()) && pluginsWantToSave()) { 250 flags.add(SessionWriter.SessionWriterFlags.SAVE_PLUGIN_INFORMATION); 251 } 252 if (isZipSessionFile) { 253 flags.add(SessionWriter.SessionWriterFlags.IS_ZIP); 254 } 255 SessionWriter sw = new SessionWriter(layersOut, active, exporters, dependencies, flags.toArray(new SessionWriter.SessionWriterFlags[0])); 244 256 try { 245 257 Notification savingNotification = showSavingNotification(sessionFile.getName()); 246 258 sw.write(sessionFile); … … 434 446 op.add(tabs, GBC.eol().fill()); 435 447 JCheckBox chkSaveLocal = new JCheckBox(tr("Save all local files to disk"), SAVE_LOCAL_FILES_PROPERTY.get()); 436 448 chkSaveLocal.addChangeListener(l -> SAVE_LOCAL_FILES_PROPERTY.put(chkSaveLocal.isSelected())); 437 op.add(chkSaveLocal); 449 op.add(chkSaveLocal, GBC.eol()); 450 if (pluginsWantToSave()) { 451 JCheckBox chkSavePlugins = new JCheckBox(tr("Save plugin information to disk"), SAVE_PLUGIN_INFORMATION_PROPERTY.get()); 452 chkSavePlugins.addChangeListener(l -> SAVE_PLUGIN_INFORMATION_PROPERTY.put(chkSavePlugins.isSelected())); 453 chkSavePlugins.setToolTipText(tr("Plugins may have additional information that can be saved")); 454 op.add(chkSavePlugins, GBC.eol()); 455 } 438 456 return op; 439 457 } 440 458 … … 509 527 * @param file file 510 528 * @param zip if it is a zip session file 511 529 * @param layers layers that are currently represented in the session file 530 * @deprecated since xxx, use {@link #setCurrentSession(File, List, SessionWriter.SessionWriterFlags...)} instead 512 531 */ 532 @Deprecated 513 533 public static void setCurrentSession(File file, boolean zip, List<Layer> layers) { 534 if (zip) { 535 setCurrentSession(file, layers, SessionWriter.SessionWriterFlags.IS_ZIP); 536 } else { 537 setCurrentSession(file, layers); 538 } 539 } 540 541 /** 542 * Sets the current session file and the layers included in that file 543 * @param file file 544 * @param layers layers that are currently represented in the session file 545 * @param flags The flags for the current session 546 * @since xxx 547 */ 548 public static void setCurrentSession(File file, List<Layer> layers, SessionWriter.SessionWriterFlags... flags) { 549 final EnumSet<SessionWriter.SessionWriterFlags> flagSet = EnumSet.noneOf(SessionWriter.SessionWriterFlags.class); 550 flagSet.addAll(Arrays.asList(flags)); 551 setCurrentSession(file, layers, flagSet); 552 } 553 554 /** 555 * Sets the current session file and the layers included in that file 556 * @param file file 557 * @param layers layers that are currently represented in the session file 558 * @param flags The flags for the current session 559 * @since xxx 560 */ 561 public static void setCurrentSession(File file, List<Layer> layers, Set<SessionWriter.SessionWriterFlags> flags) { 514 562 setCurrentLayers(layers); 515 setCurrentSession(file, zip); 563 setCurrentSession(file, flags.contains(SessionWriter.SessionWriterFlags.IS_ZIP)); 564 pluginData = flags.contains(SessionWriter.SessionWriterFlags.SAVE_PLUGIN_INFORMATION); 516 565 } 517 566 518 567 /** … … 550 599 return tooltip; 551 600 } 552 601 602 /** 603 * Check to see if any plugins want to save their state 604 * @return {@code true} if the plugin wants to save their state 605 */ 606 private static boolean pluginsWantToSave() { 607 for (PluginSessionExporter exporter : PluginHandler.load(PluginSessionExporter.class)) { 608 if (exporter.requiresSaving()) { 609 return true; 610 } 611 } 612 return false; 613 } 614 553 615 } -
src/org/openstreetmap/josm/io/session/GenericSessionExporter.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java b/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java
a b 31 31 import org.openstreetmap.josm.gui.util.GuiHelper; 32 32 import org.openstreetmap.josm.gui.widgets.JosmTextField; 33 33 import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 34 import org.openstreetmap.josm.plugins.PluginHandler; 34 35 import org.openstreetmap.josm.tools.GBC; 35 36 import org.openstreetmap.josm.tools.ImageProvider; 36 37 import org.w3c.dom.Element; … … 210 211 211 212 @Override 212 213 public boolean requiresZip() { 213 return include.isSelected(); 214 if (include.isSelected()) { 215 return true; 216 } 217 for (PluginSessionExporter exporter : PluginHandler.load(PluginSessionExporter.class)) { 218 if (exporter.requiresSaving()) { 219 return true; 220 } 221 } 222 return false; 214 223 } 215 224 216 225 protected abstract void addDataFile(OutputStream out) throws IOException; -
new file src/org/openstreetmap/josm/io/session/PluginSessionExporter.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/session/PluginSessionExporter.java b/src/org/openstreetmap/josm/io/session/PluginSessionExporter.java new file mode 100644
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import java.io.IOException; 5 import java.io.OutputStream; 6 import java.util.zip.ZipEntry; 7 import java.util.zip.ZipException; 8 import java.util.zip.ZipOutputStream; 9 10 /** 11 * Export arbitrary data from a plugin. 12 * @since xxx 13 */ 14 public interface PluginSessionExporter { 15 /** 16 * Get the filename to store the data in the archive 17 * @return The filename 18 * @see PluginSessionImporter#getFileName() 19 */ 20 String getFileName(); 21 22 /** 23 * Check to see if the specified exporter needs to save anything 24 * @return {@code true} if the exporter needs to save something 25 */ 26 boolean requiresSaving(); 27 28 /** 29 * Write data to a zip file 30 * @param zipOut The zip output stream 31 * @throws IOException see {@link ZipOutputStream#putNextEntry(ZipEntry)} 32 * @throws ZipException see {@link ZipOutputStream#putNextEntry(ZipEntry)} 33 */ 34 default void writeZipEntries(ZipOutputStream zipOut) throws IOException { 35 if (requiresSaving()) { 36 final ZipEntry zipEntry = new ZipEntry(this.getFileName()); 37 zipOut.putNextEntry(zipEntry); 38 this.write(zipOut); 39 } 40 } 41 42 /** 43 * Write the plugin data to a stream 44 * @param outputStream The stream to write to 45 */ 46 void write(OutputStream outputStream); 47 } -
new file src/org/openstreetmap/josm/io/session/PluginSessionImporter.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/session/PluginSessionImporter.java b/src/org/openstreetmap/josm/io/session/PluginSessionImporter.java new file mode 100644
- + 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.io.session; 3 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.util.zip.ZipEntry; 7 import java.util.zip.ZipFile; 8 9 /** 10 * Import arbitrary data for a plugin. 11 * @since xxx 12 */ 13 public interface PluginSessionImporter { 14 /** 15 * Get the filename that was used to store data in the archive. 16 * @return The filename 17 * @see PluginSessionExporter#getFileName() 18 */ 19 String getFileName(); 20 21 /** 22 * Read data from a file stream 23 * @param inputStream The stream to read 24 * @return {@code true} if the importer loaded data 25 */ 26 boolean read(InputStream inputStream); 27 28 /** 29 * Read the data from a zip file 30 * @param zipFile The zipfile to read 31 * @return {@code true} if the importer loaded data 32 * @throws IOException if there was an issue reading the zip file. See {@link ZipFile#getInputStream(ZipEntry)}. 33 */ 34 default boolean readZipFile(ZipFile zipFile) throws IOException { 35 final ZipEntry entry = zipFile.getEntry(this.getFileName()); 36 if (entry != null) { 37 try (InputStream inputStream = zipFile.getInputStream(entry)) { 38 return this.read(inputStream); 39 } 40 } 41 return false; 42 } 43 } -
src/org/openstreetmap/josm/io/session/SessionReader.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/session/SessionReader.java b/src/org/openstreetmap/josm/io/session/SessionReader.java
a b 39 39 import org.openstreetmap.josm.data.coor.ILatLon; 40 40 import org.openstreetmap.josm.data.coor.LatLon; 41 41 import org.openstreetmap.josm.data.projection.Projection; 42 import org.openstreetmap.josm.gui.ExceptionDialogUtil; 42 43 import org.openstreetmap.josm.gui.ExtendedDialog; 43 44 import org.openstreetmap.josm.gui.MainApplication; 44 45 import org.openstreetmap.josm.gui.layer.Layer; 45 46 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 46 47 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 48 import org.openstreetmap.josm.gui.util.GuiHelper; 47 49 import org.openstreetmap.josm.io.Compression; 48 50 import org.openstreetmap.josm.io.IllegalDataException; 51 import org.openstreetmap.josm.plugins.PluginHandler; 49 52 import org.openstreetmap.josm.tools.CheckParameterUtil; 50 53 import org.openstreetmap.josm.tools.JosmRuntimeException; 51 54 import org.openstreetmap.josm.tools.Logging; … … 156 159 157 160 private URI sessionFileURI; 158 161 private boolean zip; // true, if session file is a .joz file; false if it is a .jos file 162 private boolean pluginData; // true, if a plugin restored state from a .joz file. False otherwise. 159 163 private ZipFile zipFile; 160 164 private List<Layer> layers = new ArrayList<>(); 161 165 private int active = -1; … … 192 196 Class<? extends SessionLayerImporter> importerClass = sessionLayerImporters.get(layerType); 193 197 if (importerClass == null) 194 198 return null; 195 SessionLayerImporter importer = null;199 SessionLayerImporter importer; 196 200 try { 197 201 importer = importerClass.getConstructor().newInstance(); 198 202 } catch (ReflectiveOperationException e) { … … 243 247 return projectionChoice; 244 248 } 245 249 250 /** 251 * Returns whether plugins loaded additonal data 252 * @return {@code true} if at least one plugin loaded additional data 253 * @since xxx 254 */ 255 public boolean loadedPluginData() { 256 return this.pluginData; 257 } 258 246 259 /** 247 260 * A class that provides some context for the individual {@link SessionLayerImporter} 248 261 * when doing the import. … … 308 321 309 322 /** 310 323 * Return an InputStream for a URI from a .jos/.joz file. 311 * 324 * <p> 312 325 * The following forms are supported: 313 * 326 * <p> 314 327 * - absolute file (both .jos and .joz): 315 328 * "file:///home/user/data.osm" 316 329 * "file:/home/user/data.osm" … … 351 364 352 365 /** 353 366 * Return a File for a URI from a .jos/.joz file. 354 * 367 * <p> 355 368 * Returns null if the URI points to a file inside the zip archive. 356 369 * In this case, inZipPath will be set to the corresponding path. 357 370 * @param uriStr the URI as string … … 712 725 /** 713 726 * Show Dialog when there is an error for one layer. 714 727 * Ask the user whether to cancel the complete session loading or just to skip this layer. 715 * 728 * <p> 716 729 * This is expected to run in a worker thread (PleaseWaitRunnable), so invokeAndWait is 717 730 * needed to block the current thread and wait for the result of the modal dialog from EDT. 718 731 */ … … 742 755 } 743 756 } 744 757 758 private void loadPluginData() { 759 if (!zip) { 760 return; 761 } 762 for (PluginSessionImporter importer : PluginHandler.load(PluginSessionImporter.class)) { 763 try { 764 this.pluginData |= importer.readZipFile(zipFile); 765 } catch (IOException ioException) { 766 GuiHelper.runInEDT(() -> ExceptionDialogUtil.explainException(ioException)); 767 } 768 } 769 } 770 745 771 /** 746 772 * Loads session from the given file. 747 773 * @param sessionFile session file to load … … 753 779 public void loadSession(File sessionFile, boolean zip, ProgressMonitor progressMonitor) throws IllegalDataException, IOException { 754 780 try (InputStream josIS = createInputStream(sessionFile, zip)) { 755 781 loadSession(josIS, sessionFile.toURI(), zip, progressMonitor); 782 this.postLoadTasks.add(this::loadPluginData); 756 783 } 757 784 } 758 785 -
src/org/openstreetmap/josm/io/session/SessionWriter.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/session/SessionWriter.java b/src/org/openstreetmap/josm/io/session/SessionWriter.java
a b 9 9 import java.nio.charset.StandardCharsets; 10 10 import java.nio.file.Files; 11 11 import java.util.Collection; 12 import java.util.EnumSet; 12 13 import java.util.HashMap; 13 14 import java.util.List; 14 15 import java.util.Locale; … … 43 44 import org.openstreetmap.josm.gui.layer.geoimage.GeoImageLayer; 44 45 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 45 46 import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference; 47 import org.openstreetmap.josm.plugins.PluginHandler; 46 48 import org.openstreetmap.josm.tools.JosmRuntimeException; 47 49 import org.openstreetmap.josm.tools.Logging; 48 50 import org.openstreetmap.josm.tools.MultiMap; … … 58 60 */ 59 61 public class SessionWriter { 60 62 63 /** 64 * {@link SessionWriter} options 65 * @since xxx 66 */ 67 public enum SessionWriterFlags { 68 /** 69 * Use if the file to be written needs to be a zip file 70 */ 71 IS_ZIP, 72 /** 73 * Use if there are plugins that want to save information 74 */ 75 SAVE_PLUGIN_INFORMATION 76 } 77 61 78 private static final Map<Class<? extends Layer>, Class<? extends SessionLayerExporter>> sessionLayerExporters = new HashMap<>(); 62 79 63 80 private final List<Layer> layers; … … 65 82 private final Map<Layer, SessionLayerExporter> exporters; 66 83 private final MultiMap<Layer, Layer> dependencies; 67 84 private final boolean zip; 85 private final boolean plugins; 68 86 69 87 private ZipOutputStream zipOut; 70 88 … … 82 100 83 101 /** 84 102 * Register a session layer exporter. 85 * 103 * <p> 86 104 * The exporter class must have a one-argument constructor with layerClass as formal parameter type. 87 105 * @param layerClass layer class 88 106 * @param exporter exporter for this layer class … … 120 138 */ 121 139 public SessionWriter(List<Layer> layers, int active, Map<Layer, SessionLayerExporter> exporters, 122 140 MultiMap<Layer, Layer> dependencies, boolean zip) { 141 this(layers, active, exporters, dependencies, 142 zip ? new SessionWriterFlags[] {SessionWriterFlags.IS_ZIP} : new SessionWriterFlags[0]); 143 } 144 145 /** 146 * Constructs a new {@code SessionWriter}. 147 * @param layers The ordered list of layers to save 148 * @param active The index of active layer in {@code layers} (starts at 0). Ignored if set to -1 149 * @param exporters The exporters to use to save layers 150 * @param dependencies layer dependencies 151 * @param flags The flags to use when writing data 152 * @since xxx 153 */ 154 public SessionWriter(List<Layer> layers, int active, Map<Layer, SessionLayerExporter> exporters, 155 MultiMap<Layer, Layer> dependencies, SessionWriterFlags... flags) { 123 156 this.layers = layers; 124 157 this.active = active; 125 158 this.exporters = exporters; 126 159 this.dependencies = dependencies; 127 this.zip = zip; 160 final EnumSet<SessionWriterFlags> flagSet = flags.length == 0 ? EnumSet.noneOf(SessionWriterFlags.class) : 161 EnumSet.of(flags[0], flags); 162 this.zip = flagSet.contains(SessionWriterFlags.IS_ZIP); 163 this.plugins = flagSet.contains(SessionWriterFlags.SAVE_PLUGIN_INFORMATION); 128 164 } 129 165 130 166 /** … … 218 254 * @throws IOException if any I/O error occurs 219 255 */ 220 256 public Document createJosDocument() throws IOException { 221 DocumentBuilder builder = null;257 DocumentBuilder builder; 222 258 try { 223 259 builder = XmlUtils.newSafeDOMBuilder(); 224 260 } catch (ParserConfigurationException e) { … … 361 397 ZipEntry entry = new ZipEntry("session.jos"); 362 398 zipOut.putNextEntry(entry); 363 399 writeJos(doc, zipOut); 400 if (this.plugins) { 401 for (PluginSessionExporter exporter : PluginHandler.load(PluginSessionExporter.class)) { 402 exporter.writeZipEntries(zipOut); 403 } 404 } 364 405 Utils.close(zipOut); 365 406 } else { 366 407 writeJos(doc, new BufferedOutputStream(out)); -
src/org/openstreetmap/josm/plugins/PluginHandler.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/plugins/PluginHandler.java b/src/org/openstreetmap/josm/plugins/PluginHandler.java
a b 32 32 import java.util.Map; 33 33 import java.util.Map.Entry; 34 34 import java.util.Objects; 35 import java.util.ServiceLoader; 35 36 import java.util.Set; 36 37 import java.util.TreeMap; 37 38 import java.util.TreeSet; … … 357 358 return Collections.unmodifiableCollection(classLoaders.values()); 358 359 } 359 360 361 /** 362 * Get a {@link ServiceLoader} for the specified service. This uses {@link #getJoinedPluginResourceCL()} as the 363 * class loader, so that we don't have to iterate through the {@link ClassLoader}s from {@link #getPluginClassLoaders()}. 364 * @param <S> The service type 365 * @param service The service class to look for 366 * @return The service loader 367 * @since xxx 368 */ 369 public static <S> ServiceLoader<S> load(Class<S> service) { 370 return ServiceLoader.load(service, getJoinedPluginResourceCL()); 371 } 372 360 373 /** 361 374 * Removes deprecated plugins from a collection of plugins. Modifies the 362 375 * collection <code>plugins</code>.
