Merge pull request #42 from stevage/train-routes
authorRichard Fairhurst <richard@systemeD.net>
Sun, 25 Mar 2012 18:07:10 +0000 (11:07 -0700)
committerRichard Fairhurst <richard@systemeD.net>
Sun, 25 Mar 2012 18:07:10 +0000 (11:07 -0700)
Add train routes

1  2 
net/systemeD/potlatch2/mapfeatures/Feature.as
resources/map_features.xml
resources/map_features/transport.xml

index 8ae89c8ed5c33fa7bad87a6034ca2fcc14691426,57b2525f4fef4afd1c76cf7251ba626fc15ace94..a1d7c31effe9684f479664c501ea20044358743b
@@@ -1,5 -1,4 +1,4 @@@
  package net.systemeD.potlatch2.mapfeatures {
      import flash.events.Event;
      import flash.events.EventDispatcher;
      import flash.net.*;
@@@ -8,16 -7,19 +7,18 @@@
      import mx.core.BitmapAsset;
      import mx.graphics.codec.PNGEncoder;
      
 -    import net.systemeD.halcyon.ImageBank;
 +    import net.systemeD.halcyon.FileBank;
      import net.systemeD.halcyon.connection.Entity;
 -    import net.systemeD.potlatch2.utils.CachedDataLoader;
  
-         /** A "map feature" is sort of a template for a map entity. It consists of a few crucial key/value pairs that define the feature, so that
-          * entities can be recognised. It also contains optional keys, with associated editing controls, that are defined as being appropriate
-          * for the feature. */
+     /** A "map feature" is sort of a template for a map entity. It consists of a few crucial key/value pairs that define the feature, so that
+      * entities can be recognised. It also contains optional keys, with associated editing controls, that are defined as being appropriate
+      * for the feature. */
        public class Feature extends EventDispatcher {
          private var mapFeatures:MapFeatures;
          private var _xml:XML;
-         private static var variablesPattern:RegExp = /[$][{]([^}]+)[}]/g;
+         // match ${foo|bar|baz|...} - see makeHTMLIcon()
+         private static var variablesPattern:RegExp = /\$\{([^|}]+)\|?([^|}]+)?\|?([^|}]+)?\|?([^|}]+)?\|?([^|}]+)?\|?([^}]+)?\}/g;
          private var _tags:Array;
          private var _withins:Array;
          private var _editors:Array;
          public function Feature(mapFeatures:MapFeatures, _xml:XML) {
              this.mapFeatures = mapFeatures;
              this._xml = _xml;
 +            loadImages();
              parseConditions();
              parseEditors();
          }
  
 +        private function loadImages():void {
 +            var icon:XMLList = _xml.icon;
 +            if ( icon.length() > 0 ) {
 +                if ( icon[0].hasOwnProperty("@dnd") ) {
 +                    FileBank.getInstance().addFromFile(icon[0].@dnd);
 +                }
 +                if ( icon[0].hasOwnProperty("@image") ) {
 +                    FileBank.getInstance().addFromFile(icon[0].@image);
 +                }
 +            }
 +        }
 +
          private function parseConditions():void {
              _tags = [];
             _withins = [];
          /** Fetches the feature's image, as defined by the icon element in the feature definition.
          * @param dnd if true, overrides the normal image and returns the one defined by the dnd property instead. */
          private function getImage(dnd:Boolean = false):ByteArray {
 +            var fileBank:FileBank = FileBank.getInstance();
              var icon:XMLList = _xml.icon;
              var imageURL:String;
  
                  imageURL = icon[0].@image;
              }
  
 -            if ( imageURL ) {
 -                              if (ImageBank.getInstance().hasImage(imageURL)) {
 -                                      return ImageBank.getInstance().getAsByteArray(imageURL)
 -                              } else {
 -                      return CachedDataLoader.loadData(imageURL, imageLoaded);
 -                              }
 +            if ( imageURL && fileBank.hasFile(imageURL) ) {
 +                if (fileBank.fileLoaded(imageURL, imageLoaded)) {
 +                    return fileBank.getAsByteArray(imageURL);
 +                } else {
 +                    return null;
 +                }
              }
              var bitmap:BitmapAsset = new missingIconCls() as BitmapAsset;
              return new PNGEncoder().encode(bitmap.bitmapData);
                return point.length() > 0 && !(XML(point[0]).attribute("draganddrop")[0] == "no");
          }
  
 -        private function imageLoaded(url:String, data:ByteArray):void {
 +        private function imageLoaded(fileBank:FileBank, url:String):void {
              dispatchEvent(new Event("imageChanged"));
          }
  
              return makeHTMLIcon(icon, entity);
          }
  
-         /** Convert the contents of the "icon" tag as an HTML string, with variable substitution. */
+         /** Convert the contents of the "icon" tag as an HTML string, with variable substitution:
+         *   ${highway} shows the value of the highway key
+         *   ${name|operator|network} - if there's no name value, show operator, or network, or nothing.
+         *   (${ref}) - renders as nothing if $ref is valueless.
+         */
          public static function makeHTMLIcon(icon:XMLList, entity:Entity):String {
              if ( icon == null )
                  return "";
  
              var txt:String = icon.children().toXMLString();
+             // Args to this function: "string matched", "substring 1", "substring 2"..., index of match, whole string
              var replaceTag:Function = function():String {
-                 var value:String = entity.getTag(arguments[1]);
+               var matchnum=0;
+               var args=arguments;
+               var value:String = null;
+               while ((value == null || value == "") && matchnum < args.length - 3  ) {
+                   value = entity.getTag(args[matchnum + 1]);
+                   matchnum++;
+               }
                  return value == null ? "" : htmlEscape(value);
              };
              txt = txt.replace(variablesPattern, replaceTag);
+             // a slightly hacky way of making "${name} (${ref})" look ok even if ref is undefined.
+             txt = txt.replace("()", ""); 
              return txt;
          }
  
index bfcdc4d45bcab7b2294cbfffb66e6a7bb632575f,af3bade67c4789b61fe7abe21816707c59638303..fbc4a39864913cedb4698693a3b41a38e47b75c3
@@@ -48,7 -48,7 +48,7 @@@
     </inputSet> 
  
    <inputSet id="source">
 -    <input type="freetext" category="Details" presence="onTagMatch" name="Source" key="source" description="The primary source of information for this object (GPS, survey, Yahoo, ...)" priority="lowest"/>
 +    <input type="freetext" category="Details" presence="onTagMatch" name="Source" key="source" description="The primary source of information for this object (GPS, survey, Bing, ...)" priority="lowest"/>
    </inputSet>
  
    <inputSet id="designation">
      <inputSet ref="cycle"/>
      <inputSet ref="bicycle-lane"/>
      <inputSet ref="bus-route"/>
 +    <inputSet ref="tram-route"/>
      <inputSet ref="pedestrians"/>
      <inputSet ref="roadLanes"/>
      <inputSet ref="roadRoundabout"/>
      <inputSet ref="cycle"/>
      <inputSet ref="bicycle-lane"/>
      <inputSet ref="bus-route"/>
 +    <inputSet ref="tram-route"/>
      <inputSet ref="pedestrians"/>
      <inputSet ref="roadLanes"/>
      <inputSet ref="roadRoundabout"/>
        <choice value="750" text="750V"/>
        <choice value="1500" text="1500V"/>
        <choice value="3000" text="3000V"/>
 +      <choice value="12000" text="12kV"/>
        <choice value="15000" text="15kV"/>
        <choice value="25000" text="25kV"/>
      </input>
        <role role="via"/>
      </input>
    </inputSet>
 +  
 +  <inputSet id="trafficSignals">
 +    <!-- can't add as standalone feature due to current limitations, would conflict with junction node feature -->
 +    <input type="choice" key="highway" name="Traffic signals" description="Intersection controlled by traffic lights" category="Restrictions" presence="always">
 +      <choice value="traffic_signals" text="Yes"/>
 +    </input>
 +  </inputSet>
  
    <inputSet id="pedestrians">
      <input type="choice" name="Pedestrians" description="Can pedestrians use this road, including footpaths if any?" category="Walk" key="foot">
      </input>
    </inputSet>
  
+   <inputSet id="train-route">
+     <input type="route" name="Train Route" description="Train route" category="Transport" priority="low" presence="onTagMatch">
+       <match k="type" v="route"/>
+       <match k="route" v="train"/>
+       <icon image="features/transport__railway.png">
+         <font size="12pt">${name|operator} <b>(${ref})</b></font>
+       </icon>
+     </input>
+   </inputSet>
    <inputSet id="cycle">
      <inputSet ref="bicycle-permission"/>
      <input type="route" name="National Cycle Routes" description="A signposted route in a National Cycle Network, or nearest equivalent." category="Cycle" priority="low">
        <choice value="designated" text="Designated" description="Permitted, according to signs or specific local laws."/>
      </input>
  
 -    <input type="choice" name="Horses" category="Restrictions" key="horse" description="Are cars and other private vehicles allowed?">
 +    <inputSet ref="hores-permission" />
 +
 +  </inputSet>
 +
 +  <inputSet id="horse-permission">
 +    <input type="choice" name="Horses" category="Restrictions" key="horse" description="Are horses allowed?">
        <choice value="yes" text="Allowed" description="General right of way."/>
        <choice value="no" text="Prohibited" description="No access to the public."/>
        <choice value="permissive" text="Permissive" description="Access permitted through private land."/>
        <choice value="private" text="Private" description="No access to the public, except individual exceptions."/>
        <choice value="designated" text="Designated" description="Permitted, according to signs or specific local laws."/>
      </input>
 -
    </inputSet>
  
    <inputSet id="places">
        <choice value="35000" text="35 kV"/>
        <choice value="110000" text="110 kV"/>
        <choice value="132000" text="132 kV"/>
 -      <choice value="138000" text="238 kV"/>
 +      <choice value="138000" text="138 kV"/>
        <choice value="220000" text="220 kV"/>
        <choice value="380000" text="380 kV"/>
 +      <choice value="500000" text="500 kV"/>
      </input>
    </inputSet>
  
        <choice value="volleyball" text="Volleyball"/>
      </input>
    </inputSet>
+   
+   <inputSet id="wheelchair-basic">
+     <input type="choice" name="Wheelchair" key="wheelchair" presence="onTagMatch" category="Details">
+       <choice value="yes" text="Yes: ramps/elevators/etc" />
+       <choice value="no" text="No: inaccessible to wheelchairs" />
+       <choice value="limited" text="Limited accessibility" />
+     </input>
+   </inputSet>      
  
  <!-- Features -->
  
index 483ee8eb6c8532d598db7290a7cad00ed10c6358,e9e17d200ee6ea42f64cde0a35f63318d09e08ba..a6462be6d90e6bffd3b64ba2a290318fb377eb28
@@@ -14,6 -14,8 +14,8 @@@
          <inputSet ref="embankment-cutting"/>
          <inputSet ref="rail-electrification"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
+         
        </feature>
      
      
@@@ -29,6 -31,7 +31,7 @@@
          <tag k="railway" v="rail"/>
          <tag k="service" v="spur"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
@@@ -44,6 -47,7 +47,7 @@@
          <tag k="railway" v="rail"/>
          <tag k="service" v="siding"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
@@@ -56,6 -60,7 +60,7 @@@
          <line/>
          <tag k="railway" v="preserved"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
@@@ -70,6 -75,7 +75,7 @@@
          <line/>
          <tag k="railway" v="disused"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
@@@ -82,6 -88,7 +88,7 @@@
          <line/>
          <tag k="railway" v="abandoned"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
          <inputSet ref="embankment-cutting"/>
          <inputSet ref="rail-electrification"/>
          <inputSet ref="common"/>
+         <inputSet ref="tram-route"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
      
          <line/>
          <tag k="railway" v="tram"/>
 -        <input ref="tram-route"/>
 +        <inputSet ref="tram-route"/>
          <inputSet ref="bridge"/>
          <inputSet ref="tunnel"/>
          <inputSet ref="embankment-cutting"/>
          <inputSet ref="embankment-cutting"/>
          <inputSet ref="rail-electrification"/>
          <inputSet ref="common"/>
+         <inputSet ref="train-route"/>
        </feature>
      
      
      <inputSet ref="names"/>
      <input type="freetext" presence="onTagMatch" category="Details" name="Operator" key="operator" description="The provider of the postal service" priority="low"/>
      <input type="number" minimum="0" maximum="99999" stepSize="1" presence="always" category="Parking" name="Capacity" key="capacity" description="The number of cars that can be parked in the car park"/>
 +    <input type="choice" presence="always" category="Parking" name="Type" key="parking" priority="high">
 +      <choice value="surface" text="Surface (outdoor)" />
 +      <choice value="multi-storey" text="Multi-storey" />
 +      <choice value="underground" text="Underground" />
 +      <choice value="garage" text="Garage" />
 +      <choice value="park_and_ride" text="Park-and-ride" />
 +      <choice value="garage_boxes" text="Garage boxes" />
 +    </input>
 +    <input type="freetext" presence="onTagMatch" category="Parking" name="Maximum stay" key="maxstay" description="The maximum permitted duration of parking (eg, 4h)."/>
      <inputSet ref="fee"/>
      <inputSet ref="common"/>
    </feature>
      <input type="freetext" presence="onTagMatch" category="Details" name="Operator" key="operator" description="The provider of the service" priority="low"/>
      <input type="number" minimum="1" maximum="99999" stepSize="1" presence="onTagMatch" category="Details" name="Platforms" key="platforms" description="The number of passenger platforms at the station" priority="low"/>
      <inputSet ref="common"/>
+     <inputSet ref="train-route"/>
+     
    </feature>
  
  
      <inputSet ref="common"/>
    </feature>
  
+   <feature name="Train Route">
+     <category>transport</category>
+     <icon image="features/transport__railway.png">
+       <font size="12pt">
+         ${name|operator} <b>(${ref})</b>
+       </font>
+     </icon>
+     <relation/>
+     <tag k="type" v="route"/>
+     <tag k="route" v="train"/>
+     <input type="freetext" presence="always" category="Details" name="Name" priority="high" key="name" description="Official route name"/>
+     <input type="freetext" presence="always" category="Details" name="Reference" priority="high" key="ref" description="The official reference number"/>
+     <input type="freetext" presence="always" category="Details" name="Network" key="network" description="The network of the train service" priority="high"/>
+     <input type="freetext" presence="always" category="Details" name="Operator" key="operator" description="The provider of the train service" priority="low"/>
+     <input type="freetext" presence="onTagMatch" category="Details" name="Colour code" key="colour" description="Official colour designation for the route, if any." priority="low" />
+     <inputSet ref="source"/>
+     <inputSet ref="wheelchair-basic" />
+   </feature>
        
  </featureGroup>