blob: bd9b8b954a3933ffa410e96258f48665782cb6b1 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2017-2020 Robert Bosch GmbH.
*
* 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.emf.viewer.plantuml.builders;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Display;
public class ObjectContentBuilder extends AbstractPlantUMLBuilder {
UISynchronize sync;
public ObjectContentBuilder(UISynchronize sync) {
this.sync = sync;
}
@Override
public BuilderResult generatePlantUML(Object selectedObject) {
if (selectedObject instanceof EList) {
return generatePlantUMLForCollection((EList<?>) selectedObject);
}
return super.generatePlantUML(selectedObject);
}
// NOTE: EClass is an EObject
@Override
public BuilderResult generatePlantUML(final EClass eObject) {
return generatePlantUML((EObject) eObject);
}
@Override
public BuilderResult generatePlantUML(final EObject eObject) {
resetCaches();
final StringBuilder plantuml = new StringBuilder();
plantuml.append("@startuml\n\n");
plantuml.append("' Created by ObjectContentBuilder (" + timestamp() + ")\n\n");
plantuml.append("' ===== Main Object =====\n\n");
buildBuffer(eObject, plantuml);
plantuml.append("\n@enduml");
return new BuilderResult(getId2ObjectMap(), plantuml.toString());
}
public BuilderResult generatePlantUMLForCollection(final EList<?> eList) {
resetCaches();
final StringBuilder plantuml = new StringBuilder();
plantuml.append("@startuml\n\n");
plantuml.append("' Created by ObjectContentBuilder (" + timestamp() + ")\n\n");
plantuml.append("' ===== Main Objects =====\n\n");
createClass(plantuml, eList, null);
for (final Object object : getElementsBasedOnRange(eList)) {
if (object instanceof EObject) {
createClass(plantuml, (EObject) object);
final String name = getName((EObject) object).toString();
plantuml.append("Collection --> " + name);
plantuml.append("\n");
}
}
plantuml.append("\n@enduml");
return new BuilderResult(getId2ObjectMap(), plantuml.toString());
}
private void buildBuffer(final EObject selectedEObj, final StringBuilder plantuml) {
final EList<EStructuralFeature> eStructuralFeatures = selectedEObj.eClass().getEAllStructuralFeatures();
/*- if refs of the EClass are found, then fill the plantUMLBuffer with the appropriate contents */
if (!eStructuralFeatures.isEmpty()) {
createClass(plantuml, selectedEObj);
final List<EStructuralFeature> processedFeatures = new ArrayList<>();
for (final EStructuralFeature eStructuralFeature : eStructuralFeatures) {
final boolean eIsSet = selectedEObj.eIsSet(eStructuralFeature);
if (eIsSet && !processedFeatures.contains(eStructuralFeature)
&& (eStructuralFeature instanceof EReference)) {
processedFeatures.add(eStructuralFeature);
final Object eobj = selectedEObj.eGet(eStructuralFeature);
if (eobj instanceof EObject) {
createClass(plantuml, (EObject) eobj);
final String name = getName((EObject) eobj).toString();
final String relation = ((EReference) eStructuralFeature).isContainment() ? " *-- " : "--> ";
plantuml.append(getName(selectedEObj) + relation + name);
plantuml.append("\n");
} else if (eobj instanceof EList) {
createClass(plantuml, (EList<?>) eobj, eStructuralFeature);
final String relation = ((EReference) eStructuralFeature).isContainment() ? " *-- " : "--> ";
plantuml.append(getName(selectedEObj) + relation + eStructuralFeature.getName());
plantuml.append("\n");
}
}
}
} else {
/*- no references for this EClass are found */
createClass(plantuml, selectedEObj);
}
}
private void createClass(final StringBuilder plantuml, final EList<?> eList, final EStructuralFeature eStructuralFeature) {
final String uuid = getIdForObject(eList);
if (eStructuralFeature != null) {
final String name = eStructuralFeature.getName();
final String typeName = eStructuralFeature.getEType().getName();
plantuml.append("class \"" + name + "\"" + " << (*,#FF7700) EList<" + typeName + "> >>" + " [[" + uuid + "]]");
} else {
plantuml.append("class \"" + "Collection" + "\"" + " << (*,#FF7700) Collection<" + "EList" + "> >>" + " [[" + uuid + "]]");
}
plantuml.append("\n");
}
private void createClass(final StringBuilder plantuml, final EObject selectedEObj) {
final Object name = getName(selectedEObj);
final String className = selectedEObj.eClass().getName();
final String uuid = getIdForObject(selectedEObj);
plantuml.append("class " + name + " << (O,#B4A7E5) " + className + " >>" + " [[" + uuid + "]]");
final EList<EAttribute> eAllAttributes = selectedEObj.eClass().getEAllAttributes();
if (!eAllAttributes.isEmpty()) {
plantuml.append(" {");
final List<EAttribute> processedFeatures = new ArrayList<>();
for (final EAttribute eAttribute : eAllAttributes) {
if (selectedEObj.eIsSet(eAttribute) && !processedFeatures.contains(eAttribute)) {
processedFeatures.add(eAttribute);
plantuml.append("\n ");
plantuml.append(eAttribute.getEType().getName() + " " + eAttribute.getName() + " = " + selectedEObj.eGet(eAttribute));
}
}
plantuml.append("\n}");
}
plantuml.append("\n");
}
private Object getName(final EObject eObject) {
final EStructuralFeature eStructuralFeature = eObject.eClass().getEStructuralFeature("name");
if (eStructuralFeature != null) {
final Object originalName = eObject.eGet(eStructuralFeature);
return "\"" + originalName + "\"";
}
return eObject.eClass().getName() + "__" + eObject.hashCode();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private List<?> getElementsBasedOnRange(final EList<?> eList) {
if (eList.size() > 100) {
if (sync != null) {
sync.syncExec(() -> {
List subList = new ArrayList();
InputDialog inputDialog = new InputDialog(
Display.getDefault().getActiveShell(),
"Element selection dialog",
"There are " + eList.size() + " references. Specify the range for which contents should be represented graphically",
"0-" + (eList.size() - 1),
newText -> (Pattern.matches("(\\d)+\\-(\\d)+", newText))
? null
: "Specify the range in the following way int-int eg. 10-20"
);
int status = inputDialog.open();
if (status == Window.OK) {
String value = inputDialog.getValue();
String[] split = value.split("-");
subList = new ArrayList<>(eList).subList(
Integer.parseInt(split[0]),
Integer.parseInt(split[1]) < eList.size()
? Integer.parseInt(split[1])
: (eList.size() - 1));
} else {
subList = new ArrayList<>(eList).subList(0, 99);
}
eList.clear();
eList.addAll(subList);
});
}
}
return eList;
}
}