com.esofthead.mycollab.module.project.view.task.TaskKanbanBoardViewImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.esofthead.mycollab.module.project.view.task.TaskKanbanBoardViewImpl.java

Source

/**
 * This file is part of mycollab-web.
 *
 * mycollab-web is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * mycollab-web is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with mycollab-web.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.esofthead.mycollab.module.project.view.task;

import com.esofthead.mycollab.common.domain.OptionVal;
import com.esofthead.mycollab.common.i18n.GenericI18Enum;
import com.esofthead.mycollab.common.i18n.OptionI18nEnum.StatusI18nEnum;
import com.esofthead.mycollab.common.service.OptionValService;
import com.esofthead.mycollab.core.arguments.BasicSearchRequest;
import com.esofthead.mycollab.core.arguments.NumberSearchField;
import com.esofthead.mycollab.core.arguments.SearchCriteria;
import com.esofthead.mycollab.core.utils.StringUtils;
import com.esofthead.mycollab.eventmanager.ApplicationEventListener;
import com.esofthead.mycollab.eventmanager.EventBusFactory;
import com.esofthead.mycollab.module.project.CurrentProjectVariables;
import com.esofthead.mycollab.module.project.ProjectRolePermissionCollections;
import com.esofthead.mycollab.module.project.ProjectTypeConstants;
import com.esofthead.mycollab.module.project.domain.SimpleTask;
import com.esofthead.mycollab.module.project.domain.criteria.TaskSearchCriteria;
import com.esofthead.mycollab.module.project.events.TaskEvent;
import com.esofthead.mycollab.module.project.i18n.TaskI18nEnum;
import com.esofthead.mycollab.module.project.service.ProjectTaskService;
import com.esofthead.mycollab.module.project.view.ProjectView;
import com.esofthead.mycollab.module.project.view.kanban.AddNewColumnWindow;
import com.esofthead.mycollab.module.project.view.kanban.DeleteColumnWindow;
import com.esofthead.mycollab.module.project.view.task.components.TaskSavedFilterComboBox;
import com.esofthead.mycollab.module.project.view.task.components.TaskSearchPanel;
import com.esofthead.mycollab.module.project.view.task.components.ToggleTaskSummaryField;
import com.esofthead.mycollab.spring.AppContextUtil;
import com.esofthead.mycollab.vaadin.AppContext;
import com.esofthead.mycollab.vaadin.AsyncInvoker;
import com.esofthead.mycollab.vaadin.events.HasSearchHandlers;
import com.esofthead.mycollab.vaadin.mvp.AbstractPageView;
import com.esofthead.mycollab.vaadin.mvp.ViewComponent;
import com.esofthead.mycollab.vaadin.mvp.ViewManager;
import com.esofthead.mycollab.vaadin.ui.ELabel;
import com.esofthead.mycollab.vaadin.ui.NotificationUtil;
import com.esofthead.mycollab.vaadin.ui.UIUtils;
import com.esofthead.mycollab.vaadin.web.ui.ConfirmDialogExt;
import com.esofthead.mycollab.vaadin.web.ui.OptionPopupContent;
import com.esofthead.mycollab.vaadin.web.ui.ToggleButtonGroup;
import com.esofthead.mycollab.vaadin.web.ui.UIConstants;
import com.esofthead.mycollab.vaadin.web.ui.grid.GridFormLayoutHelper;
import com.google.common.eventbus.Subscribe;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.event.dd.acceptcriteria.Not;
import com.vaadin.server.FontAwesome;
import com.vaadin.shared.ui.MarginInfo;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.shared.ui.dd.HorizontalDropLocation;
import com.vaadin.shared.ui.dd.VerticalDropLocation;
import com.vaadin.ui.*;
import com.vaadin.ui.components.colorpicker.ColorChangeEvent;
import com.vaadin.ui.components.colorpicker.ColorChangeListener;
import com.vaadin.ui.components.colorpicker.ColorPickerPopup;
import fi.jasoft.dragdroplayouts.DDHorizontalLayout;
import fi.jasoft.dragdroplayouts.DDVerticalLayout;
import fi.jasoft.dragdroplayouts.client.ui.LayoutDragMode;
import fi.jasoft.dragdroplayouts.events.LayoutBoundTransferable;
import fi.jasoft.dragdroplayouts.events.VerticalLocationIs;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vaadin.dialogs.ConfirmDialog;
import org.vaadin.hene.popupbutton.PopupButton;
import org.vaadin.jouni.restrain.Restrain;
import org.vaadin.viritin.layouts.MHorizontalLayout;
import org.vaadin.viritin.layouts.MVerticalLayout;
import org.vaadin.viritin.layouts.MWindow;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MyCollab Ltd
 * @since 5.1.1
 */
