/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.gses.webui.executor;
import com.google.common.base.Function;
import com.vaadin.data.Item;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Form;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.Reindeer;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import ru.codeinside.adm.AdminServiceProvider;
import ru.codeinside.adm.database.Bid;
import ru.codeinside.adm.database.BidStatus;
import ru.codeinside.adm.database.TaskDates;
import ru.codeinside.gses.activiti.forms.FormID;
import ru.codeinside.gses.beans.ActivitiBean;
import ru.codeinside.gses.service.ExecutorService;
import ru.codeinside.gses.service.Functions;
import ru.codeinside.gses.webui.Flash;
import ru.codeinside.gses.webui.components.ProcedureHistoryPanel;
import ru.codeinside.gses.webui.components.ShowDiagramComponent;
import ru.codeinside.gses.webui.components.ShowDiagramComponentParameterObject;
import ru.codeinside.gses.webui.components.TableForExecutor;
import ru.codeinside.gses.webui.components.TaskGraphListener;
import ru.codeinside.gses.webui.components.api.Changer;
import ru.codeinside.gses.webui.components.api.WithTaskId;
import ru.codeinside.gses.webui.data.AssigneeTaskListQuery;
import ru.codeinside.gses.webui.data.BatchItemBuilder;
import ru.codeinside.gses.webui.data.CandidateTaskListQuery;
import ru.codeinside.gses.webui.data.Durations;
import ru.codeinside.gses.webui.data.ItemBuilder;
import ru.codeinside.gses.webui.data.TaskStylist;
import ru.codeinside.gses.webui.eventbus.TaskChanged;
import ru.codeinside.gses.webui.form.DataAccumulator;
import ru.codeinside.gses.webui.form.FormDescription;
import ru.codeinside.gses.webui.form.FormDescriptionBuilder;
import ru.codeinside.gses.webui.form.TaskForm;
import ru.codeinside.gses.webui.supervisor.TaskFilter;
import ru.codeinside.gses.webui.utils.Components;
import java.text.SimpleDateFormat;
import static ru.codeinside.gses.webui.utils.Components.buttonProperty;
import static ru.codeinside.gses.webui.utils.Components.stringProperty;
public class ExecutorFactory {
public final static SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy HH:mm");
public static Component create(final Changer changer, final TabSheet tabs) {
final ItemBuilder<Task> assigneeBuilder = new BatchItemBuilder<Task>() {
private static final long serialVersionUID = 1L;
transient Durations durations;
@Override
public void batchStart() {
durations = new Durations();
}
@Override
public void batchFinish() {
durations = null;
}
@Override
public Item createItem(final Task task) {
final String taskId = task.getId();
final ProcessDefinition def = ActivitiBean.get().getProcessDefinition(task.getProcessDefinitionId(), Flash.login());
String procedureName = Flash.flash().getExecutorService().getProcedureNameByDefinitionId(def.getId());
final PropertysetItem item = new PropertysetItem();
final Bid bid = getBid(task);
final String bidId = bid.getId() == null ? "" : bid.getId().toString();
item.addItemProperty("id", buttonProperty(bidId, new TaskGraphListener(changer, task)));
item.addItemProperty("name", stringProperty(task.getName()));
item.addItemProperty("startDate", stringProperty(formatter.format(bid.getDateCreated())));
item.addItemProperty("declarant", stringProperty(bid.getDeclarant()));
if (bid.getTag() == null || bid.getTag().isEmpty()) {
item.addItemProperty("process", stringProperty(procedureName));
} else {
item.addItemProperty("process", stringProperty(bid.getTag() + " - " + procedureName));
}
item.addItemProperty("version", stringProperty(bid.getVersion()));
final Button b = new Button("Обработать", new Button.ClickListener() {
private static final long serialVersionUID = 1L;
@Override
public void buttonClick(ClickEvent event) {
try {
showForm(tabs, taskId);
} catch (Exception e) {
Components.showException(event.getButton().getWindow(), e);
}
}
});
b.setStyleName(Reindeer.BUTTON_SMALL);
item.addItemProperty("claim", new ObjectProperty<Component>(b));
item.addItemProperty("priority", stringProperty(String.valueOf(task.getPriority())));
TaskDates td = AdminServiceProvider.get().getTaskDatesByTaskId(taskId);
durations.fillBidAndTask(bid, td, item);
return item;
}
private Bid getBid(final Task task) {
Bid bid = AdminServiceProvider.get().getBidByTask(task.getId());
if (bid == null) {
bid = new Bid();
bid.setDeclarant("");
bid.setVersion("");
bid.setStatus(BidStatus.Execute);
}
return bid;
}
};
final AssigneeTaskListQuery assigneeTaskQuery = new AssigneeTaskListQuery(assigneeBuilder);
final TableForExecutor assignee = new TableForExecutor(assigneeTaskQuery);
assignee.setCaption("Исполняемые заявки");
assignee.addContainerProperty("id", Component.class, null);
assignee.addContainerProperty("name", String.class, null);
assignee.addContainerProperty("startDate", String.class, null);
assignee.addContainerProperty("declarant", String.class, null);
assignee.addContainerProperty("process", String.class, null);
assignee.addContainerProperty("version", String.class, null);
assignee.addContainerProperty("status", String.class, null);
assignee.addContainerProperty("claim", Component.class, null);
assignee.addContainerProperty("priority", String.class, null);
assignee.addContainerProperty("bidDays", String.class, null);
assignee.addContainerProperty("taskDays", String.class, null);
assignee.setVisibleColumns(new Object[]{"id", "name", "startDate", "declarant", "process", "version", "claim", "bidDays", "taskDays"});
assignee.setColumnHeaders(new String[]{"Номер", "Этап", "Дата подачи заявки", "Заявитель", "Процедура", "v", "", "Ср.з.", "Ср.эт."});
assignee.setSelectable(false);
assignee.setSortDisabled(true);
assignee.setColumnAlignment("id", Table.ALIGN_RIGHT);
assignee.setColumnExpandRatio("id", 0.3f);
assignee.setColumnExpandRatio("name", 1f);
assignee.setColumnExpandRatio("process", 1.2f);
assignee.setColumnExpandRatio("bidDays", 0.2f);
assignee.setColumnExpandRatio("taskDays", 0.2f);
assignee.setCellStyleGenerator(new TaskStylist(assignee));
final ItemBuilder<Task> claimBuilder = new BatchItemBuilder<Task>() {
private static final long serialVersionUID = 1L;
Durations durations;
@Override
public void batchStart() {
durations = new Durations();
}
@Override
public void batchFinish() {
durations = null;
}
@Override
public Item createItem(final Task task) {
final String taskId = task.getId();
final ProcessDefinition def = ActivitiBean.get().getProcessDefinition(task.getProcessDefinitionId(), Flash.login());
String procedureName = Flash.flash().getExecutorService().getProcedureNameByDefinitionId(def.getId());
PropertysetItem item = new PropertysetItem();
final Bid bid = getBid(task);
ObjectProperty idProperty;
if (bid.getId() == null) {
idProperty = new ObjectProperty<String>("");
} else {
idProperty = buttonProperty(bid.getId().toString(), new TaskGraphListener(changer, task));
}
item.addItemProperty("id", idProperty);
item.addItemProperty("name", stringProperty(task.getName()));
item.addItemProperty("startDate", stringProperty(formatter.format(bid.getDateCreated())));
item.addItemProperty("declarant", stringProperty(bid.getDeclarant()));
if (bid.getTag() == null || bid.getTag().isEmpty()) {
item.addItemProperty("process", stringProperty(procedureName));
} else {
item.addItemProperty("process", stringProperty(bid.getTag() + " - " + procedureName));
}
item.addItemProperty("version", stringProperty(bid.getVersion()));
item.addItemProperty("status", stringProperty(bid.getStatus().getName()));
final Button b = new Button("Забрать", new Button.ClickListener() {
private static final long serialVersionUID = 1L;
@Override
public void buttonClick(ClickEvent event) {
final String login = Flash.login();
final String errMessage = ActivitiBean.get().claim(taskId, login, login, false);
if (!StringUtils.isEmpty(errMessage)) {
event.getButton().getWindow()
.showNotification("Ошибка", errMessage, Notification.TYPE_ERROR_MESSAGE);
}
fireTaskChangedEvent(taskId, this);
}
});
b.setStyleName(Reindeer.BUTTON_SMALL);
item.addItemProperty("claim", new ObjectProperty<Component>(b));
item.addItemProperty("priority", stringProperty(String.valueOf(task.getPriority())));
TaskDates td = AdminServiceProvider.get().getTaskDatesByTaskId(taskId);
durations.fillBidAndTask(bid, td, item);
return item;
}
private Bid getBid(final Task task) {
Bid bid = AdminServiceProvider.get().getBidByTask(task.getId());
if (bid == null) {
bid = new Bid();
bid.setDeclarant("");
bid.setVersion("");
bid.setStatus(BidStatus.Execute);
}
return bid;
}
};
final CandidateTaskListQuery candidateTaskQuery = new CandidateTaskListQuery(claimBuilder, Flash.login());
final TableForExecutor candidate = new TableForExecutor(candidateTaskQuery);
candidate.setCaption("Открытые заявки");
candidate.addContainerProperty("id", Component.class, null);
candidate.addContainerProperty("name", String.class, null);
candidate.addContainerProperty("startDate", String.class, null);
candidate.addContainerProperty("declarant", String.class, null);
candidate.addContainerProperty("process", String.class, null);
candidate.addContainerProperty("version", String.class, null);
candidate.addContainerProperty("status", String.class, null);
candidate.addContainerProperty("claim", Component.class, null);
candidate.addContainerProperty("priority", String.class, null);
candidate.addContainerProperty("bidDays", String.class, null);
candidate.addContainerProperty("taskDays", String.class, null);
candidate.setVisibleColumns(new Object[]{"id", "name", "startDate", "declarant", "process", "version", "status", "claim", "bidDays", "taskDays"});
candidate.setColumnHeaders(new String[]{"Номер", "Этап", "Дата подачи заявки", "Заявитель", "Процедура", "v", "Статус", "", "Ср.з.", "Ср.эт."});
candidate.setSelectable(false);
candidate.setSortDisabled(true);
candidate.setColumnAlignment("id", Table.ALIGN_RIGHT);
candidate.setColumnExpandRatio("name", 1f);
candidate.setColumnExpandRatio("process", 1f);
candidate.setCellStyleGenerator(new TaskStylist(candidate));
final Form filter = new TaskFilter(candidateTaskQuery, candidate, assigneeTaskQuery, assignee, TaskFilter.Mode.Executor);
HorizontalLayout asigneeLayout = new HorizontalLayout();
asigneeLayout.setSizeFull();
asigneeLayout.setMargin(true);
asigneeLayout.setSpacing(true);
asigneeLayout.addComponent(assignee);
Panel filterPanel = new Panel();
filterPanel.setHeight("100%");
filterPanel.addComponent(filter);
final HorizontalSplitPanel hSplitter = new HorizontalSplitPanel();
hSplitter.setSizeFull();
hSplitter.setFirstComponent(filterPanel);
hSplitter.setSecondComponent(asigneeLayout);
hSplitter.setSplitPosition(35);
VerticalLayout candidateLayout = new VerticalLayout();
candidateLayout.setSizeFull();
candidateLayout.setMargin(true);
candidateLayout.addComponent(candidate);
final TasksSplitter vSplitter = new TasksSplitter(assignee, candidate);
vSplitter.setSizeFull();
vSplitter.setFirstComponent(hSplitter);
vSplitter.setSecondComponent(candidateLayout);
vSplitter.setSplitPosition(57);
return vSplitter;
}
static public void showTask(final Changer changer, final Task task) {
ProcessDefinitionEntity def = Functions.withRepository(Flash.login(),
new Function<RepositoryService, ProcessDefinitionEntity>() {
public ProcessDefinitionEntity apply(final RepositoryService srv) {
RepositoryServiceImpl impl = (RepositoryServiceImpl) srv;
return (ProcessDefinitionEntity) impl.getDeployedProcessDefinition(task
.getProcessDefinitionId());
}
}
);
showTask(changer, task, def);
}
static void showTask(final Changer changer, final Task task, final ProcessDefinitionEntity def) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
layout.setSizeFull();
final Button cancel = new Button("Назад", new Button.ClickListener() {
private static final long serialVersionUID = 1L;
@Override
public void buttonClick(ClickEvent event) {
changer.back();
}
});
cancel.setClickShortcut(KeyCode.ESCAPE, 0);
layout.addComponent(cancel);
HorizontalLayout hl = new HorizontalLayout();
hl.setSizeFull();
hl.setSpacing(true);
layout.addComponent(hl);
layout.setExpandRatio(cancel, 0.01f);
layout.setExpandRatio(hl, 0.99f);
VerticalLayout vl = new VerticalLayout();
vl.setSizeFull();
vl.setSpacing(true);
hl.addComponent(vl);
final String procedureName = Flash.flash().getExecutorService().getProcedureNameByDefinitionId(def.getId());
vl.addComponent(new ProcedureHistoryPanel(task.getId()));
ShowDiagramComponentParameterObject parameterObject = new ShowDiagramComponentParameterObject();
final String procVersion = def.getVersion() + "";
parameterObject.windowHeader = procedureName + "v. " + procVersion;
parameterObject.width = "600px";
parameterObject.executionId = task.getExecutionId();
parameterObject.changer = changer;
parameterObject.processDefinitionId = def.getId();
parameterObject.caption = "Диаграмма";
ShowDiagramComponent showDiagramComponent = new ShowDiagramComponent(parameterObject);
hl.addComponent(showDiagramComponent);
hl.setExpandRatio(vl, 0.5f);
hl.setExpandRatio(showDiagramComponent, 0.5f);
changer.change(layout);
cancel.focus();
}
static private void showForm(final TabSheet tabs, final String taskId) {
// Определяем открыта ли уже
for (int i = tabs.getComponentCount(); i > 0; i--) {
final Tab tab = tabs.getTab(i - 1);
if (tab.getComponent() instanceof WithTaskId) {
if (taskId.equals(((WithTaskId) tab.getComponent()).getTaskId())) {
tabs.setSelectedTab(tab);
return;
}
}
}
DataAccumulator accumulator = new DataAccumulator();
ExecutorService executorService = Flash.flash().getExecutorService();
final FormDescription formDescription = Functions.withEngine(
new FormDescriptionBuilder(FormID.byTaskId(taskId), executorService, accumulator));
final TaskForm taskForm = new TaskForm(formDescription, new TaskForm.CloseListener() {
private static final long serialVersionUID = 3726145663843346543L;
@Override
public void onFormClose(final TaskForm form) {
final TabSheet.Tab tab = tabs.getTab(tabs.getSelectedTab());
int pos = tabs.getTabPosition(tab);
tabs.removeTab(tab);
int count = tabs.getComponentCount();
tabs.setSelectedTab(count == pos ? pos - 1 : pos);
}
}, accumulator);
final Tab tab = tabs.addTab(taskForm, formDescription.task.getName());
tab.setDescription("Услуга \"" + formDescription.processDefinition.getName() + "\"");
tabs.setSelectedTab(tab);
}
static private void fireTaskChangedEvent(final String taskId, final Object source) {
Flash.fire(new TaskChanged(source, taskId));
}
}