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