| 1 | // License: GPL. For details, see LICENSE file. |
|---|
| 2 | package org.openstreetmap.josm.corrector; |
|---|
| 3 | |
|---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr; |
|---|
| 5 | |
|---|
| 6 | import java.awt.GridBagLayout; |
|---|
| 7 | import java.util.ArrayList; |
|---|
| 8 | import java.util.Collection; |
|---|
| 9 | import java.util.Collections; |
|---|
| 10 | import java.util.HashMap; |
|---|
| 11 | import java.util.HashSet; |
|---|
| 12 | import java.util.List; |
|---|
| 13 | import java.util.Map; |
|---|
| 14 | import java.util.Set; |
|---|
| 15 | import java.util.Map.Entry; |
|---|
| 16 | |
|---|
| 17 | import javax.swing.JLabel; |
|---|
| 18 | import javax.swing.JOptionPane; |
|---|
| 19 | import javax.swing.JPanel; |
|---|
| 20 | import javax.swing.JScrollPane; |
|---|
| 21 | |
|---|
| 22 | import org.openstreetmap.josm.Main; |
|---|
| 23 | import org.openstreetmap.josm.command.ChangeCommand; |
|---|
| 24 | import org.openstreetmap.josm.command.ChangeRelationMemberRoleCommand; |
|---|
| 25 | import org.openstreetmap.josm.command.Command; |
|---|
| 26 | import org.openstreetmap.josm.data.osm.Node; |
|---|
| 27 | import org.openstreetmap.josm.data.osm.OsmPrimitive; |
|---|
| 28 | import org.openstreetmap.josm.data.osm.Relation; |
|---|
| 29 | import org.openstreetmap.josm.data.osm.Way; |
|---|
| 30 | import org.openstreetmap.josm.gui.DefaultNameFormatter; |
|---|
| 31 | import org.openstreetmap.josm.gui.JMultilineLabel; |
|---|
| 32 | import org.openstreetmap.josm.tools.GBC; |
|---|
| 33 | import org.openstreetmap.josm.tools.ImageProvider; |
|---|
| 34 | |
|---|
| 35 | /** |
|---|
| 36 | * Abstract base class for automatic tag corrections. |
|---|
| 37 | * |
|---|
| 38 | * Subclasses call applyCorrections() with maps of the requested |
|---|
| 39 | * corrections and a dialog is pesented to the user to |
|---|
| 40 | * confirm these changes. |
|---|
| 41 | */ |
|---|
| 42 | |
|---|
| 43 | public abstract class TagCorrector<P extends OsmPrimitive> { |
|---|
| 44 | |
|---|
| 45 | public abstract Collection<Command> execute(P primitive, P oldprimitive) |
|---|
| 46 | throws UserCancelException; |
|---|
| 47 | |
|---|
| 48 | private String[] applicationOptions = new String[] { |
|---|
| 49 | tr("Apply selected changes"), |
|---|
| 50 | tr("Do not apply changes"), |
|---|
| 51 | tr("Cancel") |
|---|
| 52 | }; |
|---|
| 53 | |
|---|
| 54 | protected Collection<Command> applyCorrections( |
|---|
| 55 | Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap, |
|---|
| 56 | Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap, |
|---|
| 57 | String description) throws UserCancelException { |
|---|
| 58 | |
|---|
| 59 | if (!tagCorrectionsMap.isEmpty() || !roleCorrectionMap.isEmpty()) { |
|---|
| 60 | Collection<Command> commands = new ArrayList<Command>(); |
|---|
| 61 | Map<OsmPrimitive, TagCorrectionTable> tagTableMap = |
|---|
| 62 | new HashMap<OsmPrimitive, TagCorrectionTable>(); |
|---|
| 63 | Map<OsmPrimitive, RoleCorrectionTable> roleTableMap = |
|---|
| 64 | new HashMap<OsmPrimitive, RoleCorrectionTable>(); |
|---|
| 65 | |
|---|
| 66 | final JPanel p = new JPanel(new GridBagLayout()); |
|---|
| 67 | |
|---|
| 68 | final JMultilineLabel label1 = new JMultilineLabel(description); |
|---|
| 69 | label1.setMaxWidth(600); |
|---|
| 70 | p.add(label1, GBC.eop().anchor(GBC.CENTER)); |
|---|
| 71 | |
|---|
| 72 | final JMultilineLabel label2 = new JMultilineLabel( |
|---|
| 73 | tr("Please select which property changes you want to apply.")); |
|---|
| 74 | label2.setMaxWidth(600); |
|---|
| 75 | p.add(label2, GBC.eop().anchor(GBC.CENTER)); |
|---|
| 76 | |
|---|
| 77 | for (Entry<OsmPrimitive, List<TagCorrection>> entry : tagCorrectionsMap.entrySet()) { |
|---|
| 78 | final OsmPrimitive primitive = entry.getKey(); |
|---|
| 79 | final List<TagCorrection> tagCorrections = entry.getValue(); |
|---|
| 80 | |
|---|
| 81 | if (tagCorrections.isEmpty()) { |
|---|
| 82 | continue; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | final JLabel propertiesLabel = new JLabel(tr("Properties of ")); |
|---|
| 86 | p.add(propertiesLabel, GBC.std()); |
|---|
| 87 | |
|---|
| 88 | final JLabel primitiveLabel = new JLabel( |
|---|
| 89 | primitive.getDisplayName(DefaultNameFormatter.getInstance()) + ":", |
|---|
| 90 | ImageProvider.get(primitive.getDisplayType()), |
|---|
| 91 | JLabel.LEFT |
|---|
| 92 | ); |
|---|
| 93 | p.add(primitiveLabel, GBC.eol()); |
|---|
| 94 | |
|---|
| 95 | final TagCorrectionTable table = new TagCorrectionTable( |
|---|
| 96 | tagCorrections); |
|---|
| 97 | final JScrollPane scrollPane = new JScrollPane(table); |
|---|
| 98 | p.add(scrollPane, GBC.eop().fill(GBC.HORIZONTAL)); |
|---|
| 99 | |
|---|
| 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 | } |
|---|