can now change tags in the 'Advanced' mode
authorDave Stubbs <osm@randomjunk.co.uk>
Mon, 15 Jun 2009 19:57:54 +0000 (19:57 +0000)
committerDave Stubbs <osm@randomjunk.co.uk>
Mon, 15 Jun 2009 19:57:54 +0000 (19:57 +0000)
12 files changed:
README.txt
halcyon.mxml
map_features.xml
net/systemeD/halcyon/Map.as
net/systemeD/halcyon/TagViewer.mxml
net/systemeD/halcyon/WayUI.as
net/systemeD/halcyon/connection/Connection.as
net/systemeD/halcyon/connection/Entity.as
net/systemeD/halcyon/connection/Node.as
net/systemeD/halcyon/connection/Tag.as
net/systemeD/halcyon/connection/TagEvent.as [new file with mode: 0644]
net/systemeD/halcyon/connection/Way.as

index 58f1c29fd8b71b8d02d0a024232ae05cacb8b4a6..8d4d4020706058a8932d1b10bc7c719910f137e2 100644 (file)
@@ -22,6 +22,9 @@ Compiling:
 * compile 1 
   - compile each subsequent time (_much_ faster than using mxmlc every time)
 
+* for nice debug reports compile with the mxmlc command:
+  mxmlc -managers=flash.fonts.AFEFontManager -compiler.debug -compiler.verbose-stacktraces -output=halcyon.swf halcyon.mxml
+
 Running:
 * Make sure test.yaml and icons/ are in the same directory as halcyon.swf
 * Open halcyon.swf in your browser
index cb1c45684c20653a78a0e892bd0318afa2f2a5fb..bd1f10b5fbc797a9071fd9e04e4def790fd8a50f 100755 (executable)
@@ -8,12 +8,14 @@
 
     <mx:HDividedBox width="100%" height="100%">
 
-      <mx:VBox height="100%" width="25%">
-        <mx:Button label="+" click="theMap.zoomIn();"/>
-        <mx:Button label="-" click="theMap.zoomOut();"/>
+      <mx:VBox height="100%" width="25%" horizontalAlign="right">
+        <mx:HBox>
+          <mx:Button label="-" click="theMap.zoomOut();"/>
+          <mx:Button label="+" click="theMap.zoomIn();"/>
+        </mx:HBox>
         <halcyon:TagViewer width="100%" height="100%" id="tagViewer"/>
       </mx:VBox>
-      <mx:Canvas id="map_area" width="75%"/>
+      <mx:Canvas id="map_area" width="75%" height="100%" resize="onResizeMap()"/>
     </mx:HDividedBox>
 
        <mx:Script><![CDATA[
 
                private function initApp():void {
 
+                       Globals.vars.map_area=map_area;
                        Globals.vars.root=map_area.rawChildren;                 // set up global reference to root level
                        var _root:IChildList=map_area.rawChildren;              // convenient local shorthand
 
                        // map backdrop object
+            var w:uint = map_area.width;
+            var h:uint = map_area.height;
             var b:Sprite = new Sprite();
-            b.height=200; b.width=200;
+            b.height=h; b.width=w;
             b.graphics.beginFill(0xFFFFEA,100); 
-            b.graphics.drawRect(0,0,200,200); 
+            b.graphics.drawRect(0,0,w,h); 
             b.graphics.endFill();
                        _root.addChild(b);
 
                        theMap=new Map();
                        theMap.backdrop=b;
                        _root.addChild(theMap);
+            theMap.updateSize(w, h);
 
                        // add mask for map
                        var s:Sprite=new Sprite();
                        s.graphics.beginFill(0xFFFFFF,100);
-                       s.graphics.drawRect(0,0,200,200);
+                       s.graphics.drawRect(0,0,w,h);
                        s.graphics.endFill();
                        _root.addChild(s);
                        theMap.mask=s;
 
                        // add crosshair
-                       s=new Sprite();
+                       /*s=new Sprite();
                        s.graphics.lineStyle(2,0);
                        s.graphics.moveTo(stage.stageWidth/2-20,stage.stageHeight/2);
                        s.graphics.lineTo(stage.stageWidth/2+20,stage.stageHeight/2);
                        s.graphics.moveTo(stage.stageWidth/2,stage.stageHeight/2-20);
                        s.graphics.lineTo(stage.stageWidth/2,stage.stageHeight/2+20);
-                       _root.addChild(s);
+                       _root.addChild(s);*/
 
                        // mouse-up handler attached to stage, so the user can release outside the map
                        stage.addEventListener(MouseEvent.MOUSE_UP, theMap.mouseUpHandler);
                        t.multiline=true;
                        _root.addChild(t);
                        Globals.vars.debug=t;
+            t.visible = false;
 
             var controller:EditController = new EditController(theMap, tagViewer);
             controller.setActive();
                }
 
+        public function onResizeMap():void {
+            if ( theMap != null )
+                theMap.updateSize(map_area.width, map_area.height);
+        }
+
        ]]></mx:Script>
 
 </mx:Application>
