001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.io;
003
004import java.beans.PropertyChangeListener;
005import java.beans.PropertyChangeSupport;
006import java.io.File;
007import java.util.ArrayList;
008import java.util.Comparator;
009import java.util.List;
010
011import javax.swing.table.DefaultTableModel;
012
013import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
014import org.openstreetmap.josm.gui.layer.OsmDataLayer;
015
016public class SaveLayersModel extends DefaultTableModel {
017    public static final String MODE_PROP = SaveLayerInfo.class.getName() + ".mode";
018
019    public enum Mode {
020        EDITING_DATA,
021        UPLOADING_AND_SAVING
022    }
023
024    private transient List<SaveLayerInfo> layerInfo;
025    private Mode mode;
026    private final PropertyChangeSupport support;
027
028    // keep in sync with how the columns are ordered in SaveLayersTableColumnModel#build
029    private static final int columnFilename = 0;
030    private static final int columnActions = 2;
031
032    /**
033     * Constructs a new {@code SaveLayersModel}.
034     */
035    public SaveLayersModel() {
036        mode = Mode.EDITING_DATA;
037        support = new PropertyChangeSupport(this);
038    }
039
040    public void addPropertyChangeListener(PropertyChangeListener l) {
041        support.addPropertyChangeListener(l);
042    }
043
044    public void removePropertyChangeListener(PropertyChangeListener l) {
045        support.removePropertyChangeListener(l);
046    }
047
048    protected void fireModeChanged(Mode oldValue, Mode newValue) {
049        support.firePropertyChange(MODE_PROP, oldValue, newValue);
050    }
051
052    public void setMode(Mode newValue) {
053        Mode oldValue = this.mode;
054        this.mode = newValue;
055        fireModeChanged(oldValue, newValue);
056    }
057
058    public Mode getMode() {
059        return mode;
060    }
061
062    /**
063     * Populates the model with given modifiable layers.
064     * @param layers The layers to use to populate this model
065     * @since 7358
066     */
067    public void populate(List<? extends AbstractModifiableLayer> layers) {
068        layerInfo = new ArrayList<>();
069        if (layers == null) return;
070        for (AbstractModifiableLayer layer: layers) {
071            layerInfo.add(new SaveLayerInfo(layer));
072        }
073        layerInfo.sort(Comparator.naturalOrder());
074        fireTableDataChanged();
075    }
076
077    @Override
078    public int getRowCount() {
079        if (layerInfo == null) return 0;
080        return layerInfo.size();
081    }
082
083    @Override
084    public Object getValueAt(int row, int column) {
085        if (layerInfo == null) return null;
086        return layerInfo.get(row);
087    }
088
089    @Override
090    public boolean isCellEditable(int row, int column) {
091        return column == columnFilename || column == columnActions;
092    }
093
094    @Override
095    public void setValueAt(Object value, int row, int column) {
096        final SaveLayerInfo info = this.layerInfo.get(row);
097        switch(column) {
098        case columnFilename:
099            info.setFile((File) value);
100            if (info.isSavable()) {
101                info.setDoSaveToFile(true);
102            }
103            break;
104        case columnActions:
105            boolean[] values = (boolean[]) value;
106            info.setDoUploadToServer(values[0]);
107            info.setDoSaveToFile(values[1]);
108            break;
109        default: // Do nothing
110        }
111        fireTableDataChanged();
112    }
113
114    public List<SaveLayerInfo> getSafeLayerInfo() {
115        return this.layerInfo;
116    }
117
118    public List<SaveLayerInfo> getLayersWithoutFilesAndSaveRequest() {
119        List<SaveLayerInfo> ret = new ArrayList<>();
120        if (layerInfo != null) {
121            for (SaveLayerInfo info: layerInfo) {
122                if (info.isDoSaveToFile() && info.getFile() == null) {
123                    ret.add(info);
124                }
125            }
126        }
127        return ret;
128    }
129
130    public List<SaveLayerInfo> getLayersWithIllegalFilesAndSaveRequest() {
131        List<SaveLayerInfo> ret = new ArrayList<>();
132        if (layerInfo != null) {
133            for (SaveLayerInfo info: layerInfo) {
134                if (info.isDoSaveToFile() && info.getFile() != null && info.getFile().exists() && !info.getFile().canWrite()) {
135                    ret.add(info);
136                }
137            }
138        }
139        return ret;
140    }
141
142    public List<SaveLayerInfo> getLayersWithConflictsAndUploadRequest() {
143        List<SaveLayerInfo> ret = new ArrayList<>();
144        if (layerInfo != null) {
145            for (SaveLayerInfo info: layerInfo) {
146                AbstractModifiableLayer l = info.getLayer();
147                if (info.isDoUploadToServer() && l instanceof OsmDataLayer && !((OsmDataLayer) l).getConflicts().isEmpty()) {
148                    ret.add(info);
149                }
150            }
151        }
152        return ret;
153    }
154
155    public List<SaveLayerInfo> getLayersToUpload() {
156        List<SaveLayerInfo> ret = new ArrayList<>();
157        if (layerInfo != null) {
158            for (SaveLayerInfo info: layerInfo) {
159                if (info.isDoUploadToServer()) {
160                    ret.add(info);
161                }
162            }
163        }
164        return ret;
165    }
166
167    public List<SaveLayerInfo> getLayersToSave() {
168        List<SaveLayerInfo> ret = new ArrayList<>();
169        if (layerInfo != null) {
170            for (SaveLayerInfo info: layerInfo) {
171                if (info.isDoSaveToFile()) {
172                    ret.add(info);
173                }
174            }
175        }
176        return ret;
177    }
178
179    public void setUploadState(AbstractModifiableLayer layer, UploadOrSaveState state) {
180        SaveLayerInfo info = getSaveLayerInfo(layer);
181        if (info != null) {
182            info.setUploadState(state);
183        }
184        fireTableDataChanged();
185    }
186
187    public void setSaveState(AbstractModifiableLayer layer, UploadOrSaveState state) {
188        SaveLayerInfo info = getSaveLayerInfo(layer);
189        if (info != null) {
190            info.setSaveState(state);
191        }
192        fireTableDataChanged();
193    }
194
195    public SaveLayerInfo getSaveLayerInfo(AbstractModifiableLayer layer) {
196        for (SaveLayerInfo info: this.layerInfo) {
197            if (info.getLayer() == layer)
198                return info;
199        }
200        return null;
201    }
202
203    public void resetSaveAndUploadState() {
204        for (SaveLayerInfo info: layerInfo) {
205            info.setSaveState(null);
206            info.setUploadState(null);
207        }
208    }
209
210    public boolean hasUnsavedData() {
211        for (SaveLayerInfo info: layerInfo) {
212            if (info.isDoUploadToServer() && !UploadOrSaveState.OK.equals(info.getUploadState()))
213                return true;
214            if (info.isDoSaveToFile() && !UploadOrSaveState.OK.equals(info.getSaveState()))
215                return true;
216        }
217        return false;
218    }
219
220    public int getNumCancel() {
221        int ret = 0;
222        for (SaveLayerInfo info: layerInfo) {
223            if (UploadOrSaveState.CANCELED.equals(info.getSaveState())
224                    || UploadOrSaveState.CANCELED.equals(info.getUploadState())) {
225                ret++;
226            }
227        }
228        return ret;
229    }
230
231    public int getNumFailed() {
232        int ret = 0;
233        for (SaveLayerInfo info: layerInfo) {
234            if (UploadOrSaveState.FAILED.equals(info.getSaveState())
235                    || UploadOrSaveState.FAILED.equals(info.getUploadState())) {
236                ret++;
237            }
238        }
239        return ret;
240    }
241}