diff --git a/ge/org.osate.ge/setups/svn_test_dev.setup b/ge/org.osate.ge/setups/svn_test_dev.setup new file mode 100644 index 00000000000..2e8916c4b63 --- /dev/null +++ b/ge/org.osate.ge/setups/svn_test_dev.setup @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + Adds Subversive + diff --git a/ge/org.osate.ge/src/org/osate/ge/internal/refactoring/AgeRenameParticipant.java b/ge/org.osate.ge/src/org/osate/ge/internal/refactoring/AgeRenameParticipant.java index 081d71dc3e0..7d0c71f7388 100644 --- a/ge/org.osate.ge/src/org/osate/ge/internal/refactoring/AgeRenameParticipant.java +++ b/ge/org.osate.ge/src/org/osate/ge/internal/refactoring/AgeRenameParticipant.java @@ -10,11 +10,13 @@ import java.util.Objects; import java.util.Set; +import org.eclipse.core.resources.IFile; 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.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.e4.core.contexts.EclipseContextFactory; @@ -31,6 +33,8 @@ import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.RenameParticipant; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; import org.eclipse.xtext.resource.IFragmentProvider; import org.eclipse.xtext.resource.IReferenceDescription; import org.eclipse.xtext.resource.IResourceDescription; @@ -63,7 +67,8 @@ public class AgeRenameParticipant extends RenameParticipant { private DiagramService diagramService; private ResourceSet refactoringResourceSet; private IProject project; - private DiagramService.ReferenceCollection originalReferences; // The original set of references during the refactoring. They are stored before the change because the model change will have occured before the change is executed. + private DiagramService.ReferenceCollection originalReferences; // The original set of references during the refactoring. They are stored before the change + // because the model change will have occured before the change is executed. private static class UriAndRelativeReference { public final URI uri; @@ -79,19 +84,20 @@ public UriAndRelativeReference(final URI uri, final RelativeBusinessObjectRefere protected boolean initialize(final Object element) { originalCanRefToNewInfoMap.clear(); - if(!(element instanceof IRenameElementContext)) { + if (!(element instanceof IRenameElementContext)) { return false; } - ctx = (IRenameElementContext)element; + ctx = (IRenameElementContext) element; final URI targetElementUri = ctx.getTargetElementURI(); - if(targetElementUri == null) { + if (targetElementUri == null) { return false; } - final IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(targetElementUri.toPlatformString(true))); - if(resource == null) { + final IResource resource = ResourcesPlugin.getWorkspace().getRoot() + .findMember(new Path(targetElementUri.toPlatformString(true))); + if (resource == null) { return false; } @@ -100,14 +106,15 @@ protected boolean initialize(final Object element) { .getInstance(LiveScopeResourceSetInitializer.class).initialize(tmpRs); targetObject = tmpRs.getEObject(targetElementUri, true); - if(targetObject == null || !(targetObject.eResource() instanceof XtextResource)) { + if (targetObject == null || !(targetObject.eResource() instanceof XtextResource)) { return false; } final XtextResource xtextResource = (XtextResource) targetObject.eResource(); // Get the provider for the refactoring resource set - final RefactoringResourceSetProvider refactoringResourceSetProvider = xtextResource.getResourceServiceProvider().get(RefactoringResourceSetProvider.class); + final RefactoringResourceSetProvider refactoringResourceSetProvider = xtextResource.getResourceServiceProvider() + .get(RefactoringResourceSetProvider.class); project = ProjectUtil.getProject(targetElementUri); if (project == null) { return false; @@ -115,14 +122,15 @@ protected boolean initialize(final Object element) { // Get the refactoring resource set refactoringResourceSet = refactoringResourceSetProvider.get(project); - if(refactoringResourceSet == null) { + if (refactoringResourceSet == null) { return false; } // Get global services final Bundle bundle = FrameworkUtil.getBundle(getClass()); final IEclipseContext context = EclipseContextFactory.getServiceContext(bundle.getBundleContext()); - referenceService = Objects.requireNonNull(context.get(ReferenceService.class), "Unable to get reference service"); + referenceService = Objects.requireNonNull(context.get(ReferenceService.class), + "Unable to get reference service"); diagramService = Objects.requireNonNull(context.get(DiagramService.class), "Unable to get diagram service"); // Get projects with are affected by the refactoring. @@ -132,16 +140,20 @@ protected boolean initialize(final Object element) { final Map> externalReferencesMap = buildExternalReferenceMap(relevantProjects); // Find all dependent objects - final Set dependentObjects = getDependentObjects(targetObject, targetObject.eResource().getResourceSet(), externalReferencesMap); + final Set dependentObjects = getDependentObjects(targetObject, + targetObject.eResource().getResourceSet(), externalReferencesMap); dependentObjects.add(targetObject); - for(final EObject dirtyObject : dependentObjects) { + for (final EObject dirtyObject : dependentObjects) { final URI uri = getNameIndependentUri(dirtyObject); - if(uri != null) { - final CanonicalBusinessObjectReference canonicalReference = referenceService.getCanonicalReference(dirtyObject); - final RelativeBusinessObjectReference relativeReference = referenceService.getRelativeReference(dirtyObject); - if(canonicalReference != null && relativeReference != null) { - originalCanRefToNewInfoMap.put(canonicalReference, new UriAndRelativeReference(uri, relativeReference)); + if (uri != null) { + final CanonicalBusinessObjectReference canonicalReference = referenceService + .getCanonicalReference(dirtyObject); + final RelativeBusinessObjectReference relativeReference = referenceService + .getRelativeReference(dirtyObject); + if (canonicalReference != null && relativeReference != null) { + originalCanRefToNewInfoMap.put(canonicalReference, + new UriAndRelativeReference(uri, relativeReference)); } } } @@ -160,6 +172,35 @@ public String getName() { @Override public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException { + + final Set relatedDiagramFiles = originalReferences.getRelatedDiagramFiles(); + final IFile[] relatedDiagramFilesArray = relatedDiagramFiles.toArray(new IFile[relatedDiagramFiles.size()]); + if (relatedDiagramFilesArray.length > 0) { + final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow() == null ? null + : PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + + final IStatus status = ResourcesPlugin.getWorkspace().validateEdit(relatedDiagramFilesArray, shell); + final String errorReason; + if (!status.isOK()) { + errorReason = (status.getMessage() == null || status.getMessage().length() == 0) + ? "One or more related diagrams are not editable" + : status.getMessage(); + } else if (relatedDiagramFiles.stream().anyMatch(file -> file.isReadOnly())) { + errorReason = "One ore more related diagrams are read-only."; + } else { + errorReason = null; + } + + if (errorReason != null) { + final RefactoringStatus refactoringStatus = new RefactoringStatus(); + refactoringStatus + .addError( + errorReason + + " Read-only diagrams will not be updated and broken linkages may result."); + return refactoringStatus; + } + } + return null; } @@ -176,7 +217,8 @@ public void initializeValidationData(final IProgressMonitor pm) { } @Override - public RefactoringStatus isValid(final IProgressMonitor pm) throws CoreException, OperationCanceledException { + public RefactoringStatus isValid(final IProgressMonitor pm) + throws CoreException, OperationCanceledException { return new RefactoringStatus(); } @@ -188,15 +230,18 @@ public Change perform(final IProgressMonitor pm) throws CoreException { final Map originalCanRefToNewRelRefMap = new HashMap<>(); final Map undoOriginalCanRefToNewCanRefMap = new HashMap<>(); final Map undoOriginalCanRefToNewRelRefMap = new HashMap<>(); - for(final Entry entry : originalCanRefToNewInfoMap.entrySet()) { + for (final Entry entry : originalCanRefToNewInfoMap + .entrySet()) { final EObject newObject = refactoringResourceSet.getEObject(entry.getValue().uri, true); - if(newObject != null) { + if (newObject != null) { final CanonicalBusinessObjectReference originalCanRef = entry.getKey(); - final CanonicalBusinessObjectReference newCanRef = referenceService.getCanonicalReference(newObject); - final RelativeBusinessObjectReference newRelRef = referenceService.getRelativeReference(newObject); + final CanonicalBusinessObjectReference newCanRef = referenceService + .getCanonicalReference(newObject); + final RelativeBusinessObjectReference newRelRef = referenceService + .getRelativeReference(newObject); final RelativeBusinessObjectReference originalRelRef = entry.getValue().relRef; - if(newCanRef != null && newRelRef != null) { + if (newCanRef != null && newRelRef != null) { originalCanRefToNewCanRefMap.put(originalCanRef, newCanRef); originalCanRefToNewRelRefMap.put(originalCanRef, newRelRef); undoOriginalCanRefToNewCanRefMap.put(originalCanRef, originalCanRef); @@ -226,13 +271,14 @@ public Object getModifiedElement() { // Builds a mapping between EObject URIs and the URIs of EObjects that it affects based on the EMF Index. private static final Map> buildExternalReferenceMap(final Set projects) { final Map> externalReferencesMap = new HashMap<>(); - for(final IResourceDescription resourceDescription : ScopedEMFIndexRetrieval.calculateResourceDescriptions(projects)) { - for(final IReferenceDescription refDescription : resourceDescription.getReferenceDescriptions()) { + for (final IResourceDescription resourceDescription : ScopedEMFIndexRetrieval + .calculateResourceDescriptions(projects)) { + for (final IReferenceDescription refDescription : resourceDescription.getReferenceDescriptions()) { final EReference ref = refDescription.getEReference(); - if(isHandledRefinedReference(ref)) { - if(refDescription.getSourceEObjectUri() != null && refDescription.getTargetEObjectUri() != null) { + if (isHandledRefinedReference(ref)) { + if (refDescription.getSourceEObjectUri() != null && refDescription.getTargetEObjectUri() != null) { Set affectedUris = externalReferencesMap.get(refDescription.getTargetEObjectUri()); - if(affectedUris == null) { + if (affectedUris == null) { affectedUris = new HashSet<>(); externalReferencesMap.put(refDescription.getTargetEObjectUri(), affectedUris); } @@ -258,8 +304,8 @@ private static URI getNameIndependentUri(final EObject obj) { IFragmentProvider oldFragmentProvider = null; XtextResource res = null; try { - if(obj.eResource() instanceof XtextResource) { - res = (XtextResource)obj.eResource(); + if (obj.eResource() instanceof XtextResource) { + res = (XtextResource) obj.eResource(); oldFragmentProvider = res.getFragmentProvider(); res.setFragmentProvider(null); } @@ -267,64 +313,62 @@ private static URI getNameIndependentUri(final EObject obj) { // Store the URIs return EcoreUtil.getURI(obj); - } finally { // Restore the old fragment processor - if(oldFragmentProvider != null) { + if (oldFragmentProvider != null) { res.setFragmentProvider(oldFragmentProvider); } } } - private static Set getDependentObjects(final EObject obj, final ResourceSet rs, final Map> externalReferencesMap) { + private static Set getDependentObjects(final EObject obj, final ResourceSet rs, + final Map> externalReferencesMap) { final Set results = new HashSet<>(); final EObject objectOfInterest; // If the object is a component type rename, replace it with the component type it renames. This will result in additional objects being returned but it // is the only known way of getting types related to the renames. - if(obj instanceof ComponentTypeRename) { - final ComponentType renamedComponentType = ((ComponentTypeRename)obj).getRenamedComponentType(); + if (obj instanceof ComponentTypeRename) { + final ComponentType renamedComponentType = ((ComponentTypeRename) obj).getRenamedComponentType(); objectOfInterest = renamedComponentType == null ? null : renamedComponentType; } else { objectOfInterest = obj; } - if(objectOfInterest != null) { - getRelatedObjects(Collections.singleton(objectOfInterest), rs, results, externalReferencesMap, obj instanceof Feature); + if (objectOfInterest != null) { + getRelatedObjects(Collections.singleton(objectOfInterest), rs, results, externalReferencesMap, + obj instanceof Feature); } return results; } // Gets objects related to the specified objects of interest - private static void getRelatedObjects(Collection objectsOfInterest, - final ResourceSet rs, - final Set results, - final Map> externalReferencesMap, - final boolean recursive) { + private static void getRelatedObjects(Collection objectsOfInterest, final ResourceSet rs, + final Set results, final Map> externalReferencesMap, final boolean recursive) { final Collection newObjects = new ArrayList<>(); - for(final Collection settings : UsageCrossReferencer.findAll(objectsOfInterest, rs).values()) { - for(final Setting s : settings) { + for (final Collection settings : UsageCrossReferencer.findAll(objectsOfInterest, rs).values()) { + for (final Setting s : settings) { final EStructuralFeature sf = s.getEStructuralFeature(); - if(isHandledRefinedReference(sf)) { + if (isHandledRefinedReference(sf)) { newObjects.add(s.getEObject()); - } else if(sf == Aadl2Package.eINSTANCE.getRealization_Implemented()) { + } else if (sf == Aadl2Package.eINSTANCE.getRealization_Implemented()) { // Get the component implementation from the realization - final Realization realization = (Realization)s.getEObject(); + final Realization realization = (Realization) s.getEObject(); newObjects.add(realization.getSpecific()); } } } - for(final EObject objectOfInterest : objectsOfInterest) { + for (final EObject objectOfInterest : objectsOfInterest) { final URI objectOfInterestUri = EcoreUtil.getURI(objectOfInterest); - if(objectOfInterestUri != null) { + if (objectOfInterestUri != null) { // Add objects references in the external references map final Set affectedUris = externalReferencesMap.get(objectOfInterestUri); - if(affectedUris != null) { - for(final URI affectedUri : affectedUris) { + if (affectedUris != null) { + for (final URI affectedUri : affectedUris) { final EObject affectedObject = rs.getEObject(affectedUri, true); - if(affectedObject != null) { + if (affectedObject != null) { newObjects.add(affectedObject); } } @@ -332,28 +376,26 @@ private static void getRelatedObjects(Collection objectsOfInterest, } } - if(results.addAll(newObjects)) { - if(recursive) { + if (results.addAll(newObjects)) { + if (recursive) { getRelatedObjects(newObjects, rs, results, externalReferencesMap, recursive); } } } private static boolean isHandledRefinedReference(final EStructuralFeature sf) { - return sf == Aadl2Package.eINSTANCE.getFeature_Refined() || - sf == Aadl2Package.eINSTANCE.getConnection_Refined() || - sf == Aadl2Package.eINSTANCE.getSubcomponent_Refined() || - sf == Aadl2Package.eINSTANCE.getSubcomponent_Refined() || - sf == Aadl2Package.eINSTANCE.getFlowSpecification_Refined(); + return sf == Aadl2Package.eINSTANCE.getFeature_Refined() || sf == Aadl2Package.eINSTANCE.getConnection_Refined() + || sf == Aadl2Package.eINSTANCE.getSubcomponent_Refined() + || sf == Aadl2Package.eINSTANCE.getSubcomponent_Refined() + || sf == Aadl2Package.eINSTANCE.getFlowSpecification_Refined(); } - - private static class SimpleUpdatedReferenceValueProvider implements DiagramService.UpdatedReferenceValueProvider { private final Map originalCanRefToNewCanRefMap; private final Map originalCanRefToNewRelRefMap; - public SimpleUpdatedReferenceValueProvider(final Map originalCanRefToNewCanRefMap, + public SimpleUpdatedReferenceValueProvider( + final Map originalCanRefToNewCanRefMap, final Map originalCanRefToNewRelRefMap) { this.originalCanRefToNewCanRefMap = originalCanRefToNewCanRefMap; this.originalCanRefToNewRelRefMap = originalCanRefToNewRelRefMap; diff --git a/ge/org.osate.ge/src/org/osate/ge/internal/services/DiagramService.java b/ge/org.osate.ge/src/org/osate/ge/internal/services/DiagramService.java index 220f6516cc5..80ba478794a 100644 --- a/ge/org.osate.ge/src/org/osate/ge/internal/services/DiagramService.java +++ b/ge/org.osate.ge/src/org/osate/ge/internal/services/DiagramService.java @@ -19,6 +19,8 @@ import org.osate.ge.internal.diagram.runtime.RelativeBusinessObjectReference; import org.osate.ge.internal.ui.editor.AgeDiagramEditor; +import com.google.common.collect.ImmutableSet; + /** * Service for finding, opening, and creating diagrams. Registered as an Eclipse service. * @@ -98,6 +100,8 @@ default AgeDiagramEditor openOrCreateDiagramForBusinessObject(final Object bo) { interface ReferenceCollection { void update(UpdatedReferenceValueProvider newReferenceValues); + + ImmutableSet getRelatedDiagramFiles(); } // Used to provide new reference values when updating a reference collection diff --git a/ge/org.osate.ge/src/org/osate/ge/internal/services/impl/DefaultDiagramService.java b/ge/org.osate.ge/src/org/osate/ge/internal/services/impl/DefaultDiagramService.java index e8660c5045e..c4d9334639c 100644 --- a/ge/org.osate.ge/src/org/osate/ge/internal/services/impl/DefaultDiagramService.java +++ b/ge/org.osate.ge/src/org/osate/ge/internal/services/impl/DefaultDiagramService.java @@ -20,6 +20,7 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.e4.core.contexts.IEclipseContext; import org.eclipse.emf.common.util.URI; @@ -28,6 +29,7 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.ui.editor.IDiagramEditorInput; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.LabelProvider; @@ -63,6 +65,8 @@ import org.osate.ge.internal.util.Log; import org.osate.ge.internal.util.NonUndoableToolCommand; +import com.google.common.collect.ImmutableSet; + public class DefaultDiagramService implements DiagramService { private static final QualifiedName LEGACY_PROPERTY_NAME_MODIFICATION_TIMESTAMP = new QualifiedName("org.osate.ge", "diagram_name_modification_stamp"); @@ -500,29 +504,33 @@ public void execute() { final IFile diagramFile = (IFile) key; // Handle closed diagrams - final ResourceSet rs = new ResourceSetImpl(); - final URI diagramUri = URI.createPlatformResourceURI(diagramFile.getFullPath().toString(), - true); - final Resource diagramResource = rs.createResource(diagramUri); - try { - diagramResource.load(Collections.emptyMap()); - if (diagramResource.getContents().size() == 1 - && diagramResource.getContents().get(0) instanceof org.osate.ge.diagram.Diagram) { - updateReferences(updatedReferenceValues, originalCanonicalRefToReferenceMap, - diagramResource, null); - } - } catch (IOException e) { - // Ignore. Continue with next file - } finally { - // Save and unload the resource if it was loaded - if (diagramResource.isLoaded()) { - try { - diagramResource.save(Collections.emptyMap()); - } catch (final IOException e) { - // Ignore. Print stack trace so it will show in the console during development. - e.printStackTrace(); + // Don't attempt to edit read only files. + if (!diagramFile.isReadOnly()) { + + final ResourceSet rs = new ResourceSetImpl(); + final URI diagramUri = URI.createPlatformResourceURI(diagramFile.getFullPath().toString(), + true); + final Resource diagramResource = rs.createResource(diagramUri); + try { + diagramResource.load(Collections.emptyMap()); + if (diagramResource.getContents().size() == 1 + && diagramResource.getContents().get(0) instanceof org.osate.ge.diagram.Diagram) { + updateReferences(updatedReferenceValues, originalCanonicalRefToReferenceMap, + diagramResource, null); + } + } catch (IOException e) { + // Ignore. Continue with next file + } finally { + // Save and unload the resource if it was loaded + if (diagramResource.isLoaded()) { + try { + diagramResource.save(Collections.emptyMap()); + } catch (final IOException e) { + // Ignore. Print stack trace so it will show in the console during development. + e.printStackTrace(); + } + diagramResource.unload(); } - diagramResource.unload(); } } } else { @@ -532,6 +540,36 @@ public void execute() { }); } + @Override + public ImmutableSet getRelatedDiagramFiles() { + final ImmutableSet.Builder diagramFileSetsBuilder = ImmutableSet.builder(); + Display.getDefault().syncExec(() -> { + for (final Entry>> sourceToCanonicalReferenceToReferencesEntry : sourceToCanonicalReferenceToReferencesMap + .entrySet()) { + final Object key = sourceToCanonicalReferenceToReferencesEntry.getKey(); + if (key instanceof AgeDiagramEditor) { + final AgeDiagramEditor editor = (AgeDiagramEditor) key; + final IDiagramEditorInput input = editor.getDiagramEditorInput(); + if(input != null) { + final IResource diagramResource = ResourcesPlugin.getWorkspace().getRoot() + .getFile(new Path(input.getUri().toPlatformString(true))); + if (diagramResource instanceof IFile) { + diagramFileSetsBuilder.add((IFile) diagramResource); + } + } + + } else if (key instanceof IFile) { + final IFile diagramFile = (IFile) key; + diagramFileSetsBuilder.add(diagramFile); + } else { + throw new RuntimeException("Unexpected key: " + key); + } + } + }); + + return diagramFileSetsBuilder.build(); + } + private void updateReferences(final UpdatedReferenceValueProvider newBoReferences, final Map> originalCanonicalRefToReferenceMap, final Resource diagramResource, final DiagramModification diagramModification) { diff --git a/ge/org.osate.ge/src/org/osate/ge/internal/ui/editor/AgeDiagramBehavior.java b/ge/org.osate.ge/src/org/osate/ge/internal/ui/editor/AgeDiagramBehavior.java index 29df597fea1..9d8c7686dcd 100644 --- a/ge/org.osate.ge/src/org/osate/ge/internal/ui/editor/AgeDiagramBehavior.java +++ b/ge/org.osate.ge/src/org/osate/ge/internal/ui/editor/AgeDiagramBehavior.java @@ -83,6 +83,7 @@ import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.internal.EditorSite; import org.eclipse.ui.part.EditorPart; +import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.views.contentoutline.ContentOutline; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; @@ -929,6 +930,13 @@ protected Set save(final TransactionalEditingDomain editingDomain, fin throw new RuntimeException("Unable to retrieve file for resource."); } + final IStatus status = ResourcesPlugin.getWorkspace().validateEdit(new IFile[] { (IFile) resource }, + getParentPart().getSite().getShell()); + if (!status.isOK()) { + StatusManager.getManager().handle(status, StatusManager.SHOW); + return Collections.emptySet(); + } + // Save the file DiagramSerialization.write(getProject(), ageDiagram, getInput().getUri());