Перетаскивание между таблицами в HorizontalLayout не работает

#java #drag-and-drop #vaadin

#java #перетаскивание #vaadin

Вопрос:

У меня есть 3 таблицы в Vaadin:

3 Таблицы в горизонтальном макете

Моя проблема сейчас в том, что перетаскивание не работает. Мой код следующий:

 @Theme("valo")
@SpringView(name = TaskboardView.VIEW_NAME)
public class TaskboardView extends VerticalLayout implements View {

private enum TableType {
    DONE, PROGRESS, OPEN;
}

private static final long serialVersionUID = 1L;
private final Logger logger = LoggerFactory.getLogger(TaskboardView.class);
public static final String VIEW_NAME = "taskboard";

// Components:
private SprintController sprintController = new SprintController();
private TaskController taskController = new TaskController();
private Sprint sprint;
private Set<Task> allTasks;
private List<Task> openTasks = new ArrayList<Task>();
private List<Task> inProgressTasks = new ArrayList<Task>();
private List<Task> doneTasks = new ArrayList<Task>();

// UI Components:
private Table openTable = new Table("Open Tasks:");
private int openTableId = 1;
private Table inProgressTable = new Table("Tasks in Progress");
private int inProgressTableId = 1;
private Table doneTable = new Table("Done Tasks");
private int doneTableId = 1;
private TextField sprintName = new TextField();
private OpenTableDropHandler openTableDropHandler = new OpenTableDropHandler();
private InProgressTableDropHandler inProgressTableDropHandler = new InProgressTableDropHandler();
DoneTableHandler doneTableHandler = new DoneTableHandler();

@PostConstruct
void init() {
    logger.info("Initializing Taskboard View...");
    try {
        this.sprint = sprintController.getActiveSprint();
        this.allTasks = sprintController.getTasksInSprint(this.sprint.getId().intValue());
        sortSprintTasks(this.allTasks);
        this.sprintName.setNullRepresentation("-- No active Sprint found --");
        this.sprintName.setValue(this.sprint.getSprintName());
        this.sprintName.setWidth("800px");
        this.sprintName.setReadOnly(true);
        this.sprintName.addStyleName("align-center"); // sets Allignment of
                                                        // the textfield!!!

    } catch (NoActiveSprintReceivedException | NoSprintsExistException | IOException e) {
        logger.error("Something went wrong initializing active Sprint. The taskboard can't be displayed.", e);
        Notification.show("No Active Sprint found!", Notification.Type.ERROR_MESSAGE);
        e.printStackTrace();
        return;
    } catch (TaskCanNotBeAllocatedException e) {
        logger.error("Task of sprint couldn't be allocated to an status.", e);
        Notification.show("Error! n n Task of sprint couldn't be allocated to an status.",
                Notification.Type.ERROR_MESSAGE);
        e.printStackTrace();
        return;
    }
    // Layout for Sprint Name:
    VerticalLayout headLayout = new VerticalLayout();
    headLayout.setSpacing(true);
    headLayout.setSizeFull();
    ;
    headLayout.setMargin(true);
    headLayout.addComponent(this.sprintName);
    headLayout.setComponentAlignment(this.sprintName, Alignment.MIDDLE_CENTER);

    setSizeFull();
    setSpacing(true);
    setMargin(true);
    // Layout:
    VerticalLayout verticalLayout = new VerticalLayout();
    verticalLayout.setSpacing(true);

    // Layout for Board:
    HorizontalLayout taskBoardLayout = new HorizontalLayout();
    taskBoardLayout.setSizeUndefined();
    taskBoardLayout.setSpacing(true);
    taskBoardLayout.setMargin(true);

    // Adding to HorizontalLayout(TaskBoadLayout)
    try {
        initTable(this.openTable, TableType.OPEN);
        initTable(this.inProgressTable, TableType.PROGRESS);
        initTable(this.doneTable, TableType.DONE);
    } catch (IOException e) {
        logger.error("Something went wrong initizalizing Tables.");
        Notification.show("Error! n n Couldn't initialize tables.", Notification.Type.ERROR_MESSAGE);
        return;
    }

    taskBoardLayout.addComponent(openTable);
    taskBoardLayout.addComponent(inProgressTable);
    taskBoardLayout.addComponent(doneTable);

    // Adding to VerticalLayout (MainLayout)
    verticalLayout.addComponent(headLayout);
    verticalLayout.addComponent(taskBoardLayout);
    verticalLayout.setComponentAlignment(taskBoardLayout, Alignment.MIDDLE_CENTER);
    addComponent(verticalLayout);
}

/**
 * Sorts the tasks of the sprint to the required lists like open, in
 * Progress, done.
 *
 * @param tasks
 * @throws TaskCanNotBeAllocatedException
 */
private void sortSprintTasks(Set<Task> tasks) throws TaskCanNotBeAllocatedException {
    logger.info("sortSprintTask(Set<Task>tasks): Sorting Tasks to the required lists...");
    for (Task t : tasks) {
        logger.info("Checking Sprint Status of Task >>>> "   t.getHeadLine()   " <<<<");
        logger.info("Status: "   t.getStatus());
        if (t.getStatus().equals(WorkflowStatusConfigurator.open)) {
            this.openTasks.add(t);
        } else if (t.getStatus().equals(WorkflowStatusConfigurator.inProgress)) {
            this.inProgressTasks.add(t);
        } else if (t.getStatus().equals(WorkflowStatusConfigurator.done)) {
            this.doneTasks.add(t);
        } else {
            throw new TaskCanNotBeAllocatedException(
                    "Task can't be allocated to a sprint status: "   WorkflowStatusConfigurator.open   ", "
                              WorkflowStatusConfigurator.inProgress   ", "   WorkflowStatusConfigurator.done   ".");
        }

    }
}

@Override
public void enter(ViewChangeEvent event) {
    // TODO Auto-generated method stub

}

/**
 * Creates the tables depending on the type parameter
 *
 * @param table
 * @param type
 * @throws IOException
 * @throws ClientProtocolException
 */
private void initTable(Table table, TableType type) throws ClientProtocolException, IOException {
    table.setSelectable(true);
    table.setImmediate(true);
    table.setDragMode(TableDragMode.ROW);
    table.addContainerProperty("ID", Long.class, null);
    table.setColumnWidth("ID", 50);
    table.addContainerProperty("Headline", String.class, null);
    table.setColumnWidth("Headline", 300);
    table.addContainerProperty("Task-Type", String.class, null);
    table.setColumnWidth("Task-Type", 120);
    table.addContainerProperty("Assignee", String.class, null);
    table.setColumnWidth("Assignee", 100);

    if (type.equals(TableType.OPEN) amp;amp; this.openTasks.size() > 0) {
        logger.info("Loading values of Open Tasks Table...");
        table.setDropHandler(this.openTableDropHandler);
        for (Task t : this.openTasks) {
            String assignee = this.taskController.getAssigneeInTask(t.getId().intValue()).getUserName();
            table.addItem(new Object[] { t.getId(), t.getHeadLine(), t.getTaskType(), assignee }, this.openTableId);
            this.openTableId  ;
        }
        return;

    }

    if (type.equals(TableType.PROGRESS) amp;amp; this.inProgressTasks.size() > 0) {
        logger.info("Loading values of Progress Tasks Table...");
        table.setDropHandler(this.inProgressTableDropHandler);
        for (Task t : this.inProgressTasks) {
            String assignee = this.taskController.getAssigneeInTask(t.getId().intValue()).getUserName();
            table.addItem(new Object[] { t.getId(), t.getHeadLine(), t.getTaskType(), assignee }, this.inProgressTableId);
            this.inProgressTableId  ;
        }
        return;
    }

    if (type.equals(TableType.DONE) amp;amp; this.doneTasks.size() > 0) {
        logger.info("Loading values of Done Tasks Table...");
        table.setDropHandler(this.doneTableHandler);
        for (Task t : this.doneTasks) {
            String assignee = this.taskController.getAssigneeInTask(t.getId().intValue()).getUserName();
            table.addItem(new Object[] { t.getId(), t.getHeadLine(), t.getTaskType(), assignee }, this.doneTableId);
            this.doneTableId  ;
        }
        return;
    }
}

private int giveEncreasedAvailableTableId(TableType tableType) {
    if(tableType.equals(TableType.OPEN)){
        this.openTableId  ;
        return this.openTableId;
    }else if(tableType.equals(TableType.PROGRESS)){
        this.inProgressTableId  ;
        return this.inProgressTableId;
    }else if(tableType.equals(TableType.DONE)){
        this.doneTableId  ;
        return this.doneTableId;
    }else{
        return -1;
    }

}

private class OpenTableDropHandler implements DropHandler{

