Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.4.0) B31973-06 |
|
![]() Previous |
![]() Next |
This chapter describes how to add drag and drop functionality to your pages, which allows users to drag the values of attributes or objects from one component to another, or allows users to drag and drop components.
This chapter includes the following sections:
Section 32.2, "Adding Drag and Drop Functionality for Attributes"
Section 32.3, "Adding Drag and Drop Functionality for Objects"
Section 32.4, "Adding Drag and Drop Functionality for Collections"
Section 32.5, "Adding Drag and Drop Functionality for Components"
Section 32.6, "Adding Drag and Drop Functionality Into and Out of a panelDashboard Component"
Section 32.7, "Adding Drag and Drop Functionality to a Calendar"
Section 32.8, "Adding Drag and Drop Functionality for DVT Graphs"
Section 32.9, "Adding Drag and Drop Functionality for DVT Gantt Charts"
The ADF Faces framework provides the ability to drag and drop items from one place to another on a page. For example, in the File Explorer application, you can drag a file from the Table tab and drop it into another directory folder, as shown in Figure 32-1.
In this scenario, you are actually dragging an object from one collection (Folder0) and dropping it into another collection (Folder3). This is one of the many supported drag and drop scenarios. ADF Faces supports the following scenarios:
Dragging an attribute value from one component instance and copying it to another. For example, a user might be able to drag an outputText
component onto an inputText
component, which would result in the value of the text
attribute of the outputText
component becoming the value of the text
attribute on the inputText
component.
Dragging the value of one object and dropping it so that it becomes the value of another object. For example, a user might be able to drag an outputText
component onto another outputText
component, which would result in an array of String
objects populating the text
attribute of the second outputText
component.
Dragging an object from one collection and dropping it into another, as shown in Figure 32-1.
Dragging a component from one place on a page to another. For example, a user might be able to drag an existing panelBox
component to a new place within a panelGrid
component.
Dragging an activity in a calendar from one start time or date to another.
Dragging a component into or out of a panelDashboard
component.
Dragging a marker in a DVT scatter or bubble graph to change its value.
Dragging an object from a DVT Gantt chart to another component.
When users click on a source and begin to drag, the browser displays the element being dragged as a ghost element attached to the mouse pointer. Once the ghost element hovers over a valid target, the target component shows some feedback (for example, it becomes highlighted). If the user drags the ghost element over an invalid target, the cursor changes to indicate that the target is not valid.
When dragging attribute values, the user can only copy the value to the target. For all other drag and drop scenarios, on the drop, the element can be copied (copy and paste), moved (cut and paste), or linked (copy and paste as a link, for example, copying text and pasting the text as an actual URL).
The component that will be dragged and that contains the value is called the source. The component that will accept the drop is called the target. You use a specific tag as a child to the source and target components that tells the framework to allow the drop. Table 32-1 shows the different drag and drop scenarios, the valid source(s) and target(s), and the associated tags to be used for that scenario.
Table 32-1 Drag and Drop Scenarios
Scenario | Source | Target |
---|---|---|
Dragging an attribute value |
An attribute value on a component |
An attribute value on another component, as long as it is the same object type |
Tag: |
Tag: attributeDropTarget |
|
Dragging an object from one component to another |
Any component |
Any component |
Tag: |
Tag: |
|
Dragging an item from one collection and dropping it into another |
|
|
Tag: |
Tag: |
|
Dragging a component from one container to another |
Any component |
Any component |
Tag: |
Tag: |
|
Dragging a calendar activity from one start time or date to another |
|
|
Tag: None needed |
Tag: |
|
Dragging a |
|
|
Tag: componentDragSource |
Tag: |
|
Dragging a panelBox component out of a |
panelBox component in a |
Any component |
Tag: componentDragSource |
Tag: |
|
Dragging a marker in a DVT graph |
|
|
Tag: |
Tag: |
|
Dragging an object from a DVT Gantt chart and dropping it on another component |
Gantt chart |
Any component |
Tag: |
Tag: |
You can restrict the type of the object that can be dropped on a target by adding a dataFlavor
tag. This helps when the target can accept only one object type, but the source may be one of a number of different types. The dataFlavor
tag also allows you to set multiple types so that the target can accept objects from more than one source or from a source that may contain more than one type. Both the target and the source must contain the dataFlavor
tag, and the values must be the same in order for the drop to be successful.
Note: Drag and drop functionality is not supported between windows. Any drag that extends past the window boundaries will be canceled. Drag and drop functionality is supported between popup windows and the base page for the popup.Also note that drag and drop functionality is not accessible; that is, there are no keyboard strokes that can be used to execute a drag and drop. Therefore, if your application requires all functionality to be accessible, you must provide this logic. For example, your page might also present users with a method for selecting objects and a Move button or menu item that allows them to move those selected objects. |
You add drag and drop functionality for attributes by defining one component's attribute to be a target and another component's attribute to be a source.
Note: The target and source attribute values must both be the same data type. |
The following procedure assumes you have your target and source components already on the JSF page.
To add drag and drop functionality for attributes:
In the Component Palette, from the Operations panel, drag and drop an Attribute Drop Target as a child to the target component.
In the Insert Attribute Drop Target dialog, use the Attribute dropdown to select the attribute that will be populated by the drag and drop action. This dropdown list shows all valid attributes on the target component.
From the Component Palette, drag and drop an Attribute Drag Source as a child to the component that can provide a value for the target.
In the Insert Attribute Drag Source dialog, use the Attribute dropdown to select the attribute whose value will be used to populate the target attribute. This dropdown list shows all valid attributes on the source component.
When you want users to be able to drag things other than attribute values, or you want users to be able to do something other than copy attributes from one component to another, you use the dropTarget
tag. Additionally, use the DataFlavor
object to determine the valid Java types of sources for the drop target. Because there may be several drop targets and drag sources, you can further restrict valid combinations by using discriminant values. You also must implement any required functionality in response to the drag and drop action.
For example, suppose you have an outputText
component and you want the user to be able to drag the outputText
component to a panelBox
component and have that component display an array
, as shown in Figure 32-6.
The outputText
component contains an attributeDragSource
tag. However, because you want to drag an array
(and not just the String
value of the attribute), you must use the dropTarget
tag instead of the attributeDropTarget
tag. Also use a dataFlavor
tag to ensure that only an array
object will be accepted on the target.
You can also define a discriminant value for the dataFlavor
tag. This is helpful if you have two targets and two sources, all with the same object type. By creating a discriminant value, you can be sure that each target will accept only valid sources. For example, suppose you have two targets that both accept an EMPLOYEE object, TargetA and TargetB. Suppose you also have two sources, both of which are EMPLOYEE objects. By setting a discriminant value on TargetA with a value of alpha
, only the EMPLOYEE source that provides the discriminant value of alpha
will be accepted.
You also must implement a listener for the drop event. The object of the drop event is called the transferable
, which contains the payload of the drop. Your listener must access the transferable
object, and from there, use the DataFlavor
object to verify that the object can be dropped. You then use the drop event to get the target component and update the property with the dropped object. More details about this listener are covered in the procedure in Section 32.9.1, "How to Add Drag and Drop Functionality for a DVT Component".
To add drag and drop functionality, first add tags to a component that define it as a target for a drag and drop action. Then implement the event handler method that will handle the logic for the drag and drop action. Last, you define the sources for the drag and drop.
This procedure assumes the source and target components already exist on the page.
To add drag and drop functionality:
In the JSF page that contains the target, add a dropTarget
tag as a child to the target component by dragging and dropping a Drop Target tag (located in the Operations panel) from the Component Palette.
In the Insert Drop Target dialog, enter an expression that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 5).
Tip: You can also intercept the drop on the client by populating theclientDropListener attribute. For more information, see Section 32.3.3, "What You May Need to Know About Using the ClientDropListener". |
In the Insert Data Flavor dialog, enter the class for the object that can be dropped onto the target, for example java.lang.Object
. This selection will be used to create a dataFlavor
tag, which determines the type of object that can be dropped onto the target, for example a String
or a Date
. Multiple dataFlavor
tags are allowed under a single drop target to allow the drop target to accept any of those types.
Tip: To specify a typed array in aDataFlavor tag, add brackets ([]) to the class name, for example, java.lang.Object[] . |
In the Structure window, select the dropTarget
tag. In the Property inspector, select a value for the actions
attribute. This defines what actions are supported by the drop target. Valid values can be COPY
(copy and paste), MOVE
(cut and paste), and LINK
(copy and paste as a link), for example:.
MOVE COPY
If no actions are specified, the default is COPY
.
Example 32-1 shows the code for a dropTarget
component inserted into an panelBox
component that takes an array object as a drop source. Note that because an action was not defined, the only allowed action will be COPY
.
In the managed bean referenced in the EL expression created in Step 2, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This method must take a DropEvent
event as a parameter and returns a DnDAction
object, which is the action that will be performed when the source is dropped. Valid return values are DnDAction.COPY
, DnDAction.
MOVE
, and DnDAction.LINK
, and were set when you defined the target attribute in Step 5. This method should check the DropEvent
event to determine whether or not it will accept the drop. If the method accepts the drop, it should perform the drop and return the DnDAction
object it performed. Otherwise, it should return DnDAction.NONE
to indicate that the drop was rejected.
The method must also check for the presence for each dataFlavor
object in preference order.
Tip: If your target has more than one defineddataFlavor object, then you can use the Transferable.getSuitableTransferData() method, which returns a List of TransferData objects available in the Transferable object in order, from highest suitability to lowest. |
The DataFlavor
object defines the type of data being dropped, for example java.lang.Object
, and must be as defined in the DataFlavor
tag on the JSP, as created in Step 3.
Tip: To specify a typed array in aDataFlavor object, add brackets ([]) to the class name, for example, java.lang.Object[].
If the drag and drop framework doesn't know how to represent a server |
Example 32-2 shows a private method that the event handler method calls (the event handler itself does nothing but call this method; it is needed because this method also needs a String
parameter that will become the value of the outputText
component in the panelBox
component). This method copies an array object from the event payload and assigns it to the component that initiated the event.
Example 32-2 Event Handler Code for a dropListener
public DnDAction handleDrop(DropEvent dropEvent) { Transferable dropTransferable = dropEvent.getTransferable(); Object[] drinks = dropTransferable.getData(DataFlavor.OBJECT_ARRAY_FLAVOR); if (drinks != null) { UIComponent dropComponent = dropEvent.getDropComponent(); // Update the specified property of the drop component with the Object[] dropped dropComponent.getAttributes().put("value", Arrays.toString(drinks)); return DnDAction.COPY; } else { return DnDAction.NONE; } }
Add a clientAttribute
tag as a child to the source component by dragging a Client Attribute (located in the Operations panel), from the Component Palette. This tag is used to define the payload of the source for the event. Define the following for the clientAttribute
tag in the Property Inspector:
Name: Enter any name for the payload.
Value: Enter an EL expression that evaluates to the value of the payload. In the drinks example, this would resolve to the Array
that holds the different drink values.
Drag and drop an Attribute Drag Source (located in the Operations panel), from the palette as another child to the source component. In the Insert Attribute Drag Source dialog, use the dropdown list to select the name
defined for the clientAttribute
tag created in the previous step. Doing so makes the value of the clientAttribute
tag the source's payload. Example 32-3 shows the code for an outputText
component that is the source of the drag and drop operation.
When performing a drag and drop operation, users can press keys on the keyboard (called keyboard modifiers) to select the action they wish to take on a drag and drop. The drag and drop framework supports the following keyboard modifiers:
SHIFT: MOVE
CTRL: COPY
CTRL+SHIFT: LINK
When a user executes the drag and drop operation, the drop target first determines that it can accept the drag source's data flavor value. Next, if the source and target are collections, the framework intersects the actions allowed between the drag source and drop target and executes the action (one of COPY, MOVE, or LINK) in that order from the intersection. When there is only one valid action, that action is executed. When there is more than one possible action and the user's keyboard modifier matches that choice, then that is the one that is executed. If either no keyboard modifier is used, or the keyboard modifier used does not match an allowed action, then the framework chooses COPY, MOVE, LINK in that order, from the set of allowed actions.
For example, suppose you have a drop target that supports COPY and MOVE. First the drop target determines that drag source is a valid data flavor. Next, it determines which action to perform when the user performs the drop. In this example, the set is COPY and MOVE. If the user holds down the SHIFT
key while dragging (the keyboard modifier for MOVE), the framework would choose the MOVE action. If the user is doing anything other than holding down the SHIFT
key when dragging, the action will be COPY because COPY is the default when no modifier key is chosen (it is first in the order). If the user is pressing the CTRL key, that modifier matches COPY, so COPY would be performed. If the user was pressing the CTRL+SHIFT keys, the action would still be COPY because that modifier matches the LINK action which is not in the intersected set of allowed actions.
Note: Because information is lost during the roundtrip between Java and JavaScript, the data in the drop may not be the type that you expect. For example, all numeric types appear asdouble objects, char objects appear as String objects, List and Array objects appear as List objects, and most other objects appear as Map objects. For more information, see Section 5.4.3, "What You May Need to Know About Marshalling and Unmarshalling Data.". |
The dropTarget
tag contains the clientDropListner
attribute where you can reference JavaScript that will handle the drop event on the client. The client handler should not take any parameters and returns an AdfDnDContext
action. For example, if the method returns AdfDnDContext.ACTION_NONE
the drop operation will be canceled and no server call will be made; if the method returns AdfDnDContext.ACTION_COPY,
a copy operation will be allowed and a server call will be made which will execute the dropListener
method if it exists.
For example, suppose you want to log a message when the drop event is invoked. You might create a client handler to handle logging that message and then returning the correct action so that the server listener is invoked. Example 32-4 shows a client handler that uses the logger to print a message.
You.use the collectionDropTarget
and dragSource
tags to add drag and drop functionality that allows users to drag an item from one collection (for example, a row from a table), and drop it into another collection component such, as a tree. For example, in the File Explorer application, users can drag a file from the table that displays directory contents to any folder in the directory tree. Figure 32-3 shows the File0.doc
object being dragged from the table displaying the contents of the Folder0
directory to the Folder3
directory. Once the drop is complete, the object will become part of the collection that makes up Folder3
.
As with dragging and dropping single objects, you can have a drop on a collection cause a copy, move, or copy and paste as a link (or a combination of the three), and use dataFlavor
tags to limit what a target will accept.
When the target source is a collection and it supports the move operation, you may also want to also implement a method for the dragDropEndListener
attribute, which is referenced from the source component and is used to clean up the collection after the drag and drop operation. For more information, see Section 32.4.2, "What You May Need to Know About the dragDropEndListener".
To add drag and drop functionality for collections, instead of using the dropTarget
tag, you use the collectionDropTarget
tag. You then must implement the event handler method that will handle the logic for the drag and drop action. Next, you define the source for the drag and drop operation using the dragSource
tag.
This procedure assumes you already have the source and target components on the page.
To add drag and drop functionality:
Add a collectionDropTarget
tag as a child to the target collection component by dragging a Collection Drop Target from the Component Palette.
In the Insert Collection Drop Target dialog, enter an expression for the dropListener
attribute that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 4).
In the Property Inspector, set the following:
actions
: Select the actions that can be performed on the source during the drag and drop operation.
If no actions are specified, the default is COPY
.
modelName
: Define the model for the collection.
The value of the modelName
attribute is a String
object used to identify the drag source for compatibility purposes. The value of this attribute must match the value of the discriminant
attribute of the dragSource
tag you will use in a Step 6. In other words, this is an arbitrary name and works when the target and the source share the same modelName
value or discriminant value.
In the managed bean inserted into the EL expression in Step 2, implement the handler for the drop event.
This method must take a DropEvent
event as a parameter and return a DnDAction
. This method should use the DropEvent
to get the Transferable
object and from there get the RowKeySet
(the rows that were selected for the drag). Using the CollectionModel
obtained through the Transferable
object, the actual rowData
can be obtained to complete the drop. The method should then check the DropEvent
to determine whether it will accept the drop or not. If the method accepts the drop, it should perform the drop and return the DnDAction it performed -- DnDAction.COPY, DnDAction.MOVE or DnDAction.LINK, otherwise it should return DnDAction.NONE to indicate that the drop was rejected.
Example 32-5 shows the event handler method on the CollectionDnd.java
managed bean used in the collectionDropTarget
demo that handles the copy of the row between two tables.
Example 32-5 Event Handler Code for a dropListener for a Collection
public DnDAction handleDrop(DropEvent dropEvent) { Transferable transferable = dropEvent.getTransferable(); // The data in the transferable is the row key for the dragged component. DataFlavor<RowKeySet> rowKeySetFlavor = DataFlavor.getDataFlavor(RowKeySet.class, "DnDDemoModel"); RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor); if (rowKeySet != null) { // Get the model for the dragged component. CollectionModel dragModel = transferable.getData(CollectionModel.class); if (dragModel != null) { // Set the row key for this model using the row key from the transferable. Object currKey = rowKeySet.iterator().next(); dragModel.setRowKey(currKey); // And now get the actual data from the dragged model. // Note this won't work in a region. DnDDemoData dnDDemoData = (DnDDemoData)dragModel.getRowData(); // Put the dragged data into the target model directly. // Note that if you wanted validation/business rules on the drop, // this would be different. getTargetValues().add(dnDDemoData); } return dropEvent.getProposedAction(); } else { return DnDAction.NONE; } }
In the Component Palette, from the Operations panel, drag and drop a Drag Source as a child to the source component.
With the dragSource
tag selected, in the Property Inspector set the allowed Actions and any needed discriminant, as configured for the target.
There may be cases when after a drop event, you have to clean up the source collection. For example, if the drag caused a move, you may have to clean up the source component so that the moved item is no longer part of the collection.
The dragSource
tag contains the dragDropEndListener
attribute that allows you to register a handler that contains logic for after the drag drop operation ends.
For example, if you allow a drag and drop to move an object, you may have to physically remove the object from the source component once you know the drop succeeded. Example 32-6 shows a handler for a dragDropEndListener
. attribute
Example 32-6 Handler for dragDropEndListener
public void endListener(DropEvent dropEvent) { Transferable transferable = dropEvent.getTransferable(); // The data in the transferrable is the row key for the dragged component. DataFlavor<RowKeySet> rowKeySetFlavor = DataFlavor.getDataFlavor(RowKeySet.class, "DnDDemoModel"); RowKeySet rowKeySet = transferable.getData(rowKeySetFlavor); if (rowKeySet != null) { Integer currKey = (Integer)rowKeySet.iterator().next(); // Remove the dragged dta from the source model directly. Object removed = getSource2Values().remove(currKey.intValue()); } // Need to add the drag source table so it gets redrawn. AdfFacesContext.getCurrentInstance().addPartialTarget(dropEvent.getDragComponent());
You can allow components to be moved from one parent to another, or you can allow child components of a parent component to be reordered. For example, Figure 32-4 shows the darker panelBox
component being moved from being the first child component of the panelGrid
component to the last.
Note: If you want to move components into or out of a panelDashboard component, then you need to use procedures specific to that component. For more information, see Section 32.6, "Adding Drag and Drop Functionality Into and Out of a panelDashboard Component." |
Adding drag and drop functionality for components is similar for objects. However, instead of using the attributeDragSource
tag, use the componentDragSource
tag. As with dragging and dropping objects or collections, you also must implement a dropListener
handler.
To add drag and drop functionality:
From the Operations panel of the Component Palette, drag and drop a Drop Target as a child to the target component.
In the Insert Drop Target dialog, enter an expression that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 4).
With the dropTarget
tag still selected, in the Property Inspector, select a valid action set for the action
attribute.
In the managed bean referenced in the EL expression created in Step 2 for the dropListener
attribute, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This method must take a DropEvent
event as a parameter and return a DnDAction
, which is the action that will be performed when the source is dropped. Valid return values are DnDAction.COPY
, DnDAction.
MOVE
, and DnDAction.LINK
, and were set when you defined the target attribute in Step 2.
This handler method should use the DropEvent
event to get the transferable
object and its data and then complete the move or copy, and reorder the components as needed. Once the method completes the drop, it should return the DnDAction
it performed. Otherwise, it should return DnDAction.NONE
to indicate that the drop was rejected.
Example 32-7 shows the handleComponentMove
event handler on the DemoDropHandler.java
managed bean used by the componentDragSource
JSF page in the demo application.
Example 32-7 Event Handler Code for a dropListener That Handles a Component Move
public DnDAction handleComponentMove(DropEvent dropEvent) { Transferable dropTransferable = dropEvent.getTransferable(); UIComponent movedComponent = dropTransferable.getData (DataFlavor.UICOMPONENT_FLAVOR); if ((movedComponent != null) && DnDAction.MOVE.equals(dropEvent.getProposedAction())) { UIComponent dropComponent = dropEvent.getDropComponent(); UIComponent dropParent = dropComponent.getParent(); UIComponent movedParent = movedComponent.getParent(); UIComponent rootParent; ComponentChange change; // Build the new list of IDs, placing the moved component after the dropped //component. String movedLayoutId = movedParent.getId(); String dropLayoutId = dropComponent.getId(); List<String> reorderedIdList = new ArrayList<String>(dropParent.getChildCount()); for (UIComponent currChild : dropParent.getChildren()) { String currId = currChild.getId(); if (!currId.equals(movedLayoutId)) { reorderedIdList.add(currId); if (currId.equals(dropLayoutId)) { reorderedIdList.add(movedLayoutId); } } } change = new ReorderChildrenComponentChange(reorderedIdList); rootParent = dropParent; // apply the change to the component tree immediately // change.changeComponent(rootParent); // redraw the shared parent AdfFacesContext.getCurrentInstance().addPartialTarget(rootParent); return DnDAction.MOVE; } else { return DnDAction.NONE; } }
Add a componentDragSource
tag to the source component by dragging and dropping a Component Drag Source from the Component Palette as a child of the source component.
By default the panelDashboard
component supports dragging and dropping components within itself. That is, you can reorder components in a panelDashboard
component without needing to implement a listener or use additional tags. However, if you want to be able to drag a component into a panelDashboard
component, or to drag a component out of a panelDashboard
component, you do need to use tags and implement a listener. Because you would be dragging and dropping a component, you use the componentDragSource
tag when dragging into the panelDashboard
. However, because the panelDashboard
already supports being a drop target, you do not need to use the dropTarget
tag. Instead, you need to use a dataFlavor
tag with a discriminant. The tag and discriminant notify the framework that the drop is from an external component.
Dragging a component out of a panelDashboard
is mostly the same as dragging and dropping any other component. You use a dropTarget
tag for the target and the componentDragSource
tag for the source. However, you must also use the dataFlavor
tag and a discriminant.
Because the panelDashboard
component has built-in drag and drop functionality used to reorder panelBox
components within the dashboard, you cannot use a dropTarget
tag, but you do need to use a dataFlavor
tag with a discriminant and implement the dropListener
. In that implementation, you need to handle the reorder of the components.
Before you begin:
Create a panelDashboard
component. For more information, see Section 8.7, "Arranging Contents in a Dashboard."
Create another component outside of the panelDashboard
that contains panelBox
components. For more information about panelBox
components, see Section 8.8.3, "How to Use the panelBox Component."
To add drag and drop functionality into a panelDashboard component:
In the Structure window, select the panelDashboard
component that is to be the target component.
In the Property Inspector, for DropListener, enter an expression that evaluates to a method on a managed bean that will handle the drop event (you will create this code in Step 6).
In the Component Palette, from the Operations panel, drag a Data Flavor and drop it as a child to the panelDashboard
component.
In the Insert Data Flavor dialog, enter javax.faces.component.UIComponent
.
In the Property Inspector, set Discriminant to a unique name that will identify the components allowed to be dragged into the panelDashboard
component, for example, dragIntoDashboard
.
In the managed bean referenced in the EL expression created in Step 2 for the dropListener
attribute, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This method must take a DropEvent
event as a parameter and return a DnDAction
of NONE
, because the panelDashboard
handles the positioning of its child components.
This handler method should use the dropEvent.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR)
to get the transferable
object and its data. Once the method completes the drop, you can use the org.apache.myfaces.trinidad.change.ReorderChildrenComponent Change
method to preserve the new ordering of the children and the dropEvent.getDropSiteIndex()
method to get the location at which the user wants the dragged component. You can also use the dashboardComponent.prepareOptimizedEncodingOfInsertedChild()
method to animate the drop of the component.
Example 32-8 shows the move
event handler and helper methods on the DemoDashboardBean.java
managed bean used by the dashboard
JSF page in the ADF Faces demo application.
Example 32-8 Handler for DropListener on a panelDashboard Component
public DnDAction move(DropEvent e) { UIComponent dropComponent = e.getDropComponent(); UIComponent movedComponent = e.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR); UIComponent movedParent = movedComponent.getParent(); // Ensure that we are handling the re-order of a direct child of the panelDashboard: if (movedParent.equals(dropComponent) && dropComponent.equals(_dashboard)) { // Move the already rendered child and redraw the side bar since the insert indexes have // changed: _moveDashboardChild(e.getDropSiteIndex(), movedComponent.getId()); } else { // This isn't a re-order but rather the user dropped a minimized side bar item into the // dashboard, in which case that item should be restored at the specified drop location. String panelKey = _getAssociatedPanelKey(movedComponent); if (panelKey != null) { UIComponent panelBoxToShow = _dashboard.findComponent(panelKey); // Make this panelBox rendered: panelBoxToShow.setRendered(true); int insertIndex = e.getDropSiteIndex(); // Move the already rendered child and redraw the side bar since the insert indexes have // changed and because the side bar minimized states are out of date: _moveDashboardChild(insertIndex, panelKey); // Let the dashboard know that only the one child should be encoded during the render phase: _dashboard.prepareOptimizedEncodingOfInsertedChild( FacesContext.getCurrentInstance(), insertIndex); } } return DnDAction.NONE; // the client is already updated, so no need to redraw it again } private void _moveDashboardChild(int dropIndex, String movedId) { // Build the new list of IDs, placing the moved component at the drop index. List<String> reorderedIdList = new ArrayList<String>(_dashboard.getChildCount()); int index = 0; boolean added = false; for (UIComponent currChild : _dashboard.getChildren()) { if (currChild.isRendered()) { if (index == dropIndex) { reorderedIdList.add(movedId); added = true; } String currId = currChild.getId(); if (currId.equals(movedId) && index < dropIndex) { // component is moved later, need to shift the index by 1 dropIndex++; } if (!currId.equals(movedId)) { reorderedIdList.add(currId); } index++; } } if (!added) { // Added to the very end: reorderedIdList.add(movedId); } // Apply the change to the component tree immediately: ComponentChange change = new ReorderChildrenComponentChange(reorderedIdList); change.changeComponent(_dashboard); // Add the side bar as a partial target since we need to redraw the state of the side bar items // since their insert indexes are changed and possibly because the side bar minimized states // are out of date: RequestContext rc = RequestContext.getCurrentInstance(); rc.addPartialTarget(_sideBarContainer); }
In the Component Palette, from the Operations panel, drag a Component Drag Source and drop it as a child to the panelBox
component that will be the source component.
In the Property Inspector, set Discriminant to be the same value as entered for the Discriminant on the panelDashboard
in Step 5.
Implementing drag and drop functionality out of a panelDashboard
component is similar to standard drag and drop functionality for other components, except that you must use a dataFlavor
tag with a discriminant.
How to add drag and drop functionality out of a panelDashboard component:
In the Component Palette, from the Operations panel, drag and drop a Drop Target as a child to the target component.
In the Insert Drop Target dialog, enter an expression that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 5) and enter javax.faces.component.UIComponent as the FlavorClass.
With the dropTarget
tag still selected, in the Property Inspector, select MOVE as the value action
attribute.
In the Structure window, select the dataFlavor
tag and in the Property Inspector, set Discriminant to a unique name that will identify the panelBox
components allowed to be dragged into this component, for example, dragOutOfDashboard
.
In the managed bean referenced in the EL expression created in Step 2 for the dropListener
attribute, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This handler method should use the DropEvent
event to get the transferable
object and its data and then complete the move and reorder the components as needed. Once the method completes the drop, it should return a DnDAction
of NONE.
You can use the dashboardComponent.
prepareOptimizedEncodingOfDeletedChild()
method to animate the removal of the panelBox
component.
Example 32-9 shows the handleSideBarDrop
event handler and helper methods on the DemoDashboardBean.java
managed bean used by the dashboard
JSF page in the demo application.
Example 32-9 Event Handler Code for a dropListener That Handles a panelBox Move Out of a panelDashboard Component
public DnDAction handleSideBarDrop(DropEvent e) { UIComponent movedComponent = e.getTransferable().getData(DataFlavor.UICOMPONENT_FLAVOR); UIComponent movedParent = movedComponent.getParent(); // Ensure that the drag source is one of the items from the dashboard: if (movedParent.equals(_dashboard)) { _minimize(movedComponent); } return DnDAction.NONE; // the client is already updated, so no need to redraw it again } private void _minimize(UIComponent panelBoxToMinimize) { // Make this panelBox non-rendered: panelBoxToMinimize.setRendered(false); // If the dashboard is showing, let's perform an optimized render so the whole dashboard doesn't // have to be re-encoded. // If the dashboard is hidden (because the panelBox is maximized), we will not do an optimized // encode since we need to draw the whole thing. if (_maximizedPanelKey == null) { int deleteIndex = 0; List<UIComponent> children = _dashboard.getChildren(); for (UIComponent child : children) { if (child.equals(panelBoxToMinimize)) { _dashboard.prepareOptimizedEncodingOfDeletedChild( FacesContext.getCurrentInstance(), deleteIndex); break; } if (child.isRendered()) { // Only count rendered children since that's all that the panelDashboard can see: deleteIndex++; } } } RequestContext rc = RequestContext.getCurrentInstance(); if (_maximizedPanelKey != null) { // Exit maximized mode: _maximizedPanelKey = null; _switcher.setFacetName("restored"); rc.addPartialTarget(_switcher); } // Redraw the side bar so that we can update the colors of the opened items: rc.addPartialTarget(_sideBarContainer); }
In the Component Palette, from the Operations panel, drag and drop a Component Drag Source as a child of the source panelBox
component within the panelDashboard
component.
In the Property Inspector, set Discriminant to be the same value as entered for the Discriminant on the dataFlavor
tag for the target component in Step 4.
The calendar includes functionality that allows users to drag the handle of an activity to change the end time. However, if you want users to be able to drag and drop an activity to a different start time, or even a different day, then you implement drag and drop functionality. Drag and drop allows you to not only move an activity, but also to copy one.
You add drag and drop functionality by using the calendarDropTarget
tag. Unlike dragging and dropping a collection, there is no need for a source tag; the target (that is the object to which the activity is being moved, in this case, the calendar) is responsible for moving the activities. If the source (that is, the item to be moved or copied), is an activity within the calendar, then you use only the calendarDropTarget tag. The tag expects the transferable to be a calendarActivity
object.
However, you can also drag and drop objects from outside the calendar. When you want to enable this, use dataFlavor
tags configured to allow the source object (which will be something other than a calendarActivity
object) to be dropped.
To add drag and drop functionality to a calendar:
In the Component Palette, from the Operations panel, drag and drop a Calendar Drop Target as a child to the calendar
component.
In the Insert Calendar Drop Target dialog, enter an expression for the dropListener
attribute that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 4).
In the Property Inspector, set Actions. This value determines whether the activity (or other source) can be moved, copied, or copied as a link, or any combination of the three. If no action is specified, the default is COPY
.
In the managed bean inserted into the EL expression in Step 2, implement the handler for the drop event.
This method must take a DropEvent
event as a parameter and return a DnDAction
. The DnDAction
is the action that will be performed when the source is dropped. Valid return values are COPY
, MOVE
, and LINK
, and are set when you define the actions
attribute in Step 3. This method should use the DropEvent
to get the transferable
object, and from there, access the CalendarModel
object in the dragged data and from there, access the actual data. The listener can then add that data to the model for the source and then return the DnDAction
it performed: DnDAction.COPY
, DnDAction.MOVE
or DnDAction.LINK
; otherwise, the listener should return DnDAction.NONE
to indicate that the drop was rejected.
The drop site for the drop event is an instance of the oracle.adf.view.rich.dnd.CalendarDropSite
class. For an example of a drag and drop handler for a calendar, see the handleDrop
method on the oracle.adfdemo.view.calendar.rich.DemoCalendarBean
managed bean in the ADF Faces demo application.
If the source for the activity is external to the calendar, drag a Data Flavor and drop it as a child to the calendarDropTarget
tag. This tag determines the type of object that can be dropped onto the target, for example a String
or a Date
object. Multiple dataFlavor
tags are allowed under a single drop target to allow the drop target to accept any of those types.
In the Insert Data Flavor dialog, enter the class for the object that can be dropped onto the target, for example java.lang.Object
.
Tip: To specify a typed array in adataFlavor tag, add brackets ([]) to the class name, for example, java.lang.Object[] . |
For dragging and dropping activities within a calendar, users can drag and drop only within a view. That is, users can drag an activity from one time slot to another in the day view, but cannot cut an activity from a day view and paste it into a month view.
When the user is dragging and dropping activities in the day or week view, the calendar marks the drop site by half-hour increments. The user cannot move any all-day or multi-day activities in the day view.
In the week view, users can move all-day and multi-day activities, however, they can be dropped only within other all-day slots. That is, the user cannot change an all-day activity to an activity with start and end times. In the month view, users can move all-day and multi-day activities to any other day.
You can configure drag and drop for the DVT bubble and scatter graphs, which allows the user to change the value of a marker by repositioning it. When you want users to be able to drag and drop in a graph, you use the dragSource
and dropTarget
tags. Additionally, you use the DataFlavor
object to determine the valid Java type of the sources for the drop target, in this case a GraphSelection object. You also must implement any required functionality in response to the drag and drop action.
For example, you might have a scatterGraph
component and you want the user to be able to drag a human scatter marker to adjust the performance rating of an employee, as shown in Figure 32-6.
The scatterGraph
component contains both a dragSource
tag and a dropTarget
tag. You also use a dataFlavor
tag to determine the type of object being dropped.
You also must implement a listener for the drop event. The object of the drop event is called the transferable
, which contains the payload of the drop. Your listener must access the transferable
object, and from there, use the DataFlavor
object to verify that the object can be dropped. You then use the drop event to get the target component and update the property with the dropped object.
To add drag and drop functionality, first add source and target tags to the graph. Then implement the event handler method that will handle the logic for the drag and drop action. For information about what happens at runtime, see Section 32.3.2, "What Happens at Runtime."
To add drag and drop functionality:
In the Component Palette, from the Operations panel, drag a Drop Target tag and drop it as a child to the graph component.
In the Insert Drop Target dialog, enter an expression that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 6).
In the Insert Data Flavor dialog, enter oracle.adf.view.faces.bi.component.graph.GraphSelection
, which is the class for the object that can be dropped onto the target. This entry will be used to create a dataFlavor
tag, which determines the type of object that can be dropped onto the target.
In the Property Inspector, set a value for Discriminant, if needed. A discriminant is an arbitrary string used to determine which source can drop on the target. For example, suppose you have two graphs that both accept an GraphSelection
object, GraphA and GraphB. You also have two sources, both of which are GraphSelection
objects. By setting a discriminant value on GraphA with a value of alpha
, only the GraphSelection
source that provides the discriminant value of alpha
will be accepted.
In the Structure window, select the dropTarget
tag. In the Property inspector, select MOVE
as the value for Actions.
In the Component Palette, from the Operations panel, drag and drop a Drag Source as a child to the graph component.
With the dragSource
tag selected, in the Property Inspector set MOVE
as the allowed Action and add any needed discriminant, as configured for the dataFlavor
tag.
In the managed bean referenced in the EL expression created in Step 2, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This method must take a DropEvent
event as a parameter and return a DnDAction
object, which is the action that will be performed when the source is dropped, in this case DnDAction.
MOVE
. This method should check the DropEvent
event to determine whether or not it will accept the drop. If the method accepts the drop, it should perform the drop and return the DnDAction
object it performed. Otherwise, it should return DnDAction.NONE
to indicate that the drop was rejected. The method must also check for the presence of the dataFlavor
object, in this case oracle.adf.view.faces.bi.component.graph.GraphSelection
.
When you want users to be able to drag and drop between Gantt charts and other components, you use the dragSource
and dropTarget
tags. Additionally, you use the DataFlavor
object to determine the valid Java types of sources for the drop target. You also must implement any required functionality in response to the drag and drop action. Both the projectGantt
and schedulingGantt
components support drag and drop functionality.
For example, suppose you have an projectGantt
component and you want the user to be able to drag one timeline to a treeTable
component and have that component display information about the timeline, as shown in Figure 32-6.
The projectGantt
component contains a dragSource
tag. And because the user will drag the whole object and not just the String
value of the output text that is displayed, you use the dropTarget
tag instead of the attributeDropTarget
tag.
You also use a dataFlavor
tag to determine the type of object being dropped. On this tag, you can define a discriminant value. This is helpful if you have two targets and two sources, all with the same object type. By creating a discriminant value, you can be sure that each target will accept only valid sources. For example, suppose you have two targets that both accept an TaskDragInfo
object, TargetA and TargetB. Suppose you also have two sources, both of which are TaskDragInfo
objects. By setting a discriminant value on TargetA with a value of alpha
, only the TaskDragInfo
source that provides the discriminant value of alpha
will be accepted.
You also must implement a listener for the drop event. The object of the drop event is called the transferable
, which contains the payload of the drop. Your listener must access the transferable
object, and from there, use the DataFlavor
object to verify that the object can be dropped. You then use the drop event to get the target component and update the property with the dropped object.
To add drag and drop functionality, first add tags to a component that define it as a target for a drag and drop action. Then implement the event handler method that will handle the logic for the drag and drop action. Last, you define the sources for the drag and drop. For information about what happens at runtime, see Section 32.3.2, "What Happens at Runtime." For information about using the clientDropListener
attribute, see Section 32.3.3, "What You May Need to Know About Using the ClientDropListener."
To add drag and drop functionality:
In the Component Palette, from the Operations panel, drag a Drop Target tag and drop it as a child to the target component.
In the Insert Drop Target dialog, enter an expression that evaluates to a method on a managed bean that will handle the event (you will create this code in Step 6).
Tip: You can also intercept the drop on the client by populating theclientDropListener attribute. For more information, see Section 32.3.3, "What You May Need to Know About Using the ClientDropListener". |
In the Insert Data Flavor dialog, enter the class for the object that can be dropped onto the target, for example java.lang.Object
. This selection will be used to create a dataFlavor
tag, which determines the type of object that can be dropped onto the target. Multiple dataFlavor
tags are allowed under a single drop target to allow the drop target to accept any of those types.
Tip: To specify a typed array in aDataFlavor tag, add brackets ([]) to the class name, for example, java.lang.Object[] . |
In the Property Inspector, set a value for Discriminant, if needed. A discriminant is an arbitrary string used to determine what sources of the type specified by the dataFlavor will be allowed as a source.
In the Structure window, select the dropTarget
tag. In the Property inspector, select a value for Actions. This defines what actions are supported by the drop target. Valid values can be COPY
(copy and paste), MOVE
(cut and paste), and LINK
(copy and paste as a link), for example:.
MOVE COPY
If no actions are specified, the default is COPY
.
Example 32-10 shows the code for a dropTarget
component that takes a TaskDragInfo
object as a drop source. Note that because COPY was set as the value for the actions
attribute, that will be the only allowed action.
Example 32-10 JSP Code for a dropTarget tag
<af:treeTable id="treeTableDropTarget" var="task" value="#{projectGanttDragSource.treeTableModel}"> <f:facet name="nodeStamp"> <af:column headerText="Task Name"> <af:outputText value="#{task.taskName}"/> </af:column> </f:facet> <af:column headerText="Resource"> <af:outputText value="#{task.resourceName}"/> </af:column> <af:column headerText="Start Date"> <af:outputText value="#{task.startTime}"/> </af:column> <af:column headerText="End Date"> <af:outputText value="#{task.endTime}"/> </af:column> <af:dropTarget actions="COPY" dropListener="#{projectGanttDragSource.onTableDrop}"> <af:dataFlavor flavorClass= "oracle.adf.view.faces.bi.component.gantt.TaskDragInfo"/> </af:dropTarget> </af:treeTable>
In the managed bean referenced in the EL expression created in Step 2, create the event handler method (using the same name as in the EL expression) that will handle the drag and drop functionality.
This method must take a DropEvent
event as a parameter and return a DnDAction
object, which is the action that will be performed when the source is dropped. Valid return values are DnDAction.COPY
, DnDAction.
MOVE
, and DnDAction.LINK
, and were set when you defined the target attribute in Step 5. This method should check the DropEvent
event to determine whether or not it will accept the drop. If the method accepts the drop, it should perform the drop and return the DnDAction
object it performed. Otherwise, it should return DnDAction.NONE
to indicate that the drop was rejected.
The method must also check for the presence for each dataFlavor
object in preference order.
Tip: If your target has more than one defineddataFlavor object, then you can use the Transferable.getSuitableTransferData() method, which returns a List of TransferData objects available in the Transferable object in order, from highest suitability to lowest. |
The DataFlavor
object defines the type of data being dropped, for example java.lang.Object
, and must be as defined in the DataFlavor
tag on the JSP, as created in Step 3.
Tip: To specify a typed array in aDataFlavor object, add brackets ([]) to the class name, for example, java.lang.Object[].
If the drag and drop framework doesn't know how to represent a server |
Example 32-11 shows a handler method that copies a TaskDragInfo
object from the event payload and assigns it to the component that initiated the event.
Example 32-11 Event Handler Code for a dropListener
public DnDAction onTableDrop(DropEvent evt) { // retrieve the information about the task dragged DataFlavor<TaskDragInfo> _flv = DataFlavor.getDataFlavor(TaskDragInfo.class, null); Transferable _transferable = evt.getTransferable(); // if there is no data in the transferable, then the drop is unsuccessful TaskDragInfo _info = _transferable.getData(_flv); if (_info == null) return DnDAction.NONE; // find the task Task _draggedTask = findTask(_info.getTaskId()); if (_draggedTask != null) { // process the dragged task here and indicate the drop is successful by returning DnDAction.COPY return DnDAction.COPY; } else return DnDAction.NONE; }
In the Component Palette, from the Operations panel, drag and drop a Drag Source as a child to the source component.
With the dragSource
tag selected, in the Property Inspector set the allowed Actions and any needed discriminant, as configured for the target.