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 }