    private static final long serialVersionUID = 1L;
    private final Logger logger = LoggerFactory.getLogger(OpenTableDropHandler.class);

    @Override
    public void drop(DragAndDropEvent event) {
        // Wrapper for the object that is dragged
        logger.info("Received Drag and Drop Event from OpenTable...");
        DataBoundTransferable t = (DataBoundTransferable) event.getTransferable();
         AbstractSelectTargetDetails dropData = ((AbstractSelectTargetDetails) event.getTargetDetails());
        Object itemId = t.getItemId();
        Long id = (Long) t.getSourceContainer().getItem(itemId).getItemProperty("ID").getValue();
        try {
            Task taskToAdd = taskController.getById(id.intValue());
            String author = taskController.getAuthorInTask(taskToAdd.getId().intValue()).getUserName();
            if ( t.getSourceComponent() != openTable amp;amp; dropData.getTarget().equals(inProgressTable)) {
                logger.info("Preparing Task Update to InProgress...");
                openTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.OPEN));
                openTasks.add(taskToAdd);
                inProgressTable.removeItem(itemId);
                inProgressTasks.remove(taskToAdd);
            }else if(t.getSourceComponent() != openTable amp;amp; dropData.getTarget().equals(doneTable)){
                logger.info("Preparing Task Update to Done...");
                openTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.OPEN));
                openTasks.add(taskToAdd);
                doneTable.removeItem(itemId);
                doneTasks.remove(taskToAdd);
            }else{
                logger.info("Do nothing...");
                return;
            }
            taskToAdd.setStatus(WorkflowStatusConfigurator.open);
            logger.info("Sending updates of taskboard to webservice...");
            HttpResponse response = taskController.put(taskToAdd, taskToAdd.getId().intValue());
            MainView.navigator.navigateTo(TaskboardView.VIEW_NAME);
   //               HttpResponse authorResponse =      taskController.setAuthorInTask(taskToAdd.getAuthor().getId().intValue(),
 //                     taskToAdd.getId().intValue());
    //              HttpResponse assigneeResponse =    taskController.setAssigneeInTask(taskToAdd.getAssignee().getId().intValue(),
 //                     taskToAdd.getId().intValue());

        } catch (ClientProtocolException e) {

            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        } catch (IOException e) {
            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        }

    }

    @Override
    public AcceptCriterion getAcceptCriterion() {
        return AcceptAll.get();
    }

}

