/*
* Copyright (c) 2011-2015 Marat Gubaidullin.
*
* This file is part of HYBRIDBPM.
*
* 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 com.hybridbpm.ui.component.bpm.designer;
import com.hybridbpm.model.ProcessModel;
import com.hybridbpm.model.TaskModel;
import com.hybridbpm.model.TaskModel.TASK_PRIORITY;
import com.hybridbpm.model.TransitionModel;
import com.hybridbpm.ui.HybridbpmUI;
import com.hybridbpm.ui.component.ConfigureWindow;
import com.hybridbpm.ui.component.ProcessModelLayoutInterface;
import com.hybridbpm.ui.component.TransitionManager;
import com.hybridbpm.ui.component.bpm.window.TransitionConfigureWindow;
import com.vaadin.event.dd.DragAndDropEvent;
import com.vaadin.event.dd.DropHandler;
import com.vaadin.event.dd.acceptcriteria.AcceptAll;
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.Sizeable;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.DragAndDropWrapper.WrapperTargetDetails;
import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
import org.vaadin.dialogs.ConfirmDialog;
/**
*
* @author Marat Gubaidullin
*/
public class ProcessModelLayout extends AbsoluteLayout implements ProcessModelLayoutInterface, Button.ClickListener {
private ProcessEditor processEditor;
private ProcessModel processModel;
private TransitionManager transitionManager;
private ActiveElement activeElement;
// active element button bar
private final Button btnEdit = new Button(null, this);
private final Button btnDelete = new Button(null, this);
private final CssLayout elementButtonBar = new CssLayout();
// process width and heigth button bar
private final Button btnUp = new Button(null, this);
private final Button btnDown = new Button(null, this);
private final Button btnLeft = new Button(null, this);
private final Button btnRight = new Button(null, this);
private final VerticalLayout widthButtonBar = new VerticalLayout();
private final CssLayout heightButtonBar = new CssLayout();
public DropHandler dropHandler = new ProcessModelLayoutDropHandler(this);
public void initUI() {
removeAllComponents();
addStyleName("process-model");
setImmediate(true);
setWidth(processModel.getWidth(), Sizeable.Unit.PIXELS);
setHeight(processModel.getHeight(), Sizeable.Unit.PIXELS);
prepareButtonsBars();
transitionManager = new TransitionManager(this);
transitionManager.setSizeFull();
transitionManager.setValue(processModel.getWidth(), processModel.getHeight());
transitionManager.setValue(processModel.getTaskModels(), processModel.getTransitionModels());
addComponent(transitionManager);
for (TaskModel taskModel : processModel.getTaskModels().values()) {
ElementModelLayout elementModelLayout = new ElementModelLayout(taskModel, this);
addComponent(elementModelLayout, "left:" + taskModel.getX() + "px; top:" + taskModel.getY() + "px");
}
activeElement = new ActiveElement(ActiveElement.TYPE.PROCESS, processModel, null, null);
}
@Override
public void setTransitionElementValue(String transitionModelId, float x, float y) {
TransitionModel transitionModel = processModel.getTransitionModels().get(transitionModelId);
transitionModel.setX(x);
transitionModel.setY(y);
// processModel.addTransitionModel(transitionModel);
}
@Override
public void addTransitionElement(String beginElementId, String endElementId) {
StringBuilder name = new StringBuilder("transition");
int count = 0;
while (processModel.getTransitionModelByName(name.toString() + count) != null) {
count++;
}
name.append(count);
Float x;
Float y;
if (beginElementId.equals(endElementId)) {
x = (processModel.getTaskModelById(beginElementId).getX() + processModel.getTaskModelById(beginElementId).getWidth() + 25);
y = (processModel.getTaskModelById(beginElementId).getY() - 25);
} else {
x = (processModel.getTaskModelById(beginElementId).getX() + processModel.getTaskModelById(endElementId).getX()) / 2;
y = (processModel.getTaskModelById(beginElementId).getY() + processModel.getTaskModelById(endElementId).getY()) / 2;
}
processModel.addTransitionModelById(name.toString(), beginElementId, endElementId, x, y);
transitionManager.setValue(processModel.getTaskModels(), processModel.getTransitionModels());
}
public void setTaskActive(TaskModel taskModel) {
transitionManager.setDragger(taskModel);
unselectAllElements();
for (Component comp : this) {
if (comp instanceof ElementModelLayout) {
ElementModelLayout eml = ((ElementModelLayout) comp);
if (eml.getTaskModel().getId().equals(taskModel.getId())) {
eml.setStyleSelected(true);
activeElement.setTaskModel(taskModel);
break;
}
}
}
activateButtonBar();
}
public void removeTaskElement(TaskModel taskModel) {
for (Component comp : this) {
if (comp instanceof ElementModelLayout) {
ElementModelLayout eml = ((ElementModelLayout) comp);
if (eml.getTaskModel().getId().equals(taskModel.getId())) {
removeComponent(comp);
break;
}
}
}
}
@Override
public void setTransitionActive(String transitionId) {
unselectAllElements();
TransitionModel transitionModel = processModel.getTransitionModelById(transitionId);
activeElement.setTransitionModel(transitionModel);
activateButtonBar();
}
public void unselectAllElements() {
removeComponent(elementButtonBar);
for (Component comp : this) {
if (comp instanceof ElementModelLayout) {
ElementModelLayout eml = ((ElementModelLayout) comp);
eml.setStyleSelected(false);
}
}
}
@Override
public void setProcessActive() {
removeComponent(elementButtonBar);
for (Component comp : this) {
if (comp instanceof ElementModelLayout) {
ElementModelLayout eml = ((ElementModelLayout) comp);
eml.setStyleSelected(false);
}
}
activeElement.setProcessModel(processModel);
transitionManager.setValue(processModel.getTaskModels(), processModel.getTransitionModels(), null);
// setDeleteShortcutListener(false);
}
public ProcessModel getProcessModel() {
return processModel;
}
public void setProcessModel(ProcessModel processModel) {
this.processModel = processModel;
}
public void setProcessEditor(ProcessEditor processEditor) {
this.processEditor = processEditor;
}
@Override
public void addTaskModel(float x, float y) {
StringBuilder name = new StringBuilder("task");
int count = 0;
while (processModel.getTaskModelByName(name.toString() + count) != null) {
count++;
}
name.append(count);
TaskModel taskModel = new TaskModel(name.toString(), null, TaskModel.TASK_TYPE.HUMAN, TaskModel.GATE_TYPE.EXLUSIVE, TaskModel.GATE_TYPE.EXLUSIVE, TASK_PRIORITY.NORMAL, x, y);
processModel.getTaskModels().put(taskModel.getId(), taskModel);
ElementModelLayout elementModelLayout = new ElementModelLayout(taskModel, this);
addComponent(elementModelLayout, "left:" + taskModel.getX() + "px; top:" + taskModel.getY() + "px");
addTransitionElement(activeElement.getTaskModel().getId(), taskModel.getId());
setTaskActive(taskModel);
}
public ActiveElement getActiveElement() {
return activeElement;
}
@Override
public void buttonClick(Button.ClickEvent event) {
if (event.getButton().equals(btnUp)) {
processModel.setHeight(processModel.getHeight() - 100);
processEditor.setProcessModel(processModel);
} else if (event.getButton().equals(btnDown)) {
processModel.setHeight(processModel.getHeight() + 100);
processEditor.setProcessModel(processModel);
} else if (event.getButton().equals(btnRight)) {
processModel.setWidth(processModel.getWidth() + 100);
processEditor.setProcessModel(processModel);
} else if (event.getButton().equals(btnLeft)) {
processModel.setWidth(processModel.getWidth() - 100);
processEditor.setProcessModel(processModel);
} else if (event.getButton().equals(btnDelete)) {
ConfirmDialog cd = ConfirmDialog.show(HybridbpmUI.getCurrent(), "Confirmation", "Delete element?", "Yes", "Cancel", new ConfirmDialog.Listener() {
@Override
public void onClose(ConfirmDialog dialog) {
if (dialog.isConfirmed()) {
if (activeElement.getType().equals(ActiveElement.TYPE.TASK)) {
processModel.removeTaskModelByName(activeElement.getTaskModel().getName());
removeTaskElement(activeElement.getTaskModel());
} else if (activeElement.getType().equals(ActiveElement.TYPE.TRANSITION)) {
processModel.removeTransitionModel(activeElement.getTransitionModel().getId());
}
removeComponent(elementButtonBar);
transitionManager.setValue(processModel.getTaskModels(), processModel.getTransitionModels(), null);
}
}
});
cd.addStyleName("dialog");
cd.getCancelButton().addStyleName("small");
cd.getOkButton().addStyleName("small");
cd.getOkButton().addStyleName("default");
cd.getOkButton().focus();
} else if (event.getButton().equals(btnEdit)) {
if (activeElement.getType().equals(ActiveElement.TYPE.TRANSITION)) {
TransitionConfigureWindow tgw = new TransitionConfigureWindow();
tgw.initUI(this);
tgw.addCloseListener(new Window.CloseListener() {
@Override
public void windowClose(Window.CloseEvent e) {
processEditor.setProcessModel(processModel);
}
});
HybridbpmUI.getCurrent().addWindow(tgw);
} else {
final TaskConfigureCustomComponent tcl = new TaskConfigureCustomComponent();
tcl.initUI(this);
final ConfigureWindow configureWindow = new ConfigureWindow(tcl, "Task");
configureWindow.setClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
if (event.getButton().equals(configureWindow.btnClose)) {
configureWindow.close();
} else if (event.getButton().equals(configureWindow.btnOk)) {
tcl.save();
}
configureWindow.close();
}
});
configureWindow.addCloseListener(new Window.CloseListener() {
@Override
public void windowClose(Window.CloseEvent e) {
processEditor.setProcessModel(processModel);
}
});
configureWindow.setSize(800, 600);
HybridbpmUI.getCurrent().addWindow(configureWindow);
}
}
}
private void prepareButtonsBars() {
// element button bar
btnEdit.addStyleName(ValoTheme.BUTTON_LINK);
btnEdit.addStyleName(ValoTheme.BUTTON_SMALL);
btnEdit.addStyleName("edit-button");
btnEdit.setIcon(FontAwesome.PENCIL_SQUARE);
btnDelete.addStyleName(ValoTheme.BUTTON_LINK);
btnDelete.addStyleName(ValoTheme.BUTTON_SMALL);
btnDelete.addStyleName("edit-button");
btnDelete.setIcon(FontAwesome.TIMES);
elementButtonBar.addComponent(btnEdit);
elementButtonBar.addComponent(btnDelete);
elementButtonBar.setId("button-bar");
// width button bar
btnRight.setIcon(FontAwesome.ARROW_CIRCLE_RIGHT);
btnRight.addStyleName(ValoTheme.BUTTON_LINK);
btnLeft.setIcon(FontAwesome.ARROW_CIRCLE_LEFT);
btnLeft.addStyleName(ValoTheme.BUTTON_LINK);
widthButtonBar.addComponent(btnRight);
widthButtonBar.addComponent(btnLeft);
widthButtonBar.addStyleName("width-button-bar");
widthButtonBar.setWidthUndefined();
addComponent(widthButtonBar);
// height button bar
btnUp.setIcon(FontAwesome.ARROW_CIRCLE_UP);
btnUp.addStyleName(ValoTheme.BUTTON_LINK);
btnDown.setIcon(FontAwesome.ARROW_CIRCLE_DOWN);
btnDown.addStyleName(ValoTheme.BUTTON_LINK);
heightButtonBar.addComponent(btnUp);
heightButtonBar.addComponent(btnDown);
heightButtonBar.addStyleName("height-button-bar");
addComponent(heightButtonBar);
}
private void activateButtonBar() {
if (activeElement.getType().equals(ActiveElement.TYPE.TRANSITION)) {
TransitionModel transitionModel = activeElement.getTransitionModel();
addComponent(elementButtonBar, "left:" + (transitionModel.getX() - 15) + "px; top:" + (transitionModel.getY() - 25) + "px");
elementButtonBar.addStyleName("horizontal");
elementButtonBar.removeStyleName("vertical");
btnEdit.focus();
} else {
TaskModel taskModel = activeElement.getTaskModel();
addComponent(elementButtonBar, "left:" + (taskModel.getX() + taskModel.getWidth() + 3) + "px; top:" + (taskModel.getY() + 15) + "px");
elementButtonBar.addStyleName("vertical");
elementButtonBar.removeStyleName("horizontal");
}
}
private class ProcessModelLayoutDropHandler implements DropHandler {
private final ProcessModelLayout processModelLayout;
public ProcessModelLayoutDropHandler(ProcessModelLayout processModelLayout) {
this.processModelLayout = processModelLayout;
}
@Override
public void drop(DragAndDropEvent event) {
WrapperTransferable transfrable = (WrapperTransferable) event.getTransferable();
WrapperTargetDetails details = (WrapperTargetDetails) event.getTargetDetails();
System.out.println("transfrable " + transfrable.getClass().getCanonicalName());
System.out.println("transfrable.getDraggedComponent() " + transfrable.getDraggedComponent().getClass().getCanonicalName());
if (transfrable.getDraggedComponent() instanceof Button) {
// Calculate the drag coordinate difference
int xChange = details.getMouseEvent().getClientX() - transfrable.getMouseDownEvent().getClientX();
int yChange = details.getMouseEvent().getClientY() - transfrable.getMouseDownEvent().getClientY();
// Move the component in the absolute layout
AbsoluteLayout.ComponentPosition componentPosition = processModelLayout.getPosition(transfrable.getSourceComponent());
componentPosition.setLeftValue(componentPosition.getLeftValue() + xChange);
componentPosition.setTopValue(componentPosition.getTopValue() + yChange);
ElementModelLayout elementModelLayout = (ElementModelLayout) ((Button) transfrable.getDraggedComponent()).getParent();
TaskModel elementModel = elementModelLayout.getTaskModel();
elementModel.setX(componentPosition.getLeftValue());
elementModel.setY(componentPosition.getTopValue());
processModel.getTaskModels().put(elementModel.getId(), elementModel);
transitionManager.setValue(processModel.getTaskModels(), processModel.getTransitionModels());
setTaskActive(elementModel);
}
}
@Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
}
}