001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.gui.preferences.advanced; 003 004 import static org.openstreetmap.josm.tools.I18n.marktr; 005 import static org.openstreetmap.josm.tools.I18n.tr; 006 007 import java.awt.Color; 008 import java.awt.Component; 009 import java.awt.Dimension; 010 import java.awt.Font; 011 import java.awt.GridBagLayout; 012 import java.awt.event.ActionEvent; 013 import java.awt.event.ActionListener; 014 import java.awt.event.MouseAdapter; 015 import java.awt.event.MouseEvent; 016 import java.io.File; 017 import java.util.ArrayList; 018 import java.util.Collection; 019 import java.util.Collections; 020 import java.util.Comparator; 021 import java.util.List; 022 import java.util.Map; 023 import java.util.Map.Entry; 024 025 import javax.swing.Box; 026 import javax.swing.ButtonGroup; 027 import javax.swing.DefaultCellEditor; 028 import javax.swing.JButton; 029 import javax.swing.JFileChooser; 030 import javax.swing.JLabel; 031 import javax.swing.JOptionPane; 032 import javax.swing.JPanel; 033 import javax.swing.JRadioButton; 034 import javax.swing.JScrollPane; 035 import javax.swing.JTable; 036 import javax.swing.JTextField; 037 import javax.swing.event.DocumentEvent; 038 import javax.swing.event.DocumentListener; 039 import javax.swing.filechooser.FileFilter; 040 import javax.swing.table.DefaultTableCellRenderer; 041 import javax.swing.table.DefaultTableModel; 042 043 import org.openstreetmap.josm.Main; 044 import org.openstreetmap.josm.actions.DiskAccessAction; 045 import org.openstreetmap.josm.data.CustomConfigurator; 046 import org.openstreetmap.josm.data.Preferences; 047 import org.openstreetmap.josm.data.Preferences.ListListSetting; 048 import org.openstreetmap.josm.data.Preferences.ListSetting; 049 import org.openstreetmap.josm.data.Preferences.MapListSetting; 050 import org.openstreetmap.josm.data.Preferences.Setting; 051 import org.openstreetmap.josm.data.Preferences.StringSetting; 052 import org.openstreetmap.josm.gui.ExtendedDialog; 053 import org.openstreetmap.josm.gui.actionsupport.LogShowDialog; 054 import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting; 055 import org.openstreetmap.josm.gui.preferences.PreferenceSetting; 056 import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory; 057 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 058 import org.openstreetmap.josm.tools.CheckParameterUtil; 059 import org.openstreetmap.josm.tools.GBC; 060 import org.openstreetmap.josm.tools.Utils; 061 062 public class AdvancedPreference extends DefaultTabPreferenceSetting { 063 064 public static class Factory implements PreferenceSettingFactory { 065 public PreferenceSetting createPreferenceSetting() { 066 return new AdvancedPreference(); 067 } 068 } 069 070 private AdvancedPreference() { 071 super("advanced", tr("Advanced Preferences"), tr("Setting Preference entries directly. Use with caution!")); 072 } 073 074 @Override 075 public boolean isExpert() { 076 return true; 077 } 078 079 public static class PrefEntry implements Comparable<PrefEntry> { 080 private String key; 081 private Setting value; 082 private Setting defaultValue; 083 private boolean isDefault; 084 private boolean changed; 085 086 public PrefEntry(String key, Setting value, Setting defaultValue, boolean isDefault) { 087 CheckParameterUtil.ensureParameterNotNull(key); 088 CheckParameterUtil.ensureParameterNotNull(value); 089 CheckParameterUtil.ensureParameterNotNull(defaultValue); 090 this.key = key; 091 this.value = value; 092 this.defaultValue = defaultValue; 093 this.isDefault = isDefault; 094 } 095 096 public String getKey() { 097 return key; 098 } 099 100 public Setting getValue() { 101 return value; 102 } 103 104 public Setting getDefaultValue() { 105 return defaultValue; 106 } 107 108 public void setValue(Setting value) { 109 this.value = value; 110 changed = true; 111 isDefault = false; 112 } 113 114 public boolean isDefault() { 115 return isDefault; 116 } 117 118 public boolean isChanged() { 119 return changed; 120 } 121 122 private void markAsChanged() { 123 changed = true; 124 } 125 126 public void reset() { 127 value = defaultValue; 128 changed = true; 129 isDefault = true; 130 } 131 132 @Override 133 public int compareTo(PrefEntry other) { 134 return key.compareTo(other.key); 135 } 136 137 @Override 138 public String toString() { 139 return value.toString(); 140 } 141 } 142 143 private AllSettingsTableModel model; 144 protected List<PrefEntry> data; 145 protected List<PrefEntry> displayData; 146 protected JTextField txtFilter; 147 148 public void addGui(final PreferenceTabbedPane gui) { 149 JPanel p = gui.createPreferenceTab(this); 150 151 txtFilter = new JTextField(); 152 JLabel lbFilter = new JLabel(tr("Search: ")); 153 lbFilter.setLabelFor(txtFilter); 154 p.add(lbFilter); 155 p.add(txtFilter, GBC.eol().fill(GBC.HORIZONTAL)); 156 txtFilter.getDocument().addDocumentListener(new DocumentListener(){ 157 @Override public void changedUpdate(DocumentEvent e) { 158 action(); 159 } 160 @Override public void insertUpdate(DocumentEvent e) { 161 action(); 162 } 163 @Override public void removeUpdate(DocumentEvent e) { 164 action(); 165 } 166 private void action() { 167 applyFilter(); 168 } 169 }); 170 readPreferences(Main.pref); 171 model = new AllSettingsTableModel(); 172 applyFilter(); 173 174 final JTable list = new JTable(model); 175 list.putClientProperty("terminateEditOnFocusLost", true); 176 list.getColumnModel().getColumn(1).setCellRenderer(new SettingCellRenderer()); 177 list.getColumnModel().getColumn(1).setCellEditor(new SettingCellEditor()); 178 179 JScrollPane scroll = new JScrollPane(list); 180 p.add(scroll, GBC.eol().fill(GBC.BOTH)); 181 scroll.setPreferredSize(new Dimension(400,200)); 182 183 JButton add = new JButton(tr("Add")); 184 p.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL)); 185 p.add(add, GBC.std().insets(0,5,0,0)); 186 add.addActionListener(new ActionListener(){ 187 public void actionPerformed(ActionEvent e) { 188 addPreference(gui); 189 } 190 }); 191 192 JButton edit = new JButton(tr("Edit")); 193 p.add(edit, GBC.std().insets(5,5,5,0)); 194 edit.addActionListener(new ActionListener(){ 195 public void actionPerformed(ActionEvent e) { 196 editPreference(gui, list); 197 } 198 }); 199 200 JButton reset = new JButton(tr("Reset")); 201 p.add(reset, GBC.std().insets(0,5,0,0)); 202 reset.addActionListener(new ActionListener(){ 203 public void actionPerformed(ActionEvent e) { 204 resetPreference(gui, list); 205 } 206 }); 207 208 JButton read = new JButton(tr("Read from file")); 209 p.add(read, GBC.std().insets(5,5,0,0)); 210 read.addActionListener(new ActionListener(){ 211 public void actionPerformed(ActionEvent e) { 212 File[] files = askUserForCustomSettingsFiles(false, tr("Open JOSM customization file")); 213 if (files.length==0) return; 214 215 Preferences tmpPrefs = CustomConfigurator.clonePreferences(Main.pref); 216 217 StringBuilder log = new StringBuilder(); 218 log.append("<html>"); 219 for (File f: files) { 220 CustomConfigurator.readXML(f, tmpPrefs); 221 log.append(CustomConfigurator.getLog()); 222 } 223 //try { Main.pref.save(); } catch (IOException ex) { } 224 log.append("</html>"); 225 String msg = log.toString().replace("\n", "<br/>"); 226 227 new LogShowDialog(tr("Import log"), tr("<html>Here is file import summary. <br/>" 228 + "You can reject preferences changes by pressing \"Cancel\" in preferences dialog <br/>" 229 + "To activate some changes JOSM restart may be needed.</html>"), msg).showDialog(); 230 231 //JOptionPane.showMessageDialog(Main.parent, 232 // tr("Installed plugins and some changes in preferences will start to work after JOSM restart"), tr("Warning"), JOptionPane.WARNING_MESSAGE); 233 234 readPreferences(tmpPrefs); 235 // sorting after modification - first modified, then non-default, then default entries 236 Collections.sort(data, new Comparator<PrefEntry>() { 237 @Override 238 public int compare(PrefEntry o1, PrefEntry o2) { 239 if (o1.changed && !o2.changed) return -1; 240 if (o2.changed && !o1.changed) return 1; 241 if (!(o1.isDefault) && o2.isDefault) return -1; 242 if (!(o2.isDefault) && o1.isDefault) return 1; 243 return o1.key.compareTo(o2.key); 244 } 245 }); 246 247 applyFilter(); 248 ((AllSettingsTableModel) list.getModel()).fireTableDataChanged(); 249 } 250 251 }); 252 253 JButton export = new JButton(tr("Export selected items")); 254 p.add(export, GBC.std().insets(5,5,0,0)); 255 export.addActionListener(new ActionListener(){ 256 public void actionPerformed(ActionEvent e) { 257 ArrayList<String> keys = new ArrayList<String>(); 258 boolean hasLists = false; 259 for (int row : list.getSelectedRows()) { 260 PrefEntry p = (PrefEntry) model.getValueAt(row, -1); 261 if (!p.isDefault()) { 262 // preferences with default values are not saved 263 if (!(p.getValue() instanceof StringSetting)) hasLists=true; // => append and replace differs 264 keys.add(p.getKey()); 265 } 266 } 267 if (keys.size()==0) { 268 JOptionPane.showMessageDialog(Main.parent, 269 tr("Please select some preference keys not marked as default"), tr("Warning"), JOptionPane.WARNING_MESSAGE); 270 return; 271 } 272 273 File[] files = askUserForCustomSettingsFiles(true, tr("Export preferences keys to JOSM customization file")); 274 if (files.length==0) return; 275 276 int answer = 0; 277 if (hasLists) { 278 answer = JOptionPane.showOptionDialog( 279 Main.parent, tr("What to do with preference lists when this file is to be imported?"), tr("Question"), 280 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, 281 new String[]{tr("Append preferences from file to existing values"), tr("Replace existing values")}, 0); 282 } 283 CustomConfigurator.exportPreferencesKeysToFile(files[0].getAbsolutePath(), answer==0, keys); 284 } 285 }); 286 287 288 list.addMouseListener(new MouseAdapter(){ 289 @Override public void mouseClicked(MouseEvent e) { 290 if (e.getClickCount() == 2) { 291 editPreference(gui, list); 292 } 293 } 294 }); 295 } 296 297 private void readPreferences(Preferences tmpPrefs) { 298 Map<String, Setting> loaded; 299 Map<String, Setting> orig = Main.pref.getAllSettings(); 300 Map<String, Setting> defaults = tmpPrefs.getAllDefaults(); 301 orig.remove("osm-server.password"); 302 defaults.remove("osm-server.password"); 303 if (tmpPrefs != Main.pref) { 304 loaded = tmpPrefs.getAllSettings(); 305 // plugins preference keys may be changed directly later, after plugins are downloaded 306 // so we do not want to show it in the table as "changed" now 307 Setting pluginSetting = orig.get("plugins"); 308 if (pluginSetting!=null) { 309 loaded.put("plugins", pluginSetting); 310 } 311 } else { 312 loaded = orig; 313 } 314 prepareData(loaded, orig, defaults); 315 } 316 317 private File[] askUserForCustomSettingsFiles(boolean saveFileFlag, String title) { 318 FileFilter filter = new FileFilter() { 319 @Override 320 public boolean accept(File f) { 321 return f.isDirectory() || f.getName().toLowerCase().endsWith(".xml"); 322 } 323 @Override 324 public String getDescription() { 325 return tr("JOSM custom settings files (*.xml)"); 326 } 327 }; 328 JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(!saveFileFlag, !saveFileFlag, title, filter, JFileChooser.FILES_ONLY, "customsettings.lastDirectory"); 329 if (fc != null) { 330 File sel[] = fc.isMultiSelectionEnabled() ? fc.getSelectedFiles() : (new File[]{fc.getSelectedFile()}); 331 if (sel.length==1 && !sel[0].getName().contains(".")) sel[0]=new File(sel[0].getAbsolutePath()+".xml"); 332 return sel; 333 } 334 return new File[0]; 335 } 336 337 private void prepareData(Map<String, Setting> loaded, Map<String, Setting> orig, Map<String, Setting> defaults) { 338 data = new ArrayList<PrefEntry>(); 339 for (Entry<String, Setting> e : loaded.entrySet()) { 340 Setting value = e.getValue(); 341 Setting old = orig.get(e.getKey()); 342 Setting def = defaults.get(e.getKey()); 343 if (def == null) { 344 def = value.getNullInstance(); 345 } 346 PrefEntry en = new PrefEntry(e.getKey(), value, def, false); 347 // after changes we have nondefault value. Value is changed if is not equal to old value 348 if ( !Preferences.isEqual(old, value) ) { 349 en.markAsChanged(); 350 } 351 data.add(en); 352 } 353 for (Entry<String, Setting> e : defaults.entrySet()) { 354 if (!loaded.containsKey(e.getKey())) { 355 PrefEntry en = new PrefEntry(e.getKey(), e.getValue(), e.getValue(), true); 356 // after changes we have default value. So, value is changed if old value is not default 357 Setting old = orig.get(e.getKey()); 358 if ( old!=null ) { 359 en.markAsChanged(); 360 } 361 data.add(en); 362 } 363 } 364 Collections.sort(data); 365 displayData = new ArrayList<PrefEntry>(data); 366 } 367 368 class AllSettingsTableModel extends DefaultTableModel { 369 370 public AllSettingsTableModel() { 371 setColumnIdentifiers(new String[]{tr("Key"), tr("Value")}); 372 } 373 374 @Override 375 public boolean isCellEditable(int row, int column) { 376 return column == 1 && (displayData.get(row).getValue() instanceof StringSetting); 377 } 378 379 @Override 380 public int getRowCount() { 381 return displayData.size(); 382 } 383 384 @Override 385 public Object getValueAt(int row, int column) { 386 if (column == 0) 387 return displayData.get(row).getKey(); 388 else 389 return displayData.get(row); 390 } 391 392 @Override 393 public void setValueAt(Object o, int row, int column) { 394 PrefEntry pe = displayData.get(row); 395 String s = (String) o; 396 if (!s.equals(pe.getValue().getValue())) { 397 pe.setValue(new StringSetting(s)); 398 fireTableCellUpdated(row, column); 399 } 400 } 401 } 402 403 private static class SettingCellRenderer extends DefaultTableCellRenderer { 404 private Color backgroundColor = Main.pref.getUIColor("Table.background"); 405 private Color changedColor = Main.pref.getColor( 406 marktr("Advanced Background: Changed"), 407 new Color(200,255,200)); 408 private Color foregroundColor = Main.pref.getUIColor("Table.foreground"); 409 private Color nonDefaultColor = Main.pref.getColor( 410 marktr("Advanced Background: NonDefalut"), 411 new Color(255,255,200)); 412 413 @Override 414 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 415 if (value == null) 416 return this; 417 PrefEntry pe = (PrefEntry) value; 418 Setting setting = pe.getValue(); 419 Object val = setting.getValue(); 420 String display = val != null ? val.toString() : "<html><i><"+tr("unset")+"></i></html>"; 421 422 JLabel label = (JLabel)super.getTableCellRendererComponent(table, 423 display, isSelected, hasFocus, row, column); 424 425 label.setBackground(backgroundColor); 426 if (isSelected) { 427 label.setForeground(foregroundColor); 428 } 429 if(pe.isChanged()) { 430 label.setBackground(changedColor); 431 } else if(!pe.isDefault()) { 432 label.setBackground(nonDefaultColor); 433 } 434 435 if (!pe.isDefault()) { 436 label.setFont(label.getFont().deriveFont(Font.BOLD)); 437 } 438 val = pe.getDefaultValue().getValue(); 439 if(val != null) 440 { 441 if(pe.isDefault()) { 442 label.setToolTipText(tr("Current value is default.")); 443 } else { 444 label.setToolTipText(tr("Default value is ''{0}''.", val)); 445 } 446 } else { 447 label.setToolTipText(tr("Default value currently unknown (setting has not been used yet).")); 448 } 449 return label; 450 } 451 } 452 453 private static class SettingCellEditor extends DefaultCellEditor { 454 public SettingCellEditor() { 455 super(new JTextField()); 456 } 457 458 @Override 459 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 460 PrefEntry pe = (PrefEntry) value; 461 StringSetting stg = (StringSetting) pe.getValue(); 462 String s = stg.getValue() == null ? "" : stg.getValue(); 463 return super.getTableCellEditorComponent(table, s, isSelected, row, column); 464 } 465 } 466 467 private void applyFilter() { 468 displayData.clear(); 469 for (PrefEntry e : data) { 470 471 String prefKey = e.getKey(); 472 Setting valueSetting = e.getValue(); 473 String prefValue = valueSetting.getValue() == null ? "" : valueSetting.getValue().toString(); 474 475 String input[] = txtFilter.getText().split("\\s+"); 476 boolean canHas = true; 477 478 // Make 'wmsplugin cache' search for e.g. 'cache.wmsplugin' 479 final String prefKeyLower = prefKey.toLowerCase(); 480 final String prefValueLower = prefValue.toLowerCase(); 481 for (String bit : input) { 482 bit = bit.toLowerCase(); 483 if (!prefKeyLower.contains(bit) && !prefValueLower.contains(bit)) { 484 canHas = false; 485 break; 486 } 487 } 488 if (canHas) { 489 displayData.add(e); 490 } 491 } 492 model.fireTableDataChanged(); 493 } 494 495 @Override 496 public boolean ok() { 497 for (PrefEntry e : data) { 498 if (e.isChanged()) { 499 Main.pref.putSetting(e.getKey(), e.getValue()); 500 } 501 } 502 return false; 503 } 504 505 private void resetPreference(final PreferenceTabbedPane gui, final JTable list) { 506 if (list.getSelectedRowCount() == 0) { 507 JOptionPane.showMessageDialog( 508 gui, 509 tr("Please select the row to delete."), 510 tr("Warning"), 511 JOptionPane.WARNING_MESSAGE 512 ); 513 return; 514 } 515 for (int row : list.getSelectedRows()) { 516 PrefEntry e = displayData.get(row); 517 e.reset(); 518 } 519 model.fireTableDataChanged(); 520 } 521 522 private void addPreference(final PreferenceTabbedPane gui) { 523 JPanel p = new JPanel(new GridBagLayout()); 524 p.add(new JLabel(tr("Key")), GBC.std().insets(0,0,5,0)); 525 JTextField tkey = new JTextField("", 50); 526 p.add(tkey, GBC.eop().insets(5,0,0,0).fill(GBC.HORIZONTAL)); 527 528 p.add(new JLabel(tr("Select Setting Type:")), GBC.eol().insets(5,15,5,0)); 529 530 JRadioButton rbString = new JRadioButton(tr("Simple")); 531 JRadioButton rbList = new JRadioButton(tr("List")); 532 JRadioButton rbListList = new JRadioButton(tr("List of lists")); 533 JRadioButton rbMapList = new JRadioButton(tr("List of maps")); 534 535 ButtonGroup group = new ButtonGroup(); 536 group.add(rbString); 537 group.add(rbList); 538 group.add(rbListList); 539 group.add(rbMapList); 540 541 p.add(rbString, GBC.eol()); 542 p.add(rbList, GBC.eol()); 543 p.add(rbListList, GBC.eol()); 544 p.add(rbMapList, GBC.eol()); 545 546 rbString.setSelected(true); 547 548 ExtendedDialog dlg = new ExtendedDialog(gui, tr("Add setting"), new String[] {tr("OK"), tr("Cancel")}); 549 dlg.setButtonIcons(new String[] {"ok.png", "cancel.png"}); 550 dlg.setContent(p); 551 dlg.showDialog(); 552 553 PrefEntry pe = null; 554 boolean ok = false; 555 if (dlg.getValue() == 1) { 556 if (rbString.isSelected()) { 557 StringSetting sSetting = new StringSetting(null); 558 pe = new PrefEntry(tkey.getText(), sSetting, sSetting, false); 559 StringEditor sEditor = new StringEditor(gui, pe, sSetting); 560 sEditor.showDialog(); 561 if (sEditor.getValue() == 1) { 562 String data = sEditor.getData(); 563 if (!Utils.equal(sSetting.getValue(), data)) { 564 pe.setValue(new StringSetting(data)); 565 ok = true; 566 } 567 } 568 } else if (rbList.isSelected()) { 569 ListSetting lSetting = new ListSetting(null); 570 pe = new PrefEntry(tkey.getText(), lSetting, lSetting, false); 571 ListEditor lEditor = new ListEditor(gui, pe, lSetting); 572 lEditor.showDialog(); 573 if (lEditor.getValue() == 1) { 574 List<String> data = lEditor.getData(); 575 if (!Preferences.equalCollection(lSetting.getValue(), data)) { 576 pe.setValue(new ListSetting(data)); 577 ok = true; 578 } 579 } 580 } else if (rbListList.isSelected()) { 581 ListListSetting llSetting = new ListListSetting(null); 582 pe = new PrefEntry(tkey.getText(), llSetting, llSetting, false); 583 ListListEditor llEditor = new ListListEditor(gui, pe, llSetting); 584 llEditor.showDialog(); 585 if (llEditor.getValue() == 1) { 586 List<List<String>> data = llEditor.getData(); 587 if (!Preferences.equalArray((Collection) llSetting.getValue(), data)) { 588 pe.setValue(new ListListSetting(data)); 589 ok = true; 590 } 591 } 592 } else if (rbMapList.isSelected()) { 593 MapListSetting mlSetting = new MapListSetting(null); 594 pe = new PrefEntry(tkey.getText(), mlSetting, mlSetting, false); 595 MapListEditor mlEditor = new MapListEditor(gui, pe, mlSetting); 596 mlEditor.showDialog(); 597 if (mlEditor.getValue() == 1) { 598 List<Map<String, String>> data = mlEditor.getData(); 599 if (!Preferences.equalListOfStructs(mlSetting.getValue(), data)) { 600 pe.setValue(new MapListSetting(data)); 601 ok = true; 602 } 603 } 604 } 605 if (ok) { 606 data.add(pe); 607 Collections.sort(data); 608 applyFilter(); 609 } 610 } 611 } 612 613 private void editPreference(final PreferenceTabbedPane gui, final JTable list) { 614 if (list.getSelectedRowCount() != 1) { 615 JOptionPane.showMessageDialog( 616 gui, 617 tr("Please select the row to edit."), 618 tr("Warning"), 619 JOptionPane.WARNING_MESSAGE 620 ); 621 return; 622 } 623 final PrefEntry e = (PrefEntry) model.getValueAt(list.getSelectedRow(), 1); 624 Setting stg = e.getValue(); 625 if (stg instanceof StringSetting) { 626 list.editCellAt(list.getSelectedRow(), 1); 627 Component editor = list.getEditorComponent(); 628 if (editor != null) { 629 editor.requestFocus(); 630 } 631 } else if (stg instanceof ListSetting) { 632 ListSetting lSetting = (ListSetting) stg; 633 ListEditor lEditor = new ListEditor(gui, e, lSetting); 634 lEditor.showDialog(); 635 if (lEditor.getValue() == 1) { 636 List<String> data = lEditor.getData(); 637 if (!Preferences.equalCollection(lSetting.getValue(), data)) { 638 e.setValue(new ListSetting(data)); 639 applyFilter(); 640 } 641 } 642 } else if (stg instanceof ListListSetting) { 643 ListListEditor llEditor = new ListListEditor(gui, e, (ListListSetting) stg); 644 llEditor.showDialog(); 645 if (llEditor.getValue() == 1) { 646 List<List<String>> data = llEditor.getData(); 647 if (!Preferences.equalArray((Collection) stg.getValue(), data)) { 648 e.setValue(new ListListSetting(data)); 649 applyFilter(); 650 } 651 } 652 } else if (stg instanceof MapListSetting) { 653 MapListSetting mlSetting = (MapListSetting) stg; 654 MapListEditor mlEditor = new MapListEditor(gui, e, mlSetting); 655 mlEditor.showDialog(); 656 if (mlEditor.getValue() == 1) { 657 List<Map<String, String>> data = mlEditor.getData(); 658 if (!Preferences.equalListOfStructs(mlSetting.getValue(), data)) { 659 e.setValue(new MapListSetting(data)); 660 applyFilter(); 661 } 662 } 663 } 664 } 665 }