private class InProgressTableDropHandler implements DropHandler{


    private static final long serialVersionUID = 1L;
    private final Logger logger = LoggerFactory.getLogger(InProgressTableDropHandler.class);

    @Override
    public void drop(DragAndDropEvent event) {
        // Wrapper for the object that is dragged
        logger.info("Received Drag and Drop Event from In Progress Table.");
        DataBoundTransferable t = (DataBoundTransferable) event.getTransferable();
        AbstractSelectTargetDetails dropData = ((AbstractSelectTargetDetails) event.getTargetDetails());
        Object itemId = t.getItemId();
        Long id = (Long) t.getSourceContainer().getItem(itemId).getItemProperty("ID").getValue();


        try {
            Task taskToAdd = taskController.getById(id.intValue());
            String author = taskController.getAuthorInTask(taskToAdd.getId().intValue()).getUserName();
            if (t.getSourceComponent() != inProgressTable amp;amp; dropData.getTarget().equals(doneTable) ){
                inProgressTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.PROGRESS));
                doneTable.removeItem(itemId);
                inProgressTasks.add(taskToAdd);
                doneTasks.remove(taskToAdd);
            }else if(t.getSourceComponent() != inProgressTable amp;amp; dropData.getTarget().equals(openTable)){
                inProgressTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.PROGRESS));
                openTable.removeItem(itemId);
                inProgressTasks.add(taskToAdd);
                openTasks.remove(taskToAdd);
            }else{
                return;
            }
            logger.info("Sending updates of taskboard to webservice...");
            taskToAdd.setStatus(WorkflowStatusConfigurator.inProgress);
                HttpResponse response = taskController.put(taskToAdd, taskToAdd.getId().intValue());
            MainView.navigator.navigateTo(TaskboardView.VIEW_NAME);
        }catch (ClientProtocolException e) {
            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        } catch (IOException e) {
            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        }

    }

    @Override
    public AcceptCriterion getAcceptCriterion() {
        return AcceptAll.get();
    }

}

