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

Last change on this file since 6267 was 6267, checked in by Don-vip, 11 years ago

Sonar/FindBugs - Replace singular fields by local variables

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