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

Last change on this file since 16846 was 16846, checked in by simon04, 4 years ago

PreferencesTable: remove code duplication

  • Property svn:eol-style set to native
File size: 12.5 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.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.gui.ExtendedDialog;
32import org.openstreetmap.josm.gui.util.GuiHelper;
33import org.openstreetmap.josm.gui.widgets.JosmTextField;
34import org.openstreetmap.josm.spi.preferences.ListListSetting;
35import org.openstreetmap.josm.spi.preferences.ListSetting;
36import org.openstreetmap.josm.spi.preferences.MapListSetting;
37import org.openstreetmap.josm.spi.preferences.Setting;
38import org.openstreetmap.josm.spi.preferences.StringSetting;
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 return Arrays.stream(getSelectedRows())
83 .mapToObj(row -> (PrefEntry) model.getValueAt(row, -1))
84 .collect(Collectors.toList());
85 }
86
87 /**
88 * Call this to edit selected row in preferences table
89 * @param gui - parent component for messagebox
90 * @return true if editing was actually performed during this call
91 */
92 public boolean editPreference(final JComponent gui) {
93 if (getSelectedRowCount() != 1) {
94 return false;
95 }
96 final PrefEntry e = (PrefEntry) model.getValueAt(getSelectedRow(), 1);
97 Setting<?> stg = e.getValue();
98 boolean ok = false;
99 if (stg instanceof StringSetting) {
100 editCellAt(getSelectedRow(), 1);
101 Component editor = getEditorComponent();
102 if (editor != null) {
103 editor.requestFocus();
104 }
105 } else if (stg instanceof ListSetting) {
106 ok = doAddEditList(gui, e, (ListSetting) stg);
107 } else if (stg instanceof ListListSetting) {
108 ok = doAddEditListList(gui, e, (ListListSetting) stg);
109 } else if (stg instanceof MapListSetting) {
110 ok = doAddEditMapList(gui, e, (MapListSetting) stg);
111 }
112 return ok;
113 }
114
115 /**
116 * Add new preference to the table
117 * @param gui - parent component for asking dialogs
118 * @return newly created entry or null if adding was cancelled
119 */
120 public PrefEntry addPreference(final JComponent gui) {
121 JPanel p = new JPanel(new GridBagLayout());
122 p.add(new JLabel(tr("Key")), GBC.std().insets(0, 0, 5, 0));
123 JosmTextField tkey = new JosmTextField("", 50);
124 p.add(tkey, GBC.eop().insets(5, 0, 0, 0).fill(GBC.HORIZONTAL));
125
126 p.add(new JLabel(tr("Select Setting Type:")), GBC.eol().insets(5, 15, 5, 0));
127
128 JRadioButton rbString = new JRadioButton(tr("Simple"));
129 JRadioButton rbList = new JRadioButton(tr("List"));
130 JRadioButton rbListList = new JRadioButton(tr("List of lists"));
131 JRadioButton rbMapList = new JRadioButton(tr("List of maps"));
132
133 ButtonGroup group = new ButtonGroup();
134 group.add(rbString);
135 group.add(rbList);
136 group.add(rbListList);
137 group.add(rbMapList);
138
139 p.add(rbString, GBC.eol());
140 p.add(rbList, GBC.eol());
141 p.add(rbListList, GBC.eol());
142 p.add(rbMapList, GBC.eol());
143
144 rbString.setSelected(true);
145
146 PrefEntry pe = null;
147 boolean ok = false;
148 if (askAddSetting(gui, p)) {
149 if (rbString.isSelected()) {
150 StringSetting sSetting = new StringSetting(null);
151 pe = new PrefEntry(tkey.getText(), sSetting, sSetting, false);
152 ok = doAddSimple(gui, pe, sSetting);
153 } else if (rbList.isSelected()) {
154 ListSetting lSetting = new ListSetting(null);
155 pe = new PrefEntry(tkey.getText(), lSetting, lSetting, false);
156 ok = doAddEditList(gui, pe, lSetting);
157 } else if (rbListList.isSelected()) {
158 ListListSetting llSetting = new ListListSetting(null);
159 pe = new PrefEntry(tkey.getText(), llSetting, llSetting, false);
160 ok = doAddEditListList(gui, pe, llSetting);
161 } else if (rbMapList.isSelected()) {
162 MapListSetting mlSetting = new MapListSetting(null);
163 pe = new PrefEntry(tkey.getText(), mlSetting, mlSetting, false);
164 ok = doAddEditMapList(gui, pe, mlSetting);
165 }
166 }
167 return ok ? pe : null;
168 }
169
170 private static boolean askAddSetting(JComponent gui, JPanel p) {
171 return new ExtendedDialog(gui, tr("Add setting"), tr("OK"), tr("Cancel"))
172 .setContent(p).setButtonIcons("ok", "cancel").showDialog().getValue() == 1;
173 }
174
175 private static boolean doAddSimple(final JComponent gui, PrefEntry pe, StringSetting sSetting) {
176 StringEditor sEditor = new StringEditor(gui, pe, sSetting);
177 sEditor.showDialog();
178 if (sEditor.getValue() == 1) {
179 String data = sEditor.getData();
180 if (!Objects.equals(sSetting.getValue(), data)) {
181 pe.setValue(new StringSetting(data));
182 return true;
183 }
184 }
185 return false;
186 }
187
188 private static boolean doAddEditList(final JComponent gui, PrefEntry pe, ListSetting lSetting) {
189 ListEditor lEditor = new ListEditor(gui, pe, lSetting);
190 lEditor.showDialog();
191 if (lEditor.getValue() == 1) {
192 List<String> data = lEditor.getData();
193 if (!lSetting.equalVal(data)) {
194 pe.setValue(new ListSetting(data));
195 return true;
196 }
197 }
198 return false;
199 }
200
201 private static boolean doAddEditListList(final JComponent gui, PrefEntry pe, ListListSetting llSetting) {
202 ListListEditor llEditor = new ListListEditor(gui, pe, llSetting);
203 llEditor.showDialog();
204 if (llEditor.getValue() == 1) {
205 List<List<String>> data = llEditor.getData();
206 if (!llSetting.equalVal(data)) {
207 pe.setValue(new ListListSetting(data));
208 return true;
209 }
210 }
211 return false;
212 }
213
214 private static boolean doAddEditMapList(final JComponent gui, PrefEntry pe, MapListSetting mlSetting) {
215 MapListEditor mlEditor = new MapListEditor(gui, pe, mlSetting);
216 mlEditor.showDialog();
217 if (mlEditor.getValue() == 1) {
218 List<Map<String, String>> data = mlEditor.getData();
219 if (!mlSetting.equalVal(data)) {
220 pe.setValue(new MapListSetting(data));
221 return true;
222 }
223 }
224 return false;
225 }
226
227 /**
228 * Reset selected preferences to their default values
229 * @param gui - parent component to display warning messages
230 */
231 public void resetPreferences(final JComponent gui) {
232 if (getSelectedRowCount() == 0) {
233 return;
234 }
235 for (int row : getSelectedRows()) {
236 PrefEntry e = displayData.get(row);
237 e.reset();
238 }
239 fireDataChanged();
240 }
241
242 final class AllSettingsTableModel extends DefaultTableModel {
243
244 AllSettingsTableModel() {
245 setColumnIdentifiers(new String[]{tr("Key"), tr("Value")});
246 }
247
248 @Override
249 public boolean isCellEditable(int row, int column) {
250 return column == 1 && (displayData.get(row).getValue() instanceof StringSetting);
251 }
252
253 @Override
254 public int getRowCount() {
255 return displayData.size();
256 }
257
258 @Override
259 public Object getValueAt(int row, int column) {
260 if (column == 0)
261 return displayData.get(row).getKey();
262 else
263 return displayData.get(row);
264 }
265
266 @Override
267 public void setValueAt(Object o, int row, int column) {
268 PrefEntry pe = displayData.get(row);
269 String s = (String) o;
270 if (!s.equals(pe.getValue().getValue())) {
271 pe.setValue(new StringSetting(s));
272 fireTableCellUpdated(row, column);
273 }
274 }
275 }
276
277 static final class SettingCellRenderer extends DefaultTableCellRenderer {
278 private final Color backgroundColor = UIManager.getColor("Table.background");
279 private final Color changedColor = new NamedColorProperty(
280 marktr("Advanced Background: Changed"),
281 new Color(200, 255, 200)).get();
282 private final Color nonDefaultColor = new NamedColorProperty(
283 marktr("Advanced Background: NonDefault"),
284 new Color(255, 255, 200)).get();
285
286 @Override
287 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
288 if (value == null)
289 return this;
290 PrefEntry pe = (PrefEntry) value;
291 Setting<?> setting = pe.getValue();
292 Object val = setting.getValue();
293 String display = val != null ? val.toString() : "<html><i>&lt;"+tr("unset")+"&gt;</i></html>";
294
295 JLabel label = (JLabel) super.getTableCellRendererComponent(table,
296 display, isSelected, hasFocus, row, column);
297
298 GuiHelper.setBackgroundReadable(label, backgroundColor);
299 if (pe.isChanged()) {
300 GuiHelper.setBackgroundReadable(label, changedColor);
301 } else if (!pe.isDefault()) {
302 GuiHelper.setBackgroundReadable(label, nonDefaultColor);
303 }
304
305 if (!pe.isDefault()) {
306 label.setFont(label.getFont().deriveFont(Font.BOLD));
307 }
308 val = pe.getDefaultValue().getValue();
309 if (val != null) {
310 if (pe.isDefault()) {
311 label.setToolTipText(tr("Current value is default."));
312 } else {
313 label.setToolTipText(tr("Default value is ''{0}''.", val));
314 }
315 } else {
316 label.setToolTipText(tr("Default value currently unknown (setting has not been used yet)."));
317 }
318 return label;
319 }
320 }
321
322 static final class SettingCellEditor extends DefaultCellEditor {
323 SettingCellEditor() {
324 super(new JosmTextField());
325 }
326
327 @Override
328 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
329 PrefEntry pe = (PrefEntry) value;
330 StringSetting stg = (StringSetting) pe.getValue();
331 String s = stg.getValue() == null ? "" : stg.getValue();
332 return super.getTableCellEditorComponent(table, s, isSelected, row, column);
333 }
334 }
335}
Note: See TracBrowser for help on using the repository browser.