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}