| <?xml version="1.0" encoding="utf-8"?> |
| <!-- |
| |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| --> |
| <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx" |
| xmlns:views="com.flexcapacitor.views.*" |
| xmlns:c="com.flexcapacitor.controls.*" |
| |
| width="200" height="100%" |
| creationComplete="creationCompleteHandler(event)" |
| implements="com.flexcapacitor.views.IInspector" |
| > |
| |
| <fx:Script> |
| <![CDATA[ |
| import com.flexcapacitor.controller.Radiate; |
| import com.flexcapacitor.events.RadiateEvent; |
| import com.flexcapacitor.model.IDocument; |
| import com.flexcapacitor.utils.DisplayObjectUtils; |
| import com.flexcapacitor.utils.supportClasses.ComponentDescription; |
| import com.flexcapacitor.views.renderers.LayersRenderer; |
| import com.flexcapacitor.views.supportClasses.LayersDataDescriptor; |
| |
| import mx.collections.ArrayCollection; |
| import mx.core.mx_internal; |
| import mx.events.DragEvent; |
| import mx.events.FlexEvent; |
| import mx.events.ListEvent; |
| import mx.events.TreeEvent; |
| import mx.states.AddItems; |
| |
| import spark.components.Application; |
| |
| private var rootDisplayObject:DisplayObject; |
| private var displayList:Array = []; |
| private var radiate:Radiate; |
| private var designDocument:IEventDispatcher; |
| |
| [Bindable] |
| public var components:ArrayCollection = new ArrayCollection(); |
| |
| private var _target:*; |
| |
| public function get target():* { |
| return _target; |
| } |
| |
| [Bindable] |
| public function set target(value:*):void { |
| _target = value; |
| } |
| |
| public function activate():void { |
| radiate = Radiate.instance; |
| updateComponentDisplayList(); |
| |
| radiate.addEventListener(RadiateEvent.TARGET_CHANGE, targetChangeHandler, false, 0, true); |
| radiate.addEventListener(RadiateEvent.DOCUMENT_CHANGE, documentChangeHandler, false, 0, true); |
| radiate.addEventListener(RadiateEvent.ADD_ITEM, addItemChangeHandler, false, 0, true); |
| radiate.addEventListener(RadiateEvent.MOVE_ITEM, addItemChangeHandler, false, 0, true); |
| radiate.addEventListener(RadiateEvent.REMOVE_ITEM, addItemChangeHandler, false, 0, true); |
| |
| if (radiate.target) { |
| updateTarget(radiate.target); |
| } |
| } |
| |
| public function deactivate():void { |
| if (radiate) { |
| |
| radiate.removeEventListener(RadiateEvent.TARGET_CHANGE, targetChangeHandler); |
| radiate.removeEventListener(RadiateEvent.DOCUMENT_CHANGE, documentChangeHandler); |
| radiate.removeEventListener(RadiateEvent.ADD_ITEM, addItemChangeHandler); |
| radiate.removeEventListener(RadiateEvent.MOVE_ITEM, addItemChangeHandler); |
| radiate.removeEventListener(RadiateEvent.REMOVE_ITEM, addItemChangeHandler); |
| |
| target = null; |
| } |
| } |
| |
| /** |
| * Listen for any changes to the display list |
| * */ |
| protected function creationCompleteHandler(event:FlexEvent):void { |
| /*radiate = Radiate.instance; |
| updateComponentDisplayList(); |
| |
| radiate.addEventListener(RadiateEvent.TARGET_CHANGE, targetChangeHandler); |
| radiate.addEventListener(RadiateEvent.DOCUMENT_CHANGE, documentChangeHandler); |
| radiate.addEventListener(RadiateEvent.ADD_ITEM, addItemChangeHandler); |
| radiate.addEventListener(RadiateEvent.MOVE_ITEM, addItemChangeHandler); |
| radiate.addEventListener(RadiateEvent.REMOVE_ITEM, addItemChangeHandler); |
| |
| if (radiate.target) { |
| updateTarget(radiate.target); |
| } |
| */ |
| } |
| |
| |
| /** |
| * Found on blog by Flex SDK developer (source). |
| * Not used. For reference. |
| */ |
| public function sortDisplayByDepth(item:Object, parentItem:Object = null, depth:int = 0):void { |
| |
| |
| if (displayList.length <= depth) { |
| displayList.push(new ArrayCollection()); |
| } |
| |
| |
| if ("numElements" in item) { |
| for (var i:int = 0; i < item.numElements; i++) { |
| var child:Object = item.getElementAt(i); |
| sortDisplayByDepth(child, parentItem, depth + 1); |
| displayList[depth].push(child); |
| } |
| } |
| |
| } |
| |
| |
| private function labelFunction(data:Object):String { |
| return data.name; |
| } |
| |
| /** |
| * When the target changes reselect it |
| * */ |
| protected function targetChangeHandler(event:RadiateEvent):void { |
| updateTarget(event.selectedItem); |
| } |
| |
| /** |
| * |
| * */ |
| public function updateTarget(selectedItem:Object):void { |
| var item:ComponentDescription = displayListTree.selectedItem as ComponentDescription; |
| var collection:ArrayCollection = displayListTree.dataProvider as ArrayCollection; |
| var rootApplicationDescription:ComponentDescription; |
| var targetDescription:ComponentDescription; |
| var parent:ComponentDescription; |
| |
| target = selectedItem; |
| |
| if (item && target!=item.instance) { |
| //updateComponentDisplayList(); |
| } |
| |
| if (collection.length==0) { |
| updateComponentDisplayList(); |
| collection = displayListTree.dataProvider as ArrayCollection; |
| } |
| |
| if (target && collection.length) { |
| rootApplicationDescription = collection.getItemAt(0) as ComponentDescription; |
| |
| if (rootApplicationDescription) { |
| targetDescription = DisplayObjectUtils.getTargetInComponentDisplayList(target, rootApplicationDescription); |
| |
| if (targetDescription) { |
| |
| parent = targetDescription.parent; |
| |
| while (parent) { |
| |
| // open item if not open |
| if (!displayListTree.isItemOpen(parent)) { |
| displayListTree.expandItem(parent, true, false, false); |
| displayListTree.validateNow(); |
| } |
| |
| parent = parent.parent; |
| } |
| |
| |
| // NOTE: IMPORTANT: READ: the open items can't be reassigned references. they have to be actual items |
| // ALSO we are resetting the dataProvider so it's not going to find the items |
| for (var i:int;i<length;i++) { |
| //displayListTree.expandItem(openItems[i], true, false, false); |
| //trace("expanding"); |
| } |
| |
| displayListTree.selectedItem = targetDescription; |
| } |
| } |
| } |
| |
| //openAllItems(); |
| updateTreeHeight(); |
| scrollIntoView(); |
| } |
| |
| /** |
| * Open all items |
| * */ |
| public function openAllItems():void { |
| var item:ComponentDescription = displayListTree.selectedItem as ComponentDescription; |
| var collection:ArrayCollection = displayListTree.dataProvider as ArrayCollection; |
| var rootApplicationDescription:ComponentDescription; |
| var targetDescription:ComponentDescription; |
| var parent:ComponentDescription; |
| |
| if (item && target!=item.instance) { |
| //updateComponentDisplayList(); |
| } |
| |
| if (collection.length==0) { |
| collection = displayListTree.dataProvider as ArrayCollection; |
| } |
| |
| if (collection.length<1) return; |
| rootApplicationDescription = collection.getItemAt(0) as ComponentDescription; |
| |
| for (var i:int;i<rootApplicationDescription.children.length;i++) { |
| displayListTree.expandChildrenOf(rootApplicationDescription.children[i], true); |
| displayListTree.validateNow(); |
| } |
| |
| } |
| |
| /** |
| * Close all items |
| * */ |
| public function closeAllItems():void { |
| var item:ComponentDescription = displayListTree.selectedItem as ComponentDescription; |
| var collection:ArrayCollection = displayListTree.dataProvider as ArrayCollection; |
| var rootApplicationDescription:ComponentDescription; |
| var targetDescription:ComponentDescription; |
| var parent:ComponentDescription; |
| |
| if (item && target!=item.instance) { |
| //updateComponentDisplayList(); |
| } |
| |
| if (collection.length==0) { |
| collection = displayListTree.dataProvider as ArrayCollection; |
| } |
| |
| if (collection.length<1) return; |
| rootApplicationDescription = collection.getItemAt(0) as ComponentDescription; |
| |
| for (var i:int;i<rootApplicationDescription.children.length;i++) { |
| displayListTree.expandChildrenOf(rootApplicationDescription.children[i], false); |
| displayListTree.validateNow(); |
| } |
| |
| } |
| |
| /** |
| * |
| * */ |
| protected function documentChangeHandler(event:Event):void {
|
| if (designDocument!=radiate.selectedDocument) { |
| updateComponentDisplayList(false); |
| }
|
| } |
| |
| /** |
| * Select target |
| * */ |
| protected function displayListTree_changeHandler(event:ListEvent):void { |
| var item:ComponentDescription = displayListTree.selectedItem as ComponentDescription; |
| |
| if (item) { |
| radiate.setTarget(item.instance as IEventDispatcher, true); |
| } |
| /* |
| if (!preventChange) { |
| } |
| else { |
| displayListTree.selectable |
| } |
| |
| preventChange = false; */
|
| } |
| |
| /** |
| * Recreate the display list and open all items. |
| * */ |
| private function updateComponentDisplayList(preserveOpenItems:Boolean = true):void {
|
| var openItems:Object = displayListTree.openItems; |
| var document:IDocument = radiate.selectedDocument; |
| var display:Object; |
| var length:int; |
| |
| |
| if (!document) return; |
| |
| // we need to create a list of the instances of open items |
| // componentDescription.instance not componentDescription |
| |
| // we could check for the target and update that branch |
| display = document.componentDescription; |
| displayListTree.dataProvider = display; |
| |
| // |
| //DisplayObjectUtils.walkDownTree(application as IVisualElement, traceTree); |
| |
| |
| if (preserveOpenItems) { |
| displayListTree.validateNow(); |
| |
| /* for each (var item:ComponentDescription in openItems) { |
| displayListTree.expandItem(item, true, false, false); |
| //trace("expanding"); |
| } |
| */ |
| length = openItems.length; |
| |
| // NOTE: IMPORTANT: READ: the open items can't be reassigned references. they have to be actual items |
| // ALSO we are resetting the dataProvider so it's not going to find the items if we do that |
| for (var i:int;i<length;i++) { |
| if (!displayListTree.isItemOpen(openItems[i])) { |
| displayListTree.expandItem(openItems[i], true, false, false); |
| } |
| //trace("expanding"); |
| } |
| }
|
| } |
| |
| public function traceTree(element:Object):void { |
| //trace("element="+NameUtil.getUnqualifiedClassName(element)); |
| } |
| |
| /** |
| * |
| * */ |
| private function findTargetInDisplayList(target:Object, parentItem:ComponentDescription, depth:int = 0):ComponentDescription { |
| var length:int = parentItem.children ? parentItem.children.length : 0; |
| var possibleItem:ComponentDescription; |
| var item:ComponentDescription; |
| var itemFound:Boolean; |
| |
| for (var i:int; i < length; i++) { |
| item = parentItem.children.getItemAt(i) as ComponentDescription; |
| |
| if (item && item.instance==target) { |
| itemFound = true; |
| break; |
| } |
| |
| if (item.children) { |
| possibleItem = findTargetInDisplayList(target, item, depth + 1); |
| |
| if (possibleItem) { |
| itemFound = true; |
| item = possibleItem; |
| break; |
| } |
| } |
| |
| } |
| |
| if (itemFound) return item; |
| |
| return null; |
| }
|
| |
| /** |
| * Add item handler |
| * */ |
| protected function addItemChangeHandler(event:RadiateEvent):void { |
| updateComponentDisplayList(); |
| } |
| |
| |
| /** |
| * Move item handler |
| * */ |
| protected function moveItemChangeHandler(event:RadiateEvent):void { |
| updateComponentDisplayList(); |
| } |
| |
| /** |
| * Item open handler |
| * */ |
| protected function displayListTree_itemOpenHandler(event:TreeEvent):void {
|
| updateTreeHeight() |
| } |
| |
| /** |
| * |
| * */ |
| public function getTotalRowCount(item:ComponentDescription, count:int = 0):int { |
| |
| if (item.children && item.children.length>0) { |
| // NOTE: IMPORTANT: READ: the open items can't be reassigned references. they have to be actual items |
| // ALSO we are resetting the dataProvider so it's not going to find the items if we do that |
| for (var i:int;i<item.children.length;i++) { |
| count++; |
| if (displayListTree.isItemOpen(item.children[i])) { |
| count = getTotalRowCount(item.children[i] as ComponentDescription, count); |
| } |
| } |
| } |
| return count; |
| } |
| |
| /** |
| * Resize the tree to be as high as all open items |
| * */ |
| public function updateTreeHeight():void { |
| var newHeight:int = displayListTree.rowCount * displayListTree.rowHeight; |
| var numChildren:int = displayListTree.numChildren; |
| var openItems:Object = displayListTree.openItems; |
| var openItemsLength:int = displayListTree.openItems.length; |
| var dataProvider:Object = displayListTree.dataProvider; |
| var dataProviderLength:int = displayListTree.dataProvider.length; |
| var item:ComponentDescription; |
| var count:int = 2; // application plus one for easier drop on last row |
| |
| var newCount:int = getTotalRowCount(dataProvider[0] as ComponentDescription, count); |
| |
| newHeight = newCount * displayListTree.rowHeight; |
| // ArgumentError: Error #2004: One of the parameters is invalid. |
| // at flash.display::Graphics/drawRect() |
| //displayListTree.setActualSize(NaN, newHeight); |
| //displayListTree.height = newHeight; |
| displayListTree.explicitHeight = newHeight; |
| } |
| |
| // THIS IS ALL TO HANDLE SCROLLING INSIDE ANOTHER SCROLLER THAT HAS TOUCH INTERACTION |
| // SPARK COMPONENTS DON'T HAVE THIS PROBLEM |
| private var mouseDownLocation:int; |
| public var preventChange:Boolean; |
| |
| protected function displayListTree_mouseDownHandler(event:MouseEvent):void {
|
| mouseDownLocation = event.stageY; |
| stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false, 0, true);
|
| stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, 0, true);
|
| } |
| |
| protected function mouseMoveHandler(event:MouseEvent):void {
|
| |
| var diff:int = Math.abs(event.stageY - mouseDownLocation); |
| |
| if (diff>10) { |
| displayListTree.selectable = false; |
| }
|
| } |
| |
| protected function mouseUpHandler(event:MouseEvent):void { |
| stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
|
| stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); |
| displayListTree.selectable = true;
|
| } |
| |
| protected function displayListTree_itemCloseHandler(event:TreeEvent):void {
|
| updateTreeHeight();
|
| } |
| |
| private function scrollIntoView():void { |
| |
| if (displayListTree.selectedIndex>-1) { |
| displayListTree.scrollToIndex(displayListTree.selectedIndex); |
| }
|
| } |
| |
| /** |
| * |
| * */ |
| protected function displayListTree_dragDropHandler(event:DragEvent):void {
|
| //Radiate.log.info("Drag drop handler"); |
| event.draggedItem; |
| event.target; |
| event.relatedObject; |
| |
| /* |
| Pay attention at mx_internal namespace : |
| Behaviour could change in the next flex version. |
| Drop data structure. |
| _dropData = { |
| parent: parent, |
| index: index, |
| localX: event.localX, |
| localY: event.localY, |
| emptyFolder: emptyFolder, |
| rowHeight: rowHeight, |
| rowIndex: rowNum }; |
| */ |
| var dropData:Object = displayListTree.mx_internal::_dropData; |
| var dropParent:Object = dropData.parent; |
| var dropIndex:int = dropData.index; |
| var rowIndex:int = dropData.rowIndex; |
| var draggedElement:Object = (event.dragSource.dataForFormat("treeItems") as Array)[0]; |
| var draggedElementParent:Object = draggedElement.parent; |
| var canDragOutOfParent:Boolean = !displayListTree.showRoot; |
| var currentIndex:int; |
| |
| if (!canDragOutOfParent && |
| draggedElementParent != dropParent) { |
| |
| // element is an item and parent is different => can not drop |
| event.preventDefault(); |
| displayListTree.hideDropFeedback(event); |
| return; |
| } |
| |
| // you can also play with |
| //var dropIndex:int = displayListTree.calculateDropIndex(event); |
| //var itemIndex:int = displayListTree.getItemIndex(dropIndex); |
| |
| // but it is a little more complicated to find |
| // the real parent because we haven't drop indicator |
| // information (child or parent position). |
| |
| // I did not use xml element id but it is also possible |
| // parent.id != draggedElement.parent().id |
| |
| // some reason there is a bug when on the application |
| // we have to subtract one from the drop index if it's lower than it's current index |
| if (dropParent && |
| draggedElement.parent == dropParent && |
| dropParent.instance is Application) { |
| currentIndex = ComponentDescription(dropParent).children.getItemIndex(draggedElement); |
| |
| // when dragging to an index after our index we have to subtract one |
| if (currentIndex<dropIndex) { |
| dropIndex--; |
| //Radiate.log.info("Lowering index"); |
| } |
| } |
| |
| |
| // make sure application can't be dropped into itself |
| if (draggedElement.instance is Application) { |
| event.preventDefault(); |
| displayListTree.hideDropFeedback(event); |
| return; |
| } |
| |
| // make sure container can't be dropped into child container |
| if (draggedElement.instance is DisplayObjectContainer && |
| dropParent && |
| dropParent.instance is DisplayObjectContainer && |
| DisplayObjectContainer(draggedElement.instance).contains(dropParent.instance)) { |
| |
| event.preventDefault(); |
| displayListTree.hideDropFeedback(event); |
| return; |
| } |
| |
| if (dropParent) { |
| /* |
| Radiate.log.info("drop index:"+ dropIndex); |
| Radiate.log.info("row index:" + rowIndex); |
| Radiate.log.info("item index:" + droppingIndex);*/ |
| |
| Radiate.moveElement(draggedElement.instance, dropParent.instance, [], [], null, |
| RadiateEvent.MOVE_ITEM, AddItems.LAST, null, dropIndex); |
| |
| radiate.setTarget(draggedElement.instance); |
| } |
| else { |
| |
| // if not showing root then allow drop |
| if (canDragOutOfParent && dropParent==null) { |
| dropParent = ArrayCollection(displayListTree.dataProvider).getItemAt(0); |
| currentIndex = ComponentDescription(dropParent).children.getItemIndex(draggedElement); |
| |
| // when dragging to an index after our index we have to subtract one |
| if (currentIndex<dropIndex && dropParent.instance==draggedElement.parent.instance) { |
| dropIndex--; |
| //Radiate.log.info("Lowering index"); |
| } |
| |
| Radiate.moveElement(draggedElement.instance, dropParent.instance, [], [], null, |
| RadiateEvent.MOVE_ITEM, AddItems.LAST, null, dropIndex); |
| } |
| else { |
| |
| // element is an item and parent is different => can not drop |
| event.preventDefault(); |
| displayListTree.hideDropFeedback(event); |
| } |
| } |
|
|
| } |
| |
| protected function displayListTree_dragCompleteHandler(event:DragEvent):void {
|
|
|
| } |
| |
| /** |
| * Handle when dragging just outside of tree |
| * */ |
| protected function displayListTree_dragOverHandler(event:DragEvent):void {
|
| |
| var dropData:Object = displayListTree.mx_internal::_dropData; |
| var dropParent:Object = dropData.parent; |
| |
| // dragging outside of tree |
| if (dropParent==null) { |
| // prevents dragging from working after this point |
| //event.preventDefault(); |
| //displayListTree.hideDropFeedback(event); |
| }
|
| } |
| |
| protected function expandAllNodes_clickHandler(event:MouseEvent):void {
|
| openAllItems();
|
| } |
| |
| protected function closeAllNodes_clickHandler(event:MouseEvent):void {
|
| closeAllItems();
|
| } |
| |
| ]]> |
| </fx:Script> |
| |
| <s:layout> |
| <s:VerticalLayout gap="0"/> |
| </s:layout> |
| <!-- |
| <views:BlendMode height="20" width="50%" />--> |
| |
| <s:Scroller id="scroller" width="100%" height="100%" |
| top="0" |
| bottom="0"> |
| <s:Group width="100%" height="100%"> |
| <mx:Tree id="displayListTree" |
| width="100%" |
| focusAlpha="0" |
| minHeight="50" |
| itemOpen="displayListTree_itemOpenHandler(event)" |
| itemClose="displayListTree_itemCloseHandler(event)" |
| change="displayListTree_changeHandler(event)" |
| showRoot="false" |
| dataProvider="{components}" |
| labelFunction="labelFunction" |
| verticalScrollPolicy="off" |
| horizontalScrollPolicy="auto" |
| rollOverColor="#ffffff" |
| selectionColor="#d8d8d8" |
| useRollOver="false" |
| borderVisible="false" |
| indentation="16" |
| dragEnabled="true" |
| dropEnabled="true" |
| dragMoveEnabled="true" |
| itemRenderer="com.flexcapacitor.views.renderers.LayersRenderer" |
| mouseDown="displayListTree_mouseDownHandler(event)" |
| dragOver="displayListTree_dragOverHandler(event)" |
| dragDrop="displayListTree_dragDropHandler(event)" |
| dragComplete="displayListTree_dragCompleteHandler(event)" |
| dataDescriptor="{new LayersDataDescriptor()}" |
| > |
| |
| |
| </mx:Tree> |
| </s:Group> |
| </s:Scroller> |
| |
| |
| <s:HGroup width="100%" |
| height="24" |
| minHeight="24" |
| verticalAlign="middle" |
| paddingRight="8" |
| > |
| <s:Spacer width="100%"/> |
| <c:ImageButton id="closeAllNodes" |
| source="{Radii8LibraryAssets.treeViewClosed}" |
| toolTip="Expand All" |
| click="closeAllNodes_clickHandler(event)" |
| /> |
| <c:ImageButton id="expandAllNodes" |
| source="{Radii8LibraryAssets.treeView}" |
| toolTip="Expand All" |
| click="expandAllNodes_clickHandler(event)" |
| /> |
| </s:HGroup> |
| |
| </s:Group> |