blob: c06f9e3bcf46821563b1c37f93ca83c2f542f29c [file] [log] [blame]
<?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>