001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.dialogs.changeset;
003    
004    import java.util.ArrayList;
005    import java.util.Collection;
006    import java.util.Collections;
007    import java.util.Comparator;
008    import java.util.HashSet;
009    import java.util.List;
010    import java.util.Set;
011    
012    import javax.swing.DefaultListModel;
013    import javax.swing.DefaultListSelectionModel;
014    
015    import org.openstreetmap.josm.data.osm.Changeset;
016    import org.openstreetmap.josm.data.osm.ChangesetCache;
017    import org.openstreetmap.josm.data.osm.ChangesetCacheEvent;
018    import org.openstreetmap.josm.data.osm.ChangesetCacheListener;
019    import org.openstreetmap.josm.data.osm.DataSet;
020    import org.openstreetmap.josm.data.osm.OsmPrimitive;
021    import org.openstreetmap.josm.data.osm.Storage;
022    
023    public class ChangesetListModel extends DefaultListModel  implements ChangesetCacheListener{
024        private final List<Changeset> data = new ArrayList<Changeset>();
025        private final Storage<Changeset> shownChangesets = new Storage<Changeset>(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<Changeset>();
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<Integer>();
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<Changeset>(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<Changeset>();
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<Changeset>();
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 Object 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                        public int compare(Changeset cs1, Changeset cs2) {
147                            if (cs1.getId() > cs2.getId()) return -1;
148                            if (cs1.getId() == cs2.getId()) return 0;
149                            return 1;
150                        }
151                    }
152            );
153        }
154    
155        /**
156         * Replies true if  there is at least one selected open changeset
157         *
158         * @return true if  there is at least one selected open changeset
159         */
160        public boolean hasSelectedOpenChangesets() {
161            return !getSelectedOpenChangesets().isEmpty();
162        }
163    
164        /**
165         * Replies the selected open changesets
166         *
167         * @return the selected open changesets
168         */
169        public List<Changeset> getSelectedOpenChangesets() {
170            List<Changeset> ret = new ArrayList<Changeset>();
171            for (int i=0; i< getSize(); i++) {
172                if (selectionModel.isSelectedIndex(i)) {
173                    Changeset cs = data.get(i);
174                    if (cs.isOpen()) {
175                        ret.add(cs);
176                    }
177                }
178            }
179            return ret;
180        }
181    
182        /* ---------------------------------------------------------------------------- */
183        /* Interface ChangesetCacheListener                                             */
184        /* ---------------------------------------------------------------------------- */
185        public void changesetCacheUpdated(ChangesetCacheEvent event) {
186            Set<Changeset> sel = getSelectedChangesets();
187            for(Changeset cs: event.getAddedChangesets()) {
188                int idx = data.indexOf(cs);
189                if (idx >= 0 && data.get(idx) != cs) {
190                    data.get(idx).mergeFrom(cs);
191                }
192            }
193            for(Changeset cs: event.getUpdatedChangesets()) {
194                int idx = data.indexOf(cs);
195                if (idx >= 0 && data.get(idx) != cs) {
196                    data.get(idx).mergeFrom(cs);
197                }
198            }
199            for(Changeset cs: event.getRemovedChangesets()) {
200                int idx = data.indexOf(cs);
201                if (idx >= 0) {
202                    // replace with an incomplete changeset
203                    data.set(idx, new Changeset(cs.getId()));
204                }
205            }
206            fireContentsChanged(this, 0, getSize());
207            setSelectedChangesets(sel);
208        }
209    }