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(new BorderLayout()); 041 String msg = tr("<html>{0} relations build a cycle because they refer to each other.<br>" 042 + "JOSM cannot upload them. Please edit the relations and remove the " 043 + "cyclic dependency.</html>", dep.size()-1); 044 pnl.add(new JLabel(msg), BorderLayout.NORTH); 045 046 DefaultTableModel model = new DefaultTableModel(); 047 model.addColumn(tr("Relation ...")); 048 model.addColumn(tr("... refers to relation")); 049 for (int i = 0; i < dep.size()-1; i++) { 050 Relation r1 = dep.get(i); 051 Relation r2 = dep.get(i+1); 052 model.addRow(new Relation[] {r1, r2}); 053 } 054 JTable tbl = new JTable(model); 055 OsmPrimitivRenderer renderer = new OsmPrimitivRenderer(); 056 tbl.getColumnModel().getColumn(0).setCellRenderer(renderer); 057 tbl.getColumnModel().getColumn(1).setCellRenderer(renderer); 058 pnl.add(new JScrollPane(tbl), BorderLayout.CENTER); 059 return pnl; 060 } 061 062 /** 063 * Warns the user if a cyclic dependency is detected 064 * 065 * @param e the cyclic dependency exception 066 */ 067 protected void warnCyclicUploadDependency(CyclicUploadDependencyException e) { 068 List<Relation> dep = e.getCyclicUploadDependency(); 069 Relation last = dep.get(dep.size() -1); 070 Iterator<Relation> it = dep.iterator(); 071 while (it.hasNext()) { 072 if (it.next() != last) { 073 it.remove(); 074 } else { 075 break; 076 } 077 } 078 JPanel pnl = buildWarningPanel(dep); 079 ExtendedDialog dialog = new ExtendedDialog( 080 Main.parent, 081 tr("Cycling dependencies"), 082 new String[] {tr("OK")} 083 ); 084 dialog.setContent(pnl, false /* don't embed in scroll pane */); 085 dialog.setButtonIcons(new String[] {"ok"}); 086 dialog.setRememberWindowGeometry( 087 getClass().getName() + ".geometry", 088 WindowGeometry.centerInWindow(Main.parent, new Dimension(300, 300)) 089 ); 090 dialog.showDialog(); 091 } 092 093 @Override 094 public boolean checkUpload(APIDataSet apiDataSet) { 095 try { 096 apiDataSet.adjustRelationUploadOrder(); 097 return true; 098 } catch (CyclicUploadDependencyException e) { 099 warnCyclicUploadDependency(e); 100 return false; 101 } 102 } 103}