//------------------------------------------------------------------------------ // 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.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().getCurrentMethodLibraryLocation())); } 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; } public Activity getRealizedForUnmodified(Object activity, IFilter filter, Suppression suppression) { // Does nothing, just interface implementation. return null; } }