private class DoneTableHandler implements DropHandler{


    private static final long serialVersionUID = 1L;
    private final Logger logger = LoggerFactory.getLogger(DoneTableHandler.class);

    @Override
    public void drop(DragAndDropEvent event) {
        logger.info("Received Drag and Drop Event from In Done Table.");
        DataBoundTransferable t = (DataBoundTransferable) event.getTransferable();
        AbstractSelectTargetDetails dropData = ((AbstractSelectTargetDetails) event.getTargetDetails());
        Object itemId = t.getItemId();
        Long id = (Long) t.getSourceContainer().getItem(itemId).getItemProperty("ID").getValue();
        try {
            Task taskToAdd = taskController.getById(id.intValue());
            String author = taskController.getAuthorInTask(taskToAdd.getId().intValue()).getUserName();
            if (t.getSourceComponent() != doneTable amp;amp; dropData.getTarget().equals(inProgressTable) ){
                doneTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.DONE));
                inProgressTable.removeItem(itemId);
                doneTasks.add(taskToAdd);
                inProgressTasks.remove(taskToAdd);
            }else if(t.getSourceComponent() != doneTable amp;amp; dropData.getTarget().equals(openTable)){
                doneTable.addItem(new Object[] { taskToAdd.getId(), taskToAdd.getHeadLine(),
                        taskToAdd.getTaskType(), author, taskToAdd.getStatus() }, giveEncreasedAvailableTableId(TableType.DONE));
                openTable.removeItem(itemId);
                doneTasks.add(taskToAdd);
                openTasks.remove(taskToAdd);
            }else{
                return;
            }
            logger.info("Sending updates of taskboard to webservice...");
            taskToAdd.setStatus(WorkflowStatusConfigurator.done);
            HttpResponse response = taskController.put(taskToAdd, taskToAdd.getId().intValue());
            MainView.navigator.navigateTo(TaskboardView.VIEW_NAME);
        }catch (ClientProtocolException e) {
            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        } catch (IOException e) {
            logger.warn("Something went wrong during Drag and Drop Process", e.getCause());
        }

    }

    @Override
    public AcceptCriterion getAcceptCriterion() {
        return AcceptAll.get();
    }

 }

}
 

Есть ли у кого-нибудь идеи или хотя бы подсказки, почему это не работает? Я написал код, следуя тому же шаблону или способу, и он работал нормально. Единственное отличие в том, что там я не использую горизонтальную компоновку. И теперь таблица in Progress и Done не реагирует на перетаскивание строки на них.

Комментарии:

1. Я только что попробовал простой пример, похожий на ваш, и он отлично работает с Vaadin 7.7.3. Я предполагаю, что вы отфильтровываете удаленные данные в своих обработчиках в else {return}; ветвях. Глядя на DoneTableHandler это, я вижу `if (t.getSourceComponent() != doneTable amp;amp; dropData.getTarget().equals(inProgressTable) ){` что, я думаю, не совсем правильно. Обработчик удаления должен обрабатывать данные, удаленные из этого компонента, поэтому источником, вероятно, должны быть таблицы open или in progress , а целевой таблицей done .

Ответ №1:

Не по теме: почему у вас есть @Theme("valo") представление? Насколько я знаю, это используется с UI классом…


По теме:

Как я уже говорил в своем комментарии, я не думаю, что это связано HorizontalLayout с. Возможно, вы неправильно поняли концепции перетаскивания источника и цели, или это просто проскользнуло в коде.

