001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005import static org.openstreetmap.josm.tools.I18n.trn;
006
007import java.awt.GridBagConstraints;
008import java.awt.GridBagLayout;
009import java.util.ArrayList;
010import java.util.List;
011import java.util.Optional;
012
013import javax.swing.AbstractListModel;
014import javax.swing.JLabel;
015import javax.swing.JList;
016import javax.swing.JPanel;
017import javax.swing.JScrollPane;
018
019import org.openstreetmap.josm.data.osm.OsmPrimitive;
020import org.openstreetmap.josm.gui.PrimitiveRenderer;
021
022/**
023 * This panel displays a summary of the objects to upload. It is displayed in the upper part of the {@link UploadDialog}.
024 * @since 2599
025 */
026public class UploadedObjectsSummaryPanel extends JPanel {
027    /**
028     * The swing property name for the number of objects to upload
029     */
030    public static final String NUM_OBJECTS_TO_UPLOAD_PROP = UploadedObjectsSummaryPanel.class.getName() + ".numObjectsToUpload";
031
032    /** the list with the added primitives */
033    private PrimitiveList lstAdd;
034    private JLabel lblAdd;
035    private JScrollPane spAdd;
036    /** the list with the updated primitives */
037    private PrimitiveList lstUpdate;
038    private JLabel lblUpdate;
039    private JScrollPane spUpdate;
040    /** the list with the deleted primitives */
041    private PrimitiveList lstDelete;
042    private JLabel lblDelete;
043    private JScrollPane spDelete;
044
045    /**
046     * Constructs a new {@code UploadedObjectsSummaryPanel}.
047     */
048    public UploadedObjectsSummaryPanel() {
049        build();
050    }
051
052    protected void build() {
053        setLayout(new GridBagLayout());
054        PrimitiveRenderer renderer = new PrimitiveRenderer();
055        // initialize the three lists for uploaded primitives, but don't add them to the dialog yet, see setUploadedPrimitives()
056        //
057        lstAdd = new PrimitiveList();
058        lstAdd.setCellRenderer(renderer);
059        lstAdd.setVisibleRowCount(Math.min(lstAdd.getModel().getSize(), 10));
060        spAdd = new JScrollPane(lstAdd);
061        lblAdd = new JLabel(tr("Objects to add:"));
062        lblAdd.setLabelFor(lstAdd);
063
064        lstUpdate = new PrimitiveList();
065        lstUpdate.setCellRenderer(renderer);
066        lstUpdate.setVisibleRowCount(Math.min(lstUpdate.getModel().getSize(), 10));
067        spUpdate = new JScrollPane(lstUpdate);
068        lblUpdate = new JLabel(tr("Objects to modify:"));
069        lblUpdate.setLabelFor(lstUpdate);
070
071        lstDelete = new PrimitiveList();
072        lstDelete.setCellRenderer(renderer);
073        lstDelete.setVisibleRowCount(Math.min(lstDelete.getModel().getSize(), 10));
074        spDelete = new JScrollPane(lstDelete);
075        lblDelete = new JLabel(tr("Objects to delete:"));
076        lblDelete.setLabelFor(lstDelete);
077    }
078
079    /**
080     * Sets the collections of primitives which will be uploaded
081     *
082     * @param add  the collection of primitives to add
083     * @param update the collection of primitives to update
084     * @param delete the collection of primitives to delete
085     */
086    public void setUploadedPrimitives(List<OsmPrimitive> add, List<OsmPrimitive> update, List<OsmPrimitive> delete) {
087        lstAdd.getPrimitiveListModel().setPrimitives(add);
088        lstUpdate.getPrimitiveListModel().setPrimitives(update);
089        lstDelete.getPrimitiveListModel().setPrimitives(delete);
090
091        GridBagConstraints gcLabel = new GridBagConstraints();
092        gcLabel.fill = GridBagConstraints.HORIZONTAL;
093        gcLabel.weightx = 1.0;
094        gcLabel.weighty = 0.0;
095        gcLabel.anchor = GridBagConstraints.FIRST_LINE_START;
096
097        GridBagConstraints gcList = new GridBagConstraints();
098        gcList.fill = GridBagConstraints.BOTH;
099        gcList.weightx = 1.0;
100        gcList.weighty = 1.0;
101        gcList.anchor = GridBagConstraints.CENTER;
102        removeAll();
103        int y = -1;
104        if (!add.isEmpty()) {
105            y++;
106            gcLabel.gridy = y;
107            lblAdd.setText(trn("{0} object to add:", "{0} objects to add:", add.size(), add.size()));
108            add(lblAdd, gcLabel);
109            y++;
110            gcList.gridy = y;
111            add(spAdd, gcList);
112        }
113        if (!update.isEmpty()) {
114            y++;
115            gcLabel.gridy = y;
116            lblUpdate.setText(trn("{0} object to modify:", "{0} objects to modify:", update.size(), update.size()));
117            add(lblUpdate, gcLabel);
118            y++;
119            gcList.gridy = y;
120            add(spUpdate, gcList);
121        }
122        if (!delete.isEmpty()) {
123            y++;
124            gcLabel.gridy = y;
125            lblDelete.setText(trn("{0} object to delete:", "{0} objects to delete:", delete.size(), delete.size()));
126            add(lblDelete, gcLabel);
127            y++;
128            gcList.gridy = y;
129            add(spDelete, gcList);
130        }
131
132        firePropertyChange(NUM_OBJECTS_TO_UPLOAD_PROP, 0, getNumObjectsToUpload());
133    }
134
135    /**
136     * Replies the number of objects to upload
137     *
138     * @return the number of objects to upload
139     */
140    public int getNumObjectsToUpload() {
141        return lstAdd.getModel().getSize()
142        + lstUpdate.getModel().getSize()
143        + lstDelete.getModel().getSize();
144    }
145
146    /**
147     * A simple list of OSM primitives.
148     */
149    static class PrimitiveList extends JList<OsmPrimitive> {
150        /**
151         * Constructs a new {@code PrimitiveList}.
152         */
153        PrimitiveList() {
154            super(new PrimitiveListModel());
155        }
156
157        public PrimitiveListModel getPrimitiveListModel() {
158            return (PrimitiveListModel) getModel();
159        }
160    }
161
162    /**
163     * A list model for a list of OSM primitives.
164     */
165    static class PrimitiveListModel extends AbstractListModel<OsmPrimitive> {
166        private transient List<OsmPrimitive> primitives;
167
168        /**
169         * Constructs a new {@code PrimitiveListModel}.
170         */
171        PrimitiveListModel() {
172            primitives = new ArrayList<>();
173        }
174
175        PrimitiveListModel(List<OsmPrimitive> primitives) {
176            setPrimitives(primitives);
177        }
178
179        public void setPrimitives(List<OsmPrimitive> primitives) {
180            this.primitives = Optional.ofNullable(primitives).orElseGet(ArrayList::new);
181            fireContentsChanged(this, 0, getSize());
182        }
183
184        @Override
185        public OsmPrimitive getElementAt(int index) {
186            if (primitives == null) return null;
187            return primitives.get(index);
188        }
189
190        @Override
191        public int getSize() {
192            if (primitives == null) return 0;
193            return primitives.size();
194        }
195    }
196}