diff --git a/pyUml/.classpath b/pyUml/.classpath new file mode 100755 index 0000000..b702a85 --- /dev/null +++ b/pyUml/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pyUml/.project b/pyUml/.project new file mode 100755 index 0000000..4f83593 --- /dev/null +++ b/pyUml/.project @@ -0,0 +1,28 @@ + + + pyUml + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/pyUml/.pydevproject b/pyUml/.pydevproject new file mode 100755 index 0000000..bf7a68b --- /dev/null +++ b/pyUml/.pydevproject @@ -0,0 +1,4 @@ + + + + diff --git a/pyUml/.settings/org.eclipse.core.resources.prefs b/pyUml/.settings/org.eclipse.core.resources.prefs new file mode 100755 index 0000000..09f3ed7 --- /dev/null +++ b/pyUml/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,5 @@ +#Tue Jan 08 23:39:24 CET 2008 +eclipse.preferences.version=1 +encoding//custom-src/pyUMLProfile.umlprofile_diagram=UTF-8 +encoding//documents/pythonTree.uml=UTF-8 +encoding//documents/pythonTree.umlclass_diagram=UTF-8 diff --git a/pyUml/.settings/org.eclipse.ltk.core.refactoring.prefs b/pyUml/.settings/org.eclipse.ltk.core.refactoring.prefs new file mode 100755 index 0000000..c4ec3c5 --- /dev/null +++ b/pyUml/.settings/org.eclipse.ltk.core.refactoring.prefs @@ -0,0 +1,3 @@ +#Tue Nov 13 00:31:02 CET 2007 +eclipse.preferences.version=1 +org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/pyUml/META-INF/MANIFEST.MF b/pyUml/META-INF/MANIFEST.MF new file mode 100755 index 0000000..a95a1c7 --- /dev/null +++ b/pyUml/META-INF/MANIFEST.MF @@ -0,0 +1,37 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: PyUML +Bundle-SymbolicName: pyUml;singleton:=true +Bundle-Version: 0.9 +Bundle-Activator: pyUML.plugin.Activator +Eclipse-LazyStart: true +Bundle-ClassPath: lib/refactoring.jar, + ., + src/, + bin/ +Bundle-Vendor: Freie University Berlin, Germany, Martin Dittmar +Export-Package: pyUML.actions, + pyUML.backend, + pyUML.exceptions, + pyUML.listeners, + pyUML.plugin, + pyUML.pythonTree, + pyUML.refactoring, + pyUML.views +Require-Bundle: org.eclipse.core.resources, + org.eclipse.core.runtime, + org.eclipse.jface, + org.eclipse.ui, + org.eclipse.ui.ide, + org.eclipse.emf.common, + org.eclipse.emf.ecore, + org.eclipse.uml2.uml, + org.eclipse.gmf.runtime.common.core, + org.eclipse.gmf.runtime.diagram.core, + org.eclipse.gmf.runtime.common.ui, + org.eclipse.gmf.runtime.diagram.ui, + org.eclipse.gmf.runtime.diagram.ui.resources.editor, + org.python.pydev, + org.python.pydev.core, + org.python.pydev.parser, + org.eclipse.uml2.diagram.clazz diff --git a/pyUml/build.properties b/pyUml/build.properties new file mode 100755 index 0000000..0dea3e7 --- /dev/null +++ b/pyUml/build.properties @@ -0,0 +1,12 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + lib/refactoring.jar,\ + images/,\ + src/,\ + bin/ +additional.bundles = org.eclipse.ui.ide +src.includes = src/,\ + .usedDocuments/ diff --git a/pyUml/custom-src/PyUMLProfile.uml b/pyUml/custom-src/PyUMLProfile.uml new file mode 100755 index 0000000..d448e9c --- /dev/null +++ b/pyUml/custom-src/PyUMLProfile.uml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/custom-src/UMLMarkerNavigationProvider.java b/pyUml/custom-src/UMLMarkerNavigationProvider.java new file mode 100755 index 0000000..ea6ce25 --- /dev/null +++ b/pyUml/custom-src/UMLMarkerNavigationProvider.java @@ -0,0 +1,96 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.Arrays; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.EditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; +import org.eclipse.gmf.runtime.emf.ui.providers.marker.AbstractModelMarkerNavigationProvider; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil; + +/** + * @generated + */ +public class UMLMarkerNavigationProvider extends + AbstractModelMarkerNavigationProvider { + + /** + * @generated + */ + public static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID + + ".diagnostic"; //$NON-NLS-1$ + + /** + * @generated + */ + protected void doGotoMarker(IMarker marker) { + String elementId = marker + .getAttribute( + org.eclipse.gmf.runtime.common.core.resources.IMarker.ELEMENT_ID, + null); + if (elementId == null || !(getEditor() instanceof DiagramEditor)) { + return; + } + DiagramEditor editor = (DiagramEditor) getEditor(); + Map editPartRegistry = editor.getDiagramGraphicalViewer() + .getEditPartRegistry(); + EObject targetView = editor.getDiagram().eResource().getEObject( + elementId); + if (targetView == null) { + return; + } + EditPart targetEditPart = (EditPart) editPartRegistry.get(targetView); + if (targetEditPart != null) { + UMLDiagramEditorUtil.selectElementsInDiagram(editor, Arrays + .asList(new EditPart[] { targetEditPart })); + } + } + + /** + * @generated + */ + public static void deleteMarkers(IResource resource) { + try { + resource.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Failed to delete validation markers", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public static IMarker addMarker(IFile file, String elementId, + String location, String message, int statusSeverity) { + IMarker marker = null; + try { + marker = file.createMarker(MARKER_TYPE); + marker.setAttribute(IMarker.MESSAGE, message); + marker.setAttribute(IMarker.LOCATION, location); + marker + .setAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + elementId); + int markerSeverity = IMarker.SEVERITY_INFO; + if (statusSeverity == IStatus.WARNING) { + markerSeverity = IMarker.SEVERITY_WARNING; + } else if (statusSeverity == IStatus.ERROR + || statusSeverity == IStatus.CANCEL) { + markerSeverity = IMarker.SEVERITY_ERROR; + } + marker.setAttribute(IMarker.SEVERITY, markerSeverity); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Failed to create validation marker", e); //$NON-NLS-1$ + } + return marker; + } +} diff --git a/pyUml/custom-src/UMLValidationDecoratorProvider.java b/pyUml/custom-src/UMLValidationDecoratorProvider.java new file mode 100755 index 0000000..cc79f07 --- /dev/null +++ b/pyUml/custom-src/UMLValidationDecoratorProvider.java @@ -0,0 +1,463 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.draw2d.FlowLayout; +import org.eclipse.draw2d.Label; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; +import org.eclipse.gef.EditDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.editparts.AbstractConnectionEditPart; +import org.eclipse.gmf.runtime.common.core.service.AbstractProvider; +import org.eclipse.gmf.runtime.common.core.service.IOperation; +import org.eclipse.gmf.runtime.common.ui.resources.FileChangeManager; +import org.eclipse.gmf.runtime.common.ui.resources.IFileObserver; +import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; +import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; +import org.eclipse.gmf.runtime.notation.Diagram; +import org.eclipse.gmf.runtime.notation.Edge; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry; + +/** + * @generated + */ +public class UMLValidationDecoratorProvider extends AbstractProvider implements + IDecoratorProvider { + + public static Resource usedResource = null; + + /** + * @generated + */ + private static final String KEY = "validationStatus"; //$NON-NLS-1$ + + /** + * @generated + */ + private static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID + + ".diagnostic"; //$NON-NLS-1$ + + /** + * @generated + */ + private static MarkerObserver fileObserver; + + /** + * @generated + */ + private static Map/*>*/allDecorators = new HashMap(); + + /** + * @generated + */ + public void createDecorators(IDecoratorTarget decoratorTarget) { + EditPart editPart = (EditPart) decoratorTarget + .getAdapter(EditPart.class); + if (editPart instanceof GraphicalEditPart + || editPart instanceof AbstractConnectionEditPart) { + Object model = editPart.getModel(); + if ((model instanceof View)) { + View view = (View) model; + if (!(view instanceof Edge) && !view.isSetElement()) { + return; + } + } + EditDomain ed = editPart.getViewer().getEditDomain(); + if (!(ed instanceof DiagramEditDomain)) { + return; + } + if (((DiagramEditDomain) ed).getEditorPart() instanceof UMLDiagramEditor) { + decoratorTarget.installDecorator(KEY, new StatusDecorator( + decoratorTarget)); + } + } + } + + /** + * @generated + */ + public boolean provides(IOperation operation) { + if (!(operation instanceof CreateDecoratorsOperation)) { + return false; + } + IDecoratorTarget decoratorTarget = ((CreateDecoratorsOperation) operation) + .getDecoratorTarget(); + View view = (View) decoratorTarget.getAdapter(View.class); + return view != null + && PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry + .getModelID(view)); + } + + /** + * @generated + */ + public static void refreshDecorators(View view) { + refreshDecorators(ViewUtil.getIdStr(view), view.getDiagram()); + } + + /** + * @generated + */ + private static void refreshDecorators(String viewId, Diagram diagram) { + final List decorators = viewId != null ? (List) allDecorators + .get(viewId) : null; + if (decorators == null || decorators.isEmpty() || diagram == null) { + return; + } + final Diagram fdiagram = diagram; + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + + public void run() { + try { + if (UMLValidationDecoratorProvider.usedResource == null) + UMLValidationDecoratorProvider.usedResource = fdiagram.eResource(); + + if (UMLValidationDecoratorProvider.usedResource == null) + return; + + TransactionalEditingDomain domain = + TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain( + UMLValidationDecoratorProvider.usedResource.getResourceSet()); + domain.runExclusive( + new Runnable() { + + public void run() { + for (Iterator it = decorators.iterator(); it + .hasNext();) { + IDecorator decorator = (IDecorator) it + .next(); + decorator.refresh(); + } + } + }); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Decorator refresh failure", e); //$NON-NLS-1$ + } + } + }); + } + + /** + * @generated + */ + public static class StatusDecorator extends AbstractDecorator { + + /** + * @generated + */ + private String viewId; + + /** + * @generated + */ + public StatusDecorator(IDecoratorTarget decoratorTarget) { + super(decoratorTarget); + try { + final View view = (View) getDecoratorTarget().getAdapter( + View.class); + TransactionUtil.getEditingDomain(view).runExclusive( + new Runnable() { + + public void run() { + StatusDecorator.this.viewId = view != null ? ViewUtil + .getIdStr(view) + : null; + } + }); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "ViewID access failure", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public void refresh() { + removeDecoration(); + View view = (View) getDecoratorTarget().getAdapter(View.class); + if (view == null || view.eResource() == null) { + return; + } + EditPart editPart = (EditPart) getDecoratorTarget().getAdapter( + EditPart.class); + if (editPart == null || editPart.getViewer() == null) { + return; + } + + // query for all the validation markers of the current resource + String elementId = ViewUtil.getIdStr(view); + if (elementId == null) { + return; + } + int severity = IMarker.SEVERITY_INFO; + IMarker foundMarker = null; + IResource resource = WorkspaceSynchronizer + .getFile(view.eResource()); + if (resource == null || !resource.exists()) { + return; + } + IMarker[] markers = null; + try { + markers = resource.findMarkers(MARKER_TYPE, true, + IResource.DEPTH_INFINITE); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation markers refresh failure", e); //$NON-NLS-1$ + } + if (markers == null || markers.length == 0) { + return; + } + Label toolTip = null; + for (int i = 0; i < markers.length; i++) { + IMarker marker = markers[i]; + String attribute = marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + ""); //$NON-NLS-1$ + if (attribute.equals(elementId)) { + int nextSeverity = marker.getAttribute(IMarker.SEVERITY, + IMarker.SEVERITY_INFO); + Image nextImage = getImage(nextSeverity); + if (foundMarker == null) { + foundMarker = marker; + toolTip = new Label(marker.getAttribute( + IMarker.MESSAGE, ""), //$NON-NLS-1$ + nextImage); + } else { + if (toolTip.getChildren().isEmpty()) { + Label comositeLabel = new Label(); + FlowLayout fl = new FlowLayout(false); + fl.setMinorSpacing(0); + comositeLabel.setLayoutManager(fl); + comositeLabel.add(toolTip); + toolTip = comositeLabel; + } + toolTip.add(new Label(marker.getAttribute( + IMarker.MESSAGE, ""), //$NON-NLS-1$ + nextImage)); + } + severity = (nextSeverity > severity) ? nextSeverity + : severity; + } + } + if (foundMarker == null) { + return; + } + + // add decoration + if (editPart instanceof org.eclipse.gef.GraphicalEditPart) { + if (view instanceof Edge) { + setDecoration(getDecoratorTarget().addConnectionDecoration( + getImage(severity), 50, true)); + } else { + int margin = -1; + if (editPart instanceof org.eclipse.gef.GraphicalEditPart) { + margin = MapModeUtil.getMapMode( + ((org.eclipse.gef.GraphicalEditPart) editPart) + .getFigure()).DPtoLP(margin); + } + setDecoration(getDecoratorTarget() + .addShapeDecoration(getImage(severity), + IDecoratorTarget.Direction.NORTH_EAST, + margin, true)); + } + getDecoration().setToolTip(toolTip); + } + } + + /** + * @generated + */ + private Image getImage(int severity) { + String imageName = ISharedImages.IMG_OBJS_ERROR_TSK; + switch (severity) { + case IMarker.SEVERITY_ERROR: + imageName = ISharedImages.IMG_OBJS_ERROR_TSK; + break; + case IMarker.SEVERITY_WARNING: + imageName = ISharedImages.IMG_OBJS_WARN_TSK; + break; + default: + imageName = ISharedImages.IMG_OBJS_INFO_TSK; + } + return PlatformUI.getWorkbench().getSharedImages().getImage( + imageName); + } + + /** + * @generated + */ + public void activate() { + if (viewId == null) { + return; + } + + // add self to global decorators registry + List list = (List) allDecorators.get(viewId); + if (list == null) { + list = new ArrayList(2); + list.add(this); + allDecorators.put(viewId, list); + } else if (!list.contains(this)) { + list.add(this); + } + + // start listening to changes in resources + View view = (View) getDecoratorTarget().getAdapter(View.class); + if (view == null) { + return; + } + Diagram diagramView = view.getDiagram(); + if (diagramView == null) { + return; + } + if (fileObserver == null) { + FileChangeManager.getInstance().addFileObserver( + fileObserver = new MarkerObserver(diagramView)); + } + } + + /** + * @generated + */ + public void deactivate() { + if (viewId == null) { + return; + } + + // remove self from global decorators registry + List list = (List) allDecorators.get(viewId); + if (list != null) { + list.remove(this); + if (list.isEmpty()) { + allDecorators.remove(viewId); + } + } + + // stop listening to changes in resources if there are no more decorators + if (fileObserver != null && allDecorators.isEmpty()) { + FileChangeManager.getInstance() + .removeFileObserver(fileObserver); + fileObserver = null; + } + super.deactivate(); + } + } + + /** + * @generated + */ + static class MarkerObserver implements IFileObserver { + + /** + * @generated + */ + private Diagram diagram; + + /** + * @generated + */ + private MarkerObserver(Diagram diagram) { + this.diagram = diagram; + } + + /** + * @generated + */ + public void handleFileRenamed(IFile oldFile, IFile file) { + } + + /** + * @generated + */ + public void handleFileMoved(IFile oldFile, IFile file) { + } + + /** + * @generated + */ + public void handleFileDeleted(IFile file) { + } + + /** + * @generated + */ + public void handleFileChanged(IFile file) { + } + + /** + * @generated + */ + public void handleMarkerAdded(IMarker marker) { + if (marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + null) != null) { + handleMarkerChanged(marker); + } + } + + /** + * @generated + */ + public void handleMarkerDeleted(IMarker marker, Map attributes) { + String viewId = (String) attributes + .get(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID); + refreshDecorators(viewId, diagram); + } + + /** + * @generated + */ + public void handleMarkerChanged(IMarker marker) { + if (!MARKER_TYPE.equals(getType(marker))) { + return; + } + String viewId = marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + ""); //$NON-NLS-1$ + refreshDecorators(viewId, diagram); + } + + /** + * @generated + */ + private String getType(IMarker marker) { + try { + return marker.getType(); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation marker refresh failure", e); //$NON-NLS-1$ + return ""; //$NON-NLS-1$ + } + } + } +} diff --git a/pyUml/custom-src/UMLValidationProvider.java b/pyUml/custom-src/UMLValidationProvider.java new file mode 100755 index 0000000..964fd2c --- /dev/null +++ b/pyUml/custom-src/UMLValidationProvider.java @@ -0,0 +1,406 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.emf.validation.model.IClientSelector; +import org.eclipse.emf.validation.service.IBatchValidator; +import org.eclipse.emf.validation.service.ITraversalStrategy; +import org.eclipse.gmf.runtime.common.ui.services.action.contributionitem.AbstractContributionItemProvider; +import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.jface.action.IAction; +import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry; +import org.eclipse.uml2.diagram.clazz.part.ValidateAction; + +/** + * @generated + */ +public class UMLValidationProvider extends AbstractContributionItemProvider { + + /** + * @generated + */ + private static boolean constraintsActive = false; + + /** + * @generated + */ + public static boolean shouldConstraintsBePrivate() { + return false; + } + + /** + * @generated + */ + protected IAction createAction(String actionId, + IWorkbenchPartDescriptor partDescriptor) { + if (ValidateAction.VALIDATE_ACTION_KEY.equals(actionId)) { + return new ValidateAction(partDescriptor); + } + return super.createAction(actionId, partDescriptor); + } + + /** + * @generated + */ + public static void runWithConstraints(View view, Runnable op) { + final Runnable fop = op; + Runnable task = new Runnable() { + + public void run() { + try { + constraintsActive = true; + fop.run(); + } finally { + constraintsActive = false; + } + } + }; + TransactionalEditingDomain txDomain = TransactionUtil + .getEditingDomain(view); + if (txDomain != null) { + try { + txDomain.runExclusive(task); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } else { + task.run(); + } + } + + /** + * @generated + */ + static boolean isInDefaultEditorContext(Object object) { + if (shouldConstraintsBePrivate() && !constraintsActive) { + return false; + } + if (object instanceof View) { + return constraintsActive + && PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry + .getModelID((View) object)); + } + return true; + } + + /** + * @generated + */ + static final Map semanticCtxIdMap = new HashMap(); + + /** + * @generated + */ + public static class DefaultCtx1 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx2 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx3 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx4 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx5 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx6 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx7 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx8 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx9 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx10 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx11 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx12 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx13 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx14 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static ITraversalStrategy getNotationTraversalStrategy( + IBatchValidator validator) { + return new CtxSwitchStrategy(validator); + } + + /** + * @generated + */ + private static class CtxSwitchStrategy implements ITraversalStrategy { + + /** + * @generated + */ + private ITraversalStrategy defaultStrategy; + + /** + * @generated + */ + private String currentSemanticCtxId; + + /** + * @generated + */ + private boolean ctxChanged = true; + + /** + * @generated + */ + private EObject currentTarget; + + /** + * @generated + */ + private EObject preFetchedNextTarget; + + /** + * @generated + */ + CtxSwitchStrategy(IBatchValidator validator) { + this.defaultStrategy = validator.getDefaultTraversalStrategy(); + } + + /** + * @generated + */ + public void elementValidated(EObject element, IStatus status) { + defaultStrategy.elementValidated(element, status); + } + + /** + * @generated + */ + public boolean hasNext() { + return defaultStrategy.hasNext(); + } + + /** + * @generated + */ + public boolean isClientContextChanged() { + if (preFetchedNextTarget == null) { + preFetchedNextTarget = next(); + prepareNextClientContext(preFetchedNextTarget); + } + return ctxChanged; + } + + /** + * @generated + */ + public EObject next() { + EObject nextTarget = preFetchedNextTarget; + if (nextTarget == null) { + nextTarget = defaultStrategy.next(); + } + this.preFetchedNextTarget = null; + return this.currentTarget = nextTarget; + } + + /** + * @generated + */ + public void startTraversal(Collection traversalRoots, + IProgressMonitor monitor) { + defaultStrategy.startTraversal(traversalRoots, monitor); + } + + /** + * @generated + */ + private void prepareNextClientContext(EObject nextTarget) { + if (nextTarget != null && currentTarget != null) { + if (nextTarget instanceof View) { + String id = ((View) nextTarget).getType(); + String nextSemanticId = id != null + && semanticCtxIdMap.containsKey(id) ? id : null; + if ((currentSemanticCtxId != null && !currentSemanticCtxId + .equals(nextSemanticId)) + || (nextSemanticId != null && !nextSemanticId + .equals(currentSemanticCtxId))) { + this.ctxChanged = true; + } + currentSemanticCtxId = nextSemanticId; + } else { + // context of domain model + this.ctxChanged = currentSemanticCtxId != null; + currentSemanticCtxId = null; + } + } else { + this.ctxChanged = false; + } + } + } + + /** + * @generated + */ + static class JavaAudits { + } +} diff --git a/pyUml/custom-src/ValidateAction.java b/pyUml/custom-src/ValidateAction.java new file mode 100755 index 0000000..96f2844 --- /dev/null +++ b/pyUml/custom-src/ValidateAction.java @@ -0,0 +1,297 @@ +package org.eclipse.uml2.diagram.clazz.part; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.validation.model.EvaluationMode; +import org.eclipse.emf.validation.model.IConstraintStatus; +import org.eclipse.emf.validation.service.IBatchValidator; +import org.eclipse.emf.validation.service.ModelValidationService; +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor; +import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory; +import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; +import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation; +import org.eclipse.uml2.diagram.clazz.providers.UMLMarkerNavigationProvider; +import org.eclipse.uml2.diagram.clazz.providers.UMLValidationProvider; + +/** + * @generated + */ +public class ValidateAction extends Action { + + /** + * @generated + */ + public static final String VALIDATE_ACTION_KEY = "validateAction"; //$NON-NLS-1$ + + /** + * @generated + */ + private IWorkbenchPartDescriptor workbenchPartDescriptor; + + /** + * @generated + */ + public ValidateAction(IWorkbenchPartDescriptor workbenchPartDescriptor) { + setId(VALIDATE_ACTION_KEY); + setText(Messages.ValidateActionMessage); + this.workbenchPartDescriptor = workbenchPartDescriptor; + } + + /** + * @generated + */ + public void run() { + IWorkbenchPart workbenchPart = workbenchPartDescriptor.getPartPage() + .getActivePart(); + if (workbenchPart instanceof IDiagramWorkbenchPart) { + final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) workbenchPart; + try { + new WorkspaceModifyDelegatingOperation( + new IRunnableWithProgress() { + + public void run(IProgressMonitor monitor) + throws InterruptedException, + InvocationTargetException { + runValidation(part.getDiagramEditPart(), part + .getDiagram()); + } + }).run(new NullProgressMonitor()); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } + } + + /** + * @generated + */ + public static void runValidation(View view) { + try { + if (UMLDiagramEditorUtil.openDiagram(view.eResource())) { + IEditorPart editorPart = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage() + .getActiveEditor(); + if (editorPart instanceof IDiagramWorkbenchPart) { + runValidation(((IDiagramWorkbenchPart) editorPart) + .getDiagramEditPart(), view); + } else { + runNonUIValidation(view); + } + } + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public static void runNonUIValidation(View view) { + DiagramEditPart diagramEditPart = OffscreenEditPartFactory + .getInstance().createDiagramEditPart(view.getDiagram()); + runValidation(diagramEditPart, view); + } + + /** + * @generated + */ + public static void runValidation(DiagramEditPart diagramEditPart, View view) { + final DiagramEditPart fpart = diagramEditPart; + final View fview = view; + UMLValidationProvider.runWithConstraints(view, new Runnable() { + + public void run() { + validate(fpart, fview); + } + }); + } + + /** + * @generated + */ + private static Diagnostic runEMFValidator(View target) { + if (target.isSetElement() && target.getElement() != null) { + return new Diagnostician() { + + public String getObjectLabel(EObject eObject) { + return EMFCoreUtil.getQualifiedName(eObject, true); + } + }.validate(target.getElement()); + } + return Diagnostic.OK_INSTANCE; + } + + /** + * @generated + */ + private static void validate(DiagramEditPart diagramEditPart, View view) { + IFile target = view.eResource() != null ? WorkspaceSynchronizer + .getFile(view.eResource()) : null; + if (target != null) { + UMLMarkerNavigationProvider.deleteMarkers(target); + } + Diagnostic diagnostic = runEMFValidator(view); + createMarkers(target, diagnostic, diagramEditPart); + IBatchValidator validator = (IBatchValidator) ModelValidationService + .getInstance().newValidator(EvaluationMode.BATCH); + validator.setIncludeLiveConstraints(true); + if (view.isSetElement() && view.getElement() != null) { + IStatus status = validator.validate(view.getElement()); + createMarkers(target, status, diagramEditPart); + } + } + + /** + * @generated + */ + private static void createMarkers(IFile target, IStatus validationStatus, + DiagramEditPart diagramEditPart) { + if (validationStatus.isOK()) { + return; + } + final IStatus rootStatus = validationStatus; + List allStatuses = new ArrayList(); + UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap( + diagramEditPart.getDiagramView(), collectTargetElements( + rootStatus, new HashSet(), allStatuses)); + for (Iterator it = allStatuses.iterator(); it.hasNext();) { + IConstraintStatus nextStatus = (IConstraintStatus) it.next(); + View view = UMLDiagramEditorUtil.findView(diagramEditPart, + nextStatus.getTarget(), element2ViewMap); + addMarker(diagramEditPart.getViewer(), target, view.eResource() + .getURIFragment(view), EMFCoreUtil.getQualifiedName( + nextStatus.getTarget(), true), nextStatus.getMessage(), + nextStatus.getSeverity()); + } + } + + /** + * @generated + */ + private static void createMarkers(IFile target, + Diagnostic emfValidationStatus, DiagramEditPart diagramEditPart) { + if (emfValidationStatus.getSeverity() == Diagnostic.OK) { + return; + } + final Diagnostic rootStatus = emfValidationStatus; + List allDiagnostics = new ArrayList(); + UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap( + diagramEditPart.getDiagramView(), collectTargetElements( + rootStatus, new HashSet(), allDiagnostics)); + for (Iterator it = emfValidationStatus.getChildren().iterator(); it + .hasNext();) { + Diagnostic nextDiagnostic = (Diagnostic) it.next(); + List data = nextDiagnostic.getData(); + if (data != null && !data.isEmpty() + && data.get(0) instanceof EObject) { + EObject element = (EObject) data.get(0); + View view = UMLDiagramEditorUtil.findView(diagramEditPart, + element, element2ViewMap); + addMarker( + diagramEditPart.getViewer(), + target, + view.eResource().getURIFragment(view), + EMFCoreUtil.getQualifiedName(element, true), + nextDiagnostic.getMessage(), + diagnosticToStatusSeverity(nextDiagnostic.getSeverity())); + } + } + } + + /** + * @generated + */ + private static void addMarker(EditPartViewer viewer, IFile target, + String elementId, String location, String message, + int statusSeverity) { + if (target == null) { + return; + } + UMLMarkerNavigationProvider.addMarker(target, elementId, location, + message, statusSeverity); + } + + /** + * @generated + */ + private static int diagnosticToStatusSeverity(int diagnosticSeverity) { + if (diagnosticSeverity == Diagnostic.OK) { + return IStatus.OK; + } else if (diagnosticSeverity == Diagnostic.INFO) { + return IStatus.INFO; + } else if (diagnosticSeverity == Diagnostic.WARNING) { + return IStatus.WARNING; + } else if (diagnosticSeverity == Diagnostic.ERROR + || diagnosticSeverity == Diagnostic.CANCEL) { + return IStatus.ERROR; + } + return IStatus.INFO; + } + + /** + * @generated + */ + private static Set collectTargetElements(IStatus status, + Set targetElementCollector, List allConstraintStatuses) { + if (status instanceof IConstraintStatus) { + targetElementCollector + .add(((IConstraintStatus) status).getTarget()); + allConstraintStatuses.add(status); + } + if (status.isMultiStatus()) { + IStatus[] children = status.getChildren(); + for (int i = 0; i < children.length; i++) { + collectTargetElements(children[i], targetElementCollector, + allConstraintStatuses); + } + } + return targetElementCollector; + } + + /** + * @generated + */ + private static Set collectTargetElements(Diagnostic diagnostic, + Set targetElementCollector, List allDiagnostics) { + List data = diagnostic.getData(); + EObject target = null; + if (data != null && !data.isEmpty() && data.get(0) instanceof EObject) { + target = (EObject) data.get(0); + targetElementCollector.add(target); + allDiagnostics.add(diagnostic); + } + if (diagnostic.getChildren() != null + && !diagnostic.getChildren().isEmpty()) { + for (Iterator it = diagnostic.getChildren().iterator(); it + .hasNext();) { + collectTargetElements((Diagnostic) it.next(), + targetElementCollector, allDiagnostics); + } + } + return targetElementCollector; + } +} diff --git a/pyUml/custom-src/classDiagram.gmfgen b/pyUml/custom-src/classDiagram.gmfgen new file mode 100755 index 0000000..6b081ad --- /dev/null +++ b/pyUml/custom-src/classDiagram.gmfgen @@ -0,0 +1,9215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uml + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.notation.View + org.eclipse.gef.EditPart + abstractNavigatorItem + + + + + + + + diff --git a/pyUml/custom-src/classDiagram.gmfmap b/pyUml/custom-src/classDiagram.gmfmap new file mode 100755 index 0000000..89493db --- /dev/null +++ b/pyUml/custom-src/classDiagram.gmfmap @@ -0,0 +1,1978 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/custom-src/pyUMLProfile.umlprofile_diagram b/pyUml/custom-src/pyUMLProfile.umlprofile_diagram new file mode 100755 index 0000000..455d427 --- /dev/null +++ b/pyUml/custom-src/pyUMLProfile.umlprofile_diagram @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/custom-src/uml2tools_class_plugin.xml b/pyUml/custom-src/uml2tools_class_plugin.xml new file mode 100755 index 0000000..69b692d --- /dev/null +++ b/pyUml/custom-src/uml2tools_class_plugin.xml @@ -0,0 +1,1675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %newWizardDesc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VisibilityKind::protected]]> + + + + + + + + + + + + VisibilityKind::private or self.name.substring(1,2) = '__']]> + + + + + + VisibilityKind::private or self.name.substring(1,2) = '__']]> + + + + + + VisibilityKind::protected or self.name.substring(1,1) = '_']]> + + + + + + VisibilityKind::protected or self.name.substring(1,1) = '_']]> + + + + + + + + + + + + forAll(op1, op2 | op1<>op2 implies op1.name <> op2.name)]]> + + + + + + + + + + + + forAll(param | param.name <> 'self' ))]]> + + + + + + forAll(param | param.name <> 'self' )]]> + + + + + + + + + + + + + + + + + + null]]> + + + + + + ParameterDirectionKind::out and self.direction <> ParameterDirectionKind::return and self.direction <> ParameterDirectionKind::inout)]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/custom-src/umltools_class_MANIFEST.MF b/pyUml/custom-src/umltools_class_MANIFEST.MF new file mode 100755 index 0000000..0583601 --- /dev/null +++ b/pyUml/custom-src/umltools_class_MANIFEST.MF @@ -0,0 +1,49 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.uml2.diagram.clazz; singleton:=true +Bundle-Version: 0.7.1.qualifier +Bundle-ClassPath: . +Bundle-Activator: org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Export-Package: org.eclipse.uml2.diagram.clazz.edit.parts, + org.eclipse.uml2.diagram.clazz.part, + org.eclipse.uml2.diagram.clazz.providers, + org.eclipse.uml2.diagram.clazz.navigator +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.core.resources, + org.eclipse.core.expressions, + org.eclipse.jface, + org.eclipse.ui.ide, + org.eclipse.ui.views, + org.eclipse.ui.navigator, + org.eclipse.emf.ecore, + org.eclipse.emf.ecore.xmi, + org.eclipse.emf.edit.ui, + org.eclipse.gef;visibility:=reexport, + org.eclipse.gmf.runtime.emf.core, + org.eclipse.gmf.runtime.emf.commands.core, + org.eclipse.gmf.runtime.emf.ui.properties, + org.eclipse.gmf.runtime.diagram.ui, + org.eclipse.gmf.runtime.diagram.ui.properties, + org.eclipse.gmf.runtime.diagram.ui.providers, + org.eclipse.gmf.runtime.diagram.ui.providers.ide, + org.eclipse.gmf.runtime.diagram.ui.resources.editor, + org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide, + org.eclipse.gmf.runtime.notation.providers, + org.eclipse.uml2.uml;visibility:=reexport, + org.eclipse.uml2.uml.edit;visibility:=reexport, + org.eclipse.emf.ecore;visibility:=reexport, + org.eclipse.emf.ecore.edit;visibility:=reexport, + org.eclipse.emf.ocl;visibility:=reexport, + org.eclipse.emf.query.ocl;visibility:=reexport, + org.eclipse.gmf.runtime.draw2d.ui;visibility:=reexport, + org.eclipse.uml2.diagram.common;visibility:=reexport, + org.eclipse.draw2d;visibility:=reexport, + org.eclipse.ocl.ecore;visibility:=reexport, + org.eclipse.gmf.runtime.diagram.ui.render, + org.eclipse.ui.navigator.resources, + org.eclipse.emf.validation;visibility:=reexport +Eclipse-LazyStart: true +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/pyUml/documents/pythonTree.uml b/pyUml/documents/pythonTree.uml new file mode 100755 index 0000000..bfcae39 --- /dev/null +++ b/pyUml/documents/pythonTree.uml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/documents/pythonTree.umlclass_diagram b/pyUml/documents/pythonTree.umlclass_diagram new file mode 100755 index 0000000..d4a088d --- /dev/null +++ b/pyUml/documents/pythonTree.umlclass_diagram @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/images/class_obj.png b/pyUml/images/class_obj.png new file mode 100755 index 0000000..c57c2d0 Binary files /dev/null and b/pyUml/images/class_obj.png differ diff --git a/pyUml/images/manageViews.png b/pyUml/images/manageViews.png new file mode 100755 index 0000000..e8541d4 Binary files /dev/null and b/pyUml/images/manageViews.png differ diff --git a/pyUml/images/openuml.png b/pyUml/images/openuml.png new file mode 100755 index 0000000..7a9daf7 Binary files /dev/null and b/pyUml/images/openuml.png differ diff --git a/pyUml/images/package_obj.png b/pyUml/images/package_obj.png new file mode 100755 index 0000000..0afea5b Binary files /dev/null and b/pyUml/images/package_obj.png differ diff --git a/pyUml/images/py2uml.png b/pyUml/images/py2uml.png new file mode 100755 index 0000000..3111ecf Binary files /dev/null and b/pyUml/images/py2uml.png differ diff --git a/pyUml/images/pyUML_icons.tgz b/pyUml/images/pyUML_icons.tgz new file mode 100755 index 0000000..e2b470e Binary files /dev/null and b/pyUml/images/pyUML_icons.tgz differ diff --git a/pyUml/images/uml2py.png b/pyUml/images/uml2py.png new file mode 100755 index 0000000..46cdd5e Binary files /dev/null and b/pyUml/images/uml2py.png differ diff --git a/pyUml/lib/refactoring.jar b/pyUml/lib/refactoring.jar new file mode 100755 index 0000000..9c31750 Binary files /dev/null and b/pyUml/lib/refactoring.jar differ diff --git a/pyUml/license.html b/pyUml/license.html new file mode 100755 index 0000000..d7b88e9 --- /dev/null +++ b/pyUml/license.html @@ -0,0 +1,319 @@ + + + + + +Eclipse Public License - Version 1.0 + + + + + + +
+ +

Eclipse Public License - v 1.0 +

+ +

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER +THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, +REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE +OF THIS AGREEMENT.

+ +

1. DEFINITIONS

+ +

"Contribution" means:

+ +

a) +in the case of the initial Contributor, the initial code and documentation +distributed under this Agreement, and
+b) in the case of each subsequent Contributor:

+ +

i) +changes to the Program, and

+ +

ii) +additions to the Program;

+ +

where +such changes and/or additions to the Program originate from and are distributed +by that particular Contributor. A Contribution 'originates' from a Contributor +if it was added to the Program by such Contributor itself or anyone acting on +such Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in conjunction +with the Program under their own license agreement, and (ii) are not derivative +works of the Program.

+ +

"Contributor" means any person or +entity that distributes the Program.

+ +

"Licensed Patents " mean patent +claims licensable by a Contributor which are necessarily infringed by the use +or sale of its Contribution alone or when combined with the Program.

+ +

"Program" means the Contributions +distributed in accordance with this Agreement.

+ +

"Recipient" means anyone who +receives the Program under this Agreement, including all Contributors.

+ +

2. GRANT OF RIGHTS

+ +

a) +Subject to the terms of this Agreement, each Contributor hereby grants Recipient +a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly +display, publicly perform, distribute and sublicense the Contribution of such +Contributor, if any, and such derivative works, in source code and object code +form.

+ +

b) +Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free +patent license under Licensed Patents to make, use, sell, offer to sell, import +and otherwise transfer the Contribution of such Contributor, if any, in source +code and object code form. This patent license shall apply to the combination +of the Contribution and the Program if, at the time the Contribution is added +by the Contributor, such addition of the Contribution causes such combination +to be covered by the Licensed Patents. The patent license shall not apply to +any other combinations which include the Contribution. No hardware per se is +licensed hereunder.

