001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.awt.GridBagLayout; 008import java.awt.event.KeyEvent; 009import java.beans.PropertyChangeListener; 010import java.io.File; 011 012import javax.swing.JCheckBox; 013import javax.swing.JLabel; 014import javax.swing.JPanel; 015import javax.swing.SwingConstants; 016 017import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener; 018import org.openstreetmap.josm.gui.ExtendedDialog; 019import org.openstreetmap.josm.gui.MainApplication; 020import org.openstreetmap.josm.gui.layer.GpxLayer; 021import org.openstreetmap.josm.gui.layer.Layer; 022import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; 023import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; 024import org.openstreetmap.josm.gui.layer.OsmDataLayer; 025import org.openstreetmap.josm.gui.layer.SaveToFile; 026import org.openstreetmap.josm.gui.util.GuiHelper; 027import org.openstreetmap.josm.spi.preferences.Config; 028import org.openstreetmap.josm.tools.GBC; 029import org.openstreetmap.josm.tools.Shortcut; 030 031/** 032 * Export the data as an OSM xml file. 033 * 034 * @author imi 035 */ 036public final class SaveAction extends SaveActionBase { 037 private static SaveAction instance = new SaveAction(); 038 039 private final PropertyChangeListener updateOnRequireSaveChange = evt -> { 040 if (OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP.equals(evt.getPropertyName())) { 041 updateEnabledState(); 042 } 043 }; 044 045 private final GpxDataChangeListener updateOnRequireSaveChangeGpx = evt -> updateEnabledState(); 046 047 /** 048 * Construct the action with "Save" as label. 049 */ 050 private SaveAction() { 051 super(tr("Save"), "save", tr("Save the current data."), 052 Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.CTRL), 053 true); 054 setHelpId(ht("/Action/Save")); 055 } 056 057 /** 058 * Returns the unique instance. 059 * @return the unique instance 060 */ 061 public static SaveAction getInstance() { 062 return instance; 063 } 064 065 @Override 066 protected LayerChangeAdapter buildLayerChangeAdapter() { 067 return new LayerChangeAdapter() { 068 @Override 069 public void layerAdded(LayerAddEvent e) { 070 Layer l = e.getAddedLayer(); 071 if (l instanceof OsmDataLayer) { 072 l.addPropertyChangeListener(updateOnRequireSaveChange); 073 } 074 if (l instanceof GpxLayer) { 075 ((GpxLayer) l).data.addWeakChangeListener(updateOnRequireSaveChangeGpx); 076 } 077 super.layerAdded(e); 078 } 079 080 @Override 081 public void layerRemoving(LayerRemoveEvent e) { 082 Layer l = e.getRemovedLayer(); 083 if (l instanceof OsmDataLayer) { 084 l.removePropertyChangeListener(updateOnRequireSaveChange); 085 } 086 if (l instanceof GpxLayer) { 087 ((GpxLayer) l).data.removeChangeListener(updateOnRequireSaveChangeGpx); 088 } 089 super.layerRemoving(e); 090 } 091 }; 092 } 093 094 @Override 095 protected void updateEnabledState() { 096 Layer activeLayer = getLayerManager().getActiveLayer(); 097 boolean en = activeLayer != null 098 && activeLayer.isSavable() && (!(activeLayer.getAssociatedFile() != null 099 && activeLayer instanceof SaveToFile && !((SaveToFile) activeLayer).requiresSaveToFile())); 100 GuiHelper.runInEDT(() -> setEnabled(en)); 101 } 102 103 @Override 104 public File getFile(Layer layer) { 105 File f = layer.getAssociatedFile(); 106 if (f != null && !f.exists()) { 107 f = null; 108 } 109 110 // Ask for overwrite in case of GpxLayer 111 if (f != null && layer instanceof GpxLayer && !Config.getPref().getBoolean("gpx.export.overwrite", false)) { 112 JPanel p = new JPanel(new GridBagLayout()); 113 JLabel label = new JLabel(tr("File {0} exists. Overwrite?", f.getName())); 114 label.setHorizontalAlignment(SwingConstants.CENTER); 115 JCheckBox remember = new JCheckBox(tr("Remember choice")); 116 remember.setHorizontalAlignment(SwingConstants.CENTER); 117 p.add(label, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 10)); 118 p.add(remember, GBC.eop().fill(GBC.HORIZONTAL)); 119 ExtendedDialog dialog = new ExtendedDialog( 120 MainApplication.getMainFrame(), 121 tr("Overwrite"), 122 tr("Overwrite"), tr("Cancel")) 123 .setButtonIcons("save_as", "cancel") 124 .setContent(p); 125 if (dialog.showDialog().getValue() != 1) { 126 f = null; 127 } else if (remember.isSelected()) { 128 Config.getPref().putBoolean("gpx.export.overwrite", true); 129 } 130 } 131 return f == null ? layer.createAndOpenSaveFileChooser() : f; 132 } 133}