Show changeset comments in the history dialogue
authorRichard Fairhurst <richard@systemeD.net>
Fri, 28 Sep 2012 14:45:17 +0000 (15:45 +0100)
committerRichard Fairhurst <richard@systemeD.net>
Fri, 28 Sep 2012 14:45:17 +0000 (15:45 +0100)
net/systemeD/halcyon/connection/Changeset.as
net/systemeD/halcyon/connection/Connection.as
net/systemeD/halcyon/connection/Entity.as
net/systemeD/halcyon/connection/XMLBaseConnection.as
net/systemeD/halcyon/connection/XMLConnection.as
net/systemeD/potlatch2/history/HistoryDialog.mxml

index de7d97a..3f6ed61 100644 (file)
@@ -14,6 +14,13 @@ package net.systemeD.halcyon.connection {
                public override function getType():String {
                        return 'changeset';
                }
+
+               public function get comment():String {
+                       var t:Object=getTagsHash();
+                       var s:String=t['comment'] ? t['comment'] : '';
+                       if (t['source']) { s+=" ["+t['source']+"]"; }
+                       return s;
+               }
     }
 
 }
index 7828885..8032969 100644 (file)
@@ -95,6 +95,7 @@ package net.systemeD.halcyon.connection {
         private var pois:Array = [];
         private var changeset:Changeset = null;
                private var changesetUpdated:Number;
+               private var changesets:Object = {};     // used for fetching history only
                private var modified:Boolean = false;
                public var nodecount:int=0;
                public var waycount:int=0;
@@ -129,6 +130,10 @@ package net.systemeD.halcyon.connection {
             if (relation.loaded) { sendEvent(new EntityEvent(NEW_RELATION, relation),queue); }
         }
 
+               protected function setChangeset(changeset:Changeset):void {
+                       changesets[changeset.id] = changeset;
+               }
+
                protected function setOrUpdateNode(newNode:Node, queue:Boolean):void {
                if (nodes[newNode.id]) {
                                var wasDeleted:Boolean=nodes[newNode.id].isDeleted();
@@ -212,6 +217,10 @@ package net.systemeD.halcyon.connection {
             return markers[id];
         }
 
+        public function getChangeset(id:Number):Changeset {
+            return changesets[id];
+        }
+
                protected function findEntity(type:String, id:*):Entity {
                        var i:Number=Number(id);
                        switch (type.toLowerCase()) {
index 4a91966..7728dd5 100644 (file)
@@ -19,7 +19,9 @@ package net.systemeD.halcyon.connection {
         private var modified:Boolean = false;
         private var _loaded:Boolean = true;
         private var parents:Dictionary = new Dictionary();
-               public var status:String;
+        public var status:String;
+        /** Last changeset in which the Entity was updated. Used only by history calls, therefore we don't bloat the constructor by initialising it. */
+        public var lastChangeset:Number;
         /** Lock against purging when off-screen */
         public var locked:Boolean = false;
         public var deleted:Boolean = false;
index 2ab736a..683e8d7 100644 (file)
@@ -47,6 +47,11 @@ package net.systemeD.halcyon.connection {
                                        fetchSet.add(new Box().fromBbox(minlon,minlat,maxlon,maxlat));
                                }
 
+                               for each(var csData:XML in map.changeset) {
+                                       var cs:Changeset = new Changeset(this, csData.@id, parseTags(csData.tag) );
+                                       setChangeset(cs);
+                               }
+
                                for each(var relData:XML in map.relation) {
                                        id = Number(relData.@id);
                                        version = uint(relData.@version);
index 6b5d8ae..b66c282 100644 (file)
@@ -538,6 +538,7 @@ package net.systemeD.halcyon.connection {
                     nodeData.@timestamp,
                     nodeData.@user
                     );
+                newNode.lastChangeset=nodeData.@changeset;
                 results.push(newNode);
             }
 
@@ -557,6 +558,7 @@ package net.systemeD.halcyon.connection {
                     wayData.@timestamp,
                     wayData.@user
                     );
+                newWay.lastChangeset=wayData.@changeset;
                 results.push(newWay);
             }
 
index aae94c7..c471d43 100644 (file)
@@ -10,7 +10,7 @@
         xmlns:s="library://ns.adobe.com/flex/spark"
         xmlns:help="net.systemeD.potlatch2.help.*"
         title="History for {entity.getType()} {entity.id}"
-        width="600" height="400">
+        width="640" height="400">
 
   <s:layout>
     <s:VerticalLayout />
             </s:GridColumn>
             <s:GridColumn editable="false" dataField="timestamp" headerText="Date" />
             <s:GridColumn editable="false" dataField="diff" headerText="Changes" width="200" showDataTips="true" />
-            <s:GridColumn editable="false" dataField="user" headerText="User" />
             <s:GridColumn editable="false">
-              <s:itemRenderer>
-                <fx:Component>
-                  <s:GridItemRenderer>
-                    <s:VGroup horizontalAlign="center" verticalAlign="middle" width="100%" height="100%">
-                      <s:Button label="Contact Mapper" click="parentDocument.parentDocument.message(data.user)"/>
-                    </s:VGroup>
-                  </s:GridItemRenderer>
-                </fx:Component>
-              </s:itemRenderer>
+              <s:itemRenderer><fx:Component><s:GridItemRenderer>
+                <s:VGroup horizontalAlign="center" verticalAlign="middle" width="100%" height="100%">
+                  <s:Label text="{data.user}" 
+                      color="0x336699"  textDecoration="underline" buttonMode="true" 
+                      click="parentDocument.parentDocument.userPage(data.user)"/>
+                </s:VGroup>
+              </s:GridItemRenderer></fx:Component></s:itemRenderer>
             </s:GridColumn>
+            <s:GridColumn editable="false" dataField="comment" headerText="Comment" width="200" showDataTips="true" />
           </s:ArrayList>
         </s:columns>
       </s:DataGrid>
     [Bindable]
     private var entityStates:ArrayList = new ArrayList();
 
-    // store intermediate states for ways
-    private var wayStates:Array; // an array of ways
+    // store intermediate states
+    private var entityStateList:Array; // an array of objects
     private var wayNodeStates:Array; // an array of arrays of nodes
 
+    /** Changesets used in the history. */
+    private var changesets:Array=[];
+    private var pendingChangesetFetches:uint;
+
     // the number of outstanding asynchronous node history requests,
     // so we know when all have been fetched
     private var pendingNodeFetches:uint;
         }
     }
 
-    private function processNode(results:Array):void {
-        // Simply copy the nodes into the states array
-        // todo sorting or somesuch
+       private function processNode(results:Array):void {
+               entityStateList = results;
+               for each(var node:Node in results) {
+                       changesets.push(node.lastChangeset);
+               }
+               fetchChangesets();
+       }
+       
+       private function displayNodeResults(e:Event):void {
                var arr:Array=[];
                var oldNode:Node;
-               for each (var node:Node in results) {
+               for each (var node:Node in entityStateList) {
                        var changes:Array=[];
                        if (node.version==1) {
                                changes.push("Created");
                                version: node.version,
                                timestamp: node.timestamp.replace('T',' ').replace('Z',''),
                                user: node.user,
-                               diff: changes.length==0 ? "None" : changes.join('; ')
+                               diff: changes.length==0 ? "None" : changes.join('; '),
+                               comment: entity.connection.getChangeset(node.lastChangeset).comment
                        });
                        oldNode=node;
                }
         // In potlatch(2) we show the user the number of different states, bearing in mind
         // node movements (and tag changes?).
 
-        wayStates = results;
+        entityStateList = results;
 
         // figure out the list of nodes that have ever been involved in the way, and fetch them.
         // pendingNode will store each one, and trigger an event when they are all downloaded.
         wayNodeStates = [];
-        addEventListener("pendingNodesAllFetched", processWayStates);
+        addEventListener("pendingNodesAllFetched", fetchChangesets);
 
         var nodes:Object = {};
         var count:uint = 0;
                     count++;
                 }
             }
+            changesets.push(oldWay.lastChangeset);
         }
 
         pendingNodeFetches = count;
     // nodes remaining this will trigger an event.
     private function pendingNode(results:Array):void {
         wayNodeStates.push(results)
+        for each (var n:Node in results) changesets.push(n.lastChangeset);
         pendingNodeFetches--;
         if (pendingNodeFetches == 0) {
             dispatchEvent(new Event("pendingNodesAllFetched"));
         }
     }
 
+       /** Work out which changesets were used, and fetch details for all of them. */
+       private function fetchChangesets(e:Event=null):void {
+               changesets=ArrayUtil.createUniqueCopy(changesets);
+               pendingChangesetFetches=changesets.length;
+               entity.connection.addEventListener(Connection.LOAD_COMPLETED, pendingChangeset);
+               for each (var id:Number in changesets) entity.connection.loadEntityByID("changeset",id);
+        addEventListener("pendingChangesetsAllFetched", (entity is Way) ? processWayStates : displayNodeResults);
+       }
+       
+       private function pendingChangeset(e:Event):void {
+        pendingChangesetFetches--;
+        if (pendingChangesetFetches == 0) dispatchEvent(new Event("pendingChangesetsAllFetched"));
+       }
+
     private function processWayStates(e:Event):void {
         // we now have all the node histories for
         // for each node that has ever been part of the way.
         var revdates:Array = [];
         var revusers:Object = {};
         var revdiffs:Object = {};
+               var revchangesets:Object = {};
 
         var oldWay:Way;
-        for each (var way:Way in wayStates) {
+        for each (var way:Way in entityStateList) {
             // assemble diff
             var changes:Array=[];
             if (way.version==1) {
             revdates.push(way.timestamp);
             revdiffs[way.timestamp] = changes;
             revusers[way.timestamp] = way.user;
+            revchangesets[way.timestamp] = entity.connection.getChangeset(way.lastChangeset);
             oldWay=way;
         }
 
             for each (var node:Node in nodeStates) {
                 revdates.push(node.timestamp);
                 revusers[node.timestamp] = node.user;
+                revchangesets[node.timestamp] = entity.connection.getChangeset(node.lastChangeset);
                 addRevDiff(revdiffs,node.timestamp,"(Node edit)");
             }
         }
 
         revdates = revdates.sort();
         revdates = ArrayUtil.createUniqueCopy(revdates); // (corelib) de-duplicates
-        revdates = revdates.filter(function(e:*, i:int, arr:Array):Boolean { return e >= wayStates[0].timestamp});
+        revdates = revdates.filter(function(e:*, i:int, arr:Array):Boolean { return e >= entityStateList[0].timestamp});
 
         var version:int = 1;
         var subversion:int = 0;
         for each (var revdate:String in revdates) {
           var entitystate:Object = {};
 
-          var w:Way = getEntityAtDate(wayStates, revdate) as Way;
+          var w:Way = getEntityAtDate(entityStateList, revdate) as Way;
 
           if (w.version == version) {
               subversion++;
               version: String(version) + "." + String(subversion),
               timestamp: revdate.replace('T',' ').replace('Z',''),
               user: revusers[revdate],
-              diff: revdiffs[revdate].length==0 ? "None" : revdiffs[revdate].join('; ')
+              diff: revdiffs[revdate].length==0 ? "None" : revdiffs[revdate].join('; '),
+              comment: revchangesets[revdate].comment
           });
         }
 
         return null;
     }
 
-    public function message(user:String):void {
+    public function userPage(user:String):void {
         if (user) {
-            var urlBase:String = entity.connection.apiBase + '../../message/new/';
-            navigateToURL(new URLRequest(urlBase+user), "potlatch_message");
+            var urlBase:String = entity.connection.apiBase + '../../user/';
+            navigateToURL(new URLRequest(urlBase+user), "potlatch_user");
         }
     }
     ]]>