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.GpxConstants; 018import org.openstreetmap.josm.gui.ExtendedDialog; 019import org.openstreetmap.josm.gui.MainApplication; 020import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; 021import org.openstreetmap.josm.gui.layer.GpxLayer; 022import org.openstreetmap.josm.gui.layer.Layer; 023import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent; 024import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent; 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 final SaveAction instance = new SaveAction(); 038 039 private final PropertyChangeListener updateOnRequireSaveChange = evt -> { 040 if (AbstractModifiableLayer.REQUIRES_SAVE_TO_DISK_PROP.equals(evt.getPropertyName())) { 041 updateEnabledState(); 042 } 043 }; 044 045 /** 046 * Construct the action with "Save" as label. 047 */ 048 private SaveAction() { 049 super(tr("Save"), "save", tr("Save the current data."), 050 Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.CTRL), 051 true); 052 setHelpId(ht("/Action/Save")); 053 } 054 055 /** 056 * Returns the unique instance. 057 * @return the unique instance 058 */ 059 public static SaveAction getInstance() { 060 return instance; 061 } 062 063 @Override 064 protected LayerChangeAdapter buildLayerChangeAdapter() { 065 return new LayerChangeAdapter() { 066 @Override 067 public void layerAdded(LayerAddEvent e) { 068 Layer l = e.getAddedLayer(); 069 if (l instanceof AbstractModifiableLayer) { 070 l.addPropertyChangeListener(updateOnRequireSaveChange); 071 } 072 super.layerAdded(e); 073 } 074 075 @Override 076 public void layerRemoving(LayerRemoveEvent e) { 077 Layer l = e.getRemovedLayer(); 078 if (l instanceof AbstractModifiableLayer) { 079 l.removePropertyChangeListener(updateOnRequireSaveChange); 080 } 081 super.layerRemoving(e); 082 } 083 }; 084 } 085 086 @Override 087 protected boolean listenToSelectionChange() { 088 return false; 089 } 090 091 @Override 092 protected void updateEnabledState() { 093 Layer activeLayer = getLayerManager().getActiveLayer(); 094 boolean en = activeLayer != null 095 && activeLayer.isSavable() && !(activeLayer.getAssociatedFile() != null 096 && activeLayer instanceof SaveToFile && !((SaveToFile) activeLayer).requiresSaveToFile()); 097 GuiHelper.runInEDT(() -> setEnabled(en)); 098 } 099 100 @Override 101 public File getFile(Layer layer) { 102 File f = layer.getAssociatedFile(); 103 if (f != null && !f.exists()) { 104 f = null; 105 } 106 107 // Ask for overwrite in case of GpxLayer 108 if (f != null 109 && layer instanceof GpxLayer 110 && (((GpxLayer) layer).data == null 111 || !GpxConstants.JOSM_CREATOR_NAME.equals(((GpxLayer) layer).data.creator)) 112 && !Config.getPref().getBoolean("gpx.export.overwrite", false)) { 113 114 JPanel p = new JPanel(new GridBagLayout()); 115 JLabel label = new JLabel("<html>" 116 + tr("The file \"{0}\" will be modified.<br>Would you like to overwrite the existing file?", f.getName()) 117 + "</html>"); 118 label.setHorizontalAlignment(SwingConstants.CENTER); 119 JCheckBox remember = new JCheckBox(tr("Always overwrite GPX files without asking")); 120 remember.setHorizontalAlignment(SwingConstants.CENTER); 121 p.add(label, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 10)); 122 p.add(remember, GBC.eop().fill(GBC.HORIZONTAL)); 123 ExtendedDialog dialog = new ExtendedDialog( 124 MainApplication.getMainFrame(), 125 tr("Overwrite"), 126 tr("Overwrite"), tr("Save As..."), tr("Cancel")) 127 .setButtonIcons("save", "save_as", "cancel") 128 .setContent(p); 129 int val = dialog.showDialog().getValue(); 130 if (val == 1) { 131 Config.getPref().putBoolean("gpx.export.overwrite", remember.isSelected()); 132 } else if (val == 2) { 133 f = null; 134 } else { 135 return null; 136 } 137 } 138 return f == null ? layer.createAndOpenSaveFileChooser() : f; 139 } 140}