/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.reuseware.coconut.description.browse.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.ecore.OCL;
import org.eclipse.ocl.ecore.OCLExpression;
import org.eclipse.ocl.ecore.OCL.Helper;
import org.eclipse.ocl.ecore.OCL.Query;
import org.eclipse.ocl.expressions.Variable;
import org.reuseware.coconut.description.BrowserState;
import org.reuseware.coconut.description.DescriptionPackage;
import org.reuseware.coconut.description.Facet;
import org.reuseware.coconut.description.FacetType;
import org.reuseware.coconut.description.FacetTypeDecorator;
import org.reuseware.coconut.description.FacetValue;
import org.reuseware.coconut.description.FacetValueDecorator;
import org.reuseware.coconut.description.FragmentDescription;
import org.reuseware.coconut.description.GUIState;
import org.reuseware.coconut.description.browse.BrowserStateManager;
import org.reuseware.coconut.description.browse.MainBrowserManager;
import org.reuseware.coconut.description.classify.DescriptionManager;
import org.reuseware.coconut.description.classify.views.facet.ZoomListener;
import org.reuseware.coconut.reuseextension.util.ocl.EnhancedEcoreEnvironmentFactory;
/**
* This singleton class implements the <code>ZoomListener</code> interface to
* perform a zoom-step using an OCL constrain given by the description meta
* model.
*
* @author Matthias Schmidt
*
*/
public class OCLZoomer extends ZoomListener {
private int c;
private static final OCL OCL_ENV = OCL.newInstance(new EnhancedEcoreEnvironmentFactory());
public static String QUERY = "if self.facets->exists(f | f.type = filterFacet.type) then self.facets->any(f | f.type = filterFacet.type).values->exists(v | filterFacet.values->exists(fv | v = fv)) else false endif";
protected OCLZoomer() {
super();
c = 0;
}
/**
* Retrieves the single instance of the <code>OCLZoomer</code>.
*
* @return The one and only instance of <code>OCLZoomer</code>.
*/
public static ZoomListener getInstance() {
if (instance == null)
instance = new OCLZoomer();
return instance;
}
/*
* (non-Javadoc)
*
* @see
* org.reuseware.coconut.description.classify.views.util.ZoomListener#zoom
* (org.reuseware.coconut.description.FacetType)
*/
@Override
public void zoom(FacetType type, boolean lazy) {
Facet facet = DescriptionManager.buildFacet(type, new ArrayList<FacetValue>());
zoom(facet, lazy);
}
@Override
public void zoom(Facet facet, boolean lazy) {
BrowserStateManager stateManager = MainBrowserManager.getInstance()
.getBrowserStateManager();
BrowserState state = stateManager.getState();
// update state with new selected facet
for (FacetTypeDecorator tDecor : state.getPresentedFacets()) {
if (tDecor.getSelection() == null)
continue;
if (tDecor.getSelection().getType().equals(facet.getType())) {
tDecor.setSelection(facet);
break;
}
}
state = zoomContent(state, facet);
if (!lazy) {
state = zoomFacetValues(state, facet);
state.setGuiState(GUIState.REFRESH_VALUE_COUNTS);
}
stateManager.setState(state, lazy);
}
/*
* (non-Javadoc)
* @see org.reuseware.coconut.description.classify.views.util.ZoomListener#zoomContent(org.reuseware.coconut.description.BrowserState, org.reuseware.coconut.description.Facet)
*/
@Override
public BrowserState zoomContent(BrowserState state, Facet facet) {
state.getFilteredContent().clear();
List<FragmentDescription> filtered = performZoom(state, facet, true);
state.getFilteredContent().addAll(filtered);
return state;
}
/**
* Second refresh the lasting <code>FacetTypeDecorator</code>s which can be
* used to perform the next zoom-step. The attribute <code>valueCount</code>
* of each <code>FacetValueDecorator</code> of these types need changing
* because the content has changed.
*
* @param state
* The <code>BrowserState</code> we are working on.
* @param facet
* The <code>Facet</code> which describes the current zoom-step.
* @return The refreshed <code>BrowserState</code>.
*/
private BrowserState zoomFacetValues(BrowserState state, Facet facet) {
// build list of lasting decorators
List<FacetTypeDecorator> tDecors = new ArrayList<FacetTypeDecorator>();
tDecors.addAll(state.getPresentedFacets());
tDecors.addAll(state.getAdditionalFacets());
// refresh the value counts
for (FacetTypeDecorator tDecor : tDecors) {
calcValueCounts(tDecor, state);
}
return state;
}
/*
* (non-Javadoc)
*
* @seeorg.reuseware.coconut.description.classify.views.util.ZoomListener#
* calcValueCounts(org.reuseware.coconut.description.FacetTypeDecorator,
* org.reuseware.coconut.description.BrowserState)
*/
@Override
public FacetTypeDecorator calcValueCounts(FacetTypeDecorator tDecor, BrowserState state) {
Facet facet;
// TODO BUG it doesn't calculate values correctly if facets where added
// later
for (FacetValueDecorator vDecor : tDecor.getValues()) {
facet = DescriptionManager.buildFacet(tDecor.getDecoratee(), Collections
.singletonList(vDecor.getDecoratee()));
if (state != null) {
@SuppressWarnings("unchecked")
List list = performZoom(state, facet, false);
vDecor.setValueCount(list.size());
System.out.println();
} else
vDecor.setValueCount(0);
}
return tDecor;
}
private List<FragmentDescription> performZoom(BrowserState state, Facet facet, boolean fresh) {
List<FragmentDescription> content;
if (fresh)
content = DescriptionManager.getRegisteredDescriptions();
else
content = state.getFilteredContent();
// make sure content is completely build
for (FragmentDescription fDesc : content) {
DescriptionManager.loadDescription(fDesc);
}
// collect the facets which influence the query
List<Facet> filteringFacets = new ArrayList<Facet>();
filteringFacets.addAll(state.getSelectedFacets());
for (FacetTypeDecorator fDecor : state.getPresentedFacets()) {
if (fDecor.getSelection() != null) {
if (!fDecor.getSelection().getType().equals(facet.getType()))
filteringFacets.add(fDecor.getSelection());
}
}
// make sure an empty selected facet has priority over same typed facets
// Facet badFacet = null;
// if (facet != null && (facet.getValueNames() == null ||
// facet.getValueNames().size() == 0)) {
// for (Facet fac : filteringFacets) {
// if (fac.getType().equals(facet.getType())) {
// badFacet = fac;
// break;
// }
// }
// if (badFacet != null)
// filteringFacets.remove(badFacet);
// }
filteringFacets.add(facet);
c++;
System.out.println();
System.out.println("Zoom! no.: " + c);
System.out.println("fresh: " + fresh);
for (Facet fac : filteringFacets) {
System.out.print(fac.getType().getName() + " = {");
for (FacetValue value : fac.getValues()) {
System.out.print(value.getName() + ",");
}
System.out.println("}");
}
System.out.println();
List<FragmentDescription> filterContent = new ArrayList<FragmentDescription>(content.size());
String query;
for (Facet filterFacet : filteringFacets) {
if (filterFacet.getValues().size() < 1)
continue;
query = filterFacet.getType().getQuery();
for (FragmentDescription fragmentDescription : content) {
if (fDescContainsFacet(fragmentDescription, query, filterFacet))
filterContent.add(fragmentDescription);
}
content = filterContent;
filterContent = new ArrayList<FragmentDescription>(content.size());
}
return content;
}
public boolean fDescContainsFacet(FragmentDescription context, String expression,
Facet filterFacet) {
if (expression == null)
return true;
if (expression.equals(""))
return true;
if (OCL_ENV.getEnvironment().getVariables().isEmpty()) {
OCL_ENV.getEnvironment().getVariables().clear();
Variable<EClassifier, EParameter> var = OCL_ENV.getEnvironment().getOCLFactory()
.createVariable();
var.setName("filterFacet");
var.setType(DescriptionPackage.Literals.FACET);
OCL_ENV.getEnvironment().addElement(var.getName(), var, true);
}
OCLExpression oclExpression = parse(context.eClass(), expression, OCL_ENV);
if (oclExpression == null)
return true;
Query query = OCL_ENV.createQuery(oclExpression);
query.getEvaluationEnvironment().add("filterFacet", filterFacet);
Object result = null;
try {
result = query.evaluate(context);
} catch (Exception e) {
result = null;
}
if (result == null) {
return true;
}
if (result instanceof Boolean)
return ((Boolean) result).booleanValue();
return true;
}
private static OCLExpression parse(EClass context, String expression, OCL env) {
if (expression == null)
return null;
OCLExpression oclExpression = null;
Helper helper = env.createOCLHelper();
helper.setContext(context);
try {
oclExpression = helper.createQuery(expression);
} catch (ParserException e) {
System.err.println(e.getLocalizedMessage());
}
return oclExpression;
}
}