четверг, 17 декабря 2015 г.

Использование Drag and Drop функциональности в ADF(Using Drag and Drop in ADF)

ADF Faces framework поддерживает возможность перетаскивания элементов на странице из одного места, в другое. Например перенос строки из одной таблицы в другую, перемещение компонентов на странице или копирование значений из одних объектов в другой.

ADF Faces поддерживает следующие сценарии:
  • Перемещение  значения атрибута из одного экземпляра компонента и копирование в другой. Например, пользователь может перенести данные из outputText в inputText .
  • Перемещение значения одного объекта в другой объект так, что он становится значением другого объекта.
  • Перемещение объекта из одной коллекции в другую.
  • Перемещение компонента из одной части страницы в другую.
  • Перемещения в компоненте calendar
  • Перемещения компонента  из или в  panelDashboard .
  • Перемещения маркера в DVT графиках для изменения значений.
  • Перемещение объекта из диаграммы Gantt в другой компонент.
  • Прочие перемещения в DVT

Когда пользователь нажимает на источник и начинает перемещение, браузер отображает прозрачным перетаскиваемый компонент прикрепленный к указателю мышки.

Компонент который перемещается и содержит значение называется источником(source). Компонент который принимает перемещаемый компонент, называется целью (target).Для источника и цели нужно использовать определенные тэги ( attributeDragSource, dragSource, componentDragSource,attributeDropTarget,dropTarget,collectionDropTarget,calendarDropTarget,dataFlavor) Ниже показаны возможные сценарии использования Drag and Drop в ADF

Сценарий
Источник(Source)
Цель(Target)
Перемещение значение атрибута
Компонент со значением(с атрибутом value)
Тип атрибута  должен соответствовать переносимому значению
Тэг:
attributeDragSource
         Тэг:
attributeDropTarget
Перемещение объекта из одного компонента в другой
Любой компонент
Любой компонент
Тэг:
attributeDragSource
Тэг:
dropTarget
Перемещение объекта из одной коллекции в другую
tabletree,  и treeTable компоненты
tabletree, and treeTable компоненты
Тэг:
dragSource
Тэг:
collectionDropTarget
Перемещение компонента из одного контейнера в другой
Любой компонент
Любой компонент
Тэг:
componentDragSource
Тэг:
dropTarget
Перемещение дат в календаре
объект calendarActivity 
компоненты calendar 
Тэг:
не нужен
Тэг:
calendarDropTarget
Перемещение  panelBox вpanelDashboard
компонент panelBox
компонент panelDashboard
Тэг:
componentDragSource
Тэг:
dataFlavor
Перемещение  panelBox из panelDashboard
компонент panelBox в  panelDashboard компоненте
Любой компонент
Тэг:
componentDragSource
Тэг:
dropTarget
Перемещение маркера в DVT graph
компонент graph 
компоненты graph 
Тэг:
dragSource
Тэг:
dropTarget
Перемещение объекта из DVT Gantt chart  в другой компонент
Gantt chart
Любой компонент
Тэг:
dragSource
Тэг:
dropTarget
Перемещение узла (ноды) из DVT hierarchy viewer, sunburst, или  treemap в другой компонент
hierarchyViewersunburst, или treemap компонент
Любой компонент
Тэг:
dragSource
Тэг:
dropTarget
Перемещение события из timeline компонента  в  компоненты и с коллекциями.
timeline компоненты
tabletree, и treeTable компоненты
Тэг:
dragSource
Тэг:
collectionDropTarget

