package de.ovgu.cide.fm.guidsl;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import de.ovgu.cide.Change;
import de.ovgu.cide.ChangeType;
import de.ovgu.cide.ColorListChangedEvent;
import de.ovgu.cide.configuration.AbstractConfigurationPage;
import de.ovgu.cide.configuration.NonValidatingConfigurationListPage;
import de.ovgu.cide.features.AbstractFeatureModel;
import de.ovgu.cide.features.IFeature;
import featureide.fm.core.Feature;
import featureide.fm.core.FeatureModel;
import featureide.fm.core.GrammarFile;
import featureide.fm.core.configuration.Configuration;
import featureide.fm.core.configuration.Selection;
import featureide.fm.core.io.ModelWarning;
import featureide.fm.core.io.UnsupportedModelException;
import featureide.fm.core.io.guidsl.FeatureModelReader;
/**
* this class wraps a feature model from the FeatureIDE implementation.
*
* it additionally stores visibility, colors, and ids separately.
*
*
* @author ckaestne
*
*/
public class GuidslFeatureModelWrapper extends AbstractFeatureModel {
private class ModelResourceChangeListener implements
IResourceChangeListener {
public void resourceChanged(IResourceChangeEvent event) {
checkModelChange(event.getDelta().findMember(
grammarFile.getResource().getFullPath()));
}
private void checkModelChange(IResourceDelta delta) {
if (delta == null
|| (delta.getFlags() & IResourceDelta.CONTENT) == 0)
return;
System.out.println("Model "
+ grammarFile.getResource().getFullPath() + " changed");
Job job = new Job("Load Model") {
protected IStatus run(IProgressMonitor monitor) {
List<Change> changes = new ArrayList<Change>();
for (IFeature f : getFeatures())
changes.add(new Change(f, ChangeType.REMOVE));
loadModel();
for (IFeature f : getFeatures())
changes.add(new Change(f, ChangeType.ADD));
fireFeatureModelChanged(new ColorListChangedEvent(this,
project, changes));
return Status.OK_STATUS;
}
};
job.setPriority(Job.SHORT);
job.schedule();
}
}
private GrammarFile grammarFile;
FeatureModel model;
public ExtraAttributeStorage extraAttributeStorage;
private static WeakHashMap<IProject, WeakReference<GuidslFeatureModelWrapper>> instanceCache = new WeakHashMap<IProject, WeakReference<GuidslFeatureModelWrapper>>();
public static GuidslFeatureModelWrapper getInstance(IProject project) {
WeakReference<GuidslFeatureModelWrapper> fmRef = instanceCache
.get(project);
if (fmRef != null) {
GuidslFeatureModelWrapper fm = fmRef.get();
if (fm != null)
return fm;
}
GuidslFeatureModelWrapper fm = new GuidslFeatureModelWrapper(project);
fmRef = new WeakReference<GuidslFeatureModelWrapper>(fm);
instanceCache.put(project, fmRef);
return fm;
}
private GuidslFeatureModelWrapper(IProject project) {
super(project);
this.grammarFile = new GrammarFile(project.getFile("model.m"));
this.model = new FeatureModel();
this.extraAttributeStorage = new ExtraAttributeStorage(project
.getFile("model.colors"), this);
initResourceListener();
loadModel();
}
private void initResourceListener() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(
new ModelResourceChangeListener(),
IResourceChangeEvent.POST_CHANGE);
}
/**
* Loads the model again from the file. Attend that all local changes in the
* model get lost.
*
* Before loading all error markers will be deleted and afterwards new ones
* might be created if some errors occur.
*/
private void loadModel() {
grammarFile.deleteAllModelMarkers();
try {
FeatureModelReader modelReader = new FeatureModelReader(model);
modelReader.readFromFile(grammarFile.getResource());
for (ModelWarning warning : modelReader.getWarnings())
grammarFile.createModelMarker(warning.message,
IMarker.SEVERITY_WARNING, warning.line);
} catch (IOException e) {
grammarFile.createModelMarker(e.getMessage(),
IMarker.SEVERITY_ERROR, 0);
} catch (UnsupportedModelException e) {
grammarFile.createModelMarker(e.getMessage(),
IMarker.SEVERITY_ERROR, e.lineNumber);
}
}
public IFeature getFeature(long id) {
Feature feature = extraAttributeStorage.findFeatureById(model
.getFeatures(), id);
if (feature != null)
return new FeatureAdapter(feature, this);
return null;
}
public Set<IFeature> getFeatures() {
Collection<Feature> features = model.getFeatures();
Set<IFeature> result = new HashSet<IFeature>(features.size());
for (Feature feature : features) {
if (!feature.isAbstract())
result.add(new FeatureAdapter(feature, this));
}
return result;
}
public void fireFeatureChanged(Feature feature, ChangeType type) {
fireFeatureModelChanged(new ColorListChangedEvent(this, project,
new Change(new FeatureAdapter(feature, this), type)));
}
public AbstractConfigurationPage getConfigurationPage(String pageName) {
try {
// Class.forName("");
return new EquationEditorPage(pageName, this);
} catch (NoClassDefFoundError e) {
return new NonValidatingConfigurationListPage(pageName, this);
}
}
public boolean isValidSelection(Set<IFeature> selection) {
Configuration conf = new Configuration(model, false);
for (IFeature feature : selection)
conf.setManual(feature.getName(), Selection.SELECTED);
return conf.valid();
}
//private Configuration conf = new Configuration(model, true);
private Configuration conf = null;
public void getSelectedAndUnselectedFeatures(
Set<IFeature> featureSelection, Set<IFeature> selected,
Set<IFeature> unSelected) {
if (conf == null)
conf = new Configuration(model, true);
for (IFeature feature : featureSelection)
conf.setManual(feature.getName(), Selection.SELECTED);
for (Feature feature : conf.getSelectedFeatures()) {
if (!feature.isAbstract())
selected.add(new FeatureAdapter(feature, this));
}
for (Feature feature : conf.getUnSelectedFeatures()) {
if (!feature.isAbstract())
unSelected.add(new FeatureAdapter(feature, this));
}
for (IFeature feature : featureSelection)
conf.setManual(feature.getName(), Selection.UNDEFINED);
}
public IFeature createNewFeature() {
throw new UnsupportedOperationException();
}
/**
* to be used only internally in this plugin.
*
* @return
*/
FeatureModel getInternalModel() {
return model;
}
}