relation actions menu. This should make it easier to merge relations, etc. etc.
authorRichard Fairhurst <richard@systemed.net>
Fri, 14 Jan 2011 19:08:41 +0000 (19:08 +0000)
committerRichard Fairhurst <richard@systemed.net>
Fri, 14 Jan 2011 19:08:41 +0000 (19:08 +0000)
TODO.txt
net/systemeD/halcyon/connection/Entity.as
net/systemeD/halcyon/connection/EntityCollection.as
net/systemeD/halcyon/connection/Relation.as
net/systemeD/potlatch2/TagViewer.mxml

index 398f48e332a234130dd8c08f6b5eeeac3af6e248..6dfebc4ab4d5a29ea40325f9eee2cf5680c48cc5 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -27,6 +27,7 @@ Potlatch 2: main outstanding issues
 * 'Select relation' panel could be sorted by something useful (e.g. ref for route relations)
 * Checkbox needs a clear button, or to be changed to a ✓✗? triplet
 * Relations should talk to FunctionKeyManager too, so you can assign a route to a particular key
+* RelationsGrid should be a discrete component, so we don't repeat ourselves so much in TagViewer.mxml
 
 == UI ==
 
index 3e9204df4bb295a01f5b9d993d5c1b2bac654efc..4c3f70e2cab76d43ca7267ea8623581b672f16dd 100644 (file)
@@ -31,7 +31,7 @@ package net.systemeD.halcyon.connection {
             modified = id < 0;
         }
 
-        /** ID for the entity. */
+        /** OSM ID. */
         public function get id():Number {
             return _id;
         }
@@ -41,16 +41,22 @@ package net.systemeD.halcyon.connection {
             return _version;
         }
 
-        /** User identifier associated with the entity. (?) */
+        /** User ID who last edited this entity (from OSM API). */
         public function get uid():Number {
             return _uid;
         }
 
+               /** Is entity fully loaded, or is it just a placeholder reference (as a relation member)? */
         public function get loaded():Boolean {
             return _loaded;
         }
 
-        /** Most recent modification of the entity. */
+               /** List of entities. Overridden by EntityCollection. */
+               public function get entities():Array {
+                       return [this];
+               }
+
+        /** Most recent modification of the entity (from OSM API). */
         public function get timestamp():String {
             return _timestamp;
         }
index f0e84058256cda394ca77fdf50271224c36cc092..6056cc6c1bbbe4619e2ac6d54d729bbd1227ce6e 100644 (file)
@@ -32,7 +32,7 @@ package net.systemeD.halcyon.connection {
                        }
         }
                