index f8c99550f56a7a1295c52303047f877ff0e764bf..099d104dbd3916efa0bb3cff6544bc5c1d70fdec 100644 (file)
@@ -5,7 +5,7 @@
   <!-- Roads -->
 
   <feature name="Motorway">
-    <icon background="blue" image="features/highway__motorway.png">
+    <icon image="features/highway__motorway.png">
       <font size="16pt"><b>${ref}</b></font><br/>
     </icon>
 
@@ -19,7 +19,7 @@
   </feature>
 
   <feature name="Trunk Road">
-    <icon background="green" image="features/highway__trunk.png">
+    <icon image="features/highway__trunk.png">
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
     </icon>
@@ -29,7 +29,7 @@
   </feature>
 
   <feature name="Primary Road">
-    <icon background="red">
+    <icon>
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
     </icon>
@@ -39,7 +39,7 @@
   </feature>
 
   <feature name="Secondary Road">
-    <icon background="orange">
+    <icon>
       <font size="16pt"><b>${ref}</b></font><br/>
       <font size="10pt">${name}</font>
     </icon>
@@ -49,7 +49,7 @@
   </feature>
 
   <feature name="Tertiary Road">
-    <icon background="yellow">
+    <icon>
       <font size="14pt"><b>${name}</b></font><br/>
       <font size="10pt">${ref}</font>
     </icon>
@@ -59,7 +59,7 @@
   </feature>
 
   <feature name="Residential Road">
-    <icon background="white" image="features/highway__residential.png">
+    <icon image="features/highway__residential.png">
       <font size="14pt"><b>${name}</b></font><br/>
       <font size="6pt">${postal_code}</font>
     </icon>
@@ -69,7 +69,7 @@
   </feature>
 
   <feature name="Road">
-    <icon background="white" image="features/highway__unclassified.png">
+    <icon image="features/highway__unclassified.png">
       <font size="14pt"><b>${name}</b></font>
     </icon>
 
@@ -78,7 +78,7 @@
   </feature>
 
   <feature name="Service Road">
-    <icon background="white" image="features/highway__service.png">
+    <icon image="features/highway__service.png">
       <font size="14pt"><b>${name}</b></font>
     </icon>
     <description>
@@ -90,7 +90,7 @@
   </feature>
 
   <feature name="Unknown Road">
-    <icon background="gray">
+    <icon>
       <font size="10pt">This road has not been given a specific type. It's a road, and that's all that's known.</font>
     </icon>
 
@@ -99,7 +99,7 @@
   </feature>
 
   <feature name="Living Street">
-    <icon background="white">
+    <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
 
   </feature>
 
   <feature name="Track">
-    <icon background="white">
+    <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
 
   </feature>
 
   <feature name="Pedestrian Road">
