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;
011
012import javax.swing.BorderFactory;
013import javax.swing.JLabel;
014import javax.swing.JPanel;
015import javax.swing.event.HyperlinkEvent;
016import javax.swing.event.HyperlinkListener;
017
018import org.openstreetmap.josm.data.osm.Changeset;
019import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
020import org.openstreetmap.josm.io.Capabilities;
021import org.openstreetmap.josm.io.OsmApi;
022import org.openstreetmap.josm.io.UploadStrategySpecification;
023import org.openstreetmap.josm.spi.preferences.Config;
024import org.openstreetmap.josm.tools.ImageProvider;
025
026/**
027 * A panel that displays a summary of data the user is about to upload
028 * <p>
029 * FIXME this class should extend HtmlPanel instead (duplicated code in here)
030 */
031public class UploadParameterSummaryPanel extends JPanel implements HyperlinkListener, PropertyChangeListener {
032    private transient UploadStrategySpecification spec = new UploadStrategySpecification();
033    private int numObjects;
034    private JMultilineLabel jepMessage;
035    private JLabel lblWarning;
036
037    private transient Changeset selectedChangeset;
038    private boolean closeChangesetAfterNextUpload;
039    private transient ConfigurationParameterRequestHandler configHandler;
040
041    /**
042     * Constructs a new {@code UploadParameterSummaryPanel}.
043     */
044    public UploadParameterSummaryPanel() {
045        build();
046        updateSummary();
047    }
048
049    protected String buildChangesetSummary() {
050        StringBuilder msg = new StringBuilder(96);
051        if (selectedChangeset == null || selectedChangeset.isNew()) {
052            msg.append(tr("Objects are uploaded to a <strong>new changeset</strong>."));
053        } else {
054            msg.append(tr("Objects are uploaded to the <strong>open changeset</strong> {0} with upload comment ''{1}''.",
055                    selectedChangeset.getId(),
056                    selectedChangeset.getComment()
057            ));
058        }
059        msg.append(' ');
060        if (closeChangesetAfterNextUpload) {
061            msg.append(tr("The changeset is going to be <strong>closed</strong> after this upload"));
062        } else {
063            msg.append(tr("The changeset is <strong>left open</strong> after this upload"));
064        }
065        msg.append(" (<a href=\"urn:changeset-configuration\">").append(tr("configure changeset")).append("</a>)");
066        return msg.toString();
067    }
068
069    protected String buildStrategySummary() {
070        if (spec == null)
071            return "";
072        // check whether we can use one changeset only or whether we have to use multiple changesets
073        //
074        boolean useOneChangeset = true;
075        Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
076        int maxChunkSize = capabilities != null ? capabilities.getMaxChangesetSize() : -1;
077        if (maxChunkSize > 0 && numObjects > maxChunkSize) {
078            useOneChangeset = false;
079        }
080
081        int numRequests = spec.getNumRequests(numObjects);
082        String msg = null;
083        if (useOneChangeset) {
084            lblWarning.setVisible(false);
085            if (numRequests == 0) {
086                msg = trn(
087                        "Uploading <strong>{0} object</strong> to <strong>1 changeset</strong>",
088                        "Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong>",
089                        numObjects, numObjects
090                );
091            } else if (numRequests == 1) {
092                msg = trn(
093                        "Uploading <strong>{0} object</strong> to <strong>1 changeset</strong> using <strong>1 request</strong>",
094                        "Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong> using <strong>1 request</strong>",
095                        numObjects, numObjects
096                );
097            } else if (numRequests > 1) {
098                msg = tr("Uploading <strong>{0} objects</strong> to <strong>1 changeset</strong> using <strong>{1} requests</strong>",
099                        numObjects, numRequests);
100            }
101            msg = msg + " (<a href=\"urn:advanced-configuration\">" + tr("advanced configuration") + "</a>)";
102        } else {
103            lblWarning.setVisible(true);
104            if (numRequests == 0) {
105                msg = tr("{0} objects exceed the max. allowed {1} objects in a changeset on the server ''{2}''. " +
106                        "Please <a href=\"urn:advanced-configuration\">configure</a> how to proceed with <strong>multiple changesets</strong>",
107                        numObjects, maxChunkSize, OsmApi.getOsmApi().getBaseUrl());
108            } else if (numRequests > 1) {
109                msg = tr("Uploading <strong>{0} objects</strong> to <strong>multiple changesets</strong> using <strong>{1} requests</strong>",
110                        numObjects, numRequests);
111                msg = msg + " (<a href=\"urn:advanced-configuration\">" + tr("advanced configuration") + "</a>)";
112            }
113        }
114        return msg;
115    }
116
117    protected void build() {
118        jepMessage = new JMultilineLabel("");
119        jepMessage.addHyperlinkListener(this);
120
121        setLayout(new BorderLayout());
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(ConfigurationParameterRequestHandler 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        jepMessage.setText("<html>"
166                + buildStrategySummary()
167                + "<br>"
168                + Optional.of(OsmApi.getOsmApi().getServerUrl())
169                .filter(url -> !Config.getUrls().getDefaultOsmApiUrl().equals(url))
170                .map(url -> tr("… to server: <strong>{0}</strong>", url))
171                .orElse("")
172                + "<br><br>"
173                + buildChangesetSummary()
174                + "</html>");
175    }
176
177    /* --------------------------------------------------------------------- */
178    /* Interface HyperlinkListener
179    /* --------------------------------------------------------------------- */
180    @Override
181    public void hyperlinkUpdate(HyperlinkEvent e) {
182        if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType())) {
183            String desc = e.getDescription();
184            if (desc == null || configHandler == null)
185                return;
186            if ("urn:changeset-configuration".equals(desc)) {
187                configHandler.handleChangesetConfigurationRequest();
188            } else if ("urn:advanced-configuration".equals(desc)) {
189                configHandler.handleUploadStrategyConfigurationRequest();
190            }
191        }
192    }
193
194    /* --------------------------------------------------------------------- */
195    /* Interface PropertyChangeListener
196    /* --------------------------------------------------------------------- */
197    @Override
198    public void propertyChange(PropertyChangeEvent evt) {
199        if (evt.getPropertyName().equals(ChangesetManagementPanel.SELECTED_CHANGESET_PROP)) {
200            selectedChangeset = (Changeset) evt.getNewValue();
201            updateSummary();
202        } else if (evt.getPropertyName().equals(ChangesetManagementPanel.CLOSE_CHANGESET_AFTER_UPLOAD)) {
203            closeChangesetAfterNextUpload = (Boolean) evt.getNewValue();
204            updateSummary();
205        } else if (evt.getPropertyName().equals(UploadedObjectsSummaryPanel.NUM_OBJECTS_TO_UPLOAD_PROP)) {
206            numObjects = (Integer) evt.getNewValue();
207            updateSummary();
208        } else if (evt.getPropertyName().equals(UploadStrategySelectionPanel.UPLOAD_STRATEGY_SPECIFICATION_PROP)) {
209            this.spec = (UploadStrategySpecification) evt.getNewValue();
210            updateSummary();
211        }
212    }
213}