001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.upload;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.BorderLayout;
007import java.awt.Dimension;
008import java.util.ArrayList;
009import java.util.Iterator;
010import java.util.List;
011
012import javax.swing.JLabel;
013import javax.swing.JPanel;
014import javax.swing.JScrollPane;
015import javax.swing.JTable;
016import javax.swing.table.DefaultTableModel;
017
018import org.openstreetmap.josm.data.APIDataSet;
019import org.openstreetmap.josm.data.osm.CyclicUploadDependencyException;
020import org.openstreetmap.josm.data.osm.Relation;
021import org.openstreetmap.josm.gui.ExtendedDialog;
022import org.openstreetmap.josm.gui.MainApplication;
023import org.openstreetmap.josm.gui.PrimitiveRenderer;
024import org.openstreetmap.josm.gui.util.WindowGeometry;
025
026/**
027 * This upload hook reorders the list of new relations to upload such that child
028 * relations are uploaded before parent relations. It also checks for cyclic
029 * dependencies in the list of new relations.
030 *
031 *
032 */
033public class RelationUploadOrderHook implements UploadHook {
034
035    /**
036     * builds the panel which warns users about a cyclic dependency
037     *
038     * @param dep  the list of relations with a cyclic dependency
039     * @return the panel
040     */
041    protected JPanel buildWarningPanel(List<Relation> dep) {
042        JPanel pnl = new JPanel(new BorderLayout());
043        String msg = tr("<html>{0} relations build a cycle because they refer to each other.<br>"
044                + "JOSM cannot upload them. Please edit the relations and remove the "
045                + "cyclic dependency.</html>", dep.size()-1);
046        pnl.add(new JLabel(msg), BorderLayout.NORTH);
047
048        DefaultTableModel model = new DefaultTableModel();
049        model.addColumn(tr("Relation ..."));
050        model.addColumn(tr("... refers to relation"));
051        for (int i = 0; i < dep.size()-1; i++) {
052            Relation r1 = dep.get(i);
053            Relation r2 = dep.get(i+1);
054            model.addRow(new Relation[] {r1, r2});
055        }
056        JTable tbl = new JTable(model);
057        PrimitiveRenderer renderer = new PrimitiveRenderer();
058        tbl.getColumnModel().getColumn(0).setCellRenderer(renderer);
059        tbl.getColumnModel().getColumn(1).setCellRenderer(renderer);
060        pnl.add(new JScrollPane(tbl), BorderLayout.CENTER);
061        return pnl;
062    }
063
064    /**
065     * Warns the user if a cyclic dependency is detected
066     *
067     * @param e the cyclic dependency exception
068     */
069    protected void warnCyclicUploadDependency(CyclicUploadDependencyException e) {
070        List<Relation> dep = new ArrayList<>(e.getCyclicUploadDependency());
071        Relation last = dep.get(dep.size() -1);
072        Iterator<Relation> it = dep.iterator();
073        while (it.hasNext()) {
074            if (it.next() != last) {
075                it.remove();
076            } else {
077                break;
078            }
079        }
080        JPanel pnl = buildWarningPanel(dep);
081        ExtendedDialog dialog = new ExtendedDialog(
082                MainApplication.getMainFrame(),
083                tr("Cycling dependencies"),
084                tr("OK")
085        );
086        dialog.setContent(pnl, false /* don't embed in scroll pane */);
087        dialog.setButtonIcons("ok");
088        dialog.setRememberWindowGeometry(
089                getClass().getName() + ".geometry",
090                WindowGeometry.centerInWindow(MainApplication.getMainFrame(), new Dimension(300, 300))
091        );
092        dialog.showDialog();
093    }
094
095    @Override
096    public boolean checkUpload(APIDataSet apiDataSet) {
097        try {
098            apiDataSet.adjustRelationUploadOrder();
099            return true;
100        } catch (CyclicUploadDependencyException e) {
101            warnCyclicUploadDependency(e);
102            return false;
103        }
104    }
105}