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.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009
010import javax.swing.JComponent;
011import javax.swing.JPanel;
012import javax.swing.table.AbstractTableModel;
013
014import org.openstreetmap.josm.spi.preferences.ListListSetting;
015
016/**
017 * Editor for List of Lists preference entries.
018 * @since 4634
019 */
020public class ListListEditor extends AbstractTableListEditor<List<String>> {
021
022    private final transient List<List<String>> data;
023
024    /**
025     * Constructs a new {@code ListListEditor}.
026     * @param gui The parent component
027     * @param entry preference entry
028     * @param setting list of lists setting
029     */
030    public ListListEditor(final JComponent gui, PrefEntry entry, ListListSetting setting) {
031        super(gui, tr("Change list of lists setting"), entry);
032        List<List<String>> orig = setting.getValue();
033        data = new ArrayList<>();
034        if (orig != null) {
035            for (List<String> l : orig) {
036                data.add(new ArrayList<>(l));
037            }
038        }
039    }
040
041    @Override
042    public List<List<String>> getData() {
043        return data;
044    }
045
046    @Override
047    protected final JPanel build() {
048        table.setTableHeader(null);
049        return super.build();
050    }
051
052    private class EntryListModel extends AbstractEntryListModel {
053
054        @Override
055        public String getElementAt(int index) {
056            return (index+1) + ": " + data.get(index);
057        }
058
059        @Override
060        public int getSize() {
061            return data.size();
062        }
063
064        @Override
065        public void add() {
066            data.add(new ArrayList<String>());
067            fireIntervalAdded(this, getSize() - 1, getSize() - 1);
068        }
069
070        @Override
071        public void remove(int idx) {
072            data.remove(idx);
073            fireIntervalRemoved(this, idx, idx);
074        }
075    }
076
077    private class ListTableModel extends AbstractTableModel {
078
079        private List<String> data() {
080            return entryIdx == null ? Collections.<String>emptyList() : data.get(entryIdx);
081        }
082
083        private int size() {
084            return data().size();
085        }
086
087        @Override
088        public int getRowCount() {
089            return entryIdx == null ? 0 : size() + 1;
090        }
091
092        @Override
093        public int getColumnCount() {
094            return 1;
095        }
096
097        @Override
098        public Object getValueAt(int row, int column) {
099            return size() == row ? "" : data().get(row);
100        }
101
102        @Override
103        public void setValueAt(Object o, int row, int column) {
104            String s = (String) o;
105            if (row == size()) {
106                data().add(s);
107                fireTableRowsInserted(row+1, row+1);
108            } else {
109                data().set(row, s);
110                fireTableCellUpdated(row, column);
111            }
112        }
113
114        @Override
115        public boolean isCellEditable(int row, int column) {
116            return true;
117        }
118    }
119
120    @Override
121    protected AbstractEntryListModel newEntryListModel() {
122        return new EntryListModel();
123    }
124
125    @Override
126    protected AbstractTableModel newTableModel() {
127        return new ListTableModel();
128    }
129}