source: josm/src/org/openstreetmap/josm/gui/ConflictResolver.java@ 104

Last change on this file since 104 was 104, checked in by imi, 18 years ago
  • started i18n
  • started "download incomplete ways" action
  • added straight line selection mode
File size: 9.9 KB
Line 
1package org.openstreetmap.josm.gui;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4import static org.openstreetmap.josm.tools.I18n.trn;
5
6import java.awt.Component;
7import java.awt.Dimension;
8import java.awt.Font;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Iterator;
17import java.util.List;
18import java.util.Map;
19import java.util.TreeSet;
20import java.util.Map.Entry;
21
22import javax.swing.AbstractAction;
23import javax.swing.JButton;
24import javax.swing.JLabel;
25import javax.swing.JPanel;
26import javax.swing.JScrollPane;
27import javax.swing.JTable;
28import javax.swing.ListSelectionModel;
29import javax.swing.event.ListSelectionEvent;
30import javax.swing.event.ListSelectionListener;
31import javax.swing.event.TableModelListener;
32import javax.swing.table.DefaultTableCellRenderer;
33import javax.swing.table.TableCellRenderer;
34import javax.swing.table.TableModel;
35
36import org.openstreetmap.josm.data.conflict.ConflictItem;
37import org.openstreetmap.josm.data.conflict.DeleteConflict;
38import org.openstreetmap.josm.data.conflict.FromConflict;
39import org.openstreetmap.josm.data.conflict.PositionConflict;
40import org.openstreetmap.josm.data.conflict.PropertyConflict;
41import org.openstreetmap.josm.data.conflict.SegmentConflict;
42import org.openstreetmap.josm.data.conflict.ToConflict;
43import org.openstreetmap.josm.data.osm.OsmPrimitive;
44import org.openstreetmap.josm.tools.GBC;
45import org.openstreetmap.josm.tools.ImageProvider;
46
47/**
48 * A panel which implement the conflict resolving of a set of primitive-pairs. There will be
49 * three tables in the screen, one for each both sides and one resulting table. The user can
50 * move items from either one of the sides ("my" and "their") to the resulting table.
51 *
52 * @author Imi
53 */
54public class ConflictResolver extends JPanel {
55
56 public static enum Resolution {MY, THEIR}
57
58 private final class ConflictTableModel implements TableModel {
59 private final Resolution resolution;
60 public ConflictTableModel(Resolution resolution) {
61 this.resolution = resolution;
62 }
63
64 public int getRowCount() {
65 return conflicts.size();
66 }
67
68 public Object getValueAt(int rowIndex, int columnIndex) {
69 ConflictItem ci = conflicts.get(rowIndex);
70 if (columnIndex == 0)
71 return ci.key();
72 Resolution r = resolution == null ? ci.resolution : resolution;
73 if (r == null)
74 return "<html><i>???</i></html>";
75 JLabel l = new JLabel(r == Resolution.MY ? ci.my : ci.their);
76 if (ci.resolution == resolution && resolution != null)
77 l.setFont(l.getFont().deriveFont(Font.BOLD));
78 return l;
79 }
80
81 public String getColumnName(int columnIndex) {return columnIndex == 0 ? tr("Key") : tr("Value");}
82 public int getColumnCount() {return 2;}
83 public boolean isCellEditable(int row, int column) {return false;}
84 public Class<?> getColumnClass(int columnIndex) {return Object.class;}
85
86 public void addTableModelListener(TableModelListener l) {}
87 public void removeTableModelListener(TableModelListener l) {}
88 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {}
89 }
90
91 private final class DblClickListener extends MouseAdapter {
92 private final Resolution resolution;
93 public DblClickListener(Resolution resolution) {
94 this.resolution = resolution;
95 }
96 @Override public void mouseClicked(MouseEvent e) {
97 if (e.getClickCount() >= 2) {
98 int sel = ((JTable)e.getSource()).getSelectedRow();
99 if (sel == -1)
100 return;
101 ConflictResolver.this.conflicts.get(sel).resolution = resolution;
102 repaint();
103 }
104 }
105 }
106 private final class ResolveAction extends AbstractAction {
107 private final Resolution resolution;
108 public ResolveAction(String name, Resolution resolution) {
109 super(null, ImageProvider.get("dialogs", name));
110 this.resolution = resolution;
111 }
112 public void actionPerformed(ActionEvent e) {
113 int sel = myTable.getSelectedRow();
114 if (sel == -1)
115 return;
116 conflicts.get(sel).resolution = resolution;
117 if (sel == myTable.getRowCount()-1)
118 myTable.clearSelection();
119 else
120 myTable.getSelectionModel().setSelectionInterval(sel+1, sel+1);
121 repaint();
122 }
123 }
124
125 public final List<ConflictItem> conflicts = new ArrayList<ConflictItem>();
126
127 private final ConflictTableModel my = new ConflictTableModel(Resolution.MY);
128 private final JTable myTable;
129 private final ConflictTableModel their = new ConflictTableModel(Resolution.THEIR);
130 private final JTable theirTable;
131 private final ConflictTableModel resolve = new ConflictTableModel(null);
132 private final JTable resolveTable;
133
134
135 public ConflictResolver(Map<OsmPrimitive, OsmPrimitive> conflicts) {
136 super(new GridBagLayout());
137 Collection<ConflictItem> possibleConflicts = new ArrayList<ConflictItem>();
138 possibleConflicts.add(new DeleteConflict());
139 possibleConflicts.add(new PositionConflict());
140 possibleConflicts.add(new FromConflict());
141 possibleConflicts.add(new ToConflict());
142 possibleConflicts.add(new SegmentConflict());
143 TreeSet<String> allkeys = new TreeSet<String>();
144 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
145 allkeys.addAll(e.getKey().keySet());
146 allkeys.addAll(e.getValue().keySet());
147 }
148 for (String s : allkeys)
149 possibleConflicts.add(new PropertyConflict(s));
150
151 for (Entry<OsmPrimitive, OsmPrimitive> e : conflicts.entrySet()) {
152 for (Iterator<ConflictItem> it = possibleConflicts.iterator(); it.hasNext();) {
153 ConflictItem ci = it.next();
154 if (ci.hasConflict(e.getKey(), e.getValue())) {
155 ci.initialize(conflicts);
156 this.conflicts.add(ci);
157 it.remove();
158 }
159 }
160 }
161
162 if (this.conflicts.isEmpty())
163 throw new RuntimeException(tr("No conflicts but in conflict list:\n{0}" , Arrays.toString(conflicts.entrySet().toArray())));
164
165 // have to initialize the JTables here and not in the declaration, because its constructor
166 // may access this.conflicts (indirectly)
167 myTable = new JTable(my);
168 theirTable = new JTable(their);
169 resolveTable = new JTable(resolve);
170
171 myTable.setPreferredScrollableViewportSize(new Dimension(250,70));
172 theirTable.setPreferredScrollableViewportSize(new Dimension(250,70));
173 resolveTable.setPreferredScrollableViewportSize(new Dimension(250,70));
174
175 TableCellRenderer renderer = new DefaultTableCellRenderer(){
176 final Font defFont = new JLabel().getFont();
177 @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
178 JLabel c = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
179 c.setIcon(null);
180 c.setFont(defFont);
181 if (value instanceof JLabel) {
182 JLabel l = (JLabel)value;
183 String text = l.getText();
184 c.setText(text);
185 c.setFont(l.getFont());
186 if (text.startsWith("<html>") && l.getFont().isBold())
187 c.setText("<html>"+"<b>"+text.substring(6, text.length()-12));
188 } else {
189 String s = value.toString();
190 int i = s.indexOf('|');
191 if (i != -1) {
192 c.setIcon(ImageProvider.get("data", s.substring(0,i)));
193 c.setText(s.substring(i+1));
194 }
195 }
196 return c;
197 }
198 };
199 myTable.setDefaultRenderer(Object.class, renderer);
200 theirTable.setDefaultRenderer(Object.class, renderer);
201 resolveTable.setDefaultRenderer(Object.class, renderer);
202
203 myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
204 theirTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
205 resolveTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
206 ListSelectionListener selListener = new ListSelectionListener(){
207 public void valueChanged(ListSelectionEvent e) {
208 if (((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
209 myTable.clearSelection();
210 theirTable.clearSelection();
211 resolveTable.clearSelection();
212 } else {
213 int i = ((ListSelectionModel)e.getSource()).getMinSelectionIndex();
214 myTable.scrollRectToVisible(myTable.getCellRect(i, 0, true));
215 myTable.getSelectionModel().setSelectionInterval(i, i);
216 theirTable.scrollRectToVisible(theirTable.getCellRect(i, 0, true));
217 theirTable.getSelectionModel().setSelectionInterval(i, i);
218 resolveTable.scrollRectToVisible(resolveTable.getCellRect(i, 0, true));
219 resolveTable.getSelectionModel().setSelectionInterval(i, i);
220 }
221 }
222 };
223 myTable.getSelectionModel().addListSelectionListener(selListener);
224 theirTable.getSelectionModel().addListSelectionListener(selListener);
225 resolveTable.getSelectionModel().addListSelectionListener(selListener);
226 myTable.getSelectionModel().setSelectionInterval(0,0);
227
228 myTable.addMouseListener(new DblClickListener(Resolution.MY));
229 theirTable.addMouseListener(new DblClickListener(Resolution.THEIR));
230 resolveTable.addMouseListener(new DblClickListener(null));
231
232 add(new JLabel(trn("{0} object has conflicts:","{0} objects have conflicts:",conflicts.size(),conflicts.size())), GBC.eol().insets(0,0,0,10));
233
234 JPanel p = new JPanel(new GridBagLayout());
235 p.add(new JLabel(tr("my version:")), GBC.eol());
236 p.add(new JScrollPane(myTable), GBC.eol().fill(GBC.BOTH));
237 p.add(new JButton(new ResolveAction("down", Resolution.MY)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
238 add(p, GBC.std().insets(0,0,5,0));
239
240 p = new JPanel(new GridBagLayout());
241 p.add(new JLabel(tr("their version:")), GBC.eol());
242 p.add(new JScrollPane(theirTable), GBC.eol().fill(GBC.BOTH));
243 p.add(new JButton(new ResolveAction("down", Resolution.THEIR)), GBC.eol().anchor(GBC.CENTER).insets(0,5,0,0));
244 add(p, GBC.eop().insets(5,0,0,0));
245
246 add(new JButton(new ResolveAction("up", null)), GBC.eol().anchor(GBC.CENTER));
247 add(new JLabel(tr("resolved version:")), GBC.eol().insets(0,5,0,0));
248 add(new JScrollPane(resolveTable), GBC.eol().anchor(GBC.CENTER).fill(GBC.BOTH));
249 }
250}
Note: See TracBrowser for help on using the repository browser.