| /** |
| ******************************************************************************** |
| * 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; |
| } |
| } |