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    public enum Mode {
020        EDITING_DATA,
021        UPLOADING_AND_SAVING
022    }
023
024    private List<SaveLayerInfo> layerInfo;
025    private Mode mode;
026    private 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        Collections.sort(
074                layerInfo,
075                new Comparator<SaveLayerInfo>() {
076                    @Override
077                    public int compare(SaveLayerInfo o1, SaveLayerInfo o2) {
078                        return o1.compareTo(o2);
079                    }
080                }
081        );
082        fireTableDataChanged();
083    }
084
085    @Override
086    public int getRowCount() {
087        if (layerInfo == null) return 0;
088        return layerInfo.size();
089    }
090
091    @Override
092    public Object getValueAt(int row, int column) {
093        if (layerInfo == null) return null;
094        return layerInfo.get(row);
095    }
096
097    @Override
098    public boolean isCellEditable(int row, int column) {
099        return column == columnFilename || column == columnActions;
100    }
101
102    @Override
103    public void setValueAt(Object value, int row, int column) {
104        switch(column) {
105        case columnFilename:
106            this.layerInfo.get(row).setFile((File)value);
107            this.layerInfo.get(row).setDoSaveToFile(true);
108            break;
109        case columnActions:
110            boolean[] values = (boolean[]) value;
111            this.layerInfo.get(row).setDoUploadToServer(values[0]);
112            this.layerInfo.get(row).setDoSaveToFile(values[1]);
113            break;
114        }
115        fireTableDataChanged();
116    }
117
118    public List<SaveLayerInfo> getSafeLayerInfo() {
119        return this.layerInfo;
120    }
121
122    public List<SaveLayerInfo> getLayersWithoutFilesAndSaveRequest() {
123        List<SaveLayerInfo> ret = new ArrayList<>();
124        for (SaveLayerInfo info: layerInfo) {
125            if (info.isDoSaveToFile() && info.getFile() == null) {
126                ret.add(info);
127            }
128        }
129        return ret;
130    }
131
132    public List<SaveLayerInfo> getLayersWithIllegalFilesAndSaveRequest() {
133        List<SaveLayerInfo> ret =new ArrayList<>();
134        for (SaveLayerInfo info: layerInfo) {
135            if (info.isDoSaveToFile() && info.getFile() != null && info.getFile().exists() && !info.getFile().canWrite()) {
136                ret.add(info);
137            }
138        }
139        return ret;
140    }
141
142    public List<SaveLayerInfo> getLayersWithConflictsAndUploadRequest() {
143        List<SaveLayerInfo> ret = new ArrayList<>();
144        for (SaveLayerInfo info: layerInfo) {
145            AbstractModifiableLayer l = info.getLayer();
146            if (info.isDoUploadToServer() && l instanceof OsmDataLayer && !((OsmDataLayer)l).getConflicts().isEmpty()) {
147                ret.add(info);
148            }
149        }
150        return ret;
151    }
152
153    public List<SaveLayerInfo> getLayersToUpload() {
154        List<SaveLayerInfo> ret = new ArrayList<>();
155        for (SaveLayerInfo info: layerInfo) {
156            if (info.isDoUploadToServer()) {
157                ret.add(info);
158            }
159        }
160        return ret;
161    }
162
163    public List<SaveLayerInfo> getLayersToSave() {
164        List<SaveLayerInfo> ret = new ArrayList<>();
165        for (SaveLayerInfo info: layerInfo) {
166            if (info.isDoSaveToFile()) {
167                ret.add(info);
168            }
169        }
170        return ret;
171    }
172
173    public void setUploadState(AbstractModifiableLayer layer, UploadOrSaveState state) {
174        SaveLayerInfo info = getSaveLayerInfo(layer);
175        if (info != null) {
176            info.setUploadState(state);
177        }
178        fireTableDataChanged();
179    }
180
181    public void setSaveState(AbstractModifiableLayer layer, UploadOrSaveState state) {
182        SaveLayerInfo info = getSaveLayerInfo(layer);
183        if (info != null) {
184            info.setSaveState(state);
185        }
186        fireTableDataChanged();
187    }
188
189    public SaveLayerInfo getSaveLayerInfo(AbstractModifiableLayer layer) {
190        for (SaveLayerInfo info: this.layerInfo) {
191            if (info.getLayer() == layer)
192                return info;
193        }
194        return null;
195    }
196
197    public void resetSaveAndUploadState() {
198        for (SaveLayerInfo info: layerInfo) {
199            info.setSaveState(null);
200            info.setUploadState(null);
201        }
202    }
203
204    public boolean hasUnsavedData() {
205        for (SaveLayerInfo info: layerInfo) {
206            if (info.isDoUploadToServer() && ! UploadOrSaveState.OK.equals(info.getUploadState()))
207                return true;
208            if (info.isDoSaveToFile() && ! UploadOrSaveState.OK.equals(info.getSaveState()))
209                return true;
210        }
211        return false;
212    }
213
214    public int getNumCancel() {
215        int ret = 0;
216        for (SaveLayerInfo info: layerInfo) {
217            if (UploadOrSaveState.CANCELED.equals(info.getSaveState())
218                    || UploadOrSaveState.CANCELED.equals(info.getUploadState())) {
219                ret++;
220            }
221        }
222        return ret;
223    }
224
225    public int getNumFailed() {
226        int ret = 0;
227        for (SaveLayerInfo info: layerInfo) {
228            if (UploadOrSaveState.FAILED.equals(info.getSaveState())
229                    || UploadOrSaveState.FAILED.equals(info.getUploadState())) {
230                ret++;
231            }
232        }
233        return ret;
234    }
235}