/* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.activiti.explorer.ui.task; import java.util.List; import org.activiti.engine.HistoryService; import org.activiti.engine.ProcessEngines; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.task.Task; import org.activiti.explorer.ExplorerApp; import org.activiti.explorer.I18nManager; import org.activiti.explorer.Messages; import org.activiti.explorer.identity.LoggedInUser; import org.activiti.explorer.ui.Images; import org.activiti.explorer.ui.mainlayout.ExplorerLayout; import org.activiti.explorer.ui.task.listener.DeleteSubTaskClickListener; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; import com.vaadin.event.ShortcutAction; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CustomComponent; import com.vaadin.ui.Embedded; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.Reindeer; /** * Custom component for the 'sub tasks' section for a task. * Used in the {@link TaskDetailPanel}. * * @author Joram Barrez */ public class SubTaskComponent extends CustomComponent { private static final long serialVersionUID = 1L; protected I18nManager i18nManager; protected TaskService taskService; protected HistoryService historyService; protected Task parentTask; protected TaskDetailPanel taskDetailPanel; protected VerticalLayout layout; protected Label title; protected Panel addSubTaskPanel; protected Button addSubTaskButton; protected TextField newTaskTextField; protected GridLayout subTaskLayout; public SubTaskComponent(Task parentTask) { this.parentTask = parentTask; this.i18nManager = ExplorerApp.get().getI18nManager(); this.taskService = ProcessEngines.getDefaultProcessEngine().getTaskService(); this.historyService = ProcessEngines.getDefaultProcessEngine().getHistoryService(); initUi(); } protected void initUi() { addStyleName(ExplorerLayout.STYLE_DETAIL_BLOCK); addStyleName(ExplorerLayout.STYLE_INVOLVE_PEOPLE); initLayout(); initHeader(); initSubTasks(); } protected void initLayout() { this.layout = new VerticalLayout(); setCompositionRoot(layout); } protected void initHeader() { HorizontalLayout headerLayout = new HorizontalLayout(); headerLayout.setWidth(100, UNITS_PERCENTAGE); layout.addComponent(headerLayout); initTitle(headerLayout); initAddSubTaskPanel(headerLayout); } protected void initTitle(HorizontalLayout headerLayout) { title = new Label(i18nManager.getMessage(Messages.TASK_SUBTASKS)); title.addStyleName(ExplorerLayout.STYLE_H3); title.setWidth(100, UNITS_PERCENTAGE); headerLayout.addComponent(title); headerLayout.setExpandRatio(title, 1.0f); } protected void initAddSubTaskPanel(HorizontalLayout headerLayout) { // The add button is placed in a panel, so we can catch 'enter' and 'escape' events addSubTaskPanel = new Panel(); addSubTaskPanel.setContent(new VerticalLayout()); addSubTaskPanel.setSizeUndefined(); addSubTaskPanel.addStyleName(Reindeer.PANEL_LIGHT); addSubTaskPanel.addStyleName("no-border"); headerLayout.addComponent(addSubTaskPanel); initAddSubTaskPanelKeyboardActions(); initAddButton(); } protected void initAddSubTaskPanelKeyboardActions() { addSubTaskPanel.addActionHandler(new Handler() { public void handleAction(Action action, Object sender, Object target) { if ("escape".equals(action.getCaption())) { resetAddButton(); } else if ("enter".equals(action.getCaption())) { if (newTaskTextField != null && newTaskTextField.getValue() != null && !"".equals(newTaskTextField.getValue().toString())) { LoggedInUser loggedInUser = ExplorerApp.get().getLoggedInUser(); // save task Task newTask = taskService.newTask(); newTask.setParentTaskId(parentTask.getId()); if (parentTask.getAssignee() != null) { newTask.setAssignee(parentTask.getAssignee()); } else { newTask.setAssignee(loggedInUser.getId()); } if (parentTask.getOwner() != null) { newTask.setOwner(parentTask.getOwner()); } else { newTask.setOwner(loggedInUser.getId()); } newTask.setName(newTaskTextField.getValue().toString()); taskService.saveTask(newTask); // Reset the add button to its original state resetAddButton(); // refresh sub tasks section refreshSubTasks(); } } } public Action[] getActions(Object target, Object sender) { return new Action[] { new ShortcutAction("enter", ShortcutAction.KeyCode.ENTER, null), new ShortcutAction("escape", ShortcutAction.KeyCode.ESCAPE, null) }; } }); } protected void initAddButton() { addSubTaskButton = new Button(); addSubTaskButton.addStyleName(ExplorerLayout.STYLE_ADD); addSubTaskPanel.addComponent(addSubTaskButton); addSubTaskButton.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { // Remove button addSubTaskPanel.removeAllComponents(); // And add textfield Label createSubTaskLabel = new Label("Create new subtask:"); createSubTaskLabel.addStyleName(Reindeer.LABEL_SMALL); addSubTaskPanel.addComponent(createSubTaskLabel); newTaskTextField = new TextField(); newTaskTextField.focus(); addSubTaskPanel.addComponent(newTaskTextField); } }); } protected void resetAddButton() { addSubTaskPanel.removeAllComponents(); initAddButton(); } protected void initSubTasks() { List<HistoricTaskInstance> subTasks = historyService.createHistoricTaskInstanceQuery() .taskParentTaskId(parentTask.getId()) .list(); initSubTasksLayout(); populateSubTasks(subTasks); } protected void initSubTasksLayout() { subTaskLayout = new GridLayout(); subTaskLayout.setColumns(3); subTaskLayout.addStyleName(ExplorerLayout.STYLE_TASK_SUBTASKS_LIST); subTaskLayout.setWidth(99, UNITS_PERCENTAGE); subTaskLayout.setColumnExpandRatio(2, 1.0f); subTaskLayout.setSpacing(true); layout.addComponent(subTaskLayout); } protected void populateSubTasks(List<HistoricTaskInstance> subTasks) { if (subTasks.size() > 0) { for (final HistoricTaskInstance subTask : subTasks) { // icon Embedded icon = null; if(subTask.getEndTime() != null) { icon = new Embedded(null, Images.TASK_FINISHED_22); } else { icon = new Embedded(null, Images.TASK_22); } icon.setWidth(22, UNITS_PIXELS); icon.setWidth(22, UNITS_PIXELS); subTaskLayout.addComponent(icon); // Link to subtask Button subTaskLink = new Button(subTask.getName()); subTaskLink.addStyleName(Reindeer.BUTTON_LINK); subTaskLink.addListener(new ClickListener() { public void buttonClick(ClickEvent event) { ExplorerApp.get().getViewManager().showTaskPage(subTask.getId()); } }); subTaskLayout.addComponent(subTaskLink); subTaskLayout.setComponentAlignment(subTaskLink, Alignment.MIDDLE_LEFT); if(subTask.getEndTime() == null) { // Delete icon only appears when task is not finished yet Embedded deleteIcon = new Embedded(null, Images.DELETE); deleteIcon.addStyleName(ExplorerLayout.STYLE_CLICKABLE); deleteIcon.addListener(new DeleteSubTaskClickListener(subTask, this)); subTaskLayout.addComponent(deleteIcon); subTaskLayout.setComponentAlignment(deleteIcon, Alignment.MIDDLE_RIGHT); } else { // Next line of grid subTaskLayout.newLine(); } } } else { Label noSubTasksLabel = new Label(i18nManager.getMessage(Messages.TASK_NO_SUBTASKS)); noSubTasksLabel.setSizeUndefined(); noSubTasksLabel.addStyleName(Reindeer.LABEL_SMALL); subTaskLayout.addComponent(noSubTasksLabel); } } public void refreshSubTasks() { subTaskLayout.removeAllComponents(); List<HistoricTaskInstance> subTasks = historyService.createHistoricTaskInstanceQuery() .taskParentTaskId(parentTask.getId()) .list(); populateSubTasks(subTasks); } }