3 Replies Latest reply on Oct 25, 2009 12:40 PM by Gregory Lafrance

    Tree control - dragging nodes

    Zolotoj Level 3

      Can someone confirm that it is not possible to drag a parent/child node into a collapsed node? That in order to drop a node onto a tree folder it has to be open?

       

      Thanks

        • 1. Re: Tree control - dragging nodes
          Gregory Lafrance Level 6

          If this post answers your question or helps, please mark it as such.

           

          In general that is true, but this forum post includes a mention of "TreeEx" that does what you want, so consider this proper attribution for this code:

           

          http://www.nabble.com/Flex-3-Tree---Moving-Nodes-td22420499.html

           

          package
          {
              import mx.controls.Tree;
              import mx.core.mx_internal;
              import mx.events.DragEvent;
              use namespace mx_internal;
             
              /**
               * Extends the default Tree implementation by adding the capability to drop a leaf node onto another leaf node.
               * 
               *
               */
              public class TreeEx extends Tree
              {
                 
                  /**
                   * Constructor
                   *
                   */
                  public function TreeEx() {
                      super();
                  }
                 
                  /**
                   * @inheritDoc
                   */
                  override public function get firstVisibleItem():Object {
                      // This protects the tree from crashing in very specific conditions in AIR. Sometimes, the function
                      // gets called when there are no data in the tree thus causing the crash. Data access has now been
                      // protected.
                      return (listItems.length >0 && listItems[0].lenght > 0) ? super.firstVisibleItem : null;
                  }

                  /**
                   * @inheritDoc
                   */
                  override public function calculateDropIndex(event:DragEvent=null):int {
                      super.calculateDropIndex(event);
                      if (isDroppingOnNode() && listItems[_dropData.rowIndex - verticalScrollPosition][0]) {
                          // Data will be dropped as a child so rearrange the parent and index references.
                          var itemInd:int = _dropData.rowIndex - verticalScrollPosition;
                          if ( itemInd < listItems.length && itemInd >= 0 && listItems[itemInd].length > 0 ) {
                              _dropData.parent = listItems[itemInd][0].data;
                          } else {
                              _dropData.parent = null;
                          }
                             
                          // Always drop the item as the first child
                          _dropData.index = 0;
                      }
                      return _dropData.rowIndex;
                  }
                 
                  /**
                   * @inheritDoc
                   *
                   */
                  override public function showDropFeedback(event:DragEvent):void {
                      calculateDropIndex(event);
                      if (isDroppingOnNode()) {
                          // We're on the node so highlight it.
                          showNodeDropFeedback(_dropData.rowIndex);
                          super.hideDropFeedback(event);
                      } else {
                          // We're in between nodes, so use standard drop feedback.
                          super.showDropFeedback(event);
                          hideNodeDropFeedback(_dropData.rowIndex);
                      }
                  }
                 
                  /**
                   * @inheritDoc
                   *
                   */
                  override public function hideDropFeedback(event:DragEvent):void {
                      super.hideDropFeedback(event);
                      hideNodeDropFeedback(_dropData.rowIndex);
                  }
                 
                  /**
                   * Shows a specific drop feedback when data is dropped onto a node instead of in between nodes.
                   *
                   * @param rowIndex The row index where the drop will occur.
                   *
                   */
                  protected function showNodeDropFeedback(rowIndex:int):void {
                      var index:int = rowIndex - verticalScrollPosition;
                      // Check for boundary conditions before drawing the highlight.
                      if (index >= listItems.length || listItems[index].length == 0) return;
                     
                      // We're just highlighting the cell.
                      drawItem(listItems[index][0], false, true, false, false);
                  }
                 
                  /**
                   * Hides the drop feedback created when data is dropped onto a node instead of in between nodes.
                   *
                   * @param rowIndex The row index where the drop occurred.
                   *
                   */
                  protected function hideNodeDropFeedback(rowIndex:int):void {
                      var index:int = rowIndex - verticalScrollPosition;
                      if (listItems[index] && listItems[index].length > 0) clearHighlight(listItems[index][0]);
                      // If we move the mouse from up to down, the highlight will be on the previous
                      // dropData.rowIndex. So, just in case, clear the previous row highlight too.
                      if (index > 0 && listItems[index - 1].length > 0) clearHighlight(listItems[index - 1][0]);
                     
                  }
                 
                  /**
                   * Tests wether or not the data is dropped on the node itself.
                   *
                   * The node is said to be dropped onto another node if the mouse is on the bottom half portion of the cell.
                   * 
                   * @return
                   *
                   */
                  protected function isDroppingOnNode():Boolean {
                      return _dropData.localY >= rowInfo[_dropData.rowIndex - verticalScrollPosition].y + 0.5 * _dropData.rowHeight
                  }
                 
                  /**
                   *  @inheritDoc
                   */
                  override protected function dragDropHandler(event:DragEvent):void
                  {
                      calculateDropIndex(event);
                      super.dragDropHandler(event);
                  }

              }
          }

          1 person found this helpful
          • 2. Re: Tree control - dragging nodes
            Zolotoj Level 3

            I checked that post but did not see Flex version of a JS tree. Did I miss it?

            I will try code are you are providing later.

             

            BTW, what is the easiest way of testing your code? Should I create a new project?

            • 3. Re: Tree control - dragging nodes
              Gregory Lafrance Level 6

              Create a new Flex project, here is the main app file:

               

              ----- TreeMoveNodesInFolders.mxml -----

              <?xml version="1.0"?>
              <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:comp="*">
                <mx:XML id="treeData" source="data/photoinfo.xml"/>
                <comp:TreeEx id="tree1" showRoot="false" labelField="@label"
                  dragEnabled="true" dropEnabled="true" allowMultipleSelection="true"
                  dataProvider="{treeData}" width="300" height="400"/>
              </mx:Application>

               

              TreeEx.as should be in the same directory.

               

              If this post answers your question or helps, please mark it as such.