### Navigation tree for a registered user

As it was mentioned before a navigation tree for a registered user has two main features: drag-and-drop and context menu.

Drag-and-drop feature supported in the Photo Album application is not so complicated as it may seem from the first view. In this application we can mark out two types of drag-and-drop: one type takes place only inside the tree (between tree nodes) and another one - between the watching area and the tree. The difference is not considerable enough to describe two types separately, but also not at all insignificant to be omitted here.

The tree related components (<rich:tree> and <rich:treeNode>) have their own attributes that provide drag-and-drop functionality. These attributes can be divided into two groups: those which provide drag (dragValue, dragListener, dragIndicator, dragType attributes) and those which provide drop operations (dropValue, dropListener, acceptedTypes, typeMapping).

## Note:

Due to "Shelves - Albums - Photos" hierarchy we can say that photos could be moved between albums, albums could be moved between shelves. To avoid a mishmash, it's not allowed to place photos directly in shelves as well as nesting shelves inside shelves or albums inside albums.

Let's explore how drag-and-drop works for albums.

All albums, that are represented as TreeNodes, must be marked somehow for dragging. For this purpose we use previously mentioned "dragValue", "dragType" attributes. Let's have a look at the `src/main/webapp/includes/index/tree.xhtml` file:

    <rich:treeNodesAdaptor var="album" nodes="{shelf.albums}">

          <rich:treeNode style="cursor:pointer"

                            reRender="mainArea, treePanel"

                            dragType="album"

                            dragValue="{album}"

                            dropValue="{album}"

                            acceptedTypes="image"

                            selectedClass="tree-selected-node"

                            icon="img/shell/tree_icon_album.png">

                ...

                <rich:dndParam name="label" type="drag" value="{album.name}" />

                ...

          </rich:treeNode>

    </rich:treeNodesAdaptor>

To provide drop functionality for the marked albums, we should mark Shelves as drop zones in the application code too. For this purpose we add the "dropValue" and "acceptedTypes" attributes to the "Shelf" node in the same `src/main/webapp/includes/index/tree.xhtml` file:

    <rich:treeNodesAdaptor nodes="{shelfManager.getUserShelves()}" var="shelf">

          <rich:treeNode style="cursor:pointer" acceptedTypes="album" dropValue="{shelf}" reRender="mainArea, treePanel" selectedClass="tree-selected-node">

                ...

          </rich:treeNode>

    </rich:treeNodeAdaptor>

The "acceptedTypes" attribute tells the "Shelf" node what types of dragged zones (albums in this case) it can accept. We have specified "Album" node "dragType" as "album", so the "Shelf" node can accept it.

Finally in order to process drop on the server side we need to specify a listener for the <rich:tree> in the "dropListener" attribute (`src/main/webapp/includes/index/tree.xhtml` file):

    <rich:tree adviseNodeOpened="{treeManager.adviseNodeSelected}"

                      adviseNodeSelected="{treeManager.adviseNodeSelected}"

                      ajaxSubmitSelection="false" dragIndicator="dragIndicator"

                      treeNodeVar="treeNode" switchType="client"

                      iconCollapsed="/img/shell/tree_icon_plus.png"

                      iconExpanded="/img/shell/tree_icon_minus.png"

                      dropListener="{dndManager.processDrop}"

                      showConnectingLines="false">

                ...

    </tree>

The code for the <rich:dragIndicator> looks like the following:

    <rich:dragIndicator id="dragIndicator" />

The `processDrop()` method of `DnDManager.java` class is shown in the listing below:

    ...

    public void processDrop(DropEvent dropEvent) {

          Dropzone dropzone = (Dropzone) dropEvent.getComponent();

          Object dragValue = dropEvent.getDragValue();

          Object dropValue = dropzone.getDropValue();

          if(dragValue instanceof Image){

                if(!((Album)dropValue).getOwner().getLogin().equals(user.getLogin())){

                      Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, Constants.DND_PHOTO_ERROR);

                      return;

                }

                handleImage((Image)dragValue, (Album)dropValue);

          }else if(dragValue instanceof Album){

                if(!((Shelf)dropValue).getOwner().getLogin().equals(user.getLogin())){

                      Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT, Constants.DND_ALBUM_ERROR);

                      return;

                }

                handleAlbum((Album)dragValue, (Shelf)dropValue);

          }

    }

    ...

