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