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