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

Last change on this file since 16438 was 16438, checked in by simon04, 5 years ago

see #19251 - Java 8: use Stream

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