Changeset 3342 in josm


Ignore:
Timestamp:
Jun 26, 2010 4:44:15 PM (3 years ago)
Author:
jttt
Message:

Cleanup/organize OsmPrimitive

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r3341 r3342  
    184184    } 
    185185 
    186     /* mappaint data */ 
    187     public ElemStyle mappaintStyle = null; 
    188     public int mappaintDrawnCode = 0; 
    189  
    190     /* This should not be called from outside. Fixing the UI to add relevant 
    191        get/set functions calling this implicitely is preferred, so we can have 
    192        transparent cache handling in the future. */ 
    193     protected void clearCached() 
    194     { 
    195         mappaintDrawnCode = 0; 
    196         mappaintStyle = null; 
    197     } 
    198     /* end of mappaint data */ 
    199  
    200     /** 
    201      * Unique identifier in OSM. This is used to identify objects on the server. 
    202      * An id of 0 means an unknown id. The object has not been uploaded yet to 
    203      * know what id it will get. 
    204      * 
    205      */ 
    206     private long id = 0; 
    207  
    208     /** the parent dataset */ 
    209     private DataSet dataSet; 
    210  
    211     /** 
    212      * This method should never ever by called from somewhere else than Dataset.addPrimitive or removePrimitive methods 
    213      * @param dataSet 
    214      */ 
    215     void setDataset(DataSet dataSet) { 
    216         if (this.dataSet != null && dataSet != null && this.dataSet != dataSet) 
    217             throw new DataIntegrityProblemException("Primitive cannot be included in more than one Dataset"); 
    218         this.dataSet = dataSet; 
    219     } 
    220  
    221     /** 
    222      * 
    223      * @return DataSet this primitive is part of. 
    224      */ 
    225     public DataSet getDataSet() { 
    226         return dataSet; 
    227     } 
    228  
    229     /** 
    230      * Throws exception if primitive is not part of the dataset 
    231      */ 
    232     public void checkDataset() { 
    233         if (dataSet == null) 
    234             throw new DataIntegrityProblemException("Primitive  must be part of the dataset: " + toString()); 
    235     } 
    236  
    237     private volatile short flags = FLAG_VISIBLE;   // visible per default 
    238  
    239     /** 
    240      * User that last modified this primitive, as specified by the server. 
    241      * Never changed by JOSM. 
    242      */ 
    243     private User user = null; 
    244  
    245     /** 
    246      * Contains the version number as returned by the API. Needed to 
    247      * ensure update consistency 
    248      */ 
    249     private int version = 0; 
    250  
    251     /** 
    252      * The id of the changeset this primitive was last uploaded to. 
    253      * 0 if it wasn't uploaded to a changeset yet of if the changeset 
    254      * id isn't known. 
    255      */ 
    256     private int changesetId; 
     186    /** 
     187     * Some predicates, that describe conditions on primitives. 
     188     */ 
     189    public static final Predicate<OsmPrimitive> isUsablePredicate = new Predicate<OsmPrimitive>() { 
     190        public boolean evaluate(OsmPrimitive primitive) { 
     191            return primitive.isUsable(); 
     192        } 
     193    }; 
     194 
     195    public static final Predicate<OsmPrimitive> isSelectablePredicate = new Predicate<OsmPrimitive>() { 
     196        public boolean evaluate(OsmPrimitive primitive) { 
     197            return primitive.isSelectable(); 
     198        } 
     199    }; 
     200 
     201    public static final Predicate<OsmPrimitive> nonDeletedPredicate = new Predicate<OsmPrimitive>() { 
     202        public boolean evaluate(OsmPrimitive primitive) { 
     203            return !primitive.isDeleted(); 
     204        } 
     205    }; 
     206 
     207    public static final Predicate<OsmPrimitive> nonDeletedCompletePredicate = new Predicate<OsmPrimitive>() { 
     208        public boolean evaluate(OsmPrimitive primitive) { 
     209            return !primitive.isDeleted() && !primitive.isIncomplete(); 
     210        } 
     211    }; 
     212 
     213    public static final Predicate<OsmPrimitive> nonDeletedPhysicalPredicate = new Predicate<OsmPrimitive>() { 
     214        public boolean evaluate(OsmPrimitive primitive) { 
     215            return !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation); 
     216        } 
     217    }; 
     218 
     219    public static final Predicate<OsmPrimitive> modifiedPredicate = new Predicate<OsmPrimitive>() { 
     220        public boolean evaluate(OsmPrimitive primitive) { 
     221            return primitive.isModified(); 
     222        } 
     223    }; 
     224 
     225    public static final Predicate<OsmPrimitive> nodePredicate = new Predicate<OsmPrimitive>() { 
     226        public boolean evaluate(OsmPrimitive primitive) { 
     227            return primitive.getClass() == Node.class; 
     228        } 
     229    }; 
     230 
     231    public static final Predicate<OsmPrimitive> wayPredicate = new Predicate<OsmPrimitive>() { 
     232        public boolean evaluate(OsmPrimitive primitive) { 
     233            return primitive.getClass() == Way.class; 
     234        } 
     235    }; 
     236 
     237    public static final Predicate<OsmPrimitive> relationPredicate = new Predicate<OsmPrimitive>() { 
     238        public boolean evaluate(OsmPrimitive primitive) { 
     239            return primitive.getClass() == Relation.class; 
     240        } 
     241    }; 
     242 
     243    public static final Predicate<OsmPrimitive> allPredicate = new Predicate<OsmPrimitive>() { 
     244        public boolean evaluate(OsmPrimitive primitive) { 
     245            return true; 
     246        } 
     247    }; 
    257248 
    258249    /** 
     
    304295    } 
    305296 
    306     /* ------------------------------------------------------------------------------------ */ 
    307     /* accessors                                                                            */ 
    308     /* ------------------------------------------------------------------------------------ */ 
    309  
    310     /** 
    311      * Make the primitive disabled (e.g. if a filter applies). 
    312      * To enable the primitive again, use unsetDisabledState. 
    313      * @param hide if the primitive should be completely hidden from view or 
    314      *             just shown in gray color. 
    315      */ 
    316     public void setDisabledState(boolean hide) { 
    317         flags |= FLAG_DISABLED; 
    318         if (hide) { 
    319             flags |= FLAG_HIDE_IF_DISABLED; 
    320         } else { 
    321             flags &= ~FLAG_HIDE_IF_DISABLED; 
    322         } 
    323     } 
    324  
    325     /** 
    326      * Remove the disabled flag from the primitive. 
    327      * Afterwards, the primitive is displayed normally and can be selected 
    328      * again. 
    329      */ 
    330     public void unsetDisabledState() { 
    331         flags &= ~FLAG_DISABLED; 
    332         flags &= ~FLAG_HIDE_IF_DISABLED; 
    333     } 
    334  
    335     /** 
    336      * Replies true, if this primitive is disabled. (E.g. a filter 
    337      * applies) 
    338      */ 
    339     public boolean isDisabled() { 
    340         return (flags & FLAG_DISABLED) != 0; 
    341     } 
    342  
    343     /** 
    344      * Replies true, if this primitive is disabled and marked as 
    345      * completely hidden on the map. 
    346      */ 
    347     public boolean isDisabledAndHidden() { 
    348         return (((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0)); 
    349     } 
    350  
    351     @Deprecated 
    352     public boolean isFiltered() { 
    353         return isDisabledAndHidden(); 
    354     } 
    355  
    356     /** 
    357      * Marks this primitive as being modified. 
    358      * 
    359      * @param modified true, if this primitive is to be modified 
    360      */ 
    361     public void setModified(boolean modified) { 
    362         if (modified) { 
    363             flags |= FLAG_MODIFIED; 
    364         } else { 
    365             flags &= ~FLAG_MODIFIED; 
    366         } 
    367     } 
    368  
    369     /** 
    370      * Replies <code>true</code> if the object has been modified since it was loaded from 
    371      * the server. In this case, on next upload, this object will be updated. 
    372      * 
    373      * Deleted objects are deleted from the server. If the objects are added (id=0), 
    374      * the modified is ignored and the object is added to the server. 
    375      * 
    376      * @return <code>true</code> if the object has been modified since it was loaded from 
    377      * the server 
    378      */ 
    379     public boolean isModified() { 
    380         return (flags & FLAG_MODIFIED) != 0; 
    381     } 
    382  
    383     /** 
    384      * Replies <code>true</code>, if the object has been deleted. 
    385      * 
    386      * @return <code>true</code>, if the object has been deleted. 
    387      * @see #setDeleted(boolean) 
    388      */ 
    389     public boolean isDeleted() { 
    390         return (flags & FLAG_DELETED) != 0; 
    391     } 
    392  
    393     /** 
    394      * Replies <code>true</code> if the object has been deleted on the server and was undeleted by the user. 
    395      * @return <code>true</code> if the object has been undeleted 
    396      */ 
    397     public boolean isUndeleted() { 
    398         return (flags & (FLAG_VISIBLE + FLAG_DELETED)) == 0; 
    399     } 
    400  
    401     /** 
    402      * Replies <code>true</code>, if the object is usable (i.e. complete 
    403      * and not deleted). 
    404      * 
    405      * @return <code>true</code>, if the object is usable. 
    406      * @see #delete(boolean) 
    407      */ 
    408     public boolean isUsable() { 
    409         return (flags & (FLAG_DELETED + FLAG_INCOMPLETE)) == 0; 
    410     } 
    411  
    412     public boolean isSelectable() { 
    413         return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_DISABLED + FLAG_HIDE_IF_DISABLED)) == 0; 
    414     } 
    415  
    416     public boolean isDrawable() { 
    417         return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_HIDE_IF_DISABLED)) == 0; 
    418     } 
    419  
    420     /** 
    421      * Some predicates, that describe conditions on primitives. 
    422      */ 
    423     public static Predicate<OsmPrimitive> isUsablePredicate = new Predicate<OsmPrimitive>() { 
    424         public boolean evaluate(OsmPrimitive primitive) { 
    425             return primitive.isUsable(); 
    426         } 
    427     }; 
    428  
    429     public static Predicate<OsmPrimitive> isSelectablePredicate = new Predicate<OsmPrimitive>() { 
    430         public boolean evaluate(OsmPrimitive primitive) { 
    431             return primitive.isSelectable(); 
    432         } 
    433     }; 
    434  
    435     public static Predicate<OsmPrimitive> nonDeletedPredicate = new Predicate<OsmPrimitive>() { 
    436         public boolean evaluate(OsmPrimitive primitive) { 
    437             return !primitive.isDeleted(); 
    438         } 
    439     }; 
    440  
    441     public static Predicate<OsmPrimitive> nonDeletedCompletePredicate = new Predicate<OsmPrimitive>() { 
    442         public boolean evaluate(OsmPrimitive primitive) { 
    443             return !primitive.isDeleted() && !primitive.isIncomplete(); 
    444         } 
    445     }; 
    446  
    447     public static Predicate<OsmPrimitive> nonDeletedPhysicalPredicate = new Predicate<OsmPrimitive>() { 
    448         public boolean evaluate(OsmPrimitive primitive) { 
    449             return !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation); 
    450         } 
    451     }; 
    452  
    453     public static Predicate<OsmPrimitive> modifiedPredicate = new Predicate<OsmPrimitive>() { 
    454         public boolean evaluate(OsmPrimitive primitive) { 
    455             return primitive.isModified(); 
    456         } 
    457     }; 
    458  
    459     public static Predicate<OsmPrimitive> nodePredicate = new Predicate<OsmPrimitive>() { 
    460         public boolean evaluate(OsmPrimitive primitive) { 
    461             return primitive.getClass() == Node.class; 
    462         } 
    463     }; 
    464  
    465     public static Predicate<OsmPrimitive> wayPredicate = new Predicate<OsmPrimitive>() { 
    466         public boolean evaluate(OsmPrimitive primitive) { 
    467             return primitive.getClass() == Way.class; 
    468         } 
    469     }; 
    470  
    471     public static Predicate<OsmPrimitive> relationPredicate = new Predicate<OsmPrimitive>() { 
    472         public boolean evaluate(OsmPrimitive primitive) { 
    473             return primitive.getClass() == Relation.class; 
    474         } 
    475     }; 
    476  
    477     public static Predicate<OsmPrimitive> allPredicate = new Predicate<OsmPrimitive>() { 
    478         public boolean evaluate(OsmPrimitive primitive) { 
    479             return true; 
    480         } 
    481     }; 
    482  
    483  
    484     /** 
    485      * Replies true if this primitive is either unknown to the server (i.e. its id 
    486      * is 0) or it is known to the server and it hasn't be deleted on the server. 
    487      * Replies false, if this primitive is known on the server and has been deleted 
    488      * on the server. 
    489      * 
    490      * @see #setVisible(boolean) 
    491      */ 
    492     public boolean isVisible() { 
    493         return (flags & FLAG_VISIBLE) != 0; 
    494     } 
    495  
    496     /** 
    497      * Sets whether this primitive is visible, i.e. whether it is known on the server 
    498      * and not deleted on the server. 
    499      * 
    500      * @see #isVisible() 
    501      * @throws IllegalStateException thrown if visible is set to false on an primitive with 
    502      * id==0 
    503      */ 
    504     public void setVisible(boolean visible) throws IllegalStateException{ 
    505         if (isNew() && visible == false) 
    506             throw new IllegalStateException(tr("A primitive with ID = 0 cannot be invisible.")); 
    507         if (visible) { 
    508             flags |= FLAG_VISIBLE; 
    509         } else { 
    510             flags &= ~FLAG_VISIBLE; 
    511         } 
    512     } 
     297 
     298    /*---------- 
     299     * MAPPAINT 
     300     *--------*/ 
     301    public ElemStyle mappaintStyle = null; 
     302    public int mappaintDrawnCode = 0; 
     303 
     304    /* This should not be called from outside. Fixing the UI to add relevant 
     305       get/set functions calling this implicitely is preferred, so we can have 
     306       transparent cache handling in the future. */ 
     307    protected void clearCached() 
     308    { 
     309        mappaintDrawnCode = 0; 
     310        mappaintStyle = null; 
     311    } 
     312    /* end of mappaint data */ 
     313 
     314    /*--------- 
     315     * DATASET 
     316     *---------*/ 
     317 
     318    /** the parent dataset */ 
     319    private DataSet dataSet; 
     320 
     321    /** 
     322     * This method should never ever by called from somewhere else than Dataset.addPrimitive or removePrimitive methods 
     323     * @param dataSet 
     324     */ 
     325    void setDataset(DataSet dataSet) { 
     326        if (this.dataSet != null && dataSet != null && this.dataSet != dataSet) 
     327            throw new DataIntegrityProblemException("Primitive cannot be included in more than one Dataset"); 
     328        this.dataSet = dataSet; 
     329    } 
     330 
     331    /** 
     332     * 
     333     * @return DataSet this primitive is part of. 
     334     */ 
     335    public DataSet getDataSet() { 
     336        return dataSet; 
     337    } 
     338 
     339    /** 
     340     * Throws exception if primitive is not part of the dataset 
     341     */ 
     342    public void checkDataset() { 
     343        if (dataSet == null) 
     344            throw new DataIntegrityProblemException("Primitive  must be part of the dataset: " + toString()); 
     345    } 
     346 
     347    /*------------------- 
     348     * OTHER PROPERTIES 
     349     *-------------------/ 
     350 
     351    /** 
     352     * Unique identifier in OSM. This is used to identify objects on the server. 
     353     * An id of 0 means an unknown id. The object has not been uploaded yet to 
     354     * know what id it will get. 
     355     * 
     356     */ 
     357    private long id = 0; 
     358 
     359    /** 
     360     * User that last modified this primitive, as specified by the server. 
     361     * Never changed by JOSM. 
     362     */ 
     363    private User user = null; 
     364 
     365    /** 
     366     * Contains the version number as returned by the API. Needed to 
     367     * ensure update consistency 
     368     */ 
     369    private int version = 0; 
     370 
     371    /** 
     372     * The id of the changeset this primitive was last uploaded to. 
     373     * 0 if it wasn't uploaded to a changeset yet of if the changeset 
     374     * id isn't known. 
     375     */ 
     376    private int changesetId; 
    513377 
    514378    /** 
     
    604468    } 
    605469 
    606     public void setTimestamp(Date timestamp) { 
    607         this.timestamp = (int)(timestamp.getTime() / 1000); 
    608     } 
    609  
    610     /** 
    611      * Time of last modification to this object. This is not set by JOSM but 
    612      * read from the server and delivered back to the server unmodified. It is 
    613      * used to check against edit conflicts. 
    614      * 
    615      */ 
    616     public Date getTimestamp() { 
    617         return new Date(timestamp * 1000l); 
    618     } 
    619  
    620     public boolean isTimestampEmpty() { 
    621         return timestamp == 0; 
    622     } 
    623  
    624     private int timestamp; 
    625  
    626     private static volatile Collection<String> uninteresting = null; 
    627     /** 
    628      * Contains a list of "uninteresting" keys that do not make an object 
    629      * "tagged".  Entries that end with ':' are causing a whole namespace to be considered 
    630      * "uninteresting".  Only the first level namespace is considered. 
    631      * Initialized by isUninterestingKey() 
    632      */ 
    633     public static Collection<String> getUninterestingKeys() { 
    634         if (uninteresting == null) { 
    635             uninteresting = Main.pref.getCollection("tags.uninteresting", 
    636                     Arrays.asList(new String[]{"source", "source_ref", "source:", "note", "comment", 
    637                             "converted_by", "created_by", "watch", "watch:", "fixme", "FIXME", 
    638                             "description"})); 
    639         } 
    640         return uninteresting; 
    641     } 
    642  
    643     /** 
    644      * Returns true if key is considered "uninteresting". 
    645      */ 
    646     public static boolean isUninterestingKey(String key) { 
    647         getUninterestingKeys(); 
    648         if (uninteresting.contains(key)) 
    649             return true; 
    650         int pos = key.indexOf(':'); 
    651         if (pos > 0) 
    652             return uninteresting.contains(key.substring(0, pos + 1)); 
    653         return false; 
    654     } 
    655  
    656     private static volatile Match directionKeys = null; 
    657     private static volatile Match reversedDirectionKeys = null; 
    658  
    659     /** 
    660      * Contains a list of direction-dependent keys that make an object 
    661      * direction dependent. 
    662      * Initialized by checkDirectionTagged() 
    663      */ 
    664     static { 
    665         // Legacy support - convert list of keys to search pattern 
    666         if (Main.pref.isCollection("tags.direction", false)) { 
    667             System.out.println("Collection of keys in tags.direction is no longer supported, value will converted to search pattern"); 
    668             Collection<String> keys = Main.pref.getCollection("tags.direction", null); 
    669             StringBuilder builder = new StringBuilder(); 
    670             for (String key:keys) { 
    671                 builder.append(key); 
    672                 builder.append("=* | "); 
    673             } 
    674             builder.delete(builder.length() - 3, builder.length()); 
    675             Main.pref.put("tags.direction", builder.toString()); 
    676         } 
    677  
    678         // FIXME: incline=\"-*\" search pattern does not work. 
    679         String reversedDirectionDefault = "oneway=\"-1\" | incline=down | incline=\"-*\""; 
    680  
    681         String directionDefault = "oneway? | incline=* | aerialway=* | "+ 
    682         "waterway=stream | waterway=river | waterway=canal | waterway=drain | waterway=rapids | "+ 
    683         "\"piste:type\"=downhill | \"piste:type\"=sled | man_made=\"piste:halfpipe\" | "+ 
    684         "junction=roundabout"; 
    685  
    686         try { 
    687             reversedDirectionKeys = SearchCompiler.compile(Main.pref.get("tags.reversed_direction", reversedDirectionDefault), false, false); 
    688         } catch (ParseError e) { 
    689             System.err.println("Unable to compile pattern for tags.reversed_direction, trying default pattern: " + e.getMessage()); 
    690  
    691             try { 
    692                 reversedDirectionKeys = SearchCompiler.compile(reversedDirectionDefault, false, false); 
    693             } catch (ParseError e2) { 
    694                 throw new AssertionError("Unable to compile default pattern for direction keys: " + e2.getMessage()); 
    695             } 
    696         } 
    697         try { 
    698             directionKeys = SearchCompiler.compile(Main.pref.get("tags.direction", directionDefault), false, false); 
    699         } catch (ParseError e) { 
    700             System.err.println("Unable to compile pattern for tags.direction, trying default pattern: " + e.getMessage()); 
    701  
    702             try { 
    703                 directionKeys = SearchCompiler.compile(directionDefault, false, false); 
    704             } catch (ParseError e2) { 
    705                 throw new AssertionError("Unable to compile default pattern for direction keys: " + e2.getMessage()); 
    706             } 
    707         } 
    708     } 
    709  
    710     /** 
    711      * Replies a list of direction-dependent keys that make an object 
    712      * direction dependent. 
    713      * 
    714      * @return  a list of direction-dependent keys that make an object 
    715      * direction dependent. 
    716      */ 
    717     @Deprecated 
    718     public static Collection<String> getDirectionKeys() { 
    719         return Main.pref.getCollection("tags.direction", 
    720                 Arrays.asList("oneway","incline","incline_steep","aerialway")); 
    721     } 
    722  
    723     /** 
    724      * Implementation of the visitor scheme. Subclasses have to call the correct 
    725      * visitor function. 
    726      * @param visitor The visitor from which the visit() function must be called. 
    727      */ 
    728     abstract public void visit(Visitor visitor); 
    729  
    730     /** 
    731      * Sets whether this primitive is deleted or not. 
    732      * 
    733      * Also marks this primitive as modified if deleted is true. 
    734      * 
    735      * @param deleted  true, if this primitive is deleted; false, otherwise 
    736      */ 
    737     public void setDeleted(boolean deleted) { 
    738         if (deleted) { 
    739             flags |= FLAG_DELETED; 
    740         } else { 
    741             flags &= ~FLAG_DELETED; 
    742         } 
    743         setModified(deleted ^ !isVisible()); 
    744         if (dataSet != null) { 
    745             if (deleted) { 
    746                 dataSet.firePrimitivesRemoved(Collections.singleton(this), false); 
    747             } else { 
    748                 dataSet.firePrimitivesAdded(Collections.singleton(this), false); 
    749             } 
    750         } 
    751     } 
    752  
    753470    /** 
    754471     * Replies the user who has last touched this object. May be null. 
     
    803520 
    804521    /** 
    805      * Equal, if the id (and class) is equal. 
    806      * 
    807      * An primitive is equal to its incomplete counter part. 
    808      */ 
    809     @Override public boolean equals(Object obj) { 
    810         if (obj instanceof OsmPrimitive) 
    811             return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass(); 
     522     * Replies the unique primitive id for this primitive 
     523     * 
     524     * @return the unique primitive id for this primitive 
     525     */ 
     526    public PrimitiveId getPrimitiveId() { 
     527        return new SimplePrimitiveId(getUniqueId(), getType()); 
     528    } 
     529 
     530    public void setTimestamp(Date timestamp) { 
     531        this.timestamp = (int)(timestamp.getTime() / 1000); 
     532    } 
     533 
     534    /** 
     535     * Time of last modification to this object. This is not set by JOSM but 
     536     * read from the server and delivered back to the server unmodified. It is 
     537     * used to check against edit conflicts. 
     538     * 
     539     */ 
     540    public Date getTimestamp() { 
     541        return new Date(timestamp * 1000l); 
     542    } 
     543 
     544    public boolean isTimestampEmpty() { 
     545        return timestamp == 0; 
     546    } 
     547 
     548    private int timestamp; 
     549 
     550    /* ------- 
     551    /* FLAGS 
     552    /* ------*/ 
     553 
     554    private volatile short flags = FLAG_VISIBLE;   // visible per default 
     555 
     556    private void updateFlags(int flag, boolean value) { 
     557        if (value) { 
     558            flags |= flag; 
     559        } else { 
     560            flags &= ~flag; 
     561        } 
     562    } 
     563 
     564    /** 
     565     * Make the primitive disabled (e.g. if a filter applies). 
     566     * To enable the primitive again, use unsetDisabledState. 
     567     * @param hide if the primitive should be completely hidden from view or 
     568     *             just shown in gray color. 
     569     */ 
     570    public void setDisabledState(boolean hide) { 
     571        flags |= FLAG_DISABLED; 
     572        if (hide) { 
     573            flags |= FLAG_HIDE_IF_DISABLED; 
     574        } else { 
     575            flags &= ~FLAG_HIDE_IF_DISABLED; 
     576        } 
     577    } 
     578 
     579    /** 
     580     * Remove the disabled flag from the primitive. 
     581     * Afterwards, the primitive is displayed normally and can be selected 
     582     * again. 
     583     */ 
     584    public void unsetDisabledState() { 
     585        updateFlags(FLAG_DISABLED + FLAG_HIDE_IF_DISABLED, false); 
     586    } 
     587 
     588    /** 
     589     * Replies true, if this primitive is disabled. (E.g. a filter 
     590     * applies) 
     591     */ 
     592    public boolean isDisabled() { 
     593        return (flags & FLAG_DISABLED) != 0; 
     594    } 
     595 
     596    /** 
     597     * Replies true, if this primitive is disabled and marked as 
     598     * completely hidden on the map. 
     599     */ 
     600    public boolean isDisabledAndHidden() { 
     601        return (((flags & FLAG_DISABLED) != 0) && ((flags & FLAG_HIDE_IF_DISABLED) != 0)); 
     602    } 
     603 
     604    @Deprecated 
     605    public boolean isFiltered() { 
     606        return isDisabledAndHidden(); 
     607    } 
     608 
     609    /** 
     610     * Marks this primitive as being modified. 
     611     * 
     612     * @param modified true, if this primitive is to be modified 
     613     */ 
     614    public void setModified(boolean modified) { 
     615        updateFlags(FLAG_MODIFIED, modified); 
     616    } 
     617 
     618    /** 
     619     * Replies <code>true</code> if the object has been modified since it was loaded from 
     620     * the server. In this case, on next upload, this object will be updated. 
     621     * 
     622     * Deleted objects are deleted from the server. If the objects are added (id=0), 
     623     * the modified is ignored and the object is added to the server. 
     624     * 
     625     * @return <code>true</code> if the object has been modified since it was loaded from 
     626     * the server 
     627     */ 
     628    public boolean isModified() { 
     629        return (flags & FLAG_MODIFIED) != 0; 
     630    } 
     631 
     632    /** 
     633     * Replies <code>true</code>, if the object has been deleted. 
     634     * 
     635     * @return <code>true</code>, if the object has been deleted. 
     636     * @see #setDeleted(boolean) 
     637     */ 
     638    public boolean isDeleted() { 
     639        return (flags & FLAG_DELETED) != 0; 
     640    } 
     641 
     642    /** 
     643     * Replies <code>true</code> if the object has been deleted on the server and was undeleted by the user. 
     644     * @return <code>true</code> if the object has been undeleted 
     645     */ 
     646    public boolean isUndeleted() { 
     647        return (flags & (FLAG_VISIBLE + FLAG_DELETED)) == 0; 
     648    } 
     649 
     650    /** 
     651     * Replies <code>true</code>, if the object is usable (i.e. complete 
     652     * and not deleted). 
     653     * 
     654     * @return <code>true</code>, if the object is usable. 
     655     * @see #delete(boolean) 
     656     */ 
     657    public boolean isUsable() { 
     658        return (flags & (FLAG_DELETED + FLAG_INCOMPLETE)) == 0; 
     659    } 
     660 
     661    public boolean isSelectable() { 
     662        return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_DISABLED + FLAG_HIDE_IF_DISABLED)) == 0; 
     663    } 
     664 
     665    public boolean isDrawable() { 
     666        return (flags & (FLAG_DELETED + FLAG_INCOMPLETE + FLAG_HIDE_IF_DISABLED)) == 0; 
     667    } 
     668 
     669    /** 
     670     * Replies true if this primitive is either unknown to the server (i.e. its id 
     671     * is 0) or it is known to the server and it hasn't be deleted on the server. 
     672     * Replies false, if this primitive is known on the server and has been deleted 
     673     * on the server. 
     674     * 
     675     * @see #setVisible(boolean) 
     676     */ 
     677    public boolean isVisible() { 
     678        return (flags & FLAG_VISIBLE) != 0; 
     679    } 
     680 
     681    /** 
     682     * Sets whether this primitive is visible, i.e. whether it is known on the server 
     683     * and not deleted on the server. 
     684     * 
     685     * @see #isVisible() 
     686     * @throws IllegalStateException thrown if visible is set to false on an primitive with 
     687     * id==0 
     688     */ 
     689    public void setVisible(boolean visible) throws IllegalStateException{ 
     690        if (isNew() && visible == false) 
     691            throw new IllegalStateException(tr("A primitive with ID = 0 cannot be invisible.")); 
     692        updateFlags(FLAG_VISIBLE, visible); 
     693    } 
     694 
     695    /** 
     696     * Sets whether this primitive is deleted or not. 
     697     * 
     698     * Also marks this primitive as modified if deleted is true. 
     699     * 
     700     * @param deleted  true, if this primitive is deleted; false, otherwise 
     701     */ 
     702    public void setDeleted(boolean deleted) { 
     703        updateFlags(FLAG_DELETED, deleted); 
     704        setModified(deleted ^ !isVisible()); 
     705        if (dataSet != null) { 
     706            if (deleted) { 
     707                dataSet.firePrimitivesRemoved(Collections.singleton(this), false); 
     708            } else { 
     709                dataSet.firePrimitivesAdded(Collections.singleton(this), false); 
     710            } 
     711        } 
     712    } 
     713 
     714 
     715    /** 
     716     * If set to true, this object is incomplete, which means only the id 
     717     * and type is known (type is the objects instance class) 
     718     */ 
     719    private void setIncomplete(boolean incomplete) { 
     720        if (dataSet != null && incomplete != this.isIncomplete()) { 
     721            if (incomplete) { 
     722                dataSet.firePrimitivesRemoved(Collections.singletonList(this), true); 
     723            } else { 
     724                dataSet.firePrimitivesAdded(Collections.singletonList(this), true); 
     725            } 
     726        } 
     727        updateFlags(FLAG_INCOMPLETE, incomplete); 
     728    } 
     729 
     730    public boolean isIncomplete() { 
     731        return (flags & FLAG_INCOMPLETE) != 0; 
     732    } 
     733 
     734    public boolean isSelected() { 
     735        return dataSet != null && dataSet.isSelected(this); 
     736    } 
     737 
     738    public void setHighlighted(boolean highlighted) { 
     739        if (isHighlighted() != highlighted) { 
     740            updateFlags(FLAG_HIGHLIGHTED, highlighted); 
     741            if (dataSet != null) { 
     742                dataSet.fireHighlightingChanged(this); 
     743            } 
     744        } 
     745    } 
     746 
     747    public boolean isHighlighted() { 
     748        return (flags & FLAG_HIGHLIGHTED) != 0; 
     749    } 
     750 
     751    /*---------------------------------- 
     752     * UNINTERESTING AND DIRECTION KEYS 
     753     *----------------------------------*/ 
     754 
     755 
     756    private static volatile Collection<String> uninteresting = null; 
     757    /** 
     758     * Contains a list of "uninteresting" keys that do not make an object 
     759     * "tagged".  Entries that end with ':' are causing a whole namespace to be considered 
     760     * "uninteresting".  Only the first level namespace is considered. 
     761     * Initialized by isUninterestingKey() 
     762     */ 
     763    public static Collection<String> getUninterestingKeys() { 
     764        if (uninteresting == null) { 
     765            uninteresting = Main.pref.getCollection("tags.uninteresting", 
     766                    Arrays.asList(new String[]{"source", "source_ref", "source:", "note", "comment", 
     767                            "converted_by", "created_by", "watch", "watch:", "fixme", "FIXME", 
     768                    "description"})); 
     769        } 
     770        return uninteresting; 
     771    } 
     772 
     773    /** 
     774     * Returns true if key is considered "uninteresting". 
     775     */ 
     776    public static boolean isUninterestingKey(String key) { 
     777        getUninterestingKeys(); 
     778        if (uninteresting.contains(key)) 
     779            return true; 
     780        int pos = key.indexOf(':'); 
     781        if (pos > 0) 
     782            return uninteresting.contains(key.substring(0, pos + 1)); 
    812783        return false; 
    813784    } 
    814785 
    815     /** 
    816      * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0. 
    817      * 
    818      * An primitive has the same hashcode as its incomplete counterpart. 
    819      */ 
    820     @Override public final int hashCode() { 
    821         return (int)id; 
     786    private static volatile Match directionKeys = null; 
     787    private static volatile Match reversedDirectionKeys = null; 
     788 
     789    /** 
     790     * Contains a list of direction-dependent keys that make an object 
     791     * direction dependent. 
     792     * Initialized by checkDirectionTagged() 
     793     */ 
     794    static { 
     795        // Legacy support - convert list of keys to search pattern 
     796        if (Main.pref.isCollection("tags.direction", false)) { 
     797            System.out.println("Collection of keys in tags.direction is no longer supported, value will converted to search pattern"); 
     798            Collection<String> keys = Main.pref.getCollection("tags.direction", null); 
     799            StringBuilder builder = new StringBuilder(); 
     800            for (String key:keys) { 
     801                builder.append(key); 
     802                builder.append("=* | "); 
     803            } 
     804            builder.delete(builder.length() - 3, builder.length()); 
     805            Main.pref.put("tags.direction", builder.toString()); 
     806        } 
     807 
     808        // FIXME: incline=\"-*\" search pattern does not work. 
     809        String reversedDirectionDefault = "oneway=\"-1\" | incline=down | incline=\"-*\""; 
     810 
     811        String directionDefault = "oneway? | incline=* | aerialway=* | "+ 
     812        "waterway=stream | waterway=river | waterway=canal | waterway=drain | waterway=rapids | "+ 
     813        "\"piste:type\"=downhill | \"piste:type\"=sled | man_made=\"piste:halfpipe\" | "+ 
     814        "junction=roundabout"; 
     815 
     816        try { 
     817            reversedDirectionKeys = SearchCompiler.compile(Main.pref.get("tags.reversed_direction", reversedDirectionDefault), false, false); 
     818        } catch (ParseError e) { 
     819            System.err.println("Unable to compile pattern for tags.reversed_direction, trying default pattern: " + e.getMessage()); 
     820 
     821            try { 
     822                reversedDirectionKeys = SearchCompiler.compile(reversedDirectionDefault, false, false); 
     823            } catch (ParseError e2) { 
     824                throw new AssertionError("Unable to compile default pattern for direction keys: " + e2.getMessage()); 
     825            } 
     826        } 
     827        try { 
     828            directionKeys = SearchCompiler.compile(Main.pref.get("tags.direction", directionDefault), false, false); 
     829        } catch (ParseError e) { 
     830            System.err.println("Unable to compile pattern for tags.direction, trying default pattern: " + e.getMessage()); 
     831 
     832            try { 
     833                directionKeys = SearchCompiler.compile(directionDefault, false, false); 
     834            } catch (ParseError e2) { 
     835                throw new AssertionError("Unable to compile default pattern for direction keys: " + e2.getMessage()); 
     836            } 
     837        } 
     838    } 
     839 
     840    private void updateTagged() { 
     841        if (keys != null) { 
     842            for (String key: keySet()) { 
     843                if (!isUninterestingKey(key)) { 
     844                    updateFlags(FLAG_TAGGED, true); 
     845                    return; 
     846                } 
     847            } 
     848        } 
     849        updateFlags(FLAG_TAGGED, false); 
     850    } 
     851 
     852    /** 
     853     * true if this object is considered "tagged". To be "tagged", an object 
     854     * must have one or more "interesting" tags. "created_by" and "source" 
     855     * are typically considered "uninteresting" and do not make an object 
     856     * "tagged". 
     857     */ 
     858    public boolean isTagged() { 
     859        return (flags & FLAG_TAGGED) != 0; 
     860    } 
     861 
     862    private void updateDirectionFlags() { 
     863        boolean hasDirections = false; 
     864        boolean directionReversed = false; 
     865        if (reversedDirectionKeys.match(this)) { 
     866            hasDirections = true; 
     867            directionReversed = true; 
     868        } 
     869        if (directionKeys.match(this)) { 
     870            hasDirections = true; 
     871        } 
     872 
     873        updateFlags(FLAG_DIRECTION_REVERSED, directionReversed); 
     874        updateFlags(FLAG_HAS_DIRECTIONS, hasDirections); 
     875    } 
     876 
     877    /** 
     878     * true if this object has direction dependent tags (e.g. oneway) 
     879     */ 
     880    public boolean hasDirectionKeys() { 
     881        return (flags & FLAG_HAS_DIRECTIONS) != 0; 
     882    } 
     883 
     884    public boolean reversedDirection() { 
     885        return (flags & FLAG_DIRECTION_REVERSED) != 0; 
    822886    } 
    823887 
     
    11211185    } 
    11221186 
     1187    /*----------------- 
     1188     * OTHER METHODS 
     1189     *----------------/ 
     1190 
     1191    /** 
     1192     * Implementation of the visitor scheme. Subclasses have to call the correct 
     1193     * visitor function. 
     1194     * @param visitor The visitor from which the visit() function must be called. 
     1195     */ 
     1196    abstract public void visit(Visitor visitor); 
     1197 
     1198 
    11231199    /** 
    11241200     * Get and write all attributes from the parameter. Does not fire any listener, so 
     
    12301306    } 
    12311307 
    1232     private void updateTagged() { 
    1233         if (keys != null) { 
    1234             for (String key: keySet()) { 
    1235                 if (!isUninterestingKey(key)) { 
    1236                     flags |= FLAG_TAGGED; 
    1237                     return; 
    1238                 } 
    1239             } 
    1240         } 
    1241         flags &= ~FLAG_TAGGED; 
    1242     } 
    1243  
    1244     /** 
    1245      * true if this object is considered "tagged". To be "tagged", an object 
    1246      * must have one or more "interesting" tags. "created_by" and "source" 
    1247      * are typically considered "uninteresting" and do not make an object 
    1248      * "tagged". 
    1249      */ 
    1250     public boolean isTagged() { 
    1251         return (flags & FLAG_TAGGED) != 0; 
    1252     } 
    1253  
    1254     private void updateDirectionFlags() { 
    1255         boolean hasDirections = false; 
    1256         boolean directionReversed = false; 
    1257         if (reversedDirectionKeys.match(this)) { 
    1258             hasDirections = true; 
    1259             directionReversed = true; 
    1260         } 
    1261         if (directionKeys.match(this)) { 
    1262             hasDirections = true; 
    1263         } 
    1264  
    1265         if (directionReversed) { 
    1266             flags |= FLAG_DIRECTION_REVERSED; 
    1267         } else { 
    1268             flags &= ~FLAG_DIRECTION_REVERSED; 
    1269         } 
    1270         if (hasDirections) { 
    1271             flags |= FLAG_HAS_DIRECTIONS; 
    1272         } else { 
    1273             flags &= ~FLAG_HAS_DIRECTIONS; 
    1274         } 
    1275     } 
    1276  
    1277     /** 
    1278      * true if this object has direction dependent tags (e.g. oneway) 
    1279      */ 
    1280     public boolean hasDirectionKeys() { 
    1281         return (flags & FLAG_HAS_DIRECTIONS) != 0; 
    1282     } 
    1283  
    1284     public boolean reversedDirection() { 
    1285         return (flags & FLAG_DIRECTION_REVERSED) != 0; 
    1286     } 
    12871308    /** 
    12881309     * Replies the name of this primitive. The default implementation replies the value 
     
    13661387    } 
    13671388 
     1389 
     1390    public abstract BBox getBBox(); 
     1391 
     1392    /** 
     1393     * Called by Dataset to update cached position information of primitive (bbox, cached EarthNorth, ...) 
     1394     */ 
     1395    public abstract void updatePosition(); 
     1396 
     1397    /*---------------- 
     1398     * OBJECT METHODS 
     1399     *---------------*/ 
     1400 
    13681401    protected String getFlagsAsString() { 
    13691402        StringBuilder builder = new StringBuilder(); 
     
    14001433    } 
    14011434 
    1402     public abstract BBox getBBox(); 
    1403  
    1404     /** 
    1405      * Called by Dataset to update cached position information of primitive (bbox, cached EarthNorth, ...) 
    1406      */ 
    1407     public abstract void updatePosition(); 
    1408  
    1409     /** 
    1410      * Replies the unique primitive id for this primitive 
    1411      * 
    1412      * @return the unique primitive id for this primitive 
    1413      */ 
    1414     public PrimitiveId getPrimitiveId() { 
    1415         return new SimplePrimitiveId(getUniqueId(), getType()); 
    1416     } 
    1417  
    1418     /** 
    1419      * If set to true, this object is incomplete, which means only the id 
    1420      * and type is known (type is the objects instance class) 
    1421      */ 
    1422     private void setIncomplete(boolean incomplete) { 
    1423         if (dataSet != null && incomplete != this.isIncomplete()) { 
    1424             if (incomplete) { 
    1425                 dataSet.firePrimitivesRemoved(Collections.singletonList(this), true); 
    1426             } else { 
    1427                 dataSet.firePrimitivesAdded(Collections.singletonList(this), true); 
    1428             } 
    1429         } 
    1430         if (incomplete) { 
    1431             flags |= FLAG_INCOMPLETE; 
    1432         } else { 
    1433             flags &= ~FLAG_INCOMPLETE; 
    1434         } 
    1435     } 
    1436  
    1437     public boolean isIncomplete() { 
    1438         return (flags & FLAG_INCOMPLETE) != 0; 
    1439     } 
    1440  
    1441     public boolean isSelected() { 
    1442         return dataSet != null && dataSet.isSelected(this); 
    1443     } 
    1444  
    1445     public void setHighlighted(boolean highlighted) { 
    1446         if (isHighlighted() != highlighted) { 
    1447             if (highlighted) { 
    1448                 flags |= FLAG_HIGHLIGHTED; 
    1449             } else { 
    1450                 flags &= ~FLAG_HIGHLIGHTED; 
    1451             } 
    1452             if (dataSet != null) { 
    1453                 dataSet.fireHighlightingChanged(this); 
    1454             } 
    1455         } 
    1456     } 
    1457  
    1458     public boolean isHighlighted() { 
    1459         return (flags & FLAG_HIGHLIGHTED) != 0; 
    1460     } 
     1435    /** 
     1436     * Equal, if the id (and class) is equal. 
     1437     * 
     1438     * An primitive is equal to its incomplete counter part. 
     1439     */ 
     1440    @Override public boolean equals(Object obj) { 
     1441        if (obj instanceof OsmPrimitive) 
     1442            return ((OsmPrimitive)obj).id == id && obj.getClass() == getClass(); 
     1443        return false; 
     1444    } 
     1445 
     1446    /** 
     1447     * Return the id plus the class type encoded as hashcode or super's hashcode if id is 0. 
     1448     * 
     1449     * An primitive has the same hashcode as its incomplete counterpart. 
     1450     */ 
     1451    @Override public final int hashCode() { 
     1452        return (int)id; 
     1453    } 
     1454 
    14611455} 
Note: See TracChangeset for help on using the changeset viewer.