001 // License: GPL. See LICENSE file for details. 002 package org.openstreetmap.josm.gui.preferences.advanced; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.Dimension; 007 import java.awt.GridBagLayout; 008 import java.awt.event.ActionEvent; 009 import java.util.ArrayList; 010 import java.util.Collections; 011 import java.util.List; 012 013 import javax.swing.AbstractAction; 014 import javax.swing.AbstractListModel; 015 import javax.swing.DefaultCellEditor; 016 import javax.swing.JLabel; 017 import javax.swing.JList; 018 import javax.swing.JPanel; 019 import javax.swing.JScrollPane; 020 import javax.swing.JTable; 021 import javax.swing.JTextField; 022 import javax.swing.JToolBar; 023 import javax.swing.event.ListSelectionEvent; 024 import javax.swing.event.ListSelectionListener; 025 import javax.swing.table.TableCellEditor; 026 import javax.swing.table.AbstractTableModel; 027 028 import org.openstreetmap.josm.data.Preferences.ListListSetting; 029 import org.openstreetmap.josm.gui.ExtendedDialog; 030 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; 031 import org.openstreetmap.josm.gui.preferences.advanced.AdvancedPreference.PrefEntry; 032 import org.openstreetmap.josm.tools.GBC; 033 import org.openstreetmap.josm.tools.ImageProvider; 034 import org.openstreetmap.josm.tools.WindowGeometry; 035 036 public class ListListEditor extends ExtendedDialog { 037 038 EntryListModel entryModel; 039 List<List<String>> data; 040 PrefEntry entry; 041 042 JList entryList; 043 Integer entryIdx; 044 JTable table; 045 046 ListTableModel tableModel; 047 048 public ListListEditor(final PreferenceTabbedPane gui, PrefEntry entry, ListListSetting setting) { 049 super(gui, tr("Change list of lists setting"), new String[] {tr("OK"), tr("Cancel")}); 050 this.entry = entry; 051 List<List<String>> orig = setting.getValue(); 052 data = new ArrayList<List<String>>(); 053 if (orig != null) { 054 for (List<String> l : orig) { 055 data.add(new ArrayList<String>(l)); 056 } 057 } 058 setButtonIcons(new String[] {"ok.png", "cancel.png"}); 059 setRememberWindowGeometry(getClass().getName() + ".geometry", WindowGeometry.centerInWindow(gui, new Dimension(500, 350))); 060 setContent(build(), false); 061 } 062 063 public List<List<String>> getData() { 064 return data; 065 } 066 067 protected JPanel build() { 068 JPanel p = new JPanel(new GridBagLayout()); 069 p.add(new JLabel(tr("Key: {0}", entry.getKey())), GBC.std(0,0).span(2).weight(1, 0).insets(0,0,5,10)); 070 071 JPanel left = new JPanel(new GridBagLayout()); 072 073 entryModel = new EntryListModel(); 074 entryList = new JList(entryModel); 075 entryList.getSelectionModel().addListSelectionListener(new EntryListener()); 076 JScrollPane scroll = new JScrollPane(entryList); 077 left.add(scroll, GBC.eol().fill()); 078 079 JToolBar sideButtonTB = new JToolBar(JToolBar.HORIZONTAL); 080 sideButtonTB.setBorderPainted(false); 081 sideButtonTB.setOpaque(false); 082 sideButtonTB.add(new NewEntryAction()); 083 RemoveEntryAction removeEntryAction = new RemoveEntryAction(); 084 entryList.getSelectionModel().addListSelectionListener(removeEntryAction); 085 sideButtonTB.add(removeEntryAction); 086 left.add(sideButtonTB, GBC.eol()); 087 088 left.setPreferredSize(new Dimension(80, 0)); 089 090 p.add(left, GBC.std(0,1).fill().weight(0.3, 1.0)); 091 092 tableModel = new ListTableModel(); 093 table = new JTable(tableModel); 094 table.putClientProperty("terminateEditOnFocusLost", true); 095 table.setTableHeader(null); 096 097 DefaultCellEditor editor = new DefaultCellEditor(new JTextField()); 098 editor.setClickCountToStart(1); 099 table.setDefaultEditor(table.getColumnClass(0), editor); 100 101 JScrollPane pane = new JScrollPane(table); 102 pane.setPreferredSize(new Dimension(140, 0)); 103 p.add(pane, GBC.std(1,1).insets(5,0,0,0).fill().weight(0.7, 1.0)); 104 return p; 105 } 106 107 class EntryListModel extends AbstractListModel { 108 public Object getElementAt(int index) { 109 return (index+1) + ": " + data.get(index).toString(); 110 } 111 112 public int getSize() { 113 return data.size(); 114 } 115 116 public void add(List<String> l) { 117 data.add(l); 118 fireIntervalAdded(this, data.size() - 1, data.size() - 1); 119 } 120 121 public void remove(int idx) { 122 data.remove(idx); 123 fireIntervalRemoved(this, idx, idx); 124 } 125 } 126 127 class NewEntryAction extends AbstractAction { 128 public NewEntryAction() { 129 putValue(NAME, tr("New")); 130 putValue(SHORT_DESCRIPTION, tr("add entry")); 131 putValue(SMALL_ICON, ImageProvider.get("dialogs", "add")); 132 } 133 134 public void actionPerformed(ActionEvent evt) { 135 entryModel.add(new ArrayList<String>()); 136 } 137 } 138 139 class RemoveEntryAction extends AbstractAction implements ListSelectionListener { 140 public RemoveEntryAction() { 141 putValue(NAME, tr("Remove")); 142 putValue(SHORT_DESCRIPTION, tr("Remove the selected entry")); 143 putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete")); 144 updateEnabledState(); 145 } 146 147 protected void updateEnabledState() { 148 setEnabled(entryList.getSelectedIndices().length == 1); 149 } 150 151 public void valueChanged(ListSelectionEvent e) { 152 updateEnabledState(); 153 } 154 155 public void actionPerformed(ActionEvent e) { 156 int idx = entryList.getSelectedIndices()[0]; 157 entryModel.remove(idx); 158 } 159 } 160 161 class EntryListener implements ListSelectionListener { 162 public void valueChanged(ListSelectionEvent e) { 163 TableCellEditor editor = table.getCellEditor(); 164 if (editor != null) { 165 ((DefaultCellEditor) editor).stopCellEditing(); 166 } 167 if (entryList.getSelectedIndices().length != 1) { 168 entryIdx = null; 169 table.setEnabled(false); 170 } else { 171 entryIdx = entryList.getSelectedIndices()[0]; 172 table.setEnabled(true); 173 } 174 tableModel.fireTableStructureChanged(); 175 } 176 } 177 178 class ListTableModel extends AbstractTableModel { 179 180 private List<String> data() { 181 if (entryIdx == null) return Collections.emptyList(); 182 return data.get(entryIdx); 183 } 184 185 @Override 186 public int getRowCount() { 187 return entryIdx == null ? 0 : data().size() + 1; 188 } 189 190 @Override 191 public int getColumnCount() { 192 return 1; 193 } 194 195 @Override 196 public Object getValueAt(int row, int column) { 197 return data().size() == row ? "" : data().get(row); 198 } 199 200 @Override 201 public void setValueAt(Object o, int row, int column) { 202 String s = (String)o; 203 if (row == data().size()) { 204 data().add(s); 205 fireTableRowsInserted(row+1, row+1); 206 } else { 207 data().set(row, s); 208 } 209 fireTableCellUpdated(row, column); 210 } 211 212 @Override 213 public boolean isCellEditable(int row, int column) { 214 return true; 215 } 216 } 217 218 }