blob: 37b6651332b262249d55d41edbcb15dcca4b61a6 [file] [log] [blame]
/**
********************************************************************************
* 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();
}
}