Wow, what can I say Mr Caraion, you are a LEGEND.  Thank you so much for taking 
the time to help me.  I REALLY APPRECIATE IT!

It pretty much worked out of the box - I just had to decrement values in the 
loop that "moves" the pages since deleting a page removes it from the parent's 
children XMLList and throws the indexes out of wack.

I will be remoting to ColdFusion to get and set the data so I will investigate 
using an ArrayCollection instead of XML.

Thanks again.

Nathan

Here is the updated code for anyone trying to do the same thing (renderer and 
dataDescriptor have not changed from Mr Caraion's original post so are not 
included in this):

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical">
        
        <mx:Script>
                <![CDATA[
                        import mx.events.ListEvent;
                        import 
com.nathan.descriptors.DocumentTreeDataDescriptor;
                        
                        [Bindable]
                        public var treeData:XML = <node type='folder' data='' 
label='Folder: ABC'>
                                <node type='document' data='123' label='ABC01'/>
                                <node type='document' data='124' label='ABC02'>
                                        <node type='page' data='125' 
label='ABC03'/>
                                        <node type='page' data='126' 
label='ABC04'/>
                                        <node type='page' data='127' 
label='ABC05'/>
                                </node>
                                <node type='document' data='128' label='ABC06'/>
                                <node type='document' data='129' label='ABC07'/>
                        </node>;
                        
                        private function 
tree_itemDoubleClickHandler(event:ListEvent):void
                        {
                                var node:XML = XML(event.itemRenderer.data);  
// get XML of the node
                                
                                // check whether a node of type page is double 
clicked
                                if (no...@type == "page")
                                {
                                        var pagesDocument:XML = node.parent(); 
// Tree(event.target).getParentItem(node);
                                        var documentsFolder:XML = 
pagesDocument.parent(); // Tree(event.target).getParentItem(pageDocument);
                                        var newDocumentNode:XML = <node 
type='document' data={no...@data} label={no...@label} />
                                        
                                        var nodeIndex:int = node.childIndex(); 
// node's index in its parent's children list (XMLList)
                                        var documentsPages:XMLList = 
pagesDocument.children(); // get the children of the page's document parent
                                        
                                        // store the length of documentPages in 
a variable, because
                                        // the real length will decrease by one 
each time we remove
                                        // a child from the document. In 
addition to this keep in mind
                                        // that after removing a child the 
subsequent child will take
                                        // its place, thus we retrieve and 
remove nodes at the same index: nodeIndex.
                                        var length:int = 
documentsPages.length();
                                        for (var i:int = nodeIndex; i < length; 
i++)
                                        {
                                                var pageNode:XML = 
documentsPages[i];
                                                
                                                delete documentsPages[i]; // 
reduces documentsPages.length() by 1 so decrement i, nodeIndex and length later
                                                
                                                if (i != nodeIndex)     // if 
want to set the page to be the document (i.e. a single page document has no 
"page nodes")
                                                {
                                                        
newDocumentNode.appendChild(pageNode);
                                                }
                                                else { // if it does equal the 
nodeIndex decrement nodeIndex so that it is no longer in sync with i
                                                        --nodeIndex;
                                                }
                                                // we deleted the page above 
and this reduces documentsPages.length() by 1 so decrement i, nodeIndex and 
length
                                                --i;
                                                --nodeIndex;
                                                --length;
                                        }
                                        
                                        // add new document to the folder
                                        
XML(documentsFolder).insertChildAfter(pagesDocument, newDocumentNode); // 
Inserts the given 2nd child parameter AFTER the 1st child parameter in this XML 
object and returns the resulting object.
                                        
                                        // if setting the page to be the 
document (i.e. a single page document has no "page nodes") and                  
               
                                        // if the new document has no children, 
close it.
                                        if 
(XML(pagesDocument).children().length() == 0)
                                                
Tree(event.target).expandItem(pagesDocument, false);
                                }
                        }
                        
                ]]>
        </mx:Script>
        
        <mx:Tree id="tree" dataProvider="{treeData}" labelField="@label" 
width="300"
                         doubleClickEnabled="true"
                         dataDescriptor="{new DocumentTreeDataDescriptor()}"
                         
itemRenderer="com.nathan.itemRenderers.DocumentTreeItemRenderer"
                         itemDoubleClick="tree_itemDoubleClickHandler(event)"/>
        
</mx:Application>