-               public function get entities():Array {
+               public override function get entities():Array {
                        return _entities;
                }
                
index 8ac31927f11b97ab1a6c9a8b0035c292a1fdbcc0..e6bdbd155389d00a3e82dc4886091c629835643f 100644 (file)
@@ -28,6 +28,15 @@ package net.systemeD.halcyon.connection {
             return members.length;
         }
 
+               public function get memberEntities():Array {
+                       var list:Array=[];
+                       for (var index:uint = 0; index < members.length; index++) {
+                               var e:Entity=members[index].entity;
+                               if (list.indexOf(e)==-1) list.push(e);
+                       }
+                       return list;
+               }
+
         public function findEntityMemberIndex(entity:Entity):int {
             for (var index:uint = 0; index < members.length; index++) {
                 var member:RelationMember = members[index];
index aa776a136c962f21e09ba5833a111e4a287249a3..b6db2ec293759234a210ef02b7251ba20175f750 100644 (file)
                 <mx:DataGridColumn editable="true" dataField="role" headerText="Role">
                     <mx:itemEditor><mx:Component><mx:TextInput restrict="&#x0020;-&#x10FFFF;" /></mx:Component></mx:itemEditor>
                 </mx:DataGridColumn>
+                               <mx:DataGridColumn width="20" editable="false">
+                                       <mx:itemRenderer>
+                                               <mx:Component>
+                                   <mx:HBox horizontalAlign="center" verticalAlign="middle">
+                                                               <mx:PopUpButton arrowButtonWidth="12" paddingLeft="0" paddingRight="0" width="12" height="12" 
+                                                                               open="{outerDocument.updateRelationMenu(event);}" 
+                                                                               creationComplete="{outerDocument.createRelationMenu(PopUpButton(event.target));}"/>
+                                                       </mx:HBox>
+                                               </mx:Component>
+                                       </mx:itemRenderer>
+                               </mx:DataGridColumn>
             </mx:columns>
         </mx:DataGrid>
 
             <mx:DataGridColumn editable="true" dataField="role" headerText="Role">
                 <mx:itemEditor><mx:Component><mx:TextInput restrict="&#x0020;-&#x10FFFF;" /></mx:Component></mx:itemEditor>
             </mx:DataGridColumn>
+                       <mx:DataGridColumn width="20" editable="false">
+                               <mx:itemRenderer>
+                                       <mx:Component>
+                           <mx:HBox horizontalAlign="center" verticalAlign="middle">
+                                                       <mx:PopUpButton arrowButtonWidth="12" paddingLeft="0" paddingRight="0" width="12" height="12" 
+                                                                       open="{outerDocument.updateRelationMenu(event);}" 
+                                                                       creationComplete="{outerDocument.createRelationMenu(PopUpButton(event.target));}"/>
+                                               </mx:HBox>
+                                       </mx:Component>
+                               </mx:itemRenderer>
+                       </mx:DataGridColumn>
         </mx:columns>
     </mx:DataGrid>
     <mx:HBox horizontalAlign="right" width="100%">
       import mx.events.*;
       import mx.core.*;
       import mx.managers.PopUpManager;
+      import mx.controls.Menu;
       import flash.geom.Point;
       import flash.net.*;
       import mx.events.DragEvent;
       private var tw:CategorySelector = null;
       private var feature:Feature = null;
 
+      private var rowData:Object;              // relation membership reference, needed so it's accessible from relation actions menu
+
          public function setEntity(entities:Array, layer:VectorLayer=null):void {
                UIComponent.suspendBackgroundProcessing();
 
           PopUpManager.centerPopUp(panel);
       }
 
+       /** Create relation actions menu */
+
+       public function createRelationMenu(button:PopUpButton):void {
+               var menu:Menu = new Menu(); 
+               var dp:Object = [ {label: "Select all members"}, 
+                                                 {label: "Deselect all members"}, 
+                                                 {label: "Add selection to this relation", enabled: false} ]; 
+               menu.dataProvider = dp; 
+               menu.addEventListener("itemClick", selectRelationMenu); 
+               button.popUp = menu;
+       }
+
+       /** Enable 'add selection to...' entry only if some of the selection isn't in the relation.
+           Called each time the menu is clicked. */
+       
+       public function updateRelationMenu(event:Event):void {
+               rowData=event.target.parent.data;       // this makes it accessible from selectRelationMenu
+               var menu:Menu = Menu(event.target.popUp);
+               var enable:Boolean = false;
+               if (selectedEntity != null && selectedEntity is EntityCollection) {
+                       // Enable only if some entities aren't a member of the relation
+                       enable=!rowData.universal;
+               }
+               if (enable==menu.dataProvider[2].enabled) return;
+               menu.dataProvider[2].enabled=enable;
+               menu.invalidateList();
+       }
+
+       /** Do the action selected in the relation actions menu */
+
+       public function selectRelationMenu(event:MenuEvent):void {
+               var rel:Relation=rowData.relation;
+               var entities:Array;
+               var controller:EditController=Application.application.theController;
+               switch (event.index) {
+                       case 0: // Select all members
+                               entities=selectedEntity.entities.concat(rel.memberEntities);
+                               entities=entities.filter(function(e:*, i:int, arr:Array):Boolean { return arr.indexOf(e) == i } );      // remove duplicates
+                               // ** FIXME: This is a really horrible way of changing the controller state
+                               controller.setState(controller.findStateForSelection(entities));
+                               break;
+
+                       case 1: // Deselect all members
+                               entities=selectedEntity.entities;
+                               entities=entities.filter(function(e:*, i:int, arr:Array):Boolean { return !e.hasParent(rel) } );
+                               controller.setState(controller.findStateForSelection(entities));
+                               break;
+
+                       case 2: // Add selection to this relation
+                               var undo:CompositeUndoableAction=new CompositeUndoableAction("Remove selection from relations");
+                               for each (var entity:Entity in selectedEntity.entities) {
+                                       if (!entity.hasParent(rel)) {
+                                               rel.appendMember(new RelationMember(entity,''), undo.push);
+                                       }
+                               }
+                               MainUndoStack.getGlobalStack().addAction(undo);
+                               break;
+               }
+       }
+
       private function tagChanged(event:TagEvent):void {
              if(selectedEntity != null && selectedEntity is EntityCollection) {
                        setupMultiAdvanced(selectedEntity);