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