/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.wkf;
import java.awt.Dimension;
import java.io.File;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JComponent;
import org.openflexo.ApplicationContext;
import org.openflexo.components.ProgressWindow;
import org.openflexo.components.browser.view.BrowserView.FlexoJTree;
import org.openflexo.fge.Drawing;
import org.openflexo.fge.controller.DrawingController;
import org.openflexo.fge.view.DrawingView;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.InspectorGroup;
import org.openflexo.foundation.Inspectors;
import org.openflexo.foundation.wkf.ActivityGroup;
import org.openflexo.foundation.wkf.ActivityPetriGraph;
import org.openflexo.foundation.wkf.FlexoPetriGraph;
import org.openflexo.foundation.wkf.FlexoProcess;
import org.openflexo.foundation.wkf.FlexoWorkflow;
import org.openflexo.foundation.wkf.RoleList;
import org.openflexo.foundation.wkf.WKFArtefact;
import org.openflexo.foundation.wkf.WKFObject;
import org.openflexo.foundation.wkf.edge.MessageEdge;
import org.openflexo.foundation.wkf.edge.WKFEdge;
import org.openflexo.foundation.wkf.node.FatherNode;
import org.openflexo.foundation.wkf.node.LOOPOperator;
import org.openflexo.foundation.wkf.node.PetriGraphNode;
import org.openflexo.foundation.wkf.node.SelfExecutableNode;
import org.openflexo.foundation.wkf.ws.FlexoPort;
import org.openflexo.foundation.wkf.ws.FlexoPortMap;
import org.openflexo.foundation.wkf.ws.PortMapRegistery;
import org.openflexo.foundation.wkf.ws.PortRegistery;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.logging.FlexoLogger;
import org.openflexo.module.FlexoModule;
import org.openflexo.module.Module;
import org.openflexo.module.external.ExternalWKFModule;
import org.openflexo.swing.FlexoSwingUtils;
import org.openflexo.toolbox.FileResource;
import org.openflexo.view.controller.FlexoController;
import org.openflexo.wkf.controller.WKFController;
import org.openflexo.wkf.controller.WorkflowBrowser;
import org.openflexo.wkf.processeditor.ProcessEditorController;
import org.openflexo.wkf.processeditor.ProcessRepresentation.ProcessRepresentationDefaultVisibilityDelegate;
import org.openflexo.wkf.processeditor.ProcessView;
import org.openflexo.wkf.roleeditor.RoleEditorController;
import org.openflexo.wkf.swleditor.SwimmingLaneEditorController;
import org.openflexo.wkf.swleditor.SwimmingLaneRepresentation;
import org.openflexo.wkf.swleditor.SwimmingLaneRepresentation.SwimmingLaneRepresentationDefaultVisibilityDelegate;
import org.openflexo.wkf.view.WorkflowBrowserView;
/**
* Workflow Editor module
*
* @author sguerin
*/
public class WKFModule extends FlexoModule implements ExternalWKFModule {
private static final InspectorGroup[] inspectorGroups = new InspectorGroup[] { Inspectors.WKF };
private Map<Drawing<? extends FlexoModelObject>, DrawingController<? extends Drawing<? extends FlexoModelObject>>> drawingControllers = new Hashtable<Drawing<? extends FlexoModelObject>, DrawingController<? extends Drawing<? extends FlexoModelObject>>>();
public static enum ProcessRepresentation {
BASIC_EDITOR, SWIMMING_LANE;
}
private static final Logger logger = FlexoLogger.getLogger(WKFModule.class.getPackage().getName());
public WKFModule(ApplicationContext applicationContext) throws Exception {
super(applicationContext);
WKFPreferences.init();
}
@Override
public void initModule() {
ProgressWindow.setProgressInstance(FlexoLocalization.localizedForKey("build_editor"));
super.initModule();
getWKFController().loadRelativeWindows();
}
@Override
public Module getModule() {
return Module.WKF_MODULE;
}
@Override
protected FlexoController createControllerForModule() {
return new WKFController(this);
}
@Override
public InspectorGroup[] getInspectorGroups() {
return inspectorGroups;
}
public File getPaletteDirectory() {
return new FileResource(WKFCst.PALETTE_FOLDER_PATH);
}
public WKFController getWKFController() {
return (WKFController) getFlexoController();
}
private static class BPEScreenshotProcessRepresentationObjectVisibilityDelegate extends ProcessRepresentationDefaultVisibilityDelegate {
private WKFObject target;
public BPEScreenshotProcessRepresentationObjectVisibilityDelegate(WKFObject target) {
this.target = target;
}
@Override
public boolean isVisible(WKFObject object) {
if (object == null) {
return false;
}
if (object instanceof FlexoProcess) {
return false;
}
if (object == target) {
return true;
} else if (object instanceof FlexoPetriGraph) {
return ((FlexoPetriGraph) object).getContainer() == target || object instanceof ActivityPetriGraph
&& ((ActivityPetriGraph) object).getContainer() instanceof FlexoProcess || target instanceof PetriGraphNode
&& ((PetriGraphNode) target).isEmbeddedInPetriGraph((FlexoPetriGraph) object) || target instanceof WKFArtefact
&& ((WKFArtefact) target).isEmbeddedInPetriGraph((FlexoPetriGraph) object);
} else if (object instanceof FlexoPort) {
return isVisible(((FlexoPort) object).getPortRegistery());
} else if (object instanceof FlexoPortMap) {
return !((FlexoPortMap) object).getIsHidden() && isVisible(((FlexoPortMap) object).getPortMapRegistery());
} else if (object instanceof PetriGraphNode) {
if (isVisible(((PetriGraphNode) object).getParentPetriGraph())) {
return true;
}
FlexoPetriGraph petriGraph = null;
if (object instanceof FatherNode) {
petriGraph = ((FatherNode) object).getContainedPetriGraph();
} else if (object instanceof SelfExecutableNode) {
petriGraph = ((SelfExecutableNode) object).getExecutionPetriGraph();
} else if (object instanceof LOOPOperator) {
petriGraph = ((LOOPOperator) object).getExecutionPetriGraph();
}
return petriGraph != null && isVisible(petriGraph);
} else if (object instanceof WKFArtefact) {
return isVisible(((WKFArtefact) object).getParentPetriGraph());
} else if (object instanceof PortMapRegistery) {
return !((PortMapRegistery) object).getIsHidden() && ((PortMapRegistery) object).getPortMaps().size() > 0;
} else if (object instanceof PortRegistery) {
return ((PortRegistery) object).getIsVisible();
} else if (object instanceof WKFEdge<?, ?>) {
WKFEdge<?, ?> post = (WKFEdge<?, ?>) object;
WKFObject firstVisibleStartObject = getFirstVisibleObject(post.getStartNode());
WKFObject firstVisibleEndObject = getFirstVisibleObject(post.getEndNode());
if (post instanceof MessageEdge<?, ?>) {
if (firstVisibleStartObject instanceof FlexoPortMap) {
if (((FlexoPortMap) firstVisibleStartObject).getSubProcessNode() == firstVisibleEndObject) {
return false;
}
} else if (firstVisibleEndObject instanceof FlexoPortMap) {
if (((FlexoPortMap) firstVisibleEndObject).getSubProcessNode() == firstVisibleStartObject) {
return false;
}
}
}
return !(firstVisibleStartObject != post.getStartNode() && firstVisibleEndObject != post.getEndNode() && firstVisibleStartObject == firstVisibleEndObject)
&& firstVisibleStartObject != null && firstVisibleEndObject != null;
} else if (object instanceof ActivityGroup) {
if (target instanceof PetriGraphNode) {
if (((PetriGraphNode) target).isGrouped()) {
return ((PetriGraphNode) target).getContainerGroup() == object;
}
}
}
return true;
}
}
private class SWLScreenshotProcessRepresentationObjectVisibilityDelegate extends SwimmingLaneRepresentationDefaultVisibilityDelegate {
private WKFObject target;
public SWLScreenshotProcessRepresentationObjectVisibilityDelegate(WKFObject target) {
this.target = target;
}
@Override
public boolean isVisible(WKFObject object) {
if (object == null) {
return false;
}
if (object instanceof FlexoProcess) {
return false;
}
if (object == target) {
return true;
} else if (object instanceof PetriGraphNode
&& ((PetriGraphNode) object).getParentPetriGraph() == object.getProcess().getActivityPetriGraph()) {
return true;
} else if (object instanceof FlexoPetriGraph) {
return ((FlexoPetriGraph) object).getContainer() == target || object instanceof ActivityPetriGraph
&& ((ActivityPetriGraph) object).getContainer() instanceof FlexoProcess || target instanceof PetriGraphNode
&& ((PetriGraphNode) target).isEmbeddedInPetriGraph((FlexoPetriGraph) object) || target instanceof WKFArtefact
&& ((WKFArtefact) target).isEmbeddedInPetriGraph((FlexoPetriGraph) object);
} else if (object instanceof FlexoPort) {
return isVisible(((FlexoPort) object).getPortRegistery());
} else if (object instanceof FlexoPortMap) {
return !((FlexoPortMap) object).getIsHidden() && isVisible(((FlexoPortMap) object).getPortMapRegistery());
} else if (object instanceof PetriGraphNode) {
if (isVisible(((PetriGraphNode) object).getParentPetriGraph())) {
return true;
}
FlexoPetriGraph petriGraph = null;
if (object instanceof FatherNode) {
petriGraph = ((FatherNode) object).getContainedPetriGraph();
} else if (object instanceof SelfExecutableNode) {
petriGraph = ((SelfExecutableNode) object).getExecutionPetriGraph();
} else if (object instanceof LOOPOperator) {
petriGraph = ((LOOPOperator) object).getExecutionPetriGraph();
}
return petriGraph != null && isVisible(petriGraph);
} else if (object instanceof WKFArtefact) {
return isVisible(((WKFArtefact) object).getParentPetriGraph());
} else if (object instanceof PortMapRegistery) {
return !((PortMapRegistery) object).getIsHidden() && ((PortMapRegistery) object).getPortMaps().size() > 0;
} else if (object instanceof PortRegistery) {
return ((PortRegistery) object).getIsVisible();
} else if (object instanceof WKFEdge<?, ?>) {
WKFEdge<?, ?> post = (WKFEdge<?, ?>) object;
WKFObject firstVisibleStartObject = getFirstVisibleObject(post.getStartNode());
WKFObject firstVisibleEndObject = getFirstVisibleObject(post.getEndNode());
if (post instanceof MessageEdge<?, ?>) {
if (firstVisibleStartObject instanceof FlexoPortMap) {
if (((FlexoPortMap) firstVisibleStartObject).getSubProcessNode() == firstVisibleEndObject) {
return false;
}
} else if (firstVisibleEndObject instanceof FlexoPortMap) {
if (((FlexoPortMap) firstVisibleEndObject).getSubProcessNode() == firstVisibleStartObject) {
return false;
}
}
}
return !(firstVisibleStartObject != post.getStartNode() && firstVisibleEndObject != post.getEndNode() && firstVisibleStartObject == firstVisibleEndObject)
&& firstVisibleStartObject != null && firstVisibleEndObject != null;
} else if (object instanceof ActivityGroup) {
if (target instanceof PetriGraphNode) {
if (((PetriGraphNode) target).isGrouped()) {
return ((PetriGraphNode) target).getContainerGroup() == object;
}
}
}
return true;
}
}
private class ScreenshotRetriever implements Callable<DrawingController<? extends Drawing<? extends FlexoModelObject>>> {
private FlexoModelObject target;
private final boolean showAll;
protected ScreenshotRetriever(FlexoModelObject target, boolean showAll) {
super();
this.target = target;
this.showAll = showAll;
}
@Override
public DrawingController<? extends Drawing<? extends FlexoModelObject>> call() {
DrawingController<? extends Drawing<? extends FlexoModelObject>> screenshotController = null;
if (target instanceof RoleList) {
screenshotController = new RoleEditorController((RoleList) target, null);
} else if (target instanceof WKFObject) {
screenshotController = getProcessRepresentationController((WKFObject) target, showAll);
} else {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Cannot create drawing controller for " + target);
}
}
if (screenshotController != null) {
drawingControllers.put(screenshotController.getDrawing(), screenshotController);
}
return screenshotController;
}
}
@Override
public JComponent createScreenshotForObject(final FlexoModelObject target) {
if (target == null) {
if (logger.isLoggable(Level.SEVERE)) {
logger.severe("Cannot create screenshot for null target!");
}
return null;
}
JComponent component;
if (target instanceof FlexoWorkflow) {
FlexoJTree treeView = new WorkflowBrowserView(new WorkflowBrowser(target.getProject()), null).getTreeView();
component = treeView;
// Expand all nodes in tree
for (int i = 0; i < treeView.getRowCount(); i++) {
treeView.expandRow(i);
}
} else {
DrawingController<? extends Drawing<? extends FlexoModelObject>> screenshotController = getScreenshotControllerForObject(
target, false);
DrawingView<? extends Drawing<? extends FlexoModelObject>> screenshot;
component = screenshot = screenshotController.getDrawingView();
screenshot.getDrawingGraphicalRepresentation().setDrawWorkingArea(false);
if (screenshot instanceof ProcessView) {
((ProcessView) screenshot).getDrawingGraphicalRepresentation().setShowGrid(false);
}
screenshot.getPaintManager().disablePaintingCache();
screenshot.validate();
Dimension d = screenshot.getComputedMinimumSize();
d.height += 20;
d.width += 20;
screenshot.setSize(d);
screenshot.setPreferredSize(d);
}
return component;
}
@Override
public float getScreenshotQuality() {
float reply = Float.valueOf(WKFPreferences.getScreenshotQuality()) / 100f;
if (reply > 1) {
return 1f;
}
if (reply < 0.1f) {
return 0.1f;
}
return reply;
}
private DrawingController<? extends Drawing<? extends FlexoModelObject>> getScreenshotControllerForObject(FlexoModelObject target,
boolean showAll) {
try {
return FlexoSwingUtils.syncRunInEDT(new ScreenshotRetriever(target, showAll));
} catch (Exception e) {
if (logger.isLoggable(Level.SEVERE)) {
logger.log(Level.SEVERE, "Could not retrieve screenshot for " + target, e);
}
return null;
}
}
/**
* @param target
*/
private DrawingController<? extends Drawing<FlexoProcess>> getProcessRepresentationController(WKFObject target, boolean showAll) {
DrawingController<? extends Drawing<FlexoProcess>> controller = null;
ProcessRepresentation pr = (ProcessRepresentation) target.getProcess()._graphicalPropertyForKey("preferredRepresentation");
if (pr == null) {
pr = ProcessRepresentation.BASIC_EDITOR;
}
switch (pr) {
case BASIC_EDITOR:
controller = new ProcessEditorController(target.getProcess(), null, null,
showAll ? org.openflexo.wkf.processeditor.ProcessRepresentation.SHOW_ALL
: new BPEScreenshotProcessRepresentationObjectVisibilityDelegate(target));
break;
case SWIMMING_LANE:
controller = new SwimmingLaneEditorController(target.getProcess(), null, null, showAll ? SwimmingLaneRepresentation.SHOW_ALL
: new SWLScreenshotProcessRepresentationObjectVisibilityDelegate(target));
break;
default:
if (logger.isLoggable(Level.WARNING)) {
logger.warning("Unknown process representation value: " + pr);
}
break;
}
return controller;
}
@Override
public void finalizeScreenshotGeneration(final JComponent screenshot) {
class FinalizeScreenshot implements Callable<Void> {
@Override
public Void call() throws Exception {
if (screenshot != null) {
if (screenshot instanceof DrawingView) {
DrawingController<?> controller = ((DrawingView<?>) screenshot).getController();
drawingControllers.remove(controller.getDrawing());
controller.delete();
} else if (screenshot instanceof FlexoJTree) {
((FlexoJTree) screenshot).getBrowserView().getBrowser().delete();
}
if (screenshot.getParent() != null) {
screenshot.getParent().remove(screenshot);
}
}
return null;
}
}
try {
FlexoSwingUtils.syncRunInEDT(new FinalizeScreenshot());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Overrides moduleWillClose
*
* @see org.openflexo.module.FlexoModule#moduleWillClose()
*/
@Override
public void moduleWillClose() {
super.moduleWillClose();
for (DrawingController<? extends Drawing<? extends FlexoModelObject>> drawingController : drawingControllers.values()) {
drawingController.delete();
}
drawingControllers.clear();
}
@Override
public Object getProcessRepresentation(FlexoProcess process, boolean showAll) {
try {
process.setIgnoreNotifications();
DrawingController<? extends Drawing<? extends FlexoModelObject>> controller = getScreenshotControllerForObject(process, showAll);
return controller.getDrawing();
} finally {
process.resetIgnoreNotifications();
}
}
@Override
public void disposeProcessRepresentation(final Object processRepresentation) {
class DisposeProcessRepresentation implements Callable<Void> {
@Override
public Void call() throws Exception {
DrawingController<? extends Drawing<? extends FlexoModelObject>> drawingController = drawingControllers
.remove(processRepresentation);
if (drawingController != null) {
drawingController.delete();
}
return null;
}
}
try {
FlexoSwingUtils.syncRunInEDT(new DisposeProcessRepresentation());
} catch (Exception e) {
e.printStackTrace();
}
}
}