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}