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