source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java@ 1642

Last change on this file since 1642 was 1642, checked in by Gubaer, 15 years ago

added row numbers and synchronized scrolling in conflict resolution dialog
fixed bugs in conflict resolution

  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.BorderLayout;
8import java.awt.Color;
9import java.awt.Graphics;
10import java.awt.GridLayout;
11import java.awt.Point;
12import java.awt.event.ActionEvent;
13import java.awt.event.ActionListener;
14import java.awt.event.KeyEvent;
15import java.awt.event.MouseAdapter;
16import java.awt.event.MouseEvent;
17import java.util.Collection;
18import java.util.HashMap;
19import java.util.LinkedList;
20import java.util.Map;
21
22import javax.swing.DefaultListModel;
23import javax.swing.JList;
24import javax.swing.JPanel;
25import javax.swing.JScrollPane;
26import javax.swing.ListSelectionModel;
27import javax.swing.event.ListSelectionEvent;
28import javax.swing.event.ListSelectionListener;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.command.ConflictResolveCommand;
32import org.openstreetmap.josm.data.SelectionChangedListener;
33import org.openstreetmap.josm.data.osm.DataSet;
34import org.openstreetmap.josm.data.osm.Node;
35import org.openstreetmap.josm.data.osm.OsmPrimitive;
36import org.openstreetmap.josm.data.osm.Relation;
37import org.openstreetmap.josm.data.osm.RelationMember;
38import org.openstreetmap.josm.data.osm.Way;
39import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
40import org.openstreetmap.josm.data.osm.visitor.Visitor;
41import org.openstreetmap.josm.gui.ConflictResolver;
42import org.openstreetmap.josm.gui.ExtendedDialog;
43import org.openstreetmap.josm.gui.NavigatableComponent;
44import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
45import org.openstreetmap.josm.gui.SideButton;
46import org.openstreetmap.josm.tools.Shortcut;
47
48public final class ConflictDialog extends ToggleDialog {
49
50 public final Map<OsmPrimitive, OsmPrimitive> conflicts = new HashMap<OsmPrimitive, OsmPrimitive>();
51 private final DefaultListModel model = new DefaultListModel();
52 private final JList displaylist = new JList(model);
53
54 private final SideButton sbSelect = new SideButton(marktr("Select"), "select", "Conflict",
55 tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
56 public void actionPerformed(ActionEvent e) {
57 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
58 for (Object o : displaylist.getSelectedValues()) {
59 sel.add((OsmPrimitive)o);
60 }
61 Main.ds.setSelected(sel);
62 }
63 });
64 private final SideButton sbResolve = new SideButton(marktr("Resolve"), "conflict", "Conflict",
65 tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
66 public void actionPerformed(ActionEvent e) {
67 resolve();
68 }
69 });
70
71 public ConflictDialog() {
72 super(tr("Conflict"), "conflict", tr("Merging conflicts."),
73 Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
74 displaylist.setCellRenderer(new OsmPrimitivRenderer());
75 displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
76 displaylist.addMouseListener(new MouseAdapter(){
77 @Override public void mouseClicked(MouseEvent e) {
78 if (e.getClickCount() >= 2) {
79 resolve();
80 }
81 }
82 });
83 add(new JScrollPane(displaylist), BorderLayout.CENTER);
84
85 JPanel buttonPanel = new JPanel(new GridLayout(1,2));
86 buttonPanel.add(sbResolve);
87 buttonPanel.add(sbSelect);
88 add(buttonPanel, BorderLayout.SOUTH);
89
90 DataSet.selListeners.add(new SelectionChangedListener(){
91 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
92 displaylist.clearSelection();
93 for (OsmPrimitive osm : newSelection) {
94 if (conflicts.containsKey(osm)) {
95 int pos = model.indexOf(osm);
96 displaylist.addSelectionInterval(pos, pos);
97 }
98 }
99 }
100 });
101 displaylist.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
102 public void valueChanged(ListSelectionEvent e) {
103 Main.map.mapView.repaint();
104 }
105 });
106
107 rebuildList();
108 }
109
110 private final void resolve() {
111 String method = Main.pref.get("conflict.resolution", "traditional");
112 method = method.trim().toLowerCase();
113 if (method.equals("traditional")) {
114 resolveTraditional();
115 } else if (method.equals("extended")) {
116 resolveExtended();
117 } else {
118 System.out.println(tr("WARNING: unexpected value for preference conflict.resolution, got " + method));
119 resolveTraditional();
120 }
121 }
122
123
124 private final void resolveExtended() {
125 if(model.size() == 1) {
126 displaylist.setSelectedIndex(0);
127 }
128
129 if (displaylist.getSelectedIndex() == -1)
130 return;
131
132 int [] selectedRows = displaylist.getSelectedIndices();
133 if (selectedRows == null || selectedRows.length == 0)
134 return;
135 int row = selectedRows[0];
136 OsmPrimitive my = (OsmPrimitive)model.get(row);
137 OsmPrimitive their = conflicts.get(my);
138 ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);
139 dialog.getConflictResolver().populate(my, their);
140 dialog.setVisible(true);
141 Main.map.mapView.repaint();
142 }
143
144
145 private final void resolveTraditional() {
146 if(model.size() == 1) {
147 displaylist.setSelectedIndex(0);
148 }
149
150 if (displaylist.getSelectedIndex() == -1)
151 return;
152 Map<OsmPrimitive, OsmPrimitive> sel = new HashMap<OsmPrimitive, OsmPrimitive>();
153 for (int i : displaylist.getSelectedIndices()) {
154 OsmPrimitive s = (OsmPrimitive)model.get(i);
155 sel.put(s, conflicts.get(s));
156 }
157 ConflictResolver resolver = new ConflictResolver(sel);
158 int answer = new ExtendedDialog(Main.parent,
159 tr("Resolve Conflicts"),
160 resolver,
161 new String[] { tr("Solve Conflict"), tr("Cancel") },
162 new String[] { "dialogs/conflict.png", "cancel.png"}
163 ).getValue();
164
165 if (answer != 1)
166 return;
167 Main.main.undoRedo.add(new ConflictResolveCommand(resolver.conflicts, sel));
168 Main.map.mapView.repaint();
169 }
170
171 public final void rebuildList() {
172 model.removeAllElements();
173 for (OsmPrimitive osm : this.conflicts.keySet()) {
174 model.addElement(osm);
175 }
176
177 if(model.size() != 0) {
178 setTitle(tr("Conflicts: {0}", model.size()), true);
179 } else {
180 setTitle(tr("Conflicts"), false);
181 }
182
183 sbSelect.setEnabled(model.size() > 0);
184 sbResolve.setEnabled(model.size() > 0);
185 }
186
187 public final void add(Map<OsmPrimitive, OsmPrimitive> conflicts) {
188 this.conflicts.putAll(conflicts);
189 rebuildList();
190 }
191
192
193 /**
194 * removes a conflict registered for {@see OsmPrimitive} <code>my</code>
195 *
196 * @param my the {@see OsmPrimitive} for which a conflict is registered
197 * with this dialog
198 */
199 public void removeConflictForPrimitive(OsmPrimitive my) {
200 if (! conflicts.keySet().contains(my))
201 return;
202 conflicts.remove(my);
203 rebuildList();
204 repaint();
205 }
206
207 /**
208 * registers a conflict with this dialog. The conflict is represented
209 * by a pair of {@see OsmPrimitive} with differences in their tag sets,
210 * their node lists (for {@see Way}s) or their member lists (for {@see Relation}s)
211 *
212 * @param my my version of the {@see OsmPrimitive}
213 * @param their their version of the {@see OsmPrimitive}
214 */
215 public void addConflict(OsmPrimitive my, OsmPrimitive their) {
216 conflicts.put(my, their);
217 rebuildList();
218 repaint();
219 }
220
221 static public Color getColor()
222 {
223 return Main.pref.getColor(marktr("conflict"), Color.gray);
224 }
225
226 /**
227 * Paint all conflicts that can be expressed on the main window.
228 */
229 public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
230 Color preferencesColor = getColor();
231 if (preferencesColor.equals(Main.pref.getColor(marktr("background"), Color.black)))
232 return;
233 g.setColor(preferencesColor);
234 Visitor conflictPainter = new AbstractVisitor(){
235 public void visit(Node n) {
236 Point p = nc.getPoint(n.getEastNorth());
237 g.drawRect(p.x-1, p.y-1, 2, 2);
238 }
239 public void visit(Node n1, Node n2) {
240 Point p1 = nc.getPoint(n1.getEastNorth());
241 Point p2 = nc.getPoint(n2.getEastNorth());
242 g.drawLine(p1.x, p1.y, p2.x, p2.y);
243 }
244 public void visit(Way w) {
245 Node lastN = null;
246 for (Node n : w.nodes) {
247 if (lastN == null) {
248 lastN = n;
249 continue;
250 }
251 visit(lastN, n);
252 lastN = n;
253 }
254 }
255 public void visit(Relation e) {
256 for (RelationMember em : e.members) {
257 em.member.visit(this);
258 }
259 }
260 };
261 for (Object o : displaylist.getSelectedValues()) {
262 if (conflicts.get(o) == null) {
263 continue;
264 }
265 conflicts.get(o).visit(conflictPainter);
266 }
267 }
268}
Note: See TracBrowser for help on using the repository browser.