001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.awt.Dimension; 008import java.awt.GridBagLayout; 009import java.awt.event.ActionEvent; 010import java.io.IOException; 011import java.net.MalformedURLException; 012import java.util.HashSet; 013import java.util.Set; 014 015import javax.swing.JComboBox; 016import javax.swing.JOptionPane; 017import javax.swing.JPanel; 018import javax.swing.JScrollPane; 019 020import org.openstreetmap.josm.Main; 021import org.openstreetmap.josm.data.imagery.ImageryInfo; 022import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 023import org.openstreetmap.josm.gui.ExtendedDialog; 024import org.openstreetmap.josm.gui.layer.AlignImageryPanel; 025import org.openstreetmap.josm.gui.layer.ImageryLayer; 026import org.openstreetmap.josm.gui.preferences.imagery.WMSLayerTree; 027import org.openstreetmap.josm.gui.util.GuiHelper; 028import org.openstreetmap.josm.io.imagery.WMSImagery; 029import org.openstreetmap.josm.io.imagery.WMSImagery.LayerDetails; 030import org.openstreetmap.josm.tools.GBC; 031import org.openstreetmap.josm.tools.ImageProvider; 032import org.openstreetmap.josm.tools.ImageProvider.ImageResourceCallback; 033import org.openstreetmap.josm.tools.ImageResource; 034 035/** 036 * Action displayed in imagery menu to add a new imagery layer. 037 * @since 3715 038 */ 039public class AddImageryLayerAction extends JosmAction implements AdaptableAction { 040 private final transient ImageryInfo info; 041 042 /** 043 * Constructs a new {@code AddImageryLayerAction} for the given {@code ImageryInfo}. 044 * If an http:// icon is specified, it is fetched asynchronously. 045 * @param info The imagery info 046 */ 047 public AddImageryLayerAction(ImageryInfo info) { 048 super(info.getMenuName(), /* ICON */"imagery_menu", tr("Add imagery layer {0}", info.getName()), null, false, false); 049 putValue("toolbar", "imagery_" + info.getToolbarName()); 050 putValue("help", ht("/Preferences/Imagery")); 051 this.info = info; 052 installAdapters(); 053 054 // change toolbar icon from if specified 055 try { 056 String icon = info.getIcon(); 057 if (icon != null) { 058 new ImageProvider(icon).setOptional(true).getInBackground(new ImageResourceCallback() { 059 @Override 060 public void finished(final ImageResource result) { 061 if (result != null) { 062 GuiHelper.runInEDT(new Runnable() { 063 @Override 064 public void run() { 065 result.getImageIcon(AddImageryLayerAction.this); 066 } 067 }); 068 } 069 } 070 }); 071 } 072 } catch (Exception ex) { 073 throw new RuntimeException(ex.getMessage(), ex); 074 } 075 } 076 077 @Override 078 public void actionPerformed(ActionEvent e) { 079 if (!isEnabled()) return; 080 try { 081 final ImageryInfo infoToAdd = ImageryType.WMS_ENDPOINT.equals(info.getImageryType()) 082 ? getWMSLayerInfo() : info; 083 if (infoToAdd != null) { 084 Main.main.addLayer(ImageryLayer.create(infoToAdd)); 085 AlignImageryPanel.addNagPanelIfNeeded(); 086 } 087 } catch (IllegalArgumentException ex) { 088 if (ex.getMessage() == null || ex.getMessage().isEmpty()) { 089 throw ex; 090 } else { 091 JOptionPane.showMessageDialog(Main.parent, 092 ex.getMessage(), tr("Error"), 093 JOptionPane.ERROR_MESSAGE); 094 } 095 } 096 } 097 098 protected ImageryInfo getWMSLayerInfo() { 099 try { 100 assert ImageryType.WMS_ENDPOINT.equals(info.getImageryType()); 101 final WMSImagery wms = new WMSImagery(); 102 wms.attemptGetCapabilities(info.getUrl()); 103 104 final WMSLayerTree tree = new WMSLayerTree(); 105 tree.updateTree(wms); 106 final JComboBox<String> formats = new JComboBox<>(wms.getFormats().toArray(new String[0])); 107 formats.setSelectedItem(wms.getPreferredFormats()); 108 formats.setToolTipText(tr("Select image format for WMS layer")); 109 110 if (1 != new ExtendedDialog(Main.parent, tr("Select WMS layers"), new String[]{tr("Add layers"), tr("Cancel")}) { { 111 final JScrollPane scrollPane = new JScrollPane(tree.getLayerTree()); 112 scrollPane.setPreferredSize(new Dimension(400, 400)); 113 final JPanel panel = new JPanel(new GridBagLayout()); 114 panel.add(scrollPane, GBC.eol().fill()); 115 panel.add(formats, GBC.eol().fill(GBC.HORIZONTAL)); 116 setContent(panel); 117 } }.showDialog().getValue()) { 118 return null; 119 } 120 121 final String url = wms.buildGetMapUrl( 122 tree.getSelectedLayers(), (String) formats.getSelectedItem()); 123 Set<String> supportedCrs = new HashSet<>(); 124 boolean first = true; 125 StringBuilder layersString = new StringBuilder(); 126 for (LayerDetails layer: tree.getSelectedLayers()) { 127 if (first) { 128 supportedCrs.addAll(layer.getProjections()); 129 first = false; 130 } 131 layersString.append(layer.name); 132 layersString.append(", "); 133 supportedCrs.retainAll(layer.getProjections()); 134 } 135 136 ImageryInfo ret = new ImageryInfo(info.getName(), url, "wms", info.getEulaAcceptanceRequired(), info.getCookies()); 137 if (layersString.length() > 2) { 138 ret.setName(ret.getName() + ' ' + layersString.substring(0, layersString.length() - 2)); 139 } 140 ret.setServerProjections(supportedCrs); 141 return ret; 142 } catch (MalformedURLException ex) { 143 JOptionPane.showMessageDialog(Main.parent, tr("Invalid service URL."), 144 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 145 } catch (IOException ex) { 146 JOptionPane.showMessageDialog(Main.parent, tr("Could not retrieve WMS layer list."), 147 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 148 } catch (WMSImagery.WMSGetCapabilitiesException ex) { 149 JOptionPane.showMessageDialog(Main.parent, tr("Could not parse WMS layer list."), 150 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 151 Main.error("Could not parse WMS layer list. Incoming data:\n"+ex.getIncomingData()); 152 } 153 return null; 154 } 155 156 @Override 157 protected void updateEnabledState() { 158 ImageryType type = info.getImageryType(); 159 // never enable blacklisted entries. Do not add same imagery layer twice (fix #2519) 160 if (info.isBlacklisted()) { 161 setEnabled(false); 162 } else if (type == ImageryType.TMS || type == ImageryType.BING || type == ImageryType.SCANEX) { 163 setEnabled(true); 164 } else if (Main.isDisplayingMapView() && !Main.map.mapView.getAllLayers().isEmpty()) { 165 setEnabled(true); 166 } else { 167 setEnabled(false); 168 } 169 } 170}