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.Comparator; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Set; 012 013import javax.swing.DefaultListSelectionModel; 014import javax.swing.table.AbstractTableModel; 015 016import org.openstreetmap.josm.data.osm.Changeset; 017import org.openstreetmap.josm.data.osm.ChangesetCache; 018import org.openstreetmap.josm.data.osm.ChangesetCacheEvent; 019import org.openstreetmap.josm.data.osm.ChangesetCacheListener; 020import org.openstreetmap.josm.gui.util.GuiHelper; 021 022/** 023 * This is the model for the changeset cache manager dialog. 024 * 025 */ 026public class ChangesetCacheManagerModel extends AbstractTableModel implements ChangesetCacheListener { 027 028 /** the name of the property for the currently selected changeset in the detail view */ 029 public static final String CHANGESET_IN_DETAIL_VIEW_PROP = ChangesetCacheManagerModel.class.getName() + ".changesetInDetailView"; 030 031 private final transient List<Changeset> data = new ArrayList<>(); 032 private final DefaultListSelectionModel selectionModel; 033 private transient 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 List<Changeset> ret = new ArrayList<>(); 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<>(); 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.setValueIsAdjusting(true); 107 selectionModel.clearSelection(); 108 if (selected != null) { 109 for (Changeset cs: selected) { 110 final int idx = data.indexOf(cs); 111 if (idx >= 0) { 112 selectionModel.addSelectionInterval(idx, idx); 113 } 114 } 115 } 116 GuiHelper.runInEDTAndWait(() -> selectionModel.setValueIsAdjusting(false)); 117 } 118 119 @Override 120 public int getColumnCount() { 121 return 5; 122 } 123 124 @Override 125 public int getRowCount() { 126 return data.size(); 127 } 128 129 @Override 130 public Object getValueAt(int row, int column) { 131 return data.get(row); 132 } 133 134 public void init() { 135 ChangesetCache cc = ChangesetCache.getInstance(); 136 List<Changeset> selected = getSelectedChangesets(); 137 data.clear(); 138 data.addAll(cc.getChangesets()); 139 sort(); 140 fireTableDataChanged(); 141 setSelectedChangesets(selected); 142 143 cc.addChangesetCacheListener(this); 144 } 145 146 public void tearDown() { 147 ChangesetCache.getInstance().removeChangesetCacheListener(this); 148 } 149 150 public DefaultListSelectionModel getSelectionModel() { 151 return selectionModel; 152 } 153 154 protected void sort() { 155 data.sort(Comparator.comparingInt(Changeset::getId).reversed()); 156 } 157 158 /* ------------------------------------------------------------------------------ */ 159 /* interface ChangesetCacheListener */ 160 /* ------------------------------------------------------------------------------ */ 161 @Override 162 public void changesetCacheUpdated(ChangesetCacheEvent event) { 163 List<Changeset> selected = getSelectedChangesets(); 164 for (Changeset cs: event.getAddedChangesets()) { 165 data.add(cs); 166 } 167 for (Changeset cs: event.getRemovedChangesets()) { 168 data.remove(cs); 169 } 170 for (Changeset cs: event.getUpdatedChangesets()) { 171 int idx = data.indexOf(cs); 172 if (idx >= 0) { 173 Changeset mine = data.get(idx); 174 if (mine != cs) { 175 mine.mergeFrom(cs); 176 } 177 } 178 } 179 sort(); 180 fireTableDataChanged(); 181 setSelectedChangesets(selected); 182 } 183}