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