Как это также описано в документах, перетаскивание начинается с источника, а событие удаления данных на целевой объект обрабатывается a DropHandler . Например, если вы посмотрите на свои исходные DoneTableHandler тексты, вы увидите

 if (t.getSourceComponent() != doneTable amp;amp; dropData.getTarget().equals(inProgressTable) ){
    ...
}else if(t.getSourceComponent() != doneTable amp;amp; dropData.getTarget().equals(openTable)){
    ...
}else{
    return;
}
 

Поскольку вы прослушиваете drops на своем doneTable , это будет target , а источниками может быть только openTable or inProgressTable , а не наоборот. У меня есть подозрение, что если вы собираетесь добавить строку журнала в else ветку, вы увидите ее при каждом перетаскивании.


Ниже вы можете увидеть рабочий образец в Vaadin 7.7.3 с таблицами a HorizontalLayout и 3, похожими на ваши. Это быстро и грязно, поэтому есть возможности для улучшения (предложения приветствуются), но (например: положение отброшенных элементов), он поддерживает многорядное перетаскивание, а также AcceptCriterion фильтры удаляются из исходной таблицы или любого другого компонента, отличного от ожидаемых:

 public class DragAndDropTables extends HorizontalLayout {

    public DragAndDropTables() {
        // leave some space between the tables
        setSpacing(true);

        // tables
        Table toDoTable = createTable("To do");
        Table inProgressTable = createTable("In progress");
        Table doneTable = createTable("Done");

        // drop handlers which allow only drops from expected sources
        configureDragAndDrop(toDoTable, inProgressTable, doneTable);
        configureDragAndDrop(inProgressTable, toDoTable, doneTable);
        configureDragAndDrop(doneTable, toDoTable, inProgressTable);

        // some table to make sure AcceptCriterion allows drops only from expected sources
        Table tableNotAcceptableForDrops = createTable("Drops from here will not be accepted");
        configureDragAndDrop(tableNotAcceptableForDrops);
        tableNotAcceptableForDrops.addItem(new Task(100, "Not droppable task"));

        // add some dummy data
        for (int i = 0; i < 10; i  ) {
            toDoTable.addItem(new Task(i, "Task "   i));
        }

        // add the tables to the UI
        addComponent(toDoTable);
        addComponent(inProgressTable);
        addComponent(doneTable);
        addComponent(tableNotAcceptableForDrops);
    }

    private Table createTable(String caption) {
        // basic table setup
        Table table = new Table(caption);
        BeanItemContainer<Task> itemContainer = new BeanItemContainer<>(Task.class);
        table.setContainerDataSource(itemContainer);
        table.setMultiSelect(true);
        table.setSelectable(true);
        table.setPageLength(10);
        return table;
    }

    private void configureDragAndDrop(Table table, Table... acceptedSources) {
        // drag amp; drop configuration
        table.setDragMode(Table.TableDragMode.MULTIROW);
        table.setDropHandler(new DropHandler() {
            @Override
            public void drop(DragAndDropEvent event) {
                // where the items are dragged from
                Table source = (Table) event.getTransferable().getSourceComponent();

                // where the items are dragged to
                Table target = (Table) event.getTargetDetails().getTarget();

                // unique collection of dragged tasks
                HashSet<Task> draggedTasks = new HashSet<>();

                // https://vaadin.com/api/com/vaadin/ui/Table.TableDragMode.html
                // even in MULTIROW drag mode, the event contains only the row on which the drag started
                draggedTasks.add((Task) event.getTransferable().getData("itemId"));

                // we'll get the rest, if any, from the source table selection value
                draggedTasks.addAll((Collection<Task>) source.getValue());

                // remove items from source table
                draggedTasks.forEach(((Table) source)::removeItem);

                // add items to destination table
                target.addItems(draggedTasks);
            }

            @Override
            public AcceptCriterion getAcceptCriterion() {
                // accept drops only from specified tables, and prevent drops from the source table
                return new SourceIs(acceptedSources);
            }
        });
    }


    // basic bean for easy binding
    public static class Task {
        private String name;
        private int id;

        public Task(int id, String name) {
            this.name = name;
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }
    }
}
 

Результат:

Перетаскивание таблицы Vaadin