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

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

added merge support for coordinate conflicts
added merge support for conflicts due to different deleted states

File size: 16.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.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.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.coor.LatLon;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.gui.conflict.MergeDecisionType;
25import org.openstreetmap.josm.tools.ImageProvider;
26
27/**
28 * This class represents a UI component for resolving conflicts in some properties
29 * of {@see OsmPrimitive}.
30 *
31 */
32public class PropertiesMerger extends JPanel implements Observer {
33 private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
34
35 public final static Color BGCOLOR_NO_CONFLICT = new Color(234,234,234);
36 public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
37 public final static Color BGCOLOR_DECIDED = new Color(217,255,217);
38
39 private JLabel lblMyVersion;
40 private JLabel lblMergedVersion;
41 private JLabel lblTheirVersion;
42
43 private JLabel lblMyCoordinates;
44 private JLabel lblMergedCoordinates;
45 private JLabel lblTheirCoordinates;
46
47 private JLabel lblMyDeletedState;
48 private JLabel lblMergedDeletedState;
49 private JLabel lblTheirDeletedState;
50
51 private final PropertiesMergeModel model;
52
53 protected JLabel buildValueLabel(String name) {
54 JLabel lbl = new JLabel();
55 lbl.setName(name);
56 lbl.setHorizontalAlignment(JLabel.CENTER);
57 lbl.setOpaque(true);
58 lbl.setBorder(BorderFactory.createLoweredBevelBorder());
59 return lbl;
60 }
61
62 protected void build() {
63 setLayout(new GridBagLayout());
64 GridBagConstraints gc = new GridBagConstraints();
65
66 // ------------------
67 gc.gridx = 1;
68 gc.gridy = 0;
69 gc.gridwidth = 1;
70 gc.gridheight = 1;
71 gc.fill = GridBagConstraints.NONE;
72 gc.anchor = GridBagConstraints.CENTER;
73 gc.weightx = 0.0;
74 gc.weighty = 0.0;
75 gc.insets = new Insets(10,0,10,0);
76 lblMyVersion = new JLabel(tr("My version"));
77 lblMyVersion.setToolTipText(tr("Properties in my dataset, i.e. the local dataset"));
78 add(lblMyVersion, gc);
79
80 gc.gridx = 3;
81 gc.gridy = 0;
82 lblMergedVersion = new JLabel(tr("Merged version"));
83 lblMergedVersion.setToolTipText(tr("Properties in the merged element. They will replace properties in my elements when merge decisions are applied."));
84 add(lblMergedVersion, gc);
85
86 gc.gridx = 5;
87 gc.gridy = 0;
88 lblTheirVersion = new JLabel(tr("Their version"));
89 lblTheirVersion.setToolTipText(tr("Properties in their dataset, i.e. the server dataset"));
90 add(lblTheirVersion, gc);
91
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
125 gc.gridx = 3;
126 gc.gridy = 1;
127 gc.fill = GridBagConstraints.BOTH;
128 gc.anchor = GridBagConstraints.CENTER;
129 gc.weightx = 0.33;
130 gc.weighty = 0.0;
131 add(lblMergedCoordinates = buildValueLabel("label.mergedcoordinates"), gc);
132
133 gc.gridx = 4;
134 gc.gridy = 1;
135 gc.fill = GridBagConstraints.NONE;
136 gc.anchor = GridBagConstraints.CENTER;
137 gc.weightx = 0.0;
138 gc.weighty = 0.0;
139 KeepTheirCoordinatesAction actKeepTheirCoordinates = new KeepTheirCoordinatesAction();
140 model.addObserver(actKeepTheirCoordinates);
141 JButton btnKeepTheirCoordinates = new JButton(actKeepTheirCoordinates);
142 add(btnKeepTheirCoordinates, gc);
143
144 gc.gridx = 5;
145 gc.gridy = 1;
146 gc.fill = GridBagConstraints.BOTH;
147 gc.anchor = GridBagConstraints.CENTER;
148 gc.weightx = 0.33;
149 gc.weighty = 0.0;
150 add(lblTheirCoordinates = buildValueLabel("label.theircoordinates"), gc);
151
152 // ---------------------------------------------------
153 gc.gridx = 3;
154 gc.gridy = 2;
155 gc.fill = GridBagConstraints.NONE;
156 gc.anchor = GridBagConstraints.CENTER;
157 gc.weightx = 0.0;
158 gc.weighty = 0.0;
159 gc.insets = new Insets(0,5,20,5);
160 UndecideCoordinateConflictAction actUndecideCoordinates = new UndecideCoordinateConflictAction();
161 model.addObserver(actUndecideCoordinates);
162 JButton btnUndecideCoordinates = new JButton(actUndecideCoordinates);
163 add(btnUndecideCoordinates, gc);
164 // ---------------------------------------------------
165
166 gc.gridx = 0;
167 gc.gridy = 3;
168 gc.gridwidth = 1;
169 gc.gridheight = 1;
170 gc.fill = GridBagConstraints.BOTH;
171 gc.anchor = GridBagConstraints.LINE_START;
172 gc.weightx = 0.0;
173 gc.weighty = 0.0;
174 gc.insets = new Insets(0,5,0,5);
175 add(new JLabel(tr("Deleted State:")), gc);
176
177 gc.gridx = 1;
178 gc.gridy = 3;
179 gc.fill = GridBagConstraints.BOTH;
180 gc.anchor = GridBagConstraints.CENTER;
181 gc.weightx = 0.33;
182 gc.weighty = 0.0;
183 add(lblMyDeletedState = buildValueLabel("label.mydeletedstate"), gc);
184
185 gc.gridx = 2;
186 gc.gridy = 3;
187 gc.fill = GridBagConstraints.NONE;
188 gc.anchor = GridBagConstraints.CENTER;
189 gc.weightx = 0.0;
190 gc.weighty = 0.0;
191 KeepMyDeletedStateAction actKeepMyDeletedState = new KeepMyDeletedStateAction();
192 model.addObserver(actKeepMyDeletedState);
193 JButton btnKeepMyDeletedState = new JButton(actKeepMyDeletedState);
194 btnKeepMyCoordinates.setName("button.keepmydeletedstate");
195 add(btnKeepMyDeletedState, gc);
196
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 btnKeepMyCoordinates.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 btnKeepMyCoordinates.setName("button.undecidedeletedstate");
237 add(btnUndecideDeletedState, gc);
238
239 }
240
241 public PropertiesMerger() {
242 model = new PropertiesMergeModel();
243 model.addObserver(this);
244 build();
245 }
246
247 public String coordToString(LatLon coord) {
248 if (coord == null)
249 return tr("(none)");
250 StringBuilder sb = new StringBuilder();
251 sb.append("(")
252 .append(COORD_FORMATTER.format(coord.lat()))
253 .append(",")
254 .append(COORD_FORMATTER.format(coord.lon()))
255 .append(")");
256 return sb.toString();
257 }
258
259 public String deletedStateToString(Boolean deleted) {
260 if (deleted == null)
261 return tr("(none)");
262 if (deleted)
263 return tr("deleted");
264 else
265 return tr("not deleted");
266 }
267
268 protected void updateCoordiates() {
269 lblMyCoordinates.setText(coordToString(model.getMyCoords()));
270 lblMergedCoordinates.setText(coordToString(model.getMergedCoords()));
271 lblTheirCoordinates.setText(coordToString(model.getTheirCoords()));
272 if (! model.hasCoordConflict()) {
273 lblMyCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
274 lblMergedCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
275 lblTheirCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
276 } else {
277 if (!model.isDecidedCoord()) {
278 lblMyCoordinates.setBackground(BGCOLOR_UNDECIDED);
279 lblMergedCoordinates.setBackground(BGCOLOR_NO_CONFLICT);
280 lblTheirCoordinates.setBackground(BGCOLOR_UNDECIDED);
281 } else {
282 lblMyCoordinates.setBackground(
283 model.isCoordMergeDecision(MergeDecisionType.KEEP_MINE)
284 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
285 );
286 lblMergedCoordinates.setBackground(BGCOLOR_DECIDED);
287 lblTheirCoordinates.setBackground(
288 model.isCoordMergeDecision(MergeDecisionType.KEEP_THEIR)
289 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
290 );
291 }
292 }
293 }
294
295 protected void updateDeletedState() {
296 lblMyDeletedState.setText(deletedStateToString(model.getMyDeletedState()));
297 lblMergedDeletedState.setText(deletedStateToString(model.getMergedDeletedState()));
298 lblTheirDeletedState.setText(deletedStateToString(model.getTheirDeletedState()));
299
300 if (! model.hasDeletedStateConflict()) {
301 lblMyDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
302 lblMergedDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
303 lblTheirDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
304 } else {
305 if (!model.isDecidedDeletedState()) {
306 lblMyDeletedState.setBackground(BGCOLOR_UNDECIDED);
307 lblMergedDeletedState.setBackground(BGCOLOR_NO_CONFLICT);
308 lblTheirDeletedState.setBackground(BGCOLOR_UNDECIDED);
309 } else {
310 lblMyDeletedState.setBackground(
311 model.isDeletedStateDecision(MergeDecisionType.KEEP_MINE)
312 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
313 );
314 lblMergedDeletedState.setBackground(BGCOLOR_DECIDED);
315 lblTheirDeletedState.setBackground(
316 model.isDeletedStateDecision(MergeDecisionType.KEEP_THEIR)
317 ? BGCOLOR_DECIDED : BGCOLOR_NO_CONFLICT
318 );
319 }
320 }
321 }
322
323 public void update(Observable o, Object arg) {
324 updateCoordiates();
325 updateDeletedState();
326 }
327
328 public PropertiesMergeModel getModel() {
329 return model;
330 }
331
332 class KeepMyCoordinatesAction extends AbstractAction implements Observer {
333 public KeepMyCoordinatesAction() {
334 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeepmine"));
335 putValue(Action.SHORT_DESCRIPTION, tr("Keep my coordiates"));
336 }
337
338 public void actionPerformed(ActionEvent e) {
339 model.decideCoordsConflict(MergeDecisionType.KEEP_MINE);
340 }
341
342 public void update(Observable o, Object arg) {
343 setEnabled(model.hasCoordConflict() && ! model.isDecidedCoord());
344 }
345 }
346
347 class KeepTheirCoordinatesAction extends AbstractAction implements Observer {
348 public KeepTheirCoordinatesAction() {
349 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeeptheir"));
350 putValue(Action.SHORT_DESCRIPTION, tr("Keep their coordiates"));
351 }
352
353 public void actionPerformed(ActionEvent e) {
354 model.decideCoordsConflict(MergeDecisionType.KEEP_THEIR);
355 }
356
357 public void update(Observable o, Object arg) {
358 setEnabled(model.hasCoordConflict() && ! model.isDecidedCoord());
359 }
360 }
361
362 class UndecideCoordinateConflictAction extends AbstractAction implements Observer {
363 public UndecideCoordinateConflictAction() {
364 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagundecide"));
365 putValue(Action.SHORT_DESCRIPTION, tr("Undecide conflict between different coordinates"));
366 }
367
368 public void actionPerformed(ActionEvent e) {
369 model.decideCoordsConflict(MergeDecisionType.UNDECIDED);
370 }
371
372 public void update(Observable o, Object arg) {
373 setEnabled(model.hasCoordConflict() && model.isDecidedCoord());
374 }
375 }
376
377 class KeepMyDeletedStateAction extends AbstractAction implements Observer {
378 public KeepMyDeletedStateAction() {
379 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeepmine"));
380 putValue(Action.SHORT_DESCRIPTION, tr("Keep my deleted state"));
381 }
382
383 public void actionPerformed(ActionEvent e) {
384 model.decideDeletedStateConflict(MergeDecisionType.KEEP_MINE);
385 }
386
387 public void update(Observable o, Object arg) {
388 setEnabled(model.hasDeletedStateConflict() && ! model.isDecidedDeletedState());
389 }
390 }
391
392 class KeepTheirDeletedStateAction extends AbstractAction implements Observer {
393 public KeepTheirDeletedStateAction() {
394 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagkeeptheir"));
395 putValue(Action.SHORT_DESCRIPTION, tr("Keep their deleted state"));
396 }
397
398 public void actionPerformed(ActionEvent e) {
399 model.decideDeletedStateConflict(MergeDecisionType.KEEP_THEIR);
400 }
401
402 public void update(Observable o, Object arg) {
403 setEnabled(model.hasDeletedStateConflict() && ! model.isDecidedDeletedState());
404 }
405 }
406
407 class UndecideDeletedStateConflictAction extends AbstractAction implements Observer {
408 public UndecideDeletedStateConflictAction() {
409 putValue(Action.SMALL_ICON, ImageProvider.get("dialogs/conflict", "tagundecide"));
410 putValue(Action.SHORT_DESCRIPTION, tr("Undecide conflict between deleted state"));
411 }
412
413 public void actionPerformed(ActionEvent e) {
414 model.decideDeletedStateConflict(MergeDecisionType.UNDECIDED);
415 }
416
417 public void update(Observable o, Object arg) {
418 setEnabled(model.hasDeletedStateConflict() && model.isDecidedDeletedState());
419 }
420 }
421}
Note: See TracBrowser for help on using the repository browser.