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