Changeset 13734 in josm


Ignore:
Timestamp:
2018-05-12T14:19:28+02:00 (5 weeks ago)
Author:
wiktorn
Message:

GUI for imagery definitions refactor

Extend preferences panel by:

  • allowing setting default layers for WMS / WMTS
  • allowing setting minimum expires (expert mode)
  • allowing setting custom headers (expert mode)

See: #15981, #7953, #16224, #15940, #16249

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddImageryPanel.java

    r12530 r13734  
    22package org.openstreetmap.josm.gui.preferences.imagery;
    33
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
    46import java.awt.GridBagLayout;
    57import java.awt.LayoutManager;
     8import java.awt.event.ItemEvent;
    69import java.util.ArrayList;
     10import java.util.Arrays;
    711import java.util.Collection;
     12import java.util.List;
     13import java.util.Map;
     14import java.util.concurrent.TimeUnit;
    815
    916import javax.swing.AbstractButton;
     17import javax.swing.JCheckBox;
     18import javax.swing.JComboBox;
     19import javax.swing.JLabel;
    1020import javax.swing.JPanel;
     21import javax.swing.JSpinner;
     22import javax.swing.SpinnerNumberModel;
    1123import javax.swing.event.DocumentEvent;
    1224import javax.swing.event.DocumentListener;
    1325import javax.swing.text.JTextComponent;
    1426
     27import org.openstreetmap.josm.actions.ExpertToggleAction;
    1528import org.openstreetmap.josm.data.imagery.ImageryInfo;
    1629import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
     30import org.openstreetmap.josm.data.imagery.TMSCachedTileLoaderJob;
    1731import org.openstreetmap.josm.gui.widgets.JosmTextArea;
    1832import org.openstreetmap.josm.gui.widgets.JosmTextField;
     33import org.openstreetmap.josm.tools.GBC;
     34import org.openstreetmap.josm.tools.Logging;
    1935
    2036/**
     
    3147
    3248    protected final transient Collection<ContentValidationListener> listeners = new ArrayList<>();
     49
     50    private final JCheckBox validGeoreference= new JCheckBox(tr("Is layer properly georeferenced?"));
     51    private HeadersTable headersTable;
     52    private JSpinner minimumCacheExpiry;
     53    private JComboBox<String> minimumCacheExpiryUnit;
     54    private TimeUnit currentUnit;
     55
    3356
    3457    /**
     
    4770    protected AddImageryPanel() {
    4871        this(new GridBagLayout());
     72        headersTable = new HeadersTable();
     73        minimumCacheExpiry = new JSpinner(new SpinnerNumberModel(
     74                (Number)TimeUnit.MILLISECONDS.toSeconds(TMSCachedTileLoaderJob.MINIMUM_EXPIRES.get()),
     75                0L,
     76                Long.valueOf(Integer.MAX_VALUE),
     77                1
     78                ));
     79        List<String> units = Arrays.asList(new String[]{tr("seconds"), tr("minutes"), tr("hours"), tr("days")});
     80        minimumCacheExpiryUnit = new JComboBox<>(units.toArray(new String[]{}));
     81        currentUnit = TimeUnit.SECONDS;
     82        minimumCacheExpiryUnit.addItemListener(e -> {
     83            if (e.getStateChange() == ItemEvent.SELECTED) {
     84                long newValue = 0;
     85                switch (units.indexOf(e.getItem())) {
     86                case 0:
     87                    newValue = currentUnit.toSeconds((long) minimumCacheExpiry.getValue());
     88                    currentUnit = TimeUnit.SECONDS;
     89                    break;
     90                case 1:
     91                    newValue = currentUnit.toMinutes((long) minimumCacheExpiry.getValue());
     92                    currentUnit = TimeUnit.MINUTES;
     93                    break;
     94                case 2:
     95                    newValue = currentUnit.toHours((long) minimumCacheExpiry.getValue());
     96                    currentUnit = TimeUnit.HOURS;
     97                    break;
     98                case 3:
     99                    newValue = currentUnit.toDays((long) minimumCacheExpiry.getValue());
     100                    currentUnit = TimeUnit.DAYS;
     101                    break;
     102                default:
     103                    Logging.warn("Dupa: " + units.indexOf(e.getItem()));
     104                }
     105                minimumCacheExpiry.setValue(newValue);
     106            }
     107        });
     108
     109
     110    }
     111
     112    protected void addCommonSettings() {
     113        if (ExpertToggleAction.isExpert()) {
     114            add(new JLabel(tr("Minimum cache expiry: ")));
     115            add(minimumCacheExpiry);
     116            add(minimumCacheExpiryUnit, GBC.eol());
     117            add(new JLabel(tr("Set custom HTTP headers (if needed):")), GBC.eop());
     118            add(headersTable, GBC.eol().fill());
     119            add(validGeoreference, GBC.eop().fill());
     120        }
     121    }
     122
     123    protected Map<String, String> getCommonHeaders() {
     124        return headersTable.getHeaders();
     125    }
     126
     127    protected boolean getCommonIsValidGeoreference() {
     128        return validGeoreference.isSelected();
    49129    }
    50130
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java

    r13591 r13734  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.awt.event.ActionListener;
    67import java.io.IOException;
    78import java.net.MalformedURLException;
    8 import java.net.URL;
     9import java.util.Collection;
    910import java.util.List;
     11import java.util.stream.Collectors;
    1012
    1113import javax.swing.DefaultComboBoxModel;
     
    1719import javax.swing.JScrollPane;
    1820
     21import org.openstreetmap.josm.data.imagery.DefaultLayer;
    1922import org.openstreetmap.josm.data.imagery.ImageryInfo;
    2023import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
     
    3336public class AddWMSLayerPanel extends AddImageryPanel {
    3437
    35     private final transient WMSImagery wms = new WMSImagery();
     38    private transient WMSImagery wms;
    3639    private final JCheckBox endpoint = new JCheckBox(tr("Store WMS endpoint only, select layers at usage"));
     40    private final JCheckBox setDefaultLayers = new JCheckBox(tr("Use selected layers as default"));
    3741    private final transient WMSLayerTree tree = new WMSLayerTree();
    3842    private final JComboBox<String> formats = new JComboBox<>();
     
    5458
    5559        add(new JLabel(tr("{0} Select layers", "4.")), GBC.eol());
     60
    5661        add(endpoint, GBC.eol().fill());
     62        setDefaultLayers.setEnabled(false);
     63        add(setDefaultLayers, GBC.eol().fill());
    5764        add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));
    5865
     
    6269        add(new JLabel(tr("{0} Select image format", "5.")), GBC.eol());
    6370        add(formats, GBC.eol().fill());
     71
     72        addCommonSettings();
    6473
    6574        wmsInstruction = new JLabel(tr("{0} Edit generated {1} URL (optional)", "6.", "WMS"));
     
    7483        getLayers.addActionListener(e -> {
    7584            try {
    76                 wms.attemptGetCapabilities(rawUrl.getText());
     85                wms = new WMSImagery(rawUrl.getText(), getCommonHeaders());
    7786                tree.updateTree(wms);
    78                 List<String> wmsFormats = wms.getFormats();
    79                 formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[0])));
    80                 formats.setSelectedItem(wms.getPreferredFormats());
     87                Collection<String> wmsFormats = wms.getFormats();
     88                formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[wmsFormats.size()])));
     89                formats.setSelectedItem(wms.getPreferredFormat());
    8190            } catch (MalformedURLException ex1) {
    8291                Logging.log(Logging.LEVEL_ERROR, ex1);
     
    104113        });
    105114
    106         endpoint.addItemListener(e -> {
    107             tree.getLayerTree().setEnabled(!endpoint.isSelected());
    108             showBounds.setEnabled(!endpoint.isSelected());
    109             wmsInstruction.setEnabled(!endpoint.isSelected());
    110             formats.setEnabled(!endpoint.isSelected());
    111             wmsUrl.setEnabled(!endpoint.isSelected());
    112             if (endpoint.isSelected()) {
    113                 URL url = wms.getServiceUrl();
    114                 if (url != null) {
    115                     name.setText(url.getHost());
    116                 }
    117             } else {
    118                 onLayerSelectionChanged();
    119             }
    120         });
     115        ActionListener availabilityManagerAction = a -> {
     116            setDefaultLayers.setEnabled(endpoint.isSelected());
     117            boolean enabled = !endpoint.isSelected() || setDefaultLayers.isSelected();
     118            tree.getLayerTree().setEnabled(enabled);
     119            showBounds.setEnabled(enabled);
     120            wmsInstruction.setEnabled(enabled);
     121            formats.setEnabled(enabled);
     122            wmsUrl.setEnabled(enabled);
     123            if (endpoint.isSelected() && !setDefaultLayers.isSelected() && wms != null) {
     124                name.setText(wms.buildRootUrl());
     125            }
     126            onLayerSelectionChanged();
     127        };
     128
     129        endpoint.addActionListener(availabilityManagerAction);
     130        setDefaultLayers.addActionListener(availabilityManagerAction);
    121131
    122132        tree.getLayerTree().addPropertyChangeListener("selectedLayers", evt -> onLayerSelectionChanged());
     
    125135
    126136        showBounds.addActionListener(e -> {
    127             if (tree.getSelectedLayers().get(0).bounds != null) {
     137            if (tree.getSelectedLayers().get(0).getBounds() != null) {
    128138                SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
    129                 mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds);
     139                mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).getBounds());
    130140                JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
    131141            } else {
     
    141151
    142152    protected final void onLayerSelectionChanged() {
    143         if (wms.getServiceUrl() != null) {
    144             wmsUrl.setText(wms.buildGetMapUrl(tree.getSelectedLayers(), (String) formats.getSelectedItem()));
    145             name.setText(wms.getServiceUrl().getHost() + ": " + Utils.join(", ", tree.getSelectedLayers()));
     153        if (wms != null && wms.buildRootUrl() != null) {
     154            wmsUrl.setText(wms.buildGetMapUrl(
     155                    tree.getSelectedLayers().stream().map(x -> x.getName()).collect(Collectors.toList()),
     156                    (List<String>) null,
     157                    (String) formats.getSelectedItem(),
     158                    true // TODO: ask user about transparency
     159                )
     160            );
     161            name.setText(wms.buildRootUrl() + ": " + Utils.join(", ", tree.getSelectedLayers()));
    146162        }
    147163        showBounds.setEnabled(tree.getSelectedLayers().size() == 1);
     
    150166    @Override
    151167    public ImageryInfo getImageryInfo() {
    152         final ImageryInfo info;
     168        ImageryInfo info = null;
    153169        if (endpoint.isSelected()) {
    154170            info = new ImageryInfo(getImageryName(), getImageryRawUrl());
    155171            info.setImageryType(ImageryInfo.ImageryType.WMS_ENDPOINT);
     172            if (setDefaultLayers.isSelected()) {
     173                info.setDefaultLayers(tree.getSelectedLayers().stream()
     174                        .map(x -> new DefaultLayer(
     175                                ImageryInfo.ImageryType.WMS_ENDPOINT,
     176                                x.getName(),
     177                                "", // TODO: allow selection of styles
     178                                ""))
     179                        .collect(Collectors.toList()));
     180                info.setServerProjections(wms.getServerProjections(tree.getSelectedLayers()));
     181            }
    156182        } else {
    157             info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers());
     183            info = wms.toImageryInfo(getImageryName(), tree.getSelectedLayers(), (List<String>) null, true); // TODO: ask user about transparency
    158184            info.setUrl(getWmsUrl());
    159185            info.setImageryType(ImageryType.WMS);
    160186        }
     187        info.setGeoreferenceValid(getCommonIsValidGeoreference());
     188        info.setCustomHttpHeaders(getCommonHeaders());
    161189        return info;
    162190    }
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMTSLayerPanel.java

    r13591 r13734  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.awt.Dimension;
     7import java.awt.GridBagLayout;
    68import java.io.IOException;
     9import java.util.Collections;
     10import java.util.List;
     11import java.util.Map.Entry;
    712
     13import javax.swing.JButton;
     14import javax.swing.JCheckBox;
    815import javax.swing.JLabel;
     16import javax.swing.JOptionPane;
     17import javax.swing.JPanel;
     18import javax.swing.JScrollPane;
     19import javax.swing.JTable;
    920
     21import org.openstreetmap.josm.data.imagery.DefaultLayer;
    1022import org.openstreetmap.josm.data.imagery.ImageryInfo;
    1123import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
     24import org.openstreetmap.josm.data.imagery.WMTSCapabilities;
    1225import org.openstreetmap.josm.data.imagery.WMTSTileSource;
     26import org.openstreetmap.josm.data.imagery.WMTSTileSource.Layer;
     27import org.openstreetmap.josm.data.imagery.WMTSTileSource.WMTSGetCapabilitiesException;
    1328import org.openstreetmap.josm.tools.GBC;
     29import org.openstreetmap.josm.tools.Logging;
    1430
    1531/**
     
    1935 */
    2036public class AddWMTSLayerPanel extends AddImageryPanel {
     37    private final transient JPanel layerPanel = new JPanel(new GridBagLayout());
     38    private transient JTable layerTable = null;
     39    private final JCheckBox setDefaultLayer = new JCheckBox(tr("Set default layer?"));
     40    private List<Entry<String, List<Layer>>> layers;
    2141
    2242    /**
     
    2949        rawUrl.setLineWrap(true);
    3050        rawUrl.setAlignmentY(TOP_ALIGNMENT);
     51        JButton getLayers = new JButton(tr("Get layers"));
     52        getLayers.setEnabled(setDefaultLayer.isSelected());
     53        setDefaultLayer.addActionListener(e -> {
     54                getLayers.setEnabled(setDefaultLayer.isSelected());
     55        });
     56        add(setDefaultLayer, GBC.eop().fill());
     57        add(getLayers, GBC.eop().fill());
     58        add(new JLabel(tr("Choose default layer")), GBC.eol().fill());
     59        layerPanel.setPreferredSize(new Dimension(250, 100));
     60        add(layerPanel, GBC.eol().fill());
     61
     62        addCommonSettings();
     63
    3164        add(new JLabel(tr("{0} Enter name for this layer", "3.")), GBC.eol());
    3265        add(name, GBC.eol().fill(GBC.HORIZONTAL));
    3366        registerValidableComponent(rawUrl);
     67
     68        getLayers.addActionListener(e -> {
     69            try {
     70                WMTSCapabilities capabilities = WMTSTileSource.getCapabilities(rawUrl.getText(), getCommonHeaders());
     71                layers = WMTSTileSource.groupLayersByNameAndTileMatrixSet(capabilities.getLayers());
     72                layerTable = WMTSTileSource.getLayerSelectionPanel(layers);
     73                layerPanel.removeAll();
     74                JScrollPane scrollPane = new JScrollPane(layerTable);
     75                scrollPane.setPreferredSize(new Dimension(100, 100));
     76                layerPanel.add(scrollPane, GBC.eol().fill());
     77                layerPanel.revalidate();
     78            } catch (Exception ex) {
     79                JOptionPane.showMessageDialog(
     80                        getParent(),
     81                        tr("Error getting layers: {0}", ex.getMessage()),
     82                        tr("WMTS Error"),
     83                        JOptionPane.ERROR_MESSAGE);
     84            }
     85        });
    3486    }
    3587
     
    3789    protected ImageryInfo getImageryInfo() {
    3890        ImageryInfo ret = new ImageryInfo(getImageryName(), "wmts:" + sanitize(getImageryRawUrl(), ImageryType.WMTS));
     91        if (setDefaultLayer.isSelected()) {
     92            if (layerTable == null) {
     93                // did not call get capabilities
     94                throw new RuntimeException("TODO");
     95            }
     96            int index = layerTable.getSelectedRow();
     97            if (index < 0) {
     98                throw new RuntimeException("TODO");
     99            }
     100            Layer selectedLayer = layers.get(layerTable.convertRowIndexToModel(index)).getValue().get(0);
     101            ret.setDefaultLayers(
     102                    Collections.<DefaultLayer> singletonList(
     103                            new DefaultLayer(
     104                                    ImageryType.WMTS,
     105                                    selectedLayer.getIdentifier(),
     106                                    selectedLayer.getStyle(),
     107                                    selectedLayer.getTileMatrixSet().getIdentifier()
     108                                    )
     109                            )
     110                    );
     111        }
     112        ret.setCustomHttpHeaders(getCommonHeaders());
     113        ret.setGeoreferenceValid(getCommonIsValidGeoreference());
    39114        ret.setImageryType(ImageryType.WMTS);
    40115        try {
    41116            new WMTSTileSource(ret); // check if constructor throws an error
    42         } catch (IOException e) {
     117        } catch (IOException | WMTSGetCapabilitiesException e) {
     118            Logging.warn(e);
    43119            throw new IllegalArgumentException(e); // if so, wrap exception, so proper message will be shown to the user
    44120        }
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/WMSLayerTree.java

    r8840 r13734  
    22package org.openstreetmap.josm.gui.preferences.imagery;
    33
    4 import static org.openstreetmap.josm.tools.I18n.tr;
    5 
    64import java.awt.Component;
     5import java.util.Collection;
    76import java.util.LinkedList;
    87import java.util.List;
    98
    10 import javax.swing.JOptionPane;
    119import javax.swing.JTree;
    1210import javax.swing.event.TreeSelectionEvent;
     
    1816import javax.swing.tree.TreePath;
    1917
     18import org.openstreetmap.josm.data.imagery.LayerDetails;
    2019import org.openstreetmap.josm.io.imagery.WMSImagery;
    2120
     
    2726    private final DefaultTreeModel treeData = new DefaultTreeModel(treeRootNode);
    2827    private final JTree layerTree = new JTree(treeData);
    29     private final List<WMSImagery.LayerDetails> selectedLayers = new LinkedList<>();
    30     private boolean previouslyShownUnsupportedCrsError;
     28    private final List<LayerDetails> selectedLayers = new LinkedList<>();
    3129
    3230    /**
     
    5048     * @return the list of selected layers
    5149     */
    52     public List<WMSImagery.LayerDetails> getSelectedLayers() {
     50    public List<LayerDetails> getSelectedLayers() {
    5351        return selectedLayers;
    5452    }
     
    6260    }
    6361
    64     void addLayersToTreeData(MutableTreeNode parent, List<WMSImagery.LayerDetails> layers) {
    65         for (WMSImagery.LayerDetails layerDetails : layers) {
     62    void addLayersToTreeData(MutableTreeNode parent, Collection<LayerDetails> layers) {
     63        for (LayerDetails layerDetails : layers.stream()
     64                .sorted((l1, l2) -> -1 * l1.toString().compareTo(l2.toString()))
     65                .toArray(LayerDetails[]::new)
     66                ) {
    6667            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
    67             addLayersToTreeData(treeNode, layerDetails.children);
     68            addLayersToTreeData(treeNode, layerDetails.getChildren());
    6869            treeData.insertNodeInto(treeNode, parent, 0);
    6970        }
     
    7172
    7273    /**
    73      * Updates the whole tree with the given WMS imagery info.
     74     * Updates the whole tree with the given WMS imagery info. All previous content is removed
    7475     * @param wms The imagery info for a given WMS server
    7576     */
    7677    public void updateTree(WMSImagery wms) {
    77         treeRootNode.setUserObject(wms.getServiceUrl().getHost());
     78        // treeRootNode = new DefaultMutableTreeNode();
     79        while (treeRootNode.getChildCount() > 0) {
     80            treeRootNode.remove(0);
     81        }
     82        treeRootNode.setUserObject(wms.buildRootUrl());
    7883        updateTreeList(wms.getLayers());
    7984    }
     
    8388     * @param layers The list of layers to add to the root node
    8489     */
    85     public void updateTreeList(List<WMSImagery.LayerDetails> layers) {
     90    public void updateTreeList(Collection<LayerDetails> layers) {
    8691        addLayersToTreeData(getTreeRootNode(), layers);
    8792        getLayerTree().expandRow(0);
     
    98103            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
    99104            Object userObject = treeNode.getUserObject();
    100             if (userObject instanceof WMSImagery.LayerDetails) {
    101                 WMSImagery.LayerDetails layer = (WMSImagery.LayerDetails) userObject;
    102                 setEnabled(layer.isSupported());
     105            if (userObject instanceof LayerDetails) {
     106                LayerDetails ld = (LayerDetails) userObject;
     107                setEnabled(ld.isSelectable());
    103108            }
    104109            return this;
     
    118123            for (TreePath i : selectionRows) {
    119124                Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
    120                 if (userObject instanceof WMSImagery.LayerDetails) {
    121                     WMSImagery.LayerDetails detail = (WMSImagery.LayerDetails) userObject;
    122                     if (!detail.isSupported()) {
    123                         layerTree.removeSelectionPath(i);
    124                         if (!previouslyShownUnsupportedCrsError) {
    125                             JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM''s projections,\n" +
    126                                     "so you can not use it. This message will not show again."),
    127                                     tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
    128                             previouslyShownUnsupportedCrsError = true;
    129                         }
    130                     } else if (detail.ident != null) {
     125                if (userObject instanceof LayerDetails) {
     126                    LayerDetails detail = (LayerDetails) userObject;
     127                    if (detail.isSelectable()) {
    131128                        selectedLayers.add(detail);
    132129                    }
  • trunk/test/unit/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanelTest.java

    r10977 r13734  
    22package org.openstreetmap.josm.gui.preferences.imagery;
    33
    4 import static org.junit.Assert.assertEquals;
    54import static org.junit.Assert.assertFalse;
    65
     
    2120    @Rule
    2221    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
    23     public JOSMTestRules test = new JOSMTestRules().preferences();
     22    public JOSMTestRules test = new JOSMTestRules().platform().preferences();
    2423
    2524    /**
     
    2928    public void testAddWMSLayerPanel() {
    3029        AddWMSLayerPanel panel = new AddWMSLayerPanel();
    31         assertEquals("", panel.getImageryInfo().getUrl());
    3230        assertFalse(panel.isImageryValid());
    3331    }
Note: See TracChangeset for help on using the changeset viewer.