### 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.

There are two components that provide drag-and-drop functionality: <r:dragSource> which takes care of the drag and <r:dropTarget> which takes care with of the drop operations.

## 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 <r:dragSource> and specify albums with "type" attribute. Let's have a look at the `src/main/webapp/includes/index/tree.xhtml` file:

                <r:treeModelAdaptor var="album" nodes="#{'#{'}treeNode.albums}">
                    <r:treeNode … >
                                …
                            <r:dragSource type="album" dragIndicator="dragIndicator" dragValue="#{'#{'}treeNode}" />
                                …
                        </r:outputPanel>
                    </r:treeNode>
                    …
                </r:treeModelAdaptor>

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 <r:dropTarget> with "acceptedTypes" attribute to the "Shelf" node and in order to process drop on the server side we specify a listener with the "dropListener" attribute in the same `src/main/webapp/includes/index/tree.xhtml` file:

                <r:treeModelAdaptor nodes="#{'#{'}userBean.user.shelves}">
                    <r:treeNode … >
                                …
                            <r:dropTarget acceptedTypes="album" dropValue="#{'#{'}treeNode}" dropListener="#{'#{'}dndManager.processDrop}"
                                render="treePanel, mainArea" />
                                …
                    </r:treeNode>
                    …
                </r:treeModelAdaptor>

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.

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

                <r:dragIndicator id="dragIndicator">
                    <r:panel>
                        [Album]
                    </r:panel>
                </r:dragIndicator>

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

                public void processDrop(DropEvent dropEvent) {
                    if (user == null) return;

                    Object dragValue = dropEvent.getDragValue();
                    Object dropValue = dropEvent.getDropValue();
                    if (dragValue instanceof Image) {
                        if (!((Album) dropValue).getOwner().getLogin().equals(user.getLogin())) {
                            error.fire(new SimpleEvent(Constants.DND_PHOTO_ERROR));
                            return;
                        }
                        handleImage((Image) dragValue, (Album) dropValue);
                    } else if (dragValue instanceof Album) {
                        if (!((Shelf) dropValue).getOwner().getLogin().equals(user.getLogin())) {
                            error.fire(new SimpleEvent(Constants.DND_ALBUM_ERROR));
                            return;
                        }
                        handleAlbum((Album) dragValue, (Shelf) dropValue);
                    }
                }

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

                <r:dragIndicator id="dragIndicator">
                    <r:panel>
                        [Album]
                    </r:panel>
                </r:dragIndicator>
                <r:dragIndicator id="iDragIndicator">
                    <r:panel>
                        [Image]
                    </r:panel>
                </r:dragIndicator>
                <r:tree id="userTree" var="treeNode" toggleType="client">
                    <r:treeModelAdaptor nodes="#{'#{'}userBean.user.shelves}">
                        <r:treeNode style="cursor:pointer" selectedClass="tree-selected-node"
                            iconExpanded="/img/shell/tree_icon_shelf.png" iconCollapsed="/img/shell/tree_icon_shelf.png" id="shelf">
                            <ui:include src="/includes/contextMenu/CMForShelf.xhtml">
                                <ui:param name="shelf" value="#{'#{'}treeNode}" />
                                <ui:param name="target" value="shelf" />
                            </ui:include>
                            <r:outputPanel layout="block" style="cursor:pointer;width:200px; overflow-x:hidden;">
                                <h:outputText value="#{'#{'}treeNode.name}" />
                                <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" value=" #{'#{'}messages['delimiter']} " />
                                <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" styleClass="bold"
                                    value="#{'#{'}fn:length(treeNode.unvisitedImages)}" />
                                <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" value=" #{'#{'}messages['new']}" />
                                <r:ajax render="treePanel, mainArea" event="click" listener="#{'#{'}controller.showShelf(treeNode)}" />

                                <r:dropTarget acceptedTypes="album" dropValue="#{'#{'}treeNode}" dropListener="#{'#{'}dndManager.processDrop}"
                                    render="treePanel, mainArea" />

                                <r:tooltip direction="topRight" showDelay="1000">
                                    <span style="white-space: nowrap">#{'#{'}treeNode.name}</span>
                                </r:tooltip>
                            </r:outputPanel>
                        </r:treeNode>

                        <r:treeModelAdaptor nodes="#{'#{'}treeNode.albums}">
                            <r:treeNode style="cursor:pointer" render="mainArea, treePanel" selectedClass="tree-selected-node"
                                iconLeaf="img/shell/tree_icon_album.png" id="album">
                                <ui:include src="/includes/contextMenu/CMForAlbum.xhtml">
                                    <ui:param name="album" value="#{'#{'}treeNode}" />
                                    <ui:param name="target" value="album" />
                                </ui:include>
                                <r:outputPanel layout="block" style="cursor:pointer;width:200px; overflow-x:hidden;">
                                    <h:outputText value="#{'#{'}treeNode.name}" />
                                    <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" value=" #{'#{'}messages['delimiter']} " />
                                    <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" styleClass="bold"
                                        value="#{'#{'}fn:length(treeNode.unvisitedImages)}" />
                                    <h:outputText rendered="#{'#{'}fn:length(treeNode.unvisitedImages) > 0}" value=" #{'#{'}messages['new']}" />
                                    <r:ajax render="treePanel, mainArea" event="click" listener="#{'#{'}controller.showAlbum(treeNode)}" />

                                    <r:dragSource type="album" dragIndicator="dragIndicator" dragValue="#{'#{'}treeNode}" />
                                    <r:dropTarget acceptedTypes="image" dropValue="#{'#{'}treeNode}"
                                        dropListener="#{'#{'}dndManager.processDrop}" render="treePanel, mainArea" />

                                    <r:tooltip direction="topRight" showDelay="1000">
                                        <span style="white-space: nowrap"> #{'#{'}treeNode.name} </span>
                                    </r:tooltip>
                                </r:outputPanel>
                            </r:treeNode>

                        </r:treeModelAdaptor>
                    </r:treeModelAdaptor>

                </r:tree>

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

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

- Tree for the <r:tree> component;

- Drag and Drop for the <r:dragSource> and <r:dropTarget> components;