/* FeatureIDE - An IDE to support feature-oriented software development * Copyright (C) 2005-2009 FeatureIDE Team, University of Magdeburg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * See http://www.fosd.de/featureide/ for further information. */ package featureide.fm.ui.views.featuremodeleditview; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.sat4j.specs.TimeoutException; import featureide.fm.core.FeatureModel; import featureide.fm.core.configuration.TreeElement; import featureide.fm.core.editing.Comparison; import featureide.fm.core.editing.ModelComparator; import featureide.fm.ui.FMUIPlugin; import featureide.fm.ui.views.FeatureModelEditView; /** * Calculates the edit category and provides as a content to the view. * * @author Thomas Thuem */ public class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { private static final String DEFAULT_MESSAGE = "Open a feature model."; private static final String CALCULATING_MESSAGE = "Calculating..."; private static final Image DEFAULT_IMAGE = PlatformUI.getWorkbench() .getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT); private static final Image ERROR_IMAGE = PlatformUI.getWorkbench() .getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK); /** * time in seconds after the calculation is aborted by the SAT solver */ private static final int TIMEOUT = 20000; private final FeatureModelEditView view; TreeParent invisibleRoot = new TreeParent(""); public ViewContentProvider(FeatureModelEditView view) { this.view = view; } public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { invisibleRoot = null; } public Object[] getElements(Object parent) { if (parent.equals(view.getViewSite())) return getChildren(invisibleRoot); return getChildren(parent); } public Object getParent(Object child) { if (child instanceof TreeElement) return ((TreeElement) child).getParent(); return null; } public Object[] getChildren(Object parent) { if (parent instanceof TreeElement) return ((TreeElement) parent).getChildren(); return new Object[0]; } public boolean hasChildren(Object parent) { if (parent instanceof TreeElement) return ((TreeElement) parent).hasChildren(); return false; } public void defaultContent() { invisibleRoot.setChild(new TreeObject(DEFAULT_MESSAGE, DEFAULT_IMAGE)); refresh(); } public void calculateContent(FeatureModel oldModel, FeatureModel newModel) { if (oldModel.getRoot() == null || newModel.getRoot() == null) return; invisibleRoot.setChild(new TreeObject(CALCULATING_MESSAGE, DEFAULT_IMAGE)); refresh(); long start = System.nanoTime(); ModelComparator comparator = new ModelComparator(TIMEOUT); Comparison comparison = comparator.compare(oldModel, newModel); String message = null; Image image = null; if (comparison == Comparison.REFACTORING) { message = "Software Product Line has not changed: f <=> f'"; image = FMUIPlugin.getImage("zero.gif"); } else if (comparison == Comparison.GENERALIZATION) { message = "Software Product Line has got some new products: f => f'"; image = FMUIPlugin.getImage("plus.gif"); } else if (comparison == Comparison.SPECIALIZATION) { message = "Software Product Line has lost some products: f <= f'"; image = FMUIPlugin.getImage("minus.gif"); } else if (comparison == Comparison.ARBITRARY) { message = "Software Product Line has lost some products and has got some new: f, f' incomparable"; image = FMUIPlugin.getImage("plusminus.gif"); } else if (comparison == Comparison.OUTOFMEMORY) { message = "Out of memory error!"; image = ERROR_IMAGE; } else if (comparison == Comparison.TIMEOUT) { message = "SAT4J time out!"; image = ERROR_IMAGE; } else { message = "An error has occured!"; image = ERROR_IMAGE; } message += " (" + (System.nanoTime() - start)/1000000 + "msec)"; TreeObject result = new TreeObject(message, image); invisibleRoot.setChild(result); invisibleRoot.addChild(""); invisibleRoot.addChild(new ExampleParent(true, comparator, 1)); invisibleRoot.addChild(new ExampleParent(false, comparator, 1)); invisibleRoot.addChild(""); addStatistics(oldModel, newModel); refresh(); } private void addStatistics(final FeatureModel oldModel, final FeatureModel newModel) { TreeParent statistics = new TreeParent("Statistics", null, true) { @Override public void initChildren() { addStatistics(this, "Before edit version", oldModel); addStatistics(this, "After edit version", newModel); } }; invisibleRoot.addChild(statistics); } private void addStatistics(TreeParent statistics, String text, final FeatureModel model) { TreeParent parent = new TreeParent(text, null, true) { @Override public void initChildren() { int features = model.getNumberOfFeatures(); int concrete = model.countConcreteFeatures(); int terminal = model.countTerminalFeatures(); addChild("Number of features: " + features); addChild("Number of concrete features: " + concrete); addChild("Number of abstract features: " + (features - concrete)); addChild("Number of terminal features: " + terminal); addChild("Number of non-terminal features: " + (features - terminal)); try { addChild("Featur model is valid (not void): " + model.isValid()); } catch (TimeoutException e) { addChild("Featur model is valid (not void): timeout"); } } }; statistics.addChild(parent); } private void refresh() { Display.getDefault().asyncExec(new Runnable() { public void run() { if (!view.getViewer().getControl().isDisposed()) { view.getViewer().refresh(); } } }); } }