001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.dialogs.changeset;
003    
004    import java.beans.PropertyChangeListener;
005    import java.beans.PropertyChangeSupport;
006    import java.util.ArrayList;
007    import java.util.Collection;
008    import java.util.Collections;
009    import java.util.Comparator;
010    import java.util.HashSet;
011    import java.util.List;
012    import java.util.Set;
013    
014    import javax.swing.DefaultListSelectionModel;
015    import javax.swing.table.AbstractTableModel;
016    
017    import org.openstreetmap.josm.data.osm.Changeset;
018    import org.openstreetmap.josm.data.osm.ChangesetCache;
019    import org.openstreetmap.josm.data.osm.ChangesetCacheEvent;
020    import org.openstreetmap.josm.data.osm.ChangesetCacheListener;
021    
022    /**
023     * This is the model for the changeset cache manager dialog.
024     *
025     */
026    public class ChangesetCacheManagerModel extends AbstractTableModel implements ChangesetCacheListener{
027    
028        /** the name of the property for the currently selected changeset in the detail view */
029        public final static String CHANGESET_IN_DETAIL_VIEW_PROP = ChangesetCacheManagerModel.class.getName() + ".changesetInDetailView";
030    
031        private final ArrayList<Changeset> data = new ArrayList<Changeset>();
032        private DefaultListSelectionModel selectionModel;
033        private Changeset changesetInDetailView;
034        private final PropertyChangeSupport support = new PropertyChangeSupport(this);
035    
036        public ChangesetCacheManagerModel(DefaultListSelectionModel selectionModel) {
037            this.selectionModel = selectionModel;
038        }
039    
040        public void addPropertyChangeListener(PropertyChangeListener listener) {
041            support.addPropertyChangeListener(listener);
042        }
043    
044        public void removePropertyChangeListener(PropertyChangeListener listener) {
045            support.removePropertyChangeListener(listener);
046        }
047    
048        /**
049         * Sets the changeset currently displayed in the detail view. Fires a property change event
050         * for the property {@link #CHANGESET_IN_DETAIL_VIEW_PROP} if necessary.
051         *
052         * @param cs the changeset currently displayed in the detail view.
053         */
054        public void setChangesetInDetailView(Changeset cs) {
055            Changeset oldValue = changesetInDetailView;
056            changesetInDetailView = cs;
057            if (oldValue != cs) {
058                support.firePropertyChange(CHANGESET_IN_DETAIL_VIEW_PROP, oldValue, changesetInDetailView);
059            }
060        }
061    
062        /**
063         * Replies true if there is at least one selected changeset
064         *
065         * @return true if there is at least one selected changeset
066         */
067        public boolean hasSelectedChangesets() {
068            return selectionModel.getMinSelectionIndex() >= 0;
069        }
070    
071        /**
072         * Replies the list of selected changesets
073         *
074         * @return the list of selected changesets
075         */
076        public List<Changeset> getSelectedChangesets() {
077            ArrayList<Changeset> ret = new ArrayList<Changeset>();
078            for (int i =0; i< data.size();i++) {
079                Changeset cs = data.get(i);
080                if (selectionModel.isSelectedIndex(i)) {
081                    ret.add(cs);
082                }
083            }
084            return ret;
085        }
086    
087        /**
088         * Replies a set of ids of the selected changesets
089         *
090         * @return a set of ids of the selected changesets
091         */
092        public Set<Integer> getSelectedChangesetIds() {
093            Set<Integer> ret = new HashSet<Integer>();
094            for (Changeset cs: getSelectedChangesets()) {
095                ret.add(cs.getId());
096            }
097            return ret;
098        }
099    
100        /**
101         * Selects the changesets in <code>selected</code>.
102         *
103         * @param selected the collection of changesets to select. Ignored if empty.
104         */
105        public void setSelectedChangesets(Collection<Changeset> selected) {
106            selectionModel.clearSelection();
107            if (selected == null || selected.isEmpty())
108                return;
109            for (Changeset cs: selected) {
110                int idx = data.indexOf(cs);
111                if (idx >= 0) {
112                    selectionModel.addSelectionInterval(idx,idx);
113                }
114            }
115        }
116    
117        /**
118         * Selects the changeset displayed at row <code>row</code>
119         *
120         * @param row the row. Ignored if < 0 or >= {@link #getRowCount()}
121         */
122        public void setSelectedByIdx(int row) {
123            if (row < 0 || row >= getRowCount()) return;
124            selectionModel.setSelectionInterval(row, row);
125        }
126    
127        public int getColumnCount() {
128            return 5;
129        }
130    
131        public int getRowCount() {
132            return data.size();
133        }
134    
135        public Object getValueAt(int row, int column) {
136            return data.get(row);
137        }
138    
139        public void init() {
140            ChangesetCache cc = ChangesetCache.getInstance();
141            List<Changeset> selected = getSelectedChangesets();
142            data.clear();
143            data.addAll(cc.getChangesets());
144            sort();
145            fireTableDataChanged();
146            setSelectedChangesets(selected);
147    
148            cc.addChangesetCacheListener(this);
149        }
150    
151        public void tearDown() {
152            ChangesetCache.getInstance().removeChangesetCacheListener(this);
153        }
154    
155        public DefaultListSelectionModel getSelectionModel() {
156            return selectionModel;
157        }
158    
159        protected void sort() {
160            Collections.sort(
161                    this.data,
162                    new Comparator<Changeset>() {
163                        public int compare(Changeset o1, Changeset o2) {
164                            if (o1.getId() < o2.getId()) return 1;
165                            if (o1.getId() == o2.getId()) return 0;
166                            return -1;
167                        }
168                    }
169            );
170        }
171    
172        /* ------------------------------------------------------------------------------ */
173        /* interface ChangesetCacheListener                                               */
174        /* ------------------------------------------------------------------------------ */
175        public void changesetCacheUpdated(ChangesetCacheEvent event) {
176            List<Changeset> selected = getSelectedChangesets();
177            for (Changeset cs: event.getAddedChangesets()) {
178                data.add(cs);
179            }
180            for (Changeset cs: event.getRemovedChangesets()) {
181                data.remove(cs);
182            }
183            for (Changeset cs: event.getUpdatedChangesets()) {
184                int idx = data.indexOf(cs);
185                if (idx >= 0) {
186                    Changeset mine = data.get(idx);
187                    if (mine != cs) {
188                        mine.mergeFrom(cs);
189                    }
190                }
191            }
192            sort();
193            fireTableDataChanged();
194            setSelectedChangesets(selected);
195        }
196    }