001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.preferences.advanced; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.Dimension; 008import java.awt.GridBagLayout; 009import java.awt.event.ActionEvent; 010 011import javax.swing.AbstractAction; 012import javax.swing.AbstractListModel; 013import javax.swing.DefaultCellEditor; 014import javax.swing.JLabel; 015import javax.swing.JList; 016import javax.swing.JPanel; 017import javax.swing.JScrollPane; 018import javax.swing.JTable; 019import javax.swing.JToolBar; 020import javax.swing.event.ListSelectionEvent; 021import javax.swing.event.ListSelectionListener; 022import javax.swing.table.AbstractTableModel; 023import javax.swing.table.TableCellEditor; 024 025import org.openstreetmap.josm.gui.util.TableHelper; 026import org.openstreetmap.josm.gui.widgets.JosmTextField; 027import org.openstreetmap.josm.tools.GBC; 028import org.openstreetmap.josm.tools.ImageProvider; 029 030/** 031 * Abstract superclass of {@link ListListEditor} and {@link MapListEditor}. 032 * @param <T> type of elements 033 * @since 9505 034 */ 035public abstract class AbstractTableListEditor<T> extends AbstractListEditor<T> { 036 037 protected final AbstractEntryListModel entryModel; 038 protected final JList<String> entryList; 039 040 protected final JTable table; 041 protected final AbstractTableModel tableModel; 042 043 protected Integer entryIdx; 044 045 /** 046 * Constructs a new {@code AbstractListEditor}. 047 * @param parent The parent element that will be used for position and maximum size 048 * @param title The text that will be shown in the window titlebar 049 * @param entry Preference entry 050 */ 051 protected AbstractTableListEditor(Component parent, String title, PrefEntry entry) { 052 super(parent, title, entry); 053 entryModel = newEntryListModel(); 054 entryList = new JList<>(entryModel); 055 entryList.getSelectionModel().addListSelectionListener(new EntryListener()); 056 tableModel = newTableModel(); 057 table = new JTable(tableModel); 058 TableHelper.setFont(table, PreferencesTable.class); 059 setContent(build(), false); 060 } 061 062 protected abstract static class AbstractEntryListModel extends AbstractListModel<String> { 063 064 abstract void add(); 065 066 abstract void remove(int idx); 067 } 068 069 protected final class NewEntryAction extends AbstractAction { 070 NewEntryAction() { 071 putValue(NAME, tr("New")); 072 putValue(SHORT_DESCRIPTION, tr("add entry")); 073 new ImageProvider("dialogs", "add").getResource().attachImageIcon(this, true); 074 } 075 076 @Override 077 public void actionPerformed(ActionEvent evt) { 078 entryModel.add(); 079 } 080 } 081 082 protected final class RemoveEntryAction extends AbstractAction implements ListSelectionListener { 083 RemoveEntryAction() { 084 putValue(NAME, tr("Remove")); 085 putValue(SHORT_DESCRIPTION, tr("Remove the selected entry")); 086 new ImageProvider("dialogs", "delete").getResource().attachImageIcon(this, true); 087 updateEnabledState(); 088 } 089 090 private void updateEnabledState() { 091 setEnabled(entryList.getSelectedIndices().length == 1); 092 } 093 094 @Override 095 public void valueChanged(ListSelectionEvent e) { 096 updateEnabledState(); 097 } 098 099 @Override 100 public void actionPerformed(ActionEvent e) { 101 entryModel.remove(entryList.getSelectedIndices()[0]); 102 } 103 } 104 105 private class EntryListener implements ListSelectionListener { 106 @Override 107 public void valueChanged(ListSelectionEvent e) { 108 TableCellEditor editor = table.getCellEditor(); 109 if (editor != null) { 110 ((DefaultCellEditor) editor).stopCellEditing(); 111 } 112 if (entryList.getSelectedIndices().length != 1) { 113 entryIdx = null; 114 table.setEnabled(false); 115 } else { 116 entryIdx = entryList.getSelectedIndices()[0]; 117 table.setEnabled(true); 118 } 119 tableModel.fireTableStructureChanged(); 120 tableModel.fireTableDataChanged(); 121 } 122 } 123 124 @Override 125 protected JPanel build() { 126 JPanel p = new JPanel(new GridBagLayout()); 127 p.add(new JLabel(tr("Key: {0}", entry.getKey())), GBC.std(0, 0).span(2).weight(1, 0).insets(0, 0, 5, 10)); 128 129 JPanel left = new JPanel(new GridBagLayout()); 130 131 JScrollPane scroll = new JScrollPane(entryList); 132 left.add(scroll, GBC.eol().fill()); 133 134 JToolBar sideButtonTB = new JToolBar(JToolBar.HORIZONTAL); 135 sideButtonTB.setBorderPainted(false); 136 sideButtonTB.setOpaque(false); 137 sideButtonTB.add(new NewEntryAction()); 138 RemoveEntryAction removeEntryAction = new RemoveEntryAction(); 139 entryList.getSelectionModel().addListSelectionListener(removeEntryAction); 140 sideButtonTB.add(removeEntryAction); 141 left.add(sideButtonTB, GBC.eol()); 142 143 left.setPreferredSize(new Dimension(80, 0)); 144 145 p.add(left, GBC.std(0, 1).fill().weight(0.3, 1.0)); 146 147 table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); 148 149 DefaultCellEditor editor = new DefaultCellEditor(new JosmTextField()); 150 editor.setClickCountToStart(1); 151 table.setDefaultEditor(table.getColumnClass(0), editor); 152 153 JScrollPane pane = new JScrollPane(table); 154 pane.setPreferredSize(new Dimension(140, 0)); 155 p.add(pane, GBC.std(1, 1).insets(5, 0, 0, 0).fill().weight(0.7, 1.0)); 156 return p; 157 } 158 159 protected abstract AbstractEntryListModel newEntryListModel(); 160 161 protected abstract AbstractTableModel newTableModel(); 162}