JHeadstart 11g: Tree-Form with drag and drop functionallity

A little over two years ago I wrote a post on drag and drop in an adf tree component. That post was based on ADF only. In the following post I show that you can have JHeadstart generate a tree for you that supports drag and drop.

JHeadstart 11g: Tree-Form with drag and drop functionallity intro

Not out of the box, but with use of custom templates, and some ADF knowledge.

Basic Setup.
We start with the creation of an application module based on departments and employees.

JHeadstart 11g: Tree-Form with drag and drop functionallity appModule

After enabling JHeadstart on the ViewController project, we edit the ServiceDefinition so it is configured to generate a Tree-Form layout by using the default JHeadstart templates.

JHeadstart 11g: Tree-Form with drag and drop functionallity AppDefEditor1

This will create a treeForm layout with the tree on the left, and the corresponding form on the right.

JHeadstart 11g: Tree-Form with drag and drop functionallity default

Add drag and drop.
The usual way to add functionality that can not be generated by JHeadstart by default, is to implement drag and drop without using JHeadstart. In other words, as if you were just creating an application plain ADF. So, change the page source (dragSource/dropTarget) and add a managed bean with it’s corresponding class. Once you have that all up and running, create custom JHeadstart generator templates, that generate the code for you. Creating custom templates has become much easier since the arrival of JHeadstart 11g. You now only have to select the template in the Application Definition Editor:

JHeadstart 11g: Tree-Form with drag and drop functionallity treeTemplateBefor

Change its name, and you are asked if you really want to create a new template based on the default one. And of course, that is
what we want.

JHeadstart 11g: Tree-Form with drag and drop functionallity newTemplate

The drag and drop will be implemented by the code snippet below. We only need to add this code to this new template, just before the end tag of the tree component.

        <af:dragSource actions = "MOVE"
                       dragDropEndListener="#{pageFlowScope.${JHS.current.group.name}MoveBean.dragFinished}"
                       discriminant="moveEmployees"/>
        <af:collectionDropTarget dropListener="#{pageFlowScope.${JHS.current.group.name}MoveBean.empDropped}"
                                 actions ="MOVE"
                                 modelName="moveEmployees"/>

The same goes for the bean definition. Create a new template to hold the managed bean that implements the drag and drop functionality. We will do this in a template that is derived from the groupAdfConfig template. The default AdfConfig for the group will be generated with our “MoveBean” as valuable addition.

<managed-bean>
   <managed-bean-name id="#NEW_ID("__")">${group.name}MoveBean</managed-bean-name>
   <managed-bean-class id="#NEW_ID("__")">nl.amis.technology.view.beans.MoveBean</managed-bean-class>
   <managed-bean-scope id="#NEW_ID("__")">pageFlow</managed-bean-scope>
</managed-bean>

As you can see, the managed bean class for the MoveBean is ‘nl.amis.technology.view.beans.MoveBean’. The code of this MoveBean class for drag and drop of employees is posted in the snippet below.

package nl.amis.technology.view.beans;

import java.util.Iterator;
import java.util.List;

import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.view.rich.component.rich.data.RichTree;
import oracle.adf.view.rich.datatransfer.DataFlavor;
import oracle.adf.view.rich.datatransfer.Transferable;
import oracle.adf.view.rich.dnd.DnDAction;
import oracle.adf.view.rich.event.DropEvent;

import oracle.binding.OperationBinding;
import oracle.jbo.Row;
import oracle.jbo.domain.Number;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;

import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;

public class MoveBean {
  public MoveBean() {
    }

  public DnDAction empDropped(DropEvent dropEvent){

    RichTree dropComponent = (RichTree)dropEvent.getDropComponent();
    Number theNewDepartment = null;
    List droppedRowKey = (List)dropEvent.getDropSite();
    if (droppedRowKey== null){
      return DnDAction.NONE;
    }

    dropComponent.setRowKey(droppedRowKey);
    JUCtrlHierNodeBinding dropNode = null;
    dropNode = (JUCtrlHierNodeBinding)dropComponent.getRowData();
    String dropNodeStructureDefName = dropNode.getHierTypeBinding().getStructureDefName();
    String empDef = "nl.amis.technology.model.vo.EmployeesView";

    if(dropNodeStructureDefName.equalsIgnoreCase(empDef)){
      theNewDepartment = (Number)dropNode.getParent().getRow().getAttribute("DepartmentId");
    }
    else{
      theNewDepartment = (Number)dropNode.getRow().getAttribute("DepartmentId");
    }

    Transferable transferable = dropEvent.getTransferable();
    DataFlavor<RowKeySet> rowKeySetFlavor = DataFlavor.getDataFlavor(RowKeySet.class, "moveEmployees");
    RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor);

    if (rowKeySet!=null){
      CollectionModel dragModel = null;
      dragModel = transferable.getData(CollectionModel.class);
      if (dragModel!=null){
        JUCtrlHierBinding binding = null;
        binding = (JUCtrlHierBinding) dragModel.getWrappedData();
        Iterator rowKeySetIterator = rowKeySet.iterator();
        if (binding != null){
          while (rowKeySetIterator.hasNext()){
            List nodePath = (List)rowKeySetIterator.next();
            if(nodePath!=null){
              JUCtrlHierNodeBinding node = null;
              node = binding.findNodeByKeyPath(nodePath);
              String structureDefName = node.getHierTypeBinding().getStructureDefName();
              if (structureDefName.equalsIgnoreCase(empDef)){
                Row rw  = node.getRow();
                rw.setAttribute("DepartmentId", theNewDepartment);
              }
            }
          }
          OperationBinding operationBinding =
                    (OperationBinding)getBindingContainer().getOperationBinding("Commit");
              operationBinding.execute();
          return DnDAction.MOVE;
        }
      }
    }
    return DnDAction.NONE;
  }

  public void dragFinished(DropEvent dropEvent){
   System.out.println("drop finished");
  }
.......
}

Generate the application again, and run it.

JHeadstart 11g: Tree-Form with drag and drop functionallity dragging

Here’s the result after the drag and drop.

JHeadstart 11g: Tree-Form with drag and drop functionallity afterDrop

Resources.
Luc Bors on AMIS Technology Blog: Dropping Trees.
Frank Nimphius in Chapter 14 of Oracle Fusion Developers Guide