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 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}