001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.imagery;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.util.LinkedList;
008import java.util.List;
009
010import javax.swing.JOptionPane;
011import javax.swing.JTree;
012import javax.swing.event.TreeSelectionEvent;
013import javax.swing.event.TreeSelectionListener;
014import javax.swing.tree.DefaultMutableTreeNode;
015import javax.swing.tree.DefaultTreeCellRenderer;
016import javax.swing.tree.DefaultTreeModel;
017import javax.swing.tree.MutableTreeNode;
018import javax.swing.tree.TreePath;
019
020import org.openstreetmap.josm.io.imagery.WMSImagery;
021
022public class WMSLayerTree {
023    private final MutableTreeNode treeRootNode = new DefaultMutableTreeNode();
024    private final DefaultTreeModel treeData = new DefaultTreeModel(treeRootNode);
025    private final JTree layerTree = new JTree(treeData);
026    private final List<WMSImagery.LayerDetails> selectedLayers = new LinkedList<WMSImagery.LayerDetails>();
027    private boolean previouslyShownUnsupportedCrsError = false;
028
029    public MutableTreeNode getTreeRootNode() {
030        return treeRootNode;
031    }
032
033    public JTree getLayerTree() {
034        return layerTree;
035    }
036
037    public List<WMSImagery.LayerDetails> getSelectedLayers() {
038        return selectedLayers;
039    }
040
041    /**
042     * Constructs a new {@code WMSLayerTree}.
043     */
044    public WMSLayerTree() {
045        layerTree.setCellRenderer(new LayerTreeCellRenderer());
046        layerTree.addTreeSelectionListener(new WMSTreeSelectionListener());
047    }
048
049    void addLayersToTreeData(MutableTreeNode parent, List<WMSImagery.LayerDetails> layers) {
050        for (WMSImagery.LayerDetails layerDetails : layers) {
051            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
052            addLayersToTreeData(treeNode, layerDetails.children);
053            treeData.insertNodeInto(treeNode, parent, 0);
054        }
055    }
056
057    public void updateTree(WMSImagery wms) {
058        treeRootNode.setUserObject(wms.getServiceUrl().getHost());
059        updateTreeList(wms.getLayers());
060    }
061
062    public void updateTreeList(List<WMSImagery.LayerDetails> layers) {
063        addLayersToTreeData(getTreeRootNode(), layers);
064        getLayerTree().expandRow(0);
065        getLayerTree().expandRow(1);
066    }
067
068    private static class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
069        @Override
070        public Component getTreeCellRendererComponent(JTree tree, Object value,
071                                                      boolean sel, boolean expanded, boolean leaf, int row,
072                                                      boolean hasFocus) {
073            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
074                    row, hasFocus);
075            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
076            Object userObject = treeNode.getUserObject();
077            if (userObject instanceof WMSImagery.LayerDetails) {
078                WMSImagery.LayerDetails layer = (WMSImagery.LayerDetails) userObject;
079                setEnabled(layer.isSupported());
080            }
081            return this;
082        }
083    }
084
085    private class WMSTreeSelectionListener implements TreeSelectionListener {
086
087        @Override
088        public void valueChanged(TreeSelectionEvent e) {
089            TreePath[] selectionRows = layerTree.getSelectionPaths();
090            if (selectionRows == null) {
091                return;
092            }
093
094            selectedLayers.clear();
095            for (TreePath i : selectionRows) {
096                Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
097                if (userObject instanceof WMSImagery.LayerDetails) {
098                    WMSImagery.LayerDetails detail = (WMSImagery.LayerDetails) userObject;
099                    if (!detail.isSupported()) {
100                        layerTree.removeSelectionPath(i);
101                        if (!previouslyShownUnsupportedCrsError) {
102                            JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM''s projections,\n" +
103                                    "so you can not use it. This message will not show again."),
104                                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
105                            previouslyShownUnsupportedCrsError = true;
106                        }
107                    } else if (detail.ident != null) {
108                        selectedLayers.add(detail);
109                    }
110                }
111            }
112            layerTree.firePropertyChange("selectedLayers", /*dummy values*/ false , true);
113        }
114    }
115}