+ +

c) +Recipient understands that although each Contributor grants the licenses to its +Contributions set forth herein, no assurances are provided by any Contributor +that the Program does not infringe the patent or other intellectual property +rights of any other entity. Each Contributor disclaims any liability to Recipient +for claims brought by any other entity based on infringement of intellectual +property rights or otherwise. As a condition to exercising the rights and +licenses granted hereunder, each Recipient hereby assumes sole responsibility +to secure any other intellectual property rights needed, if any. For example, +if a third party patent license is required to allow Recipient to distribute +the Program, it is Recipient's responsibility to acquire that license before +distributing the Program.

+ +

d) +Each Contributor represents that to its knowledge it has sufficient copyright +rights in its Contribution, if any, to grant the copyright license set forth in +this Agreement.

+ +

3. REQUIREMENTS

+ +

A Contributor may choose to distribute the +Program in object code form under its own license agreement, provided that: +

+ +

a) +it complies with the terms and conditions of this Agreement; and

+ +

b) +its license agreement:

+ +

i) +effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title +and non-infringement, and implied warranties or conditions of merchantability +and fitness for a particular purpose;

+ +

ii) +effectively excludes on behalf of all Contributors all liability for damages, +including direct, indirect, special, incidental and consequential damages, such +as lost profits;

+ +

iii) +states that any provisions which differ from this Agreement are offered by that +Contributor alone and not by any other party; and

+ +

iv) +states that source code for the Program is available from such Contributor, and +informs licensees how to obtain it in a reasonable manner on or through a +medium customarily used for software exchange.

+ +

When the Program is made available in source +code form:

+ +

a) +it must be made available under this Agreement; and

+ +

b) a +copy of this Agreement must be included with each copy of the Program.

+ +

Contributors may not remove or alter any +copyright notices contained within the Program.

+ +

Each Contributor must identify itself as the +originator of its Contribution, if any, in a manner that reasonably allows +subsequent Recipients to identify the originator of the Contribution.

+ +

4. COMMERCIAL DISTRIBUTION

+ +

Commercial distributors of software may +accept certain responsibilities with respect to end users, business partners +and the like. While this license is intended to facilitate the commercial use +of the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes the +Program in a commercial product offering, such Contributor ("Commercial +Contributor") hereby agrees to defend and indemnify every other +Contributor ("Indemnified Contributor") against any losses, damages and +costs (collectively "Losses") arising from claims, lawsuits and other +legal actions brought by a third party against the Indemnified Contributor to +the extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may participate +in any such claim at its own expense.

+ +

For example, a Contributor might include the +Program in a commercial product offering, Product X. That Contributor is then a +Commercial Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance claims and +warranties are such Commercial Contributor's responsibility alone. Under this +section, the Commercial Contributor would have to defend claims against the +other Contributors related to those performance claims and warranties, and if a +court requires any other Contributor to pay any damages as a result, the +Commercial Contributor must pay those damages.

+ +

5. NO WARRANTY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS +AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, +WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and distributing the +Program and assumes all risks associated with its exercise of rights under this +Agreement , including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs or +equipment, and unavailability or interruption of operations.

+ +

6. DISCLAIMER OF LIABILITY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS +AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF +THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES.

+ +

7. GENERAL

+ +

If any provision of this Agreement is invalid +or unenforceable under applicable law, it shall not affect the validity or +enforceability of the remainder of the terms of this Agreement, and without +further action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable.

+ +

