Improve selection for background objects and tidy ControllerState layer handling
[potlatch2.git] / net / systemeD / potlatch2 / controller / SelectedMultiple.as
1 package net.systemeD.potlatch2.controller {
2         import flash.events.*;
3         
4         import net.systemeD.halcyon.AttentionEvent;
5         import net.systemeD.halcyon.connection.*;
6         import net.systemeD.halcyon.connection.actions.MergeWaysAction;
7     
8
9         public class SelectedMultiple extends ControllerState {
10                 protected var initSelection:Array;
11                 
12                 public function SelectedMultiple(sel:Array) {
13                         initSelection=sel.concat();
14                 }
15
16                 override public function processMouseEvent(event:MouseEvent, entity:Entity):ControllerState {
17                         if (event.type==MouseEvent.MOUSE_MOVE || event.type==MouseEvent.ROLL_OVER || event.type==MouseEvent.MOUSE_OUT) { return this; }
18                         var focus:Entity = getTopLevelFocusEntity(entity);
19
20                         if ( event.type == MouseEvent.MOUSE_DOWN && entity && event.ctrlKey ) {
21                                 // modify selection
22                                 layer.setHighlight(entity, { selected: toggleSelection(entity) });
23                                 controller.updateSelectionUI();
24
25                                 if (selectCount>1) { return this; }
26                                 return controller.findStateForSelection(selection);
27                         }
28                         var cs:ControllerState = sharedMouseEvents(event, entity);
29                         return cs ? cs : this;
30                 }
31
32                 override public function processKeyboardEvent(event:KeyboardEvent):ControllerState {
33                         if (event.keyCode==74) return mergeWays();      // 'J'
34                         var cs:ControllerState = sharedKeyboardEvents(event);
35                         return cs ? cs : this;
36                 }
37                 
38                 public function mergeWays():ControllerState {
39                         var changed:Boolean;
40                         var waylist:Array=selectedWays;
41                         var conflictTags:Object={}; 
42                         var mergers:uint=0;
43                         do {
44                                 // ** FIXME - we should have one CompositeUndoableAction for the whole caboodle,
45                                 // but that screws up the execution order and can make the merge not work
46                                 var undo:CompositeUndoableAction = new CompositeUndoableAction("Merge ways");
47                                 changed=tryMerge(waylist, undo);
48                                 if (changed)
49                                     mergers ++;
50                 MainUndoStack.getGlobalStack().addAction(undo);
51                 
52                 if (MergeWaysAction.lastProblemTags) {
53                         for each (var t:String in MergeWaysAction.lastProblemTags) {
54                                 conflictTags[t]=t;
55                         }
56                 }
57                                         
58                         } while (changed==true);
59
60             if (mergers>0) {                                    
61                             var msg:String = 1 + mergers + " ways merged."
62                 var conflictTags2:Array = new Array();
63                 // there must be a better way of avoiding duplicates...
64                 for each (var conflict:String in conflictTags) conflictTags2.push(conflict);
65                 if (conflictTags2.length>0)
66                     msg += " *Warning* The following tags conflicted and need attention: " + conflictTags2;
67                 controller.dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, msg));
68             }
69
70                         return controller.findStateForSelection(waylist);
71                 }
72                 
73                 private function tryMerge(waylist:Array, undo:CompositeUndoableAction):Boolean {
74                         var way1:Way, way2:Way, del:uint;
75                         for (var i:uint=0; i<waylist.length; i++) {
76                                 for (var j:uint=0; j<waylist.length; j++) {
77                                         if (waylist[i]!=waylist[j]) {
78
79                                                 // Preserve positive IDs if we can
80                                                 if (waylist[i].id < waylist[j].id && waylist[i].id >= 0) {
81                                                         way1=waylist[i]; way2=waylist[j]; del=j;
82                                                 } else {
83                                                         way1=waylist[j]; way2=waylist[i]; del=i;
84                                                 }
85
86                                                 // Merge as appropriate
87                                                 if (way1.getNode(0)==way2.getNode(0)) {
88                                                         waylist.splice(del,1);
89                                                         undo.push(new MergeWaysAction(way1,way2,0,0));
90                                                         return true;
91                                                 } else if (way1.getNode(0)==way2.getLastNode()) { 
92                                                         waylist.splice(del,1);
93                                                         undo.push(new MergeWaysAction(way1,way2,0,way2.length-1));
94                                                         return true;
95                                                 } else if (way1.getLastNode()==way2.getNode(0)) {
96                                                         waylist.splice(del,1);
97                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,0));
98                                                         return true;
99                                                 } else if (way1.getLastNode()==way2.getLastNode()) { 
100                                                         waylist.splice(del,1);
101                                                         undo.push(new MergeWaysAction(way1,way2,way1.length-1,way2.length-1));
102                                                         return true;
103                                                 }
104                                         }
105                                 }
106                         }
107                         return false;
108                 }
109
110                 override public function enterState():void {
111                         selection=initSelection.concat();
112                         for each (var entity:Entity in selection) {
113                                 layer.setHighlight(entity, { selected: true, hover: false });
114                         }
115                         controller.updateSelectionUI();
116                         layer.setPurgable(selection,false);
117                 }
118
119                 override public function exitState(newState:ControllerState):void {
120                         layer.setPurgable(selection,true);
121                         for each (var entity:Entity in selection) {
122                                 layer.setHighlight(entity, { selected: false, hover: false });
123                         }
124                         selection = [];
125                         if (!newState.isSelectionState()) { controller.updateSelectionUI(); }
126                 }
127
128                 override public function toString():String {
129                         return "SelectedMultiple";
130                 }
131
132         }
133 }