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