source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTable.java@ 14052

Last change on this file since 14052 was 14052, checked in by Don-vip, 7 years ago

see #16010 - use JMockit to enable more extensive test coverage (patch by ris, modified)

see https://github.com/openstreetmap/josm/pull/24/commits for details

  • Property svn:eol-style set to native
File size: 14.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.advanced;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Color;
8import java.awt.Component;
9import java.awt.Font;
10import java.awt.GridBagLayout;
11import java.awt.event.MouseAdapter;
12import java.awt.event.MouseEvent;
13import java.util.ArrayList;
14import java.util.List;
15import java.util.Map;
16import java.util.Objects;
17
18import javax.swing.ButtonGroup;
19import javax.swing.DefaultCellEditor;
20import javax.swing.JComponent;
21import javax.swing.JLabel;
22import javax.swing.JOptionPane;
23import javax.swing.JPanel;
24import javax.swing.JRadioButton;
25import javax.swing.JTable;
26import javax.swing.UIManager;
27import javax.swing.table.DefaultTableCellRenderer;
28import javax.swing.table.DefaultTableModel;
29
30import org.openstreetmap.josm.data.preferences.NamedColorProperty;
31import org.openstreetmap.josm.spi.preferences.ListListSetting;
32import org.openstreetmap.josm.spi.preferences.ListSetting;
33import org.openstreetmap.josm.spi.preferences.MapListSetting;
34import org.openstreetmap.josm.spi.preferences.Setting;
35import org.openstreetmap.josm.spi.preferences.StringSetting;
36import org.openstreetmap.josm.gui.ExtendedDialog;
37import org.openstreetmap.josm.gui.util.GuiHelper;
38import org.openstreetmap.josm.gui.widgets.JosmTextField;
39import org.openstreetmap.josm.tools.GBC;
40
41/**
42 * Component for editing list of preferences as a table.
43 * @since 6021
44 */
45public class PreferencesTable extends JTable {
46 private final AllSettingsTableModel model;
47 private final transient List<PrefEntry> displayData;
48
49 /**
50 * Constructs a new {@code PreferencesTable}.
51 * @param displayData The list of preferences entries to display
52 */
53 public PreferencesTable(List<PrefEntry> displayData) {
54 this.displayData = displayData;
55 model = new AllSettingsTableModel();
56 setModel(model);
57 putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
58 getColumnModel().getColumn(1).setCellRenderer(new SettingCellRenderer());
59 getColumnModel().getColumn(1).setCellEditor(new SettingCellEditor());
60
61 addMouseListener(new MouseAdapter() {
62 @Override public void mouseClicked(MouseEvent e) {
63 if (e.getClickCount() == 2) {
64 editPreference(PreferencesTable.this);
65 }
66 }
67 });
68 }
69
70 /**
71 * This method should be called when displayed data was changed form external code
72 */
73 public void fireDataChanged() {
74 model.fireTableDataChanged();
75 }
76
77 /**
78 * The list of currently selected rows
79 * @return newly created list of PrefEntry
80 */
81 public List<PrefEntry> getSelectedItems() {
82 List<PrefEntry> entries = new ArrayList<>();
83 for (int row : getSelectedRows()) {
84 PrefEntry p = (PrefEntry) model.getValueAt(row, -1);
85 entries.add(p);
86 }
87 return entries;
88 }
89
90 /**
91 * Call this to edit selected row in preferences table
92 * @param gui - parent component for messagebox
93 * @return true if editing was actually performed during this call
94 */
95 public boolean editPreference(final JComponent gui) {
96 if (getSelectedRowCount() != 1) {
97 JOptionPane.showMessageDialog(
98 gui,
99 tr("Please select the row to edit."),
100 tr("Warning"),
101 JOptionPane.WARNING_MESSAGE
102 );
103 return false;
104 }
105 final PrefEntry e = (PrefEntry) model.getValueAt(getSelectedRow(), 1);
106 Setting<?> stg = e.getValue();
107 boolean ok = false;
108 if (stg instanceof StringSetting) {
109 editCellAt(getSelectedRow(), 1);
110 Component editor = getEditorComponent();
111 if (editor != null) {
112 editor.requestFocus();
113 }
114 } else if (stg instanceof ListSetting) {
115 ok = doEditList(gui, e, (ListSetting) stg);
116 } else if (stg instanceof ListListSetting) {
117 ok = doEditListList(gui, e, (ListListSetting) stg);
118 } else if (stg instanceof MapListSetting) {
119 ok = doEditMapList(gui, e, (MapListSetting) stg);
120 }
121 return ok;
122 }
123
124 private static boolean doEditList(final JComponent gui, final PrefEntry e, ListSetting lSetting) {
125 ListEditor lEditor = new ListEditor(gui, e, lSetting);
126 lEditor.showDialog();
127 if (lEditor.getValue() == 1) {
128 List<String> data = lEditor.getData();
129 if (!lSetting.equalVal(data)) {
130 e.setValue(new ListSetting(data));
131 return true;
132 }
133 }
134 return false;
135 }
136
137 private static boolean doEditListList(final JComponent gui, final PrefEntry e, ListListSetting llSetting) {
138 ListListEditor llEditor = new ListListEditor(gui, e, llSetting);
139 llEditor.showDialog();
140 if (llEditor.getValue() == 1) {
141 List<List<String>> data = llEditor.getData();
142 if (!llSetting.equalVal(data)) {
143 e.setValue(new ListListSetting(data));
144 return true;
145 }
146 }
147 return false;
148 }
149
150 private static boolean doEditMapList(final JComponent gui, final PrefEntry e, MapListSetting mlSetting) {
151 MapListEditor mlEditor = new MapListEditor(gui, e, mlSetting);
152 mlEditor.showDialog();
153 if (mlEditor.getValue() == 1) {
154 List<Map<String, String>> data = mlEditor.getData();
155 if (!mlSetting.equalVal(data)) {
156 e.setValue(new MapListSetting(data));
157 return true;
158 }
159 }
160 return false;
161 }
162
163 /**
164 * Add new preference to the table
165 * @param gui - parent component for asking dialogs
166 * @return newly created entry or null if adding was cancelled
167 */
168 public PrefEntry addPreference(final JComponent gui) {
169 JPanel p = new JPanel(new GridBagLayout());
170 p.add(new JLabel(tr("Key")), GBC.std().insets(0, 0, 5, 0));
171 JosmTextField tkey = new JosmTextField("", 50);
172 p.add(tkey, GBC.eop().insets(5, 0, 0, 0).fill(GBC.HORIZONTAL));
173
174 p.add(new JLabel(tr("Select Setting Type:")), GBC.eol().insets(5, 15, 5, 0));
175
176 JRadioButton rbString = new JRadioButton(tr("Simple"));
177 JRadioButton rbList = new JRadioButton(tr("List"));
178 JRadioButton rbListList = new JRadioButton(tr("List of lists"));
179 JRadioButton rbMapList = new JRadioButton(tr("List of maps"));
180
181 ButtonGroup group = new ButtonGroup();
182 group.add(rbString);
183 group.add(rbList);
184 group.add(rbListList);
185 group.add(rbMapList);
186
187 p.add(rbString, GBC.eol());
188 p.add(rbList, GBC.eol());
189 p.add(rbListList, GBC.eol());
190 p.add(rbMapList, GBC.eol());
191
192 rbString.setSelected(true);
193
194 PrefEntry pe = null;
195 boolean ok = false;
196 if (askAddSetting(gui, p)) {
197 if (rbString.isSelected()) {
198 StringSetting sSetting = new StringSetting(null);
199 pe = new PrefEntry(tkey.getText(), sSetting, sSetting, false);
200 ok = doAddSimple(gui, pe, sSetting);
201 } else if (rbList.isSelected()) {
202 ListSetting lSetting = new ListSetting(null);
203 pe = new PrefEntry(tkey.getText(), lSetting, lSetting, false);
204 ok = doAddList(gui, pe, lSetting);
205 } else if (rbListList.isSelected()) {
206 ListListSetting llSetting = new ListListSetting(null);
207 pe = new PrefEntry(tkey.getText(), llSetting, llSetting, false);
208 ok = doAddListList(gui, pe, llSetting);
209 } else if (rbMapList.isSelected()) {
210 MapListSetting mlSetting = new MapListSetting(null);
211 pe = new PrefEntry(tkey.getText(), mlSetting, mlSetting, false);
212 ok = doAddMapList(gui, pe, mlSetting);
213 }
214 }
215 return ok ? pe : null;
216 }
217
218 private static boolean askAddSetting(JComponent gui, JPanel p) {
219 return new ExtendedDialog(gui, tr("Add setting"), tr("OK"), tr("Cancel"))
220 .setContent(p).setButtonIcons("ok", "cancel").showDialog().getValue() == 1;
221 }
222
223 private static boolean doAddSimple(final JComponent gui, PrefEntry pe, StringSetting sSetting) {
224 StringEditor sEditor = new StringEditor(gui, pe, sSetting);
225 sEditor.showDialog();
226 if (sEditor.getValue() == 1) {
227 String data = sEditor.getData();
228 if (!Objects.equals(sSetting.getValue(), data)) {
229 pe.setValue(new StringSetting(data));
230 return true;
231 }
232 }
233 return false;
234 }
235
236 private static boolean doAddList(final JComponent gui, PrefEntry pe, ListSetting lSetting) {
237 ListEditor lEditor = new ListEditor(gui, pe, lSetting);
238 lEditor.showDialog();
239 if (lEditor.getValue() == 1) {
240 List<String> data = lEditor.getData();
241 if (!lSetting.equalVal(data)) {
242 pe.setValue(new ListSetting(data));
243 return true;
244 }
245 }
246 return false;
247 }
248
249 private static boolean doAddListList(final JComponent gui, PrefEntry pe, ListListSetting llSetting) {
250 ListListEditor llEditor = new ListListEditor(gui, pe, llSetting);
251 llEditor.showDialog();
252 if (llEditor.getValue() == 1) {
253 List<List<String>> data = llEditor.getData();
254 if (!llSetting.equalVal(data)) {
255 pe.setValue(new ListListSetting(data));
256 return true;
257 }
258 }
259 return false;
260 }
261
262 private static boolean doAddMapList(final JComponent gui, PrefEntry pe, MapListSetting mlSetting) {
263 MapListEditor mlEditor = new MapListEditor(gui, pe, mlSetting);
264 mlEditor.showDialog();
265 if (mlEditor.getValue() == 1) {
266 List<Map<String, String>> data = mlEditor.getData();
267 if (!mlSetting.equalVal(data)) {
268 pe.setValue(new MapListSetting(data));
269 return true;
270 }
271 }
272 return false;
273 }
274
275 /**
276 * Reset selected preferences to their default values
277 * @param gui - parent component to display warning messages
278 */
279 public void resetPreferences(final JComponent gui) {
280 if (getSelectedRowCount() == 0) {
281 JOptionPane.showMessageDialog(
282 gui,
283 tr("Please select the row to delete."),
284 tr("Warning"),
285 JOptionPane.WARNING_MESSAGE
286 );
287 return;
288 }
289 for (int row : getSelectedRows()) {
290 PrefEntry e = displayData.get(row);
291 e.reset();
292 }
293 fireDataChanged();
294 }
295
296 final class AllSettingsTableModel extends DefaultTableModel {
297
298 AllSettingsTableModel() {
299 setColumnIdentifiers(new String[]{tr("Key"), tr("Value")});
300 }
301
302 @Override
303 public boolean isCellEditable(int row, int column) {
304 return column == 1 && (displayData.get(row).getValue() instanceof StringSetting);
305 }
306
307 @Override
308 public int getRowCount() {
309 return displayData.size();
310 }
311
312 @Override
313 public Object getValueAt(int row, int column) {
314 if (column == 0)
315 return displayData.get(row).getKey();
316 else
317 return displayData.get(row);
318 }
319
320 @Override
321 public void setValueAt(Object o, int row, int column) {
322 PrefEntry pe = displayData.get(row);
323 String s = (String) o;
324 if (!s.equals(pe.getValue().getValue())) {
325 pe.setValue(new StringSetting(s));
326 fireTableCellUpdated(row, column);
327 }
328 }
329 }
330
331 static final class SettingCellRenderer extends DefaultTableCellRenderer {
332 private final Color backgroundColor = UIManager.getColor("Table.background");
333 private final Color changedColor = new NamedColorProperty(
334 marktr("Advanced Background: Changed"),
335 new Color(200, 255, 200)).get();
336 private final Color nonDefaultColor = new NamedColorProperty(
337 marktr("Advanced Background: NonDefault"),
338 new Color(255, 255, 200)).get();
339
340 @Override
341 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
342 if (value == null)
343 return this;
344 PrefEntry pe = (PrefEntry) value;
345 Setting<?> setting = pe.getValue();
346 Object val = setting.getValue();
347 String display = val != null ? val.toString() : "<html><i>&lt;"+tr("unset")+"&gt;</i></html>";
348
349 JLabel label = (JLabel) super.getTableCellRendererComponent(table,
350 display, isSelected, hasFocus, row, column);
351
352 GuiHelper.setBackgroundReadable(label, backgroundColor);
353 if (pe.isChanged()) {
354 GuiHelper.setBackgroundReadable(label, changedColor);
355 } else if (!pe.isDefault()) {
356 GuiHelper.setBackgroundReadable(label, nonDefaultColor);
357 }
358
359 if (!pe.isDefault()) {
360 label.setFont(label.getFont().deriveFont(Font.BOLD));
361 }
362 val = pe.getDefaultValue().getValue();
363 if (val != null) {
364 if (pe.isDefault()) {
365 label.setToolTipText(tr("Current value is default."));
366 } else {
367 label.setToolTipText(tr("Default value is ''{0}''.", val));
368 }
369 } else {
370 label.setToolTipText(tr("Default value currently unknown (setting has not been used yet)."));
371 }
372 return label;
373 }
374 }
375
376 static final class SettingCellEditor extends DefaultCellEditor {
377 SettingCellEditor() {
378 super(new JosmTextField());
379 }
380
381 @Override
382 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
383 PrefEntry pe = (PrefEntry) value;
384 StringSetting stg = (StringSetting) pe.getValue();
385 String s = stg.getValue() == null ? "" : stg.getValue();
386 return super.getTableCellEditorComponent(table, s, isSelected, row, column);
387 }
388 }
389}
Note: See TracBrowser for help on using the repository browser.