blob: 7988df3022062b40df2030c4773202d3840157a8 [file] [log] [blame]
package org.eclipse.stem.ui.views.explorer;
/*******************************************************************************
* Copyright (c) 2008 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 API and implementation
*******************************************************************************/
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
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.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.DelegatingWrapperItemProvider;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.stem.core.CorePlugin;
import org.eclipse.stem.core.common.Identifiable;
import org.eclipse.stem.core.experiment.Experiment;
import org.eclipse.stem.core.graph.Graph;
import org.eclipse.stem.core.model.Decorator;
import org.eclipse.stem.core.model.Model;
import org.eclipse.stem.core.predicate.IdentifiablePredicateExpression;
import org.eclipse.stem.core.scenario.Scenario;
import org.eclipse.stem.core.trigger.Trigger;
import org.eclipse.stem.ui.Activator;
import org.eclipse.stem.ui.Utility;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.progress.UIJob;
/**
* This class is a {@link ITreeContentProvider} for
* {@link IdentifiableInstanceTreeNode}s which appear in the
* {@link CommonNavigator} framework that is used to explore STEM Projects.
*/
@SuppressWarnings("unused")
public class IdentifiableContentProvider implements ITreeContentProvider,
IResourceChangeListener, IResourceDeltaVisitor {
Viewer viewer;
/**
* Default Constructor
*/
public IdentifiableContentProvider() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this,
IResourceChangeEvent.POST_CHANGE);
}
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
Object[] retValue = null;
// Right kind of parent?
if (parentElement instanceof IdentifiableTreeNode) {
// Yes
// if IdentifiableTreeNode
final List<Identifiable> temp = new ArrayList<Identifiable>();
final IdentifiableTreeNode itn = (IdentifiableTreeNode) parentElement;
final IFolder folder = itn.getProject().getFolder(
itn.getFolderName());
// Does the folder exist?
if (folder.exists()) {
// Yes
try {
for (final IResource identifiableFile : folder.members()) {
if(identifiableFile instanceof IFile) {
IFile ifile = (IFile) identifiableFile;
// exclude any operating system files starting with '.'
if((ifile.getName().length()>0)&&( ifile.getName().charAt(0)!='.' ) && !ifile.getName().endsWith("~")) {
try {
final Identifiable identifiable = Utility.getIdentifiable((IFile) identifiableFile);
if(identifiable != null) temp.add(identifiable);
} catch (final Throwable t) {
// here we want to protect the user and allow non STEM files in each Directory
// Just catch any exception and continue
Activator.logInformation("Error loading file "+ifile.getName()+" for display", t);
}
}
} // if instanceOF IFILE else might be folder or some other object created outside of STEM ...
}
} catch (final CoreException ce) {
Activator.logError("", ce);
} // for each IResource folder.members()
} // if folder exists
retValue = temp.toArray();
} else {
retValue = new Object[0];
}
return retValue;
} // getChildren
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(Object element) {
Object retValue = null;
if (element instanceof IdentifiableInstanceTreeNode) {
retValue = ((IdentifiableInstanceTreeNode) element).getParent();
} // if IdentifiableInstanceTreeNode
return retValue;
}
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
Object[] children = getChildren(element);
return children != null && children.length > 0;
}
/**
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
return null;
}
/**
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
}
/**
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.viewer = viewer;
((StructuredViewer)viewer).setComparer(new IElementComparer() {
public int hashCode(Object element) {
return element.hashCode();
}
public boolean equals(Object a, Object b) {
Object aRep=a, bRep=b;
while(aRep instanceof DelegatingWrapperItemProvider)
aRep = ((DelegatingWrapperItemProvider)aRep).getValue();
while(bRep instanceof DelegatingWrapperItemProvider)
bRep = ((DelegatingWrapperItemProvider)bRep).getValue();
if(aRep instanceof Identifiable && bRep instanceof Identifiable)
return ((Identifiable)aRep).getURI().toString().equals(((Identifiable)bRep).getURI().toString());
return aRep.equals(bRep);
}
});
}
/**
* @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org
* .eclipse.core.resources.IResourceChangeEvent)
*/
public void resourceChanged(final IResourceChangeEvent event) {
try {
event.getDelta().accept(this);
} catch (final CoreException e) {
Activator.logError("", e);
}
} // resourceChanged
/**
* @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core
* .resources.IResourceDelta)
*/
public boolean visit(final IResourceDelta delta) throws CoreException {
final IResource source = delta.getResource();
IPath path = delta.getFullPath();
/* Activator.logInformation("Path: "+path);
if((delta.getKind()&IResourceDelta.ADDED) == IResourceDelta.ADDED) Activator.logInformation("ADDED");
if((delta.getKind()&IResourceDelta.ADDED_PHANTOM) == IResourceDelta.ADDED_PHANTOM) Activator.logInformation("ADDED_PHANTOM");
if((delta.getKind()&IResourceDelta.ALL_WITH_PHANTOMS) == IResourceDelta.ALL_WITH_PHANTOMS) Activator.logInformation("ALL_WITH_PHANTOMS");
if((delta.getKind()&IResourceDelta.CHANGED) == IResourceDelta.CHANGED) Activator.logInformation("CHANGED");
if((delta.getKind()&IResourceDelta.CONTENT) == IResourceDelta.CONTENT) Activator.logInformation("CONTENT");
if((delta.getKind()&IResourceDelta.COPIED_FROM) == IResourceDelta.COPIED_FROM) Activator.logInformation("COPIED_FROM");
if((delta.getKind()&IResourceDelta.DESCRIPTION) == IResourceDelta.DESCRIPTION) Activator.logInformation("DESCRIPTION");
if((delta.getKind()&IResourceDelta.ENCODING) == IResourceDelta.ENCODING) Activator.logInformation("ENCODING");
if((delta.getKind()&IResourceDelta.LOCAL_CHANGED) == IResourceDelta.LOCAL_CHANGED) Activator.logInformation("LOCAL_CHANGED");
if((delta.getKind()&IResourceDelta.MARKERS) == IResourceDelta.MARKERS) Activator.logInformation("MARKERS");
if((delta.getKind()&IResourceDelta.MOVED_FROM) == IResourceDelta.MOVED_FROM) Activator.logInformation("MOVED_FROM");
if((delta.getKind()&IResourceDelta.MOVED_TO) == IResourceDelta.MOVED_TO) Activator.logInformation("MOVED_TO");
//if((delta.getKind()&IResourceDelta.NO_CHANGE) == IResourceDelta.NO_CHANGE) Activator.logInformation("NO_CHANGE");
if((delta.getKind()&IResourceDelta.OPEN) == IResourceDelta.OPEN) Activator.logInformation("OPEN");
if((delta.getKind()&IResourceDelta.REMOVED) == IResourceDelta.REMOVED) Activator.logInformation("REMOVED");
if((delta.getKind()&IResourceDelta.REMOVED_PHANTOM) == IResourceDelta.REMOVED_PHANTOM) Activator.logInformation("REMOVED_PHANTOM");
if((delta.getKind()&IResourceDelta.REPLACED) == IResourceDelta.REPLACED) Activator.logInformation("REPLACED");
if((delta.getKind()&IResourceDelta.REMOVED_PHANTOM) == IResourceDelta.REMOVED_PHANTOM) Activator.logInformation("REMOVED_PHANTOM");
if((delta.getKind()&IResourceDelta.REPLACED) == IResourceDelta.REPLACED) Activator.logInformation("REPLACED");
if((delta.getKind()&IResourceDelta.SYNC) == IResourceDelta.SYNC) Activator.logInformation("SYNC");
if((delta.getKind()&IResourceDelta.TYPE) == IResourceDelta.TYPE) Activator.logInformation("TYPE");
*/
URI uri = URI.createPlatformResourceURI(path.toString(), false);
for(Resource r: org.eclipse.stem.core.Utility.resourceSet.getResources())
if(r.getURI().equals(uri)) {
r.setModified(true);
break;
}
switch ( source.getType() ) {
case IResource.FOLDER:
final IFolder f = (IFolder)source;
new UIJob("Update Folder") {
public IStatus runInUIThread(IProgressMonitor monitor) {
if (viewer != null
&& !viewer.getControl().isDisposed()) {
refreshViewer((CommonViewer)viewer, f);
}
return Status.OK_STATUS;
}
}.schedule();
break;
case IResource.ROOT:
new UIJob("Update Root") {
public IStatus runInUIThread(IProgressMonitor monitor) {
if (viewer != null
&& !viewer.getControl().isDisposed()) {
refreshViewer((CommonViewer)viewer, source);
}
return Status.OK_STATUS;
}
}.schedule();
break;
case IResource.PROJECT:
final IProject project = (IProject)source;
new UIJob("Update Project") {
public IStatus runInUIThread(IProgressMonitor monitor) {
if (viewer != null
&& !viewer.getControl().isDisposed()) {
refreshViewer((CommonViewer)viewer, project);
}
return Status.OK_STATUS;
}
}.schedule();
break;
case IResource.FILE:
final IFile file = (IFile) source;
// When files are updated, we need to mark as modified other files that also needs to
// be refreshed since they are indirectly referencing the changed file
this.markIndirectFiles(delta);
new UIJob("Update File") {
public IStatus runInUIThread(IProgressMonitor monitor)
{
if (viewer != null
&& !viewer.getControl().isDisposed()) {
refreshViewer((CommonViewer)viewer, file);
}
return Status.OK_STATUS;
}
}.schedule();
return false;
default:
break;
}
return true;
} // visit
private void refreshViewer(CommonViewer v, Object elm) {
TreePath [] expPaths = v.getExpandedTreePaths();
v.refresh(elm);
// The last element in the tree paths containing models, scenarios etc. have
// potentially been reloaded in the viewer, so the values in expPaths are
// wrong. We need to find the new ones and expand those.
ArrayList<TreeItem>allItems = new ArrayList<TreeItem>();
getAllItems(v.getControl(), allItems);
ArrayList<TreePath> newPathsToExpand = new ArrayList<TreePath>();
for(TreePath tp:expPaths) {
Object lastSeg = tp.getLastSegment();
while(lastSeg instanceof DelegatingWrapperItemProvider)
lastSeg = ((DelegatingWrapperItemProvider)lastSeg).getValue();
if(lastSeg instanceof Identifiable) {
// See if we can find the new identifiable object in the list of items
boolean foundNewPath = false;
for(TreeItem ti:allItems) {
Object data = ti.getData();
while(data instanceof DelegatingWrapperItemProvider)
data = ((DelegatingWrapperItemProvider)data).getValue();
// Activator.logInformation("Comparing "+data+" with "+lastSeg);
if(data instanceof Identifiable &&
((Identifiable)data).getURI().equals(((Identifiable)lastSeg).getURI()) &&
!data.equals(lastSeg))
{
Object [] segments = new Object[tp.getSegmentCount()];
int i = 0;
for(i=0;i<tp.getSegmentCount()-1;++i) segments[i] = tp.getSegment(i);
segments[i] = ti.getData();
TreePath newPath = new TreePath(segments);
newPathsToExpand.add(newPath);
foundNewPath = true;
}
}
if(!foundNewPath) {
// Try and expand anyway using the old object
Object [] segments = new Object[tp.getSegmentCount()];
int i=0;
for(i=0;i<tp.getSegmentCount();++i) segments[i] = tp.getSegment(i);
TreePath newPath = new TreePath(segments);
newPathsToExpand.add(newPath);
}
}
}
v.setExpandedTreePaths(expPaths);
for(TreePath tp:newPathsToExpand)
v.expandToLevel(tp, 1);
}
private void getAllItems(Object o, ArrayList<TreeItem>items) {
if(o instanceof Tree)
for(TreeItem t:((Tree)o).getItems()) {
items.add(t);
for(TreeItem t2:t.getItems())
getAllItems(t2, items);
}
if(o instanceof TreeItem)
for(TreeItem t:((TreeItem)o).getItems()) {
items.add(t);
getAllItems(t, items);
}
}
private static class MyRunnable implements Runnable {
public IEditorReference [] references;
public void run() {
references = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences();
}
public IEditorReference [] getReferences() {
return references;
}
}
/**
* In STEM, models contain other models and graphs, and scenarios contain other models etc. When a resource is changed, we need to see
* what other resources are potentially affected and need to be marked as modified
*
* @param delta The delta
*/
private void markIndirectFiles(IResourceDelta delta) {
URI uri = URI.createPlatformResourceURI(delta.getResource().getFullPath().toString(), false);
//String filename = uri.lastSegment();
String project = getProject(uri);
String type = getType(uri);
MyRunnable runnable = new MyRunnable();
final IEditorReference [] editorReferences;
Display.getDefault().syncExec(runnable);
editorReferences = runnable.getReferences();
// We need to get a snapshot of the resources currently in the resource set since
// the loop below could potentially add more elements to the list inside it.
EList<Resource> resSnap = new BasicEList<Resource>();
synchronized(org.eclipse.stem.core.Utility.resourceSet) {
for(Resource r:org.eclipse.stem.core.Utility.resourceSet.getResources()) resSnap.add(r);
// The reason we do not release the synchronization lock here
// is that Utility.getIdentifiable(...) could be called asynchronously
// by the project explorer tree viewer, and the method will iterate
// over the resources searching for a match. That loop need to be
// protected by calls below adding new resources to the resource set.
for(Resource r:resSnap) {
String p_project = getProject(r.getURI());
if(!project.equals(p_project)) continue;
EList<EObject> content = r.getContents();
if(content == null || content.size() == 0) continue;
EObject first = content.get(0);
URI u = ((Identifiable)first).getURI();
if(u == null) continue;
if(u.equals(uri)) {
r.setModified(true);
r.unload();
continue;
}
String proj = getProject(u);
if(proj == null) continue;
if(!proj.equals(project)) continue; // wrong project
boolean modified = false;
if(type.equals("models")) {
if(!(first instanceof Model) && !(first instanceof Scenario)
&& !(first instanceof Experiment)) continue; // only models,scenarios and experiments contain other models
if(first instanceof Model)
modified = checkModel((Model)first, uri);
else if(first instanceof Scenario)
modified = checkScenario((Scenario)first, uri);
else if(first instanceof Experiment)
modified = checkExperiment((Experiment)first, uri);
if(modified) r.setModified(true);
} else if(type.equals("decorators")) {
if(!(first instanceof Model) && !(first instanceof Scenario)) continue; // only models and scenarios contain decorators
if(first instanceof Model)
modified = checkModelDecorators((Model)first, uri);
else if(first instanceof Scenario)
modified = checkScenarioDecorators((Scenario)first, uri);
} else if(type.equals("graphs")) {
if(!(first instanceof Model) && !(first instanceof Scenario)) continue; // only models & scenarios contain graphs
if(first instanceof Model) modified = checkModelGraphs((Model)first, uri);
else modified = checkScenarioGraphs((Scenario)first, uri);
} else if (type.equals("predicates")) {
if(!(first instanceof Scenario) && !(first instanceof Trigger)) continue; // Only scenarios & triggers & boolean expressions have predicates in them
if(first instanceof Scenario) modified = checkScenarioPredicate((Scenario)first, uri);
else modified = checkTriggerPredicate((Trigger)first, uri);
} else if(type.equals("modifiers")) {
if(!(first instanceof Scenario) && !(first instanceof Trigger)) continue; // Only scenarios & triggers have modifiers in them
if(first instanceof Scenario) modified = checkScenarioModifier((Scenario)first, uri);
else modified = checkTriggerModifier((Trigger)first, uri);
} else if(type.equals("triggers")) {
if(!(first instanceof Scenario)) continue; // Only scenarios have triggers in them
modified = checkScenarioTriggers((Scenario)first, uri);
}
if(modified)
r.setModified(true);
} // for each resource
// Finally check any editors open that needs to be reloaded
checkEditors(editorReferences, uri);
}
} // resourceSet is not thread safe
private void checkEditors(IEditorReference [] editorReferences, URI uri) {
/* for(IEditorReference ier:editorReferences) {
Activator.logInformation(ier);
try {
IEditorInput input = ier.getEditorInput();
FileEditorInput fei = (FileEditorInput)input;
IEditorPart editor = ier.getEditor(false);
} catch(Exception e) {
e.printStackTrace();
}
}
*/
}
private boolean checkModel(Model model, URI modifiedURI) {
if(model == null || modifiedURI == null)
CorePlugin.logError("Null model", new Exception());
if(model.getURI().lastSegment().equals(modifiedURI.lastSegment())) return true;
for(Model m:model.getModels()) {
boolean modified = checkModel(m, modifiedURI);
if(modified) return true;
}
return false;
}
private boolean checkScenario(Scenario scenario, URI modifiedURI) {
Model m = scenario.getModel();
if(m == null) return false; // no model in scenario
return checkModel(m, modifiedURI);
}
private boolean checkExperiment(Experiment experiment, URI modifiedURI) {
Scenario scenario = experiment.getScenario();
if(scenario == null) return false;
return checkScenario(scenario, modifiedURI);
}
private boolean checkModelDecorators(Model model, URI modifiedURI) {
if(model == null || modifiedURI == null)
CorePlugin.logError("Null model or decorator", new Exception());
for(Decorator d:model.getNodeDecorators())
if(d.getURI().lastSegment().equals(modifiedURI.lastSegment())) return true;
// Check sub model
for(Model m:model.getModels()) {
boolean modified = checkModelDecorators(m, modifiedURI);
if(modified) return true;
}
return false;
}
private boolean checkScenarioDecorators(Scenario scenario, URI modifiedURI) {
Model m = scenario.getModel();
if(m == null) return false;
boolean modified = checkModelDecorators(m, modifiedURI);
if(modified) return true;
// Check scenario decorator
for(Decorator d:scenario.getScenarioDecorators())
if(!d.eIsProxy() && d.getURI().lastSegment().equals(modifiedURI.lastSegment())) return true;
return false;
}
private boolean checkModelGraphs(Model model, URI modifiedURI) {
if(model == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
for(Graph g:model.getGraphs())
if(g.getURI().lastSegment().equals(modifiedURI.lastSegment())) return true;
// Check sub model
for(Model m:model.getModels()) {
boolean modified = checkModelGraphs(m, modifiedURI);
if(modified) return true;
}
return false;
}
private boolean checkScenarioGraphs(Scenario scenario, URI modifiedURI) {
if(scenario == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
Model m = scenario.getModel();
return checkModelGraphs(m, modifiedURI);
}
private boolean checkScenarioPredicate(Scenario scenario, URI modifiedURI) {
if(scenario == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
for(Decorator d : scenario.getScenarioDecorators())
if(d instanceof Trigger) {
Trigger tg = (Trigger)d;
IdentifiablePredicateExpression ipe = (IdentifiablePredicateExpression)tg.getPredicate();
if(ipe != null && ipe.getURI().equals(modifiedURI))
return true;
}
return false;
}
private boolean checkTriggerPredicate(Trigger trigger, URI modifiedURI) {
if(trigger == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
IdentifiablePredicateExpression ipe = (IdentifiablePredicateExpression)trigger.getPredicate();
if(ipe != null && ipe.getURI().equals(modifiedURI))
return true;
return false;
}
private boolean checkScenarioModifier(Scenario scenario, URI modifiedURI) {
if(scenario == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
for(Decorator d : scenario.getScenarioDecorators())
if(d instanceof Trigger) {
Trigger tg = (Trigger)d;
for(Decorator dec:tg.getActions()) {
if(dec.getURI().equals(modifiedURI))
return true;
}
}
return false;
}
private boolean checkScenarioTriggers(Scenario scenario, URI modifiedURI) {
if(scenario == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
for(Decorator d : scenario.getScenarioDecorators())
if(d instanceof Trigger) {
Trigger tg = (Trigger)d;
if(tg.getURI().equals(modifiedURI))
return true;
}
return false;
}
private boolean checkTriggerModifier(Trigger trigger, URI modifiedURI) {
if(trigger == null || modifiedURI == null)
CorePlugin.logError("Null model or uri", new Exception());
for(Decorator dec:trigger.getActions()) {
if(dec != null && dec.getURI() != null && dec.getURI().equals(modifiedURI))
return true;
}
return false;
}
private String getProject(URI uri) {
if(!uri.toString().startsWith("platform:/resource")) return null;
String s1 = uri.toString().substring(19); // "platform:/resource"
int is = s1.indexOf("/");
String project = s1.substring(0, is);
return project;
}
private String getType(URI uri) {
if(!uri.toString().startsWith("platform:/resource")) return null;
String s1 = uri.toString().substring(19); // "platform:/resource"
int is = s1.indexOf("/");
String _project = s1.substring(is+1);
int is2 = _project.indexOf("/");
if(is2 == -1) return ""; // no type
String type = _project.substring(0, is2);
return type;
}
} // IdentifiableContentProvider