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