/******************************************************************************* * Copyright (c) 2010 Herman Lee. * 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: * Herman Lee - initial API and implementation ******************************************************************************/ package ca.uwaterloo.gsd.fsml.contentassist; import java.io.IOException; 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.Vector; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup; import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup.PositionInformation; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.swt.graphics.Image; import org.eclipse.ui.IEditorPart; import ca.uwaterloo.gsd.fsml.codeAssist.FSMLCodeAssistUtil; import ca.uwaterloo.gsd.fsml.codeAssist.FSMLProposalsAction; import ca.uwaterloo.gsd.fsml.core.FSMLMappingException; import ca.uwaterloo.gsd.fsml.core.Queries; import ca.uwaterloo.gsd.fsml.ecore.FSMLEcoreUtil; import ca.uwaterloo.gsd.fsml.fsml.Model; import ca.uwaterloo.gsd.fsml.fsml.ModelContainer; import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.CodeTransforms; import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.JavaMappingInterpreter; import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.VarCollector; import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.VarDesc; import ca.uwaterloo.gsd.fsml.javaMappingInterpreter.analysis.JavaModelUtils; import ca.uwaterloo.gsd.fsml.sync.ClassSyncItem; import ca.uwaterloo.gsd.fsml.sync.ReconciliationDecision; import ca.uwaterloo.gsd.fsml.sync.StructuralFeatureSyncItem; import ca.uwaterloo.gsd.fsml.sync.SyncFactory; import ca.uwaterloo.gsd.fsml.sync.SyncItem; import ca.uwaterloo.gsd.fsml.sync.SynchronizationState; import ca.uwaterloo.gsd.fsml.xmlMappingInterpreter.XMLMappingInterpreter; public class FSMLJavaProposal extends LinkedCorrectionProposal { private EStructuralFeature feature; private ASTNode coveringNode; private EObject parentEObject; private ICompilationUnit cu; private int invocationOffset; private ASTRewrite rewrite; private EClass concreteClass; private Resource resource; private HashSet<String> variableNames; private Image image; private EList<EStructuralFeature> positionProposalStructuralFeatures; private List<EObject> contextForPositionProposalStructuralFeatures; private List<VarDesc> variablesInScope; private CompilationUnit compilationUnit; private CompletionContext context; private boolean deleteKeyword; private Vector<SyncItem> codeGenTasks; private FSMLProposalsAction action; public FSMLJavaProposal(String name, ICompilationUnit cu, ASTRewrite rewrite, int relevance, Image image, EObject currentEObject, EClass concreteClass, EStructuralFeature feature, ASTNode coveringNode, int invocationOffset, Resource resource, CompletionContext context) { super(name, cu, rewrite, relevance, image); positionProposalStructuralFeatures = new BasicEList<EStructuralFeature>(); contextForPositionProposalStructuralFeatures=new Vector<EObject>(); codeGenTasks = new Vector<SyncItem>(); action = new FSMLProposalsAction(resource,codeGenTasks,positionProposalStructuralFeatures,contextForPositionProposalStructuralFeatures); this.cu = cu; this.rewrite = rewrite; this.image = image; this.parentEObject = currentEObject; this.concreteClass = concreteClass; this.feature = feature; this.coveringNode = coveringNode; this.invocationOffset = invocationOffset; this.resource = resource; this.context = context; variablesInScope = new ArrayList<VarDesc>(); variableNames = new HashSet<String>(); if (coveringNode!=null){ compilationUnit = (CompilationUnit)coveringNode.getRoot(); VarCollector collector = new VarCollector(); try { collector.collect(compilationUnit, compilationUnit.getTypeRoot().getSource(), invocationOffset); variablesInScope = collector.getDeclarations(); for (int i = 0; i < variablesInScope.size(); i++) { variableNames.add(variablesInScope.get(i).name); } } catch (JavaModelException e) { e.printStackTrace(); } } } protected EObject performProposalChange(IEditorPart part, IDocument document) throws FSMLMappingException { EObject newConcreteClassInstance=null; CodeTransforms.currentProposal = this; ClassSyncItem parentClassSyncItem = SyncFactory.eINSTANCE .createClassSyncItem(); parentClassSyncItem.setModel(parentEObject); parentClassSyncItem .setReconciliationDecision(ReconciliationDecision.ENFORCE_LITERAL); parentClassSyncItem .setSynchronizationState(SynchronizationState.ADDED_MODEL_LITERAL); //EReference feature = element.eContainmentFeature(); NullProgressMonitor progressMonitor = new NullProgressMonitor(); if (feature==null){ ITrackedNodePosition trackedNodePosition = rewrite.track(coveringNode); CodeTransforms.currentProposal.addLinkedPosition(trackedNodePosition, true, "FSMLProposalLinkedPosition"+0); action.prepareSubProposals(concreteClass, concreteClass.getEAllStructuralFeatures(),parentEObject); }else if (feature instanceof EAttribute){ action.forwardFeatureRepresentedAsAttribute(feature, parentClassSyncItem, progressMonitor); } else if (feature instanceof EReference) { try { newConcreteClassInstance = action.forwardFeatureRepresentedAsReference(feature, concreteClass, parentEObject, parentClassSyncItem, progressMonitor); } catch (FSMLMappingException e) { e.printStackTrace(); } } try { for (SyncItem item : codeGenTasks) { if (item instanceof ClassSyncItem){ Queries.INSTANCE.forwardFeatureRepresentedAsClass((ClassSyncItem)item, progressMonitor); }else if (item instanceof StructuralFeatureSyncItem){ Queries.INSTANCE.forwardFeatureRepresentedAsAttribute((StructuralFeatureSyncItem)item, progressMonitor); } } } catch (FSMLMappingException e) { e.printStackTrace(); } codeGenTasks.clear(); //commit the changes Queries.INSTANCE.terminate(progressMonitor); //update the field cu with the new cu (for the subproposals) coveringNode= FSMLCodeAssistUtil.getCoveringNode(cu, invocationOffset+1, 0); if (coveringNode!=null && coveringNode.getRoot() instanceof CompilationUnit){ compilationUnit=(CompilationUnit)coveringNode.getRoot(); try { cu = JavaModelUtils.getTypeRoot(compilationUnit.getJavaElement()).getWorkingCopy(JavaMappingInterpreter.primaryWorkingCopyOwner, progressMonitor); } catch (JavaModelException e) { e.printStackTrace(); } } //suggest proposals for feature group createSubProposals(part,document); return newConcreteClassInstance; } public void createSubProposals(IEditorPart part, IDocument document) { if (coveringNode==null){ return; } ASTNode newNode=null; int offset = 0; for (Iterator positionGroupIterator = getLinkedProposalModel().getPositionGroupIterator(); positionGroupIterator.hasNext();) { LinkedProposalPositionGroup next = (LinkedProposalPositionGroup)positionGroupIterator.next(); PositionInformation[] positions = next.getPositions(); offset = positions[0].getOffset(); int length = positions[0].getLength(); newNode = ASTNodeSearchUtil.getAstNode(compilationUnit, offset-1, length); } if (!positionProposalStructuralFeatures.isEmpty()){ for (EStructuralFeature structuralFeature : positionProposalStructuralFeatures) { //linked position proposal test if (structuralFeature instanceof EAttribute){ String proposalName = structuralFeature.getName(); if (proposalName.length()>0){ proposalName = proposalName.toUpperCase().charAt(0)+proposalName.substring(1); //if we have more than one concrete class, we should use the concreteClass name instead //going with the reference name for now to be consistent with the metamodel in DSPD //proposalName = concreteClass.getName(); } getLinkedProposalModel() .getPositionGroup("FSMLProposalLinkedPosition"+0, true) .addProposal( new FSMLPositionProposal( "positionProposal", proposalName+"("+contextForPositionProposalStructuralFeatures.get(0).eClass().getName()+")", cu, rewrite, contextForPositionProposalStructuralFeatures.get(0), null , structuralFeature, newNode, offset, image, 1, resource,part,document)); } else if (structuralFeature instanceof EReference){ Collection<EClass> concreteClasses = FSMLEcoreUtil .getSubclassesOfEClass( ((EReference) structuralFeature) .getEReferenceType(), true); for (EClass class1 : concreteClasses) { //TODO: make the subproposals in the linked position of the feature that it is for String proposalName = structuralFeature.getName(); if (proposalName.length()>0){ proposalName = proposalName.toUpperCase().charAt(0)+proposalName.substring(1); //if we have more than one concrete class, we should use the concreteClass name instead //going with the reference name for now to be consistent with the metamodel in DSPD //proposalName = concreteClass.getName(); } getLinkedProposalModel() .getPositionGroup("FSMLProposalLinkedPosition"+0, true) .addProposal( new FSMLPositionProposal( "positionProposal", proposalName+"("+contextForPositionProposalStructuralFeatures.get(0).eClass().getName()+")", cu, rewrite, contextForPositionProposalStructuralFeatures.get(0), class1 , structuralFeature, newNode, offset, image, 1, resource,part,document)); } } } } positionProposalStructuralFeatures.clear(); contextForPositionProposalStructuralFeatures.clear(); } protected void performChange(org.eclipse.ui.IEditorPart part, org.eclipse.jface.text.IDocument document) throws org.eclipse.core.runtime.CoreException { // change the model try { EObject newConcreteClassInstance = performProposalChange(part,document); super.performChange(part, document); //TODO: fix problem with lost of linked mode OR if before super.performChange(part,document), //"linked box" positions messing up //delete the keyword if (deleteKeyword && context!=null){ try { document.replace(context.getTokenStart(), context.getTokenEnd()-context.getTokenStart()+1, ""); } catch (BadLocationException e) { e.printStackTrace(); } } FSMLEcoreUtil.parameterValuesFromRecommenderSystem.clear(); Queries.INSTANCE.reset(); JavaMappingInterpreter javaMappingInterpreter = new JavaMappingInterpreter(); Queries.INSTANCE.registerCustomInterpreter(javaMappingInterpreter); //register XML mapping interpreter XMLMappingInterpreter xmlMappingInterpreter = new XMLMappingInterpreter(); Queries.INSTANCE.registerCustomInterpreter(xmlMappingInterpreter); EList<EObject> fsmlModel = resource.getContents(); Model assertedModel = ((ModelContainer) fsmlModel.get(0)) .getAssertedModel(); Queries.INSTANCE.initialize(cu .getJavaProject().getProject(),assertedModel); javaMappingInterpreter.getAnalysisManagers().getJavaASTManager().setCompilationUnit( JavaModelUtils.getTypeRoot(((CompilationUnit)coveringNode.getRoot()).getJavaElement()),(CompilationUnit)coveringNode.getRoot()); EObject currentContext = (newConcreteClassInstance==null)?parentEObject:newConcreteClassInstance; while (coveringNode!=null){ Queries.INSTANCE.associateContext(currentContext, coveringNode); coveringNode = coveringNode.getParent(); } // Save the changes to the model Map options = new HashMap(); options.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER); try { resource.save(options); } catch (IOException e) { e.printStackTrace(); } } catch (FSMLMappingException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } //refresh the model editor // IWorkbench workbench = PlatformUI.getWorkbench(); // IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow(); // IWorkbenchPage page = workbenchWindow.getActivePage(); // final IWorkbenchPart activePart = page.getActivePart(); // String featureInstanceModelExtension = ".applet"; // //TODO: just use the project name as the model name now... // IFile fsmlModelFile = ResourcesPlugin.getWorkspace().getRoot().getFile( // cu.getJavaProject().getPath().append( // cu.getJavaProject().getElementName().toString() // + featureInstanceModelExtension)); // String modelEditorID = workbench.getEditorRegistry().getDefaultEditor( // fsmlModelFile.getFullPath().toString()).getId(); // // IEditorReference[] editorReferences = PlatformUI.getWorkbench() // .getActiveWorkbenchWindow().getActivePage() // .getEditorReferences(); // // for (IEditorReference editorReference : editorReferences) { // // if (editorReference.getEditor(true).getEditorInput().equals( // new FileEditorInput(fsmlModelFile))) { //TODO: refresh the model editor // try { // page.openEditor(new FileEditorInput(fsmlModelFile), modelEditorID, // true); // } catch (PartInitException exception) { // MessageDialog.openError(workbenchWindow.getShell(), // "Unable to open editor.", exception.getMessage()); // // } // } // } } public void setDeleteKeyword(boolean value) { deleteKeyword = value; } }