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