/*******************************************************************************
* Copyright (c) 2007 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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
*
* Contributor:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.seam.ui.views;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.navigator.ICommonContentExtensionSite;
import org.eclipse.ui.navigator.ICommonContentProvider;
import org.eclipse.ui.navigator.IExtensionStateModel;
import org.jboss.tools.seam.core.IRole;
import org.jboss.tools.seam.core.ISeamComponent;
import org.jboss.tools.seam.core.ISeamComponentDeclaration;
import org.jboss.tools.seam.core.ISeamElement;
import org.jboss.tools.seam.core.ISeamJavaComponentDeclaration;
import org.jboss.tools.seam.core.ISeamPackage;
import org.jboss.tools.seam.core.ISeamProject;
import org.jboss.tools.seam.core.ISeamScope;
import org.jboss.tools.seam.core.SeamCorePlugin;
import org.jboss.tools.seam.core.SeamCoreMessages;
import org.jboss.tools.seam.core.event.ISeamProjectChangeListener;
import org.jboss.tools.seam.core.event.SeamProjectChangeEvent;
import org.jboss.tools.seam.ui.SeamGuiPlugin;
/**
* Basic type for content providers that add seam components
* tree structure to views based on
* org.eclipse.ui.navigator.CommonNavigator
* Sub-classes need to override methods getChildren(Object)
* and getParent(Object) to specify starting points of the
* seam components sub-trees.
* Content provider for stand-alone view may start from
* the workspace root, while content provider contributing
* to the standard Project Explorer is better to append
* project-specific seam components to that project's node.
*
* @author Viacheslav Kabanovich
*/
public abstract class AbstractSeamContentProvider implements ITreeContentProvider, ISeamProjectChangeListener, ICommonContentProvider {
protected TreeViewer viewer;
IResourceChangeListener listener = null;
Set<ISeamProject> processed = new HashSet<ISeamProject>();
private IExtensionStateModel fStateModel;
IPropertyChangeListener scopePropertyListener;
IPropertyChangeListener layoutPropertyListener;
boolean isFlatLayout = true;
boolean isScopeLable = false;
public AbstractSeamContentProvider() {}
public void init(ICommonContentExtensionSite commonContentExtensionSite) {
fStateModel = commonContentExtensionSite.getExtensionStateModel();
IMemento memento = commonContentExtensionSite.getMemento();
restoreState(memento);
scopePropertyListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (ViewConstants.SCOPE_PRESENTATION.equals(event.getProperty())) {
if (event.getNewValue() != null) {
boolean newValue = ((Boolean) event.getNewValue()).booleanValue();
setIsScopeLable(newValue);
}
}
}
};
fStateModel.addPropertyChangeListener(scopePropertyListener);
layoutPropertyListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (ViewConstants.PACKAGE_STRUCTURE.equals(event.getProperty())) {
if (event.getNewValue() != null) {
boolean newValue = ((Boolean)event.getNewValue()).booleanValue();
setIsFlatLayout(newValue);
}
}
}
};
fStateModel.addPropertyChangeListener(layoutPropertyListener);
}
void setIsFlatLayout(boolean b) {
isFlatLayout = b;
}
void setIsScopeLable(boolean b) {
isScopeLable = b;
}
public Object[] getElements(Object inputElement) {
if(inputElement instanceof IProject) {
ISeamProject p = SeamCorePlugin.getSeamProject((IProject)inputElement, false);
if (p == null) return new Object[0];
if(!processed.contains(p)) {
processed.add(p);
p.addSeamProjectListener(this);
}
return new Object[]{p};
}
return getChildren(inputElement);
}
boolean isNotShowingScopeNodes() {
return isScopeLable; // ScopePresentationActionProvider.isScopePresentedAsLabel();
// if(viewer == null) return false;
// Boolean b = (Boolean)viewer.getData("scopeAsNode");
// return b != null && b.booleanValue();
}
boolean isPackageStructureFlat() {
return isFlatLayout; //ScopePresentationActionProvider.isPackageStructureFlat();
}
public boolean hasChildren(Object element) {
if(element instanceof ISeamComponentDeclaration) return false;
if(element instanceof IRole) return false;
return true;
}
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof ISeamProject) {
ISeamProject project = (ISeamProject)parentElement;
if(isNotShowingScopeNodes()) {
project.resolve();
if(isPackageStructureFlat()) {
return project.getAllPackages().toArray(new Object[0]);
} else {
return project.getPackages().toArray(new Object[0]);
}
}
return project.getScopes();
} else if(parentElement instanceof ISeamScope) {
((ISeamScope)parentElement).getSeamProject().resolve();
if(isPackageStructureFlat()) {
return ((ISeamScope)parentElement).getAllPackages().toArray(new Object[0]);
} else {
return ((ISeamScope)parentElement).getPackages().toArray(new Object[0]);
}
// return ((ISeamScope)parentElement).getComponents().toArray(new Object[0]);
} else if(parentElement instanceof ISeamPackage) {
ISeamPackage p = (ISeamPackage)parentElement;
List<Object> children = new ArrayList<Object>();
for (ISeamComponent c : p.getComponents()) {
children.add(c);
}
if(!isPackageStructureFlat()) {
for (ISeamPackage pc : p.getPackages().values()) {
children.add(pc);
}
}
return children.toArray(new Object[0]);
} else if(parentElement instanceof ISeamComponent) {
List<Object> children = new ArrayList<Object>();
Set<ISeamComponentDeclaration> ds = ((ISeamComponent)parentElement).getAllDeclarations();
children.addAll(ds);
for (ISeamComponentDeclaration d : ds) {
if(d instanceof ISeamJavaComponentDeclaration) {
Set<IRole> rs = ((ISeamJavaComponentDeclaration)d).getRoles();
children.addAll(rs);
}
}
return children.toArray(new Object[0]);
}
return new Object[0];
}
public Object getParent(Object element) {
if(element instanceof IRole) {
ISeamElement p = ((IRole)element).getParent();
return p == null ? p : p.getParent();
} else if(element instanceof ISeamElement) {
if(element instanceof ISeamComponent) {
ISeamComponent c = (ISeamComponent)element;
if(isNotShowingScopeNodes()) {
return c.getSeamProject().getPackage(c);
} else {
ISeamScope s = (ISeamScope)c.getParent();
ISeamPackage p = s.getPackage(c);
return p == null ? s : p;
}
}
return ((ISeamElement)element).getParent();
}
return null;
}
public void projectChanged(SeamProjectChangeEvent event) {
if(viewer != null) {
refresh(event.getSource());
}
}
void refresh(final Object o) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if(viewer != null) {
viewer.refresh(getTreeObject(o));
}
}
});
}
void refresh() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if(viewer != null) {
viewer.refresh();
}
}
});
}
protected Object getTreeObject(Object source) {
return source;
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.viewer = (TreeViewer)viewer;
if(listener == null) {
listener = new ResourceChangeListener();
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener);
}
}
class ResourceChangeListener implements IResourceChangeListener {
ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
public void resourceChanged(IResourceChangeEvent event) {
try {
if (event.getDelta() == null) {
if(event.getType() == IResourceChangeEvent.PRE_DELETE
|| event.getType() == IResourceChangeEvent.PRE_CLOSE) {
handlePreDelete(event.getResource());
}
} else {
event.getDelta().accept(visitor);
}
} catch (CoreException e) {
SeamCorePlugin.getPluginLog().logError(e);
}
}
}
protected void handlePreDelete(IResource resource) {
}
protected void handleProjectAdded(IProject project) {
}
protected void handleProjectInfoChanged(IProject project) {
refresh(project);
}
class ResourceDeltaVisitor implements IResourceDeltaVisitor {
public boolean visit(IResourceDelta delta) throws CoreException {
int kind = delta.getKind();
IResource r = delta.getResource();
if(kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
if(r instanceof IProject) {
if(kind == IResourceDelta.ADDED) {
handleProjectAdded((IProject)r);
}
//Do nothing for IResourceDelta.REMOVED, PRE_DELETE event already was sent.
}
} else if(kind == IResourceDelta.CHANGED) {
IResourceDelta[] cs = delta.getAffectedChildren();
if(cs != null) for (int i = 0; i < cs.length; i++) {
IResource c = cs[i].getResource();
if(c instanceof IFile && c.getName().endsWith(".project")) { //$NON-NLS-1$
handleProjectInfoChanged(c.getProject());
}
}
}
if(r instanceof IProject) return false;
return true;
}
}
public void restoreState(IMemento memento) {
}
public void saveState(IMemento memento) {
}
public void dispose() {
fStateModel.removePropertyChangeListener(layoutPropertyListener);
fStateModel.removePropertyChangeListener(scopePropertyListener);
if(listener != null) {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
listener = null;
}
viewer = null;
if(processed != null) {
for (ISeamProject p : processed) {
p.removeSeamProjectListener(this);
}
processed.clear();
}
fStateModel.removePropertyChangeListener(layoutPropertyListener);
fStateModel.removePropertyChangeListener(scopePropertyListener);
}
}