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

Java tutorial

Introduction

Here is the source code for com.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.mycollab.module.project.view.task;

import com.google.common.eventbus.Subscribe;
import com.mycollab.common.domain.OptionVal;
import com.mycollab.common.i18n.GenericI18Enum;
import com.mycollab.common.i18n.OptionI18nEnum.StatusI18nEnum;
import com.mycollab.common.service.OptionValService;
import com.mycollab.core.utils.StringUtils;
import com.mycollab.db.arguments.BasicSearchRequest;
import com.mycollab.db.arguments.NumberSearchField;
import com.mycollab.db.arguments.SearchCriteria;
import com.mycollab.eventmanager.ApplicationEventListener;
import com.mycollab.eventmanager.EventBusFactory;
import com.mycollab.module.project.CurrentProjectVariables;
import com.mycollab.module.project.ProjectRolePermissionCollections;
import com.mycollab.module.project.ProjectTypeConstants;
import com.mycollab.module.project.domain.SimpleTask;
import com.mycollab.module.project.domain.criteria.TaskSearchCriteria;
import com.mycollab.module.project.event.TaskEvent;
import com.mycollab.module.project.event.TicketEvent;
import com.mycollab.module.project.i18n.ProjectCommonI18nEnum;
import com.mycollab.module.project.i18n.TaskI18nEnum;
import com.mycollab.module.project.service.ProjectTaskService;
import com.mycollab.module.project.ui.components.BlockRowRender;
import com.mycollab.module.project.ui.components.IBlockContainer;
import com.mycollab.module.project.view.ProjectView;
import com.mycollab.module.project.view.kanban.AddNewColumnWindow;
import com.mycollab.module.project.view.kanban.DeleteColumnWindow;
import com.mycollab.module.project.view.service.TaskComponentFactory;
import com.mycollab.spring.AppContextUtil;
import com.mycollab.vaadin.AsyncInvoker;
import com.mycollab.vaadin.MyCollabUI;
import com.mycollab.vaadin.UserUIContext;
import com.mycollab.vaadin.events.HasSearchHandlers;
import com.mycollab.vaadin.mvp.AbstractVerticalPageView;
import com.mycollab.vaadin.mvp.ViewComponent;
import com.mycollab.vaadin.ui.ELabel;
import com.mycollab.vaadin.ui.NotificationUtil;
import com.mycollab.vaadin.ui.UIConstants;
import com.mycollab.vaadin.ui.UIUtils;
import com.mycollab.vaadin.web.ui.*;
import com.mycollab.vaadin.web.ui.grid.GridFormLayoutHelper;
import com.vaadin.event.ShortcutAction;
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.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.vaadin.hene.popupbutton.PopupButton;
import org.vaadin.jouni.restrain.Restrain;
import org.vaadin.viritin.button.MButton;
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 AbstractVerticalPageView implements TaskKanbanBoardView {

    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 MButton toggleShowColumnsBtn;
    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);

        toggleShowColumnsBtn = new MButton("", clickEvent -> {
            displayHiddenColumns = !displayHiddenColumns;
            reload();
            toggleShowButton();
        }).withStyleName(WebThemes.BUTTON_LINK);
        groupWrapLayout.addComponent(toggleShowColumnsBtn);
        toggleShowButton();

        if (CurrentProjectVariables.canAccess(ProjectRolePermissionCollections.TASKS)) {
            MButton addNewColumnBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.ACTION_NEW_COLUMN),
                    clickEvent -> UI.getCurrent()
                            .addWindow(new AddNewColumnWindow(this, ProjectTypeConstants.TASK, "status")))
                                    .withIcon(FontAwesome.PLUS).withStyleName(WebThemes.BUTTON_ACTION);
            groupWrapLayout.addComponent(addNewColumnBtn);
        }

        MButton deleteColumnBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.ACTION_DELETE_COLUMNS),
                clickEvent -> UI.getCurrent().addWindow(new DeleteColumnWindow(this, ProjectTypeConstants.TASK)))
                        .withIcon(FontAwesome.TRASH_O).withStyleName(WebThemes.BUTTON_DANGER);
        deleteColumnBtn.setVisible(CurrentProjectVariables.canAccess(ProjectRolePermissionCollections.TASKS));

        MButton advanceDisplayBtn = new MButton(UserUIContext.getMessage(ProjectCommonI18nEnum.OPT_LIST),
                clickEvent -> EventBusFactory.getInstance().post(new TicketEvent.GotoDashboard(this, null)))
                        .withIcon(FontAwesome.NAVICON).withWidth("100px");

        MButton kanbanBtn = new MButton(UserUIContext.getMessage(ProjectCommonI18nEnum.OPT_KANBAN))
                .withIcon(FontAwesome.TH).withWidth("100px");

        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 HashMap<>(2);
                        map.put("id", blockItem.optionVal.getId());
                        map.put("index", i);
                        indexMap.add(map);
                    }
                    if (indexMap.size() > 0) {
                        optionValService.massUpdateOptionIndexes(indexMap, MyCollabUI.getAccountId());
                    }
                }
            }

            @Override
            public AcceptCriterion getAcceptCriterion() {
                return new Not(VerticalLocationIs.MIDDLE);
            }
        });

        this.with(searchPanel, kanbanLayout).expand(kanbanLayout);
    }

    private void toggleShowButton() {
        if (displayHiddenColumns) {
            toggleShowColumnsBtn.setCaption(UserUIContext.getMessage(TaskI18nEnum.ACTION_HIDE_COLUMNS));
        } else {
            toggleShowColumnsBtn.setCaption(UserUIContext.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(getUI(), new AsyncInvoker.PageCommand() {
            @Override
            public void run() {
                List<OptionVal> optionVals = optionValService.findOptionVals(ProjectTypeConstants.TASK,
                        CurrentProjectVariables.getProjectId(), MyCollabUI.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
                            .findPageableListByCriteria(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(getUI(), 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 BlockRowRender {
        private SimpleTask task;

        private KanbanTaskBlockItem(final SimpleTask task) {
            this.task = task;
            this.addStyleName("kanban-item");

            TaskComponentFactory popupFieldFactory = AppContextUtil.getSpringBean(TaskComponentFactory.class);

            MHorizontalLayout headerLayout = new MHorizontalLayout();

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

            this.with(headerLayout);

            CssLayout footer = new CssLayout();

            footer.addComponent(popupFieldFactory.createCommentsPopupField(task));
            footer.addComponent(popupFieldFactory.createFollowersPopupField(task));
            footer.addComponent(popupFieldFactory.createStartDatePopupField(task));
            footer.addComponent(popupFieldFactory.createEndDatePopupField(task));
            footer.addComponent(popupFieldFactory.createDeadlinePopupField(task));
            footer.addComponent(popupFieldFactory.createAssigneePopupField(task));

            this.addComponent(footer);
        }
    }

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

        KanbanBlock(final OptionVal stage) {
            this.withFullHeight().withWidth("350px").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, UserUIContext.getUsername());
                        refresh();

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

                        //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, MyCollabUI.getAccountId());
                        }
                    }
                }

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

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

            final PopupButton controlsBtn = new PopupButton();
            controlsBtn.addStyleName(WebThemes.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();

            if (canExecute && canRename) {
                MButton renameColumnBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.ACTION_RENAME_COLUMN),
                        clickEvent -> {
                            controlsBtn.setPopupVisible(false);
                            UI.getCurrent().addWindow(new RenameColumnWindow());
                        }).withIcon(FontAwesome.EDIT);
                popupContent.addOption(renameColumnBtn);
            }

            if (canExecute) {
                hideColumnBtn = new Button("", clickEvent -> {
                    controlsBtn.setPopupVisible(false);
                    if (Boolean.FALSE.equals(optionVal.getIsshow())) {
                        optionVal.setIsshow(Boolean.TRUE);
                    } else {
                        optionVal.setIsshow(Boolean.FALSE);
                    }
                    optionValService.updateWithSession(optionVal, UserUIContext.getUsername());
                    toggleShowButton();
                    if (!displayHiddenColumns && Boolean.FALSE.equals(optionVal.getIsshow())) {
                        ((ComponentContainer) KanbanBlock.this.getParent()).removeComponent(KanbanBlock.this);
                    }
                });
                popupContent.addOption(hideColumnBtn);
            }

            if (canExecute) {
                MButton changeColorBtn = new MButton(UserUIContext.getMessage(GenericI18Enum.ACTION_CHANGE_COLOR),
                        clickEvent -> {
                            ColumnColorPickerWindow popup = new ColumnColorPickerWindow(Color.CYAN);
                            UI.getCurrent().addWindow(popup);
                            popup.addColorChangeListener(colorChangeEvent -> {
                                Color color = colorChangeEvent.getColor();
                                String colorStr = color.getCSS().substring(1);
                                OptionValService optionValService = AppContextUtil
                                        .getSpringBean(OptionValService.class);
                                optionVal.setColor(colorStr);
                                optionValService.updateWithSession(optionVal, UserUIContext.getUsername());
                                JavaScript.getCurrent().execute(
                                        "$('#" + optionId + "').css({'background-color':'#" + colorStr + "'});");
                            });
                            controlsBtn.setPopupVisible(false);
                        }).withIcon(FontAwesome.PENCIL);
                popupContent.addOption(changeColorBtn);
            }

            if (canExecute && canRename) {
                MButton deleteColumnBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.ACTION_DELETE_COLUMN),
                        clickEvent -> {
                            if (getTaskComponentCount() > 0) {
                                NotificationUtil.showErrorNotification(UserUIContext
                                        .getMessage(TaskI18nEnum.ERROR_CAN_NOT_DELETE_COLUMN_HAS_TASK));
                            } else {
                                ConfirmDialogExt.show(UI.getCurrent(),
                                        UserUIContext.getMessage(GenericI18Enum.DIALOG_DELETE_TITLE,
                                                MyCollabUI.getSiteName()),
                                        UserUIContext
                                                .getMessage(GenericI18Enum.DIALOG_DELETE_MULTIPLE_ITEMS_MESSAGE),
                                        UserUIContext.getMessage(GenericI18Enum.BUTTON_YES),
                                        UserUIContext.getMessage(GenericI18Enum.BUTTON_NO), confirmDialog -> {
                                            if (confirmDialog.isConfirmed()) {
                                                optionValService.removeWithSession(stage,
                                                        UserUIContext.getUsername(), MyCollabUI.getAccountId());
                                                ((ComponentContainer) KanbanBlock.this.getParent())
                                                        .removeComponent(KanbanBlock.this);
                                            }
                                        });
                            }
                            controlsBtn.setPopupVisible(false);
                        }).withIcon(FontAwesome.TRASH_O);
                popupContent.addDangerOption(deleteColumnBtn);
            }

            popupContent.addSeparator();

            if (CurrentProjectVariables.canWrite(ProjectRolePermissionCollections.TASKS)) {
                MButton addBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.NEW), clickEvent -> {
                    controlsBtn.setPopupVisible(false);
                    addNewTaskComp();
                }).withIcon(FontAwesome.PLUS);
                popupContent.addOption(addBtn);
            }
            controlsBtn.setContent(popupContent);

            if (CurrentProjectVariables.canWrite(ProjectRolePermissionCollections.TASKS)) {
                MButton addNewBtn = new MButton(UserUIContext.getMessage(TaskI18nEnum.NEW),
                        clickEvent -> addNewTaskComp()).withIcon(FontAwesome.PLUS)
                                .withStyleName(WebThemes.BUTTON_ACTION);
                buttonControls = new MHorizontalLayout(addNewBtn).withAlign(addNewBtn, Alignment.MIDDLE_RIGHT)
                        .withFullWidth();
                this.with(headerLayout, dragLayoutContainer, buttonControls);
            } else {
                this.with(headerLayout, dragLayoutContainer);
            }
            toggleShowButton();
        }

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

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

        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);
            }
        }

        @Override
        public void refresh() {
            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(MyCollabUI.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);

                MButton saveBtn = new MButton(UserUIContext.getMessage(GenericI18Enum.BUTTON_ADD), clickEvent -> {
                    String taskName = taskNameField.getValue();
                    if (StringUtils.isNotBlank(taskName)) {
                        task.setName(taskName);
                        ProjectTaskService taskService = AppContextUtil.getSpringBean(ProjectTaskService.class);
                        taskService.saveWithSession(task, UserUIContext.getUsername());
                        dragLayoutContainer.removeComponent(layout);
                        KanbanTaskBlockItem kanbanTaskBlockItem = new KanbanTaskBlockItem(task);
                        dragLayoutContainer.addComponent(kanbanTaskBlockItem, 0);
                        refresh();
                    }
                }).withStyleName(WebThemes.BUTTON_ACTION);

                MButton cancelBtn = new MButton(UserUIContext.getMessage(GenericI18Enum.BUTTON_CANCEL),
                        clickEvent -> {
                            dragLayoutContainer.removeComponent(layout);
                            newTaskComp = null;
                        }).withStyleName(WebThemes.BUTTON_OPTION);

                MHorizontalLayout controlsBtn = new MHorizontalLayout(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();
            }
        }

        private class RenameColumnWindow extends MWindow {
            RenameColumnWindow() {
                super(UserUIContext.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);

                MButton cancelBtn = new MButton(UserUIContext.getMessage(GenericI18Enum.BUTTON_CANCEL),
                        clickEvent -> close()).withStyleName(WebThemes.BUTTON_OPTION);

                MButton saveBtn = new MButton(UserUIContext.getMessage(GenericI18Enum.BUTTON_SAVE), clickEvent -> {
                    if (StringUtils.isNotBlank(columnNameField.getValue())) {
                        OptionValService optionValService = AppContextUtil.getSpringBean(OptionValService.class);
                        if (optionValService.isExistedOptionVal(ProjectTypeConstants.TASK,
                                columnNameField.getValue(), "status", optionVal.getExtraid(),
                                MyCollabUI.getAccountId())) {
                            NotificationUtil.showErrorNotification(UserUIContext.getMessage(
                                    TaskI18nEnum.ERROR_THERE_IS_ALREADY_COLUMN_NAME, columnNameField.getValue()));
                        } else {
                            taskService.massUpdateStatuses(optionVal.getTypeval(), columnNameField.getValue(),
                                    optionVal.getExtraid(), MyCollabUI.getAccountId());
                            optionVal.setTypeval(columnNameField.getValue());
                            optionValService.updateWithSession(optionVal, UserUIContext.getUsername());
                            KanbanBlock.this.refresh();
                        }
                    } else {
                        NotificationUtil.showErrorNotification(
                                UserUIContext.getMessage(TaskI18nEnum.ERROR_COLUMN_NAME_NOT_NULL));
                    }

                    close();
                }).withIcon(FontAwesome.SAVE).withStyleName(WebThemes.BUTTON_ACTION)
                        .withClickShortcut(ShortcutAction.KeyCode.ENTER);

                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();
        }
    }
}