blob: 20acce28d363551469f3a6e7cec8ef55aa220fd5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Istvan Rath and Daniel Varro
* 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:
* Istvan Rath - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.frameworkgui.content.transformation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.views.properties.IPropertySource2;
import org.eclipse.viatra2.framework.IFramework;
import org.eclipse.viatra2.framework.IMachineSetChangedListener;
import org.eclipse.viatra2.frameworkgui.FrameworkGUIPlugin;
import org.eclipse.viatra2.frameworkgui.actions.extend.ContributedActionContainer;
import org.eclipse.viatra2.frameworkgui.content.FrameworkContainer;
import org.eclipse.viatra2.frameworkgui.content.IFrameworkContentProviderExtension;
import org.eclipse.viatra2.frameworkgui.content.ITreeObject;
import org.eclipse.viatra2.frameworkgui.content.ITreeParent;
import org.eclipse.viatra2.frameworkgui.views.FrameworkTreeView;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.core.GTASMElement;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.ASMFunction;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Machine;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Rule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.CallRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.GTRuleInvocation;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.RuleUpdateASMFunction;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.ASMFunctionInvocation;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.GTPatternCall;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTPattern;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.gt.GTRule;
import org.eclipse.viatra2.lpgparser.modelbuilder.VTCLModelResolver;
public class TransformationContent
implements IFrameworkContentProviderExtension, IMachineSetChangedListener, ITreeParent
{
private RunModelAction runAction;
private DeleteModelAction deleteAction;
private SaveModelAction saveAction;
private SaveTransformationAction saveTransformationAction;
private Vector<IAction> actions;
private CrossReferenceManager xrefman;
public Collection<IAction> getActions()
{
ArrayList<IAction> r = new ArrayList<IAction>();
r.add(saveTransformationAction);
return r;
}
public Collection<IContributionItem> getContributionItems()
{
return null;
}
public ITreeObject getTopLevelEntry()
{
return this;
}
private FrameworkTreeView viewer;
private IFramework fw;
private FrameworkContainer cont;
//private HashSet<ContributedActionContainer> contributedActions = new HashSet<ContributedActionContainer>();
private void processContributedActions(FrameworkTreeView ftv)
{
for (ContributedActionContainer c : FrameworkGUIPlugin.getDefault().getContributedActions())
{
if (c.enablesFor.equals(Machine.class))
{
c.action.setupInternals(ftv);
//contributedActions.add(c);
actions.add(c.action);
}
}
}
public void init(FrameworkTreeView fv, IFramework f, FrameworkContainer c)
{
viewer = fv; this.fw = f; cont = c;
runAction = new RunModelAction(fv);
deleteAction = new DeleteModelAction(fv);
saveAction = new SaveModelAction(fv);
saveTransformationAction = new SaveTransformationAction(fv);
xrefman = new CrossReferenceManager();
processContributedActions(fv);
actions.add(runAction);
actions.add(deleteAction);
actions.add(saveAction);
//actions.add(saveTransformationAction);
initMachines();
f.addMachineSetListener(this);
brokenRefs = new HashMap<EObject, Collection<Setting>>();
}
private Map<Object, ITreeObject> machines;
public TransformationContent()
{
machines = new HashMap<Object, ITreeObject>();
actions = new Vector<IAction>();
}
public void dispose()
{
fw.removeMachineSetListener(this);
}
public Set<ITreeObject> getChildren()
{
return new HashSet<ITreeObject>(machines.values());
}
public boolean hasChildren()
{
return !machines.isEmpty();
}
public FrameworkContainer getFrameworkContainer()
{
return cont;
}
public Image getLabelImage()
{
// TODO
return null;
}
public String getLabelText()
{
return "Program models";
}
public ITreeParent getParent()
{
return cont;
}
public IPropertySource2 getPropertySource()
{
// TODO
return null;
}
protected static Image machine_image = FrameworkGUIPlugin.getImageDescriptor("icons/machine_transparent.png").createImage();
public class MachineDummy implements ITreeObject
{
public MachineDummy(Machine m)
{
machine = m;
if (m.getModule()!=null)
moduleName = m.getModule().getName();
else
moduleName = "";
}
public Machine getMachine()
{
return machine;
}
Machine machine;
String moduleName;
MachinePropertySource propertySource;
public FrameworkContainer getFrameworkContainer() {
return cont;
}
public Image getLabelImage()
{
return machine_image;
}
public String getLabelText()
{
String s = "";
if (xrefman.hasUnresolvedReferences(machine.getFqn())) {
s = " [UNRESOLVED]";
}
return machine.getFqn()+" ("+moduleName+")"+s;
}
public ITreeParent getParent()
{
return TransformationContent.this;
}
public IPropertySource2 getPropertySource() {
if (propertySource == null)
propertySource = new MachinePropertySource(machine);
return propertySource;
}
public Collection<IContributionItem> getContributionItems() {
return null;
}
public Collection<IAction> getActions()
{
return actions;
}
public IAction getDoubleClickAction() {
return runAction;
}
}
private void initMachines()
{
for (Object _m : fw.getMachines())
{
if (_m instanceof Machine)
machines.put(_m, new MachineDummy((Machine)_m));
}
}
public void machineAdded(Object machine)
{
if (machine instanceof Machine) {
resolveBrokenLinks((Machine) machine);
machines.put(machine , new MachineDummy((Machine)machine));
xrefman.checkResolvedReference(((Machine)machine).getFqn());
}
viewer.refreshViewer(this);
}
public void machineRemoved(Object machine)
{
if (machine instanceof Machine) {
recordBrokenLinks((Machine) machine);
machines.remove(machine);
xrefman.checkUnresolvedReference(((Machine)machine).getFqn());
}
viewer.refreshViewer(this);
}
public IAction getDoubleClickAction() {
return null;
}
// -- Added by Daniel Varro to record broken references --
private Map<EObject, Collection<Setting>> brokenRefs;
/**
* This method records all links which will be broken due to the removal
* of removedMachine
* @param removedMachine : the {@link Machine} to be removed
*/
protected void recordBrokenLinks(Machine removedMachine) {
List<GTASMElement> defsToResolve = new ArrayList<GTASMElement>();
List<Machine> machinesToSearch = new ArrayList<Machine>();
for (int i = 0; i < removedMachine.getAsmFunctionDefinitions().size(); i++) {
ASMFunction asmFun = removedMachine.getAsmFunctionDefinitions().get(i);
defsToResolve.add(asmFun);
}
for (int i = 0; i < removedMachine.getAsmRuleDefinitions().size(); i++) {
Rule asmRule = removedMachine.getAsmRuleDefinitions().get(i);
defsToResolve.add(asmRule);
}
for (int i = 0; i < removedMachine.getGtPatternDefinitions().size(); i++) {
GTPattern gtPatt = removedMachine.getGtPatternDefinitions().get(i);
defsToResolve.add(gtPatt);
}
for (int i = 0; i < removedMachine.getGtRuleDefinitions().size(); i++) {
GTRule gtRule = removedMachine.getGtRuleDefinitions().get(i);
defsToResolve.add(gtRule);
}
// Recording machines of interest (disregarding the machine to be removed)
for (Object obj : fw.getMachines()) {
Machine machine = (Machine) obj;
if (machine != removedMachine) {
machinesToSearch.add(machine);
}
}
// Recording cross references
if (!machinesToSearch.isEmpty() && !defsToResolve.isEmpty()) {
brokenRefs.putAll( UsageCrossReferencer.findAll(defsToResolve, machinesToSearch));
}
// Removing cross references leading out from the machine to be removed
removeLinksFromRemovedMachine(removedMachine);
}
protected void removeLinksFromRemovedMachine (Machine removedMachine) {
// toRemove is a collection of Settings (i.e. a representation of a value held by a feature of an object)
Collection<Setting> toRemove = new ArrayList<Setting>();
// if there are broken references recorded by the framework
if (brokenRefs != null) {
toRemove.clear();
Iterator<Collection<Setting>> it = brokenRefs.values().iterator();
while (it.hasNext()) {
Collection<Setting> settings = it.next();
for (Setting setting : settings) {
GTASMElement element = (GTASMElement) setting.getEObject();
// Check if removed machine is a parent / ancestor of element
if (EcoreUtil.isAncestor(removedMachine, element)) {
// Schedule the setting for removal
toRemove.add(setting);
}
// Unset the feature of the object
setting.unset();
}
if (!toRemove.isEmpty()) {
settings.removeAll(toRemove);
}
}
Collection<EObject> brokenRefsToRemove = new ArrayList<EObject>();
Iterator<EObject> it2 = brokenRefs.keySet().iterator();
while (it2.hasNext()) {
EObject nextKey = it2.next();
if (brokenRefs.get(nextKey).isEmpty()) {
brokenRefsToRemove.add(nextKey);
}
}
for (EObject nextObject : brokenRefsToRemove) {
brokenRefs.remove(nextObject);
}
}
}
protected void resolveBrokenLinks(Machine addedMachine) {
Collection<Setting> toRemove = new ArrayList<Setting>();
if (brokenRefs != null) {
for (Collection<Setting> settings : brokenRefs.values()){
toRemove.clear();
for (Setting setting : settings) {
//GTASMElement element = (GTASMElement) setting.getEObject();
//System.out.println("Resolving " + element.getFqn() + ":" + element.getClass().getCanonicalName());
GTASMElement result = resolveGTASMElement(setting);
if (result != null) {
toRemove.add(setting);
}
}
if (!toRemove.isEmpty()) {
settings.removeAll(toRemove);
}
//brokenRefs.remove(arg0);
}
Collection<EObject> brokenRefsToRemove = new ArrayList<EObject>();
Iterator<EObject> it2 = brokenRefs.keySet().iterator();
while (it2.hasNext()) {
EObject nextKey = it2.next();
if (brokenRefs.get(nextKey).isEmpty()) {
brokenRefsToRemove.add(nextKey);
}
}
for (EObject nextObject : brokenRefsToRemove) {
brokenRefs.remove(nextObject);
}
}
}
protected GTASMElement resolveGTASMElement(Setting setting) {
EObject refObject = setting.getEObject();
VTCLModelResolver fModelResolver = new VTCLModelResolver();
if (refObject instanceof CallRule) {
CallRule asmRuleInvoc = (CallRule) refObject;
return fModelResolver.reportAsmRuleInvocResolutionError(asmRuleInvoc, null, fw);
}
else if (refObject instanceof GTPatternCall) {
GTPatternCall pattCall = (GTPatternCall) refObject;
return fModelResolver.reportGtPatternCallResolutionError(pattCall, null, fw);
}
else if (refObject instanceof GTRuleInvocation) {
GTRuleInvocation gtInvoc = (GTRuleInvocation) refObject;
return fModelResolver.reportGtRuleResolutionError(gtInvoc, null, fw);
}
else if (refObject instanceof ASMFunctionInvocation) {
ASMFunctionInvocation funInvoc = (ASMFunctionInvocation) refObject;
return fModelResolver.reportFunInvocResolutionError(funInvoc, null, fw);
}
else if (refObject instanceof RuleUpdateASMFunction) {
RuleUpdateASMFunction updateRule = (RuleUpdateASMFunction) refObject;
return fModelResolver.reportAsmFunUpdateResolutionError(updateRule, null, fw);
}
else {
return null;
}
}
}