001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.imagery.vectortile.mapbox; 003import static org.openstreetmap.josm.tools.I18n.tr; 004 005import java.io.IOException; 006import java.io.InputStream; 007import java.nio.file.InvalidPathException; 008import java.util.List; 009import java.util.Objects; 010import java.util.stream.Collectors; 011 012import javax.json.Json; 013import javax.json.JsonException; 014import javax.json.JsonObject; 015import javax.json.JsonReader; 016 017import org.openstreetmap.josm.data.imagery.ImageryInfo; 018import org.openstreetmap.josm.data.imagery.JosmTemplatedTMSTileSource; 019import org.openstreetmap.josm.data.imagery.vectortile.mapbox.style.MapboxVectorStyle; 020import org.openstreetmap.josm.data.imagery.vectortile.mapbox.style.Source; 021import org.openstreetmap.josm.gui.ExtendedDialog; 022import org.openstreetmap.josm.gui.MainApplication; 023import org.openstreetmap.josm.gui.util.GuiHelper; 024import org.openstreetmap.josm.gui.widgets.JosmComboBox; 025import org.openstreetmap.josm.io.CachedFile; 026import org.openstreetmap.josm.tools.Logging; 027 028/** 029 * Tile Source handling for Mapbox Vector Tile sources 030 * @author Taylor Smock 031 * @since 17862 032 */ 033public class MapboxVectorTileSource extends JosmTemplatedTMSTileSource { 034 private final MapboxVectorStyle styleSource; 035 036 /** 037 * Create a new {@link MapboxVectorTileSource} from an {@link ImageryInfo} 038 * @param info The info to create the source from 039 */ 040 public MapboxVectorTileSource(ImageryInfo info) { 041 super(info); 042 MapboxVectorStyle mapBoxVectorStyle = null; 043 try (CachedFile style = new CachedFile(info.getUrl()); 044 InputStream inputStream = style.getInputStream(); 045 JsonReader reader = Json.createReader(inputStream)) { 046 JsonObject object = reader.readObject(); 047 // OK, we may have a stylesheet. "version", "layers", and "sources" are all required. 048 if (object.containsKey("version") && object.containsKey("layers") && object.containsKey("sources")) { 049 mapBoxVectorStyle = MapboxVectorStyle.getMapboxVectorStyle(info.getUrl()); 050 } 051 } catch (IOException | InvalidPathException | JsonException e) { 052 Logging.trace(e); 053 } 054 this.styleSource = mapBoxVectorStyle; 055 if (this.styleSource != null) { 056 final Source source; 057 List<Source> sources = this.styleSource.getSources().keySet().stream().filter(Objects::nonNull) 058 .collect(Collectors.toList()); 059 if (sources.size() == 1) { 060 source = sources.get(0); 061 } else if (!sources.isEmpty()) { 062 // Ask user what source they want. 063 source = GuiHelper.runInEDTAndWaitAndReturn(() -> { 064 ExtendedDialog dialog = new ExtendedDialog(MainApplication.getMainFrame(), 065 tr("Select Vector Tile Layers"), tr("Add layers")); 066 JosmComboBox<Source> comboBox = new JosmComboBox<>(sources.toArray(new Source[0])); 067 comboBox.setSelectedIndex(0); 068 dialog.setContent(comboBox); 069 dialog.showDialog(); 070 return (Source) comboBox.getSelectedItem(); 071 }); 072 } else { 073 // Umm. What happened? We probably have an invalid style source. 074 throw new InvalidMapboxVectorTileException(tr("Cannot understand style source: {0}", info.getUrl())); 075 } 076 if (source != null) { 077 this.name = name + ": " + source.getName(); 078 // There can technically be multiple URL's for this field; unfortunately, JOSM can only handle one right now. 079 this.baseUrl = source.getUrls().get(0); 080 this.minZoom = source.getMinZoom(); 081 this.maxZoom = source.getMaxZoom(); 082 if (source.getAttributionText() != null) { 083 this.setAttributionText(source.getAttributionText()); 084 } 085 } 086 } 087 } 088 089 /** 090 * Get the style source for this Vector Tile source 091 * @return The source to use for styling 092 */ 093 public MapboxVectorStyle getStyleSource() { 094 return this.styleSource; 095 } 096}