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 GuiHelper.runInEDTAndWait(selectionModel::clearSelection); 107 if (selected == null || selected.isEmpty()) 108 return; 109 for (Changeset cs: selected) { 110 final int idx = data.indexOf(cs); 111 if (idx >= 0) { 112 GuiHelper.runInEDTAndWait(() -> selectionModel.addSelectionInterval(idx, idx)); 113 } 114 } 115 } 116 117 @Override 118 public int getColumnCount() { 119 return 5; 120 } 121 122 @Override 123 public int getRowCount() { 124 return data.size(); 125 } 126 127 @Override 128 public Object getValueAt(int row, int column) { 129 return data.get(row); 130 } 131 132 public void init() { 133 ChangesetCache cc = ChangesetCache.getInstance(); 134 List<Changeset> selected = getSelectedChangesets(); 135 data.clear(); 136 data.addAll(cc.getChangesets()); 137 sort(); 138 fireTableDataChanged(); 139 setSelectedChangesets(selected); 140 141 cc.addChangesetCacheListener(this); 142 } 143 144 public void tearDown() { 145 ChangesetCache.getInstance().removeChangesetCacheListener(this); 146 } 147 148 public DefaultListSelectionModel getSelectionModel() { 149 return selectionModel; 150 } 151 152 protected void sort() { 153 data.sort(Comparator.comparingInt(Changeset::getId).reversed()); 154 } 155 156 /* ------------------------------------------------------------------------------ */ 157 /* interface ChangesetCacheListener */ 158 /* ------------------------------------------------------------------------------ */ 159 @Override 160 public void changesetCacheUpdated(ChangesetCacheEvent event) { 161 List<Changeset> selected = getSelectedChangesets(); 162 for (Changeset cs: event.getAddedChangesets()) { 163 data.add(cs); 164 } 165 for (Changeset cs: event.getRemovedChangesets()) { 166 data.remove(cs); 167 } 168 for (Changeset cs: event.getUpdatedChangesets()) { 169 int idx = data.indexOf(cs); 170 if (idx >= 0) { 171 Changeset mine = data.get(idx); 172 if (mine != cs) { 173 mine.mergeFrom(cs); 174 } 175 } 176 } 177 sort(); 178 fireTableDataChanged(); 179 setSelectedChangesets(selected); 180 } 181}