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