source: ComponentRegistry/trunk/ComponentBrowserGui/src/main/flex/clarin/cmdi/componentregistry/editor/CMDComponentXMLEditor.as @ 2126

Last change on this file since 2126 was 2126, checked in by twagoo, 12 years ago

Merged changes from 1.12.0 branch that fix #217 and #218 + CHANGES file for that release

File size: 14.4 KB
Line 
1package clarin.cmdi.componentregistry.editor {
2        import clarin.cmdi.componentregistry.common.CMDSpecRenderer;
3        import clarin.cmdi.componentregistry.common.ItemDescription;
4        import clarin.cmdi.componentregistry.common.LabelConstants;
5        import clarin.cmdi.componentregistry.common.StyleConstants;
6        import clarin.cmdi.componentregistry.common.components.AddComponentLabelButton;
7        import clarin.cmdi.componentregistry.common.components.AddElementLabelButton;
8        import clarin.cmdi.componentregistry.common.components.LabelButton;
9        import clarin.cmdi.componentregistry.common.components.RemoveLabelButton;
10        import clarin.cmdi.componentregistry.editor.model.CMDComponent;
11        import clarin.cmdi.componentregistry.editor.model.CMDComponentElement;
12        import clarin.cmdi.componentregistry.editor.model.CMDSpec;
13        import clarin.cmdi.componentregistry.services.IsocatService;
14       
15        import flash.display.DisplayObject;
16        import flash.events.Event;
17        import flash.events.MouseEvent;
18        import flash.utils.Dictionary;
19        import flash.utils.getTimer;
20       
21        import mx.collections.ArrayCollection;
22        import mx.containers.Form;
23        import mx.containers.FormItem;
24        import mx.containers.FormItemDirection;
25        import mx.containers.HBox;
26        import mx.controls.Alert;
27        import mx.controls.Label;
28        import mx.controls.Spacer;
29        import mx.core.Container;
30        import mx.core.UIComponent;
31        import mx.events.ChildExistenceChangedEvent;
32        import mx.events.CloseEvent;
33        import mx.events.DragEvent;
34        import mx.managers.DragManager;
35        import mx.managers.IFocusManagerComponent;
36       
37        [Event(name="editorChange", type="flash.events.Event")]
38        public class CMDComponentXMLEditor extends Form implements IFocusManagerComponent, CMDSpecRenderer {
39               
40                public static const DRAG_NEW_COMPONENT:String = "newComponent";
41                public static const DRAG_NEW_ELEMENT:String = "newElement";
42                public static const DRAG_NEW_ATTRIBUTE:String = "newAttribute";
43                private static const DRAG_ITEMS:String = "items";
44               
45                public static const EDITOR_CHANGE_EVENT:String = "editorChange";
46               
47                private var _spec:CMDSpec;
48                private var _firstComponent:CMDComponent;
49                private var addComponentLabel:Label
50                private var addElementLabel:Label
51               
52                public function CMDComponentXMLEditor() {
53                        super();
54                        focusEnabled = true;
55                        tabEnabled = true;
56                        styleName = StyleConstants.XMLBROWSER;
57                        addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
58                        addEventListener(DragEvent.DRAG_OVER, dragOverHandler);
59                        addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
60                        addEventListener(ChildExistenceChangedEvent.CHILD_ADD, dispatchEditorChangeEvent);
61                        addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, dispatchEditorChangeEvent);
62                }
63               
64                public function validate():Boolean {
65                        var componentDisplayPrioMap:Dictionary = new Dictionary(true);
66                        componentDisplayPrioMap[this] = new ArrayCollection();
67                        var result:Boolean = validateChildren(getChildren(), componentDisplayPrioMap, this);
68                        result = validateDisplayPriorityFields(componentDisplayPrioMap) && result;
69                        return result;
70                }
71               
72                private function validateChildren(children:Array, componentDisplayPrioMap:Dictionary, key:Object):Boolean {
73                        var result:Boolean = true;
74                        for each (var o:Object in children) {
75                                if (o is CMDValidator) {
76                                        var validatorResult : Boolean = CMDValidator(o).validate();
77                                        if(!validatorResult){
78                                                CMDValidator(o).validate();
79                                        }
80                                        result = validatorResult && result;
81                                }
82                                if (o is Container) {
83                                        var newKey:Object = key;
84                                        if (o is ComponentEdit) {
85                                                componentDisplayPrioMap[o] = new ArrayCollection();
86                                                newKey = o;
87                                        }
88                                        result = validateChildren(Container(o).getChildren(), componentDisplayPrioMap, newKey) && result;
89                                        if (o is DisplayPriorityInput) {
90                                                componentDisplayPrioMap[newKey].addItem(o);
91                                        }
92                                }
93                        }
94                        return result;
95                }
96               
97                private function validateDisplayPriorityFields(componentDisplayPrioMap:Dictionary):Boolean {
98                        var result:Boolean = true;
99                        for (var key:Object in componentDisplayPrioMap) {
100                                var displayPrioritySet:Boolean = false;
101                                var displayPriorityFields:ArrayCollection = componentDisplayPrioMap[key];
102                                for each (var input:DisplayPriorityInput in displayPriorityFields) { // get values
103                                        if (input.getValue() > 0) {
104                                                displayPrioritySet = true;
105                                                break;
106                                        }
107                                }
108                                for each (var inputF:DisplayPriorityInput in displayPriorityFields) { // set results
109                                        if (displayPrioritySet) {
110                                                result = inputF.validate(input.getValue()) && result;
111                                        } else {
112                                                result = inputF.validate(null) && result;
113                                        }
114                                }
115                        }
116                        return result;
117                }
118               
119                private function dragEnterHandler(event:DragEvent):void {
120                        DragManager.acceptDragDrop(event.currentTarget as UIComponent);
121                        UIComponent(event.currentTarget).drawFocus(true);
122                }
123               
124               
125                private function dragOverHandler(event:DragEvent):void {
126                        if (event.dragSource.hasFormat(DRAG_ITEMS)) {
127                                DragManager.showFeedback(DragManager.COPY);
128                        } else {
129                                DragManager.showFeedback(DragManager.NONE);
130                        }
131                }
132               
133                private function dragDropHandler(event:DragEvent):void {
134                        if (event.dragSource.hasFormat(DRAG_ITEMS)) {
135                                var items:Array = event.dragSource.dataForFormat(DRAG_ITEMS) as Array;
136                                for each (var item:ItemDescription in items) {
137                                        var comp:CMDComponent = new CMDComponent();
138                                        comp.componentId = item.id;
139                                        _firstComponent.cmdComponents.addItem(comp);
140                                        addComponent(comp);
141                                }
142                        }
143                }
144               
145                public function set cmdSpec(cmdSpec:CMDSpec):void {
146                        _spec = cmdSpec;
147                        createNewEditor();
148                        dispatchEditorChangeEvent();
149                }
150               
151                private function dispatchEditorChangeEvent(event:Event = null):void {
152                        dispatchEvent(new Event(EDITOR_CHANGE_EVENT));
153                }
154               
155                [Bindable]
156                public function get cmdSpec():CMDSpec {
157                        return _spec;
158                }
159               
160                private function createNewEditor():void {
161                        var start:int = getTimer();
162                        addComponentLabel = null
163                        addElementLabel = null
164                        removeAllChildren();
165                        checkFirstDefiningComponent(_spec.cmdComponents);
166                        handleHeader(_spec);
167                       
168                        addChild(createCollapseExpandBox());
169                       
170                        handleElements(_firstComponent.cmdElements);
171                        addElementAddButton();
172                        handleComponents(_firstComponent.cmdComponents);
173                        addComponentAddButton();
174                       
175                        addChild(createCollapseExpandBox());
176
177                        trace("Created editor view in " + (getTimer() - start) + " ms.");
178                }
179               
180                private function createCollapseExpandBox():HBox{
181                        var collapseExpandBox:HBox = new HBox();
182                        collapseExpandBox.addChild(createCollapseAllButton());
183                        collapseExpandBox.addChild(createExpandAllButton());
184                        return collapseExpandBox;
185                }
186               
187                private function createCollapseAllButton():UIComponent{
188                        var button:LabelButton = new LabelButton(collapseAll,  "Collapse all");
189                        button.setStyle("color","blue");
190                        button.toolTip = "Collapse all components and elements in this editor";
191                        return button;
192                }
193               
194                private function collapseAll(event:Event):void{
195                        for(var i:int=0;i<numChildren;i++){
196                                var child:Object = getChildAt(i);
197                                if(child is ElementEdit || child is ComponentEdit){
198                                        ItemEdit(child).collapseAll();
199                                }
200                        }
201                }
202               
203                private function createExpandAllButton():UIComponent{
204                        var button:LabelButton = new LabelButton(expandAll,  "Expand all");
205                        button.setStyle("color","blue");
206                        button.toolTip = "Expand all components and elements in this editor";
207                        return button;
208                }               
209               
210                private function expandAll(event:Event):void{
211                        for(var i:int=0;i<numChildren;i++){
212                                var child:Object = getChildAt(i);
213                                if(child is ElementEdit || child is ComponentEdit){
214                                        ItemEdit(child).expandAll();
215                                }
216                        }
217                }
218               
219                private function clearEditorHandler(event:Event):void {
220                        if (_spec && !_spec.isProfile) {
221                                clearEditorComponent();
222                        } else {
223                                clearEditorProfile();
224                        }
225                }
226               
227                public function get specHasChanges():Boolean {
228                        return _spec.hasChanged;
229                }
230               
231                public function clearEditorComponent() : void{         
232                        clearEditorSubmit(doClearEditorComponent);
233                }       
234               
235                public function clearEditorProfile() : void{
236                        clearEditorSubmit(doClearEditorProfile);
237                }
238               
239                private function clearEditorSubmit(clearFunction:Function) : void {
240                        if(_spec.hasChanged) {
241                                Alert.show("This will discard all changes to the component currently being edited", "Discard changes", Alert.OK|Alert.CANCEL, null, clearFunction); 
242                        } else{
243                                callLater(clearFunction);
244                        }
245                }
246               
247                public function doClearEditorComponent(event:CloseEvent=null) : void{
248                        if(event == null || event.detail == Alert.OK){
249                                cmdSpec = CMDSpec.createEmptyComponent();
250                                cmdSpec.changeTracking = true;
251                                dispatchEditorChangeEvent();
252                        }
253                }       
254               
255                public function doClearEditorProfile(event:CloseEvent=null) : void{
256                        if(event == null || event.detail == Alert.OK){
257                                cmdSpec = CMDSpec.createEmptyProfile();
258                                cmdSpec.changeTracking = true;
259                                dispatchEditorChangeEvent();
260                        }
261                }
262               
263                /**
264                 * The xml model allows more component to be defined but we force only one component at the "root" level.
265                 */
266                private function checkFirstDefiningComponent(components:ArrayCollection):void {
267                        if (components.length != 1) {
268                                throw new Error("A profile/component must have 1 component defined at root level.");
269                        } else {
270                                _firstComponent = components.getItemAt(0) as CMDComponent;
271                                if (_firstComponent.componentId != "" && _firstComponent.componentId != null) {
272                                        _firstComponent = new CMDComponent();
273                                        _firstComponent.name = _spec.headerName;
274                                        _firstComponent.cmdComponents = _spec.cmdComponents;
275                                        _spec.cmdComponents = new ArrayCollection();
276                                        _spec.cmdComponents.addItem(_firstComponent);
277                                }
278                        }
279                }
280               
281                private function handleHeader(spec:CMDSpec):void {
282                        var head:FormItem = new FormItem();
283                        head.direction = FormItemDirection.HORIZONTAL;
284                        var buttons:FormItem = new SelectTypeRadioButtons(spec);
285                        head.addChild(buttons);
286                        var space:Spacer = new Spacer();
287                        space.width = 55;
288                        head.addChild(space);
289                        addChild(head);
290                       
291                        var nameInput:NameInputLine = new NameInputLine(_firstComponent.name, function(val:String):void {
292                                _firstComponent.name = val;
293                                _spec.headerName = val;
294                        }, InputValidators.getNameValidator());
295                        addChild(nameInput);
296                       
297                        var groupNameInput:FormItemInputLine = new FormItemInputLine(LabelConstants.GROUP_NAME, spec.groupName, function(val:String):void {
298                                spec.groupName = val;
299                        }); // editable, not required
300                        addChild(groupNameInput);
301                       
302                        var descriptionInput:FormItemInputText = new FormItemInputText(LabelConstants.DESCRIPTION, spec.headerDescription, function(val:String):void {
303                                spec.headerDescription = val;
304                        }, InputValidators.getIsRequiredValidator()); //editable, required
305                        addChild(descriptionInput);
306                       
307                        var domainInput:ComboBoxInputLine = new ComboBoxInputLine(LabelConstants.DOMAIN_NAME, _spec.domainName, LabelConstants.DOMAIN_NAME_DATA, LabelConstants.DOMAIN_NAME_PROMPT, function(val:Object):void {
308                                if (val) {
309                                        _spec.domainName = val.data;
310                                }
311                        }); // editable, not required
312                        addChild(domainInput);
313                       
314                        //                      var idInput:FormItemInputLine = new FormItemInputLine(XMLBrowser:"Id", spec.headerId, function(val:String):void {
315                        //                                      spec.headerId = val;
316                        //                              }, false);
317                        //                      idInput.toolTip = "Id will be generated";
318                        //                      addChild(idInput);
319                        var link:ConceptLinkInput = new ConceptLinkInput(LabelConstants.CONCEPTLINK, _firstComponent.conceptLink, function(val:String):void {
320                                _firstComponent.conceptLink = val;
321                        }, IsocatService.TYPE_CONTAINER);
322                        addChild(link);
323                       
324                        addChild(new AttributeListEdit(_firstComponent, this))
325                }
326               
327                private function addComponentAddButton():void {
328                        addComponentLabel = new AddComponentLabelButton();
329                        addComponentLabel.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void {
330                                var comp:CMDComponent = CMDComponent.createEmptyComponent();
331                                _firstComponent.cmdComponents.addItem(comp);
332                                addComponent(comp);
333                               
334                        });
335                        addComponentLabel.addEventListener(MouseEvent.MOUSE_OVER, function(event:MouseEvent):void {
336                                drawFocus(true);
337                        });
338                        addComponentLabel.addEventListener(MouseEvent.MOUSE_OUT, function(event:MouseEvent):void {
339                                drawFocus(false);
340                        });
341                        addChild(addComponentLabel);
342                }
343               
344                private function addElementAddButton():void {
345                        addElementLabel = new AddElementLabelButton();
346                        addElementLabel.addEventListener(MouseEvent.CLICK, function(event:MouseEvent):void {
347                                var element:CMDComponentElement = CMDComponentElement.createEmptyElement();
348                                _firstComponent.cmdElements.addItem(element);
349                                addElement(element);
350                               
351                        });
352                        addElementLabel.addEventListener(MouseEvent.MOUSE_OVER, function(event:MouseEvent):void {
353                                drawFocus(true);
354                        });
355                        addElementLabel.addEventListener(MouseEvent.MOUSE_OUT, function(event:MouseEvent):void {
356                                drawFocus(false);
357                        });
358                        addChild(addElementLabel);
359                }
360               
361                /* private function createOptionalGroupNameInput(spec:CMDSpec):FormItem {
362                var result:FormItemInputLine = new FormItemInputLine(LabelConstants.GROUP_NAME, spec.groupName, function(val:String):void {
363                spec.groupName = val;
364                }, true, InputValidators.getIsRequiredValidator());
365                BindingUtils.bindSetter(function(val:Boolean):void {
366                result.visible = !val;
367                }, spec, "isProfile");
368                return result;
369                }  */
370               
371                private function handleComponents(components:ArrayCollection):void {
372                        for each (var component:CMDComponent in components) {
373                                addComponent(component);
374                        }
375                }
376               
377                public function addComponent(component:CMDComponent):void {
378                        var comp:Container = new ComponentEdit(component, this, _firstComponent);
379                        comp.addEventListener(ComponentEdit.REMOVE_COMPONENT_EVENT, removeComponent);
380                        if (!addComponentLabel) {
381                                addChild(comp);
382                        } else {
383                                addChildAt(comp, getChildIndex(addComponentLabel)); //Add components at the place of the button so button moves down
384                        }
385                }
386               
387                private function removeComponent(event:Event):void {
388                        var comp:CMDComponent = ComponentEdit(event.currentTarget).component;
389                        _firstComponent.removeComponent(comp);
390                        removeChild(event.currentTarget as DisplayObject);
391                }
392               
393               
394                private function handleElements(elements:ArrayCollection):void {
395                        for each (var element:CMDComponentElement in elements) {
396                                addElement(element);
397                        }
398                }
399               
400                public function addElement(element:CMDComponentElement):void {
401                        var elem:Container = new ElementEdit(element, this, _firstComponent);
402                        elem.setStyle("paddingLeft", "50");
403                        elem.addEventListener(ElementEdit.REMOVE_ELEMENT_EVENT, removeElement);
404                        if (!addElementLabel) {
405                                addChild(elem);
406                        } else {
407                                addChildAt(elem, getChildIndex(addElementLabel));
408                        }
409                }
410               
411                private function removeElement(event:Event):void {
412                        var elem:CMDComponentElement = ElementEdit(event.currentTarget).element;
413                        _firstComponent.removeElement(elem);
414                        removeChild(event.currentTarget as DisplayObject);
415                }
416        }
417}
Note: See TracBrowser for help on using the repository browser.