Monday, May 19, 2014

Drag and Drop feature in ADF tree-Drag from Tree drop in tree

So far we have seen how to create a tree structure, how to create multiple table and implement drag and drop in them.
In this exercise we will see how we can implement drag from tree and drop to tree. Before reading this article you can go through an excellent article in oracle for dragging records from tree and dropping to table i.e. just the reverse functionality what we wanted to achieve in our case.
The basic will remain the same.

We will create first a tree structure and then implement drag and drop in it.

We will use the hr schema for this purpose.

Then we will create a drag source in the tree and a drop target

The managed bean at the back end will do all the magic.

We will try to merge the two exercises that we have learned ealier to achieve the desired functionality in this exercise.It is how to create and ADF tree


There are already a lot of blogs on the implementaion but as usual i will try to implement the code in my own style taking input from all these blogs and oracle documentation

http://andrejusb.blogspot.in/2009/11/tree-table-component-in-oracle-adf.html
http://www.gabrielsideras.com/2010/10/23/adf-drag-and-drop-functionality-in-an-aftree-component/



Drag and drop tree works in the same way as drag and drop table works.

There is an additional logic in drag and drop tree is that we need to find the node which is getting dropped.

The logic for the retrieval of node lies in the fact that if the dropped node is of employee get the parent node details(which in our case is department as we are considering only two tables employee and department) and if the dropped node is department just get the node details.

Here again we need a unique identifier for the ParentNode which in our case is a DepartmentID.



The discriminant that we have defined for the dragged and dropped node is employee.

Here is the code which will do the magic of drag and drop in ADF tree.


package com.tree;

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

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.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 DropBean {
public DropBean() {
}

public DnDAction dropListener(DropEvent dropEvent) {
RichTree rt = (RichTree)dropEvent.getDropComponent();
Number newDepartmentId = null;
List dropRowSite = (List)dropEvent.getDropSite();
if (dropRowSite == null) {
return DnDAction.NONE;
}
rt.setRowKey(dropRowSite);
JUCtrlHierNodeBinding rowBinding = null;
rowBinding = (JUCtrlHierNodeBinding)rt.getRowData();
int rtDepth = rt.getDepth();
// If depth ==1 it is employee node so get the parent node for employee if depth ==0 get the node details
if (rtDepth == 1) {
newDepartmentId =
(Number)rowBinding.getParent().getRow().getAttribute("DepartmentId");
} else {
newDepartmentId =
(Number)rowBinding.getRow().getAttribute("DepartmentId");
}
Transferable transferable = dropEvent.getTransferable();
DataFlavor rowKeySetFlavor =
DataFlavor.getDataFlavor(RowKeySet.class, "employee");
RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor);
if (rowKeySet != null) {
CollectionModel draggedModel = null;
draggedModel = transferable.getData(CollectionModel.class);
if (draggedModel != null) {
JUCtrlHierBinding JuCtrlbinding = null;
JuCtrlbinding =
(JUCtrlHierBinding)draggedModel.getWrappedData();
Iterator rowKeySetIterator = rowKeySet.iterator();
if (JuCtrlbinding != null) {
while (rowKeySetIterator.hasNext()) {
List nodeAddress = (List)rowKeySetIterator.next();
if (nodeAddress != null) {
JUCtrlHierNodeBinding getNode = null;
getNode =
JuCtrlbinding.findNodeByKeyPath(nodeAddress);
Row rw = getNode.getRow();
rw.setAttribute("DepartmentId", newDepartmentId);
}
}
return DnDAction.MOVE;
}
}
}
return DnDAction.NONE;

}
}



My jsp page has following entry for the tree component

<af:tree value="#{bindings.DepartmentsView1.treeModel}" var="node"
selectionListener="#{bindings.DepartmentsView1.treeModel.makeCurrent}"
rowSelection="single" id="t1">
<f:facet name="nodeStamp">
<af:outputText value="#{node}" id="ot1"/>
</f:facet>
<af:dragSource actions="MOVE" defaultAction="MOVE"
discriminant="employee"/>
<af:collectionDropTarget dropListener="#{DropBean.dropListener}"
modelName="employee" actions="MOVE"/>
</af:tree>

Now once you have desinged your code and compiled it go ahead and deploy it to server


Once you will deploy you will get the following page.



Now try to drag and drop employees in to other nodes.
Here since we are not putting any conditions so if you will drag and drop an employee to either department or employee node it will add the entry , but you can restrict it using a simple if else condition.You can also implement a pop up saying not correct node or something like that. We will see an exercise on how to show popup

As you can see i have dropped four employee from purchasing department , 2 employee to each on Administration and Marketing so my resulting page will look like this



This code is fine for two level of hierarchy. But you can implement the same logic for multiple level of hierarcy in you code. Again this code is for moving single row from one node to another and can be enhanced to drag and drop multiple rows from one node to other.

No comments: