Eclipse-PyUML/pyUml/src/pyUML/actions/SyncModelAction.java

329 lines
10 KiB
Java
Executable File

package pyUML.actions;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.internal.impl.UMLFactoryImpl;
import org.eclipse.uml2.uml.resource.UMLResource;
import pyUML.backend.EclipseHelperMethods;
import pyUML.backend.GlobalConstants;
import pyUML.backend.PyUMLProfile;
import pyUML.backend.UMLToolsHelperMethods;
import pyUML.exceptions.PyUMLCancelledException;
import pyUML.exceptions.PyUMLParseException;
import pyUML.listeners.ModelChangeListener;
import pyUML.pythonTree.PythonTreeRoot;
public class SyncModelAction implements IWorkbenchWindowActionDelegate, IRunnableWithProgress{
IProject project = null;
public void dispose() {
// Auto-generated method stub
}
public void init(IWorkbenchWindow window) {
// Auto-generated method stub
}
/**
* Static method to manually run a Model synchronization
* @param project The model to use
*/
public static void runModelSync(IProject project) {
SyncModelAction delegate = new SyncModelAction();
delegate.project = project;
delegate.run((IAction) null);
}
public void run(IAction action) {
ProgressMonitorDialog monitor = new ProgressMonitorDialog(null);
try {
monitor.run(false, true, this);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* The central method - synchronizes the model by the python code
* @param monitor a ProgressMonitor
*/
public void doSync(IProgressMonitor monitor) {
// Ensure a project was given
if (this.project == null) {
return;
}
if (monitor != null) {
monitor.beginTask("Look for existing Model", IProgressMonitor.UNKNOWN);
}
// save all open editors
EclipseHelperMethods.saveAllOpenEditors();
// initialize XMI dictionaries as empty -> they are filled, if a
// model already exists
Map<EObject, String> modelXmiDict = new HashMap<EObject, String>();
Map<String, EObject> xmiModelDict = new HashMap<String, EObject>();
// read project
IPath projectPath = project.getLocation();
// define uml file name
String umlFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append(project.getName()+".uml").toOSString();
// look for model file
Model model;
Resource resource;
File modelFile = new File(umlFileName);
if (modelFile.exists()) {
// read Model
EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(umlFileName);
model = (Model) diagramRoot;
resource = model.eResource();
// get model -> xmi-id dictionary
UMLResource r = (UMLResource) resource;
modelXmiDict = r.getEObjectToIDMap();
// create reverse dict, so that xmi_id can be the key
for (EObject modelObject : modelXmiDict.keySet()) {
String xmi_id = modelXmiDict.get(modelObject);
xmiModelDict.put(xmi_id, modelObject);
}
} else {
// Model file does *not* exist ->
// A model has to be created
resource = new ResourceSetImpl().createResource(
URI.createFileURI(umlFileName));
model = UMLFactoryImpl.eINSTANCE.createModel();
model.setName(project.getName());
resource.getContents().add(model);
try {
resource.save(null);
} catch (IOException e) {
e.printStackTrace();
}
// update model in eclipse
EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project);
}
// define profile file name
String profileFileName=projectPath.
append(GlobalConstants.getPyUmlDir()).
append("PyUMLProfile.uml").toOSString();
// look for UML profile file
Profile profile;
Resource profileResource;
File profileFile = new File(profileFileName);
if (! profileFile.exists()) {
IFile profileIFile = EclipseHelperMethods.createFile(profileFile.getPath(), project);
try {
profileIFile.create(null, true, null);
}catch (CoreException e) {
e.printStackTrace();
}
EclipseHelperMethods.StringToIFile(profileIFile, PyUMLProfile.getProfileString());
}
// read and add Profile
EObject profileRoot = UMLToolsHelperMethods.loadUMLDiagram(profileFileName);
profile = (Profile) profileRoot;
if (model.getProfileApplication(profile) == null) {
ProfileApplication profApplication = model.createProfileApplication();
profApplication.setAppliedProfile(profile);
EAnnotation eannot = profApplication.createEAnnotation("http://www.eclipse.org/uml2/2.0.0/UML");
}
// generate PythonTree out of PythonCode
PythonTreeRoot pythonRoot = null;
try {
pythonRoot = new PythonTreeRoot(this.project, true, monitor);
}
catch (PyUMLParseException e) {
MessageDialog.openError(null, "Error parsing project code",
"There was an error parsing the python code of the current\n" +
"project.\n" +
"PyUML can not work as long as there are errors in the project code!\n" +
"Please resolve the error and try again!\n\n" +
"Error message was:\n\n"+
e.getMessage());
return;
}
catch (PyUMLCancelledException e) {
MessageDialog.openWarning(null, "Operation cancelled",
"The Operation was cancelled by the user");
return;
}
catch (Exception e) {
e.printStackTrace();
MessageDialog.openError(null, "Error parsing project code",
"There was an error parsing the python code of the current\n" +
"project.\n" +"Error message was:\n\n"+
e.getMessage());
return;
}
if (monitor != null)
monitor.beginTask("Synchronize the Model with the given Code", IProgressMonitor.UNKNOWN);
// ### Synchronize model with code ###
boolean syncSuccess = false;
String errMsg = null;
boolean normalRun = false;
try {
syncSuccess = pythonRoot.synchronizeModel(model, xmiModelDict);
normalRun=true;
}catch(Exception e) {
e.printStackTrace();
errMsg = e.getClass().getName() + "\n" +e.getMessage();
}
if (!syncSuccess) {
if (! normalRun) {
// if no error happened, but model was not synchronized,
// we assume there already was an adequate message and leave.
// otherwise, we print a generic message and leave afterwards
String message = "There was an error synchronizing the Model.\n";
if (errMsg != null)
message += "The error message was:\n"+errMsg;
MessageDialog.openError(null, "Synchronizing Model Failed", message);
}
return;
}
// save new or changed model to .uml file,
// if synchronization was successful
if (syncSuccess) try {
resource.save(null);
// update model in eclipse
EclipseHelperMethods.updateFile(resource.getURI().toFileString(), project);
System.out.println(("Saving model file done."));
} catch (IOException ioe) {
MessageDialog.openError(null,"IOException",
"Error saving uml file: \n" + ioe.getMessage());
}
// Synchronize Code
if (syncSuccess) {
try{
// after creating the model, synchronize the code
// so that all model xmi_ids will be part of the code
// re-use existing pythonRoot, so that code will not have
// to be read-in again.
SyncCodeAction.run(project, pythonRoot, monitor);
}catch (Throwable t) {
MessageDialog.openError(null,"Error synchronizing Code!",
t.getClass().getName() + " while synchronizing Code!: \n\n"
+ t.getMessage());
t.printStackTrace();
}
}
monitor.beginTask("Update UML diagram", IProgressMonitor.UNKNOWN);
// if model diagram does not exist, create it!
// create graphical diagram, if it does not already exist
// after creation, open it; if it is opened, refresh view.
IFile diagramFile = this.project.getWorkspace()
.getRoot().getFile(this.project.getFullPath()
.append(GlobalConstants.getPyUmlDir())
.append(project.getName()+GlobalConstants
.getDiagramExtension()));
if (! diagramFile.exists()) {
UMLToolsHelperMethods.createModelDiagram(model, diagramFile);
}else {
}
monitor.beginTask("Open UML diagram", IProgressMonitor.UNKNOWN);
// after creating model, be sure the diagram view is reloaded
boolean diagramOpened = null != EclipseHelperMethods
.firstOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension());
if (diagramOpened) {
// set focus to updated diagram only if no diagram is currently active
boolean keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().getActiveEditor().getTitle()
.matches(".*"+GlobalConstants.getDiagramExtension());
// close all sub-package pyUML.views of global model diagram
for ( IEditorReference editor :
EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().closeEditor(editor.getEditor(true), true);
}
IEditorPart modelEditor = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, keepFocus);
modelEditor.addPropertyListener(new ModelChangeListener(project));
}
else {
IEditorPart modelEditor = UMLToolsHelperMethods.openDiagram(project, diagramFile, project.getName()+".uml", true);
modelEditor.addPropertyListener(new ModelChangeListener(project));
}
UMLToolsHelperMethods.updateModelAndViewPages(this.project);
monitor.done();
}
public void selectionChanged(IAction action, ISelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
Object selectedElement = ts.getFirstElement();
this.project = (IProject) selectedElement;
}
}
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.setTaskName("Starting Model Synchronization");
this.doSync(monitor);
}
}