package org.bundlemaker.core.ui.artifact.tree;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.bundlemaker.core.BundleMakerCore;
import org.bundlemaker.core.analysis.AnalysisCore;
import org.bundlemaker.core.analysis.IAnalysisModelModifiedListener;
import org.bundlemaker.core.analysis.IBundleMakerArtifact;
import org.bundlemaker.core.analysis.IRootArtifact;
import org.bundlemaker.core.analysis.IVirtualRoot;
import org.bundlemaker.core.parser.IParserAwareBundleMakerProject;
import org.bundlemaker.core.resource.IModularizedSystem;
import org.bundlemaker.core.ui.artifact.Activator;
import org.bundlemaker.core.ui.artifact.configuration.IArtifactModelConfigurationProvider;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
/**
* <p>
* </p>
*
* @author Kai Lehmann
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class ArtifactTreeContentProvider implements ITreeContentProvider, IVirtualRootContentProvider {
/** EMPTY_OBJECT_ARRAY */
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* Listener used to refresh navigator on artifact model changes
*/
private final RefreshArtifactTreeModelModifiedListener ARTIFACT_TREE_MODEL_MODIFIED_LISTENER = new
RefreshArtifactTreeModelModifiedListener();
/** - */
private boolean _showRoot;
/** needed to show the root in the tree viewer, see [BM-165 Show Root-Node in Dependency Tree / XRef View] */
private IRootArtifact _virtualRoot;
private Viewer _viewer;
/**
* <p>
* Creates a new instance of type {@link ArtifactTreeContentProvider}.
* </p>
*/
public ArtifactTreeContentProvider() {
this(false);
}
/**
* <p>
* Creates a new instance of type {@link ArtifactTreeContentProvider}.
* </p>
*
* @param _showRoot
*/
public ArtifactTreeContentProvider(boolean _showRoot) {
this._showRoot = _showRoot;
}
/**
* {@inheritDoc}
*/
@Override
public IRootArtifact getVirtualRoot() {
return _virtualRoot;
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getChildren(Object parent) {
if (parent instanceof IProject) {
IProject project = (IProject) parent;
try {
//
if (project.hasNature(BundleMakerCore.NATURE_ID)) {
//
IParserAwareBundleMakerProject bundleMakerProject = BundleMakerCore
.getBundleMakerProject(project).adaptAs(
IParserAwareBundleMakerProject.class);
//
Collection<IModularizedSystem> modularizedSystems = bundleMakerProject.getModularizedSystemWorkingCopies();
List<IBundleMakerArtifact> result = new LinkedList<IBundleMakerArtifact>();
for (IModularizedSystem modularizedSystem : modularizedSystems) {
//
// modularizedSystem.applyTransformations();
IArtifactModelConfigurationProvider artifactModelConfigurationProvider = Activator.getDefault()
.getArtifactModelConfigurationProvider();
IRootArtifact artifact = AnalysisCore.getAnalysisModel(modularizedSystem,
artifactModelConfigurationProvider
.getArtifactModelConfiguration());
// // TODO!
artifact.addAnalysisModelModifiedListener(ARTIFACT_TREE_MODEL_MODIFIED_LISTENER);
result.add(artifact);
}
//
return result.toArray();
}
} catch (Exception e) {
e.printStackTrace();
}
//
return EMPTY_OBJECT_ARRAY;
} else if (parent instanceof IBundleMakerArtifact) {
return ((IBundleMakerArtifact) parent).getChildren().toArray();
}
return EMPTY_OBJECT_ARRAY;
}
@Override
public Object getParent(Object input) {
if (input instanceof IBundleMakerArtifact) {
if (_showRoot && ((IBundleMakerArtifact) input).getParent() instanceof IRootArtifact) {
return _virtualRoot;
} else {
return ((IBundleMakerArtifact) input).getParent();
}
}
//
return null;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasChildren(Object parent) {
return getChildren(parent).length > 0;
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getElements(Object parent) {
if (_showRoot && parent instanceof IRootArtifact) {
if (_virtualRoot == null) {
_virtualRoot = newVirtualRoot((IRootArtifact) parent);
}
return new Object[] { _virtualRoot };
} else {
return getChildren(parent);
}
}
@Override
public void dispose() {
if (_virtualRoot != null) {
_virtualRoot.getRoot().removeAnalysisModelModifiedListener(ARTIFACT_TREE_MODEL_MODIFIED_LISTENER);
}
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
_viewer = viewer;
if (newInput != null && newInput instanceof IRootArtifact) {
_virtualRoot = newVirtualRoot((IRootArtifact) newInput);
_virtualRoot.getRoot().addAnalysisModelModifiedListener(ARTIFACT_TREE_MODEL_MODIFIED_LISTENER);
} else {
if (_virtualRoot != null) {
_virtualRoot.getRoot().removeAnalysisModelModifiedListener(ARTIFACT_TREE_MODEL_MODIFIED_LISTENER);
}
_virtualRoot = null;
}
}
/**
* Create a new instance of a "virtual root" that delegates to an existing IRootArtifact
*
* @param rootArtifact
* @return
*/
private IRootArtifact newVirtualRoot(final IRootArtifact rootArtifact) {
return (IRootArtifact) Proxy.newProxyInstance
(rootArtifact
.getClass().getClassLoader(),
new Class[] { IRootArtifact.class, IVirtualRoot.class },
new VirtualRootInvocationHandler(rootArtifact));
}
class VirtualRootInvocationHandler implements InvocationHandler {
private final IRootArtifact _rootArtifact;
private VirtualRootInvocationHandler(IRootArtifact rootArtifact) {
this._rootArtifact = rootArtifact;
}
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (isEqualsMethod(method)) {
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
}
if (isHashCodeMethod(method)) {
return new Integer(System.identityHashCode(proxy));
}
if (isToStringMethod(method)) {
return proxy.getClass().getName() + '@' +
Integer.toHexString(proxy.hashCode());
}
if (method.getDeclaringClass() == IVirtualRoot.class) {
return this._rootArtifact;
}
return method.invoke(_rootArtifact, args);
}
/**
* Determine whether the given method is an "equals" method.
*
* @see java.lang.Object#equals(Object)
*/
private boolean isEqualsMethod(Method method) {
if (method == null || !method.getName().equals("equals")) {
return false;
}
Class<?>[] paramTypes = method.getParameterTypes();
return (paramTypes.length == 1 && paramTypes[0] == Object.class);
}
/**
* Determine whether the given method is a "hashCode" method.
*
* @see java.lang.Object#hashCode()
*/
private boolean isHashCodeMethod(Method method) {
return (method != null && method.getName().equals("hashCode") && method.getParameterTypes().length == 0);
}
/**
* Determine whether the given method is a "toString" method.
*
* @see java.lang.Object#toString()
*/
private boolean isToStringMethod(Method method) {
return (method != null && method.getName().equals("toString") && method.getParameterTypes().length == 0);
}
}
class RefreshArtifactTreeModelModifiedListener implements IAnalysisModelModifiedListener {
@Override
public void analysisModelModified() {
if (_viewer != null) {
getDisplay().syncExec(
new Runnable() {
@Override
public void run() {
_viewer.refresh();
}
});
}
//
// CommonNavigatorUtils.update(CommonNavigatorUtils.PROJECT_EXPLORER_VIEW_ID);
}
private Display getDisplay() {
Display display = Display.getCurrent();
// may be null if outside the UI thread
if (display == null)
display = Display.getDefault();
return display;
}
}
}