--- In [email protected], "mrcaraion" <mrcara...@...> wrote:
>
> Hi
> 
> Try this:
> 
> // main.mxml
> <?xml version="1.0" encoding="utf-8"?>
> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; layout="vertical">
>       
>   <mx:Script>
>     <![CDATA[
>       import mx.events.ListEvent;
>       import com.nathan.descriptors.DocumentTreeDataDescriptor;
>                       
>       [Bindable]
>       public var treeData:XML = <node type='folder' data='' label='Folder: 
> ABC'>
>                                     <node type='document' data='123' 
> label='ABC01'/>
>                                     <node type='document' data='124' 
> label='ABC02'>
>                                       <node type='page' data='125' 
> label='ABC03'/>
>                                       <node type='page' data='126' 
> label='ABC04'/>
>                                       <node type='page' data='127' 
> label='ABC05'/>
>                                     </node>
>                                     <node type='document' data='128' 
> label='ABC06'/>
>                                     <node type='document' data='129' 
> label='ABC07'/>
>                                 </node>;
>                       
>       private function tree_itemDoubleClickHandler(event:ListEvent):void
>       {
>         var node:XML = XML(event.itemRenderer.data);
>                               
>         // check whether a node of type page is double clicked
>         if (no...@type == "page")
>         {
>           var pageDocument:XML = node.parent(); // 
> Tree(event.target).getParentItem(node);
>           var documentFolder:XML = pageDocument.parent(); // 
> Tree(event.target).getParentItem(pageDocument);
>           var newDocumentNode:XML = <node type='document' data={no...@data} 
> label={no...@label} />
>                                       
>           XML(documentFolder).insertChildAfter(pageDocument, newDocumentNode);
>                                       
>           var nodeIndex:int = node.childIndex();
>           var documentPages:XMLList = pageDocument.children();
>                                       
>           // store the length of documentPages in a variable, because
>           // the real length will decrease by one each time we remove
>           // a child from the document. In addition to this keep in mind      
>     
>           // that after removing a child the subsequent child will take
>           // its place, thus we retrieve and remove nodes at the same index: 
> nodeIndex.
>           var length:int = documentPages.length();
>           for (var i:uint = nodeIndex; i < length; i++)
>           {
>             var pageNode:XML = documentPages[nodeIndex];
>                                               
>             delete documentPages[nodeIndex];
>                                               
>             if (i != nodeIndex)
>             {
>               newDocumentNode.appendChild(pageNode);
>             }
>           }
>                                       
>           // if the document has no children, close it.
>           if (XML(pageDocument).children().length() == 0)
>             Tree(event.target).expandItem(pageDocument, false);
>       }
>     }
>                       
>     ]]>
>   </mx:Script>
>       
>   <mx:Tree id="tree" dataProvider="{treeData}" labelField="@label" width="300"
>     doubleClickEnabled="true" dataDescriptor="{new 
> DocumentTreeDataDescriptor()}" 
>     itemRenderer="com.nathan.itemRenderers.DocumentTreeItemRenderer"
>     itemDoubleClick="tree_itemDoubleClickHandler(event)"/>
>       
> </mx:Application>
> 
> You will have to extend two more classes, DefaultDataDescriptor and 
> TreeItemRenderer, to tell to Tree component, through overriden isBranch 
> method from the DocumentDataDescriptor, that if a node is of type 'document' 
> than this is a branch; in DocumentTreeItemRenderer you hide the 
> disclosureIcon if the node is a branch but has no children. This is done to 
> fix some visual, I think, incorrect behavior (like the document node looks 
> like a leaf node when it has no pages ...).
> 
> // com/nathan/itemRenderers/DocumentTreeItemRenderer.as
> 
> package com.nathan.itemRenderers
> {
>       import mx.controls.Tree;
>       import mx.controls.treeClasses.TreeItemRenderer;
> 
>       public class DocumentTreeItemRenderer extends TreeItemRenderer
>       {
>               public function DocumentTreeItemRenderer()
>               {
>                       super();
>               }
>               
>               override protected function 
> updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
>               {
>                       super.updateDisplayList(unscaledWidth, unscaledHeight);
>                       
>                       if (listData && disclosureIcon)
>                       {
>                               var owner:Tree = listData.owner as Tree;
>                               var node:Object = data;
>                               
>                               if (owner.dataDescriptor.isBranch(node) && 
> owner.dataDescriptor.hasChildren(node))
>                                       disclosureIcon.visible = true;
>                               else
>                                       disclosureIcon.visible = false;
>                       }
>               }
>               
>       }
> }
> 
> // com/nathan/descriptors/DocumentTreeDataDescriptor.as
> 
> package com.nathan.descriptors
> {
>       import mx.collections.ICollectionView;
>       import mx.controls.treeClasses.DefaultDataDescriptor;
> 
>       public class DocumentTreeDataDescriptor extends DefaultDataDescriptor
>       {
>               public function DocumentTreeDataDescriptor()
>               {
>               }
> 
>               override public function isBranch(node:Object, 
> model:Object=null):Boolean
>               {
>                       if (no...@type == "document")
>                               return true;
>                       
>                       return super.isBranch(node, model);
>               }
>               
>       }
> }
> 
> You can also use an ArrayCollection for all this, the advantage is that you 
> may want to use strong typed objects for your data and to request this data 
> from a RemoteObject through AMF protocol, this will have a positive impact on 
> app performance.
> 
> Best regards,
> Mr caraion.
>


Reply via email to