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        final SaveLayerInfo info = this.layerInfo.get(row);
106        switch(column) {
107        case columnFilename:
108            info.setFile((File) value);
109            if (info.isSavable()) {
110                info.setDoSaveToFile(true);
111            }
112            break;
113        case columnActions:
114            boolean[] values = (boolean[]) value;
115            info.setDoUploadToServer(values[0]);
116            info.setDoSaveToFile(values[1]);
117            break;
118        default: // Do nothing
119        }
120        fireTableDataChanged();
121    }
122
123    public List<SaveLayerInfo> getSafeLayerInfo() {
124        return this.layerInfo;
125    }
126
127    public List<SaveLayerInfo> getLayersWithoutFilesAndSaveRequest() {
128        List<SaveLayerInfo> ret = new ArrayList<>();
129        if (layerInfo != null) {
130            for (SaveLayerInfo info: layerInfo) {
131                if (info.isDoSaveToFile() && info.getFile() == null) {
132                    ret.add(info);
133                }
134            }
135        }
136        return ret;
137    }
138
139    public List<SaveLayerInfo> getLayersWithIllegalFilesAndSaveRequest() {
140        List<SaveLayerInfo> ret = new ArrayList<>();
141        if (layerInfo != null) {
142            for (SaveLayerInfo info: layerInfo) {
143                if (info.isDoSaveToFile() && info.getFile() != null && info.getFile().exists() && !info.getFile().canWrite()) {
144                    ret.add(info);
145                }
146            }
147        }
148        return ret;
149    }
150
151    public List<SaveLayerInfo> getLayersWithConflictsAndUploadRequest() {
152        List<SaveLayerInfo> ret = new ArrayList<>();
153        if (layerInfo != null) {
154            for (SaveLayerInfo info: layerInfo) {
155                AbstractModifiableLayer l = info.getLayer();
156                if (info.isDoUploadToServer() && l instanceof OsmDataLayer && !((OsmDataLayer) l).getConflicts().isEmpty()) {
157                    ret.add(info);
158                }
159            }
160        }
161        return ret;
162    }
163
164    public List<SaveLayerInfo> getLayersToUpload() {
165        List<SaveLayerInfo> ret = new ArrayList<>();
166        if (layerInfo != null) {
167            for (SaveLayerInfo info: layerInfo) {
168                if (info.isDoUploadToServer()) {
169                    ret.add(info);
170                }
171            }
172        }
173        return ret;
174    }
175
176    public List<SaveLayerInfo> getLayersToSave() {
177        List<SaveLayerInfo> ret = new ArrayList<>();
178        if (layerInfo != null) {
179            for (SaveLayerInfo info: layerInfo) {
180                if (info.isDoSaveToFile()) {
181                    ret.add(info);
182                }
183            }
184        }
185        return ret;
186    }
187
188    public void setUploadState(AbstractModifiableLayer layer, UploadOrSaveState state) {
189        SaveLayerInfo info = getSaveLayerInfo(layer);
190        if (info != null) {
191            info.setUploadState(state);
192        }
193        fireTableDataChanged();
194    }
195
196    public void setSaveState(AbstractModifiableLayer layer, UploadOrSaveState state) {
197        SaveLayerInfo info = getSaveLayerInfo(layer);
198        if (info != null) {
199            info.setSaveState(state);
200        }
201        fireTableDataChanged();
202    }
203
204    public SaveLayerInfo getSaveLayerInfo(AbstractModifiableLayer layer) {
205        for (SaveLayerInfo info: this.layerInfo) {
206            if (info.getLayer() == layer)
207                return info;
208        }
209        return null;
210    }
211
212    public void resetSaveAndUploadState() {
213        for (SaveLayerInfo info: layerInfo) {
214            info.setSaveState(null);
215            info.setUploadState(null);
216        }
217    }
218
219    public boolean hasUnsavedData() {
220        for (SaveLayerInfo info: layerInfo) {
221            if (info.isDoUploadToServer() && !UploadOrSaveState.OK.equals(info.getUploadState()))
222                return true;
223            if (info.isDoSaveToFile() && !UploadOrSaveState.OK.equals(info.getSaveState()))
224                return true;
225        }
226        return false;
227    }
228
229    public int getNumCancel() {
230        int ret = 0;
231        for (SaveLayerInfo info: layerInfo) {
232            if (UploadOrSaveState.CANCELED.equals(info.getSaveState())
233                    || UploadOrSaveState.CANCELED.equals(info.getUploadState())) {
234                ret++;
235            }
236        }
237        return ret;
238    }
239
240    public int getNumFailed() {
241        int ret = 0;
242        for (SaveLayerInfo info: layerInfo) {
243            if (UploadOrSaveState.FAILED.equals(info.getSaveState())
244                    || UploadOrSaveState.FAILED.equals(info.getUploadState())) {
245                ret++;
246            }
247        }
248        return ret;
249    }
250}