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.
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.
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.
This will create a treeForm layout with the tree on the left, and the corresponding form on the right.
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:
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.
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.
Here’s the result after the drag and drop.
Resources.
Luc Bors on AMIS Technology Blog: Dropping Trees.
Frank Nimphius in Chapter 14 of Oracle Fusion Developers Guide