If Recipient institutes patent litigation +against any entity (including a cross-claim or counterclaim in a lawsuit) +alleging that the Program itself (excluding combinations of the Program with +other software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the date +such litigation is filed.

+ +

All Recipient's rights under this Agreement +shall terminate if it fails to comply with any of the material terms or +conditions of this Agreement and does not cure such failure in a reasonable +period of time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.

+ +

Everyone is permitted to copy and distribute +copies of this Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The Agreement +Steward reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement Steward has +the right to modify this Agreement. The Eclipse Foundation is the initial +Agreement Steward. The Eclipse Foundation may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved.

+ +

This Agreement is governed by the laws of the +State of New York and the intellectual property laws of the United States of +America. No party to this Agreement will bring a legal action under this +Agreement more than one year after the cause of action arose. Each party waives +its rights to a jury trial in any resulting litigation.

+ +

 

+ +
+ + \ No newline at end of file diff --git a/pyUml/plugin.xml b/pyUml/plugin.xml new file mode 100755 index 0000000..94317d7 --- /dev/null +++ b/pyUml/plugin.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/src/pyUML/actions/ManageViewsAction.java b/pyUml/src/pyUML/actions/ManageViewsAction.java new file mode 100755 index 0000000..886c240 --- /dev/null +++ b/pyUml/src/pyUML/actions/ManageViewsAction.java @@ -0,0 +1,92 @@ +package pyUML.actions; + +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.util.WrappedException; +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.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.uml2.uml.Model; +import org.python.pydev.navigator.elements.PythonFile; + +import pyUML.backend.GlobalConstants; +import pyUML.views.ManageViewsPage; + + + +public class ManageViewsAction implements IObjectActionDelegate{ + + IWorkbenchPart part; + ISelection selection; + IProject project; + + /** + * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart) + */ + public void setActivePart(IAction action, IWorkbenchPart part) { + this.part = part; + } + + + /** + * Manual way to open a window to manage pyUML.views + * A project is needed to open a ManagViews Window + * @param project An eclipse project + */ + public static void run(IProject project) { + ManageViewsAction manageViews = new ManageViewsAction(); + manageViews.project = project; + manageViews.run((IAction) null); + } + + + /** + * The run method used when the action is executed + * -> a new manage pyUML.views window is opened + */ + public void run(IAction action) { + + try{ + String umlFileName=project.getLocation(). + append(GlobalConstants.getPyUmlDir()). + append(project.getName()+".uml").toOSString(); + + EObject diagramRoot = null; + try { + Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlFileName), true); + diagramRoot = (EObject) resource.getContents().get(0); + } catch (WrappedException ex) { + MessageDialog.openError(null,"Error opening UML model", + "Unable to load model: " + umlFileName + "\n" + + "You must create a model before you can create pyUML.views!"); + return; + } + + Model model = (Model) diagramRoot; + + ManageViewsPage page = new ManageViewsPage((Shell) null, model, project); + if (page != null) + page.open(); + + }catch (Throwable t) { + MessageDialog.openError(null,t.getClass().getName(),"Error Managing Views:\n"+t.getClass().getName()+"\n"+t.getMessage()); + t.printStackTrace(); + } + + } + + public void selectionChanged(IAction action, ISelection selection) { + if (selection instanceof TreeSelection) { + TreeSelection ts = (TreeSelection) selection; + Object selectedElement = ts.getFirstElement(); + this.project = (IProject) selectedElement; + } + } +} diff --git a/pyUml/src/pyUML/actions/ManageViewsHandler.java b/pyUml/src/pyUML/actions/ManageViewsHandler.java new file mode 100755 index 0000000..ad87458 --- /dev/null +++ b/pyUml/src/pyUML/actions/ManageViewsHandler.java @@ -0,0 +1,28 @@ +package pyUML.actions; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; + +import pyUML.backend.EclipseHelperMethods; + + +/** + * An action Handler that calls ManageViewsAction for a user-selected project + */ +public class ManageViewsHandler extends AbstractHandler{ + public static IProject selectedProject = null; + + @Override + public Object execute(ExecutionEvent arg0) throws ExecutionException { + EclipseHelperMethods.saveAllOpenEditors(); + IProject project = EclipseHelperMethods.selectProject(); + + if (project == null) + return null; + + ManageViewsAction.run(project); + return null; + } +} diff --git a/pyUml/src/pyUML/actions/OpenModelAction.java b/pyUml/src/pyUML/actions/OpenModelAction.java new file mode 100755 index 0000000..320586a --- /dev/null +++ b/pyUml/src/pyUML/actions/OpenModelAction.java @@ -0,0 +1,88 @@ +package pyUML.actions; + + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.UMLToolsHelperMethods; +import pyUML.listeners.ModelChangeListener; + + + +public class OpenModelAction implements IWorkbenchWindowActionDelegate{ + + IProject project = null; + + public void dispose() { + // Auto-generated method stub + } + + public void init(IWorkbenchWindow window) { + // Auto-generated method stub + } + + /** + * Opens the UML diagram for the given project + * @param project + */ + public static void runOpenModel(IProject project) { + OpenModelAction delegate = new OpenModelAction(); + delegate.project = project; + delegate.run((IAction) null); + } + + public void run(IAction action) { + this.openModel(); + } + + + /** + * This is the central method - + * A UML diagram is opened. The project set + * in this object is used + */ + public void openModel() { + + // Ensure a project was given + if (this.project == null) { + return; + } + + // save all open editors + EclipseHelperMethods.saveAllOpenEditors(); + + // open diagram + IFile diagramFile = this.project.getWorkspace() + .getRoot().getFile(this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(project.getName()+GlobalConstants + .getDiagramExtension())); + + if (! diagramFile.exists()) { + MessageDialog.openWarning(null, "Opening UML diagram failed", + "Failed to open UML diagram, because it does not seem to exist.\n" + + "Please use 'synchronize Model' to create a new Diagram!"); + return; + }else { + IEditorPart modelEditor = UMLToolsHelperMethods.openDiagram(project, diagramFile, project.getName()+".uml", true); + modelEditor.addPropertyListener(new ModelChangeListener(project)); + } + } + + public void selectionChanged(IAction action, ISelection selection) { + if (selection instanceof TreeSelection) { + TreeSelection ts = (TreeSelection) selection; + Object selectedElement = ts.getFirstElement(); + this.project = (IProject) selectedElement; + } + } +} diff --git a/pyUml/src/pyUML/actions/OpenModelHandler.java b/pyUml/src/pyUML/actions/OpenModelHandler.java new file mode 100755 index 0000000..6b9b9e3 --- /dev/null +++ b/pyUml/src/pyUML/actions/OpenModelHandler.java @@ -0,0 +1,27 @@ +package pyUML.actions; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; + +import pyUML.backend.EclipseHelperMethods; + + + +/** + * An action Handler that calls OpenModelAction for a user-selected project + */ +public class OpenModelHandler extends AbstractHandler{ + public static IProject selectedProject = null; + + @Override + public Object execute(ExecutionEvent arg0) throws ExecutionException { + EclipseHelperMethods.saveAllOpenEditors(); + IProject project = EclipseHelperMethods.selectProject(); + + OpenModelAction.runOpenModel(project); + + return null; + } +} diff --git a/pyUml/src/pyUML/actions/SyncCodeAction.java b/pyUml/src/pyUML/actions/SyncCodeAction.java new file mode 100755 index 0000000..14a182f --- /dev/null +++ b/pyUml/src/pyUML/actions/SyncCodeAction.java @@ -0,0 +1,233 @@ +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.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.ecore.EObject; +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.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.resource.UMLResource; + + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.JavaHelperMethods; +import pyUML.backend.UMLToolsHelperMethods; +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLParseException; +import pyUML.pythonTree.PythonTreeRoot; + +public class SyncCodeAction implements IObjectActionDelegate, IRunnableWithProgress{ + + private IProject project; + private PythonTreeRoot pythonRoot = null; + + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + // Auto-generated method stub + + } + + /** + * Run this action manually with a Progress Monitor. + * If the monitor is null, it will be created + * A PythonTreeRoot object can be given so that + * The code will not be re-analyzed for better performance. + * @param project The synchronized project + * @param root The PythonTreeRoot created before (optional) + * @param monitor A progress monitor + */ + public static void run(IProject project, PythonTreeRoot root, IProgressMonitor monitor) { + SyncCodeAction createCode = new SyncCodeAction(); + createCode.setProject(project); + createCode.setRoot(root); + + if (monitor == null) { + ProgressMonitorDialog dialog = new ProgressMonitorDialog(null); + try { + dialog.run(false, true, createCode); + } catch (InterruptedException e) {e.printStackTrace();} + catch (InvocationTargetException e) {e.printStackTrace();} + } else { + createCode.doSync(monitor); + } + } + + /** + * run this action ( + */ + public void run(IAction action) { + ProgressMonitorDialog monitor = new ProgressMonitorDialog(null); + + try { + monitor.run(false, true, this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Do a synchronize run. This is the central method. + * It is called in automatic or manual mode + * @param monitor a ProgressMonitor + */ + public void doSync(IProgressMonitor monitor) { + // read project + IPath projectPath = project.getLocation(); + String umlFileName=projectPath. + append(GlobalConstants.getPyUmlDir()). + append(project.getName()+".uml").toOSString(); + + String umlSavedFileName=projectPath. + append(GlobalConstants.getPyUmlDir()). + append(project.getName()+"-backup.uml").toOSString(); + + + File savedModel = new File(umlSavedFileName); + File modelToCopy = new File(umlFileName); + + // read newest Model + EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(umlFileName); + + // read backuped Model if it exists + // to be able to see what changed between models + EObject diagramRootBackup = null; + if (savedModel.exists()) + diagramRootBackup = UMLToolsHelperMethods.loadUMLDiagram(umlSavedFileName); + + Model model = (Model) diagramRoot; + + // get model -> xmi-id dictionary + UMLResource res = (UMLResource) model.eResource(); + Map modelXmiDict = res.getEObjectToIDMap(); + + // do the same for the backupModel: + // get model -> xmi-id dictionary + + Map xmiModelDictOld = new HashMap(); + int classCount = 0; // count classes for progression bar + if (diagramRootBackup != null) { + UMLResource resBack = (UMLResource) ((Model)diagramRootBackup).eResource(); + Map modelXmiDictOld = resBack.getEObjectToIDMap(); + + // create reverse dict, so that xmi_id can be the key + for (EObject modelObject : modelXmiDictOld.keySet()) { + String xmi_id = modelXmiDictOld.get(modelObject); + xmiModelDictOld.put(xmi_id, modelObject); + if (modelObject instanceof Classifier) + classCount++; + } + } + + // create PythonTree from PythonCode + if (this.pythonRoot == null) + try { + this.pythonRoot = new PythonTreeRoot(this.project, true, monitor); + } + catch (PyUMLCancelledException e) { + MessageDialog.openWarning(null, "Operation cancelled", + "The Operation was cancelled by the user"); + return; + } + 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; + } + + + // ######## Synchronize the Code ############################ + monitor.beginTask("Synchronize the Python Code", IProgressMonitor.UNKNOWN); + try { + pythonRoot.synchronizeCode(model, modelXmiDict, xmiModelDictOld, monitor, classCount); + } + catch (PyUMLCancelledException e) { + MessageDialog.openWarning(null, "Operation cancelled", + "The Operation was cancelled by the user"); + return; + } catch (Throwable t) { + t.printStackTrace(); + MessageDialog.openError(null,"Error synchronizing Code!", + t.getClass().getName() + " while synchronizing Code!: \n\n" + + t.getMessage()); + } + + + // ########################################################## + + + // backup model -> copy new current model over old one + try{ + JavaHelperMethods.copy(modelToCopy, savedModel); + EclipseHelperMethods.updateFile(savedModel.getAbsolutePath(), this.project); + } catch (IOException ex) { + MessageDialog.openError(null,ex.getMessage(),"Unable to copy model file to: " + umlSavedFileName + +"\nCode creation may not work properly!"); + } + monitor.done(); + } + + /** + * Called by Eclipse. If a project is selected, it is saved + */ + public void selectionChanged(IAction action, ISelection selection) { + if (selection instanceof TreeSelection) { + TreeSelection ts = (TreeSelection) selection; + Object selectedElement = ts.getFirstElement(); + if (selectedElement instanceof IProject) { + IProject project = (IProject) selectedElement; + this.project = project; + } + } + + } + + /** + * Get the used project + * @return + */ + public IProject getProject() { + return project; + } + + /** + * Manually set the project to use + * @param project + */ + public void setProject(IProject project) { + this.project = project; + } + + /** + * Manually set a PythonTreeRoot to use (if given, + * it will not be created again) + * @param root + */ + public void setRoot(PythonTreeRoot root) { + this.pythonRoot = root; + } + + + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + doSync(monitor); + } +} diff --git a/pyUml/src/pyUML/actions/SyncCodeHandler.java b/pyUml/src/pyUML/actions/SyncCodeHandler.java new file mode 100755 index 0000000..dbb043b --- /dev/null +++ b/pyUml/src/pyUML/actions/SyncCodeHandler.java @@ -0,0 +1,24 @@ +package pyUML.actions; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; + +import pyUML.backend.EclipseHelperMethods; + + +/** + * An action Handler that calls SyncCodeAction for a user-selected project + */ +public class SyncCodeHandler extends AbstractHandler{ + public static IProject selectedProject = null; + + @Override + public Object execute(ExecutionEvent arg0) throws ExecutionException { + EclipseHelperMethods.saveAllOpenEditors(); + IProject project = EclipseHelperMethods.selectProject(); + SyncCodeAction.run(project, null, null); + return null; + } +} diff --git a/pyUml/src/pyUML/actions/SyncModelAction.java b/pyUml/src/pyUML/actions/SyncModelAction.java new file mode 100755 index 0000000..a426246 --- /dev/null +++ b/pyUml/src/pyUML/actions/SyncModelAction.java @@ -0,0 +1,328 @@ +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 modelXmiDict = new HashMap(); + Map xmiModelDict = new HashMap(); + + // 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); + } +} diff --git a/pyUml/src/pyUML/actions/SyncModelHandler.java b/pyUml/src/pyUML/actions/SyncModelHandler.java new file mode 100755 index 0000000..772a3b2 --- /dev/null +++ b/pyUml/src/pyUML/actions/SyncModelHandler.java @@ -0,0 +1,27 @@ +package pyUML.actions; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.resources.IProject; + +import pyUML.backend.EclipseHelperMethods; + + + +/** +* An action Handler that calls SyncModelAction for a user-selected project +*/ +public class SyncModelHandler extends AbstractHandler{ + public static IProject selectedProject = null; + + @Override + public Object execute(ExecutionEvent arg0) throws ExecutionException { + EclipseHelperMethods.saveAllOpenEditors(); + IProject project = EclipseHelperMethods.selectProject(); + + SyncModelAction.runModelSync(project); + + return null; + } +} diff --git a/pyUml/src/pyUML/backend/ChooseProjectDialog.java b/pyUml/src/pyUML/backend/ChooseProjectDialog.java new file mode 100755 index 0000000..8f0c746 --- /dev/null +++ b/pyUml/src/pyUML/backend/ChooseProjectDialog.java @@ -0,0 +1,126 @@ +package pyUML.backend; + +import java.util.Vector; + +import org.eclipse.core.resources.IProject; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; + +/** + * This is a SWT dialog the lets the user choose one of + * the given projects. + * By the next run, the lately selected project in preselected + */ +public class ChooseProjectDialog extends Dialog{ + public static IProject preSelectedProject = null; + + private java.util.List projects; + private List selectProjectBox; + private IProject selectedProject = null; + private java.util.List projectsList; + + public ChooseProjectDialog(Shell parent, java.util.List projects) { + super(parent); + this.projects = projects; + } + + /** + * Initializes a ChooseProjectDialog and lets the user choose + * one of the given projects. + * After "Use" or "Cancel" is pressed, the selected + * Project is returned, or null if cancel was pressed. + * @param parent + * @param projects + * @return + */ + public static IProject runChooseProject(Shell parent, java.util.List projects) { + if (preSelectedProject != null && (! preSelectedProject.isOpen())) + preSelectedProject = null; + + // Create dialog + ChooseProjectDialog dialog = new ChooseProjectDialog(parent, projects); + dialog.create(); + + // Pre-select project that was selected before + if (ChooseProjectDialog.preSelectedProject != null) { + String preSelectedProjectName = ChooseProjectDialog.preSelectedProject.getName(); + if (dialog.getProjectsList().contains(preSelectedProjectName)) { + int index = dialog.getProjectsList().indexOf(preSelectedProjectName); + dialog.selectProjectBox.setSelection(index); + } + } + + dialog.open(); + + ChooseProjectDialog.preSelectedProject = dialog.selectedProject; + + return dialog.selectedProject; + } + + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX); + createControls(composite); + //add controls to composite as necessary + return composite; + } + + public void createControls (Composite composite) { + // create graphical components + Shell shell = composite.getShell(); + shell.setText("Select Python Project To Use"); + + Group selectBoxGroup = new Group(composite, SWT.None); + selectBoxGroup.setText("Please select a project to be used by PyUML:"); + + selectBoxGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + selectBoxGroup.setLayout(new GridLayout(1, true)); + + this.selectProjectBox = new List( selectBoxGroup, SWT.BORDER|SWT.SINGLE|SWT.V_SCROLL|SWT.H_SCROLL ); + selectProjectBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + this.projectsList = new Vector(); + for (IProject project : this.projects) { + this.selectProjectBox.add(project.getName()); + projectsList.add(project.getName()); + } + + selectProjectBox.setSize(300,300); + + //buttonGroup.pack(); + selectBoxGroup.pack(); + + composite.pack(); + + } + + public void widgetDefaultSelected(SelectionEvent e) { + // Not needed in this dialog + } + + protected void buttonPressed(int buttonId) { + if (IDialogConstants.OK_ID == buttonId) { + int selectedIndex = this.selectProjectBox.getSelectionIndex(); + if (selectedIndex < 0) + return; + + this.selectedProject = this.projects.get(selectedIndex); + this.close(); + } else if (IDialogConstants.CANCEL_ID == buttonId) { + cancelPressed(); + } + } + + public java.util.List getProjectsList() { + return projectsList; + } +} diff --git a/pyUml/src/pyUML/backend/EclipseHelperMethods.java b/pyUml/src/pyUML/backend/EclipseHelperMethods.java new file mode 100755 index 0000000..36f2efb --- /dev/null +++ b/pyUml/src/pyUML/backend/EclipseHelperMethods.java @@ -0,0 +1,290 @@ +package pyUML.backend; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; +import org.python.pydev.plugin.nature.PythonNature; + +/** + * Some Helper methods for Eclipse-specific tasks + */ +public class EclipseHelperMethods { + + /** + * Closes an open Editor, if it is already opened + * @param project the current project + * @param editorName the Name of the editor to close (or a REGEX) + * @return true, if an editor was closed, false, if nothing was done + */ + public static boolean closeEditorByName(IProject project, String editorName){ + IEditorReference editor = firstOpenEditorByName(editorName); + if (editor == null) + return false; + IWorkbenchPage page = + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + return page.closeEditor(editor.getEditor(true), true); + } + + + /** + * Looks for an open editor with a name that matches the given regex. + * Returns a list of matching editors or an empty list, if no such editor is open. + * @param editorNameRegex + * @return + */ + public static List lookForOpenEditorByName(String editorNameRegex) { + IWorkbenchPage page = + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + + List editorList = new Vector(); + for (IEditorReference editor : page.getEditorReferences()) { + if (editor.getTitle().matches(editorNameRegex)) { + editorList.add(editor); + } + } + return editorList; + } + + /** + * Looks for an open editor with a name that matches the given regex. + * Returns the first matching editors or null, if no such editor is open. + * @param editorNameRegex + * @return + */ + public static IEditorReference firstOpenEditorByName(String editorNameRegex) { + List editorList = lookForOpenEditorByName(editorNameRegex); + if (editorList.size() == 0) + return null; + else + return editorList.get(0); + } + + /** + * Reads the content of an IFile and returns teh String of the content + * @param file the IFile to read + * @return The file content String, null on error + */ + public static String iFileToString(IFile file){ + String fileContents = ""; + try{ + BufferedReader reader = new BufferedReader(new InputStreamReader(file.getContents())); + String line; + while ((line = reader.readLine()) != null) { + fileContents+= line+"\n"; + } + return fileContents; + } + catch (IOException e) { + MessageDialog.openError(null, "Error Reading File", + "Cannot Read file "+file+"\nReason:\n"+e.getMessage()); + } + catch (CoreException e) { + MessageDialog.openError(null, "Error Reading File", + "Cannot Read file "+file+"\nReason:\n"+e.getMessage()); + } + + return null; + } + + /** + * Writes a string to an IFile. The old file content is replaced completely. + * + * @param file the IFile to update + * @param s the string to write to the file + * @return true on success, false otherwise + */ + public static boolean StringToIFile(IFile file, String s) { + try{ + file.setContents(JavaHelperMethods.stringToStream(s), + IResource.FORCE, null); + EclipseHelperMethods.updateFile(file); + return true; + } catch (CoreException err) { + MessageDialog.openError(null, "Error writing file", err.getMessage()); + } + return false; + } + + /** + * marks the ressource as updated in eclipse + * @param file the changed IFile + */ + public static void updateFile(IFile file) { + try { + file.refreshLocal(1, null); + } catch (CoreException e) { + System.out.println("Error updating ressource "+file.getName()); + } + } + + /** + * marks the resource as updated in eclipse + * @param path the full path of the changed file + */ + public static void updateFile(String path, IProject project) { + try { + IFile file = createFile(path, project); + file.refreshLocal(1, null); + } catch (CoreException e) { + System.out.println("Error updating ressource "+path); + e.printStackTrace(); + } + } + + /** + * marks the folder as updated in eclipse + * @param path the full path of the changed file + */ + public static void updateFolder(String path, IProject project) { + try { + IFolder file = createFolder(path, project); + file.refreshLocal(IResource.DEPTH_INFINITE, null); + } catch (CoreException e) { + System.out.println("Error updating folder "+path); + e.printStackTrace(); + } + } + + /** + * creates an IFile resource out of an absolute Path and a project + * (the file is not created on the file system, only an IFile Object + * with appropriate path is created) + */ + public static IFile createFile(String path, IProject project) { + // cut everything in front of project name + String localPath = path.replace(project.getLocation().toOSString(), ""); + IPath relativeFilePath = project.getFullPath().append(localPath); + return project.getWorkspace().getRoot().getFile(relativeFilePath); + } + + /** + * creates an IFolder resource out of an absolute Path and a project + * (the folder is not created on the file system, only an IFolder Object + * with appropriate path is created) + */ + public static IFolder createFolder(String path, IProject project) { + // cut everything in front of project name + String localPath = path.replace(project.getLocation().toOSString(), ""); + IPath relativeFilePath = project.getFullPath().append(localPath); + return project.getWorkspace().getRoot().getFolder(relativeFilePath); + } + + + /** + * Saves all Editors opened in the Workbench. + */ + public static void saveAllOpenEditors() { + // save all open editors + // (this may fail if the process is forked) + // (-> catch NullpointerException and do not save, then) + try { + IWorkbenchPage page = + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + page.saveAllEditors(false); + } catch (NullPointerException e) {} + } + + + + public static boolean isPythonProject(IProject project) { + PythonNature store = new PythonNature(); + store.setProject(project); + try { + store.getPythonPathNature().getProjectSourcePathSet(); + } catch (CoreException e) { + return false; + } + catch (NullPointerException e) { + return false; + } + catch (Exception e) { + e.printStackTrace(); + } + return true; + } + + /** + * Finds the source folder(s) of this python project. + * If an error occurs (e.g. the project is no python + * project), the project location is returned. + * Source folders contained in other source folders are + * removed from list. + * + * @param project + * @return + */ + public static Set getPythonSrcDirs(IProject project) { + PythonNature store = new PythonNature(); + store.setProject(project); + Set srcPaths = new HashSet(); + try{ + Set srcStrings = store.getPythonPathNature().getProjectSourcePathSet(); + srcDirLoop: + for (String dirString : srcStrings) { + + // continue, if this dir is already contained in any other dir + for (String dirString2 : srcStrings) { + if (dirString != dirString2 && dirString2.startsWith(dirString)) + continue srcDirLoop; + } + + IPath srcPath = new Path(dirString); + IPath srcDir = srcPath.removeFirstSegments(1); //remove project dir + IPath completeSrcPath = project.getLocation().append(srcDir); + srcPaths.add(completeSrcPath); + } + + return srcPaths; + } + catch (CoreException e) { + srcPaths.add(project.getLocation()); + return srcPaths; + } + } + + /** + * This method chooses from the list of available Projects + * in the Workspace the project to work with, which is + * -> a python project + * -> if there are several, the user us asked which one to use + * -> if there is no project selected, the user asked to select one + * + * @return the pyDev project that was selected + * null, if no project could be chosen + */ + public static IProject selectProject() { + IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + List pyDevProjects = new Vector(); + // find all pyDev-Projects + for (IProject project : projects) { + if (project.isOpen() && isPythonProject(project)) + pyDevProjects.add(project); + } + if (pyDevProjects.size() == 0) + return null; + + if (pyDevProjects.size() == 1) + return (pyDevProjects.get(0)); + + // let user choose the project to use + return ChooseProjectDialog.runChooseProject((Shell) null, pyDevProjects); + } +} diff --git a/pyUml/src/pyUML/backend/GlobalConstants.java b/pyUml/src/pyUML/backend/GlobalConstants.java new file mode 100755 index 0000000..97d3ea2 --- /dev/null +++ b/pyUml/src/pyUML/backend/GlobalConstants.java @@ -0,0 +1,51 @@ +package pyUML.backend; + +import java.util.Arrays; +import java.util.List; + +/** + * + * This class holds global parameters used by different classes + * of PyUML + * + */ +public class GlobalConstants { + + private final static String pyUmlDir="PyUML"; + private final static String viewUmlExtension = ".pyUmlView.uml"; + private final static String viewConfExtension = ".pyUmlViewConfig"; + private final static String diagramExtension = ".umlclass_diagram"; + private final static String unknownExpression = "\"??unknown??\""; + private final static String fullDefault = "PyUML:FullDefault:"; + + public final static String STEREOTYPE_BEANCLASS = "BeanClass"; + private final static String[] possibleStereotypes = {GlobalConstants.STEREOTYPE_BEANCLASS}; + + public static String getViewUmlExtension() { + return viewUmlExtension; + } + + public static String getPyUmlDir() { + return pyUmlDir; + } + + public static String getViewConfExtension() { + return viewConfExtension; + } + + public static String getDiagramExtension() { + return diagramExtension; + } + + public static String getUnknownExpression() { + return unknownExpression; + } + + public static String getFullDefault() { + return fullDefault; + } + + public static List getPossibleStereoTypes() { + return Arrays.asList(possibleStereotypes); + } +} diff --git a/pyUml/src/pyUML/backend/JavaHelperMethods.java b/pyUml/src/pyUML/backend/JavaHelperMethods.java new file mode 100755 index 0000000..1428cb6 --- /dev/null +++ b/pyUml/src/pyUML/backend/JavaHelperMethods.java @@ -0,0 +1,84 @@ +package pyUML.backend; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * some helper methods for common java problems, i.e. file copying + */ +public class JavaHelperMethods { + + /** + * Fast & simple file copy. + * copies source file to destination file + */ + public static void copy(File source, File dest) throws IOException { + + InputStream in = new FileInputStream(source); + OutputStream out = new FileOutputStream(dest); + final int bufferSize = 4096; + try { + byte[] buffer = new byte[bufferSize]; + int bytesRead; + while ((bytesRead = in.read(buffer)) >= 0) { + out.write(buffer, 0, bytesRead); + } + } finally { + out.close(); + in.close(); + } + } + public static InputStream stringToStream(String s) { + return new ByteArrayInputStream(s.getBytes()); + } + + /** + * Joins an Array of Strings to one big String separated by + * a separator + * @param array The String array to join + * @param separator The separator + * @return the joined String + */ + public static String join(String[] array, String separator) { + if (array==null) return ""; + StringBuffer sb = new StringBuffer(array[0]); + for(int i=1; i 19) { + exprString = exprString.substring(0,14) + "(...)"; + } + + return exprString; + } + + /** + * Helper method for getStringOfExpr() + * Can read a multi-line-expression of an attribute + * + * @param expr + * @param pyFile + * @param nextLine + * @return + */ + public static String readExprAsText(exprType expr, PythonTreeFile pyFile, int nextLine) { + String[] lines = pyFile.getSplittedFileContent(); + String exprString = lines[expr.beginLine-1]; + exprString = exprString.substring(exprString.indexOf("=")+1); + exprString = exprString.replaceAll("^[\\s]*",""); + exprString = exprString.replaceAll(" # created by PyUML.*$", ""); + + exprString = exprString.replaceAll("[\\s]*$", ""); + + for (int i=expr.beginLine; i < nextLine - 1; i++) { + String line = lines[i]; + + // docString comments of static attributes have a wrong "beginLine" value + // -> manually define here to ignore docStrings! + if (line.matches("^[\\s]*\"\"\".*")) + break; + line = line.replaceAll("# created by PyUML.*$", ""); + line = " " +line.replaceAll("^[\\s]*", ""); + exprString += line; + exprString = exprString.replaceAll("[\\s]*$", ""); + } + + // if there are called other classes/packages, the index + // is on the value, not on the "a.b.c"-prefix. + // if that's the case, add the prefix afterwards: + + return exprString; + } + + /** + * Simple method to extract the XMI-ID out of a line + * containing the PyUML string "# PyUML: XMI_ID: ..." + * @param content + * @return + */ + public static String extractXmiFromString(String content) { + String xmi_id = null; + String[] lines = content.split("\n"); + for (String line : lines) { + if (line.matches("\\s*# PyUML:.*")) { + String[] splittedLine = line.split("XMI_ID:"); + if (splittedLine.length == 2) { + xmi_id = splittedLine[1]; + } + } + } + return xmi_id; + } + + + /** + * This creates a string containing the model package structure as + * "/packSup/packSub/" , where the last package contains the + * current class. + * @param cl The class in the model to find the package structure for + * @return a string containing the parent package structure + * of this class + * + */ + public static String getModelPackageStructure(org.eclipse.uml2.uml.Type cl) { + org.eclipse.uml2.uml.Package pack = cl.getPackage(); + String structure = ""; + while (! (pack instanceof Model)) + { + structure = "/"+pack.getName() + structure ; + pack = pack.getNestingPackage(); + } + + return structure + "/"; + } +} diff --git a/pyUml/src/pyUML/backend/PyUMLProfile.java b/pyUml/src/pyUML/backend/PyUMLProfile.java new file mode 100755 index 0000000..1ba05a1 --- /dev/null +++ b/pyUml/src/pyUML/backend/PyUMLProfile.java @@ -0,0 +1,59 @@ +package pyUML.backend; + +public class PyUMLProfile { + + /** + * @return the pyUML XMLProfile as a string; + * the hard-coded profile String can be replaces by a method + * loading a profile UML file + */ + public static String getProfileString() { + return profileString; + } + + private static String profileString = + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n" ; +} diff --git a/pyUml/src/pyUML/backend/UMLToolsHelperMethods.java b/pyUml/src/pyUML/backend/UMLToolsHelperMethods.java new file mode 100755 index 0000000..fb40dbb --- /dev/null +++ b/pyUml/src/pyUML/backend/UMLToolsHelperMethods.java @@ -0,0 +1,311 @@ +package pyUML.backend; + +import java.io.IOException; +import java.util.List; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.commands.operations.OperationHistoryFactory; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.util.WrappedException; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.gmf.runtime.common.core.command.CommandResult; +import org.eclipse.gmf.runtime.diagram.core.services.ViewService; +import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; +import org.eclipse.gmf.runtime.emf.core.GMFEditingDomainFactory; +import org.eclipse.gmf.runtime.notation.Diagram; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart; +import org.eclipse.uml2.diagram.clazz.part.Messages; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil; +import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry; + +import pyUML.listeners.LiveValidationListener; +import pyUML.listeners.ViewChangeListener; +import pyUML.views.EditView; +import pyUML.views.EditViewWizard; + + +/** + * This class contains methods for reading and writing eclipse + * UML models and for model handling + */ +public class UMLToolsHelperMethods { + + /** + * Loads an eclipse UML2 model + * + * @param umlFileName a String containing the filename of the eclipse uml2 diagram + * @return the model root as EObject, null if an exception occured + */ + public static EObject loadUMLDiagram(String umlFileName) { + try { + Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlFileName), true); + return resource.getContents().get(0); + /*for (EObject content : resource.getContents()) { + if (content instanceof Model) + return content; + }*/ + //return null; + + } catch (WrappedException ex) { + MessageDialog.openError(null,ex.getMessage(),"Unable to load model: " + umlFileName+"\n"+ex.getMessage()); + return null; + } + } + + /** + * opens a eclipse uml2tools UML diagram in the editor + * Will edit the diagram file, if a wrong path to a UML model is set + * (Unfortunately, UML diagrams save absolute paths of the corresponding + * UML file) + * @param project the current project + * @param diagramFile the fileName in the pyUml directory + * @param putToFront if the editor is already opened, with putToFront==true + * the editor is given the focus, with putToFront==false nothing is done + * @param umlModelName The name of the corresponding UML model to this model + * This is needed to ensure the diagram has a correct UML file path set + * @return the IEitorPat of the newly opened Diagram, null on Error + * @throws PartInitException + */ + public static IEditorPart openDiagram(IProject project, IFile diagramFile, String umlModelFileName, boolean putToFront) { + // see, if UML model path is set correctly + String absoluteUmlPath = project.getLocation().append(GlobalConstants.getPyUmlDir()) + .append(umlModelFileName).toOSString(); + String[] diagramFileContent = EclipseHelperMethods.iFileToString(diagramFile).split("\n"); + + for (int i =0; i< diagramFileContent.length; i++) { + String line = diagramFileContent[i]; + Pattern pattern = Pattern.compile("(\\s* affectedFiles = new Vector(); + final org.eclipse.uml2.uml.Package model + = (org.eclipse.uml2.uml.Package) modelObject; + URI diagramModelURI = URI.createPlatformResourceURI(newDiagramFile.getFullPath().toString(), true); + ResourceSet resourceSet = editingDomain.getResourceSet(); + final Resource diagramResource = resourceSet.createResource(diagramModelURI); + affectedFiles.add(newDiagramFile); + + // create diagram from model + AbstractTransactionalCommand command = new AbstractTransactionalCommand(editingDomain, Messages.UMLNewDiagramFileWizard_InitDiagramCommand, affectedFiles) { + public CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) { + int diagramVID = UMLVisualIDRegistry.getDiagramVisualID(model); + if (diagramVID != PackageEditPart.VISUAL_ID) { + return CommandResult.newErrorCommandResult(Messages.UMLNewDiagramFileWizard_IncorrectRootError); + } + Diagram diagram = ViewService.createDiagram(model, PackageEditPart.MODEL_ID, UMLDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT); + diagramResource.getContents().add(diagram); + return CommandResult.newOKCommandResult(); + } + }; + + // save the created diagram file + try { + OperationHistoryFactory.getOperationHistory().execute(command, new NullProgressMonitor(), null); + diagramResource.save(UMLDiagramEditorUtil.getSaveOptions()); + } catch (org.eclipse.core.commands.ExecutionException e) { + e.printStackTrace(); + } + catch (IOException e) { + e.printStackTrace(); + } + // change full path file name to relative path + String diagramFileContent = EclipseHelperMethods.iFileToString(newDiagramFile);//.split("\n"); + + Pattern pattern = Pattern.compile( "(.* synchronize model every time the view is saved + + + + String openEditorName=umlEditor.getTitle(); + String viewPath = this.project.getLocation() + .append(GlobalConstants.getPyUmlDir()) + .append(openEditorName.replace(GlobalConstants.getDiagramExtension(), "") + + GlobalConstants.getViewUmlExtension()).toOSString(); + SynchronizeModelByView.synchronizeGlobalModel(viewPath, this.project); + + + IFile globalModelDiagramFile = this.project.getWorkspace() + .getRoot().getFile(this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(project.getName()+GlobalConstants + .getDiagramExtension())); + + // close all sub-package pyUML.views of global model diagram + for ( org.eclipse.ui.IEditorReference editor : + EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) { + PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().closeEditor(editor.getEditor(true), true); + } + + // after creating model, be sure the diagram view is reloaded + boolean diagramOpened = null != EclipseHelperMethods + .lookForOpenEditorByName(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()); + IEditorPart modelDiagram = UMLToolsHelperMethods.refreshDiagramEditor(project, globalModelDiagramFile, keepFocus); + modelDiagram.addPropertyListener(new ModelChangeListener(project)); + + } + } + } + } +} diff --git a/pyUml/src/pyUML/plugin/Activator.java b/pyUml/src/pyUML/plugin/Activator.java new file mode 100755 index 0000000..061377c --- /dev/null +++ b/pyUml/src/pyUML/plugin/Activator.java @@ -0,0 +1,50 @@ +package pyUML.plugin; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "pyUML.plugin"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeAttribute.java b/pyUml/src/pyUML/pythonTree/PythonTreeAttribute.java new file mode 100755 index 0000000..9759157 --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeAttribute.java @@ -0,0 +1,193 @@ +package pyUML.pythonTree; + +import java.util.List; +import java.util.Vector; + +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.VisibilityKind; +import org.python.pydev.parser.jython.ast.Assign; +import org.python.pydev.parser.jython.ast.Attribute; +import org.python.pydev.parser.jython.ast.Call; +import org.python.pydev.parser.jython.ast.Name; +import org.python.pydev.parser.jython.ast.NameTok; +import org.python.pydev.parser.jython.ast.exprType; + +import pyUML.backend.GlobalConstants; +import pyUML.backend.ParseHelpers; + + +/** + * This PythonTree member represents a python attribute. + * It can represent static attributes (defined outside any method) + * or object attributes (defined with "self." inside __init__() + */ +public class PythonTreeAttribute extends PythonTreeNode { + private Assign astNode; + private boolean valid; + private boolean staticAtt; + private String value; + private String fullValue; + private int line; + private int col; + private int nextLine; + + /** + * @param parent the parent in the PythonTree + * @param astNode the corresponding Python AST node + * @param staticAtt true, if this is an attribute outside a + * function definition + * @param nextLine the line of the next Python statement. This + * is needed to extract multi-line-attributes + */ + public PythonTreeAttribute(PythonTreeNode parent, Assign astNode, boolean staticAtt, int nextLine) { + super(parent); + this.astNode = astNode; + this.staticAtt = staticAtt; + this.nextLine = nextLine; + this.valid = this.initAttribute(); + + } + + /** + * @return false, if this is no valid attribute + */ + private boolean initAttribute(){ + exprType left = this.astNode.targets[0]; + exprType right = this.astNode.value; + + // analyze the left side of the assign and see + // if this might be a valid attribute + try { + if (staticAtt) { //static: attr without "self" + this.name = ((Name)left).id; + this.line = ((Name)left).beginLine; + this.col = ((Name)left).beginColumn; + } + else{ // object attr: begins with "self." + Attribute leftAtt = (Attribute)left; + if (! ((Name)leftAtt.value).id.equals("self")) + return false; + this.name =((NameTok)(leftAtt).attr).id; + this.line = ((NameTok)(leftAtt).attr).beginLine; + this.col = ((NameTok)(leftAtt).attr).beginColumn; + + } + } + catch (ClassCastException e) { + // if anything is not like expected, this is not a + // att=value + // or self.att=value + // attribute -> this is not considered a valid attribute! + return false; + } + + // now, look at the right side + if (right instanceof Call) + return false; + this.value = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, true, this.nextLine); + + // if the value was abbreviated, save full value, also. + if (this.value.endsWith("(...)")) { + this.fullValue = ParseHelpers.getStringOfExpr(right, this.getParent().getInFile(), true, false, this.nextLine); + } + + // if everything went right, this is considered a valid attribute! + return true; + } + + /** + * A PythonTreeAttribute is created always when an Assign + * is found in the class body or the constructor. + * Sometimes an assign does not declare an attribute; then, + * this object should not be added to the PythonTreeClass + * attributes and be left for the garbage collector. + * + * @return if this astNode really represents a python + * static/object attribute and shall be saved + */ + public boolean isValid() { + return this.valid; + } + + public boolean isStatic() { + return staticAtt; + } + + /** + * @return this attribute's (default) value + */ + public String getValue() { + return value; + } + + public boolean synchronizeModel(NamedElement modelElement) { + Property modelProperty = (Property) modelElement; + + // set this attribute private in model, if its name starts with "__" + // use protected, if class starts with "_" (this is only python convention) + if (this.getName().startsWith("__")) { + modelProperty.setVisibility(VisibilityKind.PRIVATE_LITERAL); + } else if (this.getName().startsWith("_")) { + modelProperty.setVisibility(VisibilityKind.PROTECTED_LITERAL); + } + + String defVal = this.getValue(); + if (! "None".equals(defVal)) + modelProperty.setDefault(this.getValue()); + // if default value was abbreviated -> + // save full default value as comment, + // beginning with a PyUML Marker + if (this.fullValue != null) { + Comment fullValueComment = null; + for (Comment comment : modelProperty.getOwnedComments()) { + if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) { + fullValueComment=comment; + break; + } + } + if (fullValueComment == null) + fullValueComment = modelProperty.createOwnedComment(); + + fullValueComment.setBody(GlobalConstants.getFullDefault() + + this.fullValue); + } else { + // there is no "full" value -> delete all comments + // that save a full value + List commentList = new Vector(); + commentList.addAll(modelProperty.getOwnedComments()); + for (Comment comment : commentList) { + if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) { + comment.destroy(); + } + } + } + modelProperty.setIsStatic(this.isStatic()); + return true; + } + + public int getLine() { + return line; + } + + public int getCol() { + return col; + } + + public PythonTreeClass getParent() { + return (PythonTreeClass) super.getParent(); + } + + /** + * @return the un-abbreviated attribute (default) value + * for this attribute + */ + public String getFullValue() { + return fullValue; + } + + public int getNextLine() { + return nextLine; + } +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeClass.java b/pyUml/src/pyUML/pythonTree/PythonTreeClass.java new file mode 100755 index 0000000..e807923 --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeClass.java @@ -0,0 +1,1177 @@ +package pyUML.pythonTree; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.uml2.uml.Association; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Operation; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Realization; +import org.eclipse.uml2.uml.Relationship; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.VisibilityKind; +import org.eclipse.uml2.uml.internal.impl.RealizationImpl; +import org.python.pydev.parser.jython.ast.Assign; +import org.python.pydev.parser.jython.ast.Attribute; +import org.python.pydev.parser.jython.ast.ClassDef; +import org.python.pydev.parser.jython.ast.Expr; +import org.python.pydev.parser.jython.ast.FunctionDef; +import org.python.pydev.parser.jython.ast.Name; +import org.python.pydev.parser.jython.ast.NameTok; +import org.python.pydev.parser.jython.ast.Str; +import org.python.pydev.parser.jython.ast.exprType; +import org.python.pydev.parser.jython.ast.stmtType; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.ParseHelpers; +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLParseException; +import pyUML.exceptions.PyUMLSynchronizeCodeException; +import pyUML.refactoring.BicycleRefactoring; +import pyUML.refactoring.FileRefactoring; + + + +/** + * Part of PythonTree representing a class + * - can write XMI ID to classes docstring + * + */ +public class PythonTreeClass extends PythonTreeNode{ + ClassDef astNode; + String docString; + PythonTreeFile inFile; + int docStringLine; + int docStringCol; + int lastLine; + List usedStereotypes; + Set superClasses; + private String indent = " "; + Map childMethodDict; + Map childStaticAttrDict; + Map childObjectAttrDict; + + /** + * Constructor to create a PythonTreeClass of a python class AST + * @param parent the PythonTreePackage, which is parent of this class + * @param inFile the PythonTreeFile + * @param astNode the corresponding Python AST node + * @param lastLine the last line of this class definition; 0 if + * class ends with end of file + */ + public PythonTreeClass(PythonTreeNode parent, PythonTreeFile inFile, ClassDef astNode, int lastLine) throws PyUMLParseException, PyUMLCancelledException{ + super(parent); + this.astNode = astNode; + this.inFile = inFile; + this.lastLine = lastLine; + this.superClasses = new HashSet(); + this.childMethodDict = new Hashtable(); + this.childStaticAttrDict = new Hashtable(); + this.childObjectAttrDict = new Hashtable(); + this.initClassNode(); + this.initSubStructures(); + + } + + private void initClassNode() throws PyUMLParseException, PyUMLCancelledException{ + this.name=((NameTok) this.astNode.name).id; + this.docStringLine = this.astNode.beginLine; + this.docStringCol = this.astNode.beginColumn; + + + // get class Body + stmtType[] classBody = this.astNode.body; + if (classBody.length == 0) { + return; + } + // extract DocString, if it exists + if (classBody[0] instanceof Expr) { + Expr exp = (Expr) classBody[0]; + if (exp.value instanceof Str) { + Str stringExp = (Str) exp.value; + if (stringExp.type == Str.TripleDouble) { + this.docString=stringExp.s; + this.docStringLine = stringExp.beginLine; + this.docStringCol = stringExp.beginColumn; + } + } + } + + //extract XMI-ID from DocString + if (this.docString != null) { + this.xmi_id = ParseHelpers.extractXmiFromString(this.docString); + if (this.xmi_id != null) + this.getRoot().getXmiClassDict().put(this.xmi_id, this); + } + + PythonTreeRoot root = this.getRoot(); + + // test if a class of this name already exists + String structuredName = this.getPackageStructure()+this.name; + this.getRoot().setSubTaskName(structuredName); + + if (root.getClassDict().containsKey(structuredName) && root.isShowWarnings()) { + String message = "Duplicate class detected!\n" + + "More than one class with the name " + this.name + + " was found \n" + + "in the package "+this.getPackageStructure() +"." + + "\nThis can lead to problems in PyUML.\n" + + "Please rename one of the classes in the code!\n" + + "Both classes will be ignored!"; + this.getParent().getChildClasses().remove(this.getRoot().getClassDict().get(structuredName)); + this.getRoot().getClassDict().remove(structuredName); + this.getRoot().getClassNameDict().remove(structuredName); + + MessageDialog.openWarning(null, "Duplicate class detected", message); + return; + //throw new PyUMLParseException(message); + } + + // initialize empty set of superclasses + root.getClassDict().put(structuredName, this); + root.getClassNameDict().put(structuredName, this.name); + + for (exprType superClass: this.astNode.bases) { + if (superClass instanceof Name) { + String superName = ((Name)superClass).id; + String superClassPackString = this.getPackFromImports(superName); + if (superClassPackString != null) + this.superClasses.add(superClassPackString); + } + else if (superClass instanceof Attribute) { + Attribute superAtt = (Attribute) superClass; + String superName = ((NameTok)superAtt.attr).id; + String packages = ((Name)superAtt.value).id; + String packageStructure = "/" + packages.replace(".", "/") + "/"; + this.superClasses.add(packageStructure+superName); + } + } + } + + /** + * initializes all Substructures of this class + * - Methods (object or static) + * - Static attributes (in class body) + * - Object attributes (in __init(self)) + * + * The PythonTree child objects are created and initialized + * in their constructor + */ + private void initSubStructures() throws PyUMLParseException{ + // parse class body + stmtType[] statements = this.astNode.body; + for (int i=0; i 0) + for (; line.charAt(indentLength) == ' ' && line.length() > indentLength +1; indentLength++) ; + + if (this.indent.length() != indentLength && ! line.matches("^[\\s]*\\\"\\\"\\\".*$")) { + this.indent = ""; + for (int j=0; j< indentLength; j++) + this.indent += " "; + } + + // get functions and object attributes + + int nextLine; + if (i < statements.length -1) + nextLine = statements[i+1].beginLine; + else + nextLine = (this.lastLine == -1) ? -1 : this.lastLine + 1; + + if (statement instanceof FunctionDef) { + // get line of next statement -> for a static method, this should + // be the staticmethod call + + PythonTreeMethod childMethod = new PythonTreeMethod(this, (FunctionDef) statement, nextLine); + + this.childMethodDict.put(childMethod.getName(), childMethod); + // look for object attributes in __init__ + if (childMethod.getName().equals("__init__")) { + stmtType[] methodStmts = childMethod.getAstNode().body; + // iterate over all method body statements + for (int j=0; j < methodStmts.length; j++) { + int nextStmtLine = nextLine; + if (j < methodStmts.length - 1 ) + nextStmtLine = methodStmts[j+1].beginLine; + stmtType methodStmt = methodStmts[j]; + if (methodStmt instanceof Assign) { + // need line of next statement to be able + // to multi-line-expressions + if (j < methodStmts.length-1) + nextStmtLine = methodStmts[j+1].beginLine; + PythonTreeAttribute childAtt = new PythonTreeAttribute(this, (Assign) methodStmt, false, nextStmtLine); + if (childAtt.isValid()) + this.childObjectAttrDict.put(childAtt.getName(), childAtt); + } + } + } + } + + // get static attributes + else if (statement instanceof Assign) { + PythonTreeAttribute childAtt = new PythonTreeAttribute(this, (Assign) statement, true, nextLine); + if (childAtt.isValid()) + this.childStaticAttrDict.put(childAtt.getName(), childAtt); + } + } + } + + /** + * Write/update the given XMI id to the classes docstring + * @param xmiID + */ + public void writeXmiID(String xmiID) { + if (this.docString != null) { + this.docString = docString.replaceAll("\\n[\\s]*# PyUML: [^\\n]*", ""); + + String lineToInsert =""; + lineToInsert += "# PyUML: Do not remove this line! # XMI_ID:" + xmiID+"\n"; + if (! this.docString.endsWith("\n")) + lineToInsert = "\n"+this.indent + lineToInsert + this.indent ; + if (! this.docString.startsWith("\n")) + this.docString = "\n"+this.indent + this.docString; + this.docString = docString + lineToInsert; + FileRefactoring.replaceFromCoordinate(this.inFile, this.docStringLine, this.docStringCol+3, this.docString, "\"\"\"", true); + }else{ + this.docString=this.indent+"\"\"\" # PyUML: Do not remove this line! # XMI_ID:" + xmiID + "\"\"\"\n"; + FileRefactoring.insertAtLine(this.inFile, this.docStringLine + 1, this.docString); + } + } + + /** + * Update the associations in the classes docstring. + */ + public boolean updateAssociations(Classifier modelClass) throws PyUMLSynchronizeCodeException { + if (this.docString != null) { + String lineToInsert=""; + if (modelClass.getAssociations().size() > 0) + lineToInsert += "# PyUML: Associations of this class:\n"; + + associationsLoop: + for (Association as : modelClass.getAssociations()) { + String asName = ""; + if (as.getName() != null && as.getName().length() > 0 ) + asName = "'" + as.getName()+"' "; + List ends = as.getEndTypes(); + String otherClass = "self "; + String otherEndLabel =""; + String ownEndLabel =""; + if (as.getMemberEnds().size() >1) { + Type end; + if (ends.size() > 1) { + Type end1 = ends.get(0); + Type end2 = ends.get(1); + end = (end1.equals(modelClass) ? end2 : end1); + otherEndLabel = (end1.equals(modelClass) ? as.getMemberEnds().get(1).getName() + : as.getMemberEnds().get(0).getName()); + ownEndLabel = (! end1.equals(modelClass) ? as.getMemberEnds().get(1).getName() + : as.getMemberEnds().get(0).getName()); + + + } else { + Type end1 = ends.get(0);; + Type end2 = as.getMemberEnds().get(1).getType(); + + if (end2 == null) + end = end1; + else + end = (end1.equals(modelClass)?end2:end1); + otherEndLabel = as.getMemberEnds().get(0).getName(); + ownEndLabel = as.getMemberEnds().get(1).getName(); + + if (end.equals(modelClass)) { + // if the only known end of the navigatable association + // is this class, ignore this association. + continue associationsLoop; + } + } + if (otherEndLabel != null && otherEndLabel.length() > 0) + otherEndLabel = " (being '"+otherEndLabel + "')"; + + else + otherEndLabel = ""; + + if (ownEndLabel != null && ownEndLabel.length() > 0) + ownEndLabel = "(being '"+ownEndLabel + "') "; + else + ownEndLabel = ""; + + + String endType = ""; + if (end instanceof Classifier) + endType = "class"; + else if (end instanceof Interface) + endType = "interface"; + else endType = "model element"; + + otherClass = endType+" "+ end.getName()+otherEndLabel+" in package "+ParseHelpers.getModelPackageStructure(end)+" "; + } + + + lineToInsert += this.indent+"# PyUML: Association "+asName+ownEndLabel+"to " +otherClass+"\n"; + } + + + String newDocString = this.docString.replaceAll("\\n[\\s]*# PyUML: Association[^\\n]*", ""); + + if (! newDocString.endsWith("\n" + this.indent)) + lineToInsert = "\n" + this.indent + lineToInsert; + if (! newDocString.startsWith("\n")) + newDocString = "\n" + this.indent + newDocString; + newDocString += lineToInsert; + + if (newDocString.equals(this.docString)) + return false; + + this.docString = newDocString; + FileRefactoring.replaceFromCoordinate(this.inFile, this.docStringLine, this.docStringCol+3, this.docString, "\"\"\"", true); + + this.setChanged(this.getPackageStructure()+this.getName()+"-docString", 0); + return true; + } + return false; + } + + /** + * gets a Set of PythonTreeClasses that are + * the superclasses of this class, which are located + * in the same project. + * This must be called only after a complete initialization + * of the Python Tree so that all super classes can be found + * in the root node's classNameDict. + */ + public Set getGeneralizationsInProject() { + + // try to find PythonTreeClasses from the superclass Strings + Set superClassesInProject = new HashSet(); + for (String superClass :this.superClasses) { + if (this.getRoot().getClassDict().containsKey(superClass)) + superClassesInProject.add(this.getRoot().getClassDict().get(superClass)); + } + return superClassesInProject; + } + + /** + * gets a Set of PythonTreeClasses that are + * the superclasses of this class, which are located + * in the same project. -> Uses the model generalizations to find + * the general class, not the code. + * This must be called only after a complete initialization + * of the Python Tree so that all super classes can be found + * in the root node's classNameDict. + */ + public Set getModelGeneralizationsInProject(Classifier modelClass) { + Set superClassesInProject = new HashSet(); + + for (Relationship rel : modelClass.getRelationships()) { + if (rel instanceof Realization) { + Realization real = (Realization) rel; + if (real.getClients().size() > 0 && real.getClients().get(0) instanceof Classifier) { + Classifier client = (Classifier) real.getClients().get(0); + String packageStructure = ParseHelpers.getModelPackageStructure(client) + client.getName(); + PythonTreeClass pyClass = this.getRoot().getClassDict().get(packageStructure); + superClassesInProject.add(pyClass); + } + } + } + + for (Classifier superClass : modelClass.getGenerals()) { + String packageStructure = ParseHelpers.getModelPackageStructure(superClass) + superClass.getName(); + PythonTreeClass pyClass = this.getRoot().getClassDict().get(packageStructure); + if (pyClass != null) + superClassesInProject.add(pyClass); + } + return superClassesInProject; + } + + + /** + * synchronize methods and attributes of the model with this class + * This is not done by xmi_id, but elements that changed name are always + * deleted and newly created + */ + public boolean synchronizeModel(NamedElement modelElement){ + // run super method to save corresponding model element + super.synchronizeModel(modelElement); + Classifier modelClass = (Classifier) modelElement; + + // set this class private in model, if its name starts with "__" + // use protected, if class starts with "_" (this is only python convention) + if (this.getName().startsWith("__")) { + modelClass.setVisibility(VisibilityKind.PRIVATE_LITERAL); + } else if (this.getName().startsWith("_")) { + modelClass.setVisibility(VisibilityKind.PROTECTED_LITERAL); + } + + + // ## process methods and attributes of this class ## + + // create dictionary of methods / classes, so that + // a model element can be accessed by name + + Map modelChildMethods = new Hashtable(); + + EList ownedOperations = null; + if (modelClass instanceof Class) + ownedOperations = ((Class) modelClass).getOwnedOperations(); + else if (modelClass instanceof Interface) + ownedOperations = ((Interface) modelClass).getOwnedOperations(); + else ownedOperations = new BasicEList(); + + for (Operation op : ownedOperations) { + modelChildMethods.put(op.getName(), op); + } + List processedOperations = new Vector(); + + Map modelChildProps = new Hashtable(); + for (Property prop : modelClass.getAttributes()) { + modelChildProps.put(prop.getName(), prop); + } + List processedProperties = new Vector(); + + // recurse on methods / attributes, if they exist in model; + // otherwise create and recurse + + for (PythonTreeMethod pyChildMeth : this.childMethodDict.values()) { + if (modelChildMethods.containsKey(pyChildMeth.getName())){ + // everything is OK, child method with same name found. + // method parameters are edited in child element + + // ### Synchronize child ### + boolean success = pyChildMeth.synchronizeModel(modelChildMethods.get(pyChildMeth.getName())); + if (! success) + return false; + processedOperations.add(modelChildMethods.get(pyChildMeth.getName())); + + + } else { + // Method does *not* exist -> create it and process children + Operation modelNewMethod = null; + if (modelClass instanceof Class) + modelNewMethod = ((Class) modelClass).createOwnedOperation(pyChildMeth.getName(), null, null); + else if (modelClass instanceof Interface) + modelNewMethod = ((Interface) modelClass).createOwnedOperation(pyChildMeth.getName(), null, null); + + // ### Synchronize child ### + boolean success = pyChildMeth.synchronizeModel(modelNewMethod); + if (! success) + return false; + processedOperations.add(modelNewMethod); + } + } + + Collection allAttributes = new Vector(); + allAttributes.addAll(this.childStaticAttrDict.values()); + allAttributes.addAll(this.childObjectAttrDict.values()); + for (PythonTreeAttribute pyChildAtt : allAttributes) { + if (modelChildProps.containsKey(pyChildAtt.getName())){ + // everything is OK, child method with same name found. + // method parameters are edited in child element + + // ### Synchronize child ### + boolean success = pyChildAtt.synchronizeModel(modelChildProps.get(pyChildAtt.getName())); + if (! success) + return false; + processedProperties.add(modelChildProps.get(pyChildAtt.getName())); + + } else { + // Attribute does *not* exist -> create it and process children + Property modelNewProp = null; + if (modelClass instanceof Class) + modelNewProp = ((Class) modelClass).createOwnedAttribute(pyChildAtt.getName(), null); + else if (modelClass instanceof Interface) + modelNewProp = ((Interface) modelClass).createOwnedAttribute(pyChildAtt.getName(), null); + + // ### Synchronize child ### + boolean success = pyChildAtt.synchronizeModel(modelNewProp); + if (! success) + return false; + processedProperties.add(modelNewProp); + } + } + + // delete all methods / attributes, that do no longer exist in code + + for (Operation op : modelClass.getOperations()) { + if (! processedOperations.contains(op)) + this.getRoot().getModelElementsToDestroy().add(op); + } + + for (Property prop : modelClass.getAttributes()) { + if (! processedProperties.contains(prop)) + this.getRoot().getModelElementsToDestroy().add(prop); + } + return true; + } + + + + /////// Synchronize Code (see superclass) /////// + public boolean synchronizeCode(Classifier modelClass) throws PyUMLSynchronizeCodeException{ + + // get and filter Stereotypes of this model class + // (only PyUML Stereotypes, as defined in GlobalConstants, are saved) + this.usedStereotypes = new Vector(); + List stypes = modelClass.getStereotypeApplications(); + for (EObject stObject : stypes) { + String stereotypeName = stObject.eClass().getName(); + if (GlobalConstants.getPossibleStereoTypes().contains(stereotypeName)) { + this.usedStereotypes.add(stereotypeName); + } + } + + this.handleStereoTypes(modelClass); + + // see if class was renamed: + if (! this.getName().equals(modelClass.getName())) { + // now, the file name is OK, rename the class in python code + this.renameClassInCode(modelClass); + this.getRoot().getRenamedClasses().add(this.getName()); + return true; + } + + // if class was renamed, and the old class name matches the file name, + // rename the file + // TODO: Works and can be uncommented, + // but generalizations/imports are not + // updated, so leaving that commented + /* + if (this.getRoot().getRenamedClasses().contains(this.inFile.getFilePath().lastSegment().replace(".py", ""))) { + IPath newFilePath = this.renameClassFile(modelClass.getName()); + if (newFilePath != null) { + this.inFile.setFilePath(newFilePath.addFileExtension("py")); + return true; + } + else + throw new PyUMLSynchronizeCodeException(); + } + */ + + // see if list of superclasses changed + boolean superClassesChanged = false; + + List interfaceList = new Vector(); + for (Relationship rel : modelClass.getRelationships()) { + if (rel instanceof Realization) { + interfaceList.add((Realization) rel); + } + } + + if (modelClass.getGeneralizations().size() + interfaceList.size() != this.superClasses.size()) + superClassesChanged =true; + else for (Generalization gen : modelClass.getGeneralizations()) { + if (! this.superClasses.contains( + ParseHelpers.getModelPackageStructure(gen.getGeneral()) + + gen.getGeneral().getName())) { + superClassesChanged = true; + } + } + // if yes, rewrite list of generalizations + if (superClassesChanged) + this.rewriteGeneralizations(modelClass, interfaceList); + + // if there are non-static parameters, make sure there is a + // __init__-method in the class + + boolean hasStaticAttributes = false; + boolean hasNonStaticAttributes = false; + EList ownedProperties = null; + if (modelClass instanceof Class) + ownedProperties = ((Class) modelClass).getOwnedAttributes(); + else if (modelClass instanceof Interface) + ownedProperties = ((Interface) modelClass).getOwnedAttributes(); + + for (Property modelProp : ownedProperties) { + if (! modelProp.isStatic()) + hasNonStaticAttributes = true; + else + hasStaticAttributes = true; + } + + if (hasNonStaticAttributes && (! childMethodDict.containsKey("__init__"))) { + this.createNewMethod("__init__", this.lastLine, false, null); + this.getRoot().setChangedFileLine("def __init__(self):"+this.lastLine); + return true; + } + + if (hasNonStaticAttributes) { + // check the __init__ method; this is not necessarily checked automatically, as + // it might be not present in the model + boolean changed = PythonTreeMethod.fixAttributeDefinitions(modelClass, childMethodDict.get("__init__").getIndent(), this.childObjectAttrDict, this, childMethodDict.get("__init__").getLastLine(), false); + if (changed) return true; + } + + if (hasStaticAttributes) { + // check if all static attributes in model are present in code + int insertLine; + if (this.astNode.body.length > 0) + insertLine = this.astNode.body[0].beginLine + 1; + else + insertLine = this.lastLine; + + boolean changed = PythonTreeMethod.fixAttributeDefinitions(modelClass, " ", this.childStaticAttrDict, this, insertLine, true); + if (changed) return true; + } + + + // iterate over child elements of model + + // save all method names in iteration to detect duplicate method names + List childModelOpNames = new Vector(); + + for (Element modelChild:modelClass.getOwnedElements()) { + //child method found + if (modelChild instanceof Operation) { + Operation childModelOp = (Operation) modelChild; + + // test if a method with this name already existed in model. + // if yes, an exception is thrown -> overloading is not supported in Python + if (childModelOpNames.contains(childModelOp.getName())) { + throw new PyUMLSynchronizeCodeException("Multiple methods with same name are not\n" + + "supported in Python!\n" + + "Please correct this error in the UML model!\n" + + "Source:\n" + + "- Method: "+ childModelOp.getName() + + "\n- Class: "+ this.getName() + + "\n- Package: "+this.getPackageStructure()); + + } else { + childModelOpNames.add(childModelOp.getName()); + } + + PythonTreeMethod childPyOp = null; + for (PythonTreeMethod childMeth : this.childMethodDict.values()) { + if (childMeth.getName().equals(childModelOp.getName())) { + childPyOp = childMeth; + } + } + if (childPyOp != null) { + // everything OK, child method with same name found + boolean startNew = childPyOp.synchronizeCode(childModelOp); + if (startNew) return true; + } + else { + // look if method was existing and was renamed + String xmi_id = this.getRoot().getModelXmiDict().get(childModelOp); + Map xmiModelDictOld = this.getRoot().getXmiModelDictOld(); + if (xmiModelDictOld.containsKey(xmi_id)) { + Operation oldOp = (Operation) xmiModelDictOld.get(xmi_id); + + String oldOpClassName = ((NamedElement)oldOp.getOwner()).getName(); + + if (oldOpClassName.equals(this.getName())) { + String oldName = oldOp.getName(); + PythonTreeMethod renamedPyOp = null; + for (PythonTreeMethod childMeth : this.childMethodDict.values()) { + if (childMeth.getName().equals(oldName)) { + renamedPyOp = childMeth; + } + } + if (renamedPyOp != null) { + // found operation that was renamed. + // rename it also in code + int line = renamedPyOp.getAstNode().beginLine; + int col = renamedPyOp.getAstNode().name.beginColumn; + boolean result = BicycleRefactoring.doRenameObject(this.inFile, + childModelOp.getName(), line, col, this.getRoot().getProject()); + if (! result) + return false; + setChanged(childModelOp.getName(), line); + return true; + } + // else -> was not renamed -> create new method + this.createNewMethod(childModelOp.getName(), this.lastLine, childModelOp.isStatic(), childModelOp); + setChanged(childModelOp.getName(), this.lastLine); + return true; + } + // else -> was not renamed -> create new method + this.createNewMethod(childModelOp.getName(),this.lastLine, childModelOp.isStatic(), childModelOp); + setChanged(childModelOp.getName(), this.lastLine); + return true; + } + // else -> was not renamed -> create new method + this.createNewMethod(childModelOp.getName(),this.lastLine, childModelOp.isStatic(), childModelOp); + setChanged(childModelOp.getName(), this.lastLine); + return true; + } + } + } + + // check if imports are correct! + boolean changed= this.fixImports(modelClass); + if (changed) + return true; + + changed= this.updateAssociations(modelClass); + if (changed) + return true; + + return false; + } + + + /** + * Realize all recognized stereotypes; + * For the BeanClass Stereotype, this will simply create getter/setter + * methods for every non-static attribute in the model, which will then automatically + * be realized as code. + */ + public void handleStereoTypes(Classifier modelClassifier) { + + if (! (modelClassifier instanceof Class)) { + return; + } + + Class modelClass = (Class) modelClassifier; + + if (this.usedStereotypes.contains(GlobalConstants.STEREOTYPE_BEANCLASS)) { + for (Property att : modelClass.getOwnedAttributes()) { + String attName = att.getName(); + // make first letter uppercase for CamelCase bean standard + attName = attName.substring(0,1).toUpperCase() + attName.substring(1); + + // add getter/setter + + // check if method already exists + boolean getterExists = false; + boolean setterExists = false; + for (Operation op : modelClass.getOwnedOperations()) { + if (op.getName().equals("get"+attName)) + getterExists = true; + if (op.getName().equals("set"+attName)) + setterExists = true; + } + if (!getterExists) { + Operation op = modelClass.createOwnedOperation("get"+attName, null, null); + op.createOwnedParameter("self", null); + op.createOwnedComment().setBody("Getter Created by PyUML:"+att.getName()); + } + + if (!setterExists) { + Operation op = modelClass.createOwnedOperation("set"+attName, null, null); + op.createOwnedParameter("self", null); + op.createOwnedParameter("value", null); + op.createOwnedComment().setBody("Setter Created by PyUML:"+att.getName()); + } + } + } + } + + + /** + * rename classes using bicycle repair man + * @param modelClass + * @return success + */ + public boolean renameClassInCode(Classifier modelClass) throws PyUMLSynchronizeCodeException{ + // rename Class using Bicycle Repair Man + + return BicycleRefactoring.doRenameObject( + this.inFile, + modelClass.getName(), this.astNode.name.beginLine, + this.astNode.name.beginColumn, this.getRoot().getProject()); + } + + /** + * Move this class in the python code to another package/folder + * * Rename the class file + * + * @param newPath the IPath where the class is to be moved + * @return true on success, false if package already exists + */ + public boolean moveClass(IPath newPath) { + IFile classFile = EclipseHelperMethods.createFile( + this.inFile.getFilePath().toOSString(), this.getProject()); + if (! classFile.exists()) { + MessageDialog.openError(null, "Error moving class", "Class " + this.name + " cannot " + + "be renamed\n because it does not seem to exist!"); + return false; + } + try { + newPath = EclipseHelperMethods.createFile(newPath.toOSString()+".py", this.getProject()).getFullPath(); + classFile.move(newPath, true, null); + this.inFile.setFilePath(this.getProject().getLocation().append(newPath)); + + } catch (CoreException e) { + MessageDialog.openError(null, "Error moving class", "The class " +this.name+ " cannot" + + " be moved to "+ newPath +".\n Propably a class with the new name already exists!" + + "\n\nReason:\n" +e.getMessage()); + return false; + } + PythonTreePackage.completeNewStart = true; + return true; + } + + /** + * Rename this class file in the python code + * + * @param newName the new name of the class in the same directory + * @return the iPath of the created file, null if new class file already exists + */ + public IPath renameClassFile(String newName) { + IFile classFile = EclipseHelperMethods.createFile(this.inFile.getFilePath().toOSString(), this.getProject()); + IPath newPath = classFile.getLocation().removeLastSegments(1).append(newName); + if (this.moveClass(newPath)) + return newPath; + else + return null; + } + + + /** + * Add/remove generalizations from class in code + * @param modelClass + * @return success + */ + public boolean rewriteGeneralizations(Classifier modelClass, List interfaceList) { + int line = this.astNode.beginLine; + String superClassString = ""; + + // write all available generalizations as a comma-separated string + for (Generalization gen : modelClass.getGeneralizations()) { + if (superClassString.length() > 0) + superClassString +=", "; + superClassString+= gen.getGeneral().getName(); + } + + for (Realization real :interfaceList) { + if (superClassString.length() > 0) + superClassString +=", "; + superClassString+= real.getClients().get(0).getName(); + } + + + // write all generalizations that were in code, but are not available + // in model (e.g. system classes) + for (String gen : this.superClasses) { + // if this class is part of project, is should be in model + // -> if it is not in model, it is to be removed + if (this.getRoot().getClassNameDict().containsValue( + gen.substring(gen.lastIndexOf("/")+1))) + continue; + // otherwise, this generalization has to stay, because it cannot be + // present in model + if (superClassString.length() > 0) + superClassString +=", "; + superClassString+= gen.substring(gen.lastIndexOf("/")+1); + } + // if there were generalizations, surround them by parenthesis + if (superClassString.length() > 0) { + superClassString = "(" + superClassString + ")"; + } + // replace generalizations in class definition + String classDefLine = FileRefactoring.getLine(this.inFile, line); + Pattern pattern = Pattern.compile("([\\s]*class[\\s]*[^:\\(]*[\\s]*)(\\(?[^:]*):"); + Matcher matcher = pattern.matcher(classDefLine); + if (! matcher.find()){ + return false; + } + String newClassDefLine = matcher.group(1) + superClassString + ":"; + if (! classDefLine.equals(newClassDefLine)) + FileRefactoring.replaceLine(this.inFile, line, newClassDefLine, true); + return true; + } + + /** + * create a new class in a File with the classes name + * use all information of the model class + * + * @param modelClass + * @param parentPackage + * @return true on success, false if something went wrong + */ + public static boolean createNewClass(Classifier modelClass, PythonTreePackage parentPackage) + throws PyUMLSynchronizeCodeException{ + String className = modelClass.getName(); + File newClassFile = new File(parentPackage.getPackageDir().append(className).toOSString() + ".py"); + + // create class definition line to insert to file + String newClassLine = ""; + newClassLine += "class " + className; + + // create file + if (!newClassFile.exists()) { + try { + newClassFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + throw new PyUMLSynchronizeCodeException(); + } + } else { + // if file already exists, append new content + newClassLine = ParseHelpers.fileToString(newClassFile, parentPackage.getProject()) + + "\n" + newClassLine; + } + + // get all superclasses and add them to class definition + EList superClasses = modelClass.getGenerals(); + if (superClasses.size() > 0) { + newClassLine = "\n" + newClassLine; + newClassLine +="("; + for (int i=0; i 0) + newClassLine += ", "; + newClassLine += superClass.getName(); + } + newClassLine += ")"; + } + newClassLine += ":"; + String xmi_id= parentPackage.getRoot().getModelXmiDict().get(modelClass); + if (modelClass instanceof Class) + newClassLine += "\n \"\"\"\n Class created by PyUML"; + else + newClassLine += "\n \"\"\"\n Interface created by PyUML"; + newClassLine += "\n # PyUML: Do not remove this line! # XMI_ID:" + xmi_id + + "\n \"\"\""; + ParseHelpers.stringToFile(newClassFile, newClassLine, parentPackage.getProject()); + + parentPackage.getRoot().setChangedFileLine(newClassFile.getAbsolutePath()); + return true; + } + + /** + * Checks the current import statements to ensure all superclasses + * are imported + * + * @return true, if anything was changed, false otherwise + */ + public boolean fixImports(Classifier modelClass) throws PyUMLSynchronizeCodeException{ + // iterate over all superclasses in project + Map superClassPackages = new HashMap(); + for (PythonTreeClass superClass : this.getModelGeneralizationsInProject(modelClass)) { + + // get package structure, e.g. mypackage.subpackage.MyClass + String packageDef = ""; + PythonTreePackage superPackage = superClass.getParent(); + while (superPackage != null && (! (superPackage instanceof PythonTreeRoot))) { + packageDef = superPackage.getName() + "." + packageDef; + superPackage = superPackage.getParent(); + } + String superClassModuleName = superClass.inFile.getName().replace(".py", ""); + packageDef += superClassModuleName; + superClassPackages.put(superClass.getName(), packageDef); + } + + // find import statements in code + // suppose, that all import statements are at the beginning of the + // file, only white or comment lines can be above them. + String[] fileContent = this.inFile.getFileContent().split("\n"); + int lineNo = 0; + String line = ""; + if (superClassPackages.size() > 0) { + do { + line = fileContent[lineNo]; + Pattern pattern = Pattern.compile("[\\s]*from[\\s]*([^\\s]*)[\\s]*import[\\s]*([^\\s#]*)([\\s#]?.*)"); + Matcher matcher = pattern.matcher(line); + if (matcher.find()){ + String className = matcher.group(2); + String packageDef = matcher.group(1); + // if class is imported, but package changed -> rewrite line! + if (superClassPackages.containsKey(className) && + ( ! packageDef.equals(superClassPackages.get(className)))) { + String newString = "from " + superClassPackages.get(className) + " import " + className + matcher.group(3); + FileRefactoring.replaceLine(this.inFile, lineNo, newString, true); + this.setChanged(null, lineNo); + return true; + } + if (superClassPackages.containsKey(className) && superClassPackages.get(className).equals(packageDef)) { + // line is OK -> remove them from new-import-to-insert-list + superClassPackages.remove(className); + } + } + lineNo ++; + } while(line.matches("[\\s]*[#]?") || line.matches("from.*import.*")||line.matches("import.*")); + + // now, all lines were analyzed; the needed import, that were not covered + // by a line, must be inserted now! + if (superClassPackages.size() == 0) + return false; + + String insertLines = ""; + for (String superClassName : superClassPackages.keySet()) { + String packageLine = superClassPackages.get(superClassName); + insertLines += "from " + packageLine + " import " + superClassName + "\n"; + } + // if last line is empty, don't insert new empty line + if (lineNo == 1) + // no empty lines are in fron of the insertion -> insert empty line + insertLines += "\n"; + else if (line.length() > 0 && (! fileContent[lineNo-2].matches("^[\\s]*$"))) { + insertLines += "\n"; + } + FileRefactoring.insertAtLine(this.inFile, lineNo-1, insertLines); + this.setChanged(null, lineNo); + return true; + } + + return false; + } + + /** + * This creates a new method in the current class + * + * @param name the method's name + * @param lastClassLine the last line in code that is part of the class + * (or the first line after class -1) + * -> this is the line where the method is inserted! + * can be -1 if the method should be appended to end of file + * @param isStatic if true, method will have a staticmethod call + * @param modelOp the corresponding model operation; if there is a comment + * indicating that this is a getter/setter, the appropriate method content + * is created. Can be null. + */ + public void createNewMethod(String name, int lastClassLine, boolean isStatic, Operation modelOp) { + String newLine; + if (isStatic) { + newLine = "\n" + this.indent + "def " + name +"():\n \"\"\" Created by PyUML \"\"\"\n" + + this.indent + name + " = staticmethod (" + name + ")\n"; + } else { + newLine = "\n" + this.indent + "def " + name +"(self):\n \"\"\" Created by PyUML \"\"\"\n"; + } + + // If this is a getter/setter class, put content to method + if (modelOp != null && modelOp.getOwnedComments().size() > 0) { + String opComment = modelOp.getOwnedComments().get(0).getBody(); + if (opComment.startsWith("Getter Created by PyUML:")) { + String attribute = opComment.replaceAll("Getter Created by PyUML:", ""); + newLine += " return self."+attribute+"\n"; + } + else if (opComment.startsWith("Setter Created by PyUML:")) { + String attribute = opComment.replaceAll("Setter Created by PyUML:", ""); + newLine += " self."+attribute+" = value\n"; + } + } + + if (lastClassLine <= 0) + FileRefactoring.appendToFile(this.inFile, newLine); + else + FileRefactoring.insertAtLine(this.inFile, lastClassLine, newLine); + } + + /** + * returns the parent package of this class + */ + public PythonTreePackage getParent() { + return this.inFile.getParent(); + } + + /** + * tells the position of current code change to PythonTreeRoot + * so that it can decide if the same line is changed again + * and again and thus detect an unfinished loop. + * + * @param pos Additional information. This is useful, if + * line is -1 (append), so that only dead-loops are detected + * @param line the changed line in the file + */ + private void setChanged(String pos, int line) throws PyUMLSynchronizeCodeException{ + if (pos == null) + pos = ""; + this.getRoot().setChangedFileLine(inFile.getFilePath().toOSString()+":"+line+":"+pos); + } + + public Map getChildMethodDict() { + return childMethodDict; + } + + public Map getChildStaticAttrDict() { + return childStaticAttrDict; + } + + public Map getChildObjectAttrDict() { + return childObjectAttrDict; + } + + public void setChildStaticAttrDict( + Map childStaticAttrDict) { + this.childStaticAttrDict = childStaticAttrDict; + } + + /** + * This creates a string containing the python package structure as + * "/packSup/packSub/" , where the last package contains the + * current class. + * @return a string containing the parent package structure + * of this class + */ + public String getPackageStructure() { + PythonTreePackage pack = this.getParent(); + String structure = ""; + while (! (pack instanceof PythonTreeRoot)) + { + structure = "/"+pack.getName() + structure ; + pack = pack.getParent(); + } + + return structure + "/"; + } + + /** + * Gets a complete package structure (including class) + * from the class imports for a class (separated by "/" + * e.g. "a/b/c/MyClass" for "MyClass", if there is + * an import line "from a.b.c.MyClassFile import MyClass" + * @param className the name of the class + * @return the full package/class structure + */ + public String getPackFromImports(String className) { + String fileContent = this.getInFile().getFileContent(); + Pattern pattern = Pattern.compile(".*from[\\s]+([^\\s]+)\\.[^\\.\\s]+[\\s]+import[\\s]+"+className+".*"); + Matcher matcher = pattern.matcher(fileContent); + + // if no import (with class structure in front) was found, we assume that the class + // is in the same package + if (! matcher.find()){ + return this.getPackageStructure() + className; + } + String result = "/" + (matcher.group(1) + "." + className).replace(".", "/"); + return result; + } + + /** + * @return the file where this class is defined + */ + public PythonTreeFile getInFile() { + return inFile; + } + + public List getUsedStereotypes() { + return usedStereotypes; + } + + public String getIndent() { + return indent; + } +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeFile.java b/pyUml/src/pyUML/pythonTree/PythonTreeFile.java new file mode 100755 index 0000000..eff5fef --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeFile.java @@ -0,0 +1,166 @@ +package pyUML.pythonTree; + +import java.io.File; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.IPath; +import org.python.pydev.parser.jython.SimpleNode; +import org.python.pydev.parser.jython.ast.ClassDef; +import org.python.pydev.parser.jython.ast.Module; +import org.python.pydev.parser.jython.ast.stmtType; +import org.python.pydev.refactoring.ast.visitors.VisitorFactory; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.ParseHelpers; +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLParseException; + + + +/** + * This class represents a Python file in the Python + * Package structure. + * It must have a parent package and contains a + * pydev Abstract Syntax Tree (AST) + * + */ +public class PythonTreeFile extends PythonTreeNode{ + private IPath filePath; + private PythonTreePackage parent; + private SimpleNode ast; + private List classesInFile; + private String fileContent; + private String[] splittedFileContent = null; + + + public PythonTreeFile(IPath filePath, PythonTreePackage parent) throws PyUMLParseException, PyUMLCancelledException{ + super(parent); + this.filePath = filePath; + this.parent = parent; + this.name = filePath.lastSegment(); + + this.classesInFile = new Vector(); + this.initAst(); + this.initClassesWithAST(); + } + + /** + * Parses the given Python file and saves the ast + */ + private void initAst() throws PyUMLParseException{ + // init AST so that it will never be null + this.ast=new SimpleNode(); + // try to get content of python file + this.fileContent = ParseHelpers.fileToString( + new File(filePath.toOSString()), this.getProject()); + if (this.fileContent==null) { + return; + } + + // get AST of file + try{ + this.ast = VisitorFactory.getRootNodeFromString(this.fileContent); + } catch (Throwable t) { + String message = t.getClass().getName()+ " while parsing file " + + this.filePath.toOSString() +"\n\n" +t.getMessage(); + throw new PyUMLParseException(message); + } + } + + /** + * extracts all the top level clases (no inner classes) + * out of the AST + */ + private void initClassesWithAST() throws PyUMLParseException, PyUMLCancelledException{ + if (this.ast instanceof Module) { + Module pyModule = (Module) this.ast; + stmtType[] statements = pyModule.body; + for (int i = 0; i < statements.length; i++) { + if (statements[i] instanceof ClassDef) { + // get end line of class -> look for following statement + int followingLine = 0; + if (i +1 < statements.length) { + stmtType followingStmt = statements[i+1]; + followingLine = followingStmt.beginLine; + } + ClassDef pyClass = (ClassDef) statements[i]; + PythonTreeClass cl = new PythonTreeClass(this.parent, this, pyClass, followingLine-1); + this.classesInFile.add(cl); + } + } + } + } + + public void updateFileInEclipse() { + EclipseHelperMethods.updateFile(this.getFilePath().toOSString(), this.getProject()); + } + + /** + * re-inits a file -> re-parses the content + * and adds new classes, if needed. + * @throws PyUMLParseException + */ + public void reInitFile() throws PyUMLParseException, PyUMLCancelledException { + for (PythonTreeClass cl : this.getClassesInFile()) { + this.getRoot().getClassDict().remove(cl.getPackageStructure()+cl.getName()); + this.getRoot().getClassNameDict().remove(cl.getPackageStructure()+cl.getName()); + this.getParent().getChildClasses().remove(cl); + } + + this.splittedFileContent=null; + this.classesInFile = new Vector(); + this.initAst(); + this.initClassesWithAST(); + this.getParent().getChildClasses().addAll(this.getClassesInFile()); + this.getRoot().getChildClasses().addAll(this.getParent().getChildClasses()); + + } + + /** + * Splits the file content by "\n", which results in an array of lines. + * The result is cached for performance reasons. + * @return an Array containing the lines of the file content + */ + public String[] getSplittedFileContent() { + if (splittedFileContent == null) + splittedFileContent = fileContent.split("\n"); + return splittedFileContent; + } + + public IPath getFilePath() { + return filePath; + } + public SimpleNode getAst() { + return ast; + } + public PythonTreePackage getParent() { + return parent; + } + + public List getClassesInFile() { + return classesInFile; + } + + /** + * @return the content of the whole file as a String + */ + public String getFileContent() { + return fileContent; + } + + /** + * Set this objects "file content" string. This does *not* + * update any real file! + * @param fileContent the file content as a String + */ + public void setFileContent(String fileContent) { + this.fileContent = fileContent; + this.splittedFileContent=null; + } + + public void setFilePath(IPath filePath) { + this.filePath = filePath; + } +} + diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeMethod.java b/pyUml/src/pyUML/pythonTree/PythonTreeMethod.java new file mode 100755 index 0000000..cbeaa3a --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeMethod.java @@ -0,0 +1,627 @@ +package pyUML.pythonTree; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Comment; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Operation; +import org.eclipse.uml2.uml.Parameter; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.VisibilityKind; +import org.python.pydev.parser.jython.ast.Expr; +import org.python.pydev.parser.jython.ast.FunctionDef; +import org.python.pydev.parser.jython.ast.Name; +import org.python.pydev.parser.jython.ast.NameTok; +import org.python.pydev.parser.jython.ast.Str; +import org.python.pydev.parser.jython.ast.exprType; +import org.python.pydev.parser.jython.ast.stmtType; + +import pyUML.backend.GlobalConstants; +import pyUML.backend.ParseHelpers; +import pyUML.exceptions.PyUMLParseException; +import pyUML.exceptions.PyUMLSynchronizeCodeException; +import pyUML.refactoring.BicycleRefactoring; +import pyUML.refactoring.FileRefactoring; + + +/** + * This class represents a Method definition inside a Python Class + */ +public class PythonTreeMethod extends PythonTreeNode { + private FunctionDef astNode; + private boolean staticMethod; + private List arguments; + private String docString; + private int docStringLine; + private int docStringCol; + private int lastLine; + private String indent = " "; + private Dictionary argumentDefaultDict; + private Dictionary argumentLineDict; + private Dictionary argumentColumnDict; + + public PythonTreeMethod(PythonTreeClass parent, FunctionDef astNode, int nextLine) throws PyUMLParseException{ + super(parent); + this.astNode = astNode; + this.lastLine = nextLine - 1; + // set last non-empty line as last line of this method + while (this.lastLine>=0 && parent.inFile.getSplittedFileContent()[lastLine-1].matches("[\\s]*")) { + this.lastLine--; + } + + this.arguments = new Vector(); + this.argumentDefaultDict = new Hashtable(); + this.argumentLineDict = new Hashtable(); + this.argumentColumnDict = new Hashtable(); + this.initMethod(); + } + + public void initMethod() throws PyUMLParseException{ + this.name = ((NameTok) this.astNode.name).id; + + if (this.name.matches(".*__init__.*") && this.getParent().getName().matches(".*CMCEntryBrows.*")) { + } + exprType[] argList = this.astNode.args.args; + exprType[] defaultList = this.astNode.args.defaults; + + // ### Get Arguments ### // + + // get offset of first argument with default value + int argCount = argList.length; + int defaultCount = defaultList.length; + int defaultOffset = argCount - defaultCount; + + // get arguments with corresponding default values + int argNo = 0; + for (exprType arg : argList) { + // fix indent, if needed + String line = this.getParent().getInFile().getSplittedFileContent()[arg.beginLine ]; + int indentLength=0; + if (line.length() > 0) + for (; line.charAt(indentLength) == ' ' && line.length() > indentLength +1 ; indentLength++) ; + if (this.indent.length() != indentLength && ! line.matches("^[\\s]*\\\"\\\"\\\".*$")) { + this.indent = ""; + for (int i=0; i< indentLength; i++) + this.indent += " "; + } + + // argument name + String argName = ((Name) arg).id; + if (this.arguments.contains(argName)) { + String message = "Argument inconsistency detected!\n"+ + "The python method '"+this.name+ "' in the class '" + + this.getParent().getName() + + "'\nhas an argument inconsistency with the argument '" + + argName + "'.\n\n" + + "The argument exists mor than once!\n\n" + + "Please correct this error!"; + throw new PyUMLParseException(message); + } + this.arguments.add(argName); + this.argumentLineDict.put(argName, arg.beginLine); + this.argumentColumnDict.put(argName, arg.beginColumn); + + // argument default value + if (defaultCount> 0 && argNo >= defaultOffset && (! argName.equals("self"))) { + + + exprType defaultVal = defaultList[argNo - defaultOffset]; + exprType defaultValBefore = null; + + // test if parameter without default follows parameter with default + // -> this is not allowed but not caught by pyDev + if (argNo - defaultOffset >= 1) + defaultValBefore = defaultList[argNo - defaultOffset-1]; + + String defValString = ParseHelpers.getStringOfExpr(defaultVal, this.getParent().getInFile(), false, false, 0); + + if (defaultVal == null && defaultValBefore!= null) { + String message = "Argument inconsistency detected!\n"+ + "The python method '"+this.name+ "' in the class '" + + this.getParent().getName() + + "'\nhas an argument inconsistency with the argument '" + + argName + "'.\n\n" + + "There are arguments without default values" + + "\nfollowing arguments with default values.\n\n" + + "Please correct this error!"; + throw new PyUMLParseException(message); + } else if (defaultVal != null){ + this.argumentDefaultDict.put(argName, defValString); + } + } + argNo++; + } + + // set static attribute */ + if (argList.length == 0 || (! this.arguments.get(0).equals("self"))) + this.staticMethod = true; + + + stmtType[] methodBody = this.astNode.body; + + // extract DocString, if it exists + if (methodBody.length > 0 && methodBody[0] instanceof Expr) { + Expr exp = (Expr) methodBody[0]; + if (exp.value instanceof Str) { + Str stringExp = (Str) exp.value; + if (stringExp.type == Str.TripleDouble || + stringExp.type == Str.TripleSingle) { + this.docString=stringExp.s; + this.docStringLine = stringExp.beginLine; + this.docStringCol = stringExp.beginColumn; + } + } + } + } + + public boolean synchronizeModel(NamedElement modelElement) { + + super.synchronizeModel(modelElement); + Operation modelMethod = (Operation) modelElement; + + // set this method private in model, if its name starts with "__" + // use protected, if class starts with "_" (this is only python convention) + if (this.getName().startsWith("__")) { + modelMethod.setVisibility(VisibilityKind.PRIVATE_LITERAL); + } else if (this.getName().startsWith("_")) { + modelMethod.setVisibility(VisibilityKind.PROTECTED_LITERAL); + } + + // set/remove static flag + if (this.staticMethod != modelMethod.isStatic()) + modelMethod.setIsStatic(this.staticMethod); + + List parameterList = modelMethod.getOwnedParameters(); + + // for all parameters in code -> check if model parameters are the same; + /// if not, add them + for (int i=0; i< this.getArguments().size(); i++) { + String pyArg = this.getArguments().get(i); + if (parameterList.size() > i) { + Parameter modelParam = parameterList.get(i); + // check if parameter name and default value are the same + String defautlValue = (this.getArgumentDefaultDict().get(pyArg)); + if (defautlValue == null) + defautlValue = ""; + if ((! pyArg.equals(modelParam.getName())) || + ( ! defautlValue.equals(modelParam.getDefault()))) { + + // this parameter is not the same! + // remove all parameters from here and create following parameters! + for (int j=i; j< parameterList.size(); j++) + parameterList.remove(j); + + // restart loop at the current position (again) + i--; + } + } else { + // Parameter at this position does not exist + // Append new parameter + Parameter newParam = modelMethod.createOwnedParameter(pyArg, null); + newParam.setDefault(this.getArgumentDefaultDict().get(pyArg)); + } + } + + // test, if there are additional model parameters -> remove them! + if (parameterList.size() > this.getArguments().size()) { + for (int i=this.getArguments().size(); i < parameterList.size(); i++) { + parameterList.get(i).destroy(); + } + } + return true; + } + + public boolean synchronizeCode(Operation modelOp) throws PyUMLSynchronizeCodeException{ + if (this.name.matches("search.*") && this.getParent().getName().startsWith("Group")) { + } + List modelParameters = new Vector(); + int line = this.astNode.name.beginLine; + + boolean parametersNeedRewrite = false; + + boolean modelIsStatic = true; + + methodChildLoop: + for (Parameter modelParameter : modelOp.getOwnedParameters()) { + + // get all relevant data + String modelParName = modelParameter.getName(); + modelParameters.add(modelParName); + + // stop if this is not a parameter (null) + if (modelParName == null) + continue methodChildLoop; + + if (modelParName.equals("self")) { + modelIsStatic = false; + } + + String modelParDefault = modelParameter.getDefault(); + + if (this.arguments.contains(modelParName)){ + //found parameter with same name! + String codeParDefault = this.getArgumentDefaultDict().get(modelParName); + + if (((modelParDefault == codeParDefault)&&(codeParDefault== null)) + || (modelParDefault != null && codeParDefault != null + && (codeParDefault.equals(modelParDefault) + || (modelParDefault.equals(GlobalConstants.getUnknownExpression()))))) + // parameter exists and has the same default value + // everything is fine! + continue methodChildLoop; + + + // parameter exists, but with different default! + // fix default value! + + // if default value does not exist in model + if (modelParDefault == null) { + parametersNeedRewrite = true; + continue methodChildLoop; + } + else if (codeParDefault == null) { //if default value wasn't there + //add a default value + parametersNeedRewrite = true; + continue methodChildLoop; + } + else { + // default value changed + // -> change default value + parametersNeedRewrite = true; + continue methodChildLoop; + } + } else { + + // parameter with this name not found! + // look if parameter was renamed (look in old model) + // this is done with bicycle repair man, so that + // all references will be renamed, too + + String paramXMIId = this.getRoot().getModelXmiDict().get(modelParameter); + if (this.getRoot().getXmiModelDictOld().keySet().contains(paramXMIId)) { + // parameter found -> try to find old name in code + Parameter oldModelParam = (Parameter) this.getRoot().getXmiModelDictOld().get(paramXMIId); + String oldParamName = oldModelParam.getName(); + if (this.arguments.contains(oldParamName)) { + // parameter with old name found -> rename it! + int col = this.argumentColumnDict.get(oldParamName); + BicycleRefactoring.doRenameObject(this.getParent().inFile, + modelParName, line, col, this.getRoot().getProject()); + setChanged(line, modelParName); + return true; + } + } + } + + //parameter does and did not exist in code + //create it! + parametersNeedRewrite = true; + continue methodChildLoop; + + } + + // check if parameters were deleted -> delete them in code! + for (String parameter : this.arguments) { + if (! modelParameters.contains(parameter)) { + //parameter does not exist in model -> delete it + parametersNeedRewrite = true; + break; + } + } + + // if method changed its static property, + // ensure the "staticmethod" call is added/removed + if (this.fixStaticmethodCall(modelIsStatic)) + return true; + + if (parametersNeedRewrite) { + // write new parameters definition + String parametersDef = ""; + + for (Parameter modelParameter: modelOp.getOwnedParameters()) { + // get all relevant data + String modelParName = modelParameter.getName(); + + // stop if this is not a parameter (null) + if (modelParName == null) + continue; + + String modelParDefault = modelParameter.getDefault(); + + if (parametersDef.length() > 0) + parametersDef += ", "; + + parametersDef += modelParName; + if (modelParDefault != null) + parametersDef += "=" + modelParDefault; + } + + // replace old definition with help of regex + Pattern pattern = Pattern.compile("([\\s]*def[\\s]*[^\\(]+[\\s]*\\()[^\\)]*(\\)[\\s]*:.*)"); + String defLine = FileRefactoring.getLine(this.getParent().inFile, line); + Matcher matcher = pattern.matcher(defLine); + if (! matcher.find()){ + return false; + } + + // write the new method definition line + String newDefLine = matcher.group(1) + parametersDef + matcher.group(2); + FileRefactoring.replaceLine(this.getParent().inFile, line, newDefLine, true); + + setChanged(line, newDefLine); + return true; + } + return false; + } + + /** + * On synchronizing code: + * Test the presence of all attributes + * - add/rename them, if needed + * - check initial value and fix it, if needed + * + * @param modelClass the class in the model where the attributes are defined + * @return true, if something was changed; false otherwise + */ + public static boolean fixAttributeDefinitions( + Classifier modelClass, String initIndent, + Map presentAttrs, + PythonTreeClass pyClass, int lastLine, boolean isStatic) + throws PyUMLSynchronizeCodeException{ + + // if this is the __init__ method, ensure all non-static attributes are defined here! + //Map presentAttrs = pyClass.getChildObjectAttrDict(); + List neededAttrs = null; + if (modelClass instanceof Class) + neededAttrs = ((Class) modelClass).getOwnedAttributes(); + else if (modelClass instanceof Interface) + neededAttrs = ((Interface) modelClass).getOwnedAttributes(); + + for (Property neededAttr : neededAttrs) { + if (isStatic != neededAttr.isStatic()) + continue; + + String attrName = neededAttr.getName(); + String initialValue = neededAttr.getDefault(); + + // if initial value was abbreviated before, try to get + // full value out of model + if (initialValue != null && initialValue.endsWith("(...)")) { + for (Comment comment :neededAttr.getOwnedComments()) { + if (comment.getBody().startsWith(GlobalConstants.getFullDefault())) { + initialValue = comment.getBody().substring(GlobalConstants.getFullDefault().length()); + break; + } + } + } + + if (! presentAttrs.containsKey(attrName)) { + // attribute is not present -> find out, if it was renamed in model + String param_xmi = pyClass.getRoot().getModelXmiDict().get(neededAttr); + if (pyClass.getRoot().getXmiModelDictOld().containsKey(param_xmi)) { + Property oldParameter = (Property) pyClass.getRoot().getXmiModelDictOld().get(param_xmi); + String oldParamName = oldParameter.getName(); + if (presentAttrs.containsKey(oldParamName)) { + // attribute was renamed -> rename it in code with Bicycle Repair Man + int line = presentAttrs.get(oldParamName).getLine(); + int col = presentAttrs.get(oldParamName).getCol(); + boolean success = BicycleRefactoring.doRenameObject( + pyClass.inFile, + attrName, line, col, pyClass.getRoot().getProject()); + return success; + } + } + // attribute is and was not present -> create it! + String attrDefLine = (isStatic ? pyClass.getIndent() : initIndent+"self.")+ attrName + " = "; + if (initialValue != null && (! initialValue.endsWith("(...)"))) + attrDefLine += initialValue; + else + attrDefLine += "None"; + attrDefLine += " # created by PyUML"; + if (lastLine <=0 ) + FileRefactoring.appendToFile(pyClass.inFile, attrDefLine); + else + FileRefactoring.insertAtLine(pyClass.inFile, + lastLine, attrDefLine + "\n"); + pyClass.getRoot().setChangedFileLine(pyClass.inFile.getFilePath().toOSString()+":"+lastLine + attrDefLine + ":"); + return true; + + } else { + // attribute is defined, check initial value + // if initial model value ends with (...), + // this value was cut when creating the model + // -> do not change it in code + PythonTreeAttribute pyAttr = presentAttrs.get(attrName); + if (pyAttr.getValue() != null && initialValue != null) { + } + if ((!pyAttr.getValue().equals(initialValue)) + && (!(pyAttr.getValue().equals("None") && initialValue==null)) + && (! initialValue.endsWith("(...)")) + && (! initialValue.startsWith(pyAttr.getValue().replaceAll("\\(\\.\\.\\.\\)$", ""))) ){ + // default value changed! + int line = pyAttr.getLine(); + + Pattern pattern = Pattern.compile("([\\s]*"+(isStatic?"":"self.")+"[^=]*=[\\s]*)([^#]+)(.*)"); + String defLine = FileRefactoring.getLine(pyClass.getInFile(), line); + Matcher matcher = pattern.matcher(defLine); + + if (! matcher.find()){ + return false; + } + + String initString = initialValue; + if (initString == null) + initString = "None"; + + // write the new method definition line + String commentGroup = matcher.group(3); + if (commentGroup.startsWith("#")) + commentGroup = " " + commentGroup; + String newDefLine = matcher.group(1) + initString + commentGroup; + + // if this was a multi-line attribute, delete + // all following lines and preserver comments + for (int i = line ; i < pyAttr.getNextLine() - 1; i++) + pyClass.getInFile().setFileContent(FileRefactoring.removeLine(pyClass.inFile, i, false, true)); + + // now, just replace the changed line + FileRefactoring.replaceLine(pyClass.inFile, line, newDefLine, true); + + pyClass.getRoot().setChangedFileLine(pyClass.inFile.getFilePath().toOSString()+":"+line); + return true; + + } + } + } + return false; + } + + /** + * On synchronizing code: + * Test staticmethod call of this method and + * fix it, if needed + * + * (python static methods must have the call + * = staticmethod() + * after the method definition) + * + * @param modelIsStatic true, if this method should be static + * in code and vice versa + * @return true, if something was changed + * false, otherwise + */ + public boolean fixStaticmethodCall(boolean modelIsStatic) throws PyUMLSynchronizeCodeException{ + // ensure there is a staticmethod call after the method + String fileContent[] = this.getParent().inFile.getFileContent().split("\n"); + String lineContent = ""; + int lineNo = this.lastLine; + + if (this.lastLine <= 0) + lineNo= fileContent.length -1; + + // if next command is "staticmethod", it is meant to be + // part of *this* method + if (fileContent.length > lineNo + 1 + && fileContent[lineNo+1].matches("^[\\s]*[^=\\(\\s]*[\\s]*=[\\s]*staticmethod[\\s]*\\([\\s]*[^\\)\\s]*[\\s]*\\)[\\s]*.*")) { + // the next command is the line to change + lineNo++; + } + + // find the last non-empty non-comment line + for (; lineNo>=0; lineNo--){ + lineContent = fileContent[lineNo]; + if (! (lineContent.matches("^[\\s]*$") || lineContent.matches("^[\\s]*#.*$")) ) + break; + } + + if (lineContent.matches("^[\\s]*[^=\\(\\s]*[\\s]*=[\\s]*staticmethod[\\s]*\\([\\s]*[^\\)\\s]*[\\s]*\\)[\\s]*.*")) { + // there is already a staticmethod call + if (!modelIsStatic) { + // staticmethod call has to be removed + FileRefactoring.removeLine(this.getParent().inFile, lineNo, true, false); + return true; + } + + // ensure staticmethod call is OK + if (lineContent.matches("[\\s]*"+this.getName()+"[\\s]*=[\\s]*staticmethod[\\s]*\\([^\\)\\s]*\\)[\\s]*.*")){ + // staticmethod call alright, nothing needs to be changed + return false; + } else { + // fix staticmethod call (e.g. when method was renamed) + String newContent = this.getParent().getIndent() + this.getName()+" = staticmethod("+this.getName()+")"; + FileRefactoring.replaceLine(this.getParent().inFile, lineNo+1, newContent, true); + setChanged(lineNo, newContent); + return true; + } + } else { + // there is no staticmethod call at all + if (!modelIsStatic) { + // all is OK + return false; + } else { + //-> insert it after the end of the method + String newContent = this.getParent().getIndent()+this.getName()+" = staticmethod("+this.getName()+")"; + + lineNo = this.lastLine; + + if (this.lastLine <= 0) + lineNo = fileContent.length -1; + + // from the next method, find the first before line with whitespace + for (; lineNo>=0; lineNo--){ + lineContent = fileContent[lineNo]; + if (! (lineContent.matches("^[\\s]*$"))) + break; + } + FileRefactoring.insertAtLine(this.getParent().inFile, lineNo + 2, newContent + "\n"); + + setChanged(lineNo, newContent); + return true; + } + } + } + + /** + * tells the position of current code change to PythonTreeRoot + * so that it can decide if the same line is changed again + * and again and thus detect an unfinished loop. + * + * @param line the changed line in the file + */ + private void setChanged(int line, String pos) throws PyUMLSynchronizeCodeException{ + if (pos == null) + pos = ""; + else pos = ":position:"+pos; + this.getRoot().setChangedFileLine(getParent().inFile.getFilePath().toOSString()+":"+line+pos); + } + + public boolean isStatic() { + return staticMethod; + } + + public PythonTreeClass getParent() { + return (PythonTreeClass) super.getParent(); + } + + public String getDocString() { + return docString; + } + + public int getDocStringLine() { + return docStringLine; + } + + public int getDocStringCol() { + return docStringCol; + } + + public FunctionDef getAstNode() { + return astNode; + } + + public List getArguments() { + return arguments; + } + + public Dictionary getArgumentDefaultDict() { + return argumentDefaultDict; + } + + public int getLastLine() { + return lastLine; + } + + public String getIndent() { + return indent; + } + +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeNode.java b/pyUml/src/pyUML/pythonTree/PythonTreeNode.java new file mode 100755 index 0000000..995df3a --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeNode.java @@ -0,0 +1,128 @@ +package pyUML.pythonTree; + +import org.eclipse.core.resources.IProject; +import org.eclipse.uml2.uml.NamedElement; + +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLSynchronizeCodeException; + + + +/** + * A generic node of the Python package structure tree + * This class is used as abstract super class for all + * PythonTree Elements + */ + +public abstract class PythonTreeNode { + private PythonTreeNode parent; + protected String name; + protected String xmi_id; + private NamedElement associatedModelElement; + + + public PythonTreeNode(PythonTreeNode parent) { + this.parent = parent; + } + + /** + * returns the parent of this package. + * If this is the root, return null. + * @return + */ + public PythonTreeNode getParent() { + if (! this.isRoot()) + return parent; + else + return null; + } + + /** + * Synchronize the model from the given model element + * downwards. + * Create, delete and move model elements + * + * @param modelElement + * @return + */ + public boolean synchronizeModel(NamedElement modelElement) { + this.associatedModelElement = modelElement; + + // test if name changed -> update model element name if name changed + if (! this.isRoot() && (!this.getName().equals(modelElement.getName()))) { + modelElement.setName(this.getName()); + } + + return false; + } + + + /** + * Opposite of synchronizeModel; Synchronizes the code + * with a given model + * + * @param umlElement + * @return true if code was changed (so that the python tree + * has to be updated), false if everything went OK + */ + public boolean synchronizeCode(NamedElement modelElement) throws PyUMLSynchronizeCodeException, PyUMLCancelledException{ + return false; + } + + + /** + * after running synchronizeModel, this method returns the corresponding + * UML Model NamedElement of this PythonTreeNode + * @return + */ + public NamedElement getAssociatedModelElement() { + return associatedModelElement; + } + + /** + * method to easily find out if this is the Root + * of the Python Package Tree + * + * @return false, if this is a package, + * the subclass PythonTreeRoot returns true + */ + public boolean isRoot() { + return false; + } + + /** + * Gets the XMI-id of this node, + * or null, if no XMI-ID was defined + * @return + */ + public String getXmi_id() { + return xmi_id; + } + + /** + * @return the root Element of this PythonTree + */ + public PythonTreeRoot getRoot() { + if (this.isRoot()) + return (PythonTreeRoot) this; + else + return this.getParent().getRoot(); + } + + /** + * Get the name of this node + * @return + */ + public String getName() { + return name; + } + + /** + * Get the Eclipse project that was used while creating this node + * @return + */ + public IProject getProject() { + return this.getRoot().getProject(); + } + +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreePackage.java b/pyUml/src/pyUML/pythonTree/PythonTreePackage.java new file mode 100755 index 0000000..7798150 --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreePackage.java @@ -0,0 +1,531 @@ +package pyUML.pythonTree; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Package; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.ParseHelpers; +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLParseException; +import pyUML.exceptions.PyUMLSynchronizeCodeException; + + + +/** + * This class represents a package directory in the python + * code structure. + * A package can contain child packages or Python files. + */ +public class PythonTreePackage extends PythonTreeNode{ + IPath packageDir; + private List childPackages; + private List childClasses; + private List pythonFiles; + private PythonTreeFile initPy; + static int count = 0; + + // this is used when a class was moved -> a complete restart is needed + // instead of re-initializing the changed class + static boolean completeNewStart = false; + + public PythonTreePackage(IPath packageDir, PythonTreeNode parent) throws PyUMLParseException, PyUMLCancelledException { + super(parent); + this.packageDir = packageDir; + this.childClasses = new Vector(); + this.childPackages = new Vector(); + this.pythonFiles = new Vector(); + + if (packageDir != null) { + initPackage(); + } + } + + private void initPackage() throws PyUMLParseException, PyUMLCancelledException{ + File dir = new File(packageDir.toOSString()); + this.name = dir.getName(); + // list dir + File[] dirList = dir.listFiles(); + + for (File entry:dirList) { + // if directory found: check if it is package, + // if yes, recursively add child packages + if (entry.isDirectory()){ + if (checkForInitPy(entry)){ + childPackages.add(new PythonTreePackage( + new Path(entry.getAbsolutePath()),this)); + } + continue; + } + if (entry.getName().endsWith(".py")) { + PythonTreeFile f = new PythonTreeFile( + new Path(entry.getAbsolutePath()), this); + this.pythonFiles.add(f); + this.childClasses.addAll(f.getClassesInFile()); + if (entry.getName().equals("__init__.py")) { + this.initPy = f; + } + this.getRoot().worked(); + } + } + + // get XMI:ID from __init__.py + if (this.initPy != null) { + this.xmi_id = ParseHelpers.extractXmiFromString( + this.initPy.getFileContent()); + if (this.xmi_id != null) + this.getRoot().getXmiPackDict().put(this.xmi_id, this); + } + } + + /** + * tests, if the given directory contains a file "__init__.py" + * If yes, it can be considered as package. + * + * @param dir the directory to check + * @return + */ + private boolean checkForInitPy(File dir) { + if (! dir.isDirectory()) + return false; + for (File entry: dir.listFiles()) { + if (entry.getName().equals("__init__.py")) + return true; + } + return false; + } + + /** + * Writes a XMI-ID as a comment to this packages's __init__.py file + * @param xmiID + */ + public void writeXmiID(String xmiID) { + String initPyContent = this.getInitPy().getFileContent(); + initPyContent = initPyContent.replaceAll("# PyUML: .*\n", ""); + initPyContent = "# PyUML: Do not remove this line! # XMI_ID:" + xmiID + "\n" + initPyContent; + File f = new File(this.getInitPy().getFilePath().toOSString()); + ParseHelpers.stringToFile(f, initPyContent, this.getProject()); + } + + /** + * synchronize the model by this Package using + * the packages/classes XMI-IDs + */ + public boolean synchronizeModel(NamedElement modelElement){ + super.synchronizeModel(modelElement); + + Package modelPack = (Package) modelElement; + Map xmiModelDict = this.getRoot().getXmiModelDict(); + + List processedElements = new Vector(); + List childElements = new Vector(); + childElements.addAll(this.getChildPackages()); + childElements.addAll(this.getChildClasses()); + + for (PythonTreeNode pyChildNode : childElements) { + String xmi_id= pyChildNode.getXmi_id(); + boolean createNewElement = false; + if (xmi_id != null) { + if (xmiModelDict.containsKey(xmi_id)) { + NamedElement modelChild = (NamedElement) xmiModelDict.get(xmi_id); + // if found element is also child of model, + // everything is OK, continue with packageSynchonization of children + if (modelElement.getOwnedElements().contains(modelChild)) { + pyChildNode.synchronizeModel(modelChild); + processedElements.add(modelChild); + } + else { + // element found, but at another place + // -> move model element to be child of this model element + if (modelChild instanceof Package) { + Package childPack = (Package) modelChild; + childPack.setNestingPackage(modelPack); + } + else if (modelChild instanceof Class || modelChild instanceof Interface) { + Classifier childClass = (Classifier) modelChild; + childClass.setPackage(modelPack); + } + + // ## synchronize children ## + // now the package has the right place, continue recursively + if (! pyChildNode.synchronizeModel(modelChild)) + return false; + processedElements.add(modelChild); + } + } else { + /* the xmi_id in the code is not present in model, but + * in the code. (Propably it was deleted in the model) + * This is not possible, because when this method is called + * the code was supposed to change, not the model. + * -> This is an inconsistency that cannot be resolved. + * -> Because a Model element with a special xmi_id cannot + * be created. + * -> Show an Error message + */ + if (! this.getRoot().isCreateNewModel()) { + boolean ignore = false; + if (this.getRoot().getXmiModelDict().size() == 0) { + ignore = MessageDialog.openQuestion(null, "Deleted Model", + "The current python code was synchronized \n" + + "with a UML model earlier.\n" + + "Now, the UML model cannot be found.\n\n" + + "Do you want to create a new UML model?"); + } else { + + ignore = MessageDialog.openQuestion(null, "Model Synchronization error found", + "The model is missing an element it formerly had\n" + + "and which is still present in the code.\n" + + "Obviously, the model was edited outside PyUml!\n\n" + + "Please manually resolve the situation by removing\n" + + "the XMI_ID comment in the __init__.py file of the\n" + + "package or in the DocString comment of the class.\n\n" + + "Element name: "+ pyChildNode.getName() +"\n\n"+ + "Do you want to ignore this and create new model elements?"); + } + if (! ignore) + return false; + else { + this.getRoot().setCreateNewModel(true); + createNewElement=true; + } + } else { + // the warning was disabled by user; + createNewElement=true; + } + } + } + if (xmi_id==null || createNewElement) { + // no xmi_id is present in the code -> this is a manually + // created package! It must be created in the model, too. + NamedElement modelNewChild = null; + if (pyChildNode instanceof PythonTreePackage) { + modelNewChild = modelPack.createNestedPackage(pyChildNode.getName()); + } else if (pyChildNode instanceof PythonTreeClass) { + modelNewChild = modelPack.createOwnedClass(pyChildNode.getName(), false); + } + + // ## synchronize children ## + if (modelNewChild != null) { + // now the package is created, we can recursively edit it + // by the pyPack synchronization method + if (! pyChildNode.synchronizeModel(modelNewChild)) + return false; + processedElements.add(modelNewChild); + } + } + } + + // test if all elements of model were processed + for (Element modelChild : modelElement.getOwnedElements()) { + if ((modelChild instanceof Class || modelChild instanceof Package) + && (! processedElements.contains(modelChild))) + // if this model element was not touched until now, + // it obviously was deleted in code and must be deleted + // also in model + this.getRoot().getModelElementsToDestroy().add((NamedElement)modelChild); + } + + return true; + } + + public boolean synchronizeCode(NamedElement modelElement) throws PyUMLSynchronizeCodeException, PyUMLCancelledException { + Map modelXmiDict = this.getRoot().getModelXmiDict(); + Map xmiPackDict = this.getRoot().getXmiPackDict(); + Map xmiClassDict = this.getRoot().getXmiClassDict(); + + Package modelPack = (Package) modelElement; + + // if package is to be renamed + if (! modelPack.getName().equals(this.getName())) { + // rename package; + boolean success = this.renamePackage(modelPack.getName()); + if (! success) + throw new PyUMLSynchronizeCodeException(); + // folder has changed -> return "true" to start from beginning + return true; + } + + // iterate over child elements of model + globalLoop: + for (Element modelChild:modelElement.getOwnedElements()) { + //child package found + if (modelChild instanceof Package) { + Package modelChildPack = (Package) modelChild; + // get xmi_id of model element + String xmi_id = modelXmiDict.get(modelChildPack); + if (xmiPackDict.containsKey(xmi_id)) { + // this package is present in model + // now we have to check it is also child of this package and + // recurse over child elements. + PythonTreePackage pyPack = xmiPackDict.get(xmi_id); + if (this.getChildPackages().contains(pyPack)) { + + // child is Okay! + boolean startNew = pyPack.synchronizeCode(modelChildPack); + if (startNew) return true; + } else { + // move package to this package + IPath newPath = EclipseHelperMethods.createFolder(this.getPackageDir().append(pyPack.name).toOSString(), this.getProject()).getFullPath(); + + boolean success = pyPack.movePackage(newPath); + if (success) + // now the package is moved, start from the beginning + return true; + else + throw new PyUMLSynchronizeCodeException(); + } + } else { + // xmi_id not found -> look for package with same name! + boolean packageFound = false; + for (PythonTreePackage pySubPack : this.getChildPackages()) { + if (pySubPack.getName().equals(modelChildPack.getName())){ + // write xmi_id to code (only needed once) + pySubPack.writeXmiID(xmi_id); + boolean startNew = pySubPack.synchronizeCode(modelChildPack); + if (startNew) return true; + packageFound=true; + break; + } + } + // if this package was not found, create it (recursively)! + if (! packageFound) { + // create package + IPath newPackPath = getPackageDir().append(modelChildPack.getName()); + File newPackDir = new File(newPackPath.toOSString()); + newPackDir.mkdir(); + EclipseHelperMethods.updateFolder(newPackDir.getAbsolutePath(), this.getProject()); + File initPy = new File(newPackPath.append("__init__.py").toOSString()); + try{ + initPy.createNewFile(); + EclipseHelperMethods.updateFile(initPy.getAbsolutePath(), this.getProject()); + } + catch (IOException e) { + MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath()); + throw new PyUMLSynchronizeCodeException(); + } + PythonTreePackage newPyPack=null; + try{ + newPyPack = new PythonTreePackage(newPackPath, this); + } + catch (PyUMLParseException e){ + e.printStackTrace(); + } + + newPyPack.writeXmiID(xmi_id); + this.childPackages.add(newPyPack); + boolean startNew = newPyPack.synchronizeCode(modelChildPack); + if (startNew) return true; + } + } + } + // handle child classes in model + else if (modelChild instanceof Class || modelChild instanceof Interface) { + Classifier modelChildClass = (Classifier) modelChild; + this.getRoot().worked(this.getName() + "/" + modelChildClass.getName()); + this.getRoot().setSubTaskName(this.getName() + "/" + modelChildClass.getName()); + String xmi_id = modelXmiDict.get(modelChildClass); + // look for class with this xmi_id + if (xmiClassDict.containsKey(xmi_id)) { + PythonTreeClass pyClass = xmiClassDict.get(xmi_id); + // if the class is already child of this package + if (this.getChildClasses().contains(pyClass)) { + + // continue with children in model+code + boolean startNew = pyClass.synchronizeCode(modelChildClass); + while (startNew) { + try { + pyClass.getInFile().reInitFile(); + startNew = this.synchronizeCode(modelElement); + if (PythonTreePackage.completeNewStart) { + PythonTreePackage.completeNewStart = false; + return true; + } + } catch (PyUMLParseException e) { + String message = "After changing the code parsing the " + + "changed code failed!\n" + + "Error was:\n" + + e.getMessage(); + e.printStackTrace(); + + throw new PyUMLSynchronizeCodeException(message); + } + } + } else { + // move class to this package; + IPath newPath = this.getPackageDir().append(pyClass.name); + + boolean success = pyClass.moveClass(newPath); + if (success) + // now the class is moved, start from the beginning + return true; + else + throw new PyUMLSynchronizeCodeException("Class could not be moved."); + } + } else { + // no class with this xmi_id found! + // look for python child class with same name + // and write the right xmi_id + boolean classFound = false; + for (PythonTreeClass pySubClass : this.getChildClasses()) { + if (pySubClass.getName().equals(modelChildClass.getName())){ + classFound = true; + // write xmi_id to code (only needed once) + pySubClass.writeXmiID(xmi_id); + // restart hole process + setChanged(pySubClass.astNode.beginLine); + + try { + pySubClass.getInFile().reInitFile(); + this.synchronizeCode(modelElement); + + } catch (PyUMLParseException e) { + String message = "After changing the code parsing the " + + "changed code failed!\n" + + "Error was:\n" + + e.getMessage(); + e.printStackTrace(); + + throw new PyUMLSynchronizeCodeException(message); + } + break; + } + } + if (! classFound) { + // if this class was not found, create it (recursively)! + boolean success = PythonTreeClass.createNewClass(modelChildClass, this); + if (success) { + File newClassFile = new File(this.getPackageDir().append(modelChildClass.getName()).toOSString() + ".py"); + try { + PythonTreeFile newPyFile = new PythonTreeFile(Path.fromOSString(newClassFile.toString()), this); + this.childClasses.addAll(newPyFile.getClassesInFile()); + this.synchronizeCode(modelElement); + break globalLoop; + + } catch (PyUMLParseException e) { + throw new PyUMLSynchronizeCodeException( + "Error: The newly created class" + newClassFile + + "\ncannot be parsed!\n" + + "Synchronizing Code cannot continue!\n" + + "Message was:\n" + + e.getClass().getName()+"\n"+e.getMessage()); + } + //OK, class was created! + } else { + throw new PyUMLSynchronizeCodeException("Error creating class: "+modelChildClass.getName()); + } + } + } + } + } + return false; + } + + /** + * Move this package in the python code to another package/folder + * * Rename the package directory + * * TODO: Update references + * + * @param newPath the IPath where the package is to be moved + * @return true on success, false if package already exists + */ + public boolean movePackage(IPath newPath) { + IFolder packDir = EclipseHelperMethods.createFolder(this.getPackageDir().toOSString(), this.getProject()); + if (! packDir.exists()) { + MessageDialog.openError(null, "Error moving package", "Package " + this.name + " cannot " + + "be renamed\n because it does not seem to exist!"); + return false; + } + try { + packDir.move(newPath, true, null); + } catch (CoreException e) { + MessageDialog.openError(null, "Error moving package", "The package " +this.name+ " cannot" + + " be moved to "+ newPath +".\n Propably a package with the new name already exists!" + + "\n\nReason:\n" +e.getMessage()); + return false; + } + return true; + } + + /** + * Rename this package in the python code + * * Rename the package directory + * * TODO: Update references + * + * @param newName the new name of the package in the same directory + * @return true on success, false if package already exists + */ + public boolean renamePackage(String newName) { + IFolder packDir = EclipseHelperMethods.createFolder(this.getPackageDir().toOSString(), this.getProject()); + IPath newPath = packDir.getFullPath().removeLastSegments(1).append(newName); + return this.movePackage(newPath); + } + + + /** + * Submits the position of current code change to PythonTreeRoot + * so that it can decide if the same line is changed again + * and again and thus detect an unfinished loop. + * + * @param line the changed line in the file + */ + private void setChanged(int line) throws PyUMLSynchronizeCodeException{ + this.getRoot().setChangedFileLine(this.packageDir+":"+line); + } + + /** + * Puts a new Package as a child beneath this package. + * @param pack + */ + public void addChildPackage(PythonTreePackage pack) { + childPackages.add(pack); + } + + /** + * returns all child Packages + */ + public List getChildPackages() { + return this.childPackages; + } + + /** + * returns all child classes (as PythonTreeClass) + * @return + */ + public List getChildClasses() { + return childClasses; + } + + /** + * @return __init__.py file of this package + */ + public PythonTreeFile getInitPy() { + return initPy; + } + + public IPath getPackageDir() { + return packageDir; + } + + /** + * gets the parent package of this package, + * null if the parent package is root + */ + public PythonTreePackage getParent() { + return (PythonTreePackage) super.getParent(); + } +} diff --git a/pyUml/src/pyUML/pythonTree/PythonTreeRoot.java b/pyUml/src/pyUML/pythonTree/PythonTreeRoot.java new file mode 100755 index 0000000..96cab17 --- /dev/null +++ b/pyUml/src/pyUML/pythonTree/PythonTreeRoot.java @@ -0,0 +1,529 @@ +package pyUML.pythonTree; + +import java.io.File; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.Relationship; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.JavaHelperMethods; +import pyUML.exceptions.PyUMLCancelledException; +import pyUML.exceptions.PyUMLParseException; +import pyUML.exceptions.PyUMLSynchronizeCodeException; + +/** + * This class is the root of the Python Syntax Tree + * it represents the parent directory of the uppermost + * package in the python package structure. + * + * If the Project directory is already a package + * (contains __init__.py), then this class will + * contain a Package representing the own directory + * as child. + * + * Typically, this represents the "src" directory + * of the eclipse project. + * + * The root node corresponds with the "model" node of the UML diagram. + * + */ +public class PythonTreeRoot extends PythonTreePackage{ + private IProject project; + private Set srcPaths; + private Map xmiPackDict; + private Map xmiClassDict; + private Map classDict; + private Map classNameDict; + private List renamedClasses; + + // Attributes needed for model synchronization + private Map xmiModelDict; + private Map modelXmiDict; + private Map xmiModelDictOld; + private List modelElementsToDestroy; + + private List changedFileLines; + private boolean createNewModel = false; + private boolean showWarnings = true; + private IProgressMonitor monitor; + private List progressFinishedItems; + + /** + * createNewModel is true, if a user decided to create a new model, + * even though a model former existed and was obviously deleted + * or edited outside PyUML + * initially, createNewModel is false, and if a former model is detected, + * the user is asked + * @return the current value of is CreateNewModel + */ + public boolean isCreateNewModel() { + return createNewModel; + } + + /** + * if a user decided to create a new model, + * even though a model former existed and was obviously deleted + * or edited outside PyUML, this decision can be saved here so that + * the user is asked only once + + * @param createNewModel -> true, if the user decided to re-create the model + */ + public void setCreateNewModel(boolean createNewModel) { + this.createNewModel = createNewModel; + } + + /** + * sets the last changed line on synchronizing code. + * + * Background: + * on synchronizing code, after every change the whole code is re-read + * an synchronizing started from beginning, until there are no more changes. + * The danger is that the program runs in an endless loop, e.g. if changes + * are not sufficient (this should NOT happen normally) + * To detect this situation, the line of the last change in code is saved; + * if this line does not change for many times, we detect a dead loop + * and break it with an error message + * + * @param changedFileLine a line, typically representing the changed line + * in code. It can also hold a package/file path etc. + * It must always be the same for the same operation! + */ + public void setChangedFileLine(String changedFileLine) throws PyUMLSynchronizeCodeException{ + if (this.changedFileLines.size() == 0){ + this.changedFileLines.add(changedFileLine); + return; + } + if (this.changedFileLines.get(this.changedFileLines.size()-1).equals(changedFileLine)) { + this.changedFileLines.add(changedFileLine); + } else { + this.changedFileLines.clear(); + this.changedFileLines.add(changedFileLine); + } + if (this.changedFileLines.size() > 20) { + String message = "Error: Synchronize Code runs in an unfinished loop!\n\n" + + "The loop is in the File/Line\n" + changedFileLine; + throw new PyUMLSynchronizeCodeException(message); + } + } + + /** + * + * @param project the eclipse IProject + * @param showWarnings if true, warnings (e.g. duplicate classes) are shown + * this is typically done only on the first run, if there are several runs + */ + public PythonTreeRoot(IProject project, boolean showWarnings, IProgressMonitor monitor) throws PyUMLParseException, PyUMLCancelledException{ + super(null, null); + this.project = project; + this.showWarnings = showWarnings; + this.monitor = monitor; + this.srcPaths = EclipseHelperMethods.getPythonSrcDirs(project); + + // first Source dir is standard dir -> all new packages will be + // created here! + this.packageDir = this.srcPaths.iterator().next(); + int numPackages=JavaHelperMethods.getFileCount(this.packageDir.toFile(), "^.*.py$"); + this.beginTask("Analyze Python Code", numPackages); + + initRoot(); + } + + /** + * On object Creation, this initializes the root of the python + * code representationS + * @throws PyUMLParseException + */ + private void initRoot() throws PyUMLParseException, PyUMLCancelledException{ + // initialize name and xmi_id dictionaries + this.xmiPackDict = new Hashtable(); + this.xmiClassDict = new Hashtable(); + this.classDict = new Hashtable(); + this.classNameDict = new Hashtable(); + + + // set the Tree name (= project name = model name) + this.name = this.project.getName(); + + // iterate over all source paths: find uppermost package(s) + // and append it to this root node. + for (IPath path : this.srcPaths) { + + File srcDir = new File(path.toOSString()); + if (! srcDir.isDirectory()) + continue; + + // check if dir is already package. + // if yes, add it + // if no, check all child dirs (until packages were found) + + List checkPackDirs = new Vector(); + checkPackDirs.add(srcDir); + + while(checkPackDirs.size() > 0) { //take the next subdir + File dir = checkPackDirs.get(0); + checkPackDirs.remove(dir); + + // list dir + File[] dirList = dir.listFiles(); + boolean isPackage=false; + List childDirList =new Vector(); + + // look for child directories or "__init__.py" + for (File entry:dirList) { + if (entry.isDirectory()) + childDirList.add(entry); + else if (entry.getName().equals("__init__.py")) + isPackage=true; + } + + // if this dir is a package, initialize a new PythonTreePackage + if (isPackage) + this.addChildPackage( + new PythonTreePackage( + new Path(dir.getAbsolutePath()), this)); + else + checkPackDirs.addAll(childDirList); + } + } + } + + + /** + * For a given model (it can be empty), synchronize the Model + * with the code represented by this PythonTreeNode + * use xmi_id for identifying moved Packages + * + * @param model + * @param xmiModelDict + * @return true on success, false on Errors (Model must not be saved) + */ + public boolean synchronizeModel(Model model, Map xmiModelDict) throws PyUMLCancelledException{ + // set name of model (e.g. when newly created + if (! model.getName().equals(this.name)) + model.setName(this.name); + + this.xmiModelDict = xmiModelDict; + this.modelElementsToDestroy = new Vector(); + boolean success = super.synchronizeModel(model); + if (! success) + return false; + + // create Generalizations + this.createModelGeneralizations(model); + + // delete elements not present in model any more + for (NamedElement elementToDestroy : this.modelElementsToDestroy) { + // destroy all relationships + Vector rels = new Vector(); + for (Relationship rel : elementToDestroy.getRelationships()) + rels.add(rel); + for (Relationship rel : rels) + rel.destroy(); + + elementToDestroy.destroy(); + } + + return true; + } + + /** + * after synchronizeModel was run, this method creates all generals + * in the model. That can be done only *after* the model synchronized, + * to ensure all classes are present in the model. + * @param model + */ + public void createModelGeneralizations(Model model) { + for (PythonTreeClass pyClass : classDict.values()) { + // get model class of this class + Classifier modelClass = (Classifier) pyClass.getAssociatedModelElement(); + + // get all model superclasses for this class + List modelGenerals = modelClass.getGeneralizations(); + Map modelSuperClasses = + new Hashtable(); + for (Generalization gen : modelGenerals) { + if (gen.getGeneral() != null) + modelSuperClasses.put(gen.getGeneral(), gen); + } + + // get list of superclasses in python code + Set pySuperClasses = pyClass.getGeneralizationsInProject(); + + // ensure all python superclasses are in model + for (PythonTreeClass pySuperClass : pySuperClasses) { + if (! modelSuperClasses.containsKey((Classifier)pySuperClass.getAssociatedModelElement())) { + modelClass.createGeneralization( + (Classifier)pySuperClass.getAssociatedModelElement()); + } + } + + // ensure all model superclasses are present in python. + // if not, delete model superclass + List modelGeneralList = new Vector(); + modelGeneralList.addAll(modelGenerals); + for (Generalization modelGen : modelGeneralList) { + Classifier modelSuperClass = modelGen.getGeneral(); + if (modelSuperClass == null) { + modelGen.destroy(); + continue; + } + + // if no class with the Generalization exists + if (! this.getClassDict().containsKey(this.getModelPackageStructure(modelSuperClass) + modelSuperClass.getName())) { + // destroy generalization + modelGen.destroy(); + } else { + PythonTreeClass pySuperClass = this.getClassDict().get(this.getModelPackageStructure(modelSuperClass) + modelSuperClass.getName()); + // if Superclass exists, but is no superclass + if (! pySuperClasses.contains(pySuperClass)) { + // destroy all relationships + Vector rels = new Vector(); + for (Relationship rel : modelSuperClasses.get(modelSuperClass).getRelationships()) + rels.add(rel); + for (Relationship rel : rels) + rel.destroy(); + // destroy superclass + modelSuperClasses.get(modelSuperClass).destroy(); + } + } + //otherwise: everything is OK + } + } + } + + /** + * + * @param modelElement + * @param modelXmiDict + * @param xmiModelDictOld + * @param monitor + * @param classCount the number of classes in model - optional parameter for progress bar + * @return + */ + public boolean synchronizeCode(NamedElement modelElement, Map modelXmiDict, Map xmiModelDictOld, + IProgressMonitor monitor, int classCount) + throws PyUMLCancelledException{ + this.monitor = monitor; + this.modelXmiDict = modelXmiDict; + this.xmiModelDictOld = xmiModelDictOld; + this.renamedClasses = new Vector(); + this.showWarnings = false; + this.changedFileLines = new Vector(); + this.progressFinishedItems = new Vector(); + + this.beginTask("Synchronize Code by Model", classCount); + + // synchronize until no more changes were found (synchronize returns false) + try { + while(super.synchronizeCode(modelElement)) { + // if synchronizeCode returned true, it just changed the code! + // -> Re-read the code and start from the beginning + this.initRoot(); + this.beginTask("Synchronize Code by Model", classCount*2); + } + // finally, do a second sync run to ensure all newly + // created classes can be used in import statements + super.synchronizeCode(modelElement); + } catch (PyUMLSynchronizeCodeException e) { + e.printStackTrace(); + MessageDialog.openError(null, "An Exception happened while synchronizing code", + "An Exception happened while synchronizing code.\n" + + "Message was: \n\n" + e.getMessage()); + return false; + } catch (PyUMLParseException e) { + e.printStackTrace(); + MessageDialog.openError(null, "An Exception happened while synchronizing code", + "Obviously, while synchronizing code a python syntax error was\n" + + "created. This should not happen!\n" + + "Please resolve the problem manually!\n\n" + + "Message was: \n" + e.getMessage()); + return false; + } + return true; + } + + + public boolean isRoot() { + return true; + } + + /** + * returns a dictionary of all class names with their corresponding + * PythonTreeClass + * @return + */ + public Map getClassDict() { + return classDict; + } + + /** + * returns the XMI-ID <-> PythonTreePackage dictionary with XMI-IDs as keys + * @return + */ + + public Map getXmiPackDict() { + return xmiPackDict; + } + + /** + * returns the XMI-ID <-> PythonTreeClass dictionary with XMI-IDs as keys + * @return + */ + public Map getXmiClassDict() { + return xmiClassDict; + } + + /** + * returns the XMI-ID <-> model dictionary with XMI-IDs as keys + * @return + */ + public Map getXmiModelDict() { + return xmiModelDict; + } + + /** + * returns the XMI-ID <-> model dictionary with model elements as keys + * @return + */ + public Map getModelXmiDict() { + return modelXmiDict; + } + + /** + * Like PythonTreeClass.getPackageStructure(), this + * generates a string with the Package structure containing + * a class, like "/supPack/subPack/" + * @param c The model class to use + * @return the parent package structure as a String + */ + public String getModelPackageStructure(Classifier c) { + + Package parent = c.getPackage(); + String structure = ""; + do { + structure = "/"+parent.getName() + structure; + parent = parent.getNestingPackage(); + } while (! (parent instanceof Model)); + + return structure + "/"; + } + + /** + * Proxy method. Runs beginTask, if there is a monitor, + * does nothing, otherwise + * @param name The name of the task to start + * @param totalWork The number of task steps to display + */ + public void beginTask(String name, int totalWork) { + if (this.monitor != null) + this.monitor.beginTask(name, totalWork); + } + + /** + * Completes a sub-step in the progress monitor, + * if any. + */ + public void worked() throws PyUMLCancelledException { + if (this.monitor.isCanceled()) + throw new PyUMLCancelledException(); + if (this.monitor != null) { + monitor.worked(1); + } + // update UI + while (Display.getCurrent().readAndDispatch()) + ; + } + + /** + * Sets the name of the current task in the progress monitor + * @param name + * @throws PyUMLCancelledException + */ + public void setSubTaskName(String name) throws PyUMLCancelledException{ + if (this.monitor.isCanceled()) + throw new PyUMLCancelledException(); + if (this.monitor != null) { + monitor.subTask(name); + } + + // update UI + while (Display.getCurrent().readAndDispatch()) + ; + } + + /** + * like worked(), this additionally has the possibility to + * put an item name of the finished item, so that + * the progress bar will only be updated the first time an item is + * finished. + * This is useful for a progress bar with recursive sync calls + * @param itemName the name of the finished item + */ + public void worked(String itemName) throws PyUMLCancelledException{ + if (! this.progressFinishedItems.contains(itemName)) { + this.progressFinishedItems.add(itemName); + this.worked(); + } + } + + public void setMonitor(IProgressMonitor monitor) { + this.monitor = monitor; + } + + /** + * returns the list of model elements that are to be removed from + * the model after synchronizing. + * This has to be done as the last step of the sync process + * so that no concurrent modification is done on the model. + * @return + */ + public List getModelElementsToDestroy() { + return modelElementsToDestroy; + } + + /** + * Overwrites the method fromPythonTreePackage + * -> On a renaming of the model root nothing is to be done! + * @param newName + */ + public boolean renamePackage(String newName) { + return true; + } + + public Map getXmiModelDictOld() { + return xmiModelDictOld; + } + + public IProject getProject() { + return project; + } + + public List getRenamedClasses() { + return renamedClasses; + } + + public boolean isShowWarnings() { + return showWarnings; + } + + public Map getClassNameDict() { + return classNameDict; + } +} diff --git a/pyUml/src/pyUML/refactoring/BicycleRefactoring.java b/pyUml/src/pyUML/refactoring/BicycleRefactoring.java new file mode 100755 index 0000000..f64f375 --- /dev/null +++ b/pyUml/src/pyUML/refactoring/BicycleRefactoring.java @@ -0,0 +1,120 @@ +package pyUML.refactoring; + +import java.io.IOException; +import java.net.URLDecoder; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.MessageDialog; +import org.python.pydev.core.IPythonNature; +import org.python.pydev.core.REF; +import org.python.pydev.editor.codecompletion.shell.AbstractShell; +import org.python.pydev.editor.refactoring.AbstractPyRefactoring; +import org.python.pydev.editor.refactoring.IPyRefactoring; +import org.python.pydev.plugin.nature.PythonNature; + + +import pyUML.exceptions.PyUMLSynchronizeCodeException; +import pyUML.pythonTree.PythonTreeFile; + + +/** + * Helper class to use the Python pyUML.refactoring functionality + * provided by "Bicycle Repair Man", written in Python + * as used by PyDev + */ +public class BicycleRefactoring { + + + /** + * This is the generic refactor command using bicycle pyUML.refactoring. + * Is is used by specializes pyUML.refactoring methods + * + * @param refactorCommand - the String with the pyUML.refactoring to be done + * @param conditionalMethod - the name of the pyUML.refactoring method + * @param project - the current project + * @return true on success, false on error + */ + public static boolean doGenericBikeRefactoring(String refactorCommand, String conditionalMethod, IProject project) throws PyUMLSynchronizeCodeException{ + IPyRefactoring pyRefactoring = AbstractPyRefactoring.getPyRefactoring(); + IPythonNature pythonNature = PythonNature.getPythonNature(project); + try { + if ((Boolean) REF.invoke(pyRefactoring, conditionalMethod, new Object[0])) { + AbstractShell pytonShell = AbstractShell.getServerShell(pythonNature, AbstractShell.OTHERS_SHELL); + String output = ""; + try{ + pytonShell.changePythonPath(pythonNature.getPythonPathNature().getCompleteProjectPythonPath(null)); //default + pytonShell.write(refactorCommand); + output = URLDecoder.decode(pytonShell.read((IProgressMonitor)null), "UTF-8"); + } catch (Exception e) { + output = "ERROR: "+e.getClass().getName()+"\n"; + e.printStackTrace(); + pytonShell.restartShell(); + } + if (output.startsWith("ERROR:")) { + String errmsg = output.substring(0, output.indexOf('\n')); + pytonShell.restartShell(); + MessageDialog.openError(null, "Error on pyUML.refactoring using Bike!" , + "There was a pyUML.refactoring error using the Bicycle Repair Man Browser\n" + + "The command was: "+refactorCommand + +"\nThe error was: "+errmsg); + return false; + } + } else { + throw new PyUMLSynchronizeCodeException("Error on pyUML.refactoring using Bike!\n\n" + + "pyRefactoring is not available!"); + } + }catch (CoreException e) { + throw new PyUMLSynchronizeCodeException("CoreException on pyUML.refactoring using Bike!\n\n" + + e.getMessage()); + }catch (IOException e) { + throw new PyUMLSynchronizeCodeException("IOException on pyUML.refactoring using Bike!\n\n" + + e.getMessage()); + } + + return true; + } + + + /** + * DO a 'rename' Refactoring. This is for class / method renaming + * + * @param filePath the Path of the file to edit + * (other files may be affected as well) + * (use File.toOSString() to get this Path string) + * @param newName the new Name of the object + * @param line the line of the object + * @param col the column of the object + * @param project the current project + * @return true on success, false otherwise. + */ + public static boolean doRenameObject(PythonTreeFile file, String newName, int line, int col, IProject project) throws PyUMLSynchronizeCodeException{ + + String filePath = file.getFilePath().toOSString(); + + // make sure the line to change is not the last line in file + // -> then bike will fail! + if (line == file.getFileContent().split("\n").length ) { + // insert line and start again + FileRefactoring.appendToFile(file, " "); + file.getRoot().setChangedFileLine(filePath+":"+line); + return true; + } + + + String command = "@@BIKE"; + command+= "renameByCoordinates"; + command+= "|"+filePath; + command+= "|"+line; + command+= "|"+(col-1); + command+= "|"+newName; + command+= "END@@"; + + String conditionalMethod = "canRename"; + + boolean success = doGenericBikeRefactoring(command, conditionalMethod, project); + file.updateFileInEclipse(); + return success; + } +} diff --git a/pyUml/src/pyUML/refactoring/FileRefactoring.java b/pyUml/src/pyUML/refactoring/FileRefactoring.java new file mode 100755 index 0000000..adceebc --- /dev/null +++ b/pyUml/src/pyUML/refactoring/FileRefactoring.java @@ -0,0 +1,161 @@ +package pyUML.refactoring; + +import java.io.File; + + +import pyUML.backend.ParseHelpers; +import pyUML.pythonTree.PythonTreeFile; + +/** + * Some convenience methods for modifying/writing files + */ +public class FileRefactoring { + + + /** + * replaces a string in a file from a given line/col + * deletes the file from that position unto + * + * @param pyFile the python file to edit + * @param startLine the line, from which the replace should begin + * @param startCol the column, from which the replace should begin + * @param newString the new String to replace the deleted with + * @param endMarker the char/string, unto the file content is replaces + * @param reInit if true, a reInit() is called on the python file after finishing + * @return + */ + public static boolean replaceFromCoordinate(PythonTreeFile pyFile, int startLine, int startCol, String newString, String endMarker, boolean reInit){ + String content = pyFile.getFileContent(); + int lineIndex = 0; + for (int i=1; i lineIndex) { + String contentAfter = content.substring(lineIndexAfter); + newContent += contentAfter; + } + if (writeToFile) { + ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject()); + pyFile.updateFileInEclipse(); + } + pyFile.setFileContent(newContent); + + return newContent; + } + + /** + * completely removes a given line in a python file + * @param pyFile + * @param lineNo The lineNo to deletes + * @param writeToFile if true, the changes are directly written to the python file + * @param onlyIfNotEmpty if true, only a non-empty-line is deleted (to preserve file design) + * @return the String with the replaced line + */ + public static String removeLine(PythonTreeFile pyFile, int lineNo, boolean writeToFile, boolean onlyIfNotEmpty) { + String content = pyFile.getFileContent(); + int lineIndex = 0; + for (int i=1; i lineIndex) { + String contentAfter = content.substring(lineIndexAfter); + newContent += contentAfter; + } + if (onlyIfNotEmpty) { + String lineToDelete = content.substring(lineIndex+1, lineIndexAfter ); + if (lineToDelete.matches("[\\s]*")) + return content; + } + + if (writeToFile) { + ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject()); + pyFile.updateFileInEclipse(); + } + + pyFile.setFileContent(newContent); + return newContent; + } + + /** + * Appends a String to a PythonTreeFile and saves the file on disk + * @param pyFile + * @param stringToAppend + * @return + */ + public static boolean appendToFile(PythonTreeFile pyFile, String stringToAppend) { + String content = pyFile.getFileContent(); + String newContent = content + stringToAppend; + ParseHelpers.stringToFile(new File(pyFile.getFilePath().toOSString()), newContent, pyFile.getProject()); + pyFile.updateFileInEclipse(); + pyFile.setFileContent(newContent); + return true; + } + + /** + * Returns the line with the given line number + * for this file. Line numbers start with 1, not with 0 + * @param pyFile the PythonTreeFile which represents the file + * @param lineNo the lineNumber + * @return The searched line as a string, null if lineNo is + * not in index. + */ + public static String getLine(PythonTreeFile pyFile, int lineNo) { + String[] splittedFileContent = pyFile.getSplittedFileContent(); + if (lineNo <= 0) + return null; + if (lineNo > splittedFileContent.length) + return null; + + return splittedFileContent[lineNo - 1]; + } +} diff --git a/pyUml/src/pyUML/views/EditView.java b/pyUml/src/pyUML/views/EditView.java new file mode 100755 index 0000000..a6886e0 --- /dev/null +++ b/pyUml/src/pyUML/views/EditView.java @@ -0,0 +1,63 @@ +package pyUML.views; + +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.util.WrappedException; +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.dialogs.MessageDialog; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.resource.UMLResource; + +import pyUML.backend.GlobalConstants; + + +/** + * This edits a given view for a project. + * It loads the view configuration and calls EditViewWizard + */ +public class EditView{ + private EditViewWizard editViewWizard; + + public EditView(IProject project, IFile confFile, String viewName, boolean open) { + + try{ + String umlModelFileName=project.getLocation(). + append(GlobalConstants.getPyUmlDir()). + append(project.getName()+".uml").toOSString(); + + EObject diagramRoot = null; + try { + Resource resource = new ResourceSetImpl().getResource(URI.createFileURI(umlModelFileName), true); + diagramRoot = (EObject) resource.getContents().get(0); + } catch (WrappedException ex) { + MessageDialog.openError(null,ex.getMessage(),"Unable to load model: " + umlModelFileName); + return; + } + UMLResource res = (UMLResource) diagramRoot.eResource(); + Map modelXmiDict = res.getEObjectToIDMap(); + Model model = (Model) diagramRoot; + + editViewWizard = new EditViewWizard(null, model, res, project, confFile, viewName, modelXmiDict); + WizardDialog dialog = new WizardDialog(null, editViewWizard); + if (open) + dialog.open(); + else + dialog.create(); + + }catch (Throwable t) { + MessageDialog.openError(null,t.getMessage(),"Error Managing Views:"+t.getMessage()); + t.printStackTrace(); + } + + } + + public EditViewWizard getEditViewWizard() { + return editViewWizard; + } +} diff --git a/pyUml/src/pyUML/views/EditViewWizard.java b/pyUml/src/pyUML/views/EditViewWizard.java new file mode 100755 index 0000000..08846b1 --- /dev/null +++ b/pyUml/src/pyUML/views/EditViewWizard.java @@ -0,0 +1,437 @@ +package pyUML.views; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +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.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IEditorPart; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.Relationship; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.resource.UMLResource; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.UMLToolsHelperMethods; +import pyUML.listeners.ViewChangeListener; + + +/** + * This wizard lets the user edit a view. Classes + * and Packages can be selected; super- or child classes + * can be used creating a view. + */ +public class EditViewWizard extends Wizard implements IWizard{ + private Model model; + private UMLResource resource; + private IProject project; + private IFile confFile; + private String viewName; + private SelectViewElementsPage partsPage; + private List usedXmiIds; + private boolean includeSuperClasses=false; + private boolean includeSubClasses=false; + private Map modelXmiDict; + + private List nodeToDeleteList; + private List usedModelElements; + + public EditViewWizard(Shell parentShell, Model model, UMLResource resource, IProject project, IFile confFile, String viewName, MapmodelXmiDict) { + super(); + this.model = model; + this.resource = resource; + this.project = project; + this.confFile = confFile; + this.viewName = viewName; + this.modelXmiDict = modelXmiDict; + this.usedModelElements = new Vector(); + this.setWindowTitle("Create UML View"); + this.readConfFile(); + } + + @Override + public void addPages() { + this.partsPage = new SelectViewElementsPage("Select Model Elements for this View", + this.model, this.usedXmiIds, this.modelXmiDict, this.viewName, + this.includeSuperClasses, this.includeSubClasses); + addPage(partsPage); + } + + /** + * Reads the CONF file of this view (e.g. used classes+packages) + */ + public void readConfFile(){ + this.usedXmiIds = new Vector(); + + String[] confContent = EclipseHelperMethods.iFileToString(confFile).split("\n"); + boolean xmiSectionFound=false; + for (String line:confContent) { + + if(xmiSectionFound) { + this.usedXmiIds.add(line); + } + + if (line.matches("CONF_INCLUDE_SUPERCLASSES:.*")) { + this.includeSuperClasses= + line.replaceAll("CONF_INCLUDE_SUPERCLASSES:", "") + .equals("TRUE"); + } + if (line.matches("CONF_INCLUDE_SUBCLASSES:.*")) { + this.includeSubClasses= + line.replaceAll("CONF_INCLUDE_SUBCLASSES:", "") + .equals("TRUE"); + } + + if (line.matches("XMI_SECTION")) + xmiSectionFound=true; + } + + + } + + + + @Override + public boolean performFinish() { + return performFinish(true); + } + + /** + * + * @param openAfterFinish if true, the created view will be + * opened immediately + * @return true on success + */ + public boolean performFinish(boolean openAfterFinish) { + //generate new model as part of old one + String oldViewName = viewName; + String viewName = this.viewName; + if (this.partsPage.viewNameField != null) + viewName = this.partsPage.getViewNameField().getText(); + + + IFile umlFile = this.project.getWorkspace().getRoot() + .getFile(this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(oldViewName+GlobalConstants.getViewUmlExtension())); + + IFile diagramFile = this.project.getWorkspace().getRoot() + .getFile(this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(oldViewName+GlobalConstants.getDiagramExtension())); + + boolean editorChangedNameAndWasOpen =true; + + // if view name changed, move all files to new name + if (!viewName.equals(oldViewName)) { + + // compute new file names with changed view name + IPath newConfFilePath = this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(viewName+GlobalConstants.getViewConfExtension()); + + IPath newViewUmlPath = this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(viewName+GlobalConstants.getViewUmlExtension()); + + + IPath newDiagramFilePath = this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(viewName+GlobalConstants.getDiagramExtension()); + + // close editor, if it is open + EclipseHelperMethods.closeEditorByName(project, diagramFile.getName()); + editorChangedNameAndWasOpen = true; + + try { + // now really move view files + this.confFile.move(newConfFilePath, true, null); + + if (umlFile.exists()) + umlFile.move(newViewUmlPath, true, null); + + if (diagramFile.exists()) + diagramFile.move(newDiagramFilePath, true, null); + + this.confFile = project.getFile(newConfFilePath.removeFirstSegments(1)); + umlFile = project.getFile(newViewUmlPath.removeFirstSegments(1)); + diagramFile = project.getFile(newDiagramFilePath.removeFirstSegments(1)); + + } catch (CoreException e) { + System.out.println("error moving view file to new view name!"); + } + } + + //model.setName(viewName); + this.nodeToDeleteList = new Vector(); + + if (partsPage.viewNameField != null) + this.usedXmiIds= new Vector(); + + removeUnmarkedNodes(this.model); + + List classList; + classList = getClassListFromModel(this.model); + + + // if "include superclasses" was checked: + // remove all superclasses of selected items from 'classes to remove' list + + if (this.partsPage.getButtInclSuperClasses() != null) + this.includeSuperClasses = this.partsPage.getButtInclSuperClasses().getSelection(); + if (this.partsPage.getButtInclSubClasses() != null) + this.includeSubClasses = this.partsPage.getButtInclSubClasses().getSelection(); + + if (includeSuperClasses) { + boolean superClassFound; + do { + superClassFound = false; + for (Classifier cl:classList) { + EList gens = cl.getGeneralizations(); + for (Generalization gen : gens) { + if (nodeToDeleteList.contains(gen.getGeneral()) + && (! nodeToDeleteList.contains(cl))) { + nodeToDeleteList.remove(gen.getGeneral()); + superClassFound = true; + } + } + } + } + while (superClassFound); + } + + // exclude subclasses from nodeToDeleteList for every class in list + // if includeSubClasses was set in gui + if (includeSubClasses) { + boolean subClassFound; + do { + subClassFound = false; + for (Classifier cl:classList) { + for (Relationship rel : cl.getRelationships()) { + if (rel instanceof Generalization) { + Generalization gen = (Generalization) rel; + if (gen.getOwner() == cl) + continue; + if (nodeToDeleteList.contains(gen.getOwner()) + && (! nodeToDeleteList.contains(cl))) { + nodeToDeleteList.remove(gen.getOwner()); + subClassFound = true; + } + + } + } + } + } + while (subClassFound); + + } + + + List elList = getPackagedElementsFromModel(this.model); + + Package viewPack = model.createNestedPackage("View_"+viewName); + + // make model "flat", setting parent of all classes to model root + for(Type el : elList) { + if (! this.nodeToDeleteList.contains(el)) + el.setPackage(viewPack); + } + + // remove elements in nodeToDeleteList + /*for (Element e:this.nodeToDeleteList) { + e.destroy(); + } + */ + /* + //remove all package entries of model + List packageList = new Vector(); + for (Element e: model.getOwnedElements()) { + if (e instanceof Package) { + packageList.add(e); + } + } + for (Element e: packageList) { + //e.destroy(); + }*/ + + //save new "view"-model + try { + // if model was renamed, rename old model + String umlFileName=project.getLocation(). + append(GlobalConstants.getPyUmlDir()). + append(viewName + GlobalConstants.getViewUmlExtension()).toOSString(); + + resource.setURI(URI.createFileURI(umlFileName)); + resource.save(null); + + EclipseHelperMethods.updateFile(umlFile); + System.out.println(("Saving view file "+umlFileName+" done.")); + } catch (IOException ioe) { + MessageDialog.openError(null,"IOException", + "Error saving uml file: \n" + ioe.getMessage()); + } + + //save configuration + String confFileContents="CONF_INCLUDE_SUPERCLASSES:" + +( includeSuperClasses ? "TRUE" : "FALSE" ) + "\n"; + + confFileContents+="CONF_INCLUDE_SUBCLASSES:" + +( includeSubClasses ? "TRUE" : "FALSE" ) + "\n"; + + confFileContents += "XMI_SECTION\n"; + for (String id: this.usedXmiIds) { + confFileContents += id + "\n"; + } + EclipseHelperMethods.StringToIFile(confFile, confFileContents); + + + + // create graphical diagram, if it does not already exist + + // create diagram, if it does not exist; after creation, open it + // (diagram should not be opened when "edit" was pressed) + if (! diagramFile.exists() || editorChangedNameAndWasOpen) { + // create and open diagram, if it was created as new + if (! diagramFile.exists()) + UMLToolsHelperMethods.createModelDiagram(viewPack, diagramFile); + else { + String oldDiagramContent = EclipseHelperMethods.iFileToString(diagramFile); + Pattern pattern = Pattern.compile("(.*.*)"); + String viewId = resource.getID(viewPack); + + // get old view package id + Matcher matcher = pattern.matcher(oldDiagramContent); + String oldViewId = null; + if (matcher.find()) { + oldViewId = matcher.group(2); + } else + return false; + // replace all old IDs to the new ID + oldDiagramContent = oldDiagramContent.replace(oldViewId, viewId); + + EclipseHelperMethods.StringToIFile(diagramFile, oldDiagramContent); + + } + if (openAfterFinish) + UMLToolsHelperMethods.openDiagram(project, diagramFile, umlFile.getName() ,true); + } else { + // refresh editor, if it was open + if (null != EclipseHelperMethods.lookForOpenEditorByName(diagramFile.getName())) { + IEditorPart newPage = UMLToolsHelperMethods.refreshDiagramEditor(project, diagramFile, false); + newPage.addPropertyListener(new ViewChangeListener(this.project)); + } + } + EclipseHelperMethods.updateFile(diagramFile); + return true; + } + + /** + * Recursive Helper method to add the nodes that were not + * selected to the nodeToDeletelist + * If a package node is selected, all children will be selected, implicitely. + * If a package node is not selected, a recursion on the children is started. + * @param node + */ + private void removeUnmarkedNodes(Element node) { + TreeItem assignedItem =this.partsPage.getNodeCheckboxDict().get(node); + if (assignedItem != null && (assignedItem.getChecked())) + this.usedXmiIds.add(this.modelXmiDict.get(node)); + + if (node instanceof Relationship) { + return; + } + + if (node instanceof org.eclipse.uml2.uml.Classifier) { + assignedItem =this.partsPage.getNodeCheckboxDict().get(node); + if (assignedItem == null) { + if (this.usedXmiIds.contains(modelXmiDict.get(node))) { + this.usedModelElements.add(node); + } else { + this.nodeToDeleteList.add(node); + } + }else if (! assignedItem.getChecked()) { + // add node to remove list if it is not marked. + this.nodeToDeleteList.add(node); + return; + } else { + this.usedModelElements.add(node); + this.usedXmiIds.add(this.modelXmiDict.get(node)); + } + } + else if (node instanceof Package) { + for (Element childNode : node.getOwnedElements()) { + assignedItem =this.partsPage.getNodeCheckboxDict().get(node); + if (assignedItem == null) { + } + else if (assignedItem.getChecked()) + this.usedXmiIds.add(this.modelXmiDict.get(node)); + removeUnmarkedNodes(childNode); + } + } + } + + /** + * return all classes in model + * @param node + */ + private Vector getClassListFromModel(Element node) { + Vector classList = new Vector(); + if (node instanceof Classifier) { + Classifier cl = (Classifier) node; + classList.add(cl); + } else { + EList children = node.getOwnedElements(); + for (Element child : children) { + classList.addAll(getClassListFromModel(child)); + } + } + return classList; + } + + + /** + * get all child elements of a package + * that are Types (direct successors of packages) + * + * @param node The node where the search is to be started + * @return the list of Types + */ + private Vector getPackagedElementsFromModel(Element node) { + + Vector elList = new Vector(); + if (node instanceof Classifier) { + Classifier cl = (Classifier) node; + elList.add(cl); + elList.addAll(cl.getAssociations()); + } else { + EList children = node.getOwnedElements(); + for (Element child : children) { + elList.addAll(getPackagedElementsFromModel(child)); + } + } + return elList; + } + + public SelectViewElementsPage getPartsPage() { + return partsPage; + } +} \ No newline at end of file diff --git a/pyUml/src/pyUML/views/ManageViewsPage.java b/pyUml/src/pyUML/views/ManageViewsPage.java new file mode 100755 index 0000000..fcef5ea --- /dev/null +++ b/pyUml/src/pyUML/views/ManageViewsPage.java @@ -0,0 +1,307 @@ +package pyUML.views; + + +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.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorPart; +import org.eclipse.uml2.uml.Model; + +import pyUML.actions.ManageViewsAction; +import pyUML.backend.GlobalConstants; +import pyUML.backend.JavaHelperMethods; +import pyUML.backend.UMLToolsHelperMethods; +import pyUML.listeners.ViewChangeListener; + + +/** + * This is the dialog for managing pyUML.views. + * Views can be selected, deleted, edited and created. + * A listener is implemented with this class, so here + * is defined what happens when you press buttons in the dialog. + */ +public class ManageViewsPage extends Dialog implements SelectionListener{ + Composite composite = null; + Group viewsBoxGroup = null; + List viewsBox = null; + Button openButton = null; + Button editButton = null; + Button deleteButton = null; + Button createNewButton = null; + Model model; + IProject project; + + Shell shell=null; + + public ManageViewsPage(Shell parent, Model model, IProject project){ + super(parent); + this.model= model; + this.project=project; + + } + + protected Control createDialogArea(Composite parent) { + this.composite = (Composite) super.createDialogArea(parent); + setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MAX); + createControls(composite); + initializeDialog(); + //add controls to composite as necessary + return composite; + } + + + public void createControls (Composite composite) { + // create graphical components + shell = composite.getShell(); + shell.setText("Manage UML Views"); + + viewsBoxGroup = new Group(composite, SWT.None); + viewsBoxGroup.setText("Available Views"); + + viewsBoxGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + viewsBoxGroup.setLayout(new GridLayout(1, true)); + + + viewsBox = new List( viewsBoxGroup, SWT.BORDER|SWT.SINGLE|SWT.V_SCROLL|SWT.H_SCROLL ); + viewsBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + Composite buttonGroup = new Composite(viewsBoxGroup, SWT.NONE); + buttonGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + buttonGroup.setLayout(new GridLayout(3, true)); + + viewsBox.setSize(300,300); + + openButton = new Button(buttonGroup, SWT.PUSH); + openButton.setText("Open View"); + openButton.addSelectionListener(this); + + editButton = new Button(buttonGroup, SWT.PUSH); + editButton.setText("Edit View"); + editButton.addSelectionListener(this); + + deleteButton = new Button(buttonGroup, SWT.PUSH); + deleteButton.setText("Delete View"); + deleteButton.addSelectionListener(this); + + + buttonGroup.pack(); + viewsBoxGroup.pack(); + setElementEnabled(false, viewsBoxGroup); + + createNewButton = new Button(composite, SWT.PUSH); + createNewButton.setText("Create New View"); + createNewButton.setLayoutData(new GridData(GridData.FILL_BOTH)); + createNewButton.addSelectionListener(this); + + composite.pack(); + + } + + + /** + * Sets a composite element and all children enabled/disabled + * @param enabled + * @param element + */ + public static void setElementEnabled(boolean enabled, Control element) { + element.setEnabled(enabled); + if (element instanceof Composite) { + Composite comp = (Composite) element; + for (Control child : comp.getChildren()) { + setElementEnabled(enabled, child); + } + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + // Auto-generated method stub + } + + /** + * Handles pressed-button events and runs appropriate pyUML.actions + */ + public void widgetSelected(SelectionEvent e) { + // "CREATE NEW" BUTTON + if (e.getSource() == this.createNewButton) { + this.createDialog(); + + // re-open View management window + this.cancelPressed(); + } + //DELETE BUTTON + else if (e.getSource() == this.deleteButton) { + + // return if nothing was selected + if (this.viewsBox.getSelection().length <= 0) + return; + + // warn before deletion + if (MessageDialog.openConfirm(null, "Confirm deletion of view", + "Do you really want to delete this view?") == false) + return; + + // delete view configuration, UML model and diagram + String selectedElement = this.viewsBox.getSelection()[0]; + IPath conFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir()) + .append(selectedElement+GlobalConstants.getViewConfExtension()); + IFile confFile = this.project.getWorkspace().getRoot().getFile(conFilePath); + IPath umlFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir()) + .append(selectedElement+GlobalConstants.getViewUmlExtension()); + IFile umlFile = this.project.getWorkspace().getRoot().getFile(umlFilePath); + IPath diagramFilePath = project.getFullPath().append(GlobalConstants.getPyUmlDir()) + .append(selectedElement+GlobalConstants.getDiagramExtension()); + IFile diagramFile = this.project.getWorkspace().getRoot().getFile(diagramFilePath); + + try { + if (confFile.exists()) + confFile.delete(false, null); + if (umlFile.exists()) + umlFile.delete(false, null); + if (diagramFile.exists()) + diagramFile.delete(false, null); + } catch (CoreException err) { + MessageDialog.openError(null, "Error deleting element", + "Could not delete view. Reason:\n"+err.getMessage()); + } + this.cancelPressed(); + ManageViewsAction.run(project); + + // OPEN BUTTON + } else if (e.getSource() == this.openButton) { + if (this.viewsBox.getSelection().length <= 0) + return; + String ViewUmlFileName = this.viewsBox.getSelection()[0]+GlobalConstants.getViewUmlExtension(); + String ViewConfFileName = this.viewsBox.getSelection()[0]+GlobalConstants.getViewConfExtension(); + String selectedElement = this.viewsBox.getSelection()[0]+GlobalConstants.getDiagramExtension(); + IFile viewDiagramFile = this.project.getWorkspace().getRoot(). + getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()). + append(selectedElement)); + IFile viewConfFile = this.project.getWorkspace().getRoot(). + getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()). + append(ViewConfFileName)); + + if (! viewDiagramFile.exists()) { + MessageDialog.openError(null, "Error opening view", "The selected view could not be opened;\n" + + "The UML diagram does not seem to exist!"); + } else { + UMLToolsHelperMethods.updateViewModel(project, viewConfFile); + IEditorPart newPage = null; + try { + newPage = UMLToolsHelperMethods.refreshDiagramEditor(this.project, viewDiagramFile, false); + } catch (Throwable t) { + t.printStackTrace(); + } + if (newPage == null) + newPage = UMLToolsHelperMethods.openDiagram(this.project, viewDiagramFile, ViewUmlFileName, true); + + + if ( newPage == null) { + MessageDialog.openError(null, "Error opening view", "The selected view could not be opened!"); + } + else { + newPage.addPropertyListener(new ViewChangeListener(this.project)); + this.close(); + } + } + } // EDIT BUTTON + else if (e.getSource() == this.editButton) { + + String selectedViewName = this.viewsBox.getSelection()[0]; + + IFile confFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(selectedViewName + GlobalConstants.getViewConfExtension())); + IFile viewDiagramFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(selectedViewName + GlobalConstants.getDiagramExtension())); + + + // open view editor + new EditView(this.project, confFile, selectedViewName, true); + + // reload View, if it is already opened + UMLToolsHelperMethods.refreshDiagramEditor(project, viewDiagramFile, true); + + // re-open View management window + this.cancelPressed(); + ManageViewsAction.run(project); + } + } + + /** + * creates a "new View" dialog + * creates an empty view config file and runs "edit" on this file + */ + public void createDialog() { + String viewName = "newView"; + String newViewName = viewName; + IPath filePath=this.project.getLocation().append(GlobalConstants.getPyUmlDir()); + + // find initial filename that is not already used + int i=0; + java.io.File f; + do { + newViewName = viewName+(i==0?"":i); + String fileName=filePath.append(newViewName +GlobalConstants.getViewConfExtension()).toOSString(); + f= new java.io.File(fileName); + i++; + } while (f.exists()); + + // create initial config file + try{ + IFile confFile = this.project.getWorkspace().getRoot().getFile(project.getFullPath().append(GlobalConstants.getPyUmlDir()).append(newViewName + GlobalConstants.getViewConfExtension())); + confFile.create(JavaHelperMethods.stringToStream(""), false, null); + + //open "edit view" editor + new EditView(this.project, confFile, newViewName, true); + this.close(); + + } catch (CoreException err) { + MessageDialog.openError(null, "Cannot create View", "View could not be created.\n" + + "Reason:\n"+err.getMessage()); + return; + } + + + } + + /** + * re-reads available pyUML.views from hard disk + */ + protected void initializeDialog() { + boolean viewFound = false; + String pyUmlDir = project.getLocation().append(GlobalConstants.getPyUmlDir()).toOSString(); + java.io.File umlDir = new java.io.File(pyUmlDir); + if (umlDir.list() == null) { + MessageDialog.openError(null, "Error Managing Views", + "No UML Model was found.\n" + + "Please create a Model before creating a View!"); + this.close(); + return; + } + + for (String file : umlDir.list()) { + if (file.matches(".*.pyUmlView.uml$")) { + viewFound=true; + this.viewsBox.add(file.replace(".pyUmlView.uml", "")); + this.viewsBox.add("a"); + this.viewsBox.remove(this.viewsBox.getItemCount()-1); + } + } + + if (viewFound) + setElementEnabled(true, viewsBoxGroup); + else + setElementEnabled(false, viewsBoxGroup); + } +} diff --git a/pyUml/src/pyUML/views/SelectViewElementsPage.java b/pyUml/src/pyUML/views/SelectViewElementsPage.java new file mode 100755 index 0000000..d5831d1 --- /dev/null +++ b/pyUml/src/pyUML/views/SelectViewElementsPage.java @@ -0,0 +1,235 @@ +package pyUML.views; + +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.Model; + +/** + * This Wizard page contains a tree view where + * the user can select packages/classes used in the view. + */ +public class SelectViewElementsPage extends WizardPage implements SelectionListener{ + + private Model model; + private List usedXmiIds; + protected Dictionary nodeCheckboxDict; + protected Text viewNameField; + protected Button buttInclSuperClasses; + protected Button buttInclSubClasses; + private Map modelXmiDict; + private boolean initialIncludeSuperclasses; + private boolean initialIncludeSubclasses; + private String initialViewName; + + public Text getViewNameField() { + return viewNameField; + } + + protected SelectViewElementsPage(String pageName, Model model, List usedXmiIds, + Map modelXmiDict, String initialViewName, + boolean initialIncludSuperclasses, boolean initialIncludSubclasses) { + super(pageName); + this.setTitle(pageName); + this.model=model; + this.nodeCheckboxDict = new Hashtable(); + this.usedXmiIds = usedXmiIds; + this.modelXmiDict = modelXmiDict; + this.initialIncludeSuperclasses = initialIncludSuperclasses; + this.initialIncludeSubclasses = initialIncludSubclasses; + this.initialViewName = initialViewName; + } + + public void createControl(Composite parent) { + // create the composite to hold the widgets + GridData gd; + Composite composite = new Composite(parent, SWT.NULL); + + // create the desired layout for this wizard page + GridLayout gl = new GridLayout(); + int ncol = 1; + gl.numColumns = ncol; + gl.makeColumnsEqualWidth=true; + composite.setLayout(gl); + + Composite viewNameComp= new Composite(composite, composite.getStyle()); + GridLayout ViewNameLayout = new GridLayout(); + ViewNameLayout.numColumns=2; + ViewNameLayout.makeColumnsEqualWidth=false; + viewNameComp.setLayout(ViewNameLayout); + + Label viewNameLabel = new Label(viewNameComp, SWT.HORIZONTAL); + viewNameLabel.setText("View name: "); + viewNameField = new Text(viewNameComp, SWT.SINGLE); + viewNameField.setText(this.initialViewName); + viewNameField.setSize(200, 25); + + Tree tree = new Tree(composite, SWT.CHECK); + gd = new GridData(GridData.FILL_BOTH); + + tree.setLayoutData(gd); + + TreeItem item = new TreeItem(tree, tree.getStyle()); + item.setText(this.model.getName()); + + nodeCheckboxDict.put(model, item); + if (usedXmiIds.contains(modelXmiDict.get(model))) + item.setChecked(true); + + for (Element child : model.getOwnedElements()) { + recurseModelElements(child, item); + } + + if (usedXmiIds.contains(modelXmiDict.get(model))) + item.setChecked(true); + + + this.buttInclSuperClasses = new Button(composite, SWT.CHECK); + this.buttInclSuperClasses.setText("Include superclasses of selected classes"); + this.buttInclSuperClasses.setSelection(this.initialIncludeSuperclasses); + + this.buttInclSubClasses = new Button(composite, SWT.CHECK); + this.buttInclSubClasses.setText("Include child classes of selected classes"); + this.buttInclSubClasses.setSelection(this.initialIncludeSubclasses); + + + // set the composite as the control for this page + setControl(composite); + tree.addSelectionListener(this); + + } + + /** + * This adds all sub-elements of checked packages + * to the list of used XMI-IDs. This is needed for a non-interactive + * View update to ensure all newly created sub-classes/-packages + * are added to a checked package. + */ + public void addPackagedXmiIds() { + this.recurseModelElements(this.model, null); + } + + /** + * Initialize the TreeView by iterationg the Model + * -> Package and class nodes are created in the tree + * @param node + * @param parentItem if null, the XMI-ID will be added to used IDs + * insead of checking the box (used non-interactive mode) + */ + protected void recurseModelElements(Element node, TreeItem parentItem) { + if (node instanceof org.eclipse.uml2.uml.Package) { + org.eclipse.uml2.uml.Package pack = (org.eclipse.uml2.uml.Package) node; + if (parentItem == null) { + if (this.usedXmiIds.contains(this.modelXmiDict.get(pack))) + for (Element childNode : pack.getOwnedElements()) { + this.usedXmiIds.add(this.modelXmiDict.get(childNode)); + recurseModelElements(childNode, null); + } + } else { + TreeItem item = new TreeItem(parentItem, parentItem.getStyle()); + item.setText("Package " + pack.getName()); + nodeCheckboxDict.put(pack, item); + + for (Element childNode : pack.getOwnedElements()) + recurseModelElements(childNode, item); + + if(this.usedXmiIds.contains(this.modelXmiDict.get(pack))) + setWidgetChecked(item, true); + } + return; + } + if (node instanceof Classifier && parentItem != null) { + Classifier cl = (Classifier) node; + TreeItem item = new TreeItem(parentItem, parentItem.getStyle()); + if (cl instanceof org.eclipse.uml2.uml.Class) + item.setText("Class " + cl.getName()); + else if (cl instanceof Interface) + item.setText("Interface " + cl.getName()); + else + item.setText("Element " + cl.getName()); + + nodeCheckboxDict.put(cl, item); + if(this.usedXmiIds.contains(this.modelXmiDict.get(cl))) + item.setChecked(true); + + for (Element childNode : cl.getOwnedElements()) + recurseModelElements(childNode, item); + return; + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + + /** + * Check/uncheck a Class/Package in the Tree View + * and *all* subpackages/classes of a view + * This can be called by the listener or + * automatically when updating a view + * -> all new Child-Elements of a selected package + * should be automatically added to a view. + * @param item + * @param checked + */ + public void setWidgetChecked(TreeItem item, boolean checked) { + item.setChecked(checked); + List children = new Vector(); + children.addAll(Arrays.asList(item.getItems())); + while(! children.isEmpty()) { + TreeItem child = children.get(0); + children.remove(child); + children.addAll(Arrays.asList(child.getItems())); + child.setChecked(checked); + } + } + + public void widgetSelected(SelectionEvent e) { + // mark or unmark all children check boxes + // of a marked/unmarked box + if (e.item instanceof TreeItem) { + TreeItem item = (TreeItem) e.item; + boolean checked = item.getChecked(); + this.setWidgetChecked(item, checked); + } + } + + public Dictionary getNodeCheckboxDict() { + return nodeCheckboxDict; + } + + public Button getButtInclSuperClasses() { + return buttInclSuperClasses; + } + + public boolean isInitialIncludeSuperclasses() { + return initialIncludeSuperclasses; + } + + public void setInitialIncludeSuperclasses(boolean initialIncludeSuperclasses) { + this.initialIncludeSuperclasses = initialIncludeSuperclasses; + } + + public Button getButtInclSubClasses() { + return buttInclSubClasses; + } +} diff --git a/pyUml/src/pyUML/views/SynchronizeModelByView.java b/pyUml/src/pyUML/views/SynchronizeModelByView.java new file mode 100755 index 0000000..b662b93 --- /dev/null +++ b/pyUml/src/pyUML/views/SynchronizeModelByView.java @@ -0,0 +1,512 @@ +package pyUML.views; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.EClassImpl; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.uml2.uml.Association; +import org.eclipse.uml2.uml.BehavioredClassifier; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.PackageableElement; +import org.eclipse.uml2.uml.ParameterableElement; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Realization; +import org.eclipse.uml2.uml.Relationship; +import org.eclipse.uml2.uml.TemplateParameter; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.resource.UMLResource; + +import pyUML.backend.GlobalConstants; +import pyUML.backend.UMLToolsHelperMethods; + + + +/** + * This is an action class where the global UML model + * is to be updated by a view. + * Classes cannot be copied, because this would destroy all + * model relationships of the class. + * New classes in a view are ignored, because it is not known where + * they are to be inserted in the model. + * + * At the moment, class attributes and methods are *not* synchronized + * with the mail model. + * + */ +public class SynchronizeModelByView implements IObjectActionDelegate{ + private String pathToModel;; + private String pathToView; + private Model model; + private Model viewModel; + private Resource[] viewResource = {null}; + private Map xmiModelDict; + private Map modelXmiDict; + private Map xmiViewDict; + private Map viewXmiDict; + private IProject project; + + + public static void synchronizeGlobalModel(String pathToView, IProject project) { + SynchronizeModelByView sv = new SynchronizeModelByView(); + sv.project = project; + sv.synchronizeGlobalModel(pathToView); + } + + /** + * Updates the global model by changes made by the given view. + * Class deletions are removed from the view, not from the model. + * + * New classes/packages are ignored, because it is not known + * where they should be inserted. + * + * Other changes are updated in the global model. + * + * @param pathToModel + * @param pathToView + * @return + */ + public boolean synchronizeGlobalModel(String pathToView) { + String pathToModel = this.project.getLocation() + .append(GlobalConstants.getPyUmlDir()) + .append(this.project.getName()+".uml").toOSString(); + + //init models + this.pathToModel = pathToModel; + this.pathToView = pathToView; + initModels(); + + + String viewName = new Path(pathToView).lastSegment().replaceAll(GlobalConstants.getViewUmlExtension(), ""); + + Package viewPackage = null; + + viewPackage = this.viewModel.getNestedPackage("View_"+viewName); + + if (viewPackage == null) { + MessageDialog.openError(null, "Error synchronizing View", + "The Model could not be synchronized by the view, because\n" + + "The View package View_"+viewName+" could not\n" + + "be found."); + return false; + } + List elList = new Vector(); + elList.addAll(viewPackage.getPackagedElements()); + for (PackageableElement el : elList) { + // find parent package in model + if (el instanceof Type) { + Type packagedType = (Type) el; + + Type includingType = packagedType; + + if (packagedType instanceof Association) { + Association as = (Association) packagedType; + includingType = as.getEndTypes().get(0); + } + + String xmi_id = this.viewXmiDict.get(includingType); + if (xmi_id == null || (! this.xmiModelDict.containsKey(xmi_id))) + continue; + + Type modelType = (Type) this.xmiModelDict.get(xmi_id); + Package parentPackage = modelType.getPackage(); + String modelPackageXmiId= this.modelXmiDict.get(parentPackage); + if (modelPackageXmiId == null) + continue; + Package newViewPackage = (Package) this.xmiViewDict.get(modelPackageXmiId); + if (newViewPackage == null) + continue; + + packagedType.setPackage(newViewPackage); + + } else if (el instanceof ParameterableElement) { + ParameterableElement parEl = (ParameterableElement) el; + String xmi_id = this.viewXmiDict.get(el); + ParameterableElement modelParEl = (ParameterableElement) this.xmiModelDict.get(xmi_id); + Realization r; + TemplateParameter parentParEl = modelParEl.getOwningTemplateParameter(); + String modelParElXmiId=this.modelXmiDict.get(parentParEl); + if (modelParElXmiId == null) + continue; + TemplateParameter newViewParEl = (TemplateParameter) this.xmiViewDict.get(modelParElXmiId); + if (newViewParEl == null) + continue; + parEl.setOwningTemplateParameter(newViewParEl); + } + } + viewPackage.destroy(); + + /* + // synchronize by all child classes + try{ + List elementCopy = new Vector(); + elementCopy.addAll(this.viewModel.getOwnedElements()); + for (Element child : elementCopy) { + if (child instanceof Class) + synchronizeClass((Class)child); + } + } catch (Throwable t) { + t.printStackTrace(); + } + */ + // save model + this.viewResource[0].setURI(URI.createFileURI(project.getLocation().append(GlobalConstants.getPyUmlDir()).append(project.getName()+".uml").toOSString())); + try { + this.viewResource[0].save(null); + }catch (IOException e) { + e.printStackTrace(); + } + return true; + //return saveModel(); + } + + /** + * initializes the Model of the view and the main model + */ + private void initModels() { + // save all open editors + IWorkbenchPage page = + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + page.saveAllEditors(false); + + // initialize XMI dictionaries as empty -> they are filled, if a + // model already exists + this.modelXmiDict = new HashMap(); + this.xmiModelDict = new HashMap(); + this.viewXmiDict = new HashMap(); + this.xmiViewDict = new HashMap(); + + // load view and model + // this.model = + this.model= initModel(this.pathToModel, this.xmiModelDict, this.modelXmiDict, null); + if (this.model == null) + return; + this.viewModel = initModel(this.pathToView, this.xmiViewDict, this.viewXmiDict, this.viewResource); + if (this.viewModel == null) + return; + } + + /** + * loads a .uml model (main model or view) + * and fills the given dictionaries + * @param pathToModel + * @param xmiModelDict + * @param modelXmiDict + * @param modelResource + * @return + */ + private Model initModel(String pathToModel, Map xmiModelDict, + Map modelXmiDict, Resource[] modelResource) { + + // look for model file + Model model; + Resource resource; + File modelFile = new File(pathToModel); + if (! modelFile.exists()) { + MessageDialog.openError(null, "Error synchronizing Model by View", + "Model can not be found: "+pathToModel); + return null; + } + // read Model + EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(pathToModel); + model = (Model) diagramRoot; + resource = model.eResource(); + + // get model -> xmi-id dictionary + UMLResource r = (UMLResource) resource; + modelXmiDict.putAll(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); + } + if (modelResource != null) + modelResource[0] = resource; + return model; + } + + + /** + * Synchronizes a model class by a view class + * @param viewClass + */ + private void synchronizeClass(Class viewClass) { + String classXmiId = this.viewXmiDict.get(viewClass); + if (! xmiModelDict.containsKey(classXmiId)) { + MessageDialog.openWarning(null, "Error saving View", + "You created a new class \""+ viewClass.getName() + + "\" in the view.\n" + + "This is not supported, because it is not " + + "known \nwhere to put the class in the original " + + "model.\n" + + "The inserted class will be ignored."); + return; + + } + + Class modelClass = (Class) xmiModelDict.get(classXmiId); + Package parentPackage = (Package) modelClass.getOwner(); + + // destroy all generalizations and associations in model, + // if both ends are present in view and association is no more + // present in view + + for (Relationship rel : modelClass.getRelationships()) { + if (rel instanceof Association) { + String modelRelationXmiID = this.modelXmiDict.get(rel); + if (modelRelationXmiID != null && ! this.xmiViewDict.containsKey(modelRelationXmiID)) { + rel.destroy(); + } + } + } + + // now, copy all changes from + // View to Model. + // Also, we have to make sure to delete Attributes/methods in + // the model if they were deleted in the code. + + List relList = new Vector(); + relList.addAll(viewClass.getRelationships()); + System.out.println(viewClass.getRelationships()); + System.out.println(viewClass.getSourceDirectedRelationships()); + + for (Relationship rel : relList) { + if (rel instanceof Association) { + Association assoc = (Association) rel; + + EList elList = rel.getRelatedElements(); + + Type connectedElement = (Type) elList.get(0); + + Property end1 = (Property) rel.getOwnedElements().get(0); + Property end2 = (Property) (rel.getOwnedElements().size() > 1 ? rel.getOwnedElements().get(1) : end1); + + Type secondElement = (Type) connectedElement; + if (elList.size() > 1) { + secondElement = (Type) elList.get(1); + } + + // if source (first) element is not current class, + // switch first and second element + // to be sure element to be connected by this class is second. + if (! (connectedElement == viewClass)) { + Type tmpElement = secondElement; + secondElement = connectedElement; + connectedElement = tmpElement; + + Property tmpProp = end1; + end1=end2; + end2=tmpProp; + } + + String secondElXmiID = this.viewXmiDict.get(secondElement); + // continue if connected element is not present in model + // -> this relationship can not be handled! + if (! this.xmiModelDict.containsKey(secondElXmiID)) { + continue; + } + + Type connectedElementInModel = (Type) this.xmiModelDict.get(secondElXmiID); + + if (rel.getOwnedElements().size() == 0) { + continue; + } + + // get old association, if possible + Relationship modelRelationship = null; + if (this.xmiModelDict.containsKey(this.viewXmiDict.get(rel))) { + modelRelationship = (Relationship) this.xmiModelDict.get(this.viewXmiDict.get(rel)); + } + + + boolean changed = true; + if (modelRelationship != null) { + changed = false; + Property modelEnd2 = (Property) modelRelationship.getOwnedElements().get(0); + Property modelEnd1 = (Property) (modelRelationship.getOwnedElements().size() > 1 ? modelRelationship.getOwnedElements().get(1) : modelEnd2); + + // update classes that take part in this association + modelEnd1.setType(modelClass); + modelEnd2.setType(connectedElementInModel); + + // look if anything changed in association; if yes, move view association + // to model + if ( modelEnd1.isNavigable() != end1.isNavigable() + || modelEnd1.isNavigable() != end1.isNavigable() + || modelEnd2.isNavigable() != end2.isNavigable() + || ! modelEnd1.getAggregation().equals(end1.getAggregation()) + || ! modelEnd2.getAggregation().equals(end2.getAggregation()) + || ! modelEnd1.getName().equals(end1.getName()) + || ! modelEnd2.getName().equals(end2.getName()) + || modelEnd1.getLower() != end1.getLower() + || modelEnd2.getLower() != end2.getLower() + || modelEnd1.getUpper() != end1.getUpper() + || modelEnd2.getUpper() != end2.getUpper() + || ! this.modelXmiDict.get(modelEnd1.getType()).equals(this.viewXmiDict.get(end1.getType())) + || ! this.modelXmiDict.get(modelEnd2.getType()).equals(this.viewXmiDict.get(end2.getType()))) + changed = true; + } + + if (changed) { + assoc.setPackage(parentPackage); + + end1.setType(modelClass); + end2.setType(connectedElementInModel); + //modelClass.createAssociation(end1.isNavigable(), end1.getAggregation(), end1.getName(), end1.getLower(), end1.getUpper(), connectedElementInModel, end2.isNavigable(), end2.getAggregation(), end2.getName(), end2.getLower(), end2.getUpper()); + + if (modelRelationship != null) + modelRelationship.destroy(); + } + } + } + + + // Directed Associations are hidden in attributes + propertyLoop: + for (Property att : viewClass.getAllAttributes()) { + if (att.getAssociation() != null) { + Association as = att.getAssociation(); + String asXmiId = this.viewXmiDict.get(as); + Type modelType = null; + String typeXmiId = this.viewXmiDict.get(att.getType()); + if (this.xmiModelDict.containsKey(typeXmiId)) + modelType = (Type) this.xmiModelDict.get(typeXmiId); + else + continue propertyLoop; + + Property modelProp = null; + + + // try to find model property -> property with same association + for (Property prop : modelClass.getAllAttributes()) { + if (prop.getAssociation()!= null && + this.xmiModelDict.get(prop.getAssociation()).equals(asXmiId)) + modelProp = prop; + } + + if (modelProp != null){ + // Property is present, check if everything is correct; + modelProp = (Property) this.xmiModelDict.get(asXmiId); + modelProp.setName(att.getName()); + } else { + //create this Property + modelProp = modelClass.createOwnedAttribute(att.getName(), modelType); + } + + as.setPackage(parentPackage); + //for (Element e : as.getOwnedElements(); + modelProp.setOwningAssociation(as); + modelProp.setType(modelType); + modelProp.setLower(att.getLower()); + modelProp.setUpper(att.getUpper()); + } + } + + + + // delete all generalizations in model not present in view + List tmpGens= new Vector(); + tmpGens.addAll(modelClass.getGeneralizations()); + for (Generalization general: tmpGens) { + String modelSupXmiID = this.modelXmiDict.get(general.getGeneral()); + Classifier viewSuperClass = (Classifier) this.xmiViewDict.get(modelSupXmiID); + + boolean generalIsPresentInView = false; + for (Generalization viewSuper : viewClass.getGeneralizations()) { + if (viewSuper.getGeneral() == viewSuperClass) { + generalIsPresentInView = true; + break; + } + } + if (! generalIsPresentInView) { + general.destroy(); + } + } + + // copy all generalizations of classes + for (Generalization general: viewClass.getGeneralizations()) { + String superClassXmiID = viewXmiDict.get(general.getGeneral()); + Classifier modelSuperClass = (Classifier) xmiModelDict.get(superClassXmiID); + + boolean generalIsPresentInModel = false; + for (Generalization modelSuper : modelClass.getGeneralizations()) { + if (modelSuper.getGeneral() == modelSuperClass) { + generalIsPresentInModel = true; + break; + } + } + + if (! xmiViewDict.containsKey(superClassXmiID)) + continue; + + if (! generalIsPresentInModel) { + modelClass.createGeneralization(modelSuperClass); + } + } + + } + + /** + * Saves the edited model .uml file + * @return + */ + private boolean saveModel() { + /*try { + this.modelResource[0].save(null); + EclipseHelperMethods.updateFile(pathToModel, project); + return true; + } catch (IOException e) { + MessageDialog.openError(null, "Error saving model", + "The model cannot be saved. Reason:\n" + e.getMessage()); + return false; + }*/ + return true; + } + + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + // Auto-generated method stub + } + + public void run(IAction action) { + this.synchronizeGlobalModel(this.pathToView); + + } + + public void selectionChanged(IAction action, ISelection selection) { + // save selected uml view + if (selection instanceof TreeSelection) { + TreeSelection ts = (TreeSelection) selection; + if (ts.getFirstElement() instanceof org.eclipse.core.internal.resources.File) { + org.eclipse.core.internal.resources.File selectedFile = (org.eclipse.core.internal.resources.File) ts.getFirstElement(); + this.pathToView = selectedFile.getLocation().toOSString(); + this.project = selectedFile.getProject(); + } + + } + } +} diff --git a/pyUml/src/pyUML/views/SynchronizeViews.java b/pyUml/src/pyUML/views/SynchronizeViews.java new file mode 100755 index 0000000..bfa6e65 --- /dev/null +++ b/pyUml/src/pyUML/views/SynchronizeViews.java @@ -0,0 +1,384 @@ +package pyUML.views; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.uml2.uml.Association; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Model; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.ParameterableElement; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Relationship; +import org.eclipse.uml2.uml.Type; +import org.eclipse.uml2.uml.resource.UMLResource; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.UMLToolsHelperMethods; + + + +/** + * This is an action class where the global UML model + * is to be updated by a view. + * Classes cannot be copied, because this would destroy all + * model relationships of the class. + * New classes in a view are ignored, because it is not known where + * they are to be inserted in the model. + * + * At the moment, class attributes and methods are *not* synchronized + * with the mail model. + * + */ +public class SynchronizeViews implements IObjectActionDelegate{ + private String pathToModel;; + private String pathToView; + //private Model model; + private Model viewModel; + private Resource[] modelResource = {null}; + private Map xmiModelDict; + private Map modelXmiDict; + private Map xmiViewDict; + private Map viewXmiDict; + private IProject project; + + + public static void synchronizeGlobalModel(String pathToView, IProject project) { + SynchronizeViews sv = new SynchronizeViews(); + sv.project = project; + sv.synchronizeGlobalModel(pathToView); + } + + /** + * Updates the global model by changes made by the given view. + * Class deletions are removed from the view, not from the model. + * + * New classes/packages are ignored, because it is not known + * where they should be inserted. + * + * Other changes are updated in the global model. + * + * @param pathToModel + * @param pathToView + * @return + */ + public boolean synchronizeGlobalModel(String pathToView) { + String pathToModel = this.project.getLocation() + .append(GlobalConstants.getPyUmlDir()) + .append(this.project.getName()+".uml").toOSString(); + + //init models + this.pathToModel = pathToModel; + this.pathToView = pathToView; + initModels(); + + // synchronize by all child classes + try{ + List elementCopy = new Vector(); + elementCopy.addAll(this.viewModel.getOwnedElements()); + for (Element child : elementCopy) { + if (child instanceof Class) + synchronizeClass((Class)child); + } + } catch (Throwable t) { + t.printStackTrace(); + } + + // save model + return saveModel(); + } + + /** + * initializes the Model of the view and the main model + */ + private void initModels() { + // save all open editors + IWorkbenchPage page = + PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + page.saveAllEditors(false); + + // initialize XMI dictionaries as empty -> they are filled, if a + // model already exists + this.modelXmiDict = new HashMap(); + this.xmiModelDict = new HashMap(); + this.viewXmiDict = new HashMap(); + this.xmiViewDict = new HashMap(); + + // load view and model + // this.model = + initModel(this.pathToModel, this.xmiModelDict, this.modelXmiDict, this.modelResource); + this.viewModel = initModel(this.pathToView, this.xmiViewDict, this.viewXmiDict, null); + } + + /** + * loads a .uml model (main model or view) + * and fills the given dictionaries + * @param pathToModel + * @param xmiModelDict + * @param modelXmiDict + * @param modelResource + * @return + */ + private Model initModel(String pathToModel, Map xmiModelDict, + Map modelXmiDict, Resource[] modelResource) { + + // look for model file + Model model; + Resource resource; + File modelFile = new File(pathToModel); + if (! modelFile.exists()) { + MessageDialog.openError(null, "Error synchronizing Model by View", + "Model can not be found: "+pathToModel); + return null; + } + // read Model + EObject diagramRoot = UMLToolsHelperMethods.loadUMLDiagram(pathToModel); + model = (Model) diagramRoot; + resource = model.eResource(); + + // get model -> xmi-id dictionary + UMLResource r = (UMLResource) resource; + modelXmiDict.putAll(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); + } + if (modelResource != null) + modelResource[0] = resource; + return model; + } + + + /** + * Synchronizes a model class by a view class + * @param viewClass + */ + private void synchronizeClass(Class viewClass) { + String classXmiId = this.viewXmiDict.get(viewClass); + if (! xmiModelDict.containsKey(classXmiId)) { + MessageDialog.openWarning(null, "Error saving View", + "You created a new class \""+ viewClass.getName() + + "\" in the view.\n" + + "This is not supported, because it is not " + + "known \nwhere to put the class in the original " + + "model.\n" + + "The inserted class will be ignored."); + return; + + } + + Class modelClass = (Class) xmiModelDict.get(classXmiId); + Package parentPackage = (Package) modelClass.getOwner(); + + // destroy all generalizations and associations in model, + // if both ends are present in view and association is no more + // present in view + + for (Relationship rel : modelClass.getRelationships()) { + if (rel instanceof Association) { + String modelRelationXmiID = this.modelXmiDict.get(rel); + if (modelRelationXmiID != null && ! this.xmiViewDict.containsKey(modelRelationXmiID)) { + rel.destroy(); + } + } + } + + // now, copy all associations / attributes/methods from + // View to Model. + // We cannot just copy the whole class, because this would + // destroy the associations/generalizations etc. + // Also, we have to make sure to delete Attributes/methods in + // the model if they were deleted in the code. + + for (Relationship rel : viewClass.getRelationships()) { + if (rel instanceof Association) { + Association assoc = (Association) rel; + + EList elList = rel.getRelatedElements(); + + Type connectedElement = (Type) elList.get(0); + + Property end1 = (Property) rel.getOwnedElements().get(0); + Property end2 = (Property) (rel.getOwnedElements().size() > 1 ? rel.getOwnedElements().get(1) : end1); + + Type secondElement = (Type) connectedElement; + if (elList.size() > 1) { + secondElement = (Type) elList.get(1); + } + + // if source (first) element is not current class, + // switch first and second element + // to be sure element to be connected by this class is second. + if (! (connectedElement == viewClass)) { + Type tmpElement = secondElement; + secondElement = connectedElement; + connectedElement = tmpElement; + + Property tmpProp = end1; + end1=end2; + end2=tmpProp; + } + + String secondElXmiID = this.viewXmiDict.get(secondElement); + // continue if connected element is not present in model + // -> this relationship can not be handled! + if (! this.xmiModelDict.containsKey(secondElXmiID)) { + continue; + } + + Type connectedElementInModel = (Type) this.xmiModelDict.get(secondElXmiID); + + if (rel.getOwnedElements().size() == 0) { + continue; + } + + // get old association, if possible + Relationship modelRelationship = null; + if (this.xmiModelDict.containsKey(this.viewXmiDict.get(rel))) { + modelRelationship = (Relationship) this.xmiModelDict.get(this.viewXmiDict.get(rel)); + } + + + boolean changed = true; + if (modelRelationship != null) { + changed = false; + Property modelEnd2 = (Property) modelRelationship.getOwnedElements().get(0); + Property modelEnd1 = (Property) (modelRelationship.getOwnedElements().size() > 1 ? modelRelationship.getOwnedElements().get(1) : modelEnd2); + + // update classes that take part in this association + modelEnd1.setType(modelClass); + modelEnd2.setType(connectedElementInModel); + + // look if anything changed in association; if yes, move view association + // to model + if ( modelEnd1.isNavigable() != end1.isNavigable() + || modelEnd1.isNavigable() != end1.isNavigable() + || modelEnd2.isNavigable() != end2.isNavigable() + || ! modelEnd1.getAggregation().equals(end1.getAggregation()) + || ! modelEnd2.getAggregation().equals(end2.getAggregation()) + || ! modelEnd1.getName().equals(end1.getName()) + || ! modelEnd2.getName().equals(end2.getName()) + || modelEnd1.getLower() != end1.getLower() + || modelEnd2.getLower() != end2.getLower() + || modelEnd1.getUpper() != end1.getUpper() + || modelEnd2.getUpper() != end2.getUpper() + || ! this.modelXmiDict.get(modelEnd1.getType()).equals(this.viewXmiDict.get(end1.getType())) + || ! this.modelXmiDict.get(modelEnd2.getType()).equals(this.viewXmiDict.get(end2.getType()))) + changed = true; + } + + if (changed) { + assoc.setPackage(parentPackage); + + end1.setType(modelClass); + end2.setType(connectedElementInModel); + //modelClass.createAssociation(end1.isNavigable(), end1.getAggregation(), end1.getName(), end1.getLower(), end1.getUpper(), connectedElementInModel, end2.isNavigable(), end2.getAggregation(), end2.getName(), end2.getLower(), end2.getUpper()); + + if (modelRelationship != null) + modelRelationship.destroy(); + } + } + } + + // delete all generalizations in model not present in view + List tmpGens= new Vector(); + tmpGens.addAll(modelClass.getGeneralizations()); + for (Generalization general: tmpGens) { + String modelSupXmiID = this.modelXmiDict.get(general.getGeneral()); + Classifier viewSuperClass = (Classifier) this.xmiViewDict.get(modelSupXmiID); + + boolean generalIsPresentInView = false; + for (Generalization viewSuper : viewClass.getGeneralizations()) { + if (viewSuper.getGeneral() == viewSuperClass) { + generalIsPresentInView = true; + break; + } + } + if (! generalIsPresentInView) { + general.destroy(); + } + } + + // copy all generalizations of classes + for (Generalization general: viewClass.getGeneralizations()) { + String superClassXmiID = viewXmiDict.get(general.getGeneral()); + Classifier modelSuperClass = (Classifier) xmiModelDict.get(superClassXmiID); + + boolean generalIsPresentInModel = false; + for (Generalization modelSuper : modelClass.getGeneralizations()) { + if (modelSuper.getGeneral() == modelSuperClass) { + generalIsPresentInModel = true; + break; + } + } + + if (! xmiViewDict.containsKey(superClassXmiID)) + continue; + + if (! generalIsPresentInModel) { + modelClass.createGeneralization(modelSuperClass); + } + } + + } + + /** + * Saves the edited model .uml file + * @return + */ + private boolean saveModel() { + try { + this.modelResource[0].save(null); + EclipseHelperMethods.updateFile(pathToModel, project); + return true; + } catch (IOException e) { + MessageDialog.openError(null, "Error saving model", + "The model cannot be saved. Reason:\n" + e.getMessage()); + return false; + } + } + + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + // Auto-generated method stub + } + + public void run(IAction action) { + this.synchronizeGlobalModel(this.pathToView); + + } + + public void selectionChanged(IAction action, ISelection selection) { + // save selected uml view + if (selection instanceof TreeSelection) { + TreeSelection ts = (TreeSelection) selection; + if (ts.getFirstElement() instanceof org.eclipse.core.internal.resources.File) { + org.eclipse.core.internal.resources.File selectedFile = (org.eclipse.core.internal.resources.File) ts.getFirstElement(); + this.pathToView = selectedFile.getLocation().toOSString(); + this.project = selectedFile.getProject(); + } + + } + } +} diff --git a/pyUml/trash/CodeFromModelCreator.java b/pyUml/trash/CodeFromModelCreator.java new file mode 100755 index 0000000..ad7a1cf --- /dev/null +++ b/pyUml/trash/CodeFromModelCreator.java @@ -0,0 +1,133 @@ +package parser; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Element; +import org.eclipse.uml2.uml.Package; + +import parser.pythonTree.PythonTreeClass; +import parser.pythonTree.PythonTreeNode; +import parser.pythonTree.PythonTreePackage; + +public class CodeFromModelCreator { + /** + * synchronizes the code with the model. + * if any python file is changed, false is returned + * to rebuild the tree and start from beginning + * + * @param pythonNode + * @param umlElement + * @param xmiModelDict + * @return + */ + public static boolean synchronizeCodeFromModel(PythonTreeNode pythonNode, Element umlElement, Map xmiModelDict) { + for (Element modelElement:umlElement.getOwnedElements()) { + if (modelElement instanceof Package) { + Package modelPack = (Package) modelElement; + PythonTreePackage pyPack = (PythonTreePackage) pythonNode; + if (xmiModelDict.containsKey(modelPack)) { + String xmi_id = xmiModelDict.get(modelPack); + if (pythonNode.getRoot().getXmiPackDict().containsKey(xmi_id)) { + PythonTreeNode node = pythonNode.getRoot().getXmiPackDict().get(xmi_id); + if (pyPack.getChildPackages().contains(node)) { + boolean startNew = synchronizeCodeFromModel(node, modelElement, xmiModelDict); + if (startNew) return true; + PythonTreePackage subPack = (PythonTreePackage) node; + // TODO: umhaengen des Pakets an die richtige Stelle + // im FS und im Python Tree + } + } else { + // look for python node with same name + boolean packageFound = false; + for (PythonTreePackage pySubPack : pyPack.getChildPackages()) { + if (pySubPack.getName().equals(modelPack.getName())){ + // write xmi_id to code (only needed once) + pySubPack.writeXmiID(xmi_id); + packageFound=true; + break; + } + } + // if this package was not found, create it (recursively)! + if (! packageFound) { + // create package + IPath newPackPath = pyPack.getPackageDir().append(modelPack.getName()); + File newPackDir = new File(newPackPath.toOSString()); + newPackDir.mkdir(); + File initPy = new File(newPackPath.append("__init__.py").toOSString()); + try{ + initPy.createNewFile(); + } + catch (IOException e) { + MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath()); + } + PythonTreePackage newPyPack = new PythonTreePackage(newPackPath, pyPack); + newPyPack.writeXmiID(xmi_id); + boolean startNew = synchronizeCodeFromModel(newPyPack, modelPack, xmiModelDict); + if (startNew) return true; + } + } + } else { + MessageDialog.openError(null,"Error synchronizing","There was an inconsistency in the Python Package Tree"); + return true; + } + } + + else if (modelElement instanceof Class) { + Class modelClass = (Class) modelElement; + PythonTreePackage pyPack = (PythonTreePackage) pythonNode; + if (xmiModelDict.containsKey(modelClass)) { + String xmi_id = xmiModelDict.get(modelClass); + if (pythonNode.getRoot().getXmiClassDict().containsKey(xmi_id)) { + PythonTreeNode node = pythonNode.getRoot().getXmiClassDict().get(xmi_id); + if (pyPack.getChildClasses().contains(node)) { + boolean startNew = synchronizeCodeFromModel(node, modelElement, xmiModelDict); + if (startNew) return true; + PythonTreeClass subPack = (PythonTreeClass) node; + // TODO: umhaengen der Klasse an die richtige Stelle + } + } else { + // look for python child class with same name + // and write the right xmi_id + boolean classFound = false; + for (PythonTreeClass pySubClass : pyPack.getChildClasses()) { + if (pySubClass.getName().equals(modelClass.getName())){ + // write xmi_id to code (only needed once) + pySubClass.writeXmiID(xmi_id); + classFound=true; + return false; + } + } + // if this class was not found, create it (recursively)! + /* if (! classFound) { + // create package + IPath newPackPath = treePack.getPackageDir().append(modelPack.getName()); + File newPackDir = new File(newPackPath.toOSString()); + newPackDir.mkdir(); + File initPy = new File(newPackPath.append("__init__.py").toOSString()); + try{ + initPy.createNewFile(); + } + catch (IOException e) { + MessageDialog.openError(null, "IOException", "Error writing to file "+ initPy.getPath()); + } + PythonTreePackage newPyPack = new PythonTreePackage(newPackPath, treePack); + newPyPack.writeXmiID(xmi_id); + generateCodeFromModel(newPyPack, modelPack, xmiModelDict); + } + */ + } + }else { + MessageDialog.openError(null,"Error synchronizing","There was an inconsistency in the Python Package Tree"); + return true; + } + } + } + return false; + } +} diff --git a/pyUml/trash/Py2UMLCreator.java b/pyUml/trash/Py2UMLCreator.java new file mode 100755 index 0000000..ef69077 --- /dev/null +++ b/pyUml/trash/Py2UMLCreator.java @@ -0,0 +1,211 @@ +package synchronize; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Vector; + +import org.eclipse.emf.common.util.BasicEList; +import org.eclipse.emf.common.util.EList; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.uml2.uml.Class; +import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.Operation; +import org.eclipse.uml2.uml.Package; +import org.eclipse.uml2.uml.Property; +import org.eclipse.uml2.uml.Type; +import org.python.pydev.parser.jython.SimpleNode; +import org.python.pydev.parser.jython.ast.Assign; +import org.python.pydev.parser.jython.ast.Attribute; +import org.python.pydev.parser.jython.ast.Call; +import org.python.pydev.parser.jython.ast.ClassDef; +import org.python.pydev.parser.jython.ast.FunctionDef; +import org.python.pydev.parser.jython.ast.Import; +import org.python.pydev.parser.jython.ast.ImportFrom; +import org.python.pydev.parser.jython.ast.Module; +import org.python.pydev.parser.jython.ast.Name; +import org.python.pydev.parser.jython.ast.NameTok; +import org.python.pydev.parser.jython.ast.Num; +import org.python.pydev.parser.jython.ast.Str; +import org.python.pydev.parser.jython.ast.exprType; +import org.python.pydev.parser.jython.ast.stmtType; + +import parser.ParseHelpers; + +public class Py2UMLCreator { + + // dictionary of all created classes for later access + private Dictionary classDict; + + // list of generalizations to add to model + // after adding all classes + private List> generalizations; + + + public Py2UMLCreator() { + this.classDict = new Hashtable(); + this.generalizations = new Vector>(); + } + + public void createModelFromAST(SimpleNode root, Package rootPack) { + parsePackage(root, rootPack); + } + + private void parsePackage(SimpleNode node, Package pack) { + if (node instanceof Module) { + Module pyModule = (Module) node; + stmtType[] statements = pyModule.body; + for (int i = 0; i < statements.length; i++) { + parsePackage(statements[i], pack); + if (statements[i] instanceof ClassDef) { + ClassDef pyClass = (ClassDef) statements[i]; + parseClass(pyClass, pack); + } + if (statements[i] instanceof ImportFrom) { + ImportFrom importFrom = (ImportFrom) statements[i]; + //System.out.println("---import---"); + //System.out.println(((NameTok)importFrom.names[0].name).id); + } + if (statements[i] instanceof Import) { + Import importFrom = (Import) statements[i]; + //System.out.println("---import---"); + //System.out.println(((NameTok)importFrom.names[0].name).id); + } + + + } + } + } + + /** + * Add generalizations to model + */ + public void createGeneralizations() { + System.out.println("creating Gens"); + System.out.println(this.generalizations); + for (Tuple tup : this.generalizations) { + Class subClass = tup.a; + String superClassStr = tup.b; + System.out.println("create gen for " + subClass.getName()); + System.out.println(superClassStr); + if ((classDict.get(superClassStr)) == null) { + System.out.println("...failed"); + continue; + } + Class superclass = classDict.get(superClassStr); + Generalization gen = subClass.createGeneralization(superclass); + } + } + + // get basic class information + + private void parseClass(ClassDef pyClass, Package pack) { + String className=((NameTok) pyClass.name).id; + Class cl = pack.createOwnedClass(className, false); + if (classDict.get(className) != null) + MessageDialog.openError(null, "Duplicate Class detected", + "The class '"+className+ "' exists more than 1 time!"); + this.classDict.put(className, cl); + + System.out.println("class "+className); + exprType[] baseClasses=pyClass.bases; + for (exprType baseClass : baseClasses) { + if (baseClass instanceof Name) { + String baseName = ((Name)baseClass).id; + System.out.println("found base class " + baseName); + // add generalization + generalizations.add(new Tuple(cl, baseName)); + }else if (baseClass instanceof Attribute){ + Attribute att = (Attribute) baseClass; + String baseName=att.attr.toString(); + System.out.println("found base class " + baseName); + // add generalization + generalizations.add(new Tuple(cl, baseName)); + } + } + + // parse class body + + stmtType[] statements = pyClass.body; + parseBody: for (int i = 0; i < statements.length; i++) { + System.out.println("stmt at line " + statements[i].beginLine); + System.out.println(statements[i].getClass().getName()); + + // look for static attributes (=assertions inside class body) + if (statements[i] instanceof Assign) { + Assign assign = (Assign) statements[i]; + exprType left = assign.targets[0]; + exprType right = assign.value; + + String assignTo = ((Name)left).id; + String assignVal = ""; + + assignVal = ParseHelpers.getStringOfExpr(right); + System.out.println("attrs:"); + System.out.println(right.getClass().getName()); + System.out.println(assignVal); + if (right instanceof Call) { + Call call = (Call) right; + String callName =(((Name)call.func).id); + if (callName.equals("staticmethod")) + continue parseBody; + } + Property classAttr = cl.createOwnedAttribute(assignTo, null); + classAttr.setIsStatic(true); + classAttr.setDefault(assignVal); + } + // get method definitions + if (statements[i] instanceof FunctionDef) { + FunctionDef func = (FunctionDef) statements[i]; + String funcName=((NameTok)func.name).id; + exprType[] argList = func.args.args; + EList paramNameList = new BasicEList(); + EList paramTypeList = new BasicEList(); + + // get arguments + for (exprType arg : argList) { + Name n = (Name) arg; + paramNameList.add(n.id); + paramTypeList.add(null); + System.out.println(n.id); + } + // create model element + Operation op = cl.createOwnedOperation(funcName, paramNameList, null); + // set static method (if so) + if (argList.length == 0 || (! ((Name) argList[0]).id.equals("self"))) + op.setIsStatic(true); + + // get object variables, if this is the __init__ method + if (funcName.equals("__init__")){ + stmtType[] initStmts = func.body; + for (stmtType initStmt: initStmts) { + if (initStmt instanceof Assign) { + Assign assign = (Assign) initStmt; + exprType left = assign.targets[0]; + exprType right = assign.value; + if (left instanceof Attribute) { + Attribute attrLeft = (Attribute) left; + String attrName = ((NameTok)attrLeft.attr).id; + String attrVal = ParseHelpers.getStringOfExpr(right); + Property att = cl.createOwnedAttribute(attrName, null); + att.setDefault(attrVal); + } + } + } + } + } + } + } + + class Tuple{ + A a; + B b; + public Tuple(A a, B b) { + this.a=a; + this.b=b; + } + public String toString() { + return "(<"+this.a+">,<"+this.b+">)"; + } + } +} diff --git a/pyUml/trash/ViewChangeListener2.java b/pyUml/trash/ViewChangeListener2.java new file mode 100755 index 0000000..9fb2f36 --- /dev/null +++ b/pyUml/trash/ViewChangeListener2.java @@ -0,0 +1,134 @@ +package pyUML.listeners; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.PlatformUI; + +import pyUML.backend.EclipseHelperMethods; +import pyUML.backend.GlobalConstants; +import pyUML.backend.UMLToolsHelperMethods; +import pyUML.views.SynchronizeModelByView; + + + +/** + * This listener synchronizes the global model and + * all other pyUML.views whenever a view is saved + */ +public abstract class ViewChangeListener2 implements IPropertyListener { + private IProject project; + private static boolean listenerEnabled = true; + + + public ViewChangeListener2(IProject project) { + super(); + this.project = project; + } + + /** + * Enables or disables all Listeners; this can be + * useful to avoid circular listener calls + * (model, view...) on a document change + * @param enabled + */ + public static void setListenersEnabled(boolean enabled) { + listenerEnabled = enabled; + } + + /** + @return true, if the View listeners are currently enabled, false otehrwise. + */ + public static boolean getListenersEnabled() { + return listenerEnabled; + } + + + + public void propertyChanged(Object source, int propId) { + if (! ViewChangeListener2.listenerEnabled) + return; + + if (source instanceof DiagramEditor) { + // Wait until the Model is saved in file system + try { + Thread.sleep(1000); + }catch (Exception e) {} + + DiagramEditor umlEditor = (DiagramEditor) source; + if (! umlEditor.isDirty()) { + try { + umlEditor.getDiagram().eResource().save(null); + } catch (Exception e){e.printStackTrace();} + + ViewChangeListener2.listenerEnabled = false; + ModelChangeListener.setEnabled(false); + + // editor was just saved, otherwise it would be dirty. + // -> synchronize model every time the view is saved + + + String openEditorName=umlEditor.getTitle(); + String viewPath = this.project.getLocation() + .append(GlobalConstants.getPyUmlDir()) + .append(openEditorName.replace(GlobalConstants.getDiagramExtension(), "") + + GlobalConstants.getViewUmlExtension()).toOSString(); + SynchronizeModelByView.synchronizeGlobalModel(viewPath, this.project); + + + + + IFile globalModelDiagramFile = this.project.getWorkspace() + .getRoot().getFile(this.project.getFullPath() + .append(GlobalConstants.getPyUmlDir()) + .append(project.getName()+GlobalConstants + .getDiagramExtension())); + + // close all sub-package pyUML.views of global model diagram + for ( org.eclipse.ui.IEditorReference editor : + EclipseHelperMethods.lookForOpenEditorByName(project.getName()+"::.*")) { + PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().closeEditor(editor.getEditor(true), true); + } + + // after creating model, be sure the diagram view is reloaded + /*boolean diagramOpened = null != EclipseHelperMethods + .lookForOpenEditorByName(project.getName()+GlobalConstants.getDiagramExtension()); + if (diagramOpened) { + // set focus to updated diagram only if no diagram is currently active + boolean keepFocus = false; + try { + keepFocus = PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getActivePage().getActiveEditor().getTitle() + .matches(".*"+GlobalConstants.getDiagramExtension()); + } catch (Exception e) { + e.printStackTrace(); + } + IEditorPart newPage = UMLToolsHelperMethods.refreshDiagramEditor(project, globalModelDiagramFile, keepFocus); + if (newPage != null) + newPage.addPropertyListener(new ViewChangeListener2(this.project)); + }*/ + + UMLToolsHelperMethods.updateModelAndViewPages(this.project, openEditorName.replace(GlobalConstants.getDiagramExtension(), ""), false); + // enable Listeners only after 4 seconds, when all diagrams are reloaded + Thread t = new Thread( + new Runnable() { + public void run() { + try { + Thread.sleep(4000); + System.out.println("finish"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ViewChangeListener2.listenerEnabled = true; + ModelChangeListener.setEnabled(true); + System.out.println(ViewChangeListener2.listenerEnabled); + } + }); + t.start(); + } + } + } +} diff --git a/pyUml/usedDocuments/UML.ecore b/pyUml/usedDocuments/UML.ecore new file mode 100755 index 0000000..a31a993 --- /dev/null +++ b/pyUml/usedDocuments/UML.ecore @@ -0,0 +1,15558 @@ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + + + + +
+ + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + + + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + + + + + + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + + + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + + +
+ + + + + + + + +
+ + + + + +
+ + + + + + + +
+ + + + + +
+ + + + + + +
+ + + + + +
+ + + +
+ + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + + + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + +
+ + + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + + + +
+ + + + +
+ + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + +
+ + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + +
+ + + + + + + + + +
+ + + + diff --git a/pyUml/usedDocuments/UML.uml b/pyUml/usedDocuments/UML.uml new file mode 100755 index 0000000..65030d1 --- /dev/null +++ b/pyUml/usedDocuments/UML.uml @@ -0,0 +1,1947 @@ + + + + + + + + + + + + + + + + + + + + + + Destroys this element by removing all cross references to/from it and removing it from its containing resource or object. + + + + + Determines whether this element has the specified keyword. + + + + + The keyword in question. + + + + + + Retrieves the keywords for this element. + + + + + + + + + Adds the specified keyword to this element. + + + + + The keyword to add. + + + + + + Removes the specified keyword from this element. + + + + + The keyword to remove. + + + + + + Retrieves the nearest package that owns (either directly or indirectly) this element, or the element itself (if it is a package). + + + + + + + + + Retrieves the model that owns (either directly or indirectly) this element. + + + + + + + + + Determines whether the specified stereotype is applicable to this element. + + + + + The stereotype in question. + + + + + + Determines whether the specified stereotype is required for this element. + + + + + The stereotype in question. + + + + + + Determines whether the specified stereotype is applied to this element. + + + + + The stereotype in question. + + + + + + Applies the specified stereotype to this element. + + + + + + + The stereotype to apply. + + + + + + Unapplies the specified stereotype from this element. + + + + + + + The stereotype to unapply. + + + + + + Retrieves the stereotypes that are applicable to this element, including those that are required and/or may already be applied. + + + + + + + + + Retrieves the stereotype with the specified qualified name that is applicable to this element, or null if no such stereotype is applicable. + + + + + + + + The qualified name of the applicable stereotype to retrieve. + + + + + + Retrieves the stereotype applications for this element. + + + + + + + + + + Retrieves the application of the specified stereotype for this element, or null if no such stereotype application exists. + + + + + + + + + The stereotype for which to retrieve an application. + + + + + + Retrieves the stereotypes that are required for this element. + + + + + + + + + Retrieves the stereotype with the specified qualified name that is required for this element, or null if no such stereotype is required. + + + + + + + + The qualified name of the required stereotype to retrieve. + + + + + + Retrieves the stereotypes that are applied to this element. + + + + + + + + + Retrieves the stereotype with the specified qualified name that is applied to this element, or null if no such stereotype is applied. + + + + + + + + The qualified name of the applied stereotype to retrieve. + + + + + + Retrieves the substereotypes of the specified stereotype that are applied to this element. + + + + + + + + The superstereotype of the applied substereotypes to retrieve. + + + + + + Retrieves the substereotype of the specified stereotype with the specified qualified name that is applied to this element, or null if no such stereotype is applied. + + + + + + + + The superstereotype of the applied substereotype to retrieve. + + + + + The qualified name of the applied substereotype to retrieve. + + + + + + Determines whether this element has a (non-default) value for the property with the specified name in the specified stereotype. + + + + + The stereotype for which to test the property. + + + + + The name of the property in question. + + + + + + Retrieves the value of the property with the specified name in the specified stereotype for this element. + + + + + + + + + The stereotype for which to retrieve the value. + + + + + The name of the property whose value to retrieve. + + + + + + Sets the value of the property with the specified name in the specified stereotype for this element. + + + + The stereotype for which to set the value. + + + + + The name of the property whose value to set. + + + + + The new value for the property. + + + + + + + Creates an annotation with the specified source and this element as its model element. + + + + + + + The source for the new annotation. + + + + + + Retrieves the relationships in which this element is involved. + + + + + + + + + Retrieves the relationships of the specified type in which this element is involved. + + + + + + + + The (meta)type of the relationships to retrieve. + + + + + + + Retrieves the directed relationships for which this element is a source. + + + + + + + + + Retrieves the directed relationships of the specified type for which this element is a source. + + + + + + + + The (meta)type of the directed relationships to retrieve. + + + + + + + Retrieves the directed relationships for which this element is a target. + + + + + + + + + Retrieves the directed relationships of the specified type for which this element is a target. + + + + + + + + The (meta)type of the directed relationships to retrieve. + + + + + + + + + + + + + + + Creates an operation with the specified name, parameter names, parameter types, and return type (or null) as an owned operation of this class. + + + + + The name for the new operation, or null. + + + + + + + The parameter names for the new operation, or null. + + + + + + + The parameter types for the new operation, or null. + + + + + + + The return type for the new operation, or null. + + + + + + + + Determines whether this class is a metaclass. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sets the navigability of this property as indicated. + + + + The new navigability. + + + + + + Retrieves the other end of the (binary) association in which this property is a member end. + + + + + + + + + Sets the default value for this property to the specified Boolean value. + + + + The new default value. + + + + + + Sets the default value for this property to the specified integer value. + + + + The new default value. + + + + + + Sets the default value for this property to the specified string value. + + + + The new default value. + + + + + + Sets the default value for this property to the specified unlimited natural value. + + + + The new default value. + + + + + + Sets the default value for this property to the null value. + + + + + + + + + + + + + + + + + + + + Sets the default value for this parameter to the specified Boolean value. + + + + The new default value. + + + + + + Sets the default value for this parameter to the specified integer value. + + + + The new default value. + + + + + + Sets the default value for this parameter to the specified string value. + + + + The new default value. + + + + + + Sets the default value for this parameter to the specified unlimited natural value. + + + + The new default value. + + + + + + Sets the default value for this parameter to the null value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Retrieves the (only) return result parameter for this operation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Retrieves the interfaces on which this behaviored classifier has an interface realization dependency. + + + + + + + + + Retrieves all the interfaces on which this behaviored classifier or any of its parents has an interface realization dependency. + + + + + + + + + + + Retrieves the extension end that is typed by a stereotype (as opposed to a metaclass). + + + + + + + + + Retrieves the stereotype that extends a metaclass through this extension. + + + + + + + + + + + Creates a dependency between this named element and the specified supplier, owned by this named element's nearest package. + + + + + The supplier for the new dependency. + + + + + + Retrieves a localized label for this named element. + + + + + + + + + Retrieves a label for this named element, localized if indicated. + + + + + + + + Whether to localize the label. + + + + + + Creates a usage between this named element and the specified supplier, owned by this named element's nearest package. + + + + + The supplier for the new usage. + + + + + + + + Creates a(n) (binary) association between this type and the specified other type, with the specified navigabilities, aggregations, names, lower bounds, and upper bounds, and owned by this type's nearest package. + + + + + The navigability for the first end of the new association. + + + + + The aggregation for the first end of the new association. + + + + + The name for the first end of the new association. + + + + + The lower bound for the first end of the new association. + + + + + The upper bound for the first end of the new association. + + + + + The type for the first end of the new association. + + + + + The navigability for the second end of the new association. + + + + + The aggregation for the second end of the new association. + + + + + The name for the second end of the new association. + + + + + The lower bound for the second end of the new association. + + + + + The upper bound for the second end of the new association. + + + + + + Retrieves the associations in which this type is involved. + + + + + + + + + + + Creates an operation with the specified name, parameter names, parameter types, and return type (or null) as an owned operation of this interface. + + + + + The name for the new operation, or null. + + + + + + + The parameter names for the new operation, or null. + + + + + + + The parameter types for the new operation, or null. + + + + + + + The return type for the new operation, or null. + + + + + + + + Creates a property with the specified name, type, lower bound, and upper bound as an owned attribute of this interface. + + + + + The name for the new attribute, or null. + + + + + + + The type for the new attribute, or null. + + + + + + + The lower bound for the new attribute. + + + + + The upper bound for the new attribute. + + + + + + + + + Creates a(n) (abstract) class with the specified name as an owned type of this package. + + + + + The name for the new class, or null. + + + + + Whether the new class should be abstract. + + + + + + Creates a enumeration with the specified name as an owned type of this package. + + + + + The name for the new enumeration, or null. + + + + + + Creates a primitive type with the specified name as an owned type of this package. + + + + + The name for the new primitive type, or null. + + + + + + Creates an interface with the specified name as an owned type of this package. + + + + + The name for the new interface, or null. + + + + + + Determines whether the specified profile is applied to this package. + + + + + The profile in question. + + + + + + Applies the current definition of the specified profile to this package and automatically applies required stereotypes in the profile to elements within this package's namespace hieararchy. If a different definition is already applied, automatically migrates any associated stereotype values on a "best effort" basis (matching classifiers and structural features by name). + + + + + + + + + The profile to apply. + + + + + + Unapplies the specified profile from this package and automatically unapplies stereotypes in the profile from elements within this package's namespace hieararchy. + + + + + + + + + The profile to unapply. + + + + + + Retrieves the profiles that are applied to this package. + + + + + + + + + Retrieves all the profiles that are applied to this package, including profiles applied to its nesting package(s). + + + + + + + + + Retrieves the profile with the specified qualified name that is applied to this package, or null if no such profile is applied. + + + + + + + + The qualified name of the applied profile to retrieve. + + + + + + Retrieves the profile with the specified qualified name that is applied to this package or any of its nesting packages (if indicated), or null if no such profile is applied. + + + + + + + + The qualified name of the applied profile to retrieve. + + + + + Whether to look in nesting packages. + + + + + + Retrieves all the profile applications for this package, including profile applications for its nesting package(s). + + + + + + + + + Retrieves the application of the specified profile to this package, or null if no such profile is applied. + + + + + + + + The profile whose application to retrieve. + + + + + + Retrieves the application of the specified profile to this package or any of its nesting packages (if indicated), or null if no such profile is applied. + + + + + + + + The profile whose application to retrieve. + + + + + Whether to look in nesting packages. + + + + + + Determines whether this package is a model library. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Creates and returns an instance of (the Ecore representation of) the specified classifier defined in this profile. + + + + + + + The classifier of which to create an instance. + + + + + + Creates a(n) (abstract) stereotype with the specified name as an owned stereotype of this profile. + + + + + The name for the new stereotype, or null. + + + + + Whether the new stereotype should be abstract. + + + + + + Determines whether this profile is defined. + + + + + + Defines this profile by (re)creating Ecore representations of its current contents. + + + + + + + + + + Defines this profile by (re)creating Ecore representations of its current contents, using the specified options, diagnostics, and context. + + + + + + + The options to use. + + + + + The chain of diagnostics to which problems are to be appended. + + + + + + The cache of context-specific information. + + + + + + Retrieves the current definition (Ecore representation) of this profile. + + + + + + + + + + Retrieves the current definition (Ecore representation) of the specified named element in this profile. + + + + + + + + + The named element whose definition to retrieve. + + + + + + Retrieves the metaclasses referenced by this profile. + + + + + + + + + Retrieves the metamodels referenced by this profile. + + + + + + + + + Retrieves the extensions owned by this profile, excluding non-required extensions if indicated. + + + + + + + + Whether to retrieve only required extensions. + + + + + + + + Creates a(n) (required) extension of the specified metaclass with this stereotype. + + + + + The metaclass for the new extension. + + + + + Whether the new extension should be required. + + + + + + Retrieves the profile that owns this stereotype. + + + + + + + + + Retrieves the localized keyword for this stereotype. + + + + + + Retrieves the keyword for this stereotype, localized if indicated. + + + + + Whether to localize the keyword. + + + + + + Retrieves the metaclasses extended by this stereotype. + + + + + + + + + Retrieves all the metaclasses extended by this stereotype, including the metaclasses extended by its superstereotypes. + + + + + + + + + Retrieves the current definition (Ecore representation) of this stereotype. + + + + + + + + + + Creates an icon with the specified location for this stereotype. + + + + + The location for the new icon. + + + + + + Creates an icon with the specified format and content for this stereotype. + + + + + The format for the new icon. + + + + + The content for the new icon. + + + + + + + + Determines whether this model is a metamodel. + + + + + + + + Retrieves the definition (Ecore representation) of the profile associated with this profile application. + + + + + + + + + + Retrieves the definition (Ecore representation) of the specified named element in the profile associated with this profile application. + + + + + + + + + The named element for which to retrieve the applied definition. + + + + + + + + + + + + Retrieves all the attributes of this classifier, including those inherited from its parents. + + + + + + + + + Retrieves the operations of this classifier. + + + + + + + + + Retrieves all the operations of this classifier, including those inherited from its parents. + + + + + + + + + Retrieves the first operation with the specified name, parameter names, and parameter types from this classifier. + + + + + + + + The name of the operation to retrieve, or null. + + + + + + + The parameter names of the operation to retrieve, or null. + + + + + + + The parameter types of the operation to retrieve, or null. + + + + + + + + Retrieves the first operation with the specified name, parameter names, and parameter types from this classifier, ignoring case if indicated. + + + + + + + + The name of the operation to retrieve, or null. + + + + + + + The parameter names of the operation to retrieve, or null. + + + + + + + The parameter types of the operation to retrieve, or null. + + + + + + + Whether to ignore case in String comparisons. + + + + + + Retrieves the interfaces on which this classifier has a usage dependency. + + + + + + + + + Retrieves all the interfaces on which this classifier or any of its parents has a usage dependency. + + + + + + + + + + + + Creates an import of the specified element into this namespace with the specified visibility. + + + + + The element to import. + + + + + The visibility for the new element import. + + + + + + Creates an import of the specified package into this namespace with the specified visibility. + + + + + The package to import. + + + + + The visibility for the new package import. + + + + + + Retrieves the elements imported by this namespace. + + + + + + + + + Retrieves the packages imported by this namespace. + + + + + + + + + + + + Determines whether this association is a binary association, i.e. whether it has exactly two member ends. + + + + + + + + + + Creates a property with the specified name, type, lower bound, and upper bound as an owned attribute of this structured classifier. + + + + + The name for the new attribute, or null. + + + + + + + The type for the new attribute, or null. + + + + + + + The lower bound for the new attribute. + + + + + The upper bound for the new attribute. + + + + + + + + + Creates an operation with the specified name, parameter names, parameter types, and return type (or null) as an owned operation of this artifact. + + + + + The name for the new operation, or null. + + + + + + + The parameter names for the new operation, or null. + + + + + + + The parameter types for the new operation, or null. + + + + + + + The return type for the new operation, or null. + + + + + + + + Creates a property with the specified name, type, lower bound, and upper bound as an owned attribute of this artifact. + + + + + The name for the new attribute, or null. + + + + + + + The type for the new attribute, or null. + + + + + + + The lower bound for the new attribute. + + + + + The upper bound for the new attribute. + + + + + + + + Creates an operation with the specified name, parameter names, parameter types, and return type (or null) as an owned operation of this data type. + + + + + The name for the new operation, or null. + + + + + + + The parameter names for the new operation, or null. + + + + + + + The parameter types for the new operation, or null. + + + + + + + The return type for the new operation, or null. + + + + + + + + Creates a property with the specified name, type, lower bound, and upper bound as an owned attribute of this data type. + + + + + The name for the new attribute, or null. + + + + + + + The type for the new attribute, or null. + + + + + + + The lower bound for the new attribute. + + + + + The upper bound for the new attribute. + + + + + + + + Creates a property with the specified name, type, lower bound, and upper bound as an owned attribute of this signal. + + + + + The name for the new attribute, or null. + + + + + + + The type for the new attribute, or null. + + + + + + + The lower bound for the new attribute. + + + + + The upper bound for the new attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + Creates a return result parameter with the specified name and type. + + + + + The name for the new return result, or null. + + + + + + + The type for the new return result, or null. + + + + + + + + + + + + Creates a(n) (abstract) class with the specified name as a packaged element of this component. + + + + + The name for the new class, or null. + + + + + Whether the new class should be abstract. + + + + + + Creates a enumeration with the specified name as a packaged element of this component. + + + + + The name for the new enumeration, or null. + + + + + + Creates a primitive type with the specified name as a packaged element of this component. + + + + + The name for the new primitive type, or null. + + + + + + Creates an interface with the specified name as a packaged element of this component. + + + + + The name for the new interface, or null. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pyUml/usedDocuments/UMLMarkerNavigationProvider.java b/pyUml/usedDocuments/UMLMarkerNavigationProvider.java new file mode 100755 index 0000000..ea6ce25 --- /dev/null +++ b/pyUml/usedDocuments/UMLMarkerNavigationProvider.java @@ -0,0 +1,96 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.Arrays; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.EditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor; +import org.eclipse.gmf.runtime.emf.ui.providers.marker.AbstractModelMarkerNavigationProvider; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorUtil; + +/** + * @generated + */ +public class UMLMarkerNavigationProvider extends + AbstractModelMarkerNavigationProvider { + + /** + * @generated + */ + public static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID + + ".diagnostic"; //$NON-NLS-1$ + + /** + * @generated + */ + protected void doGotoMarker(IMarker marker) { + String elementId = marker + .getAttribute( + org.eclipse.gmf.runtime.common.core.resources.IMarker.ELEMENT_ID, + null); + if (elementId == null || !(getEditor() instanceof DiagramEditor)) { + return; + } + DiagramEditor editor = (DiagramEditor) getEditor(); + Map editPartRegistry = editor.getDiagramGraphicalViewer() + .getEditPartRegistry(); + EObject targetView = editor.getDiagram().eResource().getEObject( + elementId); + if (targetView == null) { + return; + } + EditPart targetEditPart = (EditPart) editPartRegistry.get(targetView); + if (targetEditPart != null) { + UMLDiagramEditorUtil.selectElementsInDiagram(editor, Arrays + .asList(new EditPart[] { targetEditPart })); + } + } + + /** + * @generated + */ + public static void deleteMarkers(IResource resource) { + try { + resource.deleteMarkers(MARKER_TYPE, true, IResource.DEPTH_ZERO); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Failed to delete validation markers", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public static IMarker addMarker(IFile file, String elementId, + String location, String message, int statusSeverity) { + IMarker marker = null; + try { + marker = file.createMarker(MARKER_TYPE); + marker.setAttribute(IMarker.MESSAGE, message); + marker.setAttribute(IMarker.LOCATION, location); + marker + .setAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + elementId); + int markerSeverity = IMarker.SEVERITY_INFO; + if (statusSeverity == IStatus.WARNING) { + markerSeverity = IMarker.SEVERITY_WARNING; + } else if (statusSeverity == IStatus.ERROR + || statusSeverity == IStatus.CANCEL) { + markerSeverity = IMarker.SEVERITY_ERROR; + } + marker.setAttribute(IMarker.SEVERITY, markerSeverity); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Failed to create validation marker", e); //$NON-NLS-1$ + } + return marker; + } +} diff --git a/pyUml/usedDocuments/UMLValidationDecoratorProvider.java b/pyUml/usedDocuments/UMLValidationDecoratorProvider.java new file mode 100755 index 0000000..cc79f07 --- /dev/null +++ b/pyUml/usedDocuments/UMLValidationDecoratorProvider.java @@ -0,0 +1,463 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.draw2d.FlowLayout; +import org.eclipse.draw2d.Label; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; +import org.eclipse.gef.EditDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.editparts.AbstractConnectionEditPart; +import org.eclipse.gmf.runtime.common.core.service.AbstractProvider; +import org.eclipse.gmf.runtime.common.core.service.IOperation; +import org.eclipse.gmf.runtime.common.ui.resources.FileChangeManager; +import org.eclipse.gmf.runtime.common.ui.resources.IFileObserver; +import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; +import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider; +import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget; +import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; +import org.eclipse.gmf.runtime.notation.Diagram; +import org.eclipse.gmf.runtime.notation.Edge; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditor; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry; + +/** + * @generated + */ +public class UMLValidationDecoratorProvider extends AbstractProvider implements + IDecoratorProvider { + + public static Resource usedResource = null; + + /** + * @generated + */ + private static final String KEY = "validationStatus"; //$NON-NLS-1$ + + /** + * @generated + */ + private static final String MARKER_TYPE = UMLDiagramEditorPlugin.ID + + ".diagnostic"; //$NON-NLS-1$ + + /** + * @generated + */ + private static MarkerObserver fileObserver; + + /** + * @generated + */ + private static Map/*>*/allDecorators = new HashMap(); + + /** + * @generated + */ + public void createDecorators(IDecoratorTarget decoratorTarget) { + EditPart editPart = (EditPart) decoratorTarget + .getAdapter(EditPart.class); + if (editPart instanceof GraphicalEditPart + || editPart instanceof AbstractConnectionEditPart) { + Object model = editPart.getModel(); + if ((model instanceof View)) { + View view = (View) model; + if (!(view instanceof Edge) && !view.isSetElement()) { + return; + } + } + EditDomain ed = editPart.getViewer().getEditDomain(); + if (!(ed instanceof DiagramEditDomain)) { + return; + } + if (((DiagramEditDomain) ed).getEditorPart() instanceof UMLDiagramEditor) { + decoratorTarget.installDecorator(KEY, new StatusDecorator( + decoratorTarget)); + } + } + } + + /** + * @generated + */ + public boolean provides(IOperation operation) { + if (!(operation instanceof CreateDecoratorsOperation)) { + return false; + } + IDecoratorTarget decoratorTarget = ((CreateDecoratorsOperation) operation) + .getDecoratorTarget(); + View view = (View) decoratorTarget.getAdapter(View.class); + return view != null + && PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry + .getModelID(view)); + } + + /** + * @generated + */ + public static void refreshDecorators(View view) { + refreshDecorators(ViewUtil.getIdStr(view), view.getDiagram()); + } + + /** + * @generated + */ + private static void refreshDecorators(String viewId, Diagram diagram) { + final List decorators = viewId != null ? (List) allDecorators + .get(viewId) : null; + if (decorators == null || decorators.isEmpty() || diagram == null) { + return; + } + final Diagram fdiagram = diagram; + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + + public void run() { + try { + if (UMLValidationDecoratorProvider.usedResource == null) + UMLValidationDecoratorProvider.usedResource = fdiagram.eResource(); + + if (UMLValidationDecoratorProvider.usedResource == null) + return; + + TransactionalEditingDomain domain = + TransactionalEditingDomain.Factory.INSTANCE.getEditingDomain( + UMLValidationDecoratorProvider.usedResource.getResourceSet()); + domain.runExclusive( + new Runnable() { + + public void run() { + for (Iterator it = decorators.iterator(); it + .hasNext();) { + IDecorator decorator = (IDecorator) it + .next(); + decorator.refresh(); + } + } + }); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Decorator refresh failure", e); //$NON-NLS-1$ + } + } + }); + } + + /** + * @generated + */ + public static class StatusDecorator extends AbstractDecorator { + + /** + * @generated + */ + private String viewId; + + /** + * @generated + */ + public StatusDecorator(IDecoratorTarget decoratorTarget) { + super(decoratorTarget); + try { + final View view = (View) getDecoratorTarget().getAdapter( + View.class); + TransactionUtil.getEditingDomain(view).runExclusive( + new Runnable() { + + public void run() { + StatusDecorator.this.viewId = view != null ? ViewUtil + .getIdStr(view) + : null; + } + }); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "ViewID access failure", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public void refresh() { + removeDecoration(); + View view = (View) getDecoratorTarget().getAdapter(View.class); + if (view == null || view.eResource() == null) { + return; + } + EditPart editPart = (EditPart) getDecoratorTarget().getAdapter( + EditPart.class); + if (editPart == null || editPart.getViewer() == null) { + return; + } + + // query for all the validation markers of the current resource + String elementId = ViewUtil.getIdStr(view); + if (elementId == null) { + return; + } + int severity = IMarker.SEVERITY_INFO; + IMarker foundMarker = null; + IResource resource = WorkspaceSynchronizer + .getFile(view.eResource()); + if (resource == null || !resource.exists()) { + return; + } + IMarker[] markers = null; + try { + markers = resource.findMarkers(MARKER_TYPE, true, + IResource.DEPTH_INFINITE); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation markers refresh failure", e); //$NON-NLS-1$ + } + if (markers == null || markers.length == 0) { + return; + } + Label toolTip = null; + for (int i = 0; i < markers.length; i++) { + IMarker marker = markers[i]; + String attribute = marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + ""); //$NON-NLS-1$ + if (attribute.equals(elementId)) { + int nextSeverity = marker.getAttribute(IMarker.SEVERITY, + IMarker.SEVERITY_INFO); + Image nextImage = getImage(nextSeverity); + if (foundMarker == null) { + foundMarker = marker; + toolTip = new Label(marker.getAttribute( + IMarker.MESSAGE, ""), //$NON-NLS-1$ + nextImage); + } else { + if (toolTip.getChildren().isEmpty()) { + Label comositeLabel = new Label(); + FlowLayout fl = new FlowLayout(false); + fl.setMinorSpacing(0); + comositeLabel.setLayoutManager(fl); + comositeLabel.add(toolTip); + toolTip = comositeLabel; + } + toolTip.add(new Label(marker.getAttribute( + IMarker.MESSAGE, ""), //$NON-NLS-1$ + nextImage)); + } + severity = (nextSeverity > severity) ? nextSeverity + : severity; + } + } + if (foundMarker == null) { + return; + } + + // add decoration + if (editPart instanceof org.eclipse.gef.GraphicalEditPart) { + if (view instanceof Edge) { + setDecoration(getDecoratorTarget().addConnectionDecoration( + getImage(severity), 50, true)); + } else { + int margin = -1; + if (editPart instanceof org.eclipse.gef.GraphicalEditPart) { + margin = MapModeUtil.getMapMode( + ((org.eclipse.gef.GraphicalEditPart) editPart) + .getFigure()).DPtoLP(margin); + } + setDecoration(getDecoratorTarget() + .addShapeDecoration(getImage(severity), + IDecoratorTarget.Direction.NORTH_EAST, + margin, true)); + } + getDecoration().setToolTip(toolTip); + } + } + + /** + * @generated + */ + private Image getImage(int severity) { + String imageName = ISharedImages.IMG_OBJS_ERROR_TSK; + switch (severity) { + case IMarker.SEVERITY_ERROR: + imageName = ISharedImages.IMG_OBJS_ERROR_TSK; + break; + case IMarker.SEVERITY_WARNING: + imageName = ISharedImages.IMG_OBJS_WARN_TSK; + break; + default: + imageName = ISharedImages.IMG_OBJS_INFO_TSK; + } + return PlatformUI.getWorkbench().getSharedImages().getImage( + imageName); + } + + /** + * @generated + */ + public void activate() { + if (viewId == null) { + return; + } + + // add self to global decorators registry + List list = (List) allDecorators.get(viewId); + if (list == null) { + list = new ArrayList(2); + list.add(this); + allDecorators.put(viewId, list); + } else if (!list.contains(this)) { + list.add(this); + } + + // start listening to changes in resources + View view = (View) getDecoratorTarget().getAdapter(View.class); + if (view == null) { + return; + } + Diagram diagramView = view.getDiagram(); + if (diagramView == null) { + return; + } + if (fileObserver == null) { + FileChangeManager.getInstance().addFileObserver( + fileObserver = new MarkerObserver(diagramView)); + } + } + + /** + * @generated + */ + public void deactivate() { + if (viewId == null) { + return; + } + + // remove self from global decorators registry + List list = (List) allDecorators.get(viewId); + if (list != null) { + list.remove(this); + if (list.isEmpty()) { + allDecorators.remove(viewId); + } + } + + // stop listening to changes in resources if there are no more decorators + if (fileObserver != null && allDecorators.isEmpty()) { + FileChangeManager.getInstance() + .removeFileObserver(fileObserver); + fileObserver = null; + } + super.deactivate(); + } + } + + /** + * @generated + */ + static class MarkerObserver implements IFileObserver { + + /** + * @generated + */ + private Diagram diagram; + + /** + * @generated + */ + private MarkerObserver(Diagram diagram) { + this.diagram = diagram; + } + + /** + * @generated + */ + public void handleFileRenamed(IFile oldFile, IFile file) { + } + + /** + * @generated + */ + public void handleFileMoved(IFile oldFile, IFile file) { + } + + /** + * @generated + */ + public void handleFileDeleted(IFile file) { + } + + /** + * @generated + */ + public void handleFileChanged(IFile file) { + } + + /** + * @generated + */ + public void handleMarkerAdded(IMarker marker) { + if (marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + null) != null) { + handleMarkerChanged(marker); + } + } + + /** + * @generated + */ + public void handleMarkerDeleted(IMarker marker, Map attributes) { + String viewId = (String) attributes + .get(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID); + refreshDecorators(viewId, diagram); + } + + /** + * @generated + */ + public void handleMarkerChanged(IMarker marker) { + if (!MARKER_TYPE.equals(getType(marker))) { + return; + } + String viewId = marker + .getAttribute( + org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, + ""); //$NON-NLS-1$ + refreshDecorators(viewId, diagram); + } + + /** + * @generated + */ + private String getType(IMarker marker) { + try { + return marker.getType(); + } catch (CoreException e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation marker refresh failure", e); //$NON-NLS-1$ + return ""; //$NON-NLS-1$ + } + } + } +} diff --git a/pyUml/usedDocuments/UMLValidationProvider.java b/pyUml/usedDocuments/UMLValidationProvider.java new file mode 100755 index 0000000..4c9eb99 --- /dev/null +++ b/pyUml/usedDocuments/UMLValidationProvider.java @@ -0,0 +1,367 @@ +package org.eclipse.uml2.diagram.clazz.providers; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.emf.validation.model.IClientSelector; +import org.eclipse.emf.validation.service.IBatchValidator; +import org.eclipse.emf.validation.service.ITraversalStrategy; +import org.eclipse.gmf.runtime.common.ui.services.action.contributionitem.AbstractContributionItemProvider; +import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.jface.action.IAction; +import org.eclipse.uml2.diagram.clazz.edit.parts.PackageEditPart; +import org.eclipse.uml2.diagram.clazz.part.UMLDiagramEditorPlugin; +import org.eclipse.uml2.diagram.clazz.part.UMLVisualIDRegistry; +import org.eclipse.uml2.diagram.clazz.part.ValidateAction; + +/** + * @generated + */ +public class UMLValidationProvider extends AbstractContributionItemProvider { + + /** + * @generated + */ + private static boolean constraintsActive = false; + + /** + * @generated + */ + public static boolean shouldConstraintsBePrivate() { + return false; + } + + /** + * @generated + */ + protected IAction createAction(String actionId, + IWorkbenchPartDescriptor partDescriptor) { + if (ValidateAction.VALIDATE_ACTION_KEY.equals(actionId)) { + return new ValidateAction(partDescriptor); + } + return super.createAction(actionId, partDescriptor); + } + + /** + * @generated + */ + public static void runWithConstraints(View view, Runnable op) { + final Runnable fop = op; + Runnable task = new Runnable() { + + public void run() { + try { + constraintsActive = true; + fop.run(); + } finally { + constraintsActive = false; + } + } + }; + TransactionalEditingDomain txDomain = TransactionUtil + .getEditingDomain(view); + if (txDomain != null) { + try { + txDomain.runExclusive(task); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } else { + task.run(); + } + } + + /** + * @generated + */ + static boolean isInDefaultEditorContext(Object object) { + if (shouldConstraintsBePrivate() && !constraintsActive) { + return false; + } + if (object instanceof View) { + return constraintsActive + && PackageEditPart.MODEL_ID.equals(UMLVisualIDRegistry + .getModelID((View) object)); + } + return true; + } + + /** + * @generated + */ + static final Map semanticCtxIdMap = new HashMap(); + + /** + * @generated + */ + public static class DefaultCtx1 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx2 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx3 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx4 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx5 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx6 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx7 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx8 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx9 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx10 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static class DefaultCtx11 implements IClientSelector { + + /** + * @generated + */ + public boolean selects(Object object) { + return isInDefaultEditorContext(object); + } + } + + /** + * @generated + */ + public static ITraversalStrategy getNotationTraversalStrategy( + IBatchValidator validator) { + return new CtxSwitchStrategy(validator); + } + + /** + * @generated + */ + private static class CtxSwitchStrategy implements ITraversalStrategy { + + /** + * @generated + */ + private ITraversalStrategy defaultStrategy; + + /** + * @generated + */ + private String currentSemanticCtxId; + + /** + * @generated + */ + private boolean ctxChanged = true; + + /** + * @generated + */ + private EObject currentTarget; + + /** + * @generated + */ + private EObject preFetchedNextTarget; + + /** + * @generated + */ + CtxSwitchStrategy(IBatchValidator validator) { + this.defaultStrategy = validator.getDefaultTraversalStrategy(); + } + + /** + * @generated + */ + public void elementValidated(EObject element, IStatus status) { + defaultStrategy.elementValidated(element, status); + } + + /** + * @generated + */ + public boolean hasNext() { + return defaultStrategy.hasNext(); + } + + /** + * @generated + */ + public boolean isClientContextChanged() { + if (preFetchedNextTarget == null) { + preFetchedNextTarget = next(); + prepareNextClientContext(preFetchedNextTarget); + } + return ctxChanged; + } + + /** + * @generated + */ + public EObject next() { + EObject nextTarget = preFetchedNextTarget; + if (nextTarget == null) { + nextTarget = defaultStrategy.next(); + } + this.preFetchedNextTarget = null; + return this.currentTarget = nextTarget; + } + + /** + * @generated + */ + public void startTraversal(Collection traversalRoots, + IProgressMonitor monitor) { + defaultStrategy.startTraversal(traversalRoots, monitor); + } + + /** + * @generated + */ + private void prepareNextClientContext(EObject nextTarget) { + if (nextTarget != null && currentTarget != null) { + if (nextTarget instanceof View) { + String id = ((View) nextTarget).getType(); + String nextSemanticId = id != null + && semanticCtxIdMap.containsKey(id) ? id : null; + if ((currentSemanticCtxId != null && !currentSemanticCtxId + .equals(nextSemanticId)) + || (nextSemanticId != null && !nextSemanticId + .equals(currentSemanticCtxId))) { + this.ctxChanged = true; + } + currentSemanticCtxId = nextSemanticId; + } else { + // context of domain model + this.ctxChanged = currentSemanticCtxId != null; + currentSemanticCtxId = null; + } + } else { + this.ctxChanged = false; + } + } + } + + /** + * @generated + */ + static class JavaAudits { + } +} diff --git a/pyUml/usedDocuments/ValidateAction.java b/pyUml/usedDocuments/ValidateAction.java new file mode 100755 index 0000000..96f2844 --- /dev/null +++ b/pyUml/usedDocuments/ValidateAction.java @@ -0,0 +1,297 @@ +package org.eclipse.uml2.diagram.clazz.part; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.validation.model.EvaluationMode; +import org.eclipse.emf.validation.model.IConstraintStatus; +import org.eclipse.emf.validation.service.IBatchValidator; +import org.eclipse.emf.validation.service.ModelValidationService; +import org.eclipse.emf.workspace.util.WorkspaceSynchronizer; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor; +import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory; +import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; +import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; +import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation; +import org.eclipse.uml2.diagram.clazz.providers.UMLMarkerNavigationProvider; +import org.eclipse.uml2.diagram.clazz.providers.UMLValidationProvider; + +/** + * @generated + */ +public class ValidateAction extends Action { + + /** + * @generated + */ + public static final String VALIDATE_ACTION_KEY = "validateAction"; //$NON-NLS-1$ + + /** + * @generated + */ + private IWorkbenchPartDescriptor workbenchPartDescriptor; + + /** + * @generated + */ + public ValidateAction(IWorkbenchPartDescriptor workbenchPartDescriptor) { + setId(VALIDATE_ACTION_KEY); + setText(Messages.ValidateActionMessage); + this.workbenchPartDescriptor = workbenchPartDescriptor; + } + + /** + * @generated + */ + public void run() { + IWorkbenchPart workbenchPart = workbenchPartDescriptor.getPartPage() + .getActivePart(); + if (workbenchPart instanceof IDiagramWorkbenchPart) { + final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) workbenchPart; + try { + new WorkspaceModifyDelegatingOperation( + new IRunnableWithProgress() { + + public void run(IProgressMonitor monitor) + throws InterruptedException, + InvocationTargetException { + runValidation(part.getDiagramEditPart(), part + .getDiagram()); + } + }).run(new NullProgressMonitor()); + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } + } + + /** + * @generated + */ + public static void runValidation(View view) { + try { + if (UMLDiagramEditorUtil.openDiagram(view.eResource())) { + IEditorPart editorPart = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage() + .getActiveEditor(); + if (editorPart instanceof IDiagramWorkbenchPart) { + runValidation(((IDiagramWorkbenchPart) editorPart) + .getDiagramEditPart(), view); + } else { + runNonUIValidation(view); + } + } + } catch (Exception e) { + UMLDiagramEditorPlugin.getInstance().logError( + "Validation action failed", e); //$NON-NLS-1$ + } + } + + /** + * @generated + */ + public static void runNonUIValidation(View view) { + DiagramEditPart diagramEditPart = OffscreenEditPartFactory + .getInstance().createDiagramEditPart(view.getDiagram()); + runValidation(diagramEditPart, view); + } + + /** + * @generated + */ + public static void runValidation(DiagramEditPart diagramEditPart, View view) { + final DiagramEditPart fpart = diagramEditPart; + final View fview = view; + UMLValidationProvider.runWithConstraints(view, new Runnable() { + + public void run() { + validate(fpart, fview); + } + }); + } + + /** + * @generated + */ + private static Diagnostic runEMFValidator(View target) { + if (target.isSetElement() && target.getElement() != null) { + return new Diagnostician() { + + public String getObjectLabel(EObject eObject) { + return EMFCoreUtil.getQualifiedName(eObject, true); + } + }.validate(target.getElement()); + } + return Diagnostic.OK_INSTANCE; + } + + /** + * @generated + */ + private static void validate(DiagramEditPart diagramEditPart, View view) { + IFile target = view.eResource() != null ? WorkspaceSynchronizer + .getFile(view.eResource()) : null; + if (target != null) { + UMLMarkerNavigationProvider.deleteMarkers(target); + } + Diagnostic diagnostic = runEMFValidator(view); + createMarkers(target, diagnostic, diagramEditPart); + IBatchValidator validator = (IBatchValidator) ModelValidationService + .getInstance().newValidator(EvaluationMode.BATCH); + validator.setIncludeLiveConstraints(true); + if (view.isSetElement() && view.getElement() != null) { + IStatus status = validator.validate(view.getElement()); + createMarkers(target, status, diagramEditPart); + } + } + + /** + * @generated + */ + private static void createMarkers(IFile target, IStatus validationStatus, + DiagramEditPart diagramEditPart) { + if (validationStatus.isOK()) { + return; + } + final IStatus rootStatus = validationStatus; + List allStatuses = new ArrayList(); + UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap( + diagramEditPart.getDiagramView(), collectTargetElements( + rootStatus, new HashSet(), allStatuses)); + for (Iterator it = allStatuses.iterator(); it.hasNext();) { + IConstraintStatus nextStatus = (IConstraintStatus) it.next(); + View view = UMLDiagramEditorUtil.findView(diagramEditPart, + nextStatus.getTarget(), element2ViewMap); + addMarker(diagramEditPart.getViewer(), target, view.eResource() + .getURIFragment(view), EMFCoreUtil.getQualifiedName( + nextStatus.getTarget(), true), nextStatus.getMessage(), + nextStatus.getSeverity()); + } + } + + /** + * @generated + */ + private static void createMarkers(IFile target, + Diagnostic emfValidationStatus, DiagramEditPart diagramEditPart) { + if (emfValidationStatus.getSeverity() == Diagnostic.OK) { + return; + } + final Diagnostic rootStatus = emfValidationStatus; + List allDiagnostics = new ArrayList(); + UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap( + diagramEditPart.getDiagramView(), collectTargetElements( + rootStatus, new HashSet(), allDiagnostics)); + for (Iterator it = emfValidationStatus.getChildren().iterator(); it + .hasNext();) { + Diagnostic nextDiagnostic = (Diagnostic) it.next(); + List data = nextDiagnostic.getData(); + if (data != null && !data.isEmpty() + && data.get(0) instanceof EObject) { + EObject element = (EObject) data.get(0); + View view = UMLDiagramEditorUtil.findView(diagramEditPart, + element, element2ViewMap); + addMarker( + diagramEditPart.getViewer(), + target, + view.eResource().getURIFragment(view), + EMFCoreUtil.getQualifiedName(element, true), + nextDiagnostic.getMessage(), + diagnosticToStatusSeverity(nextDiagnostic.getSeverity())); + } + } + } + + /** + * @generated + */ + private static void addMarker(EditPartViewer viewer, IFile target, + String elementId, String location, String message, + int statusSeverity) { + if (target == null) { + return; + } + UMLMarkerNavigationProvider.addMarker(target, elementId, location, + message, statusSeverity); + } + + /** + * @generated + */ + private static int diagnosticToStatusSeverity(int diagnosticSeverity) { + if (diagnosticSeverity == Diagnostic.OK) { + return IStatus.OK; + } else if (diagnosticSeverity == Diagnostic.INFO) { + return IStatus.INFO; + } else if (diagnosticSeverity == Diagnostic.WARNING) { + return IStatus.WARNING; + } else if (diagnosticSeverity == Diagnostic.ERROR + || diagnosticSeverity == Diagnostic.CANCEL) { + return IStatus.ERROR; + } + return IStatus.INFO; + } + + /** + * @generated + */ + private static Set collectTargetElements(IStatus status, + Set targetElementCollector, List allConstraintStatuses) { + if (status instanceof IConstraintStatus) { + targetElementCollector + .add(((IConstraintStatus) status).getTarget()); + allConstraintStatuses.add(status); + } + if (status.isMultiStatus()) { + IStatus[] children = status.getChildren(); + for (int i = 0; i < children.length; i++) { + collectTargetElements(children[i], targetElementCollector, + allConstraintStatuses); + } + } + return targetElementCollector; + } + + /** + * @generated + */ + private static Set collectTargetElements(Diagnostic diagnostic, + Set targetElementCollector, List allDiagnostics) { + List data = diagnostic.getData(); + EObject target = null; + if (data != null && !data.isEmpty() && data.get(0) instanceof EObject) { + target = (EObject) data.get(0); + targetElementCollector.add(target); + allDiagnostics.add(diagnostic); + } + if (diagnostic.getChildren() != null + && !diagnostic.getChildren().isEmpty()) { + for (Iterator it = diagnostic.getChildren().iterator(); it + .hasNext();) { + collectTargetElements((Diagnostic) it.next(), + targetElementCollector, allDiagnostics); + } + } + return targetElementCollector; + } +} diff --git a/pyUml/usedDocuments/classDiagram.gmfgen b/pyUml/usedDocuments/classDiagram.gmfgen new file mode 100755 index 0000000..a82c510 --- /dev/null +++ b/pyUml/usedDocuments/classDiagram.gmfgen @@ -0,0 +1,11451 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uml + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + org.eclipse.draw2d + org.eclipse.uml2.diagram.common + org.eclipse.gmf.runtime.draw2d.ui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.gmf.runtime.notation.View + org.eclipse.gef.EditPart + abstractNavigatorItem + + + + + + + + diff --git a/pyUml/usedDocuments/classDiagram.gmfmap b/pyUml/usedDocuments/classDiagram.gmfmap new file mode 100755 index 0000000..ca4c589 --- /dev/null +++ b/pyUml/usedDocuments/classDiagram.gmfmap @@ -0,0 +1,1978 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +