blob: 042de86c87783b92e99e6570c12ef1cb5985a2a5 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.gef.viewer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.epf.diagram.model.util.GraphicalDataHelper;
import org.eclipse.epf.diagram.model.util.GraphicalDataManager;
import org.eclipse.epf.diagramming.base.persistence.IDiagramService;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.configuration.ConfigurationHelper;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.edit.VariabilityInfo;
import org.eclipse.epf.library.edit.util.IDiagramManager;
import org.eclipse.epf.library.edit.util.Suppression;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.layout.ProcessAdapterFactoryFilter;
import org.eclipse.epf.library.layout.diagram.DiagramInfo;
import org.eclipse.epf.library.layout.diagram.IActivityDiagramService;
import org.eclipse.epf.library.services.SafeUpdateController;
import org.eclipse.epf.library.util.ResourceHelper;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* Provides service methods for creating diagram images for activity elements
*
* @author Jinhua Xi
* @since 1.0
*/
public class ActivityDiagramService implements IActivityDiagramService {
private Composite parent = null;
private Composite holder = null;
private File pubDir;
private static Map typeMap = new HashMap();
private DiagramInfo diagramInfo = null;
private boolean publishUncreatedADD = true;
private boolean publishADForActivityExtension = true;
static {
typeMap.put(ResourceHelper.DIAGRAM_TYPE_WORKFLOW, new Integer(
IDiagramManager.ACTIVITY_DIAGRAM));
typeMap.put(ResourceHelper.DIAGRAM_TYPE_ACTIVITY_DETAIL, new Integer(
IDiagramManager.ACTIVITY_DETAIL_DIAGRAM));
typeMap.put(ResourceHelper.DIAGRAM_TYPE_WP_DEPENDENCY, new Integer(
IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM));
}
public static int getIntType(String diagramType) {
Integer type = (Integer) typeMap.get(diagramType);
if (type != null) {
return type.intValue();
}
return -1;
}
Shell shell = null;
public ActivityDiagramService() {
this(null, new File(LibraryService.getInstance().getCurrentMethodLibraryPath()));
}
public ActivityDiagramService(File pubDir) {
this(null, pubDir);
}
public ActivityDiagramService(Composite parent, File pubDir) {
this.parent = parent;
this.pubDir = pubDir;
}
private AbstractDiagramGraphicalViewer getDiagramViewer(int diagramType) {
// if the shell window is distroyed, recreate it
if ((this.shell != null) && this.shell.isDisposed()) {
this.parent = null;
this.shell = null;
}
getViewerHolder(parent);
switch (diagramType) {
case IDiagramManager.ACTIVITY_DIAGRAM:
return new ActivityDiagramViewer(holder);
case IDiagramManager.ACTIVITY_DETAIL_DIAGRAM:
return new ActivityDetailDiagramViewer(holder);
case IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM:
return new WPDependencyDiagramViewer(holder);
default:
return null;
}
}
private void getViewerHolder(Composite parent) {
if (parent == null) {
if (shell == null || shell.isDisposed()) {
shell = createShell();
}
shell.open();
parent = shell;
}
if (holder != null) {
holder.dispose();
}
holder = new Composite(parent, SWT.NONE);
holder.setLayoutData(new GridData(1, 1)); // size can't be 0,0
// otherwise the diagram
// will not be painted
holder.setLayout(new GridLayout());
holder.setVisible(false);
}
private Shell createShell() {
Shell shell = null;
Display d = Display.getDefault();
shell = new Shell(d);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
shell.setLayout(layout);
shell.setBounds(0, 0, 0, 0);
shell.setVisible(false);
return shell;
}
public void dispose() {
if ((shell != null) && (!shell.isDisposed())) {
shell.close();
shell.dispose();
}
}
/**
* save the element diagram image and returns the image file url.
*
* @param wrapper
* @param imgPath
* @param diagramType
* @param filter
* IFilter
* @param sup
* Suppression
* @return String the image path relative to the publishing dir
*
* @see org.eclipse.epf.library.layout.diagram.IActivityDiagramService#saveDiagram(java.lang.Object, java.lang.String, java.lang.String, org.eclipse.epf.library.edit.IFilter, org.eclipse.epf.library.edit.util.Suppression)
*/
public DiagramInfo saveDiagram(final Object wrapper, final String imgPath,
final String diagramType, final IFilter filter,
final Suppression sup) {
// initialize the diagramInfo
diagramInfo = null;
// grab the UI thread to avoid thread access error
SafeUpdateController.syncExec(new Runnable() {
public void run() {
__internal_saveDiagram(wrapper, imgPath, diagramType, filter, sup);
}
});
return diagramInfo;
}
private boolean hasUserDefinedDiagram(Activity e, String imgPath, String diagramType) throws Exception
{
// if there is a user defined diagram, use it
org.eclipse.epf.diagram.model.util.DiagramInfo info = new org.eclipse.epf.diagram.model.util.DiagramInfo((Activity)e);
switch (getIntType(diagramType))
{
case IDiagramManager.ACTIVITY_DIAGRAM:
if ( info.canPublishADImage() )
{
return (info.getActivityDiagram() != null) && info.canPublishADImage();
}
break;
case IDiagramManager.ACTIVITY_DETAIL_DIAGRAM:
if ( info.canPublishADDImage() )
{
return (info.getActivityDetailDiagram() != null) && info.canPublishADDImage();
}
break;
case IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM:
if ( info.canPublishWPDImage() )
{
return (info.getWPDDiagram() != null ) && info.canPublishWPDImage();
}
break;
default:
break;
}
return false;
}
private void __internal_saveDiagram(Object wrapper, final String imgPath, String diagramType,
IFilter filter, Suppression sup) {
if ( sup.isSuppressed(wrapper) ) {
return;
}
Object o = TngUtil.unwrap(wrapper);
if (!(o instanceof Activity)) {
return;
}
//MethodElement e = (MethodElement)o;
Activity e = (Activity)o;
// DiagramInfo diagramInfo = null;
Image image = null;
int type = getIntType(diagramType);
if (type < 0) {
return;
}
AbstractDiagramGraphicalViewer viewer = null;
// keep the dirty flag and reset back to avoid make the library dirty
boolean dirtyFlag = e.eResource().isModified();
try {
if ( hasUserDefinedDiagram((Activity)e, imgPath, diagramType) )
{
return;
}
// first check if we need to generate the diagram or not
// if the diagram is supressed, don't generate diagram
// don't create the diagram if it's not there,
// id the diagram does not exist, it's supressed
org.eclipse.epf.uma.Diagram d = GraphicalDataManager.getInstance()
.getUMADiagram((Activity) e, type, false);
// Allow the option to publish 'uncreated' diagrams
// by default, uncreated activity detail diagrams will be published,
// uncreated diagrams of other types will not be published
boolean exist = (d != null);
if (exist) {
if (d.getSuppressed().booleanValue() == true)
return;
// If an extension has its own diagram. Base is replaced or contributed.
// extension diagram shows realized element in undefined location.
// In publishing don't display extension diagram even if it has its own
// diagram if realized elements are coming in through variability.
if(type == GraphicalDataHelper.ACTIVITY_DIAGRAM &&
checkVariability(e, filter,type) != null){
return;
}
}else{
if((type == GraphicalDataHelper.WORK_PRODUCT_DEPENDENCY_DIAGRAM))
return;
// For Activity Diagram un opened extension publish.
if(type == GraphicalDataHelper.ACTIVITY_DIAGRAM){
// If option is not checked, don't generate a diagram
if(!publishADForActivityExtension) return;
//If extension is modified don't generate it.
if(!e.getBreakdownElements().isEmpty())
return;
VariabilityElement calculatedBase = checkVariability(e, filter, type);
if(calculatedBase == null) {
return;
}
wrapper = calculatedBase;
e = (Activity)calculatedBase;
exist = true;
}
if (publishUncreatedADD == false && type == GraphicalDataHelper.ACTIVITY_DETAIL_DIAGRAM){
boolean contributorexist = false;
// This is need, if contributor has a ADD diagra, base don't
// base should generate ADD in browsing.
MethodConfiguration config = null;
if (filter instanceof ProcessAdapterFactoryFilter) {
config = ((ProcessAdapterFactoryFilter) filter)
.getMethodConfiguration();
}
if (config == null)
return;
// Get immediate contributors first, and check immediate contributors
// have anything extra breakdown elements.
List list = ConfigurationHelper.getContributors(e, config);
if(e instanceof Activity){
Iterator iterator = list.iterator();
if(iterator != null){
while(iterator.hasNext()){
Object act = iterator.next();
if(act != null){
org.eclipse.epf.uma.Diagram dx = GraphicalDataManager.getInstance()
.getUMADiagram((Activity) act, type, false);
if(dx != null){
contributorexist = true;
break;
}
}
}
}
}
if(!contributorexist)
return;
}
}
try {
viewer = getDiagramViewer(type);
viewer.loadDiagram(wrapper, !exist, filter, sup);
diagramInfo = viewer.getDiagramInfo();
if (diagramInfo != null && !diagramInfo.isEmpty()) {
image = viewer.createDiagramImage();
if (image != null) {
// save the image
File f = new File(pubDir, imgPath);
// make sure the file is created otherwise exception
File parent = f.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
if (!f.exists()) {
f.createNewFile();
}
OutputStream os = new FileOutputStream(f);
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image.getImageData() };
loader.save(os, SWT.IMAGE_JPEG);
diagramInfo.setImageFilePath(imgPath);
} else {
System.out.println("Unable to create diagram image"); //$NON-NLS-1$
}
}
} catch (RuntimeException e1) {
e1.printStackTrace();
}
// delete the newly created diagram from the library
if (!exist) {
d = GraphicalDataManager.getInstance().getUMADiagram(
(Activity) e, type, false);
if (d != null) {
EcoreUtil.remove(d);
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
// restore the dirty flag
e.eResource().setModified(dirtyFlag);
if (viewer != null) {
viewer.dispose();
}
if (image != null) {
image.dispose();
}
} catch (RuntimeException e1) {
e1.printStackTrace();
}
}
}
private VariabilityElement checkVariability(VariabilityElement e, IFilter filter,
int type) {
MethodConfiguration config = null;
if (filter instanceof ProcessAdapterFactoryFilter) {
config = ((ProcessAdapterFactoryFilter) filter)
.getMethodConfiguration();
}
if (config == null)
return null;
// Get immediate contributors first, and check immediate contributors
// have anything extra breakdown elements.
List list = ConfigurationHelper.getContributors(e, config);
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object next = iterator.next();
if (next instanceof Activity) {
if (!((Activity) next).getBreakdownElements().isEmpty())
return null;
}
}
// Get all Contributors from parent chain and contributor chain for the
// element e.
VariabilityInfo eInfo = ((ProcessAdapterFactoryFilter) filter)
.getVariabilityInfo((VariabilityElement) e);
List contributors = eInfo.getContributors();
VariabilityElement ve = e.getVariabilityBasedOnElement();
if (ve == null) {
return null;
}
Activity replacer = (Activity) ConfigurationHelper.getReplacer(ve,
config);
if (replacer != null) {
ve = replacer;
org.eclipse.epf.uma.Diagram replacerDiagram = GraphicalDataManager
.getInstance().getUMADiagram(replacer, type, false);
if (replacerDiagram != null) {
//anyReplacer.add(replacer);
return replacer;
} else {
return null;
}
} else {
org.eclipse.epf.uma.Diagram baseDiagram = GraphicalDataManager
.getInstance()
.getUMADiagram((Activity) ve, type, false);
if (baseDiagram != null) {
// Check first if baseDiagram is suppressed.
if (baseDiagram.getSuppressed().booleanValue() == true)
return null;
// Find the contributors of Base
VariabilityInfo veInfo = ((ProcessAdapterFactoryFilter) filter)
.getVariabilityInfo((VariabilityElement) ve);
List veContributors = veInfo.getContributors();
if (contributors.size() != veContributors.size()) {
for (Iterator iterator = contributors.iterator(); iterator
.hasNext();) {
Object next = iterator.next();
if (!veContributors.contains(next)) {
if (!((Activity) next).getBreakdownElements()
.isEmpty()) {
return null;
}
}
}
}
return ve;
}else{
// If no base diagram, check base of base had any diagram.
return checkVariability(ve, filter, type);
}
}
}
/**
* Set the window's preference attribute for Activity Detail Diagram.
*
*/
public void setPublishedUnCreatedADD(boolean flag) {
this.publishUncreatedADD = flag;
}
/**
* Set the window's preference attribute for Acitivyt Diagram
*
*/
public void setPublishADForActivityExtension(boolean flag){
this.publishADForActivityExtension = flag;
}
}