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.clearSelection();
053        if (changesets == null) return;
054        for (Changeset cs: changesets) {
055            int idx = data.indexOf(cs);
056            if (idx < 0) {
057                continue;
058            }
059            selectionModel.addSelectionInterval(idx, idx);
060        }
061    }
062
063    protected void setChangesets(Collection<Changeset> changesets) {
064        shownChangesets.clear();
065        if (changesets != null) {
066            shownChangesets.addAll(changesets);
067        }
068        updateModel();
069    }
070
071    private void updateModel() {
072        Set<Changeset> sel = getSelectedChangesets();
073        data.clear();
074        data.addAll(shownChangesets);
075        ChangesetCache cache = ChangesetCache.getInstance();
076        for (Changeset cs: data) {
077            if (cache.contains(cs) && cache.get(cs.getId()) != cs) {
078                cs.mergeFrom(cache.get(cs.getId()));
079            }
080        }
081        sort();
082        fireIntervalAdded(this, 0, getSize());
083        setSelectedChangesets(sel);
084    }
085
086    public void initFromChangesetIds(Collection<Integer> ids) {
087        if (ids == null || ids.isEmpty()) {
088            setChangesets(null);
089            return;
090        }
091        Set<Changeset> changesets = new HashSet<>(ids.size());
092        for (int id: ids) {
093            if (id <= 0) {
094                continue;
095            }
096            changesets.add(new Changeset(id));
097        }
098        setChangesets(changesets);
099    }
100
101    public void initFromPrimitives(Collection<? extends OsmPrimitive> primitives) {
102        if (primitives == null) {
103            setChangesets(null);
104            return;
105        }
106        Set<Changeset> changesets = new HashSet<>();
107        for (OsmPrimitive p: primitives) {
108            if (p.getChangesetId() <= 0) {
109                continue;
110            }
111            changesets.add(new Changeset(p.getChangesetId()));
112        }
113        setChangesets(changesets);
114    }
115
116    public void initFromDataSet(DataSet ds) {
117        if (ds == null) {
118            setChangesets(null);
119            return;
120        }
121        Set<Changeset> changesets = new HashSet<>();
122        for (OsmPrimitive p: ds.allPrimitives()) {
123            if (p.getChangesetId() <= 0) {
124                continue;
125            }
126            changesets.add(new Changeset(p.getChangesetId()));
127        }
128        setChangesets(changesets);
129    }
130
131    @Override
132    public Changeset getElementAt(int idx) {
133        return data.get(idx);
134    }
135
136    @Override
137    public int getSize() {
138        return data.size();
139    }
140
141    protected void sort() {
142        data.sort(Comparator.comparingInt(Changeset::getId).reversed());
143    }
144
145    /**
146     * Replies true if  there is at least one selected open changeset
147     *
148     * @return true if  there is at least one selected open changeset
149     */
150    public boolean hasSelectedOpenChangesets() {
151        return !getSelectedOpenChangesets().isEmpty();
152    }
153
154    /**
155     * Replies the selected open changesets
156     *
157     * @return the selected open changesets
158     */
159    public List<Changeset> getSelectedOpenChangesets() {
160        List<Changeset> ret = new ArrayList<>();
161        for (int i = 0; i < getSize(); i++) {
162            if (selectionModel.isSelectedIndex(i)) {
163                Changeset cs = data.get(i);
164                if (cs.isOpen()) {
165                    ret.add(cs);
166                }
167            }
168        }
169        return ret;
170    }
171
172    /* ---------------------------------------------------------------------------- */
173    /* Interface ChangesetCacheListener                                             */
174    /* ---------------------------------------------------------------------------- */
175    @Override
176    public void changesetCacheUpdated(ChangesetCacheEvent event) {
177        Set<Changeset> sel = getSelectedChangesets();
178        for (Changeset cs: event.getAddedChangesets()) {
179            int idx = data.indexOf(cs);
180            if (idx >= 0 && data.get(idx) != cs) {
181                data.get(idx).mergeFrom(cs);
182            }
183        }
184        for (Changeset cs: event.getUpdatedChangesets()) {
185            int idx = data.indexOf(cs);
186            if (idx >= 0 && data.get(idx) != cs) {
187                data.get(idx).mergeFrom(cs);
188            }
189        }
190        for (Changeset cs: event.getRemovedChangesets()) {
191            int idx = data.indexOf(cs);
192            if (idx >= 0) {
193                // replace with an incomplete changeset
194                data.set(idx, new Changeset(cs.getId()));
195            }
196        }
197        fireContentsChanged(this, 0, getSize());
198        setSelectedChangesets(sel);
199    }
200}