Multiple selection check for non-interactive objects
[potlatch2.git] / net / systemeD / potlatch2 / controller / SelectedMultiple.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         import flash.display.DisplayObject;
4         
5         import net.systemeD.halcyon.AttentionEvent;
6         import net.systemeD.halcyon.connection.*;
7         import net.systemeD.halcyon.connection.actions.MergeWaysAction;
8     import net.systemeD.halcyon.MapPaint;
9
10         public class SelectedMultiple extends ControllerState {
11                 protected var initSelection:Array;
12                 
13                 public function SelectedMultiple(sel:Array, layer:MapPaint=null) {
14                         if (layer) this.layer=layer;
15                         initSelection=sel.concat();
16                 }
17
18                 override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
19                         if (event.type==MouseEvent.MOUSE_MOVE || event.type==MouseEvent.ROLL_OVER || event.type==MouseEvent.MOUSE_OUT) { return this; }
20                         var paint:MapPaint = getMapPaint(DisplayObject(event.target));
21                         var focus:Entity = getTopLevelFocusEntity(entity);
22
23                         if ( event.type == MouseEvent.MOUSE_DOWN && entity && event.ctrlKey && !event.altKey && paint.interactive ) {
24                                 // modify selection
25                                 layer.setHighlight(entity, { selected: toggleSelection(entity) });
26                                 controller.updateSelectionUI();
27
28                                 if (selectCount>1) { return this; }
29                                 return controller.findStateForSelection(selection);
30
31                         } else if ( event.type == MouseEvent.MOUSE_UP && selection.indexOf(focus)>-1 ) {
32                                 return this;
33                         }
34                         var cs:ControllerState = sharedMouseEvents(event, entity);
35                         return cs ? cs : this;
36                 }
37
38                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
39                         if (event.keyCode==74) return mergeWays();                      // 'J' (join)
40                         if (event.keyCode==72) return createMultipolygon();     // 'H' (hole)
41                         var cs:ControllerState = sharedKeyboardEvents(event);
42                         return cs ? cs : this;
43                 }
44                 
45                 public function mergeWays():ControllerState {
46                         var changed:Boolean;
47                         var waylist:Array=selectedWays;
48                         var tagConflict:Boolean=false; 
49                         var relationConflict:Boolean=false;
50                         var mergers:uint=0;
51                         do {
52                                 // ** FIXME - we should have one CompositeUndoableAction for the whole caboodle,
53                                 // but that screws up the execution order and can make the merge not work
54                                 var undo:CompositeUndoableAction = new CompositeUndoableAction("Merge ways");
55                                 changed=tryMerge(waylist, undo);
56                                 if (changed) mergers++;
57                                 MainUndoStack.getGlobalStack().addAction(undo);
58                                 tagConflict     ||= MergeWaysAction.lastTagsMerged;
59                                 relationConflict||= MergeWaysAction.lastRelationsMerged;
60
61                         } while (changed==true);
62
63             if (mergers>0) {                                    
64                             var msg:String = 1 + mergers + " ways merged";
65                 if (tagConflict && relationConflict) msg+=": check tags and relations";
66                 else if (tagConflict) msg+=": check conflicting tags";
67                 else if (relationConflict) msg+=": check relations";
68                 controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, msg));
69             }
70
71                         return controller.findStateForSelection(waylist);
72                 }
73                 
74                 private function tryMerge(waylist:Array, undo:CompositeUndoableAction):Boolean {
75                         var way1:Way, way2:Way, del:uint;
76                         for (var i:uint=0; i<waylist.length; i++) {
77                                 for (var j:uint=0; j<waylist.length; j++) {
78                                         if (waylist[i]!=waylist[j]) {
79
80                                                 // Preserve positive IDs if we can
81                                                 if (waylist[i].id < waylist[j].id && waylist[i].id >= 0) {
82                                                         way1=waylist[i]; way2=waylist[j]; del=j;
83                                                 } else {
84                                                         way1=waylist[j]; way2=waylist[i]; del=i;
85                                                 }
86
87                                                 // Merge as appropriate
88                                                 if (way1.getNode(0)==way2.getNode(0)) {
89                                                         waylist.splice(del,1);
90                                                         undo.push(new MergeWaysAction(way1,way2,0,0));
91                                                         return true;
92                                                 } else if (way1.getNode(0)==way2.getLastNode()) { 
93                                                         waylist.splice(del,1);
94                                                         undo.push(new MergeWaysAction(way1,way2,0,way2.length-1));
95                                                         return true;
96                                                 } else if (way1.getLastNode()==way2.getNode(0)) {
97                                                         waylist.splice(del,1);
98                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,0));
99                                                         return true;
100                                                 } else if (way1.getLastNode()==way2.getLastNode()) { 
101                                                         waylist.splice(del,1);
102                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,way2.length-1));
103                                                         return true;
104                                                 }
105                                         }
106                                 }
107                         }
108                         return false;
109                 }
110                 
111                 /** Create multipolygon from selection, or add to existing multipolygon. */
112                 
113                 public function createMultipolygon():ControllerState {
114                         var inner:Way;
115                         var multi:Object=multipolygonMembers();
116                         if (!multi.outer) {
117                                 controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "Couldn't make the multipolygon"));
118                                 return this;
119                         }
120
121                         // If relation exists, add any inners that aren't currently present
122                         if (multi.relation) {
123                                 var action:CompositeUndoableAction = new CompositeUndoableAction("Add to multipolygon");
124                                 for each (inner in multi.inners) {
125                                         if (!multi.relation.hasMemberInRole(inner,'inner'))
126                                                 multi.relation.appendMember(new RelationMember(inner,'inner'),action.push);
127                                 }
128                                 MainUndoStack.getGlobalStack().addAction(action);
129                                 
130                         // Otherwise, create whole new relation
131                         } else {
132                                 var memberlist:Array=[new RelationMember(multi.outer,'outer')];
133                                 for each (inner in multi.inners) 
134                                         memberlist.push(new RelationMember(inner,'inner'));
135                                 layer.connection.createRelation( { type: 'multipolygon' }, memberlist, MainUndoStack.getGlobalStack().addAction);
136                         }
137
138                         return new SelectedWay(multi.outer);
139                 }
140                 
141                 override public function enterState():void {
142                         selection=initSelection.concat();
143                         for each (var entity:Entity in selection) {
144                                 layer.setHighlight(entity, { selected: true, hover: false });
145                         }
146                         controller.updateSelectionUI();
147                         layer.setPurgable(selection,false);
148                 }
149
150                 override public function exitState(newState:ControllerState):void {
151                         layer.setPurgable(selection,true);
152                         for each (var entity:Entity in selection) {
153                                 layer.setHighlight(entity, { selected: false, hover: false });
154                         }
155                         selection = [];
156                         if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
157                 }
158
159                 override public function toString():String {
160                         return "SelectedMultiple";
161                 }
162
163         }
164 }