- ADF – usage of function key (eg. F5) - 4. April 2018
- ADF resource bundle with parameters - 9. Januar 2018
- ADF help provider link per fragment - 6. November 2017
My task was to offer a kind of folder structure in a tree table and use an easy way to connect nodes with each other. The easiest way is drag & drop because this is intuitive and you can use it fast across many nodes. Alternatively, a use of arrow buttons could be used to move a node, but you often need a lot of clicks.
The first thing we need is a table structure which offers this possibility. As a reference I take the HR schema and the employees table.
This table has a self-reference via the ManagerId, which holds an EmployeeId again.
In a tree table this can look like the following:
The interesting thing is that I do not use #{node.Email} but #{node.bindings.Email.inputValue} instead. With the help of the name binding part I get access to all binding structures of this value.
The following components are needed to handle drag & drop:
This offers the source and destination of the DropListener to be catched and used in java.
public DnDAction dropListenerTreeTable(DropEvent dropEvent) { RichTreeTable tree = (RichTreeTable) dropEvent.getDragComponent(); String dragNodeVO = null; Transferable t = dropEvent.getTransferable(); DataFlavor<RowKeySet> df=DataFlavor.getDataFlavor(RowKeySet.class,"rowMove"); RowKeySet rks = t.getData(df); Iterator iter = rks.iterator(); Object dragCurrentRowKey = tree.getRowKey(); Row dragRow = null; if (iter.hasNext()) { List key = (List) iter.next(); tree.setRowKey(key); JUCtrlHierNodeBinding rowBinding = (JUCtrlHierNodeBinding) tree.getRowData(); dragRow = rowBinding.getRow(); dragNodeVO = dragRow.getStructureDef().getDefName(); } List dropRowKey = (List) dropEvent.getDropSite(); if (dropRowKey == null) { return DnDAction.NONE; } tree.setRowKey(dropRowKey); JUCtrlHierNodeBinding dropNode = (JUCtrlHierNodeBinding) tree.getRowData(); Row dropRow = dropNode.getRow(); Integer dropId = (Integer) dropRow.getAttribute("EmployeeId"); Integer childParentId = (Integer) dragRow.getAttribute("ManagerId"); if (childParentId != dropId) { dragRow.setAttribute("ManagerId", dropId); refreshTable(); } else { FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Dies existiert unterhalb des Ziels schon!"); FacesContext.getCurrentInstance().addMessage(null, msg); return DnDAction.NONE; } tree.setRowKey(dragCurrentRowKey); AdfFacesContext.getCurrentInstance().addPartialTarget(tree); return DnDAction.MOVE; }
The main idea is to set the ManagerId from the source to the ID of the destination (new parent) and refresh the table.
To clean the connection there exists a red little arrow in every child which executes the following action:
public String removeFromParentTree() { Row rw = null; RowKeySet rks = tree.getSelectedRowKeys(); if (rks != null) { Iterator rksIterator = rks.iterator(); CollectionModel model = (CollectionModel) tree.getValue(); JUCtrlHierBinding treeBinding = (JUCtrlHierBinding) model.getWrappedData(); while (rksIterator.hasNext()) { List nodeKey = (List) rksIterator.next(); JUCtrlHierNodeBinding node = treeBinding.findNodeByKeyPath(nodeKey); if (node != null) { rw = node.getRow(); rw.setAttribute("ManagerId", null); } } } refreshTable(); // PPR etc. return null; }
This method cleans the ManagerId at the corresponding node.
The result can look like this:
If you drag & drop a node to another node then this node is a new child of the destination node with all its children. If you clean the connection then the node with all its children is on the top level without any parent (next to “Stephen King”).
To open all nodes recursively, which can take a long time, depending on the amount of data:
private void expandTreeChildrenNode(RichTreeTable rt, FacesCtrlHierNodeBinding node, List<Key> parentRowKey) { ArrayList children = node.getChildren(); List<Key> rowKey; if (children != null) { for (int i = 0; i < children.size(); i++) { rowKey = new ArrayList<Key>(); rowKey.addAll(parentRowKey); rowKey.add(((FacesCtrlHierNodeBinding) children.get(i)).getRowKey()); rt.getDisclosedRowKeys().add(rowKey); if (((FacesCtrlHierNodeBinding) (children.get(i))).getChildren() == null) continue; expandTreeChildrenNode(rt, (FacesCtrlHierNodeBinding) (node.getChildren().get(i)), rowKey); } } } public String expand() { if (tree != null) { int rowCount = tree.getRowCount(); List<Key> rowKey; for (int j = 0; j < rowCount; j++) { // expand the main nodes FacesCtrlHierNodeBinding node = (FacesCtrlHierNodeBinding) tree.getRowData(j); rowKey = new ArrayList<Key>(); rowKey.add(node.getRowKey()); tree.getDisclosedRowKeys().add(rowKey); tree.setRowKey(rowKey); // expand the child nodes of the main nodes expandTreeChildrenNode(tree, node, rowKey); } } return null; }
The result is a cool solution to work with drag and drop across tree table nodes.