001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs.changeset;
003
004import java.util.ArrayList;
005import java.util.HashSet;
006import java.util.Iterator;
007import java.util.List;
008import java.util.Set;
009
010import javax.swing.DefaultListSelectionModel;
011import javax.swing.table.AbstractTableModel;
012
013import org.openstreetmap.josm.data.osm.ChangesetDataSet;
014import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetDataSetEntry;
015import org.openstreetmap.josm.data.osm.ChangesetDataSet.ChangesetModificationType;
016import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
017
018/**
019 * This is the table model for the content of a changeset.
020 * @since 2689
021 */
022public class ChangesetContentTableModel extends AbstractTableModel {
023
024    private final transient List<ChangesetContentEntry> data = new ArrayList<>();
025    private final DefaultListSelectionModel selectionModel;
026
027    /**
028     * Constructs a new {@code ChangesetContentTableModel}.
029     * @param selectionModel selection model
030     */
031    public ChangesetContentTableModel(DefaultListSelectionModel selectionModel) {
032        this.selectionModel = selectionModel;
033    }
034
035    /**
036     * Replies true if there is at least one selected primitive in the table model
037     *
038     * @return true if there is at least one selected primitive in the table model
039     */
040    public boolean hasSelectedPrimitives() {
041        return selectionModel.getMinSelectionIndex() >= 0;
042    }
043
044    /**
045     * Selects a single item by its index.
046     * @param row index
047     */
048    public void setSelectedByIdx(int row) {
049        selectionModel.setSelectionInterval(row, row);
050    }
051
052    /**
053     * Replies the selection model
054     * @return the selection model
055     */
056    public DefaultListSelectionModel getSelectionModel() {
057        return selectionModel;
058    }
059
060    /**
061     * Returns the selected history primitives.
062     * @return the selected history primitives
063     */
064    public Set<HistoryOsmPrimitive> getSelectedPrimitives() {
065        Set<HistoryOsmPrimitive> ret = new HashSet<>();
066        for (int i = 0; i < data.size(); i++) {
067            if (selectionModel.isSelectedIndex(i)) {
068                ret.add(data.get(i).getPrimitive());
069            }
070        }
071        return ret;
072    }
073
074    /**
075     * Populates the model with the content of a changeset. If ds is null, the table is cleared.
076     *
077     * @param ds the changeset content.
078     */
079    public void populate(ChangesetDataSet ds) {
080        this.data.clear();
081        if (ds == null) {
082            fireTableDataChanged();
083            return;
084        }
085        for (Iterator<ChangesetDataSetEntry> it = ds.iterator(); it.hasNext();) {
086            data.add(new ChangesetContentEntry(it.next()));
087        }
088        sort();
089        fireTableDataChanged();
090    }
091
092    /**
093     * Sort data.
094     */
095    protected void sort() {
096        data.sort((c1, c2) -> {
097                if (c1.getModificationType().equals(c2.getModificationType())) {
098                    long id1 = c1.getPrimitive().getId();
099                    long id2 = c2.getPrimitive().getId();
100
101                    if (id1 == id2)
102                        return 0;
103                    else if (id1 < id2)
104                        return -1;
105                    return 1;
106                }
107                switch(c1.getModificationType()) {
108                case CREATED: return -1;
109                case UPDATED:
110                    switch(c2.getModificationType()) {
111                    case CREATED: return 1;
112                    default: return -1;
113                    }
114                case DELETED:
115                    return 1;
116                }
117                // should not happen
118                return 0;
119            }
120        );
121    }
122
123    /* -------------------------------------------------------------- */
124    /* interface TableModel                                           */
125    /* -------------------------------------------------------------- */
126    @Override
127    public int getColumnCount() {
128        return 3;
129    }
130
131    @Override
132    public int getRowCount() {
133        return data.size();
134    }
135
136    @Override
137    public Object getValueAt(int row, int col) {
138        switch(col) {
139        case 0: return data.get(row).getModificationType();
140        default: return data.get(row).getPrimitive();
141        }
142    }
143
144    /**
145     * The type used internally to keep information about {@link HistoryOsmPrimitive}
146     * with their {@link ChangesetModificationType}.
147     */
148    private static class ChangesetContentEntry implements ChangesetDataSetEntry {
149        private final ChangesetModificationType modificationType;
150        private final HistoryOsmPrimitive primitive;
151
152        ChangesetContentEntry(ChangesetModificationType modificationType, HistoryOsmPrimitive primitive) {
153            this.modificationType = modificationType;
154            this.primitive = primitive;
155        }
156
157        ChangesetContentEntry(ChangesetDataSetEntry entry) {
158            this(entry.getModificationType(), entry.getPrimitive());
159        }
160
161        @Override
162        public ChangesetModificationType getModificationType() {
163            return modificationType;
164        }
165
166        @Override
167        public HistoryOsmPrimitive getPrimitive() {
168            return primitive;
169        }
170    }
171}