| /** |
| ******************************************************************************** |
| * Copyright (c) 2018-2022 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.amalthea.model.provider; |
| |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.app4mc.amalthea.model.ActivityGraph; |
| import org.eclipse.app4mc.amalthea.model.AmaltheaPackage; |
| import org.eclipse.app4mc.amalthea.model.AmaltheaServices; |
| import org.eclipse.app4mc.amalthea.model.CallArgument; |
| import org.eclipse.app4mc.amalthea.model.Component; |
| import org.eclipse.app4mc.amalthea.model.ComponentInstance; |
| import org.eclipse.app4mc.amalthea.model.ComponentPort; |
| import org.eclipse.app4mc.amalthea.model.Composite; |
| import org.eclipse.app4mc.amalthea.model.DataDependency; |
| import org.eclipse.app4mc.amalthea.model.DirectionType; |
| import org.eclipse.app4mc.amalthea.model.EnumMode; |
| import org.eclipse.app4mc.amalthea.model.HwAccessElement; |
| import org.eclipse.app4mc.amalthea.model.HwAccessPath; |
| import org.eclipse.app4mc.amalthea.model.HwFeatureCategory; |
| import org.eclipse.app4mc.amalthea.model.HwPathElement; |
| import org.eclipse.app4mc.amalthea.model.IExecutable; |
| import org.eclipse.app4mc.amalthea.model.INamed; |
| import org.eclipse.app4mc.amalthea.model.ISystem; |
| import org.eclipse.app4mc.amalthea.model.InterfaceKind; |
| import org.eclipse.app4mc.amalthea.model.LocalModeLabel; |
| import org.eclipse.app4mc.amalthea.model.LocalModeLabelRef; |
| import org.eclipse.app4mc.amalthea.model.LocalModeValue; |
| import org.eclipse.app4mc.amalthea.model.Mode; |
| import org.eclipse.app4mc.amalthea.model.ModeLabel; |
| import org.eclipse.app4mc.amalthea.model.ModeLabelAccess; |
| import org.eclipse.app4mc.amalthea.model.ModeLiteral; |
| import org.eclipse.app4mc.amalthea.model.ModeLiteralConst; |
| import org.eclipse.app4mc.amalthea.model.ModeValue; |
| import org.eclipse.app4mc.amalthea.model.NumericMode; |
| import org.eclipse.app4mc.amalthea.model.Process; |
| import org.eclipse.app4mc.amalthea.model.ProcessingUnit; |
| import org.eclipse.app4mc.amalthea.model.QualifiedPort; |
| import org.eclipse.app4mc.amalthea.model.Runnable; |
| import org.eclipse.app4mc.amalthea.model.RunnableCall; |
| import org.eclipse.app4mc.amalthea.model.RunnableParameter; |
| import org.eclipse.app4mc.amalthea.model.util.SoftwareUtil; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.UniqueEList; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.edit.provider.ItemPropertyDescriptor; |
| |
| public class CustomPropertyDescriptorService { |
| |
| // Suppress default constructor |
| private CustomPropertyDescriptorService() { |
| throw new IllegalStateException("Utility class"); |
| } |
| |
| // ***************************************************************************** |
| // NeedEntry Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<String> getNeedEntryValuesForKey(final Object object) { |
| final UniqueEList<String> choiceOfValues = new UniqueEList<>(); |
| |
| // get HW feature categories |
| final EClass type = AmaltheaPackage.eINSTANCE.getHwFeatureCategory(); |
| final Collection<EObject> objects = ItemPropertyDescriptor.getReachableObjectsOfType(((EObject) object), type); |
| |
| // empty entry |
| choiceOfValues.add(null); |
| |
| // entries: names of feature categories |
| objects.stream() |
| .map(obj -> ((HwFeatureCategory) obj).getName()) |
| .filter(Objects::nonNull) |
| .sorted() |
| .forEachOrdered(choiceOfValues::add); |
| |
| return choiceOfValues; |
| } |
| |
| // ***************************************************************************** |
| // CallArgument Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<RunnableParameter> getCallArgumentValuesForParameter(final Object object) { |
| if (object instanceof CallArgument) { |
| |
| // *** Parameters of called runnable |
| |
| RunnableCall call = ((CallArgument) object).getContainingCall(); |
| if (call != null && call.getRunnable() != null) { |
| List<RunnableParameter> parameters = call.getRunnable().getParameters(); |
| if (! parameters.isEmpty()) { |
| // build result list |
| UniqueEList<RunnableParameter> choiceOfValues = new UniqueEList<>(); |
| choiceOfValues.add(null); // empty entry at first position |
| choiceOfValues.addAll(parameters); |
| return choiceOfValues; |
| } |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // DataDependency Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<RunnableParameter> getDataDependencyValuesForParameters(final Object object) { |
| if (object instanceof DataDependency) { |
| |
| // *** Parameters (in, inout) of containing runnable |
| |
| final Runnable runnable = ((DataDependency) object).getContainingRunnable(); |
| if (runnable != null) { |
| // build result list |
| final List<RunnableParameter> choiceOfValues = new BasicEList<>(); |
| runnable.getParameters().stream() |
| .filter(e -> e.getDirection() == DirectionType.IN || e.getDirection() == DirectionType.INOUT) |
| .forEachOrdered(choiceOfValues::add); |
| return choiceOfValues; |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| public static Collection<CallArgument> getDataDependencyValuesForCallArguments(final Object object) { |
| if (object instanceof DataDependency) { |
| final DataDependency dependency = (DataDependency) object; |
| |
| // *** CallArguments (out, inout) of calls in the same graph |
| |
| ActivityGraph graph = null; |
| // first: check if a runnable graph is available |
| Runnable runnable = dependency.getContainingRunnable(); |
| if (runnable != null && runnable.getActivityGraph() != null) { |
| graph = runnable.getActivityGraph(); |
| } else { |
| // second: check if a process graph is available |
| Process process = AmaltheaServices.getContainerOfType(dependency, Process.class); |
| if (process != null && process.getActivityGraph() != null) { |
| graph = process.getActivityGraph(); |
| } |
| } |
| |
| if (graph != null) { |
| List<DirectionType> dirList = Arrays.asList(DirectionType.OUT, DirectionType.INOUT); |
| return SoftwareUtil.collectActivityGraphItems(graph, null, RunnableCall.class).stream() |
| .map(RunnableCall::getArguments) |
| .flatMap(Collection::stream) |
| .filter(arg -> arg.getParameter() != null) |
| .filter(arg -> dirList.contains(arg.getParameter().getDirection())) |
| .collect(Collectors.toList()); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // private helper methods for modes |
| // ***************************************************************************** |
| |
| private static Collection<String> collectModeValueStrings(Mode mode) { |
| // Identify mode and possible values |
| |
| if (mode instanceof NumericMode) return null; // standard editor |
| |
| if (mode instanceof EnumMode) { |
| return ((EnumMode) mode).getLiterals().stream() |
| .map(INamed::getName) |
| .filter(Objects::nonNull) |
| .collect(Collectors.toList()); |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // ModeValue Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<String> getValuesForModeValue(final Object object) { |
| if (object instanceof ModeValue) { |
| ModeLabel label = ((ModeValue) object).getLabel(); |
| |
| if (label != null) { |
| return collectModeValueStrings(label.getMode()); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // ModeLabel Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<String> getInitialValuesForModeLabel(final Object object) { |
| if (object instanceof ModeLabel) { |
| return collectModeValueStrings(((ModeLabel) object).getMode()); |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // ModeLabelAccess Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<String> getValuesForModeLabelAccess(final Object object) { |
| if (object instanceof ModeLabelAccess) { |
| ModeLabel label = ((ModeLabelAccess) object).getData(); |
| |
| if (label != null) { |
| return collectModeValueStrings(label.getMode()); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // LocalModeLabel Default Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<String> getDefaultValuesForLocalModeLabel(final Object object) { |
| if (object instanceof LocalModeLabel) { |
| return collectModeValueStrings(((LocalModeLabel) object).getMode()); |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // ModeLiteralConst Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<ModeLiteral> getValuesForModeLiteralConst(final Object object) { |
| if (object instanceof ModeLiteralConst) { |
| LocalModeValue container = AmaltheaServices.getContainerOfType((ModeLiteralConst) object, LocalModeValue.class); |
| |
| if (container != null && container.getLabel() != null) { |
| Mode mode = container.getLabel().getMode(); |
| |
| if (mode instanceof EnumMode) { |
| return ((EnumMode) mode).getLiterals().stream() |
| .filter(Objects::nonNull) |
| .collect(Collectors.toList()); |
| } |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // private helper methods for local mode labels |
| // ***************************************************************************** |
| |
| private static Collection<LocalModeLabel> getLocalLabelsOfExecutable(final IExecutable executable) { |
| if (executable != null) { |
| List<LocalModeLabel> choices = new BasicEList<>(); |
| choices.addAll(executable.getLocalLabels()); |
| return choices; |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // LocalModeValue Label Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<LocalModeLabel> getLabelsForLocalModeValue(final Object object) { |
| if (object instanceof LocalModeValue) { |
| LocalModeValue localModeValue = (LocalModeValue) object; |
| |
| if (localModeValue.eContainer() instanceof RunnableCall) { |
| // context of a runnable call -> get local labels of called runnable |
| Runnable runnable = ((RunnableCall) localModeValue.eContainer()).getRunnable(); |
| return getLocalLabelsOfExecutable(runnable); |
| } else { |
| // local executable context |
| IExecutable executable = AmaltheaServices.getContainerOfType(localModeValue, IExecutable.class); |
| return getLocalLabelsOfExecutable(executable); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // LocalModeLabelRef Value Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<LocalModeLabel> getValuesForLocalModeLabelRef(final Object object) { |
| if (object instanceof LocalModeLabelRef) { |
| IExecutable executable = AmaltheaServices.getContainerOfType((LocalModeLabelRef) object, IExecutable.class); |
| return getLocalLabelsOfExecutable(executable); |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // HwAccessPath Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<HwPathElement> filterValuesForPathElements(final Object object, final Collection<?> choices) { |
| if (object instanceof HwAccessPath) { |
| HwAccessElement accessElement = ((HwAccessPath) object).getContainingAccessElement(); |
| |
| if (accessElement != null) { |
| ProcessingUnit source = accessElement.getSource(); |
| |
| return choices.stream() |
| .filter(HwPathElement.class::isInstance) |
| .map (HwPathElement.class::cast) |
| .filter(e -> e != source) // remove source |
| .collect(Collectors.toList()); |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| // ***************************************************************************** |
| // private helper methods for components |
| // ***************************************************************************** |
| |
| private static Component getComponent(final QualifiedPort qualPort) { |
| if (qualPort.getInstance() == null) { |
| // Get container (Composite only, System has no ports) |
| return AmaltheaServices.getContainerOfType(qualPort, Composite.class); |
| } else { |
| // Get type of instance (Component) |
| return qualPort.getInstance().getType(); |
| } |
| } |
| |
| // ***************************************************************************** |
| // QualifiedPort Property Descriptors |
| // ***************************************************************************** |
| |
| public static Collection<ComponentInstance> getValuesForComponentInstance(final Object object) { |
| if (object instanceof QualifiedPort) { |
| // Get container (System or Composite) |
| ISystem container = AmaltheaServices.getContainerOfType((EObject) object, ISystem.class); |
| |
| if (container != null) { |
| List<ComponentInstance> choices = new BasicEList<>(); |
| choices.add(null); // represents the containing component |
| choices.addAll(container.getComponentInstances()); |
| return choices; |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| public static Collection<ComponentPort> getValuesForComponentPort(final Object object) { |
| if (object instanceof QualifiedPort) { |
| QualifiedPort qPort = (QualifiedPort) object; |
| Component component = getComponent(qPort); |
| if (component != null) { |
| List<ComponentPort> choices = new BasicEList<>(); |
| choices.add(null); |
| choices.addAll(filterPortList(component.getPorts(), qPort)); |
| return choices; |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| private static List<ComponentPort> filterPortList(final List<ComponentPort> ports, final QualifiedPort qualPort) { |
| final boolean isInnerPort = (qualPort.getInstance() != null); |
| final List<InterfaceKind> provideList = Arrays.asList( |
| InterfaceKind.PROVIDES, InterfaceKind.PROVIDES_REQUIRES, InterfaceKind._UNDEFINED_); |
| final List<InterfaceKind> requireList = Arrays.asList( |
| InterfaceKind.REQUIRES, InterfaceKind.PROVIDES_REQUIRES, InterfaceKind._UNDEFINED_); |
| |
| EStructuralFeature feature = qualPort.eContainingFeature(); |
| AmaltheaPackage amPackage = AmaltheaPackage.eINSTANCE; |
| |
| if (amPackage.getConnector_SourcePort().equals(feature)) { |
| if (isInnerPort) { |
| return ports.stream().filter(e -> provideList.contains(e.getKind())).collect(Collectors.toList()); |
| } else { |
| return ports.stream().filter(e -> requireList.contains(e.getKind())).collect(Collectors.toList()); |
| } |
| } |
| |
| if (amPackage.getConnector_TargetPort().equals(feature)) { |
| if (isInnerPort) { |
| return ports.stream().filter(e -> requireList.contains(e.getKind())).collect(Collectors.toList()); |
| } else { |
| return ports.stream().filter(e -> provideList.contains(e.getKind())).collect(Collectors.toList()); |
| } |
| } |
| |
| if (amPackage.getISystem_GroundedPorts().equals(feature)) { |
| if (isInnerPort) { |
| return ports; |
| } else { |
| return Collections.emptyList(); |
| } |
| } |
| |
| return Collections.emptyList(); |
| } |
| |
| } |