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.BorderLayout; 008import java.beans.PropertyChangeEvent; 009import java.beans.PropertyChangeListener; 010import java.util.Optional; 011import java.util.stream.Stream; 012 013import javax.swing.BorderFactory; 014import javax.swing.JLabel; 015import javax.swing.JPanel; 016import javax.swing.event.HyperlinkEvent; 017import javax.swing.event.HyperlinkListener; 018 019import org.openstreetmap.josm.data.osm.Changeset; 020import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 021import org.openstreetmap.josm.io.Capabilities; 022import org.openstreetmap.josm.io.OsmApi; 023import org.openstreetmap.josm.io.UploadStrategySpecification; 024import org.openstreetmap.josm.spi.preferences.Config; 025import org.openstreetmap.josm.tools.ImageProvider; 026import org.openstreetmap.josm.tools.StreamUtils; 027import org.openstreetmap.josm.tools.Utils; 028 029/** 030 * A panel that displays a summary of data the user is about to upload 031 * <p> 032 * FIXME this class should extend HtmlPanel instead (duplicated code in here) 033 */ 034public class UploadParameterSummaryPanel extends JPanel implements HyperlinkListener, PropertyChangeListener { 035 private transient UploadStrategySpecification spec = new UploadStrategySpecification(); 036 private int numObjects; 037 private JMultilineLabel jepMessage; 038 private JLabel lblWarning; 039 040 private transient Changeset selectedChangeset; 041 private boolean closeChangesetAfterNextUpload; 042 private transient Runnable configHandler; 043 044 /** 045 * Constructs a new {@code UploadParameterSummaryPanel}. 046 */ 047 public UploadParameterSummaryPanel() { 048 build(); 049 updateSummary(); 050 } 051 052 protected String buildChangesetSummary() { 053 if (selectedChangeset == null || selectedChangeset.isNew()) { 054 return tr("Objects are uploaded to a <strong>new changeset</strong>."); 055 } else { 056 return tr("Objects are uploaded to the <strong>open changeset</strong> {0} ''{1}''.", 057 selectedChangeset.getId(), 058 selectedChangeset.getComment() 059 ); 060 } 061 } 062 063 protected String buildChangesetSummary2() { 064 if (closeChangesetAfterNextUpload) { 065 return tr("The changeset is going to be <strong>closed</strong> after this upload"); 066 } else { 067 return tr("The changeset is <strong>left open</strong> after this upload"); 068 } 069 } 070 071 protected String buildStrategySummary() { 072 if (spec == null) 073 return ""; 074 // check whether we can use one changeset only or whether we have to use multiple changesets 075 // 076 boolean useOneChangeset = true; 077 Capabilities capabilities = OsmApi.getOsmApi().getCapabilities(); 078 int maxChunkSize = capabilities != null ? capabilities.getMaxChangesetSize() : -1; 079 if (maxChunkSize > 0 && numObjects > maxChunkSize) { 080 useOneChangeset = false; 081 } 082 083 int numRequests = spec.getNumRequests(numObjects); 084 if (useOneChangeset) { 085 lblWarning.setVisible(false); 086 if (numRequests == 0) { 087 return trn( 088 "Uploading <strong>{0} object</strong> to <strong>1 changeset</strong>", 089 "Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong>", 090 numObjects, numObjects 091 ); 092 } else if (numRequests == 1) { 093 return trn( 094 "Uploading <strong>{0} object</strong> to <strong>1 changeset</strong> using <strong>1 request</strong>", 095 "Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong> using <strong>1 request</strong>", 096 numObjects, numObjects 097 ); 098 } else if (numRequests > 1) { 099 return tr("Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong> using <strong>{1} requests</strong>", 100 numObjects, numRequests); 101 } 102 } else { 103 lblWarning.setVisible(true); 104 if (numRequests == 0) { 105 return tr("{0} objects exceed the max. allowed {1} objects in a changeset on the server ''{2}''. " + 106 "Please <a href=\"urn:changeset-configuration\">configure</a> how to proceed with <strong>multiple changesets</strong>", 107 numObjects, maxChunkSize, OsmApi.getOsmApi().getBaseUrl()); 108 } else if (numRequests > 1) { 109 return tr("Uploading <strong>{0} objects</strong> to <strong>multiple changesets</strong> using <strong>{1} requests</strong>", 110 numObjects, numRequests); 111 } 112 } 113 return ""; 114 } 115 116 protected void build() { 117 jepMessage = new JMultilineLabel(""); 118 jepMessage.addHyperlinkListener(this); 119 120 setLayout(new BorderLayout()); 121 setBorder(BorderFactory.createTitledBorder(tr("Settings:"))); 122 add(jepMessage, BorderLayout.CENTER); 123 lblWarning = new JLabel(""); 124 lblWarning.setVisible(false); 125 lblWarning.setLabelFor(jepMessage); 126 lblWarning.setIcon(ImageProvider.get("warning-small")); 127 lblWarning.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 128 JPanel pnl = new JPanel(new BorderLayout()); 129 pnl.add(lblWarning, BorderLayout.NORTH); 130 add(pnl, BorderLayout.WEST); 131 } 132 133 public void setConfigurationParameterRequestListener(Runnable handler) { 134 this.configHandler = handler; 135 } 136 137 /** 138 * Sets the {@link UploadStrategySpecification} the user chose 139 * @param spec The specification to display 140 */ 141 public void setUploadStrategySpecification(UploadStrategySpecification spec) { 142 this.spec = spec; 143 updateSummary(); 144 } 145 146 /** 147 * Sets the number of objects that will be uploaded 148 * @param numObjects The number to display 149 */ 150 public void setNumObjects(int numObjects) { 151 this.numObjects = numObjects; 152 updateSummary(); 153 } 154 155 /** 156 * Display that the changeset will be closed after the upload 157 * @param value <code>true</code> if it will be closed 158 */ 159 public void setCloseChangesetAfterNextUpload(boolean value) { 160 this.closeChangesetAfterNextUpload = value; 161 updateSummary(); 162 } 163 164 protected void updateSummary() { 165 final String server = Optional.of(OsmApi.getOsmApi().getServerUrl()) 166 .filter(url -> !Config.getUrls().getDefaultOsmApiUrl().equals(url)) 167 .map(url -> tr("… to server: <strong>{0}</strong>", url)) 168 .orElse(""); 169 final String html = Stream.of(buildChangesetSummary(), buildChangesetSummary2(), buildStrategySummary(), server) 170 .filter(s -> !Utils.isEmpty(s)) 171 .collect(StreamUtils.toHtmlList()); 172 jepMessage.setText(html); 173 validate(); 174 } 175 176 /* --------------------------------------------------------------------- */ 177 /* Interface HyperlinkListener 178 /* --------------------------------------------------------------------- */ 179 @Override 180 public void hyperlinkUpdate(HyperlinkEvent e) { 181 if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) { 182 String desc = e.getDescription(); 183 if (desc == null || configHandler == null) 184 return; 185 if ("urn:changeset-configuration".equals(desc)) { 186 configHandler.run(); 187 } 188 } 189 } 190 191 /* --------------------------------------------------------------------- */ 192 /* Interface PropertyChangeListener 193 /* --------------------------------------------------------------------- */ 194 @Override 195 public void propertyChange(PropertyChangeEvent evt) { 196 if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) { 197 selectedChangeset = (Changeset) evt.getNewValue(); 198 updateSummary(); 199 } else if (evt.getPropertyName().equals(ChangesetManagementPanel.CLOSE_CHANGESET_AFTER_UPLOAD)) { 200 closeChangesetAfterNextUpload = (Boolean) evt.getNewValue(); 201 updateSummary(); 202 } else if (evt.getPropertyName().equals(UploadStrategySelectionPanel.UPLOAD_STRATEGY_SPECIFICATION_PROP)) { 203 this.spec = (UploadStrategySpecification) evt.getNewValue(); 204 updateSummary(); 205 } 206 } 207}