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.Main; 019import org.openstreetmap.josm.data.APIDataSet; 020import org.openstreetmap.josm.data.osm.CyclicUploadDependencyException; 021import org.openstreetmap.josm.data.osm.Relation; 022import org.openstreetmap.josm.gui.ExtendedDialog; 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 Main.parent, 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(Main.parent, 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}