-    <icon background="white">
+    <icon>
       <font size="14pt"><b>${name}</b></font>
     </icon>
 
   <!-- Paths -->
 
   <feature name="Cycle Path">
-    <icon background="white">
+    <icon>
+      ${name} <i>${ncn_ref} ${rcn_ref} ${lcn_ref} ${ref}</i>
     </icon>
 
     <line/>
   </feature>
 
   <feature name="Foot Path">
-    <icon background="white">
+    <icon>
+      ${name} <i>${ref}</i>
     </icon>
 
     <line/>
   </feature>
 
   <feature name="Bridleway">
-    <icon background="white">
+    <icon>
     </icon>
 
     <line/>
   </feature>
 
   <feature name="Steps">
-    <icon background="white">
+    <icon>
     </icon>
 
     <line/>
   <!-- building -->
 
   <feature name="Building">
-    <icon background="white">
+    <icon>
       <b>${name} ${addr:housename}</b><br/>
       ${addr:housenumber} ${addr:street} ${addr:postcode}
     </icon>
index 1336784b5259fc475b8f23b1c719b4cd5d03cbab..759e3e15fb978a006eeac05500eeddfe8a289aa7 100755 (executable)
@@ -110,7 +110,7 @@ package net.systemeD.halcyon {
                        ruleset.load("test.yaml?d="+Math.random());
 //                     rules.initExample();            // initialise dummy rules
 
-                       updateSize();
+                       //updateSize();
 
                        scale=startscale;
                        scalefactor=MASTERSCALE/Math.pow(2,14-scale);
@@ -164,9 +164,17 @@ package net.systemeD.halcyon {
                // ------------------------------------------------------------------------------------------
                // Resize map size based on current stage and height
 
-               public function updateSize():void {
-                       mapwidth =stage.stageWidth; backdrop.width=mapwidth; mask.width=mapwidth;
-                       mapheight=stage.stageHeight; backdrop.height=mapheight; mask.height=mapheight;
+               public function updateSize(w:uint, h:uint):void {
+                       mapwidth = w;
+                       mapheight= h;
+            if ( backdrop != null ) {
+                backdrop.width=mapwidth;
+                backdrop.height=mapheight;
+            }
+            if ( mask != null ) {
+                mask.width=mapwidth;
+                mask.height=mapheight;
+            }
                }
 
                // ------------------------------------------------------------------------------------------
@@ -282,6 +290,7 @@ package net.systemeD.halcyon {
                
                public function keyUpHandler(event:KeyboardEvent):void {
 // addDebug("pressed "+event.keyCode);
+            if ( !event.ctrlKey ) return;
                        if (event.keyCode==82) { this.redraw(); }                       // R - redraw
                        if (event.keyCode==73) { this.zoomIn(); }                       // I - zoom in
                        if (event.keyCode==79) { this.zoomOut(); }                      // O - zoom out
index 7283484fd1e269acdbeea0dd40ccfa8ad03d5aa2..da789ed597e4f842e4a0b31d3bfb1fe8ab4aa9f1 100644 (file)
@@ -8,27 +8,29 @@
   <mx:ViewStack id="stack" width="100%" height="100%">
 
   <mx:VBox width="100%" height="100%" label="Simple">
-    <mx:HBox borderStyle="solid" verticalAlign="middle" width="100%" paddingLeft="3">
+    <mx:HBox borderStyle="inset" verticalAlign="middle" width="100%" paddingLeft="3" id="iconContainer">
         <mx:Image id="iconImage"/>
         <mx:Text condenseWhite="true" width="100%" id="iconText"/>
         <mx:LinkButton label="?" click="openDescription()" id="helpLabel"/>
     </mx:HBox>
   </mx:VBox>
 
-  <mx:VBox width="100%" height="100%" label="Advanced" initialize="checkAdvanced()">
+  <mx:VBox width="100%" height="100%" label="Advanced" initialize="checkAdvanced()" verticalGap="1">
     <mx:Label id="advancedID">
       <mx:htmlText><![CDATA[<i>No Selection</i>]]></mx:htmlText>
     </mx:Label>
 
-    <mx:DataGrid width="100%" height="100%" id="advancedTagGrid">
+    <mx:DataGrid editable="true" width="100%" height="100%" id="advancedTagGrid">
             <mx:columns>
-                <mx:DataGridColumn dataField="key" headerText="Key"/>
-                <mx:DataGridColumn dataField="value" headerText="Value"/>
+                <mx:DataGridColumn editable="true" dataField="key" headerText="Key"/>
+                <mx:DataGridColumn editable="true" dataField="value" headerText="Value"/>
             </mx:columns>
     </mx:DataGrid>
 
-    <mx:Label text="Key: {advancedTagGrid.selectedItem.key}"/>
-    <mx:Label text="Value: {advancedTagGrid.selectedItem.value}"/>
+    <mx:HBox horizontalAlign="right" width="100%">
+      <mx:LinkButton label="Delete" click="removeTag()"/>
+      <mx:LinkButton label="Add" click="addNewTag()"/>
+    </mx:HBox>
   </mx:VBox>
 
   </mx:ViewStack>
       import net.systemeD.halcyon.connection.*;
       import net.systemeD.halcyon.mapfeatures.*;
 
+      import mx.collections.*
+
       private var mapFeatures:MapFeatures;
       private var selectedEntity:Entity;
       private var variablesPattern:RegExp = /[$][{]([^}]+)[}]/g;
+      private var collection:ArrayCollection;
 
       public function setEntity(entity:Entity):void {
-          this.selectedEntity = entity;
+          if ( selectedEntity != entity ) {
+              if ( selectedEntity != null )
+                  selectedEntity.removeEventListener(Connection.TAG_CHANGE, tagChanged);
+              selectedEntity = entity;
+              selectedEntity.addEventListener(Connection.TAG_CHANGE, tagChanged);
+          }
 
           if ( advancedID != null )
               setupAdvanced(entity);
 
-          var feature:XML = mapFeatures.findMatchingFeature(entity);
+          refreshFeatureIcon();
+      }
+
+      private function refreshFeatureIcon():void {
+          var feature:XML = mapFeatures.findMatchingFeature(selectedEntity);
           if ( feature != null )
-              setFeatureIcon(entity, feature);
+              setFeatureIcon(selectedEntity, feature);
           else
-              blankFeatureIcon(entity);
+              blankFeatureIcon(selectedEntity);
       }
 
       private function setFeatureIcon(entity:Entity, feature:XML):void {
@@ -78,7 +92,9 @@
 
       private function blankFeatureIcon(entity:Entity):void {
           iconImage.source = null;
-          iconText.htmlText = entity == null ? "<i>Nothing selected</i>" : "<b>Not recognised</b><br/>Try looking at advanced";
+          iconText.htmlText = entity == null ?
+               "<i>Nothing selected</i>" :
+               "<b>Not recognised</b><br/>Try looking at the tags under the advanced properties";
       }
 
       private function checkAdvanced():void {
           if ( entity is Node ) entityText = "Node";
           else if ( entity is Way ) entityText = "Way";
           else if ( entity is Relation ) entityText = "Relation";
+
           advancedID.htmlText = entityText+": <b>"+entity.id+"</b>";
-          advancedTagGrid.dataProvider = entity.getTagArray();
+
+          if ( collection == null ) {
+              collection = new ArrayCollection();
+              //var sort:Sort = new Sort();
+              //sort.fields = [new SortField("key", true)];
+              //collection.sort = sort;
+              //collection.refresh();
+              advancedTagGrid.dataProvider = collection;
+          }
+          collection.removeAll();
+          var tags:Array = entity.getTagArray();
+          tags.sortOn("key");
+          for each(var tag:Tag in tags)
+              collection.addItem(tag);
+      }
+
+      private function tagChanged(event:TagEvent):void {
+          refreshFeatureIcon();
+          
+          if ( collection != null ) {
+              // check to see if the key is already in our list
+              var exists:Boolean = false;
+              var tag:Tag = null;
+              var i:uint;
+              for ( i = 0; i < collection.length && !exists; i++ ) {
+                  tag = Tag(collection.getItemAt(i));
+                  exists = tag.key == event.key;
+              }
+              if ( !exists ) {
+                  tag = new Tag(selectedEntity, event.key, event.newValue);
+                  collection.addItem(tag);
+                  collection.refresh();
+              } else {
+                  if ( event.newValue == null ) {
+                      collection.removeItemAt(i-1);
+                      collection.refresh();
+                  }
+              }
+          }
       }
 
       public function loadFeatures():void {
       public function openDescription():void {
           trace("open description here");
       }
+
+      public function addNewTag():void {
+          var newKey:String = "(new tag)";
+          var newTag:Tag = new Tag(selectedEntity, newKey, "(new value)");
+          collection.addItem(newTag);
+          advancedTagGrid.editedItemPosition = {rowIndex: collection.getItemIndex(newTag), columnIndex: 0};
+      }
+
+      public function removeTag():void {
+          var k:String = advancedTagGrid.selectedItem.key;
+          selectedEntity.setTag(k, null);
+      }
   ]]></mx:Script>
 </mx:VBox>
 
index 4cf6f8a1509a79956c91f3dd3100a80c487e0e60..be88475d4b17f1b234183782308c3b7d6ad1aea1 100755 (executable)
@@ -38,8 +38,13 @@ package net.systemeD.halcyon {
                        this.way = way;
                        this.map = map;
             init();
+            way.addEventListener(Connection.TAG_CHANGE, wayTagChanged);
                }
                
+        private function wayTagChanged(event:TagEvent):void {
+            redraw();
+        }
+
                private function init():void {
                        recalculate();
                        redraw();
index b3caff77ffa076e67005604b02cda382952c8596..73207ca0387d037a283dcf606282c8875362c9db 100755 (executable)
@@ -30,6 +30,7 @@ package net.systemeD.halcyon.connection {
         public static var NEW_WAY:String = "new_way";
         public static var NEW_RELATION:String = "new_relation";
         public static var NEW_POI:String = "new_poi";
+        public static var TAG_CHANGE:String = "tag_change";
 
         // store the data we download
         private var negativeID:Number = -1;
index 1836fa0d5bb0f477bcb62760a79d488bc0452e8a..5aff1b51efd08a7c9c783ea41920c07e2fcac01a 100644 (file)
@@ -1,6 +1,8 @@
 package net.systemeD.halcyon.connection {
 
-    public class Entity {
+    import flash.events.EventDispatcher;
+
+    public class Entity extends EventDispatcher {
         private var _id:Number;
         private var _version:uint;
         private var tags:Object = {};
@@ -30,7 +32,23 @@ package net.systemeD.halcyon.connection {
         }
 
         public function setTag(key:String, value:String):void {
-            tags[key] = value;
+            var old:String = tags[key];
+            if ( old != value ) {
+                if ( value == null || value == "" )
+                    delete tags[key];
+                else
+                    tags[key] = value;
+                dispatchEvent(new TagEvent(Connection.TAG_CHANGE, this, key, key, old, value));
+            }
+        }
+
+        public function renameTag(oldKey:String, newKey:String):void {
+            var value:String = tags[oldKey];
+            if ( oldKey != newKey ) {
+                delete tags[oldKey];
+                tags[newKey] = value;
+                dispatchEvent(new TagEvent(Connection.TAG_CHANGE, this, oldKey, newKey, value, value));
+            }
         }
 
         public function getTagList():TagList {
@@ -47,7 +65,7 @@ package net.systemeD.halcyon.connection {
         public function getTagArray():Array {
             var copy:Array = [];
             for (var key:String in tags )
-                copy.push(new Tag(key, tags[key]));
+                copy.push(new Tag(this, key, tags[key]));
             return copy;
         }
 
index c78c11139c3e4d81572f82c9095aa2d1c881dc4e..bf7263397d82ca241a2cc2cdfbcc81f3f488ac67 100644 (file)
@@ -32,7 +32,7 @@ package net.systemeD.halcyon.connection {
             this._lon = lon;
         }
 
-        public function toString():String {
+        public override function toString():String {
             return "Node("+id+"@"+version+"): "+lat+","+lon+" "+getTagList();
         }
 
index 76eee3212fcefd8bb2d94a9aa79526d1401cffc0..acb3ee5fedefa73ae34667f8b8b42d41c6d5b05e 100644 (file)
@@ -1,12 +1,35 @@
 package net.systemeD.halcyon.connection {
 
     public class Tag {
-        public var key:String;
-        public var value:String;
+        private var entity:Entity;
+        private var _key:String;
+        private var _value:String;
 
-        public function Tag(key:String, value:String) {
-            this.key = key;
-            this.value = value;
+        public function Tag(entity:Entity, key:String, value:String) {
+            this.entity = entity;
+            entity.addEventListener(Connection.TAG_CHANGE, tagChanged, false, 0, true);
+            this._key = key;
+            this._value = value;
+        }
+
+        public function get key():String { return _key; }
+        public function get value():String { return _value; }
+
+        public function set key(key:String):void {
+            var oldKey:String = _key;
+            var realVal:String = entity.getTag(oldKey);
+            _key = key;
+            if ( oldKey != null && realVal != null && realVal != "" )
+                entity.renameTag(oldKey, key);
+        }
+
+        public function set value(value:String):void {
+            entity.setTag(_key, value);
+        }
+
+        private function tagChanged(event:TagEvent):void {
+            if ( event.key == _key )
+                _value = event.newValue;
         }
     }
 
diff --git a/net/systemeD/halcyon/connection/TagEvent.as b/net/systemeD/halcyon/connection/TagEvent.as
new file mode 100644 (file)
index 0000000..9cd917e
--- /dev/null
@@ -0,0 +1,30 @@
+package net.systemeD.halcyon.connection {
+
+    import flash.events.Event;
+
+    public class TagEvent extends EntityEvent {
+        private var _key:String;
+        private var _oldKey:String;
+        private var _oldValue:String;
+        private var _newValue:String;
+
+        public function TagEvent(type:String, item:Entity, oldKey:String, newKey:String, oldValue:String, newValue:String) {
+            super(type, item);
+            this._key = newKey;
+            this._oldKey = oldKey;
+            this._oldValue = oldValue;
+            this._newValue = newValue;
+        }
+
+        public function get key():String { return _key; }
+        public function get oldKey():String { return _oldKey; }
+        public function get oldValue():String { return _oldValue; }
+        public function get newValue():String { return _newValue; }
+
+        public override function toString():String {
+            return super.toString() + "::'"+_oldKey+"' '"+_key +"' '"+_oldValue+"' '"+_newValue+"'";
+        }
+    }
+
+}
+
index ec37b0ff18e6ad5e6d05642340d261e0ccd49b41..e3e6333ccf5683632f8608aa5df746e46755fe55 100644 (file)
@@ -29,7 +29,7 @@ package net.systemeD.halcyon.connection {
             nodes.splice(index, 1);
         }
 
-        public function toString():String {
+        public override function toString():String {
             return "Way("+id+"@"+version+"): "+getTagList()+
                      " "+nodes.map(function(item:Node,index:int, arr:Array):String {return item.id.toString();}).join(",");
         }