blob: 05284936ab60d372a027953c908aff1b3f4c737d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2019 Chalmers | University of Gothenburg, rt-labs and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Chalmers | University of Gothenburg and rt-labs - initial API and implementation and/or initial documentation
* Chalmers | University of Gothenburg - additional features, updated API
*******************************************************************************/
package org.eclipse.capra.ui.plantuml;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.capra.core.adapters.Connection;
import org.eclipse.capra.core.adapters.TraceMetaModelAdapter;
import org.eclipse.capra.core.adapters.TracePersistenceAdapter;
import org.eclipse.capra.core.handlers.IArtifactHandler;
import org.eclipse.capra.core.handlers.IArtifactUnpacker;
import org.eclipse.capra.core.helpers.ArtifactHelper;
import org.eclipse.capra.core.helpers.EMFHelper;
import org.eclipse.capra.core.helpers.ExtensionPointHelper;
import org.eclipse.capra.ui.helpers.SelectionSupportHelper;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPart;
import net.sourceforge.plantuml.eclipse.utils.DiagramTextProvider;
import net.sourceforge.plantuml.eclipse.views.PlantUmlView;
/**
* Provides PlantUML with a string representation of elements connected by trace
* links.
*
* @author Anthony Anjorin, Salome Maro, Jan-Philipp Steghöfer
*/
public class DiagramTextProviderHandler implements DiagramTextProvider {
private EObject artifactModel = null;
@Override
public String getDiagramText(IEditorPart editor, ISelection input) {
return (getDiagramText((IWorkbenchPart) editor, input));
}
@Override
public String getDiagramText(IViewPart view, ISelection input) {
return (getDiagramText((IWorkbenchPart) view, input));
}
public String getDiagramText(IWorkbenchPart part, ISelection input) {
List<Object> selectedModels = new ArrayList<>();
if (part.getSite().getSelectionProvider() != null) {
selectedModels.addAll(SelectionSupportHelper
.extractSelectedElements(part.getSite().getSelectionProvider().getSelection(), part));
}
return getDiagramText(selectedModels, Optional.of(part));
}
@SuppressWarnings("unchecked")
public String getDiagramText(List<Object> selectedModels, Optional<IWorkbenchPart> part) {
if (selectedModels == null || selectedModels.size() < 1) {
return VisualizationHelper.createMatrix(null, artifactModel, null, null, true);
}
List<Connection> traces = new ArrayList<>();
List<EObject> selectedEObjects = new ArrayList<>();
EObject traceModel = null;
TracePersistenceAdapter persistenceAdapter = ExtensionPointHelper.getTracePersistenceAdapter().get();
TraceMetaModelAdapter metamodelAdapter = ExtensionPointHelper.getTraceMetamodelAdapter().get();
ResourceSet artifactResourceSet = part.isPresent() ? SelectionSupportHelper.getResourceSet(part.get()) : null;
artifactModel = persistenceAdapter
.getArtifactWrappers(artifactResourceSet != null ? artifactResourceSet : new ResourceSetImpl());
if (selectedModels.size() > 0) {
ArtifactHelper artifactHelper = new ArtifactHelper(artifactModel);
// Get the artifact wrappers for all selected elements
selectedModels.stream().forEach(obj -> {
IArtifactHandler<Object> handler = (IArtifactHandler<Object>) artifactHelper.getHandler(obj)
.orElse(null);
if (handler != null) {
// unpack element in case it is in a container
Object unpackedElement = null;
if (handler instanceof IArtifactUnpacker) {
unpackedElement = IArtifactUnpacker.class.cast(handler).unpack(obj);
} else {
unpackedElement = obj;
}
if (ToggleTransitivityHandler.isTraceViewTransitive()) {
// Make sure we have all relevant EObjects in the list.
selectedEObjects
.addAll(EMFHelper.linearize(handler.createWrapper(unpackedElement, artifactModel)));
} else {
selectedEObjects.add(handler.createWrapper(unpackedElement, artifactModel));
}
}
});
final EObject selectedObject = selectedEObjects.size() > 0 ? selectedEObjects.get(0) : null;
if (selectedObject != null && selectedObject.eResource() != null) {
ResourceSet resourceSet = selectedObject.eResource().getResourceSet();
traceModel = persistenceAdapter.getTraceModel(resourceSet);
List<String> selectedRelationshipTypes = SelectRelationshipsHandler.getSelectedRelationshipTypes();
for (EObject obj : selectedEObjects) {
traces.addAll(getViewableTraceLinks(obj, traceModel, metamodelAdapter, selectedRelationshipTypes));
}
;
if (selectedModels.size() == 1) {
return VisualizationHelper.createNeighboursView(traces, EMFHelper.linearize(selectedObject),
artifactModel);
} else {
// User selected to display a graph with only the selected elements
if (ToggleDisplayGraphHandler.isDisplayGraph()) {
return renderMultiSelectionGraph(traces, selectedEObjects, artifactHelper);
}
}
}
}
// Standard case is to render a traceability matrix, potentially showing a
// message instructing the user to select elements.
return VisualizationHelper.createMatrix(traceModel, artifactModel, selectedEObjects, selectedEObjects,
DisplayInternalLinksHandler.areInternalLinksShown());
}
/**
* Gets the code for a traceability graph that contains all selected objects.
*
* @param traces
* @param selectedEObjects
* @param artifactHelper
* @return
*/
@SuppressWarnings("unchecked")
protected String renderMultiSelectionGraph(List<Connection> traces, List<EObject> selectedEObjects,
ArtifactHelper artifactHelper) {
List<Connection> relevantTraces = new ArrayList<>();
List<EObject> wrappers = new ArrayList<>();
for (Connection connection : traces) {
if (selectedEObjects.contains(connection.getOrigin())
&& selectedEObjects.stream().anyMatch(connection.getTargets()::contains)) {
Connection newConnection = new Connection(connection.getOrigin(), connection.getTargets().stream()
.filter(selectedEObjects::contains).collect(Collectors.toList()), connection.getTlink());
relevantTraces.add(newConnection);
IArtifactHandler<Object> originHandler = (IArtifactHandler<Object>) artifactHelper
.getHandler(connection.getOrigin()).orElse(null);
wrappers.add(originHandler.createWrapper(connection.getOrigin(), artifactModel));
connection.getTargets().stream().filter(selectedEObjects::contains).forEach(t -> {
IArtifactHandler<Object> targetHandler = (IArtifactHandler<Object>) artifactHelper
.getHandler(connection.getOrigin()).orElse(null);
wrappers.add(targetHandler.createWrapper(t, artifactModel));
});
}
}
return VisualizationHelper.createNeighboursView(relevantTraces, wrappers, artifactModel);
}
/**
* Get all trace links for the given object from the provided trace model that
* conform to the selected trace link types.
*
* @param selectedObject
* @param traceModel
* @param metamodelAdapter
* @param selectedRelationshipTypes
* @return
*/
protected List<Connection> getViewableTraceLinks(EObject selectedObject, EObject traceModel,
TraceMetaModelAdapter metamodelAdapter, List<String> selectedRelationshipTypes) {
List<Connection> traces;
if (ToggleTransitivityHandler.isTraceViewTransitive()) {
int transitivityDepth = Integer.parseInt(TransitivityDepthHandler.getTransitivityDepth());
traces = metamodelAdapter.getTransitivelyConnectedElements(selectedObject, traceModel,
selectedRelationshipTypes, transitivityDepth);
} else {
traces = metamodelAdapter.getConnectedElements(selectedObject, traceModel, selectedRelationshipTypes);
}
if (DisplayInternalLinksHandler.areInternalLinksShown() && ToggleTransitivityHandler.isTraceViewTransitive()) {
EObject previousElement = SelectRelationshipsHandler.getPreviousElement();
int transitivityDepth = Integer.parseInt(TransitivityDepthHandler.getTransitivityDepth());
if (previousElement != null) {
String previousElementName = EMFHelper.getNameAttribute(previousElement);
String currentElementName = EMFHelper.getNameAttribute(selectedObject);
if (!previousElementName.equals(currentElementName)) {
SelectRelationshipsHandler.clearPossibleRelationsForSelection();
SelectRelationshipsHandler.emptySelectedRelationshipTypes();
SelectRelationshipsHandler.setPreviousElement(selectedObject);
}
} else {
SelectRelationshipsHandler.setPreviousElement(selectedObject);
}
traces.addAll(metamodelAdapter.getInternalElementsTransitive(selectedObject, traceModel,
selectedRelationshipTypes, transitivityDepth, traces));
} else if (DisplayInternalLinksHandler.areInternalLinksShown()) {
EObject previousElement = SelectRelationshipsHandler.getPreviousElement();
if (previousElement != null) {
String previousElementName = EMFHelper.getNameAttribute(previousElement);
String currentElementName = EMFHelper.getNameAttribute(selectedObject);
if (!previousElementName.equals(currentElementName)) {
SelectRelationshipsHandler.clearPossibleRelationsForSelection();
SelectRelationshipsHandler.emptySelectedRelationshipTypes();
SelectRelationshipsHandler.setPreviousElement(selectedObject);
}
} else {
SelectRelationshipsHandler.setPreviousElement(selectedObject);
}
traces.addAll(metamodelAdapter.getInternalElements(selectedObject, traceModel, selectedRelationshipTypes,
false, 0, traces));
}
List<EObject> links = extractLinksFromTraces(traces);
SelectRelationshipsHandler.addToPossibleRelationsForSelection(links);
return traces;
}
@Override
public boolean supportsEditor(IEditorPart editor) {
return true;
}
@Override
public boolean supportsView(IViewPart part) {
if (part instanceof PlantUmlView) {
return false;
}
return true;
}
@Override
public boolean supportsSelection(ISelection selection) {
return true;
}
private static List<EObject> extractLinksFromTraces(List<Connection> traces) {
List<EObject> links = new ArrayList<>();
for (Connection trace : traces) {
if (!links.contains(trace.getTlink())) {
links.add(trace.getTlink());
}
}
return links;
}
}