source: josm/src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java@ 36

Last change on this file since 36 was 36, checked in by imi, 18 years ago

added Mercator projection

File size: 11.0 KB
Line 
1package org.openstreetmap.josm.gui.dialogs;
2
3import java.awt.BorderLayout;
4import java.awt.Component;
5import java.awt.Dimension;
6import java.awt.Font;
7import java.awt.GridLayout;
8import java.awt.event.ActionEvent;
9import java.awt.event.ActionListener;
10import java.awt.event.KeyEvent;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
13import java.awt.event.WindowEvent;
14import java.awt.event.WindowFocusListener;
15import java.util.Collection;
16import java.util.HashMap;
17import java.util.Iterator;
18import java.util.TreeMap;
19import java.util.TreeSet;
20import java.util.Vector;
21import java.util.Map.Entry;
22
23import javax.swing.JButton;
24import javax.swing.JComboBox;
25import javax.swing.JDialog;
26import javax.swing.JLabel;
27import javax.swing.JOptionPane;
28import javax.swing.JPanel;
29import javax.swing.JScrollPane;
30import javax.swing.JTable;
31import javax.swing.JTextField;
32import javax.swing.ListSelectionModel;
33import javax.swing.table.DefaultTableCellRenderer;
34import javax.swing.table.DefaultTableModel;
35
36import org.openstreetmap.josm.Main;
37import org.openstreetmap.josm.command.ChangeKeyValueCommand;
38import org.openstreetmap.josm.data.SelectionChangedListener;
39import org.openstreetmap.josm.data.osm.Key;
40import org.openstreetmap.josm.data.osm.OsmPrimitive;
41import org.openstreetmap.josm.gui.ImageProvider;
42import org.openstreetmap.josm.gui.MapFrame;
43import org.openstreetmap.josm.gui.MapView;
44
45/**
46 * This dialog displays the properties of the current selected primitives.
47 *
48 * If no object is selected, the dialog list is empty.
49 * If only one is selected, all properties of this object are selected.
50 * If more than one object are selected, the sum of all properties are displayed. If the
51 * different objects share the same property, the shared value is displayed. If they have
52 * different values, all of them are put in a combo box and the string "<different>"
53 * is displayed in italic.
54 *
55 * Below the list, the user can click on an add, modify and delete property button to
56 * edit the table selection value.
57 *
58 * The command is applied to all selected entries.
59 *
60 * @author imi
61 */
62public class PropertiesDialog extends ToggleDialog implements SelectionChangedListener {
63
64 /**
65 * Watches for double clicks and start editing or new property, depending on the
66 * location, the click was.
67 * @author imi
68 */
69 public class DblClickWatch extends MouseAdapter {
70 @Override
71 public void mouseClicked(MouseEvent e) {
72 if (e.getClickCount() < 2)
73 return;
74 if (e.getSource() instanceof JScrollPane)
75 add();
76 else {
77 int row = propertyTable.rowAtPoint(e.getPoint());
78 edit(row);
79 }
80 }
81 }
82
83 /**
84 * Edit the value in the table row
85 * @param row The row of the table, from which the value is edited.
86 */
87 void edit(int row) {
88 String key = data.getValueAt(row, 0).toString();
89 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
90 String msg = "<html>This will change "+sel.size()+" object"+(sel.size()==1?"":"s")+".<br><br>"+
91 "Please select a new value for '"+key+"'.<br>(Empty string deletes the key.)";
92 final JComboBox combo = (JComboBox)data.getValueAt(row, 1);
93 JPanel p = new JPanel(new BorderLayout());
94 p.add(new JLabel(msg+"</html>"), BorderLayout.NORTH);
95 p.add(combo, BorderLayout.CENTER);
96
97 final JOptionPane optionPane = new JOptionPane(p, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
98 final JDialog dlg = optionPane.createDialog(Main.main, "Change values?");
99 dlg.addWindowFocusListener(new WindowFocusListener(){
100 public void windowGainedFocus(WindowEvent e) {
101 combo.requestFocusInWindow();
102 }
103 public void windowLostFocus(WindowEvent e) {
104 }
105 });
106 combo.getEditor().addActionListener(new ActionListener(){
107 public void actionPerformed(ActionEvent e) {
108 optionPane.setValue(JOptionPane.OK_OPTION);
109 dlg.setVisible(false);
110 }
111 });
112 String oldComboEntry = combo.getEditor().getItem().toString();
113 dlg.setVisible(true);
114
115 Object answer = optionPane.getValue();
116 if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
117 (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
118 combo.getEditor().setItem(oldComboEntry);
119 return;
120 }
121
122 String value = combo.getEditor().getItem().toString();
123 if (value.equals("<different>"))
124 return;
125 if (value.equals(""))
126 value = null; // delete the key
127 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), value));
128
129 if (value == null)
130 selectionChanged(sel); // update whole table
131 else
132 PropertiesDialog.this.repaint(); // repaint is enough
133 }
134
135 /**
136 * Open the add selection dialog and add a new key/value to the table (and to the
137 * dataset, of course).
138 */
139 void add() {
140 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
141
142 JPanel p = new JPanel(new BorderLayout());
143 p.add(new JLabel("<html>This will change "+sel.size()+" object"+(sel.size()==1?"":"s")+".<br><br>"+
144 "Please select a key"), BorderLayout.NORTH);
145 Vector<String> allKeys = new Vector<String>(Key.allKeys.keySet());
146 for (Iterator<String> it = allKeys.iterator(); it.hasNext();) {
147 String s = it.next();
148 for (int i = 0; i < data.getRowCount(); ++i) {
149 if (s.equals(data.getValueAt(i, 0))) {
150 it.remove();
151 break;
152 }
153 }
154 }
155 JComboBox keys = new JComboBox(allKeys);
156 keys.setEditable(true);
157 p.add(keys, BorderLayout.CENTER);
158
159 JPanel p2 = new JPanel(new BorderLayout());
160 p.add(p2, BorderLayout.SOUTH);
161 p2.add(new JLabel("Please select a value"), BorderLayout.NORTH);
162 JTextField values = new JTextField();
163 p2.add(values, BorderLayout.CENTER);
164 int answer = JOptionPane.showConfirmDialog(Main.main, p,
165 "Change values?", JOptionPane.OK_CANCEL_OPTION);
166 if (answer != JOptionPane.OK_OPTION)
167 return;
168 String key = keys.getEditor().getItem().toString();
169 String value = values.getText();
170 if (value.equals(""))
171 return;
172 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), value));
173 selectionChanged(sel); // update table
174 }
175
176 /**
177 * Delete the keys from the given row.
178 * @param row The row, which key gets deleted from the dataset.
179 */
180 private void delete(int row) {
181 String key = data.getValueAt(row, 0).toString();
182 Collection<OsmPrimitive> sel = Main.main.ds.getSelected();
183 mv.editLayer().add(new ChangeKeyValueCommand(sel, Key.get(key), null));
184 selectionChanged(sel); // update table
185 }
186
187 /**
188 * The property data.
189 */
190 private final DefaultTableModel data = new DefaultTableModel(){
191 @Override
192 public boolean isCellEditable(int row, int column) {
193 return false;
194 }
195 @Override
196 public Class<?> getColumnClass(int columnIndex) {
197 return columnIndex == 1 ? JComboBox.class : String.class;
198 }
199 };
200 /**
201 * The properties list.
202 */
203 private final JTable propertyTable = new JTable(data);
204 /**
205 * The map view this dialog operates on.
206 */
207 private final MapView mv;
208
209 /**
210 * Create a new PropertiesDialog
211 */
212 public PropertiesDialog(MapFrame mapFrame) {
213 super("Properties", "Properties Dialog", "properties", KeyEvent.VK_P, "Property for selected objects.");
214 mv = mapFrame.mapView;
215
216 setPreferredSize(new Dimension(320,150));
217
218 data.setColumnIdentifiers(new String[]{"Key", "Value"});
219 propertyTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
220 propertyTable.setDefaultRenderer(JComboBox.class, new DefaultTableCellRenderer(){
221 @Override
222 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
223 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
224 if (c instanceof JLabel) {
225 String str = ((JComboBox)value).getEditor().getItem().toString();
226 ((JLabel)c).setText(str);
227 if (str.equals("<different>"))
228 c.setFont(c.getFont().deriveFont(Font.ITALIC));
229 }
230 return c;
231 }
232 });
233 propertyTable.setDefaultRenderer(String.class, new DefaultTableCellRenderer(){
234 @Override
235 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
236 return super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
237 }
238 });
239 propertyTable.addMouseListener(new DblClickWatch());
240
241 JScrollPane scrollPane = new JScrollPane(propertyTable);
242 scrollPane.addMouseListener(new DblClickWatch());
243 add(scrollPane, BorderLayout.CENTER);
244
245 JPanel buttonPanel = new JPanel(new GridLayout(1,3));
246 ActionListener buttonAction = new ActionListener(){
247 public void actionPerformed(ActionEvent e) {
248 int sel = propertyTable.getSelectedRow();
249 if (e.getActionCommand().equals("Add"))
250 add();
251 else if (e.getActionCommand().equals("Edit")) {
252 if (sel == -1)
253 JOptionPane.showMessageDialog(Main.main, "Please select the row to edit.");
254 else
255 edit(sel);
256 } else if (e.getActionCommand().equals("Delete")) {
257 if (sel == -1)
258 JOptionPane.showMessageDialog(Main.main, "Please select the row to delete.");
259 else
260 delete(sel);
261 }
262 }
263 };
264 buttonPanel.add(createButton("Add", "Add a new key/value pair to all objects", KeyEvent.VK_A, buttonAction));
265 buttonPanel.add(createButton("Edit", "Edit the value of the selected key for all objects", KeyEvent.VK_E, buttonAction));
266 buttonPanel.add(createButton("Delete", "Delete the selected key in all objects", KeyEvent.VK_D, buttonAction));
267 add(buttonPanel, BorderLayout.SOUTH);
268 }
269
270 private JButton createButton(String name, String tooltip, int mnemonic, ActionListener actionListener) {
271 JButton b = new JButton(name, ImageProvider.get("dialogs", name.toLowerCase()));
272 b.setActionCommand(name);
273 b.addActionListener(actionListener);
274 b.setToolTipText(tooltip);
275 b.setMnemonic(mnemonic);
276 return b;
277 }
278
279 @Override
280 public void setVisible(boolean b) {
281 if (b) {
282 Main.main.ds.addSelectionChangedListener(this);
283 selectionChanged(Main.main.ds.getSelected());
284 } else {
285 Main.main.ds.removeSelectionChangedListener(this);
286 }
287 super.setVisible(b);
288 }
289
290 public void selectionChanged(Collection<OsmPrimitive> newSelection) {
291 if (propertyTable.getCellEditor() != null)
292 propertyTable.getCellEditor().cancelCellEditing();
293 data.setRowCount(0);
294 TreeMap<String, Collection<String>> props = new TreeMap<String, Collection<String>>();
295 HashMap<String, Integer> valueCounts = new HashMap<String, Integer>();
296 for (OsmPrimitive osm : newSelection) {
297 if (osm.keys != null) {
298 for (Entry<Key, String> e : osm.keys.entrySet()) {
299 Collection<String> value = props.get(e.getKey().name);
300 if (value == null) {
301 value = new TreeSet<String>();
302 props.put(e.getKey().name, value);
303 }
304 value.add(e.getValue());
305
306 Integer count = valueCounts.get(e.getValue());
307 if (count == null)
308 count = 0;
309 valueCounts.put(e.getValue(), count+1);
310 }
311 }
312 }
313 int selCount = newSelection.size();
314 for (Entry<String, Collection<String>> e : props.entrySet()) {
315 JComboBox value = new JComboBox(e.getValue().toArray());
316 value.setEditable(true);
317 if (e.getValue().size() > 1 || valueCounts.get(e.getValue().iterator().next()) != selCount)
318 value.getEditor().setItem("<different>");
319 data.addRow(new Object[]{e.getKey(), value});
320 }
321 }
322}
Note: See TracBrowser for help on using the repository browser.