Merge remote-tracking branch 'stevage/repeat-relations-3596' into repeatrelations
[potlatch2.git] / net / systemeD / potlatch2 / panels / BackgroundMergePanel.mxml
1 <?xml version="1.0" encoding="utf-8"?>
2 <!---
3     The Background Merge Panel allows the tags from two features - one from
4     a read-only vector background layer, one from an editable layer - to be
5     compared. Tags are highlighted depending whether they match, and tags from
6     the background layer can be easily merged.
7 -->
8
9 <mx:VBox
10     xmlns:fx="http://ns.adobe.com/mxml/2009"
11     xmlns:mx="library://ns.adobe.com/flex/mx"
12     xmlns:s="library://ns.adobe.com/flex/spark"
13     height="100%">
14   <s:RichText id="backgroundMergePanelText" width="100%">Review and Merge tags from the Background layer</s:RichText>
15   <mx:DataGrid editable="false" id="backgroundPanelDG" width="100%" height="50%">
16     <mx:columns>
17       <mx:DataGridColumn editable="false" dataField="k" headerText="Key" />
18       <mx:DataGridColumn editable="false" dataField="e" headerText="OSM value" />
19       <mx:DataGridColumn editable="false" headerText="Merge" width="150" textAlign="center">
20         <mx:itemRenderer>
21           <fx:Component>
22             <mx:HBox horizontalAlign="center" verticalAlign="middle" width="100%">
23               <s:Button width="50" label="&lt;&lt;" visible="{parentDocument.buttonVisible(data.b, data.e)}" click="parentDocument.mergeForKey(data.k);" />
24             </mx:HBox>
25           </fx:Component>
26         </mx:itemRenderer>
27       </mx:DataGridColumn>
28       <mx:DataGridColumn editable="false" itemRenderer="net.systemeD.potlatch2.panels.BackgroundMergeFieldComponent" dataField="b" headerText="Background value" />
29     </mx:columns>
30   </mx:DataGrid>
31   <mx:ViewStack id="statusStack" resizeToContent="true" width="100%">
32     <mx:VBox id="empty" />
33     <mx:VBox id="not_complete">
34       <s:VGroup width="100%">
35         <s:RichText width="100%">If all the information from this feature is accounted for in the main layer, you can mark this feature as 'complete'.</s:RichText>
36         <s:RichText width="100%">This lets other contributors see what still needs reconciling.</s:RichText>
37         <s:Button label="Mark feature as Complete" click="markComplete()"/>
38       </s:VGroup>
39     </mx:VBox>
40     <mx:VBox id="complete" width="100%">
41       <s:VGroup width="100%">
42         <s:RichText width="100%">This feature has been marked as 'complete'. If this is incorrect, and there is still reconciling required, you can mark this feature as 'not complete'.</s:RichText>
43         <s:Button label="Mark feature as Not complete" click="markNotComplete()"/>
44       </s:VGroup>
45     </mx:VBox>
46   </mx:ViewStack>
47   <fx:Script><![CDATA[
48
49       import net.systemeD.halcyon.connection.*;
50       import net.systemeD.halcyon.MapPaint;
51       import net.systemeD.potlatch2.utils.SnapshotConnection;
52
53       import mx.collections.*;
54
55       private var editableEntity:Entity;
56       private var backgroundEntity:Entity;
57       private var tagDataProvider:ArrayCollection;
58
59       /**
60       * @param entities The two entities that are being compared. One should be from a background layer, but the
61       *                 order is not important.
62       */
63       public function init(entities:Array):void {
64           if ( tagDataProvider == null ) {
65               tagDataProvider = new ArrayCollection();
66               backgroundPanelDG.dataProvider = tagDataProvider;
67           }
68
69           if (parentDocument.controller.map.getLayerForEntity(entities[0]).isBackground) {
70               backgroundEntity = entities[0];
71               editableEntity = entities[1];
72           } else {
73               backgroundEntity = entities[1];
74               editableEntity = entities[0];
75           }
76           backgroundEntity.addEventListener(Connection.STATUS_CHANGED, statusEvent, false, 0, true);
77           setStatusStack();
78           editableEntity.addEventListener(Connection.TAG_CHANGED, tagChanged, false, 0, true);
79           updateTagDataProvider();
80       }
81
82       private function updateTagDataProvider():void {
83           var tag:Tag;
84           var keys:Array = [];
85
86           tagDataProvider.removeAll();
87
88           for each (tag in backgroundEntity.getTagArray() ) {
89               keys.push(tag.key);
90           }
91
92           for each (tag in editableEntity.getTagArray() ) {
93               keys.push(tag.key);
94           }
95
96           keys=keys.filter(function(k:*, i:int, arr:Array):Boolean { return arr.indexOf(k) == i } ); // remove duplicates
97           keys.sort();
98
99           for each (var key:String in keys) {
100               tagDataProvider.addItem({k:key, e:editableEntity.getTag(key), b:backgroundEntity.getTag(key)});
101           }
102           backgroundPanelDG.invalidateList();
103       }
104
105       private function tagChanged(e:Event):void {
106           updateTagDataProvider();
107       }
108
109       /**
110       * Should the button for merging tags be shown?
111       *
112       * @param b The tag value for the background entity
113       * @param e The tag value for the editable entity
114       */
115       public function buttonVisible(b:String, e:String):Boolean {
116           if (b != null && b != e) {
117               return true;
118           }
119           return false;
120       }
121
122       /**
123       * Merge the data for the given key. Results in the value being copied to the editable entity, using the
124       * global undo stack.
125       *
126       * @param key The tag key to be merged.
127       */
128       public function mergeForKey(key:String):void {
129           editableEntity.setTag(key, backgroundEntity.getTag(key), MainUndoStack.getGlobalStack().addAction);
130       }
131
132       /**
133       * Figure out an appropriate background color for the row. Don't call this for things you don't want coloured in. Like for empty tags.
134       *
135       * @param i The row index in the tagDataProvider
136       * @return The colour to be used as the background of the field
137       */
138       public function getColorFor(i:int):int {
139           if (tagDataProvider[i].e == tagDataProvider[i].b) {
140               return 0xDDFFDD; // matching, green
141            } else if (tagDataProvider[i].e == null) {
142               return 0xDDDDFF; // new value, blue
143            } else if (tagDataProvider[i].b) {
144               return 0xFFDDDD; // conflicting, red
145            }
146            return NaN; // which is interpretted as black
147       }
148
149       private function statusEvent(e:Event):void {
150             setStatusStack();
151       }
152
153       private function setStatusStack():void {
154           switch (backgroundEntity.status) {
155               case 'incomplete':
156                   statusStack.selectedChild = not_complete;
157                   break;
158               case 'complete':
159                   statusStack.selectedChild = complete;
160                   break;
161               default:
162                   statusStack.selectedChild = empty;
163           }
164       }
165
166       private function markComplete():void {
167           if (backgroundEntity.connection is SnapshotConnection) {
168               SnapshotConnection(backgroundEntity.connection).markComplete(backgroundEntity);
169           }
170       }
171
172       private function markNotComplete():void {
173           if (backgroundEntity.connection is SnapshotConnection) {
174               SnapshotConnection(backgroundEntity.connection).markNotComplete(backgroundEntity);
175           }
176       }
177   ]]>
178   </fx:Script>
179 </mx:VBox>