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 }