001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer.imagery;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.awt.GridBagLayout;
008import java.util.List;
009import java.util.Map.Entry;
010import java.util.stream.Collectors;
011
012import javax.swing.JLabel;
013import javax.swing.JPanel;
014import javax.swing.JScrollPane;
015import javax.swing.JTable;
016import javax.swing.ListSelectionModel;
017import javax.swing.RowFilter;
018import javax.swing.event.DocumentEvent;
019import javax.swing.event.DocumentListener;
020import javax.swing.table.AbstractTableModel;
021import javax.swing.table.TableCellRenderer;
022import javax.swing.table.TableColumn;
023import javax.swing.table.TableRowSorter;
024
025import org.openstreetmap.josm.data.imagery.WMTSTileSource.Layer;
026import org.openstreetmap.josm.gui.util.TableHelper;
027import org.openstreetmap.josm.gui.widgets.JosmTextArea;
028import org.openstreetmap.josm.tools.GBC;
029
030/**
031 * Class for displaying WMTS layer selection panel.
032 * @since 13748
033 */
034public class WMTSLayerSelection extends JPanel {
035    private static final class AbstractTableModelExtension extends AbstractTableModel {
036        private final List<Entry<String, List<Layer>>> layers;
037
038        private AbstractTableModelExtension(List<Entry<String, List<Layer>>> layers) {
039            this.layers = layers;
040        }
041
042        @Override
043        public Object getValueAt(int rowIndex, int columnIndex) {
044            switch (columnIndex) {
045            case 0:
046                return layers.get(rowIndex).getValue()
047                        .stream()
048                        .map(Layer::getUserTitle)
049                        .collect(Collectors.joining(", ")); //this should be only one
050            case 1:
051                return layers.get(rowIndex).getValue()
052                        .stream()
053                        .map(x -> x.getTileMatrixSet().getCrs())
054                        .collect(Collectors.joining(", "));
055            case 2:
056                return layers.get(rowIndex).getValue()
057                        .stream()
058                        .map(x -> x.getTileMatrixSet().getIdentifier())
059                        .collect(Collectors.joining(", ")); //this should be only one
060            default:
061                throw new IllegalArgumentException();
062            }
063        }
064
065        @Override
066        public int getRowCount() {
067            return layers.size();
068        }
069
070        @Override
071        public int getColumnCount() {
072            return 3;
073        }
074
075        @Override
076        public String getColumnName(int column) {
077            switch (column) {
078            case 0: return tr("Layer name");
079            case 1: return tr("Projection");
080            case 2: return tr("Matrix set identifier");
081            default:
082                throw new IllegalArgumentException();
083            }
084        }
085    }
086
087    private final List<Entry<String, List<Layer>>> layers;
088    private final JTable list;
089
090    /**
091     * Constructs a new {@code WMTSLayerSelection}.
092     * @param layers list of grouped layers (by tileMatrixSet and name)
093     */
094    public WMTSLayerSelection(List<Entry<String, List<Layer>>> layers) {
095        super(new GridBagLayout());
096        this.layers = layers;
097        list = new JTable(
098                new AbstractTableModelExtension(layers));
099        TableHelper.setFont(list, getClass());
100        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
101        list.setAutoCreateRowSorter(true);
102        list.setRowSelectionAllowed(true);
103        list.setColumnSelectionAllowed(false);
104        updateColumnPreferredWidth(list.getColumnModel().getColumn(0));
105        updateColumnPreferredWidth(list.getColumnModel().getColumn(1));
106        updateColumnPreferredWidth(list.getColumnModel().getColumn(2));
107
108        add(new JLabel(tr("Filter layers:")), GBC.eol().fill(GBC.HORIZONTAL));
109        final JosmTextArea filter = new JosmTextArea();
110        filter.getDocument().addDocumentListener(new DocumentListener() {
111            @Override
112            public void insertUpdate(DocumentEvent e) {
113                update();
114            }
115
116            @Override
117            public void removeUpdate(DocumentEvent e) {
118                update();
119            }
120
121            @Override
122            public void changedUpdate(DocumentEvent e) {
123                update();
124            }
125
126            @SuppressWarnings({ "unchecked", "rawtypes" })
127            private void update() {
128                ((TableRowSorter) list.getRowSorter()).setRowFilter(RowFilter.regexFilter("(?i)" + filter.getText()));
129            }
130
131        });
132        add(filter, GBC.eop().fill(GBC.HORIZONTAL));
133        add(new JScrollPane(this.list), GBC.eol().fill());
134    }
135
136    /**
137     * Returns selected layer.
138     * @return selected layer
139     */
140    public Layer getSelectedLayer() {
141        int index = list.getSelectedRow();
142        if (index < 0) {
143            return null; //nothing selected
144        }
145        return layers.get(list.convertRowIndexToModel(index)).getValue().get(0);
146    }
147
148    private void updateColumnPreferredWidth(TableColumn column) {
149        TableCellRenderer renderer = column.getHeaderRenderer();
150        if (renderer == null) {
151            renderer = list.getTableHeader().getDefaultRenderer();
152        }
153        Component comp = renderer.getTableCellRendererComponent(list, column.getHeaderValue(), false, false, 0, 0);
154        int ret = comp.getPreferredSize().width;
155
156        for (int row = 0; row < list.getRowCount(); row++) {
157            renderer = list.getCellRenderer(row, column.getModelIndex());
158            comp = list.prepareRenderer(renderer, row, column.getModelIndex());
159            ret = Math.max(comp.getPreferredSize().width, ret);
160        }
161        column.setPreferredWidth(ret + 10);
162    }
163
164    /**
165     * Returns the list of layers.
166     * @return the list of layers
167     */
168    public JTable getTable() {
169        return list;
170    }
171}