Changeset 18466 in josm for trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java
- Timestamp:
- 2022-06-06T19:07:05+02:00 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java
r18406 r18466 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.awt.Component;8 import java.awt.Dimension;9 import java.awt.GridBagLayout;10 7 import java.awt.event.ActionEvent; 11 import java.io.File; 12 import java.io.IOException; 13 import java.util.ArrayList; 14 import java.util.Arrays; 15 import java.util.Collection; 16 import java.util.HashMap; 17 import java.util.HashSet; 18 import java.util.List; 19 import java.util.Map; 20 import java.util.Set; 21 import java.util.stream.Collectors; 22 import java.util.stream.Stream; 8 import java.awt.event.KeyEvent; 23 9 24 import javax.swing.BorderFactory;25 import javax.swing.JCheckBox;26 import javax.swing.JFileChooser;27 import javax.swing.JLabel;28 import javax.swing.JOptionPane;29 import javax.swing.JPanel;30 import javax.swing.JScrollPane;31 import javax.swing.JTabbedPane;32 import javax.swing.SwingConstants;33 import javax.swing.border.EtchedBorder;34 import javax.swing.filechooser.FileFilter;35 36 import org.openstreetmap.josm.data.preferences.BooleanProperty;37 import org.openstreetmap.josm.gui.ExtendedDialog;38 import org.openstreetmap.josm.gui.HelpAwareOptionPane;39 10 import org.openstreetmap.josm.gui.MainApplication; 40 import org.openstreetmap.josm.gui.MapFrame;41 import org.openstreetmap.josm.gui.MapFrameListener;42 import org.openstreetmap.josm.gui.Notification;43 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;44 import org.openstreetmap.josm.gui.layer.Layer;45 import org.openstreetmap.josm.gui.util.WindowGeometry;46 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;47 import org.openstreetmap.josm.io.session.SessionLayerExporter;48 import org.openstreetmap.josm.io.session.SessionWriter;49 import org.openstreetmap.josm.tools.GBC;50 import org.openstreetmap.josm.tools.JosmRuntimeException;51 11 import org.openstreetmap.josm.tools.Logging; 52 import org.openstreetmap.josm.tools. MultiMap;12 import org.openstreetmap.josm.tools.Shortcut; 53 13 import org.openstreetmap.josm.tools.UserCancelException; 54 import org.openstreetmap.josm.tools.Utils;55 14 56 15 /** 57 * Saves a JOSM session 16 * Saves a JOSM session to a new file 58 17 * @since 4685 59 18 */ 60 public class SessionSaveAsAction extends DiskAccessAction implements MapFrameListener { 61 62 private transient List<Layer> layers; 63 private transient Map<Layer, SessionLayerExporter> exporters; 64 private transient MultiMap<Layer, Layer> dependencies; 65 66 private static final BooleanProperty SAVE_LOCAL_FILES_PROPERTY = new BooleanProperty("session.savelocal", true); 19 public class SessionSaveAsAction extends SessionSaveAction { 67 20 68 21 /** … … 80 33 */ 81 34 protected SessionSaveAsAction(boolean toolbar, boolean installAdapters) { 35 82 36 super(tr("Save Session As..."), "session", tr("Save the current session to a new file."), 83 null, toolbar, "save_as-session", installAdapters); 37 Shortcut.registerShortcut("system:savesessionas", tr("File: {0}", tr("Save Session As...")), 38 KeyEvent.VK_S, Shortcut.ALT_CTRL_SHIFT), 39 toolbar, "save_as-session", installAdapters); 40 84 41 setHelpId(ht("/Action/SessionSaveAs")); 85 MainApplication.addMapFrameListener(this);86 42 } 87 43 … … 89 45 public void actionPerformed(ActionEvent e) { 90 46 try { 91 saveSession(); 47 saveSession(true, false); 92 48 } catch (UserCancelException ignore) { 93 49 Logging.trace(ignore); … … 96 52 97 53 @Override 98 public void destroy() { 99 MainApplication.removeMapFrameListener(this); 100 super.destroy(); 101 } 102 103 /** 104 * Attempts to save the session. 105 * @throws UserCancelException when the user has cancelled the save process. 106 * @since 8913 107 */ 108 public void saveSession() throws UserCancelException { 109 if (!isEnabled()) { 110 return; 111 } 112 113 SessionSaveAsDialog dlg = new SessionSaveAsDialog(); 114 dlg.showDialog(); 115 if (dlg.getValue() != 1) { 116 throw new UserCancelException(); 117 } 118 119 // TODO: resolve dependencies for layers excluded by the user 120 List<Layer> layersOut = layers.stream() 121 .filter(layer -> exporters.get(layer) != null && exporters.get(layer).shallExport()) 122 .collect(Collectors.toList()); 123 124 boolean zipRequired = layersOut.stream().map(exporters::get) 125 .anyMatch(ex -> ex != null && ex.requiresZip()); 126 127 FileFilter joz = new ExtensionFileFilter("joz", "joz", tr("Session file (archive) (*.joz)")); 128 FileFilter jos = new ExtensionFileFilter("jos", "jos", tr("Session file (*.jos)")); 129 130 AbstractFileChooser fc; 131 132 if (zipRequired) { 133 fc = createAndOpenFileChooser(false, false, tr("Save Session"), joz, JFileChooser.FILES_ONLY, "lastDirectory"); 134 } else { 135 fc = createAndOpenFileChooser(false, false, tr("Save Session"), Arrays.asList(jos, joz), jos, 136 JFileChooser.FILES_ONLY, "lastDirectory"); 137 } 138 139 if (fc == null) { 140 throw new UserCancelException(); 141 } 142 143 File file = fc.getSelectedFile(); 144 String fn = file.getName(); 145 146 boolean zip; 147 FileFilter ff = fc.getFileFilter(); 148 if (zipRequired || joz.equals(ff)) { 149 zip = true; 150 } else if (jos.equals(ff)) { 151 zip = false; 152 } else { 153 if (Utils.hasExtension(fn, "joz")) { 154 zip = true; 155 } else { 156 zip = false; 157 } 158 } 159 if (fn.indexOf('.') == -1) { 160 file = new File(file.getPath() + (zip ? ".joz" : ".jos")); 161 if (!SaveActionBase.confirmOverwrite(file)) { 162 throw new UserCancelException(); 163 } 164 } 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 } 193 194 int active = -1; 195 Layer activeLayer = getLayerManager().getActiveLayer(); 196 if (activeLayer != null) { 197 active = layersOut.indexOf(activeLayer); 198 } 199 200 SessionWriter sw = new SessionWriter(layersOut, active, exporters, dependencies, zip); 201 try { 202 Notification savingNotification = showSavingNotification(file.getName()); 203 sw.write(file); 204 SaveActionBase.addToFileOpenHistory(file); 205 showSavedNotification(savingNotification, file.getName()); 206 } catch (IOException ex) { 207 Logging.error(ex); 208 HelpAwareOptionPane.showMessageDialogInEDT( 209 MainApplication.getMainFrame(), 210 tr("<html>Could not save session file ''{0}''.<br>Error is:<br>{1}</html>", 211 file.getName(), Utils.escapeReservedCharactersHTML(ex.getMessage())), 212 tr("IO Error"), 213 JOptionPane.ERROR_MESSAGE, 214 null 215 ); 216 } 217 } 218 219 /** 220 * The "Save Session" dialog 221 */ 222 public class SessionSaveAsDialog extends ExtendedDialog { 223 224 /** 225 * Constructs a new {@code SessionSaveAsDialog}. 226 */ 227 public SessionSaveAsDialog() { 228 super(MainApplication.getMainFrame(), tr("Save Session"), tr("Save As"), tr("Cancel")); 229 configureContextsensitiveHelp("Action/SessionSaveAs", true /* show help button */); 230 initialize(); 231 setButtonIcons("save_as", "cancel"); 232 setDefaultButton(1); 233 setRememberWindowGeometry(getClass().getName() + ".geometry", 234 WindowGeometry.centerInWindow(MainApplication.getMainFrame(), new Dimension(450, 450))); 235 setContent(build(), false); 236 } 237 238 /** 239 * Initializes action. 240 */ 241 public final void initialize() { 242 layers = new ArrayList<>(getLayerManager().getLayers()); 243 exporters = new HashMap<>(); 244 dependencies = new MultiMap<>(); 245 246 Set<Layer> noExporter = new HashSet<>(); 247 248 for (Layer layer : layers) { 249 SessionLayerExporter exporter = null; 250 try { 251 exporter = SessionWriter.getSessionLayerExporter(layer); 252 } catch (IllegalArgumentException | JosmRuntimeException e) { 253 Logging.error(e); 254 } 255 if (exporter != null) { 256 exporters.put(layer, exporter); 257 Collection<Layer> deps = exporter.getDependencies(); 258 if (deps != null) { 259 dependencies.putAll(layer, deps); 260 } else { 261 dependencies.putVoid(layer); 262 } 263 } else { 264 noExporter.add(layer); 265 exporters.put(layer, null); 266 } 267 } 268 269 int numNoExporter = 0; 270 WHILE: while (numNoExporter != noExporter.size()) { 271 numNoExporter = noExporter.size(); 272 for (Layer layer : layers) { 273 if (noExporter.contains(layer)) continue; 274 for (Layer depLayer : dependencies.get(layer)) { 275 if (noExporter.contains(depLayer)) { 276 noExporter.add(layer); 277 exporters.put(layer, null); 278 break WHILE; 279 } 280 } 281 } 282 } 283 } 284 285 protected final Component build() { 286 JPanel op = new JPanel(new GridBagLayout()); 287 JPanel ip = new JPanel(new GridBagLayout()); 288 for (Layer layer : layers) { 289 JPanel wrapper = new JPanel(new GridBagLayout()); 290 wrapper.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); 291 Component exportPanel; 292 SessionLayerExporter exporter = exporters.get(layer); 293 if (exporter == null) { 294 if (!exporters.containsKey(layer)) throw new AssertionError(); 295 exportPanel = getDisabledExportPanel(layer); 296 } else { 297 exportPanel = exporter.getExportPanel(); 298 } 299 wrapper.add(exportPanel, GBC.std().fill(GBC.HORIZONTAL)); 300 ip.add(wrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(2, 2, 4, 2)); 301 } 302 ip.add(GBC.glue(0, 1), GBC.eol().fill(GBC.VERTICAL)); 303 JScrollPane sp = new JScrollPane(ip); 304 sp.setBorder(BorderFactory.createEmptyBorder()); 305 JPanel p = new JPanel(new GridBagLayout()); 306 p.add(sp, GBC.eol().fill()); 307 final JTabbedPane tabs = new JTabbedPane(); 308 tabs.addTab(tr("Layers"), p); 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; 316 } 317 318 protected final Component getDisabledExportPanel(Layer layer) { 319 JPanel p = new JPanel(new GridBagLayout()); 320 JCheckBox include = new JCheckBox(); 321 include.setEnabled(false); 322 JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEADING); 323 lbl.setToolTipText(tr("No exporter for this layer")); 324 lbl.setLabelFor(include); 325 lbl.setEnabled(false); 326 p.add(include, GBC.std()); 327 p.add(lbl, GBC.std()); 328 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL)); 329 return p; 330 } 54 protected void addListeners() { 55 MainApplication.addMapFrameListener(this); 331 56 } 332 57 333 58 @Override 334 protected void updateEnabledState() { 335 setEnabled(MainApplication.isDisplayingMapView()); 336 } 337 338 @Override 339 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 340 updateEnabledState(); 59 protected void removeListeners() { 60 MainApplication.removeMapFrameListener(this); 341 61 } 342 62 }
Note:
See TracChangeset
for help on using the changeset viewer.
