Changeset 17862 in josm for trunk


Ignore:
Timestamp:
2021-05-06T17:39:27+02:00 (4 years ago)
Author:
simon04
Message:

fix #17177 - Add support for Mapbox Vector Tile (patch by taylor.smock)

Signed-off-by: Taylor Smock <tsmock@…>

Location:
trunk
Files:
78 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/resources/data/maps.xsd

    r16128 r17862  
    3939            <xs:enumeration value="wmts" />
    4040            <xs:enumeration value="tms" />
     41            <xs:enumeration value="mvt" />
    4142            <xs:enumeration value="bing" />
    4243            <xs:enumeration value="scanex" />
     
    648649                            <!-- Historic id for the imagery source -->
    649650                            <xs:element name="oldid" minOccurs="0" maxOccurs="unbounded" type="tns:oldid" />
    650                             <!-- The type. Can be tms, wms and html. In addition, there are the special types bing and scanex
     651                            <!-- The type. Can be mvt, tms, wms and html. In addition, there are the special types bing and scanex
    651652                                with hardcoded behaviour. -->
    652653                            <xs:element name="type" minOccurs="1" maxOccurs="1" type="tns:type" />
  • trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java

    r17509 r17862  
    22package org.openstreetmap.josm.data.cache;
    33
     4import java.io.File;
    45import java.io.FileNotFoundException;
    56import java.io.IOException;
     7import java.io.InputStream;
    68import java.net.HttpURLConnection;
    79import java.net.URL;
     10import java.nio.file.Files;
    811import java.security.SecureRandom;
    912import java.util.Collections;
     
    1821import java.util.regex.Matcher;
    1922
    20 import org.apache.commons.jcs3.access.behavior.ICacheAccess;
    21 import org.apache.commons.jcs3.engine.behavior.ICacheElement;
    2223import org.openstreetmap.josm.data.cache.ICachedLoaderListener.LoadResult;
    2324import org.openstreetmap.josm.data.imagery.TileJobOptions;
     
    2728import org.openstreetmap.josm.tools.Logging;
    2829import org.openstreetmap.josm.tools.Utils;
     30
     31import org.apache.commons.jcs3.access.behavior.ICacheAccess;
     32import org.apache.commons.jcs3.engine.behavior.ICacheElement;
    2933
    3034/**
     
    295299            attributes = new CacheEntryAttributes();
    296300        }
     301        final URL url = this.getUrlNoException();
     302        if (url == null) {
     303            return false;
     304        }
     305
     306        if (url.getProtocol().contains("http")) {
     307            return loadObjectHttp();
     308        }
     309        if (url.getProtocol().contains("file")) {
     310            return loadObjectFile(url);
     311        }
     312
     313        return false;
     314    }
     315
     316    private boolean loadObjectFile(URL url) {
     317        String fileName = url.toExternalForm();
     318        File file = new File(fileName.substring("file:/".length() - 1));
     319        if (!file.exists()) {
     320            file = new File(fileName.substring("file://".length() - 1));
     321        }
     322        try (InputStream fileInputStream = Files.newInputStream(file.toPath())) {
     323            cacheData = createCacheEntry(Utils.readBytesFromStream(fileInputStream));
     324            cache.put(getCacheKey(), cacheData, attributes);
     325            return true;
     326        } catch (IOException e) {
     327            Logging.error(e);
     328            attributes.setError(e);
     329            attributes.setException(e);
     330        }
     331        return false;
     332    }
     333
     334    /**
     335     * @return true if object was successfully downloaded via http, false, if there was a loading failure
     336     */
     337    private boolean loadObjectHttp() {
    297338        try {
    298339            // if we have object in cache, and host doesn't support If-Modified-Since nor If-None-Match
     
    554595            return getUrl();
    555596        } catch (IOException e) {
     597            Logging.trace(e);
    556598            return null;
    557599        }
  • trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java

    r17484 r17862  
    6262        WMS_ENDPOINT("wms_endpoint"),
    6363        /** WMTS stores GetCapabilities URL. Does not store any information about the layer **/
    64         WMTS("wmts");
     64        WMTS("wmts"),
     65        /** Mapbox Vector Tiles entry*/
     66        MVT("mvt");
    6567
    6668        private final String typeString;
     
    655657        defaultMinZoom = 0;
    656658        for (ImageryType type : ImageryType.values()) {
    657             Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)\\])?:(.*)").matcher(url);
     659            Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)])?:(.*)").matcher(url);
    658660            if (m.matches()) {
    659661                this.url = m.group(3);
     
    670672
    671673        if (serverProjections.isEmpty()) {
    672             Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)\\}.*").matcher(url.toUpperCase(Locale.ENGLISH));
     674            Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)}.*").matcher(url.toUpperCase(Locale.ENGLISH));
    673675            if (m.matches()) {
    674676                setServerProjections(Arrays.asList(m.group(1).split(",", -1)));
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    r17830 r17862  
    1111import java.util.HashSet;
    1212import java.util.List;
     13import java.util.Locale;
    1314import java.util.Map;
    1415import java.util.Map.Entry;
     
    3435import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
    3536import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
     37import org.openstreetmap.josm.data.imagery.vectortile.VectorTile;
     38import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MVTFile;
    3639import org.openstreetmap.josm.data.preferences.LongProperty;
    3740import org.openstreetmap.josm.tools.HttpClient;
     
    150153        if (statusCode == 200 && headers.containsKey("Content-Type") && !headers.get("Content-Type").isEmpty()) {
    151154            String contentType = headers.get("Content-Type").stream().findAny().get();
    152             if (contentType != null && !contentType.startsWith("image")) {
     155            if (contentType != null && !contentType.startsWith("image") && !MVTFile.MIMETYPE.contains(contentType.toLowerCase(Locale.ROOT))) {
    153156                Logging.warn("Image not returned for tile: " + url + " content type was: " + contentType);
    154157                // not an image - do not store response in cache, so next time it will be queried again from the server
     
    321324        if (object != null) {
    322325            byte[] content = object.getContent();
    323             if (content.length > 0) {
     326            if (content.length > 0 || tile instanceof VectorTile) {
    324327                try (ByteArrayInputStream in = new ByteArrayInputStream(content)) {
    325328                    tile.loadImage(in);
    326                     if (tile.getImage() == null) {
     329                    if ((!(tile instanceof VectorTile) && tile.getImage() == null)
     330                        || ((tile instanceof VectorTile) && !tile.isLoaded())) {
    327331                        String s = new String(content, StandardCharsets.UTF_8);
    328332                        Matcher m = SERVICE_EXCEPTION_PATTERN.matcher(s);
  • trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java

    r17849 r17862  
    3232 * @since 4099
    3333 */
    34 public abstract class AbstractPrimitive implements IPrimitive {
     34public abstract class AbstractPrimitive implements IPrimitive, IFilterablePrimitive {
    3535
    3636    /**
     
    353353    }
    354354
     355    /**
     356     * Update flags
     357     * @param flag The flag to update
     358     * @param value The value to set
     359     * @return {@code true} if the flags have changed
     360     */
     361    protected boolean updateFlagsChanged(short flag, boolean value) {
     362        int oldFlags = flags;
     363        updateFlags(flag, value);
     364        return oldFlags != flags;
     365    }
     366
    355367    @Override
    356368    public void setModified(boolean modified) {
     
    408420    public boolean isIncomplete() {
    409421        return (flags & FLAG_INCOMPLETE) != 0;
     422    }
     423
     424    @Override
     425    public boolean getHiddenType() {
     426        return (flags & FLAG_HIDDEN_TYPE) != 0;
     427    }
     428
     429    @Override
     430    public boolean getDisabledType() {
     431        return (flags & FLAG_DISABLED_TYPE) != 0;
     432    }
     433
     434    @Override
     435    public boolean setDisabledState(boolean hidden) {
     436        // Store as variables to avoid short circuit boolean return
     437        final boolean flagDisabled = updateFlagsChanged(FLAG_DISABLED, true);
     438        final boolean flagHideIfDisabled = updateFlagsChanged(FLAG_HIDE_IF_DISABLED, hidden);
     439        return flagDisabled || flagHideIfDisabled;
     440    }
     441
     442    @Override
     443    public boolean unsetDisabledState() {
     444        // Store as variables to avoid short circuit boolean return
     445        final boolean flagDisabled = updateFlagsChanged(FLAG_DISABLED, false);
     446        final boolean flagHideIfDisabled = updateFlagsChanged(FLAG_HIDE_IF_DISABLED, false);
     447        return flagDisabled || flagHideIfDisabled;
     448    }
     449
     450    @Override
     451    public void setDisabledType(boolean isExplicit) {
     452        updateFlags(FLAG_DISABLED_TYPE, isExplicit);
     453    }
     454
     455    @Override
     456    public void setHiddenType(boolean isExplicit) {
     457        updateFlags(FLAG_HIDDEN_TYPE, isExplicit);
    410458    }
    411459
  • trunk/src/org/openstreetmap/josm/data/osm/BBox.java

    r17752 r17862  
    175175     */
    176176    public void addPrimitive(OsmPrimitive primitive, double extraSpace) {
     177        this.addPrimitive((IPrimitive) primitive, extraSpace);
     178    }
     179
     180    /**
     181     * Extends this bbox to include the bbox of the primitive extended by extraSpace.
     182     * @param primitive an primitive
     183     * @param extraSpace the value to extend the primitives bbox. Unit is in LatLon degrees.
     184     * @since xxx
     185     */
     186    public void addPrimitive(IPrimitive primitive, double extraSpace) {
    177187        IBounds primBbox = primitive.getBBox();
    178188        add(primBbox.getMinLon() - extraSpace, primBbox.getMinLat() - extraSpace);
     
    456466     * Returns an immutable version of this bbox, i.e., modifying calls throw an {@link UnsupportedOperationException}.
    457467     * @return an immutable version of this bbox
    458      */
    459     BBox toImmutable() {
     468     * @since xxx (interface)
     469     */
     470    public BBox toImmutable() {
    460471        return new Immutable(this);
    461472    }
     
    473484
    474485        @Override
    475         BBox toImmutable() {
     486        public BBox toImmutable() {
    476487            return this;
    477488        }
  • trunk/src/org/openstreetmap/josm/data/osm/FilterMatcher.java

    r16445 r17862  
    162162     * when hidden is false, returns whether the primitive is disabled or hidden
    163163     */
    164     private static boolean isFiltered(OsmPrimitive primitive, boolean hidden) {
     164    private static boolean isFiltered(IPrimitive primitive, boolean hidden) {
    165165        return hidden ? primitive.isDisabledAndHidden() : primitive.isDisabled();
    166166    }
     
    169169     * Check if primitive is hidden explicitly.
    170170     * Only used for ways and relations.
     171     * @param <T> The primitive type
    171172     * @param primitive the primitive to check
    172173     * @param hidden the level where the check is performed
    173174     * @return true, if at least one non-inverted filter applies to the primitive
    174175     */
    175     private static boolean isFilterExplicit(OsmPrimitive primitive, boolean hidden) {
     176    private static <T extends IFilterablePrimitive> boolean isFilterExplicit(T primitive, boolean hidden) {
    176177        return hidden ? primitive.getHiddenType() : primitive.getDisabledType();
    177178    }
     
    179180    /**
    180181     * Check if all parent ways are filtered.
     182     * @param <T> The primitive type
    181183     * @param primitive the primitive to check
    182184     * @param hidden parameter that indicates the minimum level of filtering:
     
    188190     * (c) at least one of the parent ways is explicitly filtered
    189191     */
    190     private static boolean allParentWaysFiltered(OsmPrimitive primitive, boolean hidden) {
    191         List<OsmPrimitive> refs = primitive.getReferrers();
     192    private static <T extends IPrimitive & IFilterablePrimitive> boolean allParentWaysFiltered(T primitive, boolean hidden) {
     193        List<? extends IPrimitive> refs = primitive.getReferrers();
    192194        boolean isExplicit = false;
    193         for (OsmPrimitive p: refs) {
    194             if (p instanceof Way) {
     195        for (IPrimitive p: refs) {
     196            if (p instanceof IWay && p instanceof IFilterablePrimitive) {
    195197                if (!isFiltered(p, hidden))
    196198                    return false;
    197                 isExplicit |= isFilterExplicit(p, hidden);
     199                isExplicit |= isFilterExplicit((IFilterablePrimitive) p, hidden);
    198200            }
    199201        }
     
    201203    }
    202204
    203     private static boolean oneParentWayNotFiltered(OsmPrimitive primitive, boolean hidden) {
    204         return primitive.referrers(Way.class)
     205    private static boolean oneParentWayNotFiltered(IPrimitive primitive, boolean hidden) {
     206        return primitive.getReferrers().stream().filter(IWay.class::isInstance).map(IWay.class::cast)
    205207                .anyMatch(p -> !isFiltered(p, hidden));
    206208    }
    207209
    208     private static boolean allParentMultipolygonsFiltered(OsmPrimitive primitive, boolean hidden) {
     210    private static boolean allParentMultipolygonsFiltered(IPrimitive primitive, boolean hidden) {
    209211        boolean isExplicit = false;
    210         for (Relation r : new SubclassFilteredCollection<OsmPrimitive, Relation>(
    211                 primitive.getReferrers(), OsmPrimitive::isMultipolygon)) {
     212        for (Relation r : new SubclassFilteredCollection<IPrimitive, Relation>(
     213                primitive.getReferrers(), IPrimitive::isMultipolygon)) {
    212214            if (!isFiltered(r, hidden))
    213215                return false;
     
    217219    }
    218220
    219     private static boolean oneParentMultipolygonNotFiltered(OsmPrimitive primitive, boolean hidden) {
    220         return new SubclassFilteredCollection<OsmPrimitive, Relation>(primitive.getReferrers(), OsmPrimitive::isMultipolygon).stream()
     221    private static boolean oneParentMultipolygonNotFiltered(IPrimitive primitive, boolean hidden) {
     222        return new SubclassFilteredCollection<IPrimitive, IRelation>(primitive.getReferrers(), IPrimitive::isMultipolygon).stream()
    221223                .anyMatch(r -> !isFiltered(r, hidden));
    222224    }
    223225
    224     private static FilterType test(List<FilterInfo> filters, OsmPrimitive primitive, boolean hidden) {
     226    private static <T extends IPrimitive & IFilterablePrimitive> FilterType test(List<FilterInfo> filters, T primitive, boolean hidden) {
    225227        if (primitive.isIncomplete() || primitive.isPreserved())
    226228            return FilterType.NOT_FILTERED;
     
    246248        }
    247249
    248         if (primitive instanceof Node) {
     250        if (primitive instanceof INode) {
    249251            if (filtered) {
    250252                // If there is a parent way, that is not hidden, we  show the
     
    267269                    return FilterType.NOT_FILTERED;
    268270            }
    269         } else if (primitive instanceof Way) {
     271        } else if (primitive instanceof IWay) {
    270272            if (filtered) {
    271273                if (explicitlyFiltered)
     
    296298     * The filter flags for all parent objects must be set correctly, when
    297299     * calling this method.
     300     * @param <T> The primitive type
    298301     * @param primitive the primitive
    299302     * @return FilterType.NOT_FILTERED when primitive is not hidden;
     
    303306     * are inverted
    304307     */
    305     public FilterType isHidden(OsmPrimitive primitive) {
     308    public <T extends IPrimitive & IFilterablePrimitive> FilterType isHidden(T primitive) {
    306309        return test(hiddenFilters, primitive, true);
    307310    }
     
    311314     * The filter flags for all parent objects must be set correctly, when
    312315     * calling this method.
     316     * @param <T> The primitive type
    313317     * @param primitive the primitive
    314318     * @return FilterType.NOT_FILTERED when primitive is not disabled;
     
    318322     * are inverted
    319323     */
    320     public FilterType isDisabled(OsmPrimitive primitive) {
     324    public <T extends IPrimitive & IFilterablePrimitive> FilterType isDisabled(T primitive) {
    321325        return test(disabledFilters, primitive, false);
    322326    }
  • trunk/src/org/openstreetmap/josm/data/osm/FilterWorker.java

    r12656 r17862  
    1010
    1111/**
    12  * Class for applying {@link Filter}s to {@link OsmPrimitive}s.
     12 * Class for applying {@link Filter}s to {@link IPrimitive}s.
    1313 *
    1414 * Provides a bridge between Filter GUI and the data.
     
    2525     * Apply the filters to the primitives of the data set.
    2626     *
     27     * @param <T> The primitive type
    2728     * @param all the collection of primitives for that the filter state should be updated
    2829     * @param filters the filters
    2930     * @return true, if the filter state (normal / disabled / hidden) of any primitive has changed in the process
    3031     * @throws SearchParseError if the search expression in a filter cannot be parsed
    31      * @since 12383
     32     * @since 12383, xxx (generics)
    3233     */
    33     public static boolean executeFilters(Collection<OsmPrimitive> all, Filter... filters) throws SearchParseError {
     34    public static <T extends IPrimitive & IFilterablePrimitive> boolean executeFilters(Collection<T> all, Filter... filters)
     35            throws SearchParseError {
    3436        return executeFilters(all, FilterMatcher.of(filters));
    3537    }
     
    3840     * Apply the filters to the primitives of the data set.
    3941     *
     42     * @param <T> The primitive type
    4043     * @param all the collection of primitives for that the filter state should be updated
    4144     * @param filterMatcher the FilterMatcher
    4245     * @return true, if the filter state (normal / disabled / hidden) of any primitive has changed in the process
     46     * @since xxx (generics)
    4347     */
    44     public static boolean executeFilters(Collection<OsmPrimitive> all, FilterMatcher filterMatcher) {
     48    public static <T extends IPrimitive & IFilterablePrimitive> boolean executeFilters(Collection<T> all, FilterMatcher filterMatcher) {
    4549        boolean changed;
    4650        // first relations, then ways and nodes last; this is required to resolve dependencies
    47         changed = doExecuteFilters(SubclassFilteredCollection.filter(all, Relation.class::isInstance), filterMatcher);
    48         changed |= doExecuteFilters(SubclassFilteredCollection.filter(all, Way.class::isInstance), filterMatcher);
    49         changed |= doExecuteFilters(SubclassFilteredCollection.filter(all, Node.class::isInstance), filterMatcher);
     51        changed = doExecuteFilters(SubclassFilteredCollection.filter(all, IRelation.class::isInstance), filterMatcher);
     52        changed |= doExecuteFilters(SubclassFilteredCollection.filter(all, IWay.class::isInstance), filterMatcher);
     53        changed |= doExecuteFilters(SubclassFilteredCollection.filter(all, INode.class::isInstance), filterMatcher);
    5054        return changed;
    5155    }
    5256
    53     private static boolean doExecuteFilters(Collection<OsmPrimitive> all, FilterMatcher filterMatcher) {
     57    private static <T extends IPrimitive & IFilterablePrimitive> boolean doExecuteFilters(Collection<T> all, FilterMatcher filterMatcher) {
    5458
    5559        boolean changed = false;
    5660
    57         for (OsmPrimitive primitive: all) {
     61        for (T primitive : all) {
    5862            FilterType hiddenType = filterMatcher.isHidden(primitive);
    5963            if (hiddenType != FilterType.NOT_FILTERED) {
     
    7680     * Apply the filters to a single primitive.
    7781     *
     82     * @param <T> the primitive type
    7883     * @param primitive the primitive
    7984     * @param filterMatcher the FilterMatcher
    8085     * @return true, if the filter state (normal / disabled / hidden)
    8186     * of the primitive has changed in the process
     87     * @since xxx (generics)
    8288     */
    83     public static boolean executeFilters(OsmPrimitive primitive, FilterMatcher filterMatcher) {
     89    public static <T extends IPrimitive & IFilterablePrimitive> boolean executeFilters(T primitive, FilterMatcher filterMatcher) {
    8490        return doExecuteFilters(Collections.singleton(primitive), filterMatcher);
    8591    }
     
    8793    /**
    8894     * Clear all filter flags, i.e.&nbsp;turn off filters.
     95     * @param <T> the primitive type
    8996     * @param prims the primitives
    9097     * @return true, if the filter state (normal / disabled / hidden) of any primitive has changed in the process
    9198     * @since 12388 (signature)
    9299     */
    93     public static boolean clearFilterFlags(Collection<OsmPrimitive> prims) {
     100    public static <T extends IPrimitive & IFilterablePrimitive> boolean clearFilterFlags(Collection<T> prims) {
    94101        boolean changed = false;
    95         for (OsmPrimitive osm : prims) {
     102        for (T osm : prims) {
    96103            changed |= osm.unsetDisabledState();
    97104        }
  • trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java

    r17752 r17862  
    393393
    394394    /**
     395     * Get an object to synchronize the style cache on. This <i>should</i> be a field that does not change during paint.
     396     * By default, it returns the current object, but should be overriden to avoid some performance issues.
     397     * @return A non-{@code null} object to synchronize on when painting
     398     */
     399    default Object getStyleCacheSyncObject() {
     400        return this;
     401    }
     402
     403    /**
    395404     * Replies the display name of a primitive formatted by <code>formatter</code>
    396405     * @param formatter formatter to use
  • trunk/src/org/openstreetmap/josm/data/osm/IRelationMember.java

    r13766 r17862  
    6767     */
    6868    P getMember();
     69
     70    /**
     71     * Returns the relation member as a way.
     72     * @return Member as a way
     73     * @since xxx
     74     */
     75    default IWay<?> getWay() {
     76        return (IWay<?>) getMember();
     77    }
    6978}
  • trunk/src/org/openstreetmap/josm/data/osm/OsmData.java

    r16417 r17862  
    351351     */
    352352    default Collection<N> getSelectedNodes() {
    353         return new SubclassFilteredCollection<>(getSelected(), Node.class::isInstance);
     353        return new SubclassFilteredCollection<>(getSelected(), INode.class::isInstance);
    354354    }
    355355
     
    359359     */
    360360    default Collection<W> getSelectedWays() {
    361         return new SubclassFilteredCollection<>(getSelected(), Way.class::isInstance);
     361        return new SubclassFilteredCollection<>(getSelected(), IWay.class::isInstance);
    362362    }
    363363
     
    367367     */
    368368    default Collection<R> getSelectedRelations() {
    369         return new SubclassFilteredCollection<>(getSelected(), Relation.class::isInstance);
     369        return new SubclassFilteredCollection<>(getSelected(), IRelation.class::isInstance);
    370370    }
    371371
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r17849 r17862  
    330330    }
    331331
    332     /**
    333      * Make the primitive disabled (e.g.&nbsp;if a filter applies).
    334      *
    335      * To enable the primitive again, use unsetDisabledState.
    336      * @param hidden if the primitive should be completely hidden from view or
    337      *             just shown in gray color.
    338      * @return true, any flag has changed; false if you try to set the disabled
    339      * state to the value that is already preset
    340      */
     332    @Override
    341333    public boolean setDisabledState(boolean hidden) {
    342334        boolean locked = writeLock();
    343335        try {
    344             int oldFlags = flags;
    345             updateFlagsNoLock(FLAG_DISABLED, true);
    346             updateFlagsNoLock(FLAG_HIDE_IF_DISABLED, hidden);
    347             return oldFlags != flags;
     336            return super.setDisabledState(hidden);
    348337        } finally {
    349338            writeUnlock(locked);
     
    356345     * @return {@code true} if a change occurred
    357346     */
     347    @Override
    358348    public boolean unsetDisabledState() {
    359349        boolean locked = writeLock();
    360350        try {
    361             int oldFlags = flags;
    362             updateFlagsNoLock(FLAG_DISABLED, false);
    363             updateFlagsNoLock(FLAG_HIDE_IF_DISABLED, false);
    364             return oldFlags != flags;
    365         } finally {
    366             writeUnlock(locked);
    367         }
    368     }
    369 
    370     /**
    371      * Set binary property used internally by the filter mechanism.
    372      * @param isExplicit new "disabled type" flag value
    373      */
    374     public void setDisabledType(boolean isExplicit) {
    375         updateFlags(FLAG_DISABLED_TYPE, isExplicit);
    376     }
    377 
    378     /**
    379      * Set binary property used internally by the filter mechanism.
    380      * @param isExplicit new "hidden type" flag value
    381      */
    382     public void setHiddenType(boolean isExplicit) {
    383         updateFlags(FLAG_HIDDEN_TYPE, isExplicit);
     351            return super.unsetDisabledState();
     352        } finally {
     353            writeUnlock(locked);
     354        }
    384355    }
    385356
     
    401372    public boolean isDisabledAndHidden() {
    402373        return ((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0);
    403     }
    404 
    405     /**
    406      * Get binary property used internally by the filter mechanism.
    407      * @return {@code true} if this object has the "hidden type" flag enabled
    408      */
    409     public boolean getHiddenType() {
    410         return (flags & FLAG_HIDDEN_TYPE) != 0;
    411     }
    412 
    413     /**
    414      * Get binary property used internally by the filter mechanism.
    415      * @return {@code true} if this object has the "disabled type" flag enabled
    416      */
    417     public boolean getDisabledType() {
    418         return (flags & FLAG_DISABLED_TYPE) != 0;
    419374    }
    420375
  • trunk/src/org/openstreetmap/josm/data/osm/RelationMember.java

    r15934 r17862  
    5858     * @since 1937
    5959     */
     60    @Override
    6061    public Way getWay() {
    6162        return (Way) member;
  • trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java

    r15008 r17862  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.osm;
    3 
    4 import java.awt.geom.Line2D;
    5 import java.util.Objects;
    63
    74/**
    85 * A segment consisting of 2 consecutive nodes out of a way.
    96 */
    10 public final class WaySegment implements Comparable<WaySegment> {
     7public final class WaySegment extends IWaySegment<Node, Way> {
    118
    129    /**
    13      * The way.
    14      */
    15     public final Way way;
    16 
    17     /**
    18      * The index of one of the 2 nodes in the way.  The other node has the
    19      * index <code>lowerIndex + 1</code>.
    20      */
    21     public final int lowerIndex;
    22 
    23     /**
    24      * Constructs a new {@code WaySegment}.
    25      * @param w The way
    26      * @param i The node lower index
     10     * Constructs a new {@code IWaySegment}.
     11     *
     12     * @param way The way
     13     * @param i   The node lower index
    2714     * @throws IllegalArgumentException in case of invalid index
    2815     */
    29     public WaySegment(Way w, int i) {
    30         way = w;
    31         lowerIndex = i;
    32         if (i < 0 || i >= w.getNodesCount() - 1) {
    33             throw new IllegalArgumentException(toString());
    34         }
     16    public WaySegment(Way way, int i) {
     17        super(way, i);
    3518    }
    3619
    3720    /**
    38      * Returns the first node of the way segment.
    39      * @return the first node
    40      */
    41     public Node getFirstNode() {
    42         return way.getNode(lowerIndex);
    43     }
    44 
    45     /**
    46      * Returns the second (last) node of the way segment.
    47      * @return the second node
    48      */
    49     public Node getSecondNode() {
    50         return way.getNode(lowerIndex + 1);
    51     }
    52 
    53     /**
    54      * Determines and returns the way segment for the given way and node pair.
    55      * @param way way
    56      * @param first first node
     21     * Determines and returns the way segment for the given way and node pair. You should prefer
     22     * {@link IWaySegment#forNodePair(IWay, INode, INode)} whenever possible.
     23     *
     24     * @param way    way
     25     * @param first  first node
    5726     * @param second second node
    5827     * @return way segment
     
    7140    }
    7241
     42    @Override
     43    public Node getFirstNode() {
     44        // This is kept for binary compatibility
     45        return super.getFirstNode();
     46    }
     47
     48    @Override
     49    public Node getSecondNode() {
     50        // This is kept for binary compatibility
     51        return super.getSecondNode();
     52    }
     53
     54
    7355    /**
    7456     * Returns this way segment as complete way.
    7557     * @return the way segment as {@code Way}
    7658     */
     59    @Override
    7760    public Way toWay() {
    7861        Way w = new Way();
     
    8467    @Override
    8568    public boolean equals(Object o) {
    86         if (this == o) return true;
    87         if (o == null || getClass() != o.getClass()) return false;
    88         WaySegment that = (WaySegment) o;
    89         return lowerIndex == that.lowerIndex &&
    90                 Objects.equals(way, that.way);
     69        // This is kept for binary compatibility
     70        return super.equals(o);
    9171    }
    9272
    9373    @Override
    9474    public int hashCode() {
    95         return Objects.hash(way, lowerIndex);
    96     }
    97 
    98     @Override
    99     public int compareTo(WaySegment o) {
    100         return o == null ? -1 : (equals(o) ? 0 : toWay().compareTo(o.toWay()));
     75        // This is kept for binary compatibility
     76        return super.hashCode();
    10177    }
    10278
     
    10884     */
    10985    public boolean intersects(WaySegment s2) {
    110         if (getFirstNode().equals(s2.getFirstNode()) || getSecondNode().equals(s2.getSecondNode()) ||
    111                 getFirstNode().equals(s2.getSecondNode()) || getSecondNode().equals(s2.getFirstNode()))
    112             return false;
    113 
    114         return Line2D.linesIntersect(
    115                 getFirstNode().getEastNorth().east(), getFirstNode().getEastNorth().north(),
    116                 getSecondNode().getEastNorth().east(), getSecondNode().getEastNorth().north(),
    117                 s2.getFirstNode().getEastNorth().east(), s2.getFirstNode().getEastNorth().north(),
    118                 s2.getSecondNode().getEastNorth().east(), s2.getSecondNode().getEastNorth().north());
     86        // This is kept for binary compatibility
     87        return super.intersects(s2);
    11988    }
    12089
     
    12594     */
    12695    public boolean isSimilar(WaySegment s2) {
    127         return (getFirstNode().equals(s2.getFirstNode()) && getSecondNode().equals(s2.getSecondNode()))
    128             || (getFirstNode().equals(s2.getSecondNode()) && getSecondNode().equals(s2.getFirstNode()));
     96        // This is kept for binary compatibility
     97        return super.isSimilar(s2);
    12998    }
    13099
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r17012 r17862  
    3737import java.util.concurrent.ForkJoinPool;
    3838import java.util.concurrent.TimeUnit;
     39import java.util.concurrent.locks.Lock;
    3940import java.util.function.BiConsumer;
    4041import java.util.function.Consumer;
     
    16381639        BBox bbox = bounds.toBBox();
    16391640        getSettings(renderVirtualNodes);
    1640 
    16411641        try {
    1642             if (data.getReadLock().tryLock(1, TimeUnit.SECONDS)) {
     1642            Lock readLock = data.getReadLock();
     1643            if (readLock.tryLock(1, TimeUnit.SECONDS)) {
    16431644                try {
    16441645                    paintWithLock(data, renderVirtualNodes, benchmark, bbox);
    16451646                } finally {
    1646                     data.getReadLock().unlock();
     1647                    readLock.unlock();
    16471648                }
    16481649            } else {
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationNodeMap.java

    r16896 r17862  
    1111import java.util.TreeSet;
    1212
    13 import org.openstreetmap.josm.data.osm.Node;
    14 import org.openstreetmap.josm.data.osm.RelationMember;
    15 import org.openstreetmap.josm.data.osm.Way;
     13import org.openstreetmap.josm.data.osm.INode;
     14import org.openstreetmap.josm.data.osm.IPrimitive;
     15import org.openstreetmap.josm.data.osm.IRelationMember;
     16import org.openstreetmap.josm.data.osm.IWay;
    1617
    1718/**
     
    2728 *
    2829 * @author Christiaan Welvaart &lt;cjw@time4t.net&gt;
    29  * @since 1785
     30 * @param <T> The type of {@link IRelationMember}
     31 * @since 1785, xxx (generics)
    3032 */
    31 public class RelationNodeMap {
     33public class RelationNodeMap<T extends IRelationMember<? extends IPrimitive>> {
    3234
    3335    private static final String ROLE_BACKWARD = "backward";
    3436
    3537    private static class NodesWays {
    36         public final Map<Node, Set<Integer>> nodes = new TreeMap<>();
    37         public final Map<Integer, Set<Node>> ways = new TreeMap<>();
     38        public final Map<INode, Set<Integer>> nodes = new TreeMap<>();
     39        public final Map<Integer, Set<INode>> ways = new TreeMap<>();
    3840        public final boolean oneWay;
    3941
     
    5759     */
    5860    private final Set<Integer> remaining = new TreeSet<>();
    59     private final Map<Integer, Set<Node>> remainingOneway = new TreeMap<>();
     61    private final Map<Integer, Set<INode>> remainingOneway = new TreeMap<>();
    6062
    6163    /**
     
    6870     * @param m The relation member.
    6971     * @return <code>null</code> if the member is no way, the node otherwise.
    70      */
    71     public static Node firstOnewayNode(RelationMember m) {
     72     * @since xxx (generics)
     73     */
     74    public static INode firstOnewayNode(IRelationMember<?> m) {
    7275        if (!m.isWay()) return null;
    7376        if (ROLE_BACKWARD.equals(m.getRole())) {
     
    8285     * @return <code>null</code> if the member is no way, the node otherwise.
    8386     */
    84     public static Node lastOnewayNode(RelationMember m) {
     87    public static INode lastOnewayNode(IRelationMember<?> m) {
    8588        if (!m.isWay()) return null;
    8689        if (ROLE_BACKWARD.equals(m.getRole())) {
     
    9093    }
    9194
    92     RelationNodeMap(List<RelationMember> members) {
     95    RelationNodeMap(List<T> members) {
    9396        for (int i = 0; i < members.size(); ++i) {
    94             RelationMember m = members.get(i);
     97            T m = members.get(i);
    9598            if (m.getMember().isIncomplete() || !m.isWay() || m.getWay().getNodesCount() < 2) {
    9699                notSortable.add(i);
     
    98101            }
    99102
    100             Way w = m.getWay();
     103            IWay<?> w = m.getWay();
    101104            if (RelationSortUtils.roundaboutType(w) != NONE) {
    102                 for (Node nd : w.getNodes()) {
     105                for (INode nd : w.getNodes()) {
    103106                    addPair(nd, i);
    104107                }
     
    119122    }
    120123
    121     private void addPair(Node n, int i) {
     124    private void addPair(INode n, int i) {
    122125        map.nodes.computeIfAbsent(n, k -> new TreeSet<>()).add(i);
    123126        map.ways.computeIfAbsent(i, k -> new TreeSet<>()).add(n);
    124127    }
    125128
    126     private void addNodeWayMap(Node n, int i) {
     129    private void addNodeWayMap(INode n, int i) {
    127130        onewayMap.nodes.computeIfAbsent(n, k -> new TreeSet<>()).add(i);
    128131    }
    129132
    130     private void addWayNodeMap(Node n, int i) {
     133    private void addWayNodeMap(INode n, int i) {
    131134        onewayMap.ways.computeIfAbsent(i, k -> new TreeSet<>()).add(n);
    132135    }
    133136
    134     private void addNodeWayMapReverse(Node n, int i) {
     137    private void addNodeWayMapReverse(INode n, int i) {
    135138        onewayReverseMap.nodes.computeIfAbsent(n, k -> new TreeSet<>()).add(i);
    136139    }
    137140
    138     private void addWayNodeMapReverse(Node n, int i) {
     141    private void addWayNodeMapReverse(INode n, int i) {
    139142        onewayReverseMap.ways.computeIfAbsent(i, k -> new TreeSet<>()).add(n);
    140143    }
    141144
    142     private void addRemainingForward(Node n, int i) {
     145    private void addRemainingForward(INode n, int i) {
    143146        remainingOneway.computeIfAbsent(i, k -> new TreeSet<>()).add(n);
    144147    }
    145148
    146149    private Integer firstOneway;
    147     private Node lastOnewayNode;
    148     private Node firstCircular;
     150    private INode lastOnewayNode;
     151    private INode firstCircular;
    149152
    150153    /**
     
    159162
    160163        if (map.ways.containsKey(way)) {
    161             for (Node n : map.ways.get(way)) {
     164            for (INode n : map.ways.get(way)) {
    162165                Integer i = deleteAndGetAdjacentNode(map, n);
    163166                if (i != null) return i;
     
    177180    private Integer popForwardOnewayPart(Integer way) {
    178181        if (onewayMap.ways.containsKey(way)) {
    179             Node exitNode = onewayMap.ways.get(way).iterator().next();
     182            INode exitNode = onewayMap.ways.get(way).iterator().next();
    180183
    181184            if (checkIfEndOfLoopReached(exitNode)) {
     
    202205    // an outgoing bidirectional or multiple outgoing oneways, or we
    203206    // looped back to our first circular node)
    204     private boolean checkIfEndOfLoopReached(Node n) {
     207    private boolean checkIfEndOfLoopReached(INode n) {
    205208        return map.nodes.containsKey(n)
    206209                || (onewayMap.nodes.containsKey(n) && (onewayMap.nodes.get(n).size() > 1))
     
    210213    private Integer popBackwardOnewayPart(int way) {
    211214        if (lastOnewayNode != null) {
    212             Set<Node> nodes = new TreeSet<>();
     215            Set<INode> nodes = new TreeSet<>();
    213216            if (onewayReverseMap.ways.containsKey(way)) {
    214217                nodes.addAll(onewayReverseMap.ways.get(way));
     
    217220                nodes.addAll(map.ways.get(way));
    218221            }
    219             for (Node n : nodes) {
     222            for (INode n : nodes) {
    220223                if (n == lastOnewayNode) { //if oneway part ends
    221224                    firstOneway = null;
     
    248251     * @return node next to n
    249252     */
    250     private Integer deleteAndGetAdjacentNode(NodesWays nw, Node n) {
     253    private Integer deleteAndGetAdjacentNode(NodesWays nw, INode n) {
    251254        Integer j = findAdjacentWay(nw, n);
    252255        if (j == null) return null;
     
    255258    }
    256259
    257     private static Integer findAdjacentWay(NodesWays nw, Node n) {
     260    private static Integer findAdjacentWay(NodesWays nw, INode n) {
    258261        Set<Integer> adj = nw.nodes.get(n);
    259262        if (adj == null || adj.isEmpty()) return null;
     
    261264    }
    262265
    263     private void deleteWayNode(NodesWays nw, Integer way, Node n) {
     266    private void deleteWayNode(NodesWays nw, Integer way, INode n) {
    264267        if (nw.oneWay) {
    265268            doneOneway(way);
     
    286289        if (remainingOneway.isEmpty()) return null;
    287290        for (Integer i : remainingOneway.keySet()) { //find oneway, which is connected to more than one way (is between two oneway loops)
    288             for (Node n : onewayReverseMap.ways.get(i)) {
     291            for (INode n : onewayReverseMap.ways.get(i)) {
    289292                if (onewayReverseMap.nodes.containsKey(n) && onewayReverseMap.nodes.get(n).size() > 1) {
    290293                    doneOneway(i);
     
    306309     */
    307310    private void doneOneway(Integer i) {
    308         Set<Node> nodesForward = remainingOneway.get(i);
    309         for (Node n : nodesForward) {
     311        Set<INode> nodesForward = remainingOneway.get(i);
     312        for (INode n : nodesForward) {
    310313            if (onewayMap.nodes.containsKey(n)) {
    311314                onewayMap.nodes.get(n).remove(i);
     
    320323    private void done(Integer i) {
    321324        remaining.remove(i);
    322         Set<Node> nodes = map.ways.get(i);
    323         for (Node n : nodes) {
     325        Set<INode> nodes = map.ways.get(i);
     326        for (INode n : nodes) {
    324327            boolean result = map.nodes.get(n).remove(i);
    325328            if (!result) throw new AssertionError();
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSortUtils.java

    r15364 r17862  
    77
    88import org.openstreetmap.josm.data.coor.EastNorth;
    9 import org.openstreetmap.josm.data.osm.Node;
    10 import org.openstreetmap.josm.data.osm.RelationMember;
    11 import org.openstreetmap.josm.data.osm.Way;
     9import org.openstreetmap.josm.data.osm.INode;
     10import org.openstreetmap.josm.data.osm.IRelationMember;
     11import org.openstreetmap.josm.data.osm.IWay;
    1212import org.openstreetmap.josm.gui.dialogs.relation.sort.WayConnectionType.Direction;
    1313
     
    2525     * @param member relation member
    2626     * @return roundabout type
     27     * @since xxx (generics)
    2728     */
    28     static Direction roundaboutType(RelationMember member) {
     29    static Direction roundaboutType(IRelationMember<?> member) {
    2930        if (member == null || !member.isWay()) return NONE;
    30         return roundaboutType(member.getWay());
     31        return roundaboutType((IWay<?>) member.getWay());
    3132    }
    3233
    33     static Direction roundaboutType(Way w) {
     34    /**
     35     * Check if a way is a roundabout type
     36     * @param w The way to check
     37     * @param <W> The way type
     38     * @return The roundabout type
     39     * @since xxx (generics)
     40     */
     41    static <W extends IWay<?>> Direction roundaboutType(W w) {
    3442        if (w != null && w.hasTag("junction", "circular", "roundabout")) {
    3543            int nodesCount = w.getNodesCount();
    3644            if (nodesCount > 2 && nodesCount < 200) {
    37                 Node n1 = w.getNode(0);
    38                 Node n2 = w.getNode(1);
    39                 Node n3 = w.getNode(2);
     45                INode n1 = w.getNode(0);
     46                INode n2 = w.getNode(1);
     47                INode n3 = w.getNode(2);
    4048                if (n1 != null && n2 != null && n3 != null && w.isClosed()) {
    4149                    /** do some simple determinant / cross product test on the first 3 nodes
     
    5563    }
    5664
    57     static boolean isBackward(final RelationMember member) {
     65    static boolean isBackward(final IRelationMember<?> member) {
    5866        return "backward".equals(member.getRole());
    5967    }
    6068
    61     static boolean isForward(final RelationMember member) {
     69    static boolean isForward(final IRelationMember<?> member) {
    6270        return "forward".equals(member.getRole());
    6371    }
    6472
    65     static boolean isOneway(final RelationMember member) {
     73    static boolean isOneway(final IRelationMember<?> member) {
    6674        return isForward(member) || isBackward(member);
    6775    }
  • trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorter.java

    r16438 r17862  
    1616
    1717import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
     18import org.openstreetmap.josm.data.osm.IPrimitive;
     19import org.openstreetmap.josm.data.osm.IRelationMember;
    1820import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1921import org.openstreetmap.josm.data.osm.Relation;
     
    195197     * @param defaultMembers The members to sort
    196198     * @return A sorted list of the same members
    197      */
    198     public static List<RelationMember> sortMembersByConnectivity(List<RelationMember> defaultMembers) {
    199 
    200         List<RelationMember> newMembers;
    201 
    202         RelationNodeMap map = new RelationNodeMap(defaultMembers);
     199     * @since xxx (signature change, generics)
     200     */
     201    public static <T extends IRelationMember<? extends IPrimitive>> List<T> sortMembersByConnectivity(List<T> defaultMembers) {
     202        List<T> newMembers;
     203
     204        RelationNodeMap<T> map = new RelationNodeMap<>(defaultMembers);
    203205        // List of groups of linked members
    204206        //
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r17841 r17862  
    8787import org.openstreetmap.josm.data.imagery.TMSCachedTileLoader;
    8888import org.openstreetmap.josm.data.imagery.TileLoaderFactory;
     89import org.openstreetmap.josm.data.imagery.vectortile.VectorTile;
    8990import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    9091import org.openstreetmap.josm.data.preferences.BooleanProperty;
     
    110111import org.openstreetmap.josm.gui.layer.imagery.LoadAllTilesAction;
    111112import org.openstreetmap.josm.gui.layer.imagery.LoadErroneousTilesAction;
     113import org.openstreetmap.josm.gui.layer.imagery.MVTLayer;
    112114import org.openstreetmap.josm.gui.layer.imagery.ReprojectionTile;
    113115import org.openstreetmap.josm.gui.layer.imagery.ShowErrorsAction;
     
    889891                tile = new ReprojectionTile(tileSource, x, y, zoom);
    890892            } else {
    891                 tile = new Tile(tileSource, x, y, zoom);
     893                tile = createTile(tileSource, x, y, zoom);
    892894            }
    893895            tileCache.addTile(tile);
     
    10421044                    anchorImage = getAnchor(tile, img);
    10431045                }
    1044                 if (img == null || anchorImage == null) {
     1046                if (img == null || anchorImage == null || (tile instanceof VectorTile && !tile.isLoaded())) {
    10451047                    miss = true;
    10461048                }
     
    10511053            }
    10521054
    1053             img = applyImageProcessors(img);
     1055            if (img != null) {
     1056                img = applyImageProcessors(img);
     1057            }
    10541058
    10551059            TileAnchor anchorScreen = coordinateConverter.getScreenAnchorForTile(tile);
     
    18631867                for (int x = minX; x <= maxX; x++) {
    18641868                    for (int y = minY; y <= maxY; y++) {
    1865                         requestedTiles.add(new Tile(tileSource, x, y, currentZoomLevel));
     1869                        requestedTiles.add(createTile(tileSource, x, y, currentZoomLevel));
    18661870                    }
    18671871                }
     
    19691973    }
    19701974
     1975    /**
     1976     * Create a new tile. Added to allow use of custom {@link Tile} objects.
     1977     *
     1978     * @param source Tile source
     1979     * @param x X coordinate
     1980     * @param y Y coordinate
     1981     * @param zoom Zoom level
     1982     * @return The new {@link Tile}
     1983     * @since xxx
     1984     */
     1985    public Tile createTile(T source, int x, int y, int zoom) {
     1986        return new Tile(source, x, y, zoom);
     1987    }
     1988
    19711989    @Override
    19721990    public synchronized void destroy() {
     
    19892007            if (memory != null) {
    19902008                doPaint(graphics);
     2009                if (AbstractTileSourceLayer.this instanceof MVTLayer) {
     2010                    AbstractTileSourceLayer.this.paint(graphics.getDefaultGraphics(), graphics.getMapView(), graphics.getMapView()
     2011                      .getRealBounds());
     2012                }
    19912013            } else {
    19922014                Graphics g = graphics.getDefaultGraphics();
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r16895 r17862  
    3838import org.openstreetmap.josm.gui.MenuScroller;
    3939import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
     40import org.openstreetmap.josm.gui.layer.imagery.MVTLayer;
    4041import org.openstreetmap.josm.gui.widgets.UrlLabel;
    4142import org.openstreetmap.josm.tools.GBC;
     
    169170        case SCANEX:
    170171            return new TMSLayer(info);
     172        case MVT:
     173            return new MVTLayer(info);
    171174        default:
    172175            throw new AssertionError(tr("Unsupported imagery type: {0}", info.getImageryType()));
  • trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java

    r17333 r17862  
    8787
    8888    /**
     89     * Constructs a new {@code ElemStyles} with specific style sources. This does not listen to preference changes,
     90     * and therefore should only be used with layers that have specific drawing requirements.
     91     *
     92     * @param sources The style sources (these cannot be added to, or removed from)
     93     * @since xxx
     94     */
     95    public ElemStyles(Collection<StyleSource> sources) {
     96        this.styleSources.addAll(sources);
     97    }
     98
     99    /**
    89100     * Clear the style cache for all primitives of all DataSets.
    90101     */
     
    152163     */
    153164    public Pair<StyleElementList, Range> getStyleCacheWithRange(IPrimitive osm, double scale, NavigatableComponent nc) {
    154         if (!osm.isCachedStyleUpToDate() || scale <= 0) {
    155             osm.setCachedStyle(StyleCache.EMPTY_STYLECACHE);
    156         } else {
    157             Pair<StyleElementList, Range> lst = osm.getCachedStyle().getWithRange(scale, osm.isSelected());
    158             if (lst.a != null)
    159                 return lst;
    160         }
    161         Pair<StyleElementList, Range> p = getImpl(osm, scale, nc);
    162         if (osm instanceof INode && isDefaultNodes()) {
    163             if (p.a.isEmpty()) {
    164                 if (TextLabel.AUTO_LABEL_COMPOSITION_STRATEGY.compose(osm) != null) {
    165                     p.a = DefaultStyles.DEFAULT_NODE_STYLELIST_TEXT;
     165        synchronized (osm.getStyleCacheSyncObject()) {
     166            if (!osm.isCachedStyleUpToDate() || scale <= 0) {
     167                osm.setCachedStyle(StyleCache.EMPTY_STYLECACHE);
     168            } else {
     169                Pair<StyleElementList, Range> lst = osm.getCachedStyle().getWithRange(scale, osm.isSelected());
     170                if (lst.a != null)
     171                    return lst;
     172            }
     173            Pair<StyleElementList, Range> p = getImpl(osm, scale, nc);
     174            if (osm instanceof INode && isDefaultNodes()) {
     175                if (p.a.isEmpty()) {
     176                    if (TextLabel.AUTO_LABEL_COMPOSITION_STRATEGY.compose(osm) != null) {
     177                        p.a = DefaultStyles.DEFAULT_NODE_STYLELIST_TEXT;
     178                    } else {
     179                        p.a = DefaultStyles.DEFAULT_NODE_STYLELIST;
     180                    }
    166181                } else {
    167                     p.a = DefaultStyles.DEFAULT_NODE_STYLELIST;
    168                 }
    169             } else {
    170                 boolean hasNonModifier = false;
    171                 boolean hasText = false;
     182                    boolean hasNonModifier = false;
     183                    boolean hasText = false;
     184                    for (StyleElement s : p.a) {
     185                        if (s instanceof BoxTextElement) {
     186                            hasText = true;
     187                        } else {
     188                            if (!s.isModifier) {
     189                                hasNonModifier = true;
     190                            }
     191                        }
     192                    }
     193                    if (!hasNonModifier) {
     194                        p.a = new StyleElementList(p.a, DefaultStyles.SIMPLE_NODE_ELEMSTYLE);
     195                        if (!hasText && TextLabel.AUTO_LABEL_COMPOSITION_STRATEGY.compose(osm) != null) {
     196                            p.a = new StyleElementList(p.a, DefaultStyles.SIMPLE_NODE_TEXT_ELEMSTYLE);
     197                        }
     198                    }
     199                }
     200            } else if (osm instanceof IWay && isDefaultLines()) {
     201                boolean hasProperLineStyle = false;
    172202                for (StyleElement s : p.a) {
    173                     if (s instanceof BoxTextElement) {
    174                         hasText = true;
    175                     } else {
    176                         if (!s.isModifier) {
    177                             hasNonModifier = true;
    178                         }
    179                     }
    180                 }
    181                 if (!hasNonModifier) {
    182                     p.a = new StyleElementList(p.a, DefaultStyles.SIMPLE_NODE_ELEMSTYLE);
    183                     if (!hasText && TextLabel.AUTO_LABEL_COMPOSITION_STRATEGY.compose(osm) != null) {
    184                         p.a = new StyleElementList(p.a, DefaultStyles.SIMPLE_NODE_TEXT_ELEMSTYLE);
    185                     }
    186                 }
    187             }
    188         } else if (osm instanceof IWay && isDefaultLines()) {
    189             boolean hasProperLineStyle = false;
    190             for (StyleElement s : p.a) {
    191                 if (s.isProperLineStyle()) {
    192                     hasProperLineStyle = true;
    193                     break;
    194                 }
    195             }
    196             if (!hasProperLineStyle) {
    197                 LineElement line = LineElement.UNTAGGED_WAY;
    198                 for (StyleElement element : p.a) {
    199                     if (element instanceof AreaElement) {
    200                         line = LineElement.createSimpleLineStyle(((AreaElement) element).color, true);
     203                    if (s.isProperLineStyle()) {
     204                        hasProperLineStyle = true;
    201205                        break;
    202206                    }
    203207                }
    204                 p.a = new StyleElementList(p.a, line);
    205             }
    206         }
    207         StyleCache style = osm.getCachedStyle() != null ? osm.getCachedStyle() : StyleCache.EMPTY_STYLECACHE;
    208         try {
    209             osm.setCachedStyle(style.put(p.a, p.b, osm.isSelected()));
    210         } catch (RangeViolatedError e) {
    211             throw new AssertionError("Range violated: " + e.getMessage()
    212                     + " (object: " + osm.getPrimitiveId() + ", current style: "+osm.getCachedStyle()
    213                     + ", scale: " + scale + ", new stylelist: " + p.a + ", new range: " + p.b + ')', e);
    214         }
    215         osm.declareCachedStyleUpToDate();
    216         return p;
     208                if (!hasProperLineStyle) {
     209                    LineElement line = LineElement.UNTAGGED_WAY;
     210                    for (StyleElement element : p.a) {
     211                        if (element instanceof AreaElement) {
     212                            line = LineElement.createSimpleLineStyle(((AreaElement) element).color, true);
     213                            break;
     214                        }
     215                    }
     216                    p.a = new StyleElementList(p.a, line);
     217                }
     218            }
     219            StyleCache style = osm.getCachedStyle() != null ? osm.getCachedStyle() : StyleCache.EMPTY_STYLECACHE;
     220            try {
     221                osm.setCachedStyle(style.put(p.a, p.b, osm.isSelected()));
     222            } catch (RangeViolatedError e) {
     223                throw new AssertionError("Range violated: " + e.getMessage()
     224                  + " (object: " + osm.getPrimitiveId() + ", current style: " + osm.getCachedStyle()
     225                  + ", scale: " + scale + ", new stylelist: " + p.a + ", new range: " + p.b + ')', e);
     226            }
     227            osm.declareCachedStyleUpToDate();
     228            return p;
     229        }
    217230    }
    218231
     
    377390     */
    378391    public Pair<StyleElementList, Range> generateStyles(IPrimitive osm, double scale, boolean pretendWayIsClosed) {
    379 
    380392        List<StyleElement> sl = new ArrayList<>();
    381393        MultiCascade mc = new MultiCascade();
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ConditionFactory.java

    r17824 r17862  
    871871            return e.osm.isSelected();
    872872        }
     873
     874        /**
     875         * Check if the object is highlighted (i.e., is hovered over)
     876         * @param e The MapCSS environment
     877         * @return {@code true} if the object is highlighted
     878         * @see IPrimitive#isHighlighted
     879         * @since xxx
     880         */
     881        static boolean highlighted(Environment e) {
     882            return e.osm.isHighlighted();
     883        }
    873884    }
    874885
     
    888899            PseudoClassCondition.register("completely_downloaded", PseudoClasses::completely_downloaded);
    889900            PseudoClassCondition.register("connection", PseudoClasses::connection);
     901            PseudoClassCondition.register("highlighted", PseudoClasses::highlighted);
    890902            PseudoClassCondition.register("inDownloadedArea", PseudoClasses::inDownloadedArea);
    891903            PseudoClassCondition.register("modified", PseudoClasses::modified);
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/ImageryProvidersPanel.java

    r16965 r17862  
    313313        activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.TMS));
    314314        activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.WMTS));
     315        activeToolbar.add(new NewEntryAction(ImageryInfo.ImageryType.MVT));
    315316        activeToolbar.add(remove);
    316317        activePanel.add(activeToolbar, BorderLayout.EAST);
     
    441442                icon = /* ICON(dialogs/) */ "add_wmts";
    442443                break;
     444            case MVT:
     445                icon = /* ICON(dialogs/) */ "add_mvt";
     446                break;
    443447            default:
    444448                break;
     
    460464            case WMTS:
    461465                p = new AddWMTSLayerPanel();
     466                break;
     467            case MVT:
     468                p = new AddMVTLayerPanel();
    462469                break;
    463470            default:
     
    742749        URL url;
    743750        try {
    744             url = new URL(eulaUrl.replaceAll("\\{lang\\}", LanguageInfo.getWikiLanguagePrefix()));
     751            url = new URL(eulaUrl.replaceAll("\\{lang}", LanguageInfo.getWikiLanguagePrefix()));
    745752            JosmEditorPane htmlPane;
    746753            try {
     
    750757                // give a second chance with a default Locale 'en'
    751758                try {
    752                     url = new URL(eulaUrl.replaceAll("\\{lang\\}", ""));
     759                    url = new URL(eulaUrl.replaceAll("\\{lang}", ""));
    753760                    htmlPane = new JosmEditorPane(url);
    754761                } catch (IOException e2) {
Note: See TracChangeset for help on using the changeset viewer.