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