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