001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.corrector; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.GridBagLayout; 007 import java.util.ArrayList; 008 import java.util.Collection; 009 import java.util.Collections; 010 import java.util.HashMap; 011 import java.util.HashSet; 012 import java.util.List; 013 import java.util.Map; 014 import java.util.Set; 015 import java.util.Map.Entry; 016 017 import javax.swing.JLabel; 018 import javax.swing.JOptionPane; 019 import javax.swing.JPanel; 020 import javax.swing.JScrollPane; 021 022 import org.openstreetmap.josm.Main; 023 import org.openstreetmap.josm.command.ChangeCommand; 024 import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand; 025 import org.openstreetmap.josm.command.Command; 026 import org.openstreetmap.josm.data.osm.Node; 027 import org.openstreetmap.josm.data.osm.OsmPrimitive; 028 import org.openstreetmap.josm.data.osm.Relation; 029 import org.openstreetmap.josm.data.osm.Way; 030 import org.openstreetmap.josm.gui.DefaultNameFormatter; 031 import org.openstreetmap.josm.gui.JMultilineLabel; 032 import org.openstreetmap.josm.tools.GBC; 033 import org.openstreetmap.josm.tools.ImageProvider; 034 035 /** 036 * Abstract base class for automatic tag corrections. 037 * 038 * Subclasses call applyCorrections() with maps of the requested 039 * corrections and a dialog is pesented to the user to 040 * confirm these changes. 041 */ 042 043 public abstract class TagCorrector<P extends OsmPrimitive> { 044 045 public abstract Collection<Command> execute(P primitive, P oldprimitive) 046 throws UserCancelException; 047 048 private String[] applicationOptions = new String[] { 049 tr("Apply selected changes"), 050 tr("Do not apply changes"), 051 tr("Cancel") 052 }; 053 054 protected Collection<Command> applyCorrections( 055 Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap, 056 Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap, 057 String description) throws UserCancelException { 058 059 if (!tagCorrectionsMap.isEmpty() || !roleCorrectionMap.isEmpty()) { 060 Collection<Command> commands = new ArrayList<Command>(); 061 Map<OsmPrimitive, TagCorrectionTable> tagTableMap = 062 new HashMap<OsmPrimitive, TagCorrectionTable>(); 063 Map<OsmPrimitive, RoleCorrectionTable> roleTableMap = 064 new HashMap<OsmPrimitive, RoleCorrectionTable>(); 065 066 final JPanel p = new JPanel(new GridBagLayout()); 067 068 final JMultilineLabel label1 = new JMultilineLabel(description); 069 label1.setMaxWidth(600); 070 p.add(label1, GBC.eop().anchor(GBC.CENTER)); 071 072 final JMultilineLabel label2 = new JMultilineLabel( 073 tr("Please select which property changes you want to apply.")); 074 label2.setMaxWidth(600); 075 p.add(label2, GBC.eop().anchor(GBC.CENTER)); 076 077 for (Entry<OsmPrimitive, List<TagCorrection>> entry : tagCorrectionsMap.entrySet()) { 078 final OsmPrimitive primitive = entry.getKey(); 079 final List<TagCorrection> tagCorrections = entry.getValue(); 080 081 if (tagCorrections.isEmpty()) { 082 continue; 083 } 084 085 final JLabel propertiesLabel = new JLabel(tr("Properties of ")); 086 p.add(propertiesLabel, GBC.std()); 087 088 final JLabel primitiveLabel = new JLabel( 089 primitive.getDisplayName(DefaultNameFormatter.getInstance()) + ":", 090 ImageProvider.get(primitive.getDisplayType()), 091 JLabel.LEFT 092 ); 093 p.add(primitiveLabel, GBC.eol()); 094 095 final TagCorrectionTable table = new TagCorrectionTable( 096 tagCorrections); 097 final JScrollPane scrollPane = new JScrollPane(table); 098 p.add(scrollPane, GBC.eop().fill(GBC.HORIZONTAL)); 099 100 tagTableMap.put(primitive, table); 101 } 102 103 for (Entry<OsmPrimitive, List<RoleCorrection>> entry : roleCorrectionMap.entrySet()) { 104 final OsmPrimitive primitive = entry.getKey(); 105 final List<RoleCorrection> roleCorrections = entry.getValue(); 106 107 if (roleCorrections.isEmpty()) { 108 continue; 109 } 110 111 final JLabel rolesLabel = new JLabel( 112 tr("Roles in relations referring to")); 113 p.add(rolesLabel, GBC.std()); 114 115 final JLabel primitiveLabel = new JLabel( 116 primitive.getDisplayName(DefaultNameFormatter.getInstance()), 117 ImageProvider.get(primitive.getDisplayType()), 118 JLabel.LEFT 119 ); 120 p.add(primitiveLabel, GBC.eol()); 121 122 final RoleCorrectionTable table = new RoleCorrectionTable( 123 roleCorrections); 124 final JScrollPane scrollPane = new JScrollPane(table); 125 p.add(scrollPane, GBC.eop().fill(GBC.HORIZONTAL)); 126 127 roleTableMap.put(primitive, table); 128 } 129 130 int answer = JOptionPane.showOptionDialog( 131 Main.parent, 132 p, 133 tr("Automatic tag correction"), 134 JOptionPane.YES_NO_CANCEL_OPTION, 135 JOptionPane.PLAIN_MESSAGE, 136 null, 137 applicationOptions, 138 applicationOptions[0] 139 ); 140 141 if (answer == JOptionPane.YES_OPTION) { 142 for (Entry<OsmPrimitive, List<TagCorrection>> entry : tagCorrectionsMap.entrySet()) { 143 List<TagCorrection> tagCorrections = entry.getValue(); 144 OsmPrimitive primitive = entry.getKey(); 145 146 // create the clone 147 OsmPrimitive clone = null; 148 if (primitive instanceof Way) { 149 clone = new Way((Way)primitive); 150 } else if (primitive instanceof Node) { 151 clone = new Node((Node)primitive); 152 } else if (primitive instanceof Relation) { 153 clone = new Relation((Relation)primitive); 154 } else 155 throw new AssertionError(); 156 157 // use this structure to remember keys that have been set already so that 158 // they're not dropped by a later step 159 Set<String> keysChanged = new HashSet<String>(); 160 161 // apply all changes to this clone 162 for (int i = 0; i < tagCorrections.size(); i++) { 163 if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) { 164 TagCorrection tagCorrection = tagCorrections.get(i); 165 if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) { 166 clone.remove(tagCorrection.oldKey); 167 } 168 clone.put(tagCorrection.newKey, tagCorrection.newValue); 169 keysChanged.add(tagCorrection.newKey); 170 } 171 } 172 173 // save the clone 174 if (!keysChanged.isEmpty()) { 175 commands.add(new ChangeCommand(primitive, clone)); 176 } 177 } 178 for (Entry<OsmPrimitive, List<RoleCorrection>> entry : roleCorrectionMap.entrySet()) { 179 OsmPrimitive primitive = entry.getKey(); 180 List<RoleCorrection> roleCorrections = entry.getValue(); 181 182 for (int i = 0; i < roleCorrections.size(); i++) { 183 RoleCorrection roleCorrection = roleCorrections.get(i); 184 if (roleTableMap.get(primitive).getCorrectionTableModel().getApply(i)) { 185 commands.add(new ChangeRelationMemberRoleCommand(roleCorrection.relation, roleCorrection.position, roleCorrection.newRole)); 186 } 187 } 188 } 189 } else if (answer != JOptionPane.NO_OPTION) 190 throw new UserCancelException(); 191 return commands; 192 } 193 194 return Collections.emptyList(); 195 } 196 }