blob: 6b6a9cbac089480267284d9a433c6af8cdc2bc22 [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.library.layout.elements;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.epf.common.utils.NetUtil;
import org.eclipse.epf.library.LibraryPlugin;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.configuration.ConfigurationHelper;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.layout.ElementLayoutManager;
import org.eclipse.epf.library.layout.IElementLayout;
import org.eclipse.epf.library.layout.LayoutInfo;
import org.eclipse.epf.library.layout.LayoutResources;
import org.eclipse.epf.library.layout.util.XmlElement;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.library.util.ResourceHelper;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.ContentDescription;
import org.eclipse.epf.uma.ContentElement;
import org.eclipse.epf.uma.CustomCategory;
import org.eclipse.epf.uma.DescribableElement;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodElementProperty;
import org.eclipse.epf.uma.MethodLibrary;
import org.eclipse.epf.uma.MethodPlugin;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.epf.uma.WorkOrder;
import org.eclipse.epf.uma.ecore.util.OppositeFeature;
import org.eclipse.epf.uma.util.AssociationHelper;
/**
* The abstract layout for all Method Elements.
*
* @author Jinhua Xi
* @author Kelvin Low
* @sicne 1.0
*/
public abstract class AbstractElementLayout implements IElementLayout {
protected ElementLayoutManager layoutManager;
protected MethodElement element;
protected MethodElement ownerElement;
protected String url = null;
// element element path relative to the publishing root
protected String elementPath = ""; //$NON-NLS-1$
// the back up path to reath the publishing root
protected String backPath = ""; //$NON-NLS-1$
// map of layout file to the output file extention, if the element has more
// than one layout output
protected List layouts = null;
protected MethodElement targetElement = null;
protected boolean showElementLink = true;
protected boolean debug = LibraryPlugin.getDefault().isDebugging();
public AbstractElementLayout() {
}
/**
* if the element's content is target for another element, set it here. for
* example, step content cat target for a Task or a task descriptor
* copyright content can target to different elements.
*
* The purpose of this is that the system will fix the links in the content
* to relative to the target element.
*/
public void setContentTarget(MethodElement targetElement) {
this.targetElement = targetElement;
}
/**
* need to set the owner of the current layout element. In most cases this
* should be the eContainer of the element. This is needed because in some
* situation the element does not have an owner when the object is created.
* For example, the ContentDescription object's eContiner is null if the
* content file is not saved.
*
* @param owner
* MethodElement
*/
public void setElementOwner(MethodElement owner) {
this.ownerElement = owner;
}
/**
* @deprecated
*/
public void setShowElementLink(boolean show) {
this.showElementLink = show;
}
/**
* initialize the layout with the element layout manager and the element.
* @param layoutManager ElementLayoutManager
* @param element MethodElement
*/
public abstract void init(ElementLayoutManager layoutManager,
MethodElement element);
protected void __init(ElementLayoutManager layoutManager,
MethodElement element) {
this.layoutManager = layoutManager;
this.element = element;
if (!ConfigurationHelper.isDescriptionElement(element)) {
if ( !(element instanceof MethodConfiguration) ) {
// make sure the element is loaded with the correct container
// otherwise the element may not have a valid container
// and thus the element content path can't be determined
// this is just a workaround. should we have a better way to make sure the elements are loaded correctly???????????
// 160441 - Missing template files when publish configuration
MethodPlugin plugin = LibraryUtil.getMethodPlugin(element);
if ( plugin == null || plugin.eContainer() == null) {
// this should not happen in publishing mode since the whole library is already loaded
if ( debug && getLayoutMgr().isPublishingMode() ) {
System.out.println("Error: Element without a valid container: " + LibraryUtil.getTypeName(element));
}
LibraryUtil.getMethodPlugins(LibraryService.getInstance().getCurrentMethodLibrary());
}
}
buildPath();
this.url = elementPath + getFileName(ResourceHelper.FILE_EXT_HTML);
}
// this is a workaround.
// we need to pass parameters in the file url,
// however, if the file does not exist, the parameters is not passed over in browsing
// so create a dummy file
if (!this.layoutManager.isPublishingMode() && !(
element instanceof ContentDescription
|| element.eContainer() instanceof ContentDescription
|| element instanceof MethodConfiguration) )
{
try {
String html_file = this.layoutManager.getPublishDir() + this.getFilePath() + getFileName(ResourceHelper.FILE_EXT_HTML);
File f = new File(html_file);
if ( !f.exists() )
{
f.getParentFile().mkdirs();
f.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected void setLayoutInfo(LayoutInfo info) {
if (layouts == null) {
layouts = new ArrayList();
}
layouts.add(info);
}
/**
* return a list of LayoutInfo objects
*
* @return a list of LayoutInfo objects
*/
public List getLayouts() {
return layouts;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getLayoutMgr()
*/
public ElementLayoutManager getLayoutMgr() {
return this.layoutManager;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getElement()
*/
public MethodElement getElement() {
return element;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getType()
*/
public String getType() {
return element.getType().getName();
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getName()
*/
public String getName() {
return element.getName();
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getDisplayName()
*/
public String getDisplayName() {
/*
* String name = null; if (element instanceof ContentElement) { name =
* ((ContentElement)element).getPresentationName(); } if (name == null ||
* name.length() == 0) { name = this.getName(); } return name;
*/
return TngUtil.getPresentationName(element);
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getId()
*/
public String getId() {
return element.getGuid();
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getUrl()
*/
public String getUrl() {
return url;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getBackPath()
*/
public String getBackPath() {
return backPath;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getFilePath()
*/
public String getFilePath() {
return elementPath;
}
/**
* Returns the file path relative to another element. This is the
* relativeTo.backpath + this.elementpath.
*
* @see org.eclipse.epf.library.layout.IElementLayout#getFilePath(IElementLayout)
*/
public String getFilePath(IElementLayout relativeTo) {
return relativeTo.getBackPath() + this.getFilePath();
}
/**
* Returns the file name with the given extension.
*
* @see org.eclipse.epf.library.layout.IElementLayout#getFileName(String)
*/
public String getFileName(String ext) {
return ResourceHelper.getFileName(element, ext);
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getXslUrl()
*/
public String getXslUrl() {
if (element instanceof ContentElement) {
return LayoutResources.getXslUri(getType().toLowerCase(),
"contentelement"); //$NON-NLS-1$
} else {
return LayoutResources.getXslUri(getType().toLowerCase(), null);
}
}
private void buildPath() {
// this is <plugin>/<element type>/
elementPath = "";
backPath = "./";
if ( !(element instanceof MethodConfiguration || element instanceof MethodLibrary) )
{
elementPath = ResourceHelper.getElementPath(element).replace(
File.separatorChar, '/');
backPath = ResourceHelper.getBackPath(element);
}
}
/**
* check if the html content generated from this xsl file needs to be scanned or not
* scan the content is for identifying element references in the content and copy over resource files
* in some cases we don't need to scan the content, for example, the activity breakdown structure
*
* @param xslUrl the xsl that html is generated from, null for the default xsl layout
* @return boolean
*/
public boolean needContentScan(String xslUrl)
{
// by default all contents are scanned
return true;
}
/**
* get the layout for a child element of this element
* ActivityElementLayout should override this method to create layout with node path
* @param child
* @return IElementLayout
*/
protected IElementLayout getChildLayout(MethodElement child)
{
return layoutManager.getLayout(child, true);
}
protected void processChild(Object feature, XmlElement parent, MethodElement e,
boolean includeReferences) {
if (e != null) {
IElementLayout l = getChildLayout(e);
if (l != null) {
// don't include the references of the refereced elements,
// otherwise, may cause deadlock
boolean isContent = (e instanceof MethodElement)
&& ConfigurationHelper
.isDescriptionElement((MethodElement) e);
if (isContent) {
if (targetElement != null) {
l.setContentTarget(targetElement);
}
l.setElementOwner(element);
}
parent.addChild(l.getXmlElement(includeReferences));
}
}
}
protected void processChild(Object feature, XmlElement parent, List items,
boolean includeReferences) {
if (items != null && items.size() > 0) {
for (Iterator it = items.iterator(); it.hasNext();) {
Object e = it.next();
if (e instanceof MethodElement) {
MethodElement me = (MethodElement) e;
e = ConfigurationHelper.getCalculatedElement(me,
layoutManager.getConfiguration());
if (e != null) {
IElementLayout l = getChildLayout(me);
if (l != null) {
// don't include the references of the refereced
// elements, otherwise, may cause deadlock
parent.addChild(l.getXmlElement(ConfigurationHelper
.isDescriptionElement(me) ? true
: includeReferences));
}
}
}
}
}
}
/**
* calculate the to-many references
* @param elementXml XmlElement
* @param includeReferences boolean
*/
public void calculate0nReferences(XmlElement elementXml,
boolean includeReferences) {
// referenceMap.clear();
List properties = element.getInstanceProperties();
if (properties != null) {
// get all string type attributes
for (int i = 0; i < properties.size(); i++) {
EStructuralFeature feature = (EStructuralFeature) properties
.get(i);
if (feature.isMany()) {
loadFeature(feature, elementXml, includeReferences);
}
}
}
}
protected XmlElement getXmlElement() {
XmlElement elementXml = new XmlElement("Element") //$NON-NLS-1$
.setAttribute("Type", getType()) //$NON-NLS-1$
.setAttribute("TypeName", TngUtil.getTypeText(element)) //$NON-NLS-1$
.setAttribute("Name", getName()) //$NON-NLS-1$
.setAttribute("BackPath", getBackPath()) //$NON-NLS-1$
.setAttribute("ShapeiconUrl", getShapeiconUrl()) //$NON-NLS-1$
.setAttribute("DisplayName", getDisplayName()); //$NON-NLS-1$
if ( showElementLink ) {
elementXml.setAttribute("Url", getUrl()); //$NON-NLS-1$
}
return elementXml;
}
/**
* load the attributes
* @param elementXml XmlElement
*/
public void loadAttributes(XmlElement elementXml) {
boolean isActivityAttribute = (element instanceof Activity)
|| (element instanceof ContentDescription)
&& (element.eContainer() instanceof Activity || ownerElement instanceof Activity);
List properties = element.getInstanceProperties();
if (properties != null) {
// get all string type attributes
for (int i = 0; i < properties.size(); i++) {
EStructuralFeature p = (EStructuralFeature) properties.get(i);
if (!(p instanceof EAttribute) ) {
continue;
}
EAttribute attrib = (EAttribute)p;
String name = p.getName();
Object value;
if (name.equals("presentationName")) //$NON-NLS-1$
{
// value = TngUtil.getPresentationName(element);
value = ConfigurationHelper.getPresentationName(element,
layoutManager.getConfiguration());
} else if( isActivityAttribute && String.class.isAssignableFrom(attrib.getEAttributeType().getInstanceClass())) {
// for activity, the way to merge attribute from base is different
value = ConfigurationHelper.getActivityStringAttribute(element, ownerElement, attrib, getLayoutMgr().getConfiguration());
} else {
value = getAttributeFeatureValue(p);
}
elementXml
.newChild("attribute").setAttribute("name", name).setValue((value == null) ? "" : value.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}
/**
* get the attribute feature value and merge the text, fix url referneces, etc.
* @param feature EStructuralFeature
* @return Object
*/
public Object getAttributeFeatureValue(EStructuralFeature feature) {
Object value = ConfigurationHelper.calcAttributeFeatureValue(element,
ownerElement, feature, layoutManager.getConfiguration());
// now if the target is set and is different from the element or the
// element's owner
// then fix the content
if ((targetElement != null) && (value != null)
&& (value.toString().length() > 0)) {
String contentPath = ResourceHelper
.getElementPath((element instanceof ContentDescription) ?
((ownerElement==null) ? (MethodElement) element.eContainer() : ownerElement)
: element);
String backPath = ResourceHelper
.getBackPath((targetElement instanceof ContentDescription) ? (MethodElement) targetElement
.eContainer()
: targetElement);
value = ResourceHelper.fixContentUrlPath(value.toString(),
contentPath, backPath);
}
return value;
}
/**
* load the copyright text
* @param elementXml XmlElement
*/
public void loadCopyright(XmlElement elementXml) {
// List items = new ArrayList();
// ConfigurationHelper.calculateCopyright(element,
// layoutManager.getConfiguration(), items);
// if ( items.size() > 0 )
// {
// SupportingMaterial copyright;
// StringBuffer copyrights = new StringBuffer();
// for ( Iterator it = items.iterator(); it.hasNext(); )
// {
// copyright = (SupportingMaterial) it.next();
// String statement = copyright.getPresentation().getMainDescription();
//
// // need to fix the content for relative links.
// // since the link is a relative path to the SupportingMaterial
// location,
// // need to convert to relative to the current element
// // so re-calcuate the back path
// // jxi, 06/28/05
// String contentPath = ResourceHelper.getElementPath(copyright);
// String backPath = ResourceHelper.getBackPath(element);
// statement = ResourceHelper.fixContentUrlPath(statement, contentPath,
// backPath);
// copyrights.append(statement);
// }
//
// elementXml.newChild("copyright").setValue(copyrights.toString());
// //$NON-NLS-1$
// }
String copyright = ConfigurationHelper.getCopyrightText(element,
layoutManager.getConfiguration());
if (copyright != null && copyright.length() > 0) {
elementXml.newChild("copyright").setValue(copyright); //$NON-NLS-1$
}
}
/**
* calculate the to-one reference
* @param elementXml XmlElement
* @param includeReferences boolean
*/
public void calculate01References(XmlElement elementXml,
boolean includeReferences) {
List properties = element.getInstanceProperties();
if (properties != null) {
// get element references
for (int i = 0; i < properties.size(); i++) {
EStructuralFeature p = (EStructuralFeature) properties.get(i);
// Object value = element.get(i);
EClassifier type = p.getEType();
if (!(type instanceof EClass) || p.isMany()) {
continue;
}
loadFeature(p, elementXml, includeReferences);
}
}
}
/**
* load the non-attribute feature
*
* @param feature
* @param elementXml
* @param includeReferences
*/
public void loadFeature(EStructuralFeature feature, XmlElement elementXml,
boolean includeReferences) {
if (!(feature.getEType() instanceof EClass)) {
return;
}
String name = feature.getName();
if (!feature.isMany()) {
MethodElement e = ConfigurationHelper.calc01FeatureValue(element, ownerElement,
feature, layoutManager.getElementRealizer());
// Browsing stops working when a role is set to
// replaced another role
// for replacer, the base will be evaluated to the replacer
// and causing deadlock
if (e != null && e != element) {
boolean showDetail = (ConfigurationHelper
.isDescriptionElement(e)
/*
* || (p ==
* UmaPackage.eINSTANCE.getMethodUnit_CopyrightStatement())
*/) ? true : includeReferences;
if ( acceptFeatureValue(feature, e) ) {
processChild(feature,
elementXml
.newChild("reference").setAttribute("name", name), e, showDetail); //$NON-NLS-1$ //$NON-NLS-2$
}
}
} else if (feature.isMany()) {
List pv = ConfigurationHelper.calc0nFeatureValue(element, ownerElement, feature,
layoutManager.getElementRealizer());
if ( acceptFeatureValue(feature, pv) ) {
addReferences(feature, elementXml, name, pv);
}
}
}
/**
* load the non-attribute feature
*
* @param feature
* @param elementXml
* @param includeReferences
*/
public void loadFeature(OppositeFeature feature, XmlElement elementXml,
boolean includeReferences) {
String name = feature.getName();
if (!feature.isMany()) {
MethodElement e = ConfigurationHelper.calc01FeatureValue(element,
feature, layoutManager.getElementRealizer());
// Browsing stops working when a role is set to
// replaced another role
// for replacer, the base will be evaluated to the replacer
// and causing deadlock
if (e != null && e != element) {
boolean showDetail = (ConfigurationHelper
.isDescriptionElement(e)
/*
* || (p ==
* UmaPackage.eINSTANCE.getMethodUnit_CopyrightStatement())
*/) ? true : includeReferences;
if ( acceptFeatureValue(feature, e) )
{
processChild(feature,
elementXml
.newChild("reference").setAttribute("name", name), e, showDetail); //$NON-NLS-1$ //$NON-NLS-2$
}
}
} else if (feature.isMany()) {
List pv = ConfigurationHelper.calc0nFeatureValue(element, feature,
layoutManager.getElementRealizer());
if ( acceptFeatureValue(feature, pv) && pv.size() > 0) {
addReferences(feature, elementXml, name, pv);
}
}
}
/**
* load references for the element
* @param elementXml XmlElement
* @param includeReferences boolean
*/
public void loadReferences(XmlElement elementXml, boolean includeReferences) {
List properties = element.getInstanceProperties();
if (properties != null) {
for (int i = 0; i < properties.size(); i++) {
EStructuralFeature feature = (EStructuralFeature) properties
.get(i);
if (feature.getEType() instanceof EClass) {
loadFeature(feature, elementXml, includeReferences);
}
}
}
Collection oppositeProperties = new ArrayList(element.getOppositeFeatures());
for (Iterator z= oppositeProperties.iterator(); z.hasNext(); )
{
OppositeFeature ofeature = (OppositeFeature) z.next();
loadFeature(ofeature, elementXml, includeReferences);
}
}
/**
* add the reference layout to the result
* @param feature Object
* @param elementXml XmlElement
* @param referenceName String
* @param element MethodElement
*/
public void addReference(Object feature, XmlElement elementXml, String referenceName,
MethodElement element) {
processChild(feature,
elementXml
.newChild("reference").setAttribute("name", referenceName), element, false); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* add references to the layout
* @param feature
* @param elementXml
* @param referenceName
* @param items
*/
public void addReferences(Object feature, XmlElement elementXml, String referenceName,
List items) {
processChild(feature,
elementXml
.newChild("referenceList").setAttribute("name", referenceName), items, false); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getXmlElement(boolean)
*/
public XmlElement getXmlElement(boolean includeReferences) {
XmlElement elementXml = getXmlElement();
// load the references
if (includeReferences) {
// load the copyright info
loadCopyright(elementXml);
// load the attributes
loadAttributes(elementXml);
loadReferences(elementXml, false);
}
return elementXml;
}
/**
* some layout need to have the feature values for further processing. So
* this method will be called when a feature is calculated in this abstract
* class
*
* @param name
* @param value
*/
protected boolean acceptFeatureValue(EStructuralFeature feature, Object value) {
return true;
}
protected boolean acceptFeatureValue(OppositeFeature feature, Object value) {
if ( feature == AssociationHelper.DescribableElement_CustomCategories) {
if ( value instanceof CustomCategory ) {
return getPublishCategoryProperty((MethodElement)value);
} else if ( value instanceof List) {
List items = (List)value;
int i = 0;
while ( i < items.size() ) {
MethodElement e = (MethodElement)items.get(i);
if ( !getPublishCategoryProperty(e) ) {
items.remove(i);
} else {
i++;
}
}
return true;
}
}
return true;
}
private boolean getPublishCategoryProperty(MethodElement e) {
MethodElementProperty prop = TngUtil.getPublishCategoryProperty(e);
if ( prop == null ) {
return false;
}
String v = prop.getValue();
if ( v == null || !v.toString().equals("true") ) {
return false;
}
return true;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getShapeiconUrl()
*/
public String getShapeiconUrl() {
URI uri = null;
String imageUrl;
// String imageFile;
if (element instanceof DescribableElement) {
uri = ((DescribableElement) element).getShapeicon();
}
if (uri == null) {
imageUrl = getDefaultShapeiconUrl();
} else {
URI imageUri = ResourceHelper.getRelativeURI(uri, new File(LibraryService
.getInstance().getCurrentMethodLibraryPath()).toURI());
imageUrl = NetUtil.decodedFileUrl(imageUri.toString());
}
// need to copy the image file if it's not in the default directory
if (!imageUrl.startsWith("images/")) //$NON-NLS-1$
{
File source = new File(LibraryService.getInstance()
.getCurrentMethodLibraryPath(), imageUrl);
File dest = new File(getLayoutMgr().getPublishDir(), imageUrl);
ResourceHelper.copyFile(source, dest);
}
return imageUrl;
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getNodeiconUrl()
*/
public String getNodeiconUrl() {
return ""; //$NON-NLS-1$
}
public String getDefaultShapeiconUrl() {
return LayoutResources.getDefaultShapeiconUrl(element.getType()
.getName().toLowerCase());
}
/**
* @see org.eclipse.epf.library.layout.IElementLayout#getDiagramiconUrl()
*/
public String getDiagramiconUrl() {
return "icons/" + element.getType().getName() + ".gif"; //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* this is a shared method to load the work order of the work breakdown
* element. will be used by all work breakdown elemnt layout.
*
* @param elementXml
* XmlElement the parent xml element to load the work order
* layout
*/
protected void loadWorkOrder(XmlElement elementXml) {
EStructuralFeature feature = UmaPackage.eINSTANCE
.getWorkBreakdownElement_LinkToPredecessor();
List items = ConfigurationHelper.calc0nFeatureValue(element, feature,
layoutManager.getElementRealizer());
XmlElement predecessorXml = elementXml
.newChild("referenceList").setAttribute("name", feature.getName()); //$NON-NLS-1$ //$NON-NLS-2$
if (items != null && items.size() > 0) {
for (Iterator it = items.iterator(); it.hasNext();) {
WorkOrder wo = (WorkOrder) it.next();
MethodElement me = (MethodElement) ConfigurationHelper
.calc01FeatureValue(wo, UmaPackage.eINSTANCE
.getWorkOrder_Pred(), layoutManager
.getElementRealizer());
if (me != null) {
IElementLayout l = getChildLayout(me);
if (l != null) {
predecessorXml.addChild(l.getXmlElement(false));
}
}
}
}
}
}