| /******************************************************************************* |
| * Copyright (c) 2017, 2020 Obeo. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.emf.ecoretools.design.service; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.reflect.Field; |
| import java.net.MalformedURLException; |
| import java.nio.file.Files; |
| import java.nio.file.StandardCopyOption; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| 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.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenClass; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenEnum; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenEnumLiteral; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenFeature; |
| import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EGenericType; |
| import org.eclipse.emf.ecore.EModelElement; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EParameter; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.ETypedElement; |
| import org.eclipse.emf.ecore.EcoreFactory; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.impl.EStringToStringMapEntryImpl; |
| import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.sirius.diagram.DEdge; |
| import org.eclipse.sirius.diagram.description.EdgeMapping; |
| import org.eclipse.sirius.viewpoint.DSemanticDecorator; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.PlatformUI; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Ordering; |
| |
| /** |
| * The services class used by the Properties View support. |
| */ |
| public class PropertiesServices { |
| |
| protected static final String GEN_MODEL_PACKAGE_NS_URI = "http://www.eclipse.org/emf/2002/GenModel"; |
| |
| public List<EStructuralFeature> removeFeaturesToHide(EObject ctx, Collection<EStructuralFeature> unfiltered) { |
| List<EStructuralFeature> toBeFilterd = Lists.newArrayList(unfiltered); |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_CLASS__ECORE_CLASS); |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_PACKAGE__ECORE_PACKAGE); |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_CLASS__ECORE_CLASS); |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_FEATURE__ECORE_FEATURE); |
| if (ctx instanceof EReference) { |
| toBeFilterd.remove(EcorePackage.Literals.ESTRUCTURAL_FEATURE__DEFAULT_VALUE_LITERAL); |
| } |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_ENUM__ECORE_ENUM); |
| toBeFilterd.remove(GenModelPackage.Literals.GEN_TYPE_PARAMETER__ECORE_TYPE_PARAMETER); |
| |
| PriorityComparator<EStructuralFeature> comparator = new PriorityComparator<EStructuralFeature>(ImmutableList.of( |
| EcorePackage.Literals.ENAMED_ELEMENT__NAME, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE, |
| EcorePackage.Literals.ETYPED_ELEMENT__LOWER_BOUND, EcorePackage.Literals.ETYPED_ELEMENT__UPPER_BOUND, |
| EcorePackage.Literals.ECLASSIFIER__INSTANCE_CLASS_NAME, |
| EcorePackage.Literals.ECLASSIFIER__INSTANCE_TYPE_NAME, |
| EcorePackage.Literals.ESTRUCTURAL_FEATURE__DEFAULT_VALUE_LITERAL, |
| EcorePackage.Literals.EREFERENCE__EOPPOSITE, EcorePackage.Literals.EREFERENCE__CONTAINMENT, |
| EcorePackage.Literals.ESTRUCTURAL_FEATURE__TRANSIENT, |
| EcorePackage.Literals.ESTRUCTURAL_FEATURE__DERIVED)); |
| /* |
| * reorder features |
| */ |
| |
| return Ordering.from(comparator).sortedCopy(toBeFilterd); |
| } |
| |
| class PriorityComparator<T> implements Comparator<T> { |
| private final List<T> values; |
| |
| public PriorityComparator(List<T> values) { |
| this.values = values; |
| } |
| |
| @Override |
| public int compare(T o1, T o2) { |
| int idx1 = values.indexOf(o1); |
| int idx2 = values.indexOf(o2); |
| if (idx1 > -1) { |
| return idx2 > -1 ? idx1 - idx2 : -1; |
| } |
| return idx2 > -1 ? 1 : 0; |
| } |
| } |
| |
| public List<EObject> removeSemanticElementsToHide(EObject ctx, Collection<EObject> unfiltered, |
| DSemanticDecorator selection) { |
| List<EObject> filtered = Lists.newArrayList(); |
| for (EObject eObject : unfiltered) { |
| if (!(eObject instanceof EParameter)) { |
| filtered.add(eObject); |
| } |
| } |
| if (selection instanceof DEdge && ctx instanceof EClass |
| && ((DEdge) selection).getActualMapping() instanceof EdgeMapping |
| && "EC ESupertypes".equals(((EdgeMapping) ((DEdge) selection).getActualMapping()).getName())) { |
| filtered.addAll(((EClass) ctx).getEGenericSuperTypes()); |
| for (EGenericType genType : ((EClass) ctx).getEGenericSuperTypes()) { |
| filtered.addAll(genType.getETypeArguments()); |
| } |
| } |
| |
| return filtered; |
| } |
| |
| public EStringToStringMapEntryImpl getVisibleDocAnnotations(EObject self) { |
| if (self instanceof EModelElement) { |
| EAnnotation eAnnot = ((EModelElement) self).getEAnnotation(GEN_MODEL_PACKAGE_NS_URI); |
| if (eAnnot != null) { |
| for (EStringToStringMapEntryImpl mapEntry : Iterables.filter(eAnnot.getDetails(), |
| EStringToStringMapEntryImpl.class)) { |
| if ("documentation".equals(mapEntry.getKey())) { |
| return mapEntry; |
| } |
| } |
| } |
| |
| } else if (self instanceof EAnnotation) { |
| for (EStringToStringMapEntryImpl mapEntry : Iterables.filter(((EAnnotation) self).getDetails(), |
| EStringToStringMapEntryImpl.class)) { |
| if ("documentation".equals(mapEntry.getKey())) { |
| return mapEntry; |
| } |
| } |
| } else if (self instanceof EStringToStringMapEntryImpl) { |
| if ("documentation".equals(((EStringToStringMapEntryImpl) self).getKey())) { |
| return (EStringToStringMapEntryImpl) self; |
| } |
| } |
| return null; |
| } |
| |
| public EObject setDocAnnotation(EObject self, String value) { |
| if (self instanceof EModelElement) { |
| EAnnotation eAnnot = ((EModelElement) self).getEAnnotation(GEN_MODEL_PACKAGE_NS_URI); |
| if (eAnnot != null) { |
| for (EStringToStringMapEntryImpl mapEntry : Iterables.filter(eAnnot.getDetails(), |
| EStringToStringMapEntryImpl.class)) { |
| if ("documentation".equals(mapEntry.getKey())) { |
| mapEntry.setValue(value); |
| } |
| } |
| } else { |
| EAnnotation newAnnot = EcoreFactory.eINSTANCE.createEAnnotation(); |
| newAnnot.setSource(GEN_MODEL_PACKAGE_NS_URI); |
| newAnnot.getDetails().put("documentation", value); |
| ((EModelElement) self).getEAnnotations().add(newAnnot); |
| } |
| |
| } else if (self instanceof EAnnotation) { |
| for (EStringToStringMapEntryImpl mapEntry : Iterables.filter(((EAnnotation) self).getDetails(), |
| EStringToStringMapEntryImpl.class)) { |
| if ("documentation".equals(mapEntry.getKey())) { |
| mapEntry.setValue(value); |
| } |
| } |
| |
| } else if (self instanceof EStringToStringMapEntryImpl) { |
| if ("documentation".equals(((EStringToStringMapEntryImpl) self).getKey())) { |
| ((EStringToStringMapEntryImpl) self).setValue(value); |
| } |
| } |
| return self; |
| } |
| |
| public boolean isJavaFileGenerated(EObject cur) { |
| URI javaImplementationURI = getJavaImplementationURI(cur); |
| if (javaImplementationURI != null && cur.eResource() != null && cur.eResource().getResourceSet() != null |
| && cur.eResource().getResourceSet().getURIConverter() != null) { |
| return cur.eResource().getResourceSet().getURIConverter().exists(javaImplementationURI, |
| Collections.EMPTY_MAP); |
| } |
| return false; |
| } |
| |
| public String getJavaImplementationPath(EObject cur) { |
| URI targetFile = getJavaImplementationURI(cur); |
| if (targetFile != null) { |
| return targetFile.toString(); |
| } |
| return null; |
| } |
| |
| private URI getJavaImplementationURI(EObject cur) { |
| GenClassifier gClass = null; |
| if (cur instanceof GenFeature) { |
| gClass = ((GenFeature) cur).getGenClass(); |
| } |
| if (cur instanceof GenEnumLiteral) { |
| gClass = ((GenEnumLiteral) cur).getGenEnum(); |
| } |
| if (cur instanceof GenClassifier) { |
| gClass = (GenClassifier) cur; |
| } |
| if (cur instanceof GenEnum) { |
| gClass = (GenClassifier) cur; |
| } |
| String className = ""; |
| if (gClass instanceof GenClass) { |
| className = ((GenClass) gClass).getClassName(); |
| } else if (gClass instanceof GenEnum) { |
| className = ((GenEnum) gClass).getClassifierInstanceName(); |
| } |
| |
| if (gClass != null && gClass.getGenPackage() != null) { |
| String packageName = gClass.getGenPackage().getClassPackageName(); |
| URI targetDirectory = URI.createURI(gClass.getGenPackage().getGenModel().getModelDirectory()) |
| .appendSegments(packageName.split("\\.")); |
| URI targetFile = targetDirectory.appendSegment(className + ".java"); |
| return targetFile; |
| } |
| return null; |
| } |
| |
| public String upperBoundDisplay(ETypedElement host) { |
| if (host.getUpperBound() == -1) { |
| return "*"; |
| } |
| return Integer.valueOf(host.getUpperBound()).toString(); |
| } |
| |
| public ETypedElement setUpperBound(ETypedElement host, String newValue) { |
| if ("*".equals(newValue)) { |
| host.setUpperBound(-1); |
| } else { |
| host.setUpperBound(Integer.valueOf(newValue)); |
| } |
| return host; |
| } |
| |
| public EObject eGetMonoRef(EObject cur, EStructuralFeature ref) { |
| return (EObject) cur.eGet(ref); |
| } |
| |
| public EObject moveUpInContainer(EObject cur) { |
| EObject container = cur.eContainer(); |
| if (container != null) { |
| EList<EObject> siblings = (EList<EObject>) container.eGet(cur.eContainingFeature()); |
| int oldPosition = siblings.indexOf(cur); |
| int newPosition = oldPosition - 1; |
| if (newPosition < 0) { |
| newPosition = 0; |
| } |
| siblings.move(newPosition, cur); |
| } |
| return cur; |
| } |
| |
| public EObject moveDownInContainer(EObject cur) { |
| EObject container = cur.eContainer(); |
| if (container != null) { |
| EList<EObject> siblings = (EList<EObject>) container.eGet(cur.eContainingFeature()); |
| int oldPosition = siblings.indexOf(cur); |
| int newPosition = oldPosition + 1; |
| if (newPosition > siblings.size() - 1) { |
| newPosition = siblings.size() - 1; |
| } |
| siblings.move(newPosition, cur); |
| } |
| return cur; |
| } |
| |
| public boolean isAccessible(String path) { |
| final boolean res; |
| |
| if (path != null) { |
| final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path)); |
| res = file.exists() && file.isAccessible(); |
| } else { |
| res = false; |
| } |
| |
| return res; |
| } |
| |
| public String selectIcon(String targetPath) { |
| final IFile targetFile = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(targetPath)); |
| final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| |
| final FileDialog fileDialog = new FileDialog(shell, SWT.OPEN); |
| fileDialog.setText("Select icon"); |
| fileDialog.setFileName(targetFile.getLocation().toOSString()); |
| final String[] filterExt = { "*.gif", "*.png", "*.jpg", "*.jpeg" }; |
| fileDialog.setFilterExtensions(filterExt); |
| final String source = fileDialog.open(); |
| if (source != null) { |
| try { |
| Files.copy(new File(source).toPath(), targetFile.getLocation().toFile().toPath(), |
| StandardCopyOption.REPLACE_EXISTING); |
| targetFile.refreshLocal(IResource.DEPTH_INFINITE, null); |
| } catch (IOException | CoreException e) { |
| final String message = String.format("An error occurred while copying %s to %s", source, |
| targetFile.getLocation().toFile().toPath().toString()); |
| EcoreToolsDesignPlugin.getPlugin() |
| .log(new Status(IStatus.ERROR, EcoreToolsDesignPlugin.PLUGIN_ID, message, e)); |
| } |
| } |
| |
| removeImageFromCache(ExtendedImageRegistry.INSTANCE, targetFile.getLocation()); |
| |
| return targetPath; |
| } |
| |
| /** |
| * Removes the {@link Image} from the cache used by EEF2 to ensure loading of |
| * the new content. |
| * |
| * @param registry the {@link ExtendedImageRegistry} |
| * @param targetPath the image {@link IPath} |
| */ |
| private void removeImageFromCache(ExtendedImageRegistry registry, IPath targetPath) { |
| try { |
| final ImageDescriptor descriptor = ImageDescriptor |
| .createFromURL(targetPath.toFile().toURI().toURL()); |
| |
| for (Field field : registry.getClass().getDeclaredFields()) { |
| if ("table".equals(field.getName())) { |
| field.setAccessible(true); |
| @SuppressWarnings("unchecked") |
| final Map<Object, Image> table = (Map<Object, Image>) field.get(registry); |
| final Image image = table.remove(descriptor); |
| if (image != null) { |
| image.dispose(); |
| } |
| field.setAccessible(false); |
| break; |
| } |
| } |
| |
| } catch (MalformedURLException | IllegalArgumentException | IllegalAccessException e) { |
| EcoreToolsDesignPlugin.getPlugin() |
| .log(new Status(IStatus.ERROR, EcoreToolsDesignPlugin.PLUGIN_ID, "Couldn't reload icon.", e)); |
| } |
| } |
| |
| } |