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

Last change on this file since 4947 was 4363, checked in by stoecker, 13 years ago

use createLayout() in all internal ToggleDialog's

  • Property svn:eol-style set to native
File size: 12.5 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.marktr;
6import static org.openstreetmap.josm.tools.I18n.tr;
7
8import java.awt.Color;
9import java.awt.Graphics;
10import java.awt.Point;
11import java.awt.event.ActionEvent;
12import java.awt.event.KeyEvent;
13import java.awt.event.MouseAdapter;
14import java.awt.event.MouseEvent;
15import java.util.Arrays;
16import java.util.Collection;
17import java.util.Iterator;
18import java.util.LinkedList;
19import java.util.concurrent.CopyOnWriteArrayList;
20
21import javax.swing.AbstractAction;
22import javax.swing.JList;
23import javax.swing.ListModel;
24import javax.swing.ListSelectionModel;
25import javax.swing.event.ListDataEvent;
26import javax.swing.event.ListDataListener;
27import javax.swing.event.ListSelectionEvent;
28import javax.swing.event.ListSelectionListener;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.data.SelectionChangedListener;
32import org.openstreetmap.josm.data.conflict.Conflict;
33import org.openstreetmap.josm.data.conflict.ConflictCollection;
34import org.openstreetmap.josm.data.conflict.IConflictListener;
35import org.openstreetmap.josm.data.osm.DataSet;
36import org.openstreetmap.josm.data.osm.Node;
37import org.openstreetmap.josm.data.osm.OsmPrimitive;
38import org.openstreetmap.josm.data.osm.Relation;
39import org.openstreetmap.josm.data.osm.RelationMember;
40import org.openstreetmap.josm.data.osm.Way;
41import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
42import org.openstreetmap.josm.data.osm.visitor.Visitor;
43import org.openstreetmap.josm.gui.MapView;
44import org.openstreetmap.josm.gui.NavigatableComponent;
45import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
46import org.openstreetmap.josm.gui.SideButton;
47import org.openstreetmap.josm.gui.layer.OsmDataLayer;
48import org.openstreetmap.josm.tools.ImageProvider;
49import org.openstreetmap.josm.tools.Shortcut;
50
51/**
52 * This dialog displays the {@see ConflictCollection} of the active {@see OsmDataLayer} in a toggle
53 * dialog on the right of the main frame.
54 *
55 */
56public final class ConflictDialog extends ToggleDialog implements MapView.EditLayerChangeListener, IConflictListener, SelectionChangedListener{
57
58 static public Color getColor() {
59 return Main.pref.getColor(marktr("conflict"), Color.gray);
60 }
61
62 /** the collection of conflicts displayed by this conflict dialog*/
63 private ConflictCollection conflicts;
64
65 /** the model for the list of conflicts */
66 private ConflictListModel model;
67 /** the list widget for the list of conflicts */
68 private JList lstConflicts;
69
70 private ResolveAction actResolve;
71 private SelectAction actSelect;
72
73 /**
74 * builds the GUI
75 */
76 protected void build() {
77 model = new ConflictListModel();
78
79 lstConflicts = new JList(model);
80 lstConflicts.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
81 lstConflicts.setCellRenderer(new OsmPrimitivRenderer());
82 lstConflicts.addMouseListener(new MouseAdapter(){
83 @Override public void mouseClicked(MouseEvent e) {
84 if (e.getClickCount() >= 2) {
85 resolve();
86 }
87 }
88 });
89 lstConflicts.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
90 public void valueChanged(ListSelectionEvent e) {
91 Main.map.mapView.repaint();
92 }
93 });
94
95 SideButton btnResolve = new SideButton(actResolve = new ResolveAction());
96 lstConflicts.getSelectionModel().addListSelectionListener(actResolve);
97
98 SideButton btnSelect = new SideButton(actSelect = new SelectAction());
99 lstConflicts.getSelectionModel().addListSelectionListener(actSelect);
100
101 createLayout(lstConflicts, true, Arrays.asList(new SideButton[] {
102 btnResolve, btnSelect
103 }));
104 }
105
106 /**
107 * constructor
108 */
109 public ConflictDialog() {
110 super(tr("Conflict"), "conflict", tr("Resolve conflicts."),
111 Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
112
113 build();
114 refreshView();
115 }
116
117 @Override
118 public void showNotify() {
119 DataSet.addSelectionListener(this);
120 MapView.addEditLayerChangeListener(this, true);
121 refreshView();
122 }
123
124 @Override
125 public void hideNotify() {
126 MapView.removeEditLayerChangeListener(this);
127 DataSet.removeSelectionListener(this);
128 }
129
130 /**
131 * Launches a conflict resolution dialog for the first selected conflict
132 *
133 */
134 private final void resolve() {
135 if (conflicts == null || model.getSize() == 0) return;
136
137 int index = lstConflicts.getSelectedIndex();
138 if (index < 0) {
139 index = 0;
140 }
141
142 Conflict<? extends OsmPrimitive> c = conflicts.get(index);
143 ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);
144 dialog.getConflictResolver().populate(c);
145 dialog.setVisible(true);
146
147 lstConflicts.setSelectedIndex(index);
148
149 Main.map.mapView.repaint();
150 }
151
152 /**
153 * refreshes the view of this dialog
154 */
155 public final void refreshView() {
156 OsmDataLayer editLayer = Main.main.getEditLayer();
157 conflicts = editLayer == null?new ConflictCollection():editLayer.getConflicts();
158 model.fireContentChanged();
159 updateTitle(conflicts.size());
160 }
161
162 private void updateTitle(int conflictsCount) {
163 if (conflictsCount > 0) {
164 setTitle(tr("Conflicts: {0} unresolved", conflicts.size()));
165 } else {
166 setTitle(tr("Conflict"));
167 }
168 }
169
170 /**
171 * Paint all conflicts that can be expressed on the main window.
172 */
173 public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
174 Color preferencesColor = getColor();
175 if (preferencesColor.equals(Main.pref.getColor(marktr("background"), Color.black)))
176 return;
177 g.setColor(preferencesColor);
178 Visitor conflictPainter = new AbstractVisitor(){
179 public void visit(Node n) {
180 Point p = nc.getPoint(n);
181 g.drawRect(p.x-1, p.y-1, 2, 2);
182 }
183 public void visit(Node n1, Node n2) {
184 Point p1 = nc.getPoint(n1);
185 Point p2 = nc.getPoint(n2);
186 g.drawLine(p1.x, p1.y, p2.x, p2.y);
187 }
188 public void visit(Way w) {
189 Node lastN = null;
190 for (Node n : w.getNodes()) {
191 if (lastN == null) {
192 lastN = n;
193 continue;
194 }
195 visit(lastN, n);
196 lastN = n;
197 }
198 }
199 public void visit(Relation e) {
200 for (RelationMember em : e.getMembers()) {
201 em.getMember().visit(this);
202 }
203 }
204 };
205 for (Object o : lstConflicts.getSelectedValues()) {
206 if (conflicts == null || !conflicts.hasConflictForMy((OsmPrimitive)o)) {
207 continue;
208 }
209 conflicts.getConflictForMy((OsmPrimitive)o).getTheir().visit(conflictPainter);
210 }
211 }
212
213 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
214 if (oldLayer != null) {
215 oldLayer.getConflicts().removeConflictListener(this);
216 }
217 if (newLayer != null) {
218 newLayer.getConflicts().addConflictListener(this);
219 }
220 refreshView();
221 }
222
223
224 /**
225 * replies the conflict collection currently held by this dialog; may be null
226 *
227 * @return the conflict collection currently held by this dialog; may be null
228 */
229 public ConflictCollection getConflicts() {
230 return conflicts;
231 }
232
233 /**
234 * returns the first selected item of the conflicts list
235 *
236 * @return Conflict
237 */
238 public Conflict<? extends OsmPrimitive> getSelectedConflict() {
239 if (conflicts == null || model.getSize() == 0) return null;
240
241 int index = lstConflicts.getSelectedIndex();
242 if (index < 0) return null;
243
244 return conflicts.get(index);
245 }
246
247 public void onConflictsAdded(ConflictCollection conflicts) {
248 refreshView();
249 }
250
251 public void onConflictsRemoved(ConflictCollection conflicts) {
252 System.err.println("1 conflict has been resolved.");
253 refreshView();
254 }
255
256 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
257 lstConflicts.clearSelection();
258 for (OsmPrimitive osm : newSelection) {
259 if (conflicts != null && conflicts.hasConflictForMy(osm)) {
260 int pos = model.indexOf(osm);
261 if (pos >= 0) {
262 lstConflicts.addSelectionInterval(pos, pos);
263 }
264 }
265 }
266 }
267
268 @Override
269 public String helpTopic() {
270 return ht("/Dialog/ConflictList");
271 }
272
273 /**
274 * The {@see ListModel} for conflicts
275 *
276 */
277 class ConflictListModel implements ListModel {
278
279 private CopyOnWriteArrayList<ListDataListener> listeners;
280
281 public ConflictListModel() {
282 listeners = new CopyOnWriteArrayList<ListDataListener>();
283 }
284
285 public void addListDataListener(ListDataListener l) {
286 if (l != null) {
287 listeners.addIfAbsent(l);
288 }
289 }
290
291 public void removeListDataListener(ListDataListener l) {
292 listeners.remove(l);
293 }
294
295 protected void fireContentChanged() {
296 ListDataEvent evt = new ListDataEvent(
297 this,
298 ListDataEvent.CONTENTS_CHANGED,
299 0,
300 getSize()
301 );
302 Iterator<ListDataListener> it = listeners.iterator();
303 while(it.hasNext()) {
304 it.next().contentsChanged(evt);
305 }
306 }
307
308 public Object getElementAt(int index) {
309 if (index < 0) return null;
310 if (index >= getSize()) return null;
311 return conflicts.get(index).getMy();
312 }
313
314 public int getSize() {
315 if (conflicts == null) return 0;
316 return conflicts.size();
317 }
318
319 public int indexOf(OsmPrimitive my) {
320 if (conflicts == null) return -1;
321 for (int i=0; i < conflicts.size();i++) {
322 if (conflicts.get(i).isMatchingMy(my))
323 return i;
324 }
325 return -1;
326 }
327
328 public OsmPrimitive get(int idx) {
329 if (conflicts == null) return null;
330 return conflicts.get(idx).getMy();
331 }
332 }
333
334 class ResolveAction extends AbstractAction implements ListSelectionListener {
335 public ResolveAction() {
336 putValue(NAME, tr("Resolve"));
337 putValue(SHORT_DESCRIPTION, tr("Open a merge dialog of all selected items in the list above."));
338 putValue(SMALL_ICON, ImageProvider.get("dialogs", "conflict"));
339 putValue("help", ht("/Dialog/ConflictList#ResolveAction"));
340 }
341
342 public void actionPerformed(ActionEvent e) {
343 resolve();
344 }
345
346 public void valueChanged(ListSelectionEvent e) {
347 ListSelectionModel model = (ListSelectionModel)e.getSource();
348 boolean enabled = model.getMinSelectionIndex() >= 0
349 && model.getMaxSelectionIndex() >= model.getMinSelectionIndex();
350 setEnabled(enabled);
351 }
352 }
353
354 class SelectAction extends AbstractAction implements ListSelectionListener {
355 public SelectAction() {
356 putValue(NAME, tr("Select"));
357 putValue(SHORT_DESCRIPTION, tr("Set the selected elements on the map to the selected items in the list above."));
358 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
359 putValue("help", ht("/Dialog/ConflictList#SelectAction"));
360 }
361
362 public void actionPerformed(ActionEvent e) {
363 Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
364 for (Object o : lstConflicts.getSelectedValues()) {
365 sel.add((OsmPrimitive)o);
366 }
367 Main.main.getCurrentDataSet().setSelected(sel);
368 }
369
370 public void valueChanged(ListSelectionEvent e) {
371 ListSelectionModel model = (ListSelectionModel)e.getSource();
372 boolean enabled = model.getMinSelectionIndex() >= 0
373 && model.getMaxSelectionIndex() >= model.getMinSelectionIndex();
374 setEnabled(enabled);
375 }
376 }
377
378}
Note: See TracBrowser for help on using the repository browser.