001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.changeset; 003 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.Collections; 007import java.util.Comparator; 008import java.util.HashSet; 009import java.util.List; 010import java.util.Set; 011 012import javax.swing.DefaultListModel; 013import javax.swing.DefaultListSelectionModel; 014 015import org.openstreetmap.josm.data.osm.Changeset; 016import org.openstreetmap.josm.data.osm.ChangesetCache; 017import org.openstreetmap.josm.data.osm.ChangesetCacheEvent; 018import org.openstreetmap.josm.data.osm.ChangesetCacheListener; 019import org.openstreetmap.josm.data.osm.DataSet; 020import org.openstreetmap.josm.data.osm.OsmPrimitive; 021import org.openstreetmap.josm.data.osm.Storage; 022 023public class ChangesetListModel extends DefaultListModel<Changeset> implements ChangesetCacheListener { 024 private final transient List<Changeset> data = new ArrayList<>(); 025 private final transient Storage<Changeset> shownChangesets = new Storage<>(true); 026 private final DefaultListSelectionModel selectionModel; 027 028 public ChangesetListModel(DefaultListSelectionModel selectionModel) { 029 this.selectionModel = selectionModel; 030 } 031 032 public Set<Changeset> getSelectedChangesets() { 033 Set<Changeset> ret = new HashSet<>(); 034 for (int i = 0; i < getSize(); i++) { 035 if (selectionModel.isSelectedIndex(i)) { 036 ret.add(data.get(i)); 037 } 038 } 039 return ret; 040 } 041 042 public Set<Integer> getSelectedChangesetIds() { 043 Set<Integer> ret = new HashSet<>(); 044 for (int i = 0; i < getSize(); i++) { 045 if (selectionModel.isSelectedIndex(i)) { 046 ret.add(data.get(i).getId()); 047 } 048 } 049 return ret; 050 } 051 052 public void setSelectedChangesets(Collection<Changeset> changesets) { 053 selectionModel.clearSelection(); 054 if (changesets == null) return; 055 for (Changeset cs: changesets) { 056 int idx = data.indexOf(cs); 057 if (idx < 0) { 058 continue; 059 } 060 selectionModel.addSelectionInterval(idx, idx); 061 } 062 } 063 064 protected void setChangesets(Collection<Changeset> changesets) { 065 shownChangesets.clear(); 066 if (changesets != null) { 067 shownChangesets.addAll(changesets); 068 } 069 updateModel(); 070 } 071 072 private void updateModel() { 073 Set<Changeset> sel = getSelectedChangesets(); 074 data.clear(); 075 data.addAll(shownChangesets); 076 ChangesetCache cache = ChangesetCache.getInstance(); 077 for (Changeset cs: data) { 078 if (cache.contains(cs) && cache.get(cs.getId()) != cs) { 079 cs.mergeFrom(cache.get(cs.getId())); 080 } 081 } 082 sort(); 083 fireIntervalAdded(this, 0, getSize()); 084 setSelectedChangesets(sel); 085 } 086 087 public void initFromChangesetIds(Collection<Integer> ids) { 088 if (ids == null || ids.isEmpty()) { 089 setChangesets(null); 090 return; 091 } 092 Set<Changeset> changesets = new HashSet<>(ids.size()); 093 for (int id: ids) { 094 if (id <= 0) { 095 continue; 096 } 097 changesets.add(new Changeset(id)); 098 } 099 setChangesets(changesets); 100 } 101 102 public void initFromPrimitives(Collection<? extends OsmPrimitive> primitives) { 103 if (primitives == null) { 104 setChangesets(null); 105 return; 106 } 107 Set<Changeset> changesets = new HashSet<>(); 108 for (OsmPrimitive p: primitives) { 109 if (p.getChangesetId() <= 0) { 110 continue; 111 } 112 changesets.add(new Changeset(p.getChangesetId())); 113 } 114 setChangesets(changesets); 115 } 116 117 public void initFromDataSet(DataSet ds) { 118 if (ds == null) { 119 setChangesets(null); 120 return; 121 } 122 Set<Changeset> changesets = new HashSet<>(); 123 for (OsmPrimitive p: ds.allPrimitives()) { 124 if (p.getChangesetId() <= 0) { 125 continue; 126 } 127 changesets.add(new Changeset(p.getChangesetId())); 128 } 129 setChangesets(changesets); 130 } 131 132 @Override 133 public Changeset getElementAt(int idx) { 134 return data.get(idx); 135 } 136 137 @Override 138 public int getSize() { 139 return data.size(); 140 } 141 142 protected void sort() { 143 Collections.sort( 144 data, 145 new Comparator<Changeset>() { 146 @Override 147 public int compare(Changeset cs1, Changeset cs2) { 148 if (cs1.getId() > cs2.getId()) return -1; 149 if (cs1.getId() == cs2.getId()) return 0; 150 return 1; 151 } 152 } 153 ); 154 } 155 156 /** 157 * Replies true if there is at least one selected open changeset 158 * 159 * @return true if there is at least one selected open changeset 160 */ 161 public boolean hasSelectedOpenChangesets() { 162 return !getSelectedOpenChangesets().isEmpty(); 163 } 164 165 /** 166 * Replies the selected open changesets 167 * 168 * @return the selected open changesets 169 */ 170 public List<Changeset> getSelectedOpenChangesets() { 171 List<Changeset> ret = new ArrayList<>(); 172 for (int i = 0; i < getSize(); i++) { 173 if (selectionModel.isSelectedIndex(i)) { 174 Changeset cs = data.get(i); 175 if (cs.isOpen()) { 176 ret.add(cs); 177 } 178 } 179 } 180 return ret; 181 } 182 183 /* ---------------------------------------------------------------------------- */ 184 /* Interface ChangesetCacheListener */ 185 /* ---------------------------------------------------------------------------- */ 186 @Override 187 public void changesetCacheUpdated(ChangesetCacheEvent event) { 188 Set<Changeset> sel = getSelectedChangesets(); 189 for (Changeset cs: event.getAddedChangesets()) { 190 int idx = data.indexOf(cs); 191 if (idx >= 0 && data.get(idx) != cs) { 192 data.get(idx).mergeFrom(cs); 193 } 194 } 195 for (Changeset cs: event.getUpdatedChangesets()) { 196 int idx = data.indexOf(cs); 197 if (idx >= 0 && data.get(idx) != cs) { 198 data.get(idx).mergeFrom(cs); 199 } 200 } 201 for (Changeset cs: event.getRemovedChangesets()) { 202 int idx = data.indexOf(cs); 203 if (idx >= 0) { 204 // replace with an incomplete changeset 205 data.set(idx, new Changeset(cs.getId())); 206 } 207 } 208 fireContentsChanged(this, 0, getSize()); 209 setSelectedChangesets(sel); 210 } 211}