Here is the whole example of the "Navigation tree for a registered user":

    <h:panelGroup id="tree" rendered="{identity.hasRole('admin')}" layout="block">

            <a4j:commandLink actionListener="{controller.selectShelves()}" reRender="mainArea, treePanel"><h2><h:outputText  value="My shelves:"/></h2></
    a4j:commandLink><br/>

        <rich:dragIndicator

                id="dragIndicator" />

            <rich:tree

                adviseNodeOpened="{treeManager.adviseNodeSelected}"

                adviseNodeSelected="{treeManager.adviseNodeSelected}"

                ajaxSubmitSelection="false" dragIndicator="dragIndicator"

                treeNodeVar="treeNode" switchType="client"

                iconCollapsed="/img/shell/tree_icon_plus.png"

                iconExpanded="/img/shell/tree_icon_minus.png"

                dropListener="{dndManager.processDrop}"

                showConnectingLines="false">

                    <f:facet name="icon">

                        <h:graphicImage style="border: none" value="/img/shell/tree_icon_shelf.png">

                                <a4j:support reRender="treePanel, mainArea" event="onclick" actionListener="{controller.showShelf(shelf)}" similarityGroupingId="sel" />

                        </h:graphicImage>

                    </f:facet>

                    <ui:include src="/includes/contextMenu/CMForShelf.xhtml" >

                        <ui:param name="shelf" value="{shelf}" />

                    </ui:include>

                    <a4j:outputPanel>

                        <h:outputText style="cursor:pointer" value="{shelf.name}" />

                        <h:outputText value=" :: " />

                        <strong>{shelf.unvisitedImages.size()}</strong> new

                        <a4j:support reRender="treePanel, mainArea" event="onclick" actionListener="{controller.showShelf(shelf)}" similarityGroupingId="sel" />

                    </a4j:outputPanel>

                    </rich:treeNode>

                    <rich:treeNodesAdaptor var="album"

                        nodes="{shelf.albums}">

                        <rich:treeNode style="cursor:pointer" reRender="mainArea, treePanel" dragType="album"

                            dragValue="{album}" dropValue="{album}"

                            acceptedTypes="image"

                            selectedClass="tree-selected-node"

                            icon="img/shell/tree_icon_album.png">

                            <f:facet name="iconLeaf">

                                <h:graphicImage style="border: none" value="img/shell/tree_icon_album.png">

                                        <a4j:support reRender="treePanel, mainArea" event="onclick" actionListener="{controller.showAlbum(album)}" similarityGroupingId="sel" />

                                </h:graphicImage>

                            </f:facet>

                            <ui:include src="/includes/contextMenu/CMForAlbum.xhtml" >

                            <ui:param name="album" value="{album}" />

                            </ui:include>

                            <rich:dndParam name="label" type="drag" value="{album.name}" />

                            <a4j:outputPanel >

                                <h:outputText style="cursor:pointer" value="{album.name}" />

                                <h:outputText value=" :: " />

                                    <strong>{album.unvisitedImages.size()}</strong> new

                            <a4j:support reRender="treePanel, mainArea" event="onclick" actionListener="{controller.showAlbum(album)}" similarityGroupingId="sel" />

                            </a4j:outputPanel>

                    </rich:treeNode>

                    </rich:treeNodesAdaptor>

                </rich:treeNodesAdaptor>

            </rich:tree>

            </h:panelGroup>

The image below shows how the described above drag-and-drop features are rendered in the Photo Album.

Vizit following pages at RichFaces Live Demo for more information, examples and sources on the components used in the application and described in this chapter:

- Tree for the <rich:tree> component;

- TreeNodesAdaptor for the <rich:treeNodesAdaptor> component;

- DragIndicator for the <rich:dragIndicator> component;

- DragDropParameter for the <rich:dndParam> component.