source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/pair/properties/PropertiesMerger.java@ 3362

Last change on this file since 3362 was 3362, checked in by stoecker, 14 years ago

fix #5182 - Conflict system simplification - patch by Upliner

  • Property svn:eol-style set to native
File size: 18.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.pair.properties;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.GridBagConstraints;
8import java.awt.GridBagLayout;
9import java.awt.Insets;
10import java.awt.event.ActionEvent;
11import java.text.DecimalFormat;
12import java.util.List;
13import java.util.Observable;
14import java.util.Observer;
15
16import javax.swing.AbstractAction;
17import javax.swing.Action;
18import javax.swing.BorderFactory;
19import javax.swing.JButton;
20import javax.swing.JLabel;
21import javax.swing.JPanel;
22
23import org.openstreetmap.josm.data.conflict.Conflict;
24import org.openstreetmap.josm.data.coor.LatLon;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.gui.DefaultNameFormatter;
27import org.openstreetmap.josm.gui.conflict.pair.IConflictResolver;
28import org.openstreetmap.josm.gui.conflict.pair.MergeDecisionType;
29import org.openstreetmap.josm.tools.ImageProvider;
30
31/**
32 * This class represents a UI component for resolving conflicts in some properties
33 * of {@see OsmPrimitive}.
34 *
35 */
36public class PropertiesMerger extends JPanel implements Observer, IConflictResolver {
37 private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000000");
38
39 public final static Color BGCOLOR_NO_CONFLICT = new Color(234,234,234);
40 public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
41 public final static Color BGCOLOR_DECIDED = new Color(217,255,217);
42
43 private JLabel lblMyVersion;
44 private JLabel lblMergedVersion;
45 private JLabel lblTheirVersion;
46
47 private JLabel lblMyCoordinates;
48 private JLabel lblMergedCoordinates;
49 private JLabel lblTheirCoordinates;
50
51 private JLabel lblMyDeletedState;
52 private JLabel lblMergedDeletedState;
53 private JLabel lblTheirDeletedState;
54
55 private JLabel lblMyReferrers;
56 private JLabel lblTheirReferrers;
57
58 private final PropertiesMergeModel model;
59
60 protected JLabel buildValueLabel(String name) {
61 JLabel lbl = new JLabel();
62 lbl.setName(name);
63 lbl.setHorizontalAlignment(JLabel.CENTER);
64 lbl.setOpaque(true);
65 lbl.setBorder(BorderFactory.createLoweredBevelBorder());
66 return lbl;
67 }
68
69 protected void buildHeaderRow() {
70 GridBagConstraints gc = new GridBagConstraints();
71
72 gc.gridx = 1;
73 gc.gridy = 0;
74 gc.gridwidth = 1;
75 gc.gridheight = 1;
76 gc.fill = GridBagConstraints.NONE;
77 gc.anchor = GridBagConstraints.CENTER;
78 gc.weightx = 0.0;
79 gc.weighty = 0.0;
80 gc.insets = new Insets(10,0,10,0);
81 lblMyVersion = new JLabel(tr("My version"));
82 lblMyVersion.setToolTipText(tr("Properties in my dataset, i.e. the local dataset"));
83 add(lblMyVersion, gc);
84
85 gc.gridx = 3;
86 gc.gridy = 0;
87 lblMergedVersion = new JLabel(tr("Merged version"));
88 lblMergedVersion.setToolTipText(tr("Properties in the merged element. They will replace properties in my elements when merge decisions are applied."));
89 add(lblMergedVersion, gc);
90
91 gc.gridx = 5;
92 gc.gridy = 0;
93 lblTheirVersion = new JLabel(tr("Their version"));
94 lblTheirVersion.setToolTipText(tr("Properties in their dataset, i.e. the server dataset"));
95 add(lblTheirVersion, gc);
96 }
97
98 protected void buildCoordinateConflictRows() {
99 GridBagConstraints gc = new GridBagConstraints();
100
101 gc.gridx = 0;
102 gc.gridy = 1;
103 gc.gridwidth = 1;
104 gc.gridheight = 1;
105 gc.fill = GridBagConstraints.HORIZONTAL;
106 gc.anchor = GridBagConstraints.LINE_START;
107 gc.weightx = 0.0;
108 gc.weighty = 0.0;
109 gc.insets = new Insets(0,5,0,5);
110 add(new JLabel(tr("Coordinates:")), gc);
111
112 gc.gridx = 1;
113 gc.gridy = 1;
114 gc.fill = GridBagConstraints.BOTH;
115 gc.anchor = GridBagConstraints.CENTER;
116 gc.weightx = 0.33;
117 gc.weighty = 0.0;
118 add(lblMyCoordinates = buildValueLabel("label.mycoordinates"), gc);
119
120 gc.gridx = 2;
121 gc.gridy = 1;
122 gc.fill = GridBagConstraints.NONE;
123 gc.anchor = GridBagConstraints.CENTER;
124 gc.weightx = 0.0;
125 gc.weighty = 0.0;
126 KeepMyCoordinatesAction actKeepMyCoordinates = new KeepMyCoordinatesAction();
127 model.addObserver(actKeepMyCoordinates);
128 JButton btnKeepMyCoordinates = new JButton(actKeepMyCoordinates);
129 btnKeepMyCoordinates.setName("button.keepmycoordinates");
130 add(btnKeepMyCoordinates, gc);
131
132 gc.gridx = 3;
133 gc.gridy = 1;
134 gc.fill = GridBagConstraints.BOTH;
135 gc.anchor = GridBagConstraints.CENTER;
136 gc.weightx = 0.33;
137 gc.weighty = 0.0;
138 add(lblMergedCoordinates = buildValueLabel("label.mergedcoordinates"), gc);
139
140 gc.gridx = 4;
141 gc.gridy = 1;
142 gc.fill = GridBagConstraints.NONE;
143 gc.anchor = GridBagConstraints.CENTER;
144 gc.weightx = 0.0;
145 gc.weighty = 0.0;
146 KeepTheirCoordinatesAction actKeepTheirCoordinates = new KeepTheirCoordinatesAction();
147 model.addObserver(actKeepTheirCoordinates);
148 JButton btnKeepTheirCoordinates = new JButton(actKeepTheirCoordinates);
149 add(btnKeepTheirCoordinates, gc);
150
151 gc.gridx = 5;
152 gc.gridy = 1;
153 gc.fill = GridBagConstraints.BOTH;
154 gc.anchor = GridBagConstraints.CENTER;
155 gc.weightx = 0.33;
156 gc.weighty = 0.0;
157 add(lblTheirCoordinates = buildValueLabel("label.theircoordinates"), gc);
158
159 // ---------------------------------------------------
160 gc.gridx = 3;
161 gc.gridy = 2;
162 gc.fill = GridBagConstraints.NONE;
163 gc.anchor = GridBagConstraints.CENTER;
164 gc.weightx = 0.0;
165 gc.weighty = 0.0;
166 UndecideCoordinateConflictAction actUndecideCoordinates = new UndecideCoordinateConflictAction();
167 model.addObserver(actUndecideCoordinates);
168 JButton btnUndecideCoordinates = new JButton(actUndecideCoordinates);
169 add(btnUndecideCoordinates, gc);
170 }
171
172 protected void buildDeletedStateConflictRows() {
173 GridBagConstraints gc = new GridBagConstraints();
174
175 gc.gridx = 0;
176 gc.gridy = 3;
177 gc.gridwidth = 1;
178 gc.gridheight = 1;
179 gc.fill = GridBagConstraints.BOTH;
180 gc.anchor = GridBagConstraints.LINE_START;
181 gc.weightx = 0.0;
182 gc.weighty = 0.0;
183 gc.insets = new Insets(0,5,0,5);
184 add(new JLabel(tr("Deleted State:")), gc);
185
186 gc.gridx = 1;
187 gc.gridy = 3;
188 gc.fill = GridBagConstraints.BOTH;
189 gc.anchor = GridBagConstraints.CENTER;
190 gc.weightx = 0.33;
191 gc.weighty = 0.0;
192 add(lblMyDeletedState = buildValueLabel("label.mydeletedstate"), gc);
193
194 gc.gridx = 2;
195 gc.gridy = 3;
196 gc.fill = GridBagConstraints.NONE;
197 gc.anchor = GridBagConstraints.CENTER;
198 gc.weightx = 0.0;
199 gc.weighty = 0.0;
200 KeepMyDeletedStateAction actKeepMyDeletedState = new KeepMyDeletedStateAction();
201 model.addObserver(actKeepMyDeletedState);
202 JButton btnKeepMyDeletedState = new JButton(actKeepMyDeletedState);
203 btnKeepMyDeletedState.setName("button.keepmydeletedstate");
204 add(btnKeepMyDeletedState, gc);
205
206 gc.gridx = 3;
207 gc.gridy = 3;
208 gc.fill = GridBagConstraints.BOTH;
209 gc.anchor = GridBagConstraints.CENTER;
210 gc.weightx = 0.33;
211 gc.weighty = 0.0;
212 add(lblMergedDeletedState = buildValueLabel("label.mergeddeletedstate"), gc);
213
214 gc.gridx = 4;
215 gc.gridy = 3;
216 gc.fill = GridBagConstraints.NONE;
217 gc.anchor = GridBagConstraints.CENTER;
218 gc.weightx = 0.0;
219 gc.weighty = 0.0;
220 KeepTheirDeletedStateAction actKeepTheirDeletedState = new KeepTheirDeletedStateAction();
221 model.addObserver(actKeepTheirDeletedState);
222 JButton btnKeepTheirDeletedState = new JButton(actKeepTheirDeletedState);
223 btnKeepTheirDeletedState.setName("button.keeptheirdeletedstate");
224 add(btnKeepTheirDeletedState, gc);
225
226 gc.gridx = 5;
227 gc.gridy = 3;
228 gc.fill = GridBagConstraints.BOTH;
229 gc.anchor = GridBagConstraints.CENTER;
230 gc.weightx = 0.33;
231 gc.weighty = 0.0;
232 add(lblTheirDeletedState = buildValueLabel("label.theirdeletedstate"), gc);
233
234 // ---------------------------------------------------
235 gc.gridx = 3;
236 gc.gridy = 4;
237 gc.fill = GridBagConstraints.NONE;
238 gc.anchor = GridBagConstraints.CENTER;
239 gc.weightx = 0.0;
240 gc.weighty = 0.0;
241 UndecideDeletedStateConflictAction actUndecideDeletedState = new UndecideDeletedStateConflictAction();
242 model.addObserver(actUndecideDeletedState);
243 JButton btnUndecideDeletedState = new JButton(actUndecideDeletedState);
244 btnUndecideDeletedState.setName("button.undecidedeletedstate");
245 add(btnUndecideDeletedState, gc);
246 }
247
248 protected void buildReferrersRow() {
249 GridBagConstraints gc = new GridBagConstraints();
250
251 gc.gridx = 0;
252 gc.gridy = 7;
253 gc.gridwidth = 1;
254 gc.gridheight = 1;
255 gc.fill = GridBagConstraints.BOTH;
256 gc.anchor = GridBagConstraints.LINE_START;
257 gc.weightx = 0.0;
258 gc.weighty = 0.0;
259 gc.insets = new Insets(0,5,0,5);
260 add(new JLabel(tr("Referenced by:")), gc);
261
262 gc.gridx = 1;
263 gc.gridy = 7;
264 gc.fill = GridBagConstraints.BOTH;
265 gc.anchor = GridBagConstraints.CENTER;
266 gc.weightx = 0.33;
267 gc.weighty = 0.0;
268 add(lblMyReferrers = buildValueLabel("label.myreferrers"), gc);
269
270 gc.gridx = 5;
271 gc.gridy = 7;
272 gc.fill = GridBagConstraints.BOTH;
273 gc.anchor = GridBagConstraints.CENTER;
274 gc.weightx = 0.33;
275 gc.weighty = 0.0;
276 add(lblTheirReferrers = buildValueLabel("label.theirreferrers"), gc);
277 }
278
279 protected void build() {
280 setLayout(new GridBagLayout());
281 buildHeaderRow();
282 buildCoordinateConflictRows();
283 buildDeletedStateConflictRows();
284 buildReferrersRow();
285 }
286
287 public PropertiesMerger() {
288 model = new PropertiesMergeModel();
289 model.addObserver(this);
290 build();
291 }
292
293 public String coordToString(LatLon coord) {
294 if (coord == null)
295 return tr("(none)");
296 StringBuilder sb = new StringBuilder();
297 sb.append("(")
298 .append(COORD_FORMATTER.format(coord.lat()))
299 .append(",")
300 .append(COORD_FORMATTER.format(coord.lon()))
301 .append(")");
302 return sb.toString();
303 }
304
305 public String deletedStateToString(Boolean deleted) {
306 if (deleted == null)
307 return tr("(none)");
308 if (deleted)
309 return tr("deleted");
310 else
311 return tr("not deleted");
312 }
313
314 public String referrersToString(List<OsmPrimitive> referrers) {
315 if (referrers.isEmpty())
316 return tr("(none)");
317 String str = "<html>";
318 for (OsmPrimitive r: referrers) {
319 str = str + r.getDisplayName(DefaultNameFormatter.getInstance()) + "<br>";
320 }
321 str = str + "</html>";
322 return str;
323 }
324
325 protected void updateCoordinates() {
326 lblMyCoordinates.setText(coordToString(model.getMyCoords()));
327 lblMergedCoordinates.setText(coordToString(model.getMergedCoords()));
328 lblTheirCoordinates.setText(coordToString(model.getTheirCoords()));
329 if (! model.hasCoordConflict()) {
330 lblMyCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
331 lblMergedCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
332 lblTheirCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
333 } else {
334 if (!model.isDecidedCoord()) {
335 lblMyCoordinates.setBackground(BGCOLOR_UNDECIDED);
336 lblMergedCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
337 lblTheirCoordinates.setBackground(BGCOLOR_UNDECIDED);
338 } else {
339 lblMyCoordinates.setBackground(
340 model.isCoordMergeDecision(MergeDecisionType.KEEP_MINE)
341 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
342 );
343 lblMergedCoordinates.setBackground(BGCOLOR_DECIDED);
344 lblTheirCoordinates.setBackground(
345 model.isCoordMergeDecision(MergeDecisionType.KEEP_THEIR)
346 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
347 );
348 }
349 }
350 }
351
352 protected void updateDeletedState() {
353 lblMyDeletedState.setText(deletedStateToString(model.getMyDeletedState()));
354 lblMergedDeletedState.setText(deletedStateToString(model.getMergedDeletedState()));
355 lblTheirDeletedState.setText(deletedStateToString(model.getTheirDeletedState()));
356
357 if (! model.hasDeletedStateConflict()) {
358 lblMyDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
359 lblMergedDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
360 lblTheirDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
361 } else {
362 if (!model.isDecidedDeletedState()) {
363 lblMyDeletedState.setBackground(BGCOLOR_UNDECIDED);
364 lblMergedDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
365 lblTheirDeletedState.setBackground(BGCOLOR_UNDECIDED);
366 } else {
367 lblMyDeletedState.setBackground(
368 model.isDeletedStateDecision(MergeDecisionType.KEEP_MINE)
369 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
370 );
371 lblMergedDeletedState.setBackground(BGCOLOR_DECIDED);
372 lblTheirDeletedState.setBackground(
373 model.isDeletedStateDecision(MergeDecisionType.KEEP_THEIR)
374 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
375 );
376 }
377 }
378 }
379
380 protected void updateReferrers() {
381 lblMyReferrers.setText(referrersToString(model.getMyReferrers()));
382 lblMyReferrers.setBackground(BGCOLOR_NO_CONFLICT);
383 lblTheirReferrers.setText(referrersToString(model.getTheirReferrers()));
384 lblTheirReferrers.setBackground(BGCOLOR_NO_CONFLICT);
385 }
386
387 public void update(Observable o, Object arg) {
388 updateCoordinates();
389 updateDeletedState();
390 updateReferrers();
391 }
392
393 public PropertiesMergeModel getModel() {
394 return model;
395 }
396
397 class KeepMyCoordinatesAction extends AbstractAction implements Observer {
398 public KeepMyCoordinatesAction() {
399 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeepmine"));
400 putValue(Action.SHORT_DESCRIPTION, tr("Keep my coordiates"));
401 }
402
403 public void actionPerformed(ActionEvent e) {
404 model.decideCoordsConflict(MergeDecisionType.KEEP_MINE);
405 }
406
407 public void update(Observable o, Object arg) {
408 setEnabled(model.hasCoordConflict() && ! model.isDecidedCoord());
409 }
410 }
411
412 class KeepTheirCoordinatesAction extends AbstractAction implements Observer {
413 public KeepTheirCoordinatesAction() {
414 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeeptheir"));
415 putValue(Action.SHORT_DESCRIPTION, tr("Keep their coordiates"));
416 }
417
418 public void actionPerformed(ActionEvent e) {
419 model.decideCoordsConflict(MergeDecisionType.KEEP_THEIR);
420 }
421
422 public void update(Observable o, Object arg) {
423 setEnabled(model.hasCoordConflict() && ! model.isDecidedCoord());
424 }
425 }
426
427 class UndecideCoordinateConflictAction extends AbstractAction implements Observer {
428 public UndecideCoordinateConflictAction() {
429 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagundecide"));
430 putValue(Action.SHORT_DESCRIPTION, tr("Undecide conflict between different coordinates"));
431 }
432
433 public void actionPerformed(ActionEvent e) {
434 model.decideCoordsConflict(MergeDecisionType.UNDECIDED);
435 }
436
437 public void update(Observable o, Object arg) {
438 setEnabled(model.hasCoordConflict() && model.isDecidedCoord());
439 }
440 }
441
442 class KeepMyDeletedStateAction extends AbstractAction implements Observer {
443 public KeepMyDeletedStateAction() {
444 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeepmine"));
445 putValue(Action.SHORT_DESCRIPTION, tr("Keep my deleted state"));
446 }
447
448 public void actionPerformed(ActionEvent e) {
449 model.decideDeletedStateConflict(MergeDecisionType.KEEP_MINE);
450 }
451
452 public void update(Observable o, Object arg) {
453 setEnabled(model.hasDeletedStateConflict() && ! model.isDecidedDeletedState());
454 }
455 }
456
457 class KeepTheirDeletedStateAction extends AbstractAction implements Observer {
458 public KeepTheirDeletedStateAction() {
459 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeeptheir"));
460 putValue(Action.SHORT_DESCRIPTION, tr("Keep their deleted state"));
461 }
462
463 public void actionPerformed(ActionEvent e) {
464 model.decideDeletedStateConflict(MergeDecisionType.KEEP_THEIR);
465 }
466
467 public void update(Observable o, Object arg) {
468 setEnabled(model.hasDeletedStateConflict() && ! model.isDecidedDeletedState());
469 }
470 }
471
472 class UndecideDeletedStateConflictAction extends AbstractAction implements Observer {
473 public UndecideDeletedStateConflictAction() {
474 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagundecide"));
475 putValue(Action.SHORT_DESCRIPTION, tr("Undecide conflict between deleted state"));
476 }
477
478 public void actionPerformed(ActionEvent e) {
479 model.decideDeletedStateConflict(MergeDecisionType.UNDECIDED);
480 }
481
482 public void update(Observable o, Object arg) {
483 setEnabled(model.hasDeletedStateConflict() && model.isDecidedDeletedState());
484 }
485 }
486
487 public void deletePrimitive(boolean deleted) {
488 if (deleted) {
489 if (model.getMergedCoords() == null) {
490 model.decideCoordsConflict(MergeDecisionType.KEEP_MINE);
491 }
492 } else {
493 model.decideCoordsConflict(MergeDecisionType.UNDECIDED);
494 }
495 }
496
497 public void populate(Conflict<? extends OsmPrimitive> conflict) {
498 model.populate(conflict);
499 }
500}
Note: See TracBrowser for help on using the repository browser.