Для наилучшего понимания drag and drop функциональности создадим приложение с двумя таблицами. И добавим возможность перемещения строк из одной в другую  (исходники можно скачать на github: https://github.com/JealousyM/AdfDnd).

1. Создайте  ADF Fusion Web Application;

2. Создайте jspx страницу (для вывода таблиц);

3. Создайте managed  bean (для инициализации таблиц и обработки drag and drop события);

4. Добавьте в jspx страницу две таблицы(af:table). Что бы упростить приложение, данные будем брать не с БД, а формировать в бине. 


 <af:panelGroupLayout id="pgl2" layout="horizontal" styleClass="AFStretchWidth">
<af:table var="row" rowBandingInterval="0" id="t1"
                                          value="#{viewScope.dndBean.sourceTable}" rowSelection="single">
                                    <af:column sortable="false" headerText="Source" id="c2">
                                        <af:outputText value="#{row.col}" id="ot1"/>
                                    </af:column>
                                </af:table>
                                <af:table var="row" rowBandingInterval="0" id="t2" value="#{viewScope.dndBean.targetTable}"
                                          rowSelection="single">
                                    <af:column sortable="false" headerText="Target" id="c1">
                                        <af:outputText value="#{row.col}" id="ot2"/>
                                    </af:column>
                                </af:table>
                            </af:panelGroupLayout>

5.  В bean создайте  две переменных типа  List<Digit> (Digit внутренний класс в  бине, для вывода данных в  таблице)  и заполните их данными:


   
    private List<Digit> sourceTable;
    private List<Digit> targetTable;
    public DndBean() {
    }
    
    public List<Digit> getSourceTable()
       {
           if (sourceTable == null)
           {
               sourceTable = new ArrayList<Digit>();
               sourceTable.add(new Digit(11));
               sourceTable.add(new Digit(12));
               sourceTable.add(new Digit(13));
               sourceTable.add(new Digit(14));
           }

           return sourceTable;
       }
    
    public List<Digit> getTargetTable()
       {
           if (targetTable == null)
           {
               targetTable = new ArrayList<Digit>();
               targetTable.add(new Digit(15));
               targetTable.add(new Digit(16));
               targetTable.add(new Digit(17));
               targetTable.add(new Digit(18));
           }

           return targetTable;
       }

    public static class Digit implements Serializable
        {
            private Number digitCol;

            private Digit(Number title)
            {
                digitCol = title;
            }

            public Number getCol()
            {
                return digitCol;
            }
            
        }
    

Если запустить приложение, то можно увидеть что таблицы заполнены. Теперь нужно добавить к ним  drag and drop функциональность . Исходя из верхней таблицы нам нужно использовать тэги  dragSource и collectionDropTarget.

6. Добавьте внутрь первой таблицы тэг  dragSource (эта таблица у нас будет Источником) , и collectionDropTarget во вторую (эта таблица у нас будет Целью).
Этого мало, что бы всё заработало. Дальше нужно прописать необходимые атрибуты в тэгах и написать обработчик события.

7. В dragSource   пропишите следующие свойства:

<af:dragSource actions="MOVE" discriminant="rowmove"/>

где actions - действия которые могут выполняться (move,copy,link). У нас будет перемещаться строка, а значит move. То есть в обоих тэгах нужно добавить actions="MOVE".
      discriminant значение для идентификации источникаВы можете написать произвольное значение

8. При добавлении collectionDropTarget через Components window, вам будет предложено создать dropListener (слушатель для событий target-а), создайте его. Так же пропишите свойства actions и modelname( значение discriminant из источника)


<af:collectionDropTarget dropListener="#{viewScope.dndBean.handleMove}"
actions="MOVE" modelName="rowmove"/>



9. Завершающим этапом является написание обработки события:


public DnDAction handleMove(DropEvent dropEvent) {

    //получение источника
    RichTable dragComponent = (RichTable) dropEvent.getDragComponent();
    //получение цели
    RichTable dropComponent = (RichTable) dropEvent.getDropComponent();

    Transferable t = dropEvent.getTransferable();
    DataFlavor<RowKeySet> df =
    DataFlavor.getDataFlavor(RowKeySet.class, "rowmove");
    RowKeySet rks = t.getData(df);
    Iterator iter = rks.iterator();

    //получение выбранной строки в источнике 
    Digit dragRow = (Digit)  dragComponent.getSelectedRowData();
    Digit dropRow = null;

    //получение выбранной строки в цели
    if (iter.hasNext()) {
    Integer key = (Integer)iter.next();
    dropComponent.setRowKey(key);
    dropRow =(Digit)dropComponent.getRowData();

    //удаление строки из источника и добавление её в Цель
    getTargetTable().add(getTargetTable().indexOf(dropRow), dragRow); 
    getSourceTable().remove(dragRow); 
      }

    // обновление таблиц 
    AdfFacesContext.getCurrentInstance().addPartialTarget(dragComponent);
    AdfFacesContext.getCurrentInstance().addPartialTarget(dropComponent);

    return DnDAction.MOVE;
}


       
        
Готово : )





Более детально о Drag and Drop в ADF можно прочитать здесь:  https://docs.oracle.com/middleware/1212/adf/ADFUI/af_dnd.htm