@ViewComponent
public class TaskKanbanBoardViewImpl extends AbstractPageView implements TaskKanbanBoardView {
    private static Logger LOG = LoggerFactory.getLogger(TaskKanbanBoardViewImpl.class);

    private ProjectTaskService taskService = AppContextUtil.getSpringBean(ProjectTaskService.class);
    private OptionValService optionValService = AppContextUtil.getSpringBean(OptionValService.class);

    private TaskSearchPanel searchPanel;
    private DDHorizontalLayout kanbanLayout;
    private Map<String, KanbanBlock> kanbanBlocks;
    private ComponentContainer newTaskComp = null;
    private Button toggleShowColumsBtn;
    private boolean displayHiddenColumns = false;
    private TaskSearchCriteria baseCriteria;

    private ApplicationEventListener<TaskEvent.SearchRequest> searchHandler = new ApplicationEventListener<TaskEvent.SearchRequest>() {
        @Override
        @Subscribe
        public void handle(TaskEvent.SearchRequest event) {
            TaskSearchCriteria criteria = (TaskSearchCriteria) event.getData();
            if (criteria != null) {
                criteria.setProjectId(new NumberSearchField(CurrentProjectVariables.getProjectId()));
                criteria.setOrderFields(
                        Collections.singletonList(new SearchCriteria.OrderField("taskindex", SearchCriteria.ASC)));
                queryTask(criteria);
            }
        }
    };

    public TaskKanbanBoardViewImpl() {
        this.setSizeFull();
        this.withSpacing(true).withMargin(new MarginInfo(false, true, true, true));
        searchPanel = new TaskSearchPanel();
        MHorizontalLayout groupWrapLayout = new MHorizontalLayout();
        groupWrapLayout.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
        searchPanel.addHeaderRight(groupWrapLayout);

        toggleShowColumsBtn = new Button("");
        toggleShowColumsBtn.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent clickEvent) {
                displayHiddenColumns = !displayHiddenColumns;
                reload();
                toggleShowButton();
            }
        });
        toggleShowColumsBtn.addStyleName(UIConstants.BUTTON_LINK);
        groupWrapLayout.addComponent(toggleShowColumsBtn);
        toggleShowButton();

        Button addNewColumnBtn = new Button(AppContext.getMessage(TaskI18nEnum.ACTION_NEW_COLUMN),
                new Button.ClickListener() {
                    @Override
                    public void buttonClick(Button.ClickEvent clickEvent) {
                        UI.getCurrent().addWindow(new AddNewColumnWindow(TaskKanbanBoardViewImpl.this,
                                ProjectTypeConstants.TASK, "status"));
                    }
                });
        addNewColumnBtn.setIcon(FontAwesome.PLUS);
        addNewColumnBtn.setEnabled(CurrentProjectVariables.canAccess(ProjectRolePermissionCollections.TASKS));
        addNewColumnBtn.setStyleName(UIConstants.BUTTON_ACTION);
        groupWrapLayout.addComponent(addNewColumnBtn);

        Button deleteColumnBtn = new Button("Delete columns", new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                UI.getCurrent()
                        .addWindow(new DeleteColumnWindow(TaskKanbanBoardViewImpl.this, ProjectTypeConstants.TASK));
            }
        });
        deleteColumnBtn.setIcon(FontAwesome.TRASH_O);
        deleteColumnBtn.setEnabled(CurrentProjectVariables.canAccess(ProjectRolePermissionCollections.TASKS));
        deleteColumnBtn.setStyleName(UIConstants.BUTTON_DANGER);

        Button advanceDisplayBtn = new Button("List", new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                EventBusFactory.getInstance().post(new TaskEvent.GotoDashboard(TaskKanbanBoardViewImpl.this, null));
            }
        });
        advanceDisplayBtn.setWidth("100px");
        advanceDisplayBtn.setIcon(FontAwesome.SITEMAP);
        advanceDisplayBtn.setDescription("Advance View");

        Button kanbanBtn = new Button("Kanban");
        kanbanBtn.setWidth("100px");
        kanbanBtn.setDescription("Kanban View");
        kanbanBtn.setIcon(FontAwesome.TH);

        ToggleButtonGroup viewButtons = new ToggleButtonGroup();
        viewButtons.addButton(advanceDisplayBtn);
        viewButtons.addButton(kanbanBtn);
        viewButtons.withDefaultButton(kanbanBtn);
        groupWrapLayout.addComponent(viewButtons);

        kanbanLayout = new DDHorizontalLayout();
        kanbanLayout.setHeight("100%");
        kanbanLayout.addStyleName("kanban-layout");
        kanbanLayout.setSpacing(true);
        kanbanLayout.setMargin(new MarginInfo(true, false, true, false));
        kanbanLayout.setComponentHorizontalDropRatio(0.3f);
        kanbanLayout.setDragMode(LayoutDragMode.CLONE_OTHER);

        //      Enable dropping components
        kanbanLayout.setDropHandler(new DropHandler() {
            @Override
            public void drop(DragAndDropEvent event) {
                LayoutBoundTransferable transferable = (LayoutBoundTransferable) event.getTransferable();

                DDHorizontalLayout.HorizontalLayoutTargetDetails details = (DDHorizontalLayout.HorizontalLayoutTargetDetails) event
                        .getTargetDetails();
                Component dragComponent = transferable.getComponent();
                if (dragComponent instanceof KanbanBlock) {
                    KanbanBlock kanbanItem = (KanbanBlock) dragComponent;
                    int newIndex = details.getOverIndex();
                    if (details.getDropLocation() == HorizontalDropLocation.RIGHT) {
                        kanbanLayout.addComponent(kanbanItem);
                    } else if (newIndex == -1) {
                        kanbanLayout.addComponent(kanbanItem, 0);
                    } else {
                        kanbanLayout.addComponent(kanbanItem, newIndex);
                    }

                    //Update options index for this project
                    List<Map<String, Integer>> indexMap = new ArrayList<>();
                    for (int i = 0; i < kanbanLayout.getComponentCount(); i++) {
                        KanbanBlock blockItem = (KanbanBlock) kanbanLayout.getComponent(i);
                        Map<String, Integer> map = new HashedMap(2);
                        map.put("id", blockItem.optionVal.getId());
                        map.put("index", i);
                        indexMap.add(map);
                    }
                    if (indexMap.size() > 0) {
                        optionValService.massUpdateOptionIndexes(indexMap, AppContext.getAccountId());
                    }
                }
            }

            @Override
            public AcceptCriterion getAcceptCriterion() {
                return new Not(VerticalLocationIs.MIDDLE);
            }
        });
        this.setWidth("100%");
        this.with(searchPanel, kanbanLayout).expand(kanbanLayout);
    }

    void toggleShowButton() {
        if (displayHiddenColumns) {
            toggleShowColumsBtn.setCaption(AppContext.getMessage(TaskI18nEnum.ACTION_HIDE_COLUMNS));
        } else {
            toggleShowColumsBtn.setCaption(AppContext.getMessage(TaskI18nEnum.ACTION_SHOW_COLUMNS));
        }
    }

    @Override
    public HasSearchHandlers<TaskSearchCriteria> getSearchHandlers() {
        return searchPanel;
    }

    @Override
    public void attach() {
        EventBusFactory.getInstance().register(searchHandler);
        super.attach();
    }

    @Override
    public void detach() {
        setProjectNavigatorVisibility(true);
        EventBusFactory.getInstance().unregister(searchHandler);
        super.detach();
    }

    private void setProjectNavigatorVisibility(boolean visibility) {
        ProjectView view = UIUtils.getRoot(this, ProjectView.class);
        if (view != null) {
            view.setNavigatorVisibility(visibility);
        }
    }

    @Override
    public void display() {
        searchPanel.selectQueryInfo(TaskSavedFilterComboBox.OPEN_TASKS);
    }

    private void reload() {
        if (baseCriteria == null) {
            display();
        } else {
            queryTask(baseCriteria);
        }
    }

    @Override
    public void queryTask(final TaskSearchCriteria searchCriteria) {
        baseCriteria = searchCriteria;
        kanbanLayout.removeAllComponents();
        kanbanBlocks = new ConcurrentHashMap<>();

        setProjectNavigatorVisibility(false);
        AsyncInvoker.access(new AsyncInvoker.PageCommand() {
            @Override
            public void run() {
                List<OptionVal> optionVals = optionValService.findOptionVals(ProjectTypeConstants.TASK,
                        CurrentProjectVariables.getProjectId(), AppContext.getAccountId());
                for (OptionVal optionVal : optionVals) {
                    if (!displayHiddenColumns && Boolean.FALSE.equals(optionVal.getIsshow())) {
                        continue;
                    }
                    KanbanBlock kanbanBlock = new KanbanBlock(optionVal);
                    kanbanBlocks.put(optionVal.getTypeval(), kanbanBlock);
                    kanbanLayout.addComponent(kanbanBlock);
                }
                this.push();

                int totalTasks = taskService.getTotalCount(searchCriteria);
                searchPanel.setTotalCountNumber(totalTasks);
                int pages = totalTasks / 50;
                for (int page = 0; page < pages + 1; page++) {
                    List<SimpleTask> tasks = taskService
                            .findPagableListByCriteria(new BasicSearchRequest<>(searchCriteria, page + 1, 50));
                    if (CollectionUtils.isNotEmpty(tasks)) {
                        for (SimpleTask task : tasks) {
                            String status = task.getStatus();
                            KanbanBlock kanbanBlock = kanbanBlocks.get(status);
                            if (kanbanBlock != null) {
                                kanbanBlock.addBlockItem(new KanbanTaskBlockItem(task));
                            }
                        }
                        this.push();
                    }
                }
            }
        });
    }

    @Override
    public void addColumn(final OptionVal option) {
        AsyncInvoker.access(new AsyncInvoker.PageCommand() {
            @Override
            public void run() {
                KanbanBlock kanbanBlock = new KanbanBlock(option);
                kanbanBlocks.put(option.getTypeval(), kanbanBlock);
                kanbanLayout.addComponent(kanbanBlock);
            }
        });
    }

    private static class KanbanTaskBlockItem extends CustomComponent {
        private SimpleTask task;

        KanbanTaskBlockItem(final SimpleTask task) {
            this.task = task;
            MVerticalLayout root = new MVerticalLayout();
            root.addStyleName("kanban-item");
            this.setCompositionRoot(root);

            TaskPopupFieldFactory popupFieldFactory = ViewManager.getCacheComponent(TaskPopupFieldFactory.class);

            MHorizontalLayout headerLayout = new MHorizontalLayout();

            ToggleTaskSummaryField toggleTaskSummaryField = new ToggleTaskSummaryField(task, 70);
            AbstractComponent priorityField = popupFieldFactory.createPriorityPopupField(task);
            headerLayout.with(priorityField, toggleTaskSummaryField).expand(toggleTaskSummaryField);

            root.with(headerLayout);

            CssLayout footer = new CssLayout();

            AbstractComponent commentField = popupFieldFactory.createCommentsPopupField(task);
            footer.addComponent(commentField);

            AbstractComponent followerField = popupFieldFactory.createFollowersPopupField(task);
            footer.addComponent(followerField);

            AbstractComponent deadlineField = popupFieldFactory.createDeadlinePopupField(task);
            footer.addComponent(deadlineField);

            AbstractComponent assigneeField = popupFieldFactory.createAssigneePopupField(task);
            footer.addComponent(assigneeField);

            root.addComponent(footer);
        }
    }

    private class KanbanBlock extends MVerticalLayout {
        private OptionVal optionVal;
        private DDVerticalLayout dragLayoutContainer;
        private MHorizontalLayout buttonControls;
        private Button hideColumnBtn;
        private Label header;

        public KanbanBlock(final OptionVal stage) {
            this.withFullHeight().withWidth("300px").withStyleName("kanban-block").withMargin(false);
            this.optionVal = stage;
            final String optionId = UUID.randomUUID().toString() + "-" + stage.hashCode();
            this.setId(optionId);
            JavaScript.getCurrent()
                    .execute("$('#" + optionId + "').css({'background-color':'#" + stage.getColor() + "'});");

            dragLayoutContainer = new DDVerticalLayout();
            dragLayoutContainer.setSpacing(true);
            dragLayoutContainer.setComponentVerticalDropRatio(0.3f);
            dragLayoutContainer.setDragMode(LayoutDragMode.CLONE);
            dragLayoutContainer.setDropHandler(new DropHandler() {
                @Override
                public void drop(DragAndDropEvent event) {
                    LayoutBoundTransferable transferable = (LayoutBoundTransferable) event.getTransferable();

                    DDVerticalLayout.VerticalLayoutTargetDetails details = (DDVerticalLayout.VerticalLayoutTargetDetails) event
                            .getTargetDetails();

                    Component dragComponent = transferable.getComponent();
                    if (dragComponent instanceof KanbanTaskBlockItem) {
                        KanbanTaskBlockItem kanbanItem = (KanbanTaskBlockItem) dragComponent;
                        int newIndex = details.getOverIndex();
                        if (details.getDropLocation() == VerticalDropLocation.BOTTOM) {
                            dragLayoutContainer.addComponent(kanbanItem);
                        } else if (newIndex == -1) {
                            dragLayoutContainer.addComponent(kanbanItem, 0);
                        } else {
                            dragLayoutContainer.addComponent(kanbanItem, newIndex);
                        }
                        SimpleTask task = kanbanItem.task;
                        task.setStatus(optionVal.getTypeval());
                        ProjectTaskService taskService = AppContextUtil.getSpringBean(ProjectTaskService.class);
                        taskService.updateSelectiveWithSession(task, AppContext.getUsername());
                        updateComponentCount();

                        Component sourceComponent = transferable.getSourceComponent();
                        KanbanBlock sourceKanban = UIUtils.getRoot(sourceComponent, KanbanBlock.class);
                        if (sourceKanban != null && sourceKanban != KanbanBlock.this) {
                            sourceKanban.updateComponentCount();
                        }

                        //Update task index
                        List<Map<String, Integer>> indexMap = new ArrayList<>();
                        for (int i = 0; i < dragLayoutContainer.getComponentCount(); i++) {
                            Component subComponent = dragLayoutContainer.getComponent(i);
                            if (subComponent instanceof KanbanTaskBlockItem) {
                                KanbanTaskBlockItem blockItem = (KanbanTaskBlockItem) dragLayoutContainer
                                        .getComponent(i);
                                Map<String, Integer> map = new HashMap<>(2);
                                map.put("id", blockItem.task.getId());
                                map.put("index", i);
                                indexMap.add(map);
                            }
                        }
                        if (indexMap.size() > 0) {
                            taskService.massUpdateTaskIndexes(indexMap, AppContext.getAccountId());
                        }
                    }
                }

                @Override
                public AcceptCriterion getAcceptCriterion() {
                    return new Not(VerticalLocationIs.MIDDLE);
                }
            });
            new Restrain(dragLayoutContainer).setMinHeight("50px")
                    .setMaxHeight((UIUtils.getBrowserHeight() - 450) + "px");

            MHorizontalLayout headerLayout = new MHorizontalLayout().withSpacing(false).withFullWidth()
                    .withStyleName("header");
            header = new Label(AppContext.getMessage(StatusI18nEnum.class, optionVal.getTypeval()));
            headerLayout.with(header).expand(header);

            final PopupButton controlsBtn = new PopupButton();
            controlsBtn.addStyleName(UIConstants.BUTTON_LINK);
            headerLayout.with(controlsBtn);

            String typeVal = optionVal.getTypeval();
            boolean canRename = !typeVal.equals(StatusI18nEnum.Closed.name())
                    && !typeVal.equals(StatusI18nEnum.Open.name());
            boolean canExecute = CurrentProjectVariables.canAccess(ProjectRolePermissionCollections.TASKS);

            OptionPopupContent popupContent = new OptionPopupContent();
            Button renameColumnBtn = new Button(AppContext.getMessage(TaskI18nEnum.ACTION_RENAME_COLUMN),
                    new Button.ClickListener() {
                        @Override
                        public void buttonClick(Button.ClickEvent event) {
                            controlsBtn.setPopupVisible(false);
                            UI.getCurrent().addWindow(new RenameColumnWindow());
                        }
                    });
            renameColumnBtn.setIcon(FontAwesome.EDIT);
            renameColumnBtn.setEnabled(canExecute && canRename);
            popupContent.addOption(renameColumnBtn);

            hideColumnBtn = new Button("");
            hideColumnBtn.addClickListener(new Button.ClickListener() {
                @Override
                public void buttonClick(Button.ClickEvent clickEvent) {
                    controlsBtn.setPopupVisible(false);
                    if (Boolean.FALSE.equals(optionVal.getIsshow())) {
                        optionVal.setIsshow(Boolean.TRUE);
                    } else {
                        optionVal.setIsshow(Boolean.FALSE);
                    }
                    optionValService.updateWithSession(optionVal, AppContext.getUsername());
                    toggleShowButton();
                    if (!displayHiddenColumns && Boolean.FALSE.equals(optionVal.getIsshow())) {
                        ((ComponentContainer) KanbanBlock.this.getParent()).removeComponent(KanbanBlock.this);
                    }
                }
            });
            hideColumnBtn.setEnabled(canExecute);
            popupContent.addOption(hideColumnBtn);

            Button changeColorBtn = new Button(AppContext.getMessage(TaskI18nEnum.ACTION_CHANGE_COLOR),
                    new Button.ClickListener() {
                        @Override
                        public void buttonClick(Button.ClickEvent clickEvent) {
                            ColumnColorPickerWindow popup = new ColumnColorPickerWindow(Color.CYAN);
                            UI.getCurrent().addWindow(popup);
                            popup.addColorChangeListener(new ColorChangeListener() {
                                @Override
                                public void colorChanged(ColorChangeEvent colorChangeEvent) {
                                    Color color = colorChangeEvent.getColor();
                                    String colorStr = color.getCSS().substring(1);
                                    OptionValService optionValService = AppContextUtil
                                            .getSpringBean(OptionValService.class);
                                    optionVal.setColor(colorStr);
                                    optionValService.updateWithSession(optionVal, AppContext.getUsername());
                                    JavaScript.getCurrent().execute("$('#" + optionId
                                            + "').css({'background-color':'#" + colorStr + "'});");
                                }
                            });
                            controlsBtn.setPopupVisible(false);
                        }
                    });
            changeColorBtn.setIcon(FontAwesome.PENCIL);
            changeColorBtn.setEnabled(canExecute);
            popupContent.addOption(changeColorBtn);

            Button deleteColumnBtn = new Button(AppContext.getMessage(TaskI18nEnum.ACTION_DELETE_COLUMN),
                    new Button.ClickListener() {
                        @Override
                        public void buttonClick(Button.ClickEvent event) {
                            if (getTaskComponentCount() > 0) {
                                NotificationUtil.showErrorNotification(
                                        AppContext.getMessage(TaskI18nEnum.ERROR_CAN_NOT_DELETE_COLUMN_HAS_TASK));
                            } else {
                                ConfirmDialogExt.show(UI.getCurrent(),
                                        AppContext.getMessage(GenericI18Enum.DIALOG_DELETE_TITLE,
                                                AppContext.getSiteName()),
                                        AppContext.getMessage(GenericI18Enum.DIALOG_DELETE_MULTIPLE_ITEMS_MESSAGE),
                                        AppContext.getMessage(GenericI18Enum.BUTTON_YES),
                                        AppContext.getMessage(GenericI18Enum.BUTTON_NO),
                                        new ConfirmDialog.Listener() {
                                            private static final long serialVersionUID = 1L;

                                            @Override
                                            public void onClose(ConfirmDialog dialog) {
                                                if (dialog.isConfirmed()) {
                                                    optionValService.removeWithSession(stage,
                                                            AppContext.getUsername(), AppContext.getAccountId());
                                                    ((ComponentContainer) KanbanBlock.this.getParent())
                                                            .removeComponent(KanbanBlock.this);
                                                }
                                            }
                                        });
                            }
                            controlsBtn.setPopupVisible(false);
                        }
                    });
            deleteColumnBtn.setIcon(FontAwesome.TRASH_O);
            deleteColumnBtn.setEnabled(canExecute && canRename);
            popupContent.addDangerOption(deleteColumnBtn);

            popupContent.addSeparator();

            Button addBtn = new Button(AppContext.getMessage(TaskI18nEnum.NEW), new Button.ClickListener() {
                @Override
                public void buttonClick(Button.ClickEvent clickEvent) {
                    controlsBtn.setPopupVisible(false);
                    addNewTaskComp();
                }
            });
            addBtn.setIcon(FontAwesome.PLUS);
            addBtn.setEnabled(CurrentProjectVariables.canWrite(ProjectRolePermissionCollections.TASKS));
            popupContent.addOption(addBtn);
            controlsBtn.setContent(popupContent);

            Button addNewBtn = new Button(AppContext.getMessage(TaskI18nEnum.NEW), new Button.ClickListener() {
                @Override
                public void buttonClick(Button.ClickEvent clickEvent) {
                    addNewTaskComp();
                }
            });
            addNewBtn.setIcon(FontAwesome.PLUS);
            addNewBtn.setEnabled(CurrentProjectVariables.canWrite(ProjectRolePermissionCollections.TASKS));
            addNewBtn.addStyleName(UIConstants.BUTTON_ACTION);
            buttonControls = new MHorizontalLayout(addNewBtn).withAlign(addNewBtn, Alignment.MIDDLE_RIGHT)
                    .withFullWidth();
            this.with(headerLayout, dragLayoutContainer, buttonControls);
            toggleShowButton();
        }

        void toggleShowButton() {
            if (Boolean.FALSE.equals(optionVal.getIsshow())) {
                hideColumnBtn.setCaption(AppContext.getMessage(TaskI18nEnum.ACTION_SHOW_COLUMN));
                hideColumnBtn.setIcon(FontAwesome.TOGGLE_ON);
                ELabel invisibleLbl = new ELabel("Inv").withWidthUndefined().withStyleName(UIConstants.FIELD_NOTE)
                        .withDescription(AppContext.getMessage(TaskI18nEnum.OPT_INVISIBLE_COLUMN_DESCRIPTION));
                buttonControls.addComponent(invisibleLbl, 0);
                buttonControls.withAlign(invisibleLbl, Alignment.MIDDLE_LEFT);
            } else {
                hideColumnBtn.setCaption(AppContext.getMessage(TaskI18nEnum.ACTION_HIDE_COLUMN));
                hideColumnBtn.setIcon(FontAwesome.TOGGLE_OFF);
                if (buttonControls.getComponentCount() > 1) {
                    buttonControls.removeComponent(buttonControls.getComponent(0));
                }
            }
        }

        void addBlockItem(KanbanTaskBlockItem comp) {
            dragLayoutContainer.addComponent(comp);
            updateComponentCount();
        }

        private int getTaskComponentCount() {
            Component testComp = (dragLayoutContainer.getComponentCount() > 0) ? dragLayoutContainer.getComponent(0)
                    : null;
            if (testComp instanceof KanbanTaskBlockItem || testComp == null) {
                return dragLayoutContainer.getComponentCount();
            } else {
                return (dragLayoutContainer.getComponentCount() - 1);
            }
        }

        private void updateComponentCount() {
            header.setValue(String.format("%s (%d)", optionVal.getTypeval(), getTaskComponentCount()));
        }

        void addNewTaskComp() {
            Component testComp = (dragLayoutContainer.getComponentCount() > 0) ? dragLayoutContainer.getComponent(0)
                    : null;
            if (testComp instanceof KanbanTaskBlockItem || testComp == null) {
                final SimpleTask task = new SimpleTask();
                task.setSaccountid(AppContext.getAccountId());
                task.setProjectid(CurrentProjectVariables.getProjectId());
                task.setPercentagecomplete(0d);
                task.setStatus(optionVal.getTypeval());
                task.setProjectShortname(CurrentProjectVariables.getShortName());
                final MVerticalLayout layout = new MVerticalLayout();
                layout.addStyleName("kanban-item");
                final TextField taskNameField = new TextField();
                taskNameField.focus();
                taskNameField.setWidth("100%");
                layout.with(taskNameField);
                MHorizontalLayout controlsBtn = new MHorizontalLayout();
                Button saveBtn = new Button(AppContext.getMessage(GenericI18Enum.BUTTON_ADD),
                        new Button.ClickListener() {
                            @Override
                            public void buttonClick(Button.ClickEvent clickEvent) {
                                String taskName = taskNameField.getValue();
                                if (StringUtils.isNotBlank(taskName)) {
                                    task.setTaskname(taskName);
                                    ProjectTaskService taskService = AppContextUtil
                                            .getSpringBean(ProjectTaskService.class);
                                    taskService.saveWithSession(task, AppContext.getUsername());
                                    dragLayoutContainer.removeComponent(layout);
                                    KanbanTaskBlockItem kanbanTaskBlockItem = new KanbanTaskBlockItem(task);
                                    dragLayoutContainer.addComponent(kanbanTaskBlockItem, 0);
                                    updateComponentCount();
                                }
                            }
                        });
                saveBtn.addStyleName(UIConstants.BUTTON_ACTION);

                Button cancelBtn = new Button(AppContext.getMessage(GenericI18Enum.BUTTON_CANCEL),
                        new Button.ClickListener() {
                            @Override
                            public void buttonClick(Button.ClickEvent clickEvent) {
                                dragLayoutContainer.removeComponent(layout);
                                newTaskComp = null;
                            }
                        });
                cancelBtn.addStyleName(UIConstants.BUTTON_OPTION);
                controlsBtn.with(cancelBtn, saveBtn);
                layout.with(controlsBtn).withAlign(controlsBtn, Alignment.MIDDLE_RIGHT);
                if (newTaskComp != null && newTaskComp.getParent() != null) {
                    ((ComponentContainer) newTaskComp.getParent()).removeComponent(newTaskComp);
                }
                newTaskComp = layout;
                dragLayoutContainer.addComponent(layout, 0);
                dragLayoutContainer.markAsDirty();
            }
        }

        class RenameColumnWindow extends MWindow {
            public RenameColumnWindow() {
                super(AppContext.getMessage(TaskI18nEnum.ACTION_RENAME_COLUMN));
                withWidth("500px").withModal(true).withResizable(false);
                this.center();

                MVerticalLayout content = new MVerticalLayout().withMargin(false);
                this.setContent(content);

                final TextField columnNameField = new TextField();
                columnNameField.setValue(optionVal.getTypeval());
                GridFormLayoutHelper gridFormLayoutHelper = GridFormLayoutHelper.defaultFormLayoutHelper(1, 1);
                gridFormLayoutHelper.addComponent(columnNameField, "Column name", 0, 0);

                Button cancelBtn = new Button(AppContext.getMessage(GenericI18Enum.BUTTON_CANCEL),
                        new Button.ClickListener() {
                            @Override
                            public void buttonClick(Button.ClickEvent event) {
                                close();
                            }
                        });
                cancelBtn.setStyleName(UIConstants.BUTTON_OPTION);

                Button saveBtn = new Button(AppContext.getMessage(GenericI18Enum.BUTTON_SAVE),
                        new Button.ClickListener() {
                            @Override
                            public void buttonClick(Button.ClickEvent event) {
                                if (StringUtils.isNotBlank(columnNameField.getValue())) {
                                    OptionValService optionValService = AppContextUtil
                                            .getSpringBean(OptionValService.class);
                                    if (optionValService.isExistedOptionVal(ProjectTypeConstants.TASK,
                                            columnNameField.getValue(), "status", optionVal.getExtraid(),
                                            AppContext.getAccountId())) {
                                        NotificationUtil.showErrorNotification(AppContext.getMessage(
                                                TaskI18nEnum.ERROR_THERE_IS_ALREADY_COLUMN_NAME,
                                                columnNameField.getValue()));
                                    } else {
                                        taskService.massUpdateStatuses(optionVal.getTypeval(),
                                                columnNameField.getValue(), optionVal.getExtraid(),
                                                AppContext.getAccountId());
                                        optionVal.setTypeval(columnNameField.getValue());
                                        optionValService.updateWithSession(optionVal, AppContext.getUsername());
                                        KanbanBlock.this.updateComponentCount();
                                    }
                                } else {
                                    NotificationUtil.showErrorNotification(
                                            AppContext.getMessage(TaskI18nEnum.ERROR_COLUMN_NAME_NOT_NULL));
                                }

                                RenameColumnWindow.this.close();
                            }
                        });
                saveBtn.setIcon(FontAwesome.SAVE);
                saveBtn.setStyleName(UIConstants.BUTTON_ACTION);

                MHorizontalLayout buttonControls = new MHorizontalLayout()
                        .withMargin(new MarginInfo(false, true, true, false)).with(cancelBtn, saveBtn);
                content.with(gridFormLayoutHelper.getLayout(), buttonControls).withAlign(buttonControls,
                        Alignment.MIDDLE_RIGHT);
            }
        }
    }

    private static class ColumnColorPickerWindow extends ColorPickerPopup {
        ColumnColorPickerWindow(Color initialColor) {
            super(initialColor);
            this.center();
        }
    }
}