diff options
author | Jan Belle | 2018-11-30 15:06:05 +0000 |
---|---|---|
committer | Jan Belle | 2018-11-30 15:08:24 +0000 |
commit | eeb14aa72ee42d6b320d168c42a8fea8b99a2bca (patch) | |
tree | 61203109e549d250b01cb3c6eda6f85c073c14bd | |
parent | 39368e710c8176233a272cd63396811f50301bd6 (diff) | |
download | org.eclipse.etrice-eeb14aa72ee42d6b320d168c42a8fea8b99a2bca.tar.gz org.eclipse.etrice-eeb14aa72ee42d6b320d168c42a8fea8b99a2bca.tar.xz org.eclipse.etrice-eeb14aa72ee42d6b320d168c42a8fea8b99a2bca.zip |
[generator.doc] Rewrite documentation generator to produce asciidoc
Bug 541028
Change-Id: I886faca672ef9896cd130d866204440f970d48dd
8 files changed, 520 insertions, 726 deletions
diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/Main.java b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/Main.java index fdeb85099..ac103df2d 100644 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/Main.java +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/Main.java @@ -25,7 +25,6 @@ import org.eclipse.etrice.generator.base.logging.ILogger; import org.eclipse.etrice.generator.doc.gen.InstanceDiagramGen; import org.eclipse.etrice.generator.doc.gen.MainGen; import org.eclipse.etrice.generator.doc.setup.GeneratorModule; -import org.eclipse.etrice.generator.doc.setup.DocGeneratorOptions; import com.google.inject.Inject; @@ -47,24 +46,13 @@ public class Main extends AbstractGenerator { protected InstanceDiagramGen instanceDiagramGenerator; protected int runGenerator(List<Resource> resources, Arguments arguments, IGeneratorFileIO fileIO, ILogger logger) { - Root genModel = createGeneratorModel(resources, arguments, logger); if (diagnostician.isFailed() || genModel==null) { logger.logError("errors during build of generator model"); return GENERATOR_ERROR; } - logger.logInfo("-- starting code generation"); - mainGenerator.doGenerate(genModel.eResource()); - - if (arguments.get(DocGeneratorOptions.GEN_INST_DIAG)) { - instanceDiagramGenerator.doGenerate(genModel); - } - - if (diagnostician.isFailed()) { - logger.logError("errors during code generation"); - return GENERATOR_ERROR; - } + mainGenerator.doGenerate(genModel, arguments, fileIO); return GENERATOR_OK; } diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/AsciiDocGen.xtend b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/AsciiDocGen.xtend new file mode 100644 index 000000000..934871064 --- /dev/null +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/AsciiDocGen.xtend @@ -0,0 +1,482 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * CONTRIBUTORS: + * Thomas Jung, Thomas Schuetz (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.generator.doc.gen + +import com.google.inject.Inject +import com.google.inject.Singleton +import java.util.List +import org.eclipse.etrice.core.common.base.Documentation +import org.eclipse.etrice.core.fsm.fSM.State +import org.eclipse.etrice.core.genmodel.etricegen.Root +import org.eclipse.etrice.core.room.ActorClass +import org.eclipse.etrice.core.room.Attribute +import org.eclipse.etrice.core.room.CompoundProtocolClass +import org.eclipse.etrice.core.room.DataClass +import org.eclipse.etrice.core.room.EnumerationType +import org.eclipse.etrice.core.room.LogicalSystem +import org.eclipse.etrice.core.room.Port +import org.eclipse.etrice.core.room.ProtocolClass +import org.eclipse.etrice.core.room.RoomClass +import org.eclipse.etrice.core.room.RoomModel +import org.eclipse.etrice.core.room.StandardOperation +import org.eclipse.etrice.core.room.SubSystemClass +import org.eclipse.etrice.core.room.util.RoomHelpers +import org.eclipse.etrice.generator.base.io.IGeneratorFileIO +import org.eclipse.etrice.generator.fsm.base.CodegenHelpers +import org.eclipse.etrice.core.room.GeneralProtocolClass +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.documentation.IEObjectDocumentationProvider +import org.eclipse.etrice.core.fsm.fSM.StateGraph + +@Singleton +class AsciiDocGen { + + @Inject extension RoomHelpers + @Inject extension CodegenHelpers + @Inject extension IEObjectDocumentationProvider + + def doGenerate(Root root, IGeneratorFileIO fileIO, boolean includeImages) { + val packages = root.models.groupBy[name].entrySet.map[new RoomPackage(key, value)].sortBy[name] + fileIO.generateFile("doc.adoc", generateSingleDoc(packages, includeImages)) + } + + def generateSingleDoc(Iterable<RoomPackage> packages, boolean includeImages) ''' + = Model Documentation + generated by eTrice + {docdatetime} + :toc: left + :toclevels: 2 + :table-caption!: + «IF !packages.empty» + + .Room Packages + «FOR pkg: packages» + * «crossReference(pkg.name)» + «ENDFOR» + «ENDIF» + «FOR pkg: packages» + + «generatePackageDoc(pkg)» + «FOR en: pkg.enumerationTypes» + + «en.generateEnumerationDoc» + «ENDFOR» + «FOR dc: pkg.dataClasses» + + «dc.generateDataDoc» + «ENDFOR» + «FOR pc: pkg.protocolClasses» + + «pc.generateProtocolDoc» + «ENDFOR» + «FOR sys: pkg.systems» + + «sys.generateLogicalSystemDoc(includeImages)» + «ENDFOR» + «FOR subSys: pkg.subSystemClasses» + + «subSys.generateSubSystemDoc(includeImages)» + «ENDFOR» + «FOR ac: pkg.actorClasses» + + «ac.generateActorDoc(includeImages)» + «ENDFOR» + «ENDFOR» + ''' + + def private generatePackageDoc(RoomPackage pkg) { + ''' + «defineAnchor(pkg.name)» + == «pkg.name» + «IF !pkg.systems.empty» + + .Logical System Classes + |=== + | Name | Description + «FOR s : pkg.systems» + + | «crossReference(s)» + | «s.shortDocText» + «ENDFOR» + |=== + «ENDIF» + «IF !pkg.subSystemClasses.empty» + + .Subsystem Classes + |=== + | Name | Description + «FOR s : pkg.subSystemClasses» + + | «crossReference(s)» + | «s.shortDocText» + «ENDFOR» + |=== + «ENDIF» + «IF !pkg.protocolClasses.empty» + + .ProtocolClasses + |=== + | Name | Description + «FOR c : pkg.protocolClasses» + + | «crossReference(c)» + | «c.shortDocText» + «ENDFOR» + |=== + «ENDIF» + «IF !pkg.enumerationTypes.empty» + + .Enumeration Types + |=== + | Name | Description + «FOR e : pkg.enumerationTypes» + + | «crossReference(e)» + | «e.shortDocText» + «ENDFOR» + |=== + «ENDIF» + «IF !pkg.dataClasses.empty» + + .Data Classes + |=== + | Name | Description + «FOR c : pkg.dataClasses» + + | «crossReference(c)» + | «c.shortDocText» + «ENDFOR» + |=== + «ENDIF» + «IF !pkg.actorClasses.empty» + + .Actor Classes + |=== + | Name | Description + «FOR c : pkg.actorClasses» + + | «crossReference(c)» + | «c.shortDocText» + «ENDFOR» + |=== + «ENDIF» + ''' + } + + def private generateLogicalSystemDoc(LogicalSystem system, boolean includeImages) { + ''' + «defineAnchor(system)» + === «system.name» + + «system.docText» + «IF includeImages» + + «includeImage(system.name + "_instanceTree.jpg")» + «ENDIF» + ''' + } + + def private generateSubSystemDoc(SubSystemClass ssc, boolean includeImages) ''' + «defineAnchor(ssc)» + === «ssc.name» + + «ssc.docText» + «IF includeImages» + + «includeImage(ssc.name + "_structure.jpg")» + «ENDIF» + ''' + + def private generateEnumerationDoc(EnumerationType en) ''' + «defineAnchor(en)» + === «en.name» + + «en.docText» + + «IF en.primitiveType !== null» + The literals of this enumeration are based on PrimitiveType «en.primitiveType.name». + «ELSE» + The literals of this enumeration are of type int. + «ENDIF» + + .Literals + |=== + | Name | Value | Hex Value | Binary Value + «FOR lit: en.literals» + + | «lit.name» + | «lit.literalValue» + | 0x«Long.toHexString(lit.literalValue)» + | «Long.toBinaryString(lit.literalValue)» + «ENDFOR» + |=== + ''' + + def private generateDataDoc(DataClass dc) ''' + «defineAnchor(dc)» + === «dc.name» + + «dc.docText» + + «dc.attributes.generateAttributesDoc» + «IF !dc.operations.empty» + + «dc.operations.generateOperationsDoc» + «ENDIF» + ''' + + def private dispatch generateProtocolDoc(ProtocolClass pc) ''' + «defineAnchor(pc)» + === «pc.name» + + «pc.docText» + «IF !pc.allIncomingMessages.empty» + + .Incoming Messages + |=== + | Message | Type | Description + «FOR ims : pc.allIncomingMessages» + + | «ims.name» + | «IF ims.data !== null»«ims.data.refType.type.name»«ELSE»void«ENDIF» + | «ims.docText» + «ENDFOR» + |=== + «ENDIF» + «IF !pc.allOutgoingMessages.empty» + + .Outgoing Messages + |=== + | Message | Type | Description + «FOR oms : pc.allOutgoingMessages» + + | «oms.name» + | «IF oms.data !== null»«oms.data.refType.type.name»«ELSE»void«ENDIF» + | «oms.docText» + «ENDFOR» + |=== + «ENDIF» + ''' + + def private dispatch generateProtocolDoc(CompoundProtocolClass pc) ''' + «defineAnchor(pc)» + === «pc.name» + + «pc.docText» + + .Sub Protocols + |=== + | Name | Protocol + «FOR sub : pc.subProtocols» + + | «sub.name» + | «sub.protocol.name» + «ENDFOR» + |=== + ''' + + def private generateActorDoc(ActorClass ac, boolean includeImages) ''' + «defineAnchor(ac)» + === «ac.name» + + «ac.docText» + + ==== Structure + «IF includeImages» + + «includeImage(ac.name + "_structure.jpg")» + «ENDIF» + «IF !ac.allPorts.empty» + + «generatePortDoc(ac)» + «ENDIF» + «IF !ac.attributes.empty» + + «ac.attributes.generateAttributesDoc» + «ENDIF» + «IF ac.hasNonEmptyStateMachine || !ac.operations.empty || ac.isBehaviorAnnotationPresent("BehaviorManual")» + + ==== Behavior + «IF !ac.operations.empty» + + «ac.operations.generateOperationsDoc» + «ENDIF» + «IF ac.isBehaviorAnnotationPresent("BehaviorManual")» + + The behavior for ActorClass «ac.name» is implemented manually. + «ELSEIF ac.hasNonEmptyStateMachine» + + «generateFsmDoc(ac, includeImages)» + «ENDIF» + «ENDIF» + ''' + + def private generateFsmDoc(ActorClass ac, boolean includeImages) ''' + .State Machine + Top Level State:: + «generateStateGraphDoc(ac, ac.stateMachine, includeImages, 1)» + ''' + + def private CharSequence generateStateGraphDoc(ActorClass ac, StateGraph stateGraph, boolean includeImages, int depth) { + val statePath = if(stateGraph.eContainer instanceof State) "_" + (stateGraph.eContainer as State).genStatePathName else "" + ''' + «IF includeImages» + «includeImage(ac.name + statePath + "_behavior.jpg")» + «ENDIF» + «FOR state: stateGraph.states» + «state.name»::«fill(':', depth)» + «state.docText» + «IF !state.leaf» + «generateStateGraphDoc(ac, state.subgraph, includeImages, depth + 1)» + «ENDIF» + «ENDFOR» + ''' + } + + def private String generatePortDoc(ActorClass ac) ''' + .Ports + |=== + | Name | Protocol | Type | Kind | Multiplicity | Description + «FOR at : ac.allPorts» + + | «at.name» + | «at.protocol.name» + | «at.type» + | «at.kind» + | «at.multAsText» + | «at.docText» + «ENDFOR» + |=== + ''' + + def private generateAttributesDoc(List<Attribute> attributes) ''' + .Attributes + |=== + | Name | Type | Description + «FOR at : attributes» + + | «at.name» + | «at.type.type.name» + | «at.docText» + «ENDFOR» + |=== + ''' + + def private generateOperationsDoc(List<StandardOperation> operations) ''' + .Operations + |=== + | Name | Return type | Arguments | Description + «FOR op : operations SEPARATOR '\n'» + + |«op.name» + | «IF op.returnType !== null»«op.returnType.type.name»«ELSE»void«ENDIF» + | «FOR pa : op.arguments SEPARATOR ", "»«pa.name»: «pa.refType.type.name»«ENDFOR» + | «op.docText» + «ENDFOR» + |=== + ''' + + def private getType(Port p) { + if (p.conjugated) "conjugated" else "regular" + } + + def private getKind(Port p) { + if (p.internal) "internal" + else if (p.external) "external" + else if (p.relay) "relay" + else "?" + } + + def private String getMultAsText(Port p) { + if(p.multiplicity == -1) "*" + else p.multiplicity.toString + } + + def private getDocText(EObject object) { + val eClass = object.eClass; + val feature = eClass.getEStructuralFeature("docu") + if(feature !== null) { + val docu = object.eGet(feature) as Documentation + if(docu !== null) { + return String.join('\n', docu.lines) + } + } + + val docu = object.documentation + if(docu !== null) docu else "" + } + + def private getShortDocText(EObject object) { + val docText = object.docText + val index = docText.indexOf('\n') + if(index != -1) docText.subSequence(0, index) else docText + } + + def private includeImage(String filename) { + '''image:«filename»[]''' + } + + def private static crossReference(RoomClass rc) { + crossReference(rc.anchor) + } + + def private static crossReference(CharSequence anchor) { + '''<<«anchor»>>''' + } + + def private static defineAnchor(RoomClass rc) { + defineAnchor(rc.anchor) + } + + def private static defineAnchor(CharSequence anchor) { + '''[[«anchor»]]''' + } + + def private static getAnchor(RoomClass rc) { + '''«(rc.eContainer as RoomModel).name».«rc.name»''' + } + + def private static String fill(char c, int length) { + val builder = new StringBuilder(length) + for(var i = 0; i < length; i++) { + builder.append(c) + } + builder.toString + } + + private static class RoomPackage { + + public final String name + public final Iterable<LogicalSystem> systems + public final Iterable<SubSystemClass> subSystemClasses + public final Iterable<GeneralProtocolClass> protocolClasses + public final Iterable<EnumerationType> enumerationTypes + public final Iterable<DataClass> dataClasses + public final Iterable<ActorClass> actorClasses + + private new(String name, Iterable<RoomModel> models) { + this.name = name + + systems = models.map[it.systems].flatten.sortBy[name] + subSystemClasses = models.map[it.subSystemClasses].flatten.sortBy[name] + protocolClasses = models.map[it.protocolClasses].flatten.sortBy[name] + enumerationTypes = models.map[it.enumerationTypes].flatten.sortBy[name] + dataClasses = models.map[it.dataClasses].flatten.sortBy[name] + actorClasses = models.map[it.actorClasses].flatten.sortBy[name] + } + + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/DocGen.xtend b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/DocGen.xtend deleted file mode 100644 index 3bdff414c..000000000 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/DocGen.xtend +++ /dev/null @@ -1,610 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 protos software gmbh (http://www.protos.de). - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * CONTRIBUTORS: - * Thomas Jung, Thomas Schuetz (initial contribution) - * - *******************************************************************************/ - -package org.eclipse.etrice.generator.doc.gen - -import com.google.inject.Inject -import com.google.inject.Singleton -import java.util.List -import java.util.Set -import org.eclipse.etrice.core.common.base.Documentation -import org.eclipse.etrice.core.fsm.fSM.State -import org.eclipse.etrice.core.genmodel.etricegen.Root -import org.eclipse.etrice.core.room.ActorClass -import org.eclipse.etrice.core.room.Attribute -import org.eclipse.etrice.core.room.CompoundProtocolClass -import org.eclipse.etrice.core.room.DataClass -import org.eclipse.etrice.core.room.EnumerationType -import org.eclipse.etrice.core.room.LogicalSystem -import org.eclipse.etrice.core.room.Port -import org.eclipse.etrice.core.room.ProtocolClass -import org.eclipse.etrice.core.room.RoomClass -import org.eclipse.etrice.core.room.RoomModel -import org.eclipse.etrice.core.room.StandardOperation -import org.eclipse.etrice.core.room.SubSystemClass -import org.eclipse.etrice.core.room.util.RoomHelpers -import org.eclipse.etrice.generator.base.io.IGeneratorFileIO -import org.eclipse.etrice.generator.base.logging.ILogger -import org.eclipse.etrice.generator.fsm.base.CodegenHelpers - -@Singleton -class DocGen { - - @Inject extension RoomHelpers - @Inject extension CodegenHelpers - @Inject IGeneratorFileIO fileIO - @Inject ILogger logger - - val IMGDIR_DEFAULT = "./images" - val IMGWIDTH_DEFAULT = "1.0\\textwidth" - - static class DocGenContext { - val RoomModel model - - new(Root r, RoomModel m) { - model = m - } - - } - - def doGenerate(Root root) { - for (model: root.models) { - val ctx = new DocGen.DocGenContext(root,model) - var file = model.name+".tex" - val Set<RoomModel> referencedModels = newHashSet - logger.logInfo("generating LaTeX documentation: '"+file+"'") - - // Save documentation fragments for RoomModel children - model.systems.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.systems.forEach[referencedModels.addAll(root.getReferencedModels(it))] - model.subSystemClasses.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.subSystemClasses.forEach[referencedModels.addAll(root.getReferencedModels(it))] - model.protocolClasses.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.protocolClasses.forEach[referencedModels.addAll(root.getReferencedModels(it))] - model.enumerationTypes.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.enumerationTypes.forEach[referencedModels.addAll(root.getReferencedModels(it))] - model.dataClasses.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.dataClasses.forEach[referencedModels.addAll(root.getReferencedModels(it))] - model.actorClasses.forEach[generateDoc(ctx).saveAs(model.name+docFragmentName)] - model.actorClasses.forEach[referencedModels.addAll(root.getReferencedModels(it))] - - // Save top-level documentation for RoomModel - generateModelDoc(ctx, referencedModels).saveAs(file) - -// logger.logInfo("main path "+model.docGenerationTargetPath) -// referencedModels.forEach[logger.logInfo("ref path "+docGenerationTargetPath+" - " -// +RelativePathHelpers.getRelativePath( -// model.docGenerationTargetPath.removeLast, docGenerationTargetPath.removeLast, true) -// )] - } - } - - def package removeLast(String str) { - str.substring(0, str.length-1) - } - - def package appendIfNotEmpty(String txt, String suffix) { - if (txt.empty) - txt - else - txt+suffix - } - - def private generateModelDoc(DocGen.DocGenContext ctx, Set<RoomModel> referencedModels) { - var model = ctx.model - ''' - \documentclass[titlepage]{article} - \usepackage{import} - \usepackage{graphicx} - \usepackage{xr} - \usepackage{hyperref} - \IfFileExists{../doc/userinputs.tex}{\subimport{../doc/}{userinputs.tex}}{} %hook for conditional user-specific inputs, includes, macros, ... - \usepackage[a4paper,text={160mm,255mm},centering,headsep=5mm,footskip=10mm]{geometry} - \usepackage{nonfloat} - \parindent 0pt - \makeatletter - \newcommand\level[1]{% - \ifcase#1\relax\expandafter\chapter\or - \expandafter\section\or - \expandafter\subsection\or - \expandafter\subsubsection\else - \def\next{\@level{#1}}\expandafter\next - \fi} - - \newcommand{\@level}[1]{% - \@startsection{level#1} - {#1} - {\z@}% - {-3.25ex\@plus -1ex \@minus -.2ex}% - {1.5ex \@plus .2ex}% - {\normalfont\normalsize\bfseries}} - - \newdimen\@leveldim - \newdimen\@dotsdim - {\normalfont\normalsize - \sbox\z@{0}\global\@leveldim=\wd\z@ - \sbox\z@{.}\global\@dotsdim=\wd\z@ - } - \newcounter{level4}[subsubsection] - \@namedef{thelevel4}{\thesubsubsection.\arabic{level4}} - \@namedef{level4mark}#1{} - \def\l@section{\@dottedtocline{1}{0pt}{\dimexpr\@leveldim*4+\@dotsdim*1+6pt\relax}} - \def\l@subsection{\@dottedtocline{2}{0pt}{\dimexpr\@leveldim*5+\@dotsdim*2+6pt\relax}} - \def\l@subsubsection{\@dottedtocline{3}{0pt}{\dimexpr\@leveldim*6+\@dotsdim*3+6pt\relax}} - \@namedef{l@level4}{\@dottedtocline{4}{0pt}{\dimexpr\@leveldim*7+\@dotsdim*4+6pt\relax}} - - \count@=4 - \def\@ncp#1{\number\numexpr\count@+#1\relax} - \loop\ifnum\count@<100 - \begingroup\edef\x{\endgroup - \noexpand\newcounter{level\@ncp{1}}[level\number\count@] - \noexpand\@namedef{thelevel\@ncp{1}}{% - \noexpand\@nameuse{thelevel\@ncp{0}}.\noexpand\arabic{level\@ncp{0}}} - \noexpand\@namedef{level\@ncp{1}mark}####1{}% - \noexpand\@namedef{l@level\@ncp{1}}% - {\noexpand\@dottedtocline{\@ncp{1}}{0pt}{\the\dimexpr\@leveldim*\@ncp{5}+\@dotsdim*\@ncp{0}\relax}}}% - \x - \advance\count@\@ne - \repeat - \makeatother - \setcounter{secnumdepth}{100} - \setcounter{tocdepth}{100} - - - \title{«model.name.escapedString» Model Documentation} - \date{\today} - \author{generated by eTrice} - - \begin{document} - - \pagestyle{plain} - \maketitle - \tableofcontents - - \newpage - \listoffigures - \newpage - \section{Model Description} - - «IF !referencedModels.empty» - \section{Referenced Models} - - \begin{itemize} - «FOR refModel : referencedModels.sortBy[name]» -««« «val relPath = RelativePathHelpers.getRelativePath( -««« model.generationTargetPath.removeLast, refModel.generationTargetPath.removeLast, true).appendIfNotEmpty("/")» -««« \item \href{«(relPath.replace("\\", "/")+refModel.name).escapedString».pdf}{«refModel.name.escapedString»} - \item «refModel.name.escapedString» - «ENDFOR» - \end{itemize} - \newpage - «ENDIF» - - «IF !model.systems.empty» - \section{Logical System Classes} - «FOR s : model.systems» - «s.generateImport(model.name)» - «ENDFOR» - \newpage - «ENDIF» - - «IF !model.subSystemClasses.empty» - \section{Subsystem Classes} - «FOR s : model.subSystemClasses» - «s.generateImport(model.name)» - «ENDFOR» - \newpage - «ENDIF» - - «IF !model.protocolClasses.empty» - \section{Protocol Classes} - «FOR c : model.protocolClasses» - «c.generateImport(model.name)» - «ENDFOR» - \newpage - «ENDIF» - - «IF !model.enumerationTypes.empty» - \section{Enumeration Types} - «FOR e : model.enumerationTypes» - «e.generateImport(model.name)» - «ENDFOR» - \newpage - «ENDIF» - - «IF !model.dataClasses.empty» - \section{Data Classes} - «FOR c : model.dataClasses» - «c.generateImport(model.name)» - «ENDFOR» - \newpage - «ENDIF» - - «IF !model.actorClasses.empty» - \section{Actor Classes} - «FOR c : model.actorClasses» - «c.generateImport(model.name)» - «ENDFOR» - «ENDIF» - \end{document} - ''' - } - - def private dispatch generateDoc(LogicalSystem system, DocGen.DocGenContext ctx) { - val filename = system.name + "_instanceTree.jpg" - ''' - \level{2}{«system.name.escapedString»} - «system.docu.generateDocText» - \level{3}{Instance Tree} - «IF ctx.model.fileExists(filename.imagePath).equals("true")» - «includeGraphics(filename.imagePath,IMGWIDTH_DEFAULT,system.name + " Instance Tree")» - «ENDIF» - ''' - } - - def private dispatch generateDoc(SubSystemClass ssc, DocGen.DocGenContext ctx) { - val filename = ssc.name.escapedString + "_structure.jpg" - - ''' - \level{2}{«ssc.name.escapedString»} - «ssc.docu.generateDocText» - \level{3}{Structure} - «IF ctx.model.fileExists(filename.imagePath).equals("true")» - «includeGraphics(filename.imagePath,IMGWIDTH_DEFAULT,ssc.name + " Structure")» - «ENDIF» - ''' - } - - def private dispatch generateDoc(EnumerationType dc, DocGen.DocGenContext ctx) { - ''' - \level{2} {«dc.name.escapedString»} - «dc.docu.generateDocText» - «IF dc.primitiveType!==null» - The literals of this enumeration are based on PrimitiveType «dc.primitiveType.name.escapedString». - «ELSE» - The literals of this enumeration are of type \texttt{int}. - «ENDIF» - \level{3}{Literals} - \begin{tabular}[ht]{|l|r|r|r|} - \hline - \textbf{Name} & \textbf{Value} & \textbf{Hex Value} & \textbf{Binary Value}\\ - «FOR lit: dc.literals» - \hline - «lit.name.escapedString» & «lit.literalValue» & 0x«Long.toHexString(lit.literalValue)» & «Long.toBinaryString(lit.literalValue)»\\ - «ENDFOR» - \hline - \end{tabular} - ''' - } - - def private dispatch generateDoc(DataClass dc, DocGen.DocGenContext ctx) {''' - \level{2} {«dc.name.escapedString»} - «dc.docu.generateDocText» - \level{3}{Attributes} - «dc.attributes.generateAttributesDoc» - - \level{3}{Operations} - «dc.operations.generateOperationsDoc» - ''' - } - - def private dispatch generateDoc(ProtocolClass pc, DocGen.DocGenContext ctx) {''' - \level{2} {«pc.name.escapedString»} - «pc.docu.generateDocText» - «IF !pc.allIncomingMessages.empty» - \level{3}{Incoming Messages} - - \begin{tabular}[ht]{|l|l|p{8cm}|} - \hline - Message & Type & Description\\ - «FOR ims : pc.allIncomingMessages» - \hline - «ims.name.escapedString» & «IF ims.data !== null» «ims.data.refType.type.name.escapedString» «ENDIF» & «ims.docu.generateDocText»\\ - «ENDFOR» - \hline - \end{tabular} - «ENDIF» - «IF !pc.allOutgoingMessages.empty» - \level{3}{Outgoing Messages} - \begin{tabular}[ht]{|l|l|p{8cm}|} - \hline - Message & Type & Description\\ - «FOR oms : pc.allOutgoingMessages» - \hline - «oms.name.escapedString» & «IF oms.data !== null» «oms.data.refType.type.name.escapedString» «ENDIF» & «oms.docu.generateDocText»\\ - «ENDFOR» - \hline - \end{tabular} - «ENDIF» - ''' - } - - def private dispatch generateDoc(CompoundProtocolClass pc, DocGen.DocGenContext ctx) {''' - \level{2} {«pc.name.escapedString»} - «pc.docu.generateDocText» - \level{3}{Sub Protocols} - - \begin{tabular}[ht]{|l|l|} - \hline - \textbf{Name} & \textbf{Protocol}\\ - «FOR sub : pc.subProtocols» - \hline - «sub.name.escapedString» & «sub.protocol.name.escapedString»\\ - «ENDFOR» - \hline - \end{tabular} - ''' - } - - def dispatch private generateDoc(ActorClass ac, DocGen.DocGenContext ctx) { - val filename = ac.name + "_structure.jpg" - ''' - \level{2}{«ac.name.escapedString»} - «ac.docu.generateDocText» - - «IF ctx.model.fileExists(filename.imagePath).equals("true") && (!ac.allInterfaceItems.empty || !ac.actorRefs.empty)» - \level{3}{Structure} - «ac.structureDocu.generateDocText» - «includeGraphics(filename.imagePath,IMGWIDTH_DEFAULT,ac.name + " Structure")» - «ELSEIF ac.structureDocu !== null» - \level{3}{Structure} - «ac.structureDocu.generateDocText» - «ENDIF» - - «IF !ac.allPorts.empty» - \level{3}{Ports} - «generatePortDoc(ac)» - «ENDIF» - - «IF ac.isBehaviorAnnotationPresent("BehaviorManual")» - \level{3}{Behavior} - «ac.behaviorDocu.generateDocText» - The behavior for ActorClass «ac.name» is implemented manually. - «ELSEIF ac.hasNonEmptyStateMachine» - \level{3}{Behavior} - «ac.behaviorDocu.generateDocText» - «generateFsmDoc(ctx.model, ac)» - «ELSEIF ac.behaviorDocu !== null» - \level{3}{Behavior} - «ac.behaviorDocu.generateDocText» - «ENDIF» - - «IF !ac.attributes.empty» - \level{3}{Attributes} - «ac.attributes.generateAttributesDoc» - «ENDIF» - - «IF !ac.operations.empty» - \level{3}{Operations} - «ac.operations.generateOperationsDoc» - «ENDIF» - ''' - } - - def private generateFsmDoc(RoomModel model, ActorClass ac){ - val filename = ac.name + "_behavior.jpg" - ''' - \level{4}{Top Level} - «IF model.fileExists(filename.imagePath).equals("true")» - «includeGraphics(filename.imagePath,IMGWIDTH_DEFAULT,ac.name + " Top State")» - «ENDIF» - - \begin{par} - «FOR s : ac.stateMachine.states» - «IF s.docu !== null» - \textbf{State description} \textit{«s.genStatePathName.replaceAll("_","\\\\_")»}: - \newline - «generateDocText(s.docu)» - \newline\newline - «ENDIF» - «ENDFOR» - - «FOR c : ac.stateMachine.chPoints» - «IF c.docu !== null» - \textbf{Choicepoint description} \textit{«c.name.escapedString»}: - \newline - «generateDocText(c.docu)» - \newline\newline - «ENDIF» - «ENDFOR» - \end{par} - - «FOR s : ac.stateMachine.states» - «IF !s.isLeaf» - «generateStateDoc(model, ac, s)» - «ENDIF» - «ENDFOR» - ''' - } - - def private getType(Port p) { - if (p.conjugated) "conj." else "reg." - } - - def private getKind(Port p) { - if (p.internal) - "internal" - else if (p.external) - "external" - else if (p.relay) - "relay" - else - "?" - } - - def private String getMultAsText(Port p) { - if (p.multiplicity==-1) - "*" - else - p.multiplicity.toString - } - - def private String generatePortDoc(ActorClass ac) { - ''' - \begin{tabular}[ht]{|l|l|l|l|l|p{5cm}|} - \hline - \textbf{Name} & \textbf{Protocol} & \textbf{Type} & \textbf{Kind} & \textbf{Multiplicity} & \textbf{Description}\\ - «FOR at : ac.allPorts» - \hline - «at.name.escapedString» & «at.protocol.name.escapedString» & «at.type» & «at.kind» & «at.multAsText» & «generateDocText(at.docu)»\\ - «ENDFOR» - \hline - \end{tabular} - ''' - } - - def private String generateStateDoc(RoomModel model, ActorClass ac, State state){ - val filename = ac.name + "_" + state.genStatePathName + "_behavior.jpg" - - logger.logInfo("Gen Filename: " + filename); - ''' - \level{4}{Subgraph «state.genStatePathName.replaceAll("_","\\\\_")»} - «IF model.fileExists(filename.imagePath).equals("true")» - «includeGraphics(filename.imagePath,IMGWIDTH_DEFAULT,ac.name + "_" + state.genStatePathName)» - «ENDIF» - - \begin{par} - «FOR s : state.subgraph.states» - «IF s.docu !== null» - \textbf{State description} \textit{«s.genStatePathName.replaceAll("_","\\\\_")»}: - \newline - «generateDocText(s.docu)» - \newline\newline - «ENDIF» - «ENDFOR» - - «FOR c : state.subgraph.chPoints» - «IF c.docu !== null» - \textbf{Choicepoint description} \textit{«c.name.escapedString»}: - \newline - «generateDocText(c.docu)» - \newline\newline - «ENDIF» - «ENDFOR» - \end{par} - - «FOR s : state.subgraph.states» - «IF !s.isLeaf» - «generateStateDoc(model, ac, s)» - «ENDIF» - «ENDFOR» - ''' - } - - def private generateAttributesDoc(List<Attribute> attributes) { - ''' - «IF !attributes.empty» - \begin{tabular}[ht]{|l|l|p{8cm}|} - \hline - \textbf{Name} & \textbf{Type} & \textbf{Description}\\ - «FOR at : attributes» - \hline - «at.name.escapedString» & «at.type.type.name.escapedString» & «generateDocText(at.docu)»\\ - «ENDFOR» - \hline - \end{tabular} - «ENDIF» - ''' - } - - def private generateOperationsDoc(List<StandardOperation> operations) { - ''' - «FOR op : operations» - \begin{tabular}[ht]{|l|l|} - \hline - Name: & «op.name.escapedString»\\ - \hline - ReturnType: & «IF op.returnType !== null»«op.returnType.type.name.escapedString»«ELSE»void«ENDIF»\\ - \hline - Arguments: & «FOR pa : op.arguments SEPARATOR ", "»«pa.name.escapedString»:«pa.refType.type.name.escapedString»«ENDFOR»\\ - «IF op.docu !== null» - \hline - «IF op.docu.toString.length > 85» - \multicolumn{2} {|p{13cm}|} {«generateDocText(op.docu)»}\\ - «ELSE» - \multicolumn{2} {|l|} {«generateDocText(op.docu)»}\\ - «ENDIF» - «ENDIF» - \hline - \end{tabular} - \newline\newline\newline - «ENDFOR» - ''' - } - - def private generateDocText(Documentation doc){ - ''' - «IF doc!==null» - % begin text from user Documentation - «FOR line: doc.lines» - «line.escapedString» - «ENDFOR» - % end text from user Documentation - «ENDIF» - ''' - } - - def private fileExists(RoomModel model, String f){ -// val absPath = model.generationTargetPath + f -// val file = new File(absPath); -// val exist = file.exists(); -// if (exist == true) { -// // File or directory exists -// logger.logInfo("File found ! " + f); -// return "true" -// } else { -// // File or directory does not exist -// logger.logInfo("File not found ! " + f); -// return "false" -// } - - - return "false" - } - - def private includeGraphics(String filename, String width, String caption){ - var latexCaption = caption.replaceAll("_","\\\\_"); - ''' - { - \centering{} - \includegraphics[width=«width»]{«filename»} - \figcaption{«latexCaption»} - } - ''' - } - - def private escapedString(String text) { - text.replace("_","\\_") - } - - def private getImagePath(String filename) { - var filenamei = IMGDIR_DEFAULT + "/" + filename - filenamei = filenamei.replaceAll("\\\\","/") - return filenamei - } - - def private saveAs(CharSequence content, String filename) { - fileIO.generateFile(filename, content) - } - - def private docFragmentName(RoomClass rc) { - rc.name + ".tex" - } - - def private generateImport(RoomClass rc, String dir) - '''«rc.docFragmentName.generateImport(dir)»''' - - def private generateImport(String name, String dir) - '''\subimport*{«dir»/}{«name»}''' -} diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/InstanceDiagramGen.xtend b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/InstanceDiagramGen.xtend index 3011ae551..603c4e8c5 100644 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/InstanceDiagramGen.xtend +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/InstanceDiagramGen.xtend @@ -16,7 +16,6 @@ package org.eclipse.etrice.generator.doc.gen import com.google.inject.Inject import com.google.inject.Singleton -import java.io.File import org.eclipse.etrice.core.genmodel.etricegen.AbstractInstance import org.eclipse.etrice.core.genmodel.etricegen.ActorInstance import org.eclipse.etrice.core.genmodel.etricegen.ActorInterfaceInstance @@ -25,57 +24,36 @@ import org.eclipse.etrice.core.genmodel.etricegen.StructureInstance import org.eclipse.etrice.core.genmodel.etricegen.SystemInstance import org.eclipse.etrice.generator.generic.RoomExtensions -import static java.lang.Runtime.* import org.eclipse.etrice.core.etmap.util.ETMapUtil -import org.eclipse.etrice.generator.base.logging.ILogger import org.eclipse.etrice.generator.base.io.IGeneratorFileIO @Singleton class InstanceDiagramGen { - @Inject extension IGeneratorFileIO fileIO @Inject extension RoomExtensions roomExt - @Inject ILogger logger - def doGenerate(Root root) { - for (model: root.models) { - var path = "images/" - var batchFile = "dot2jpg.bat" - for (sys : root.systemInstances) { - var file = sys.name+"_instanceTree.dot" - fileIO.generateFile("generating instance tree diagram", path + file, root.generate(sys)) - } - fileIO.generateFile(path + batchFile, root.generate2jpg()) - runDot2Jpg(path, batchFile) + def doGenerate(Root root, IGeneratorFileIO fileIO) { + var path = "images/" + for (sys : root.systemInstances) { + var file = sys.name+"_instanceTree.dot" + fileIO.generateFile("generating instance tree diagram", path + file, root.generate(sys)) } } - // generate batch file to convert .dot to .jpg - // dot -Tjpg -oSS.jpg SS.dot - def private generate2jpg(Root root){ - ''' - «FOR sys : root.systemInstances» - dot -Tjpg -o «sys.name»_instanceTree.jpg «sys.name»_instanceTree.dot - «ENDFOR» - ''' - } - - def private generate(Root root, SystemInstance sys) { - ''' - digraph «sys.name» { - rankdir=LR; - node [shape=box]; - «sys.path.getPathName()» [label="«sys.name»\n(«sys.name»)" style=filled color=red]; - «FOR ssi : sys.instances» - «ssi.path.getPathName()» [label="«ssi.name»\n(«ssi.subSystemClass.name»)" style=filled color=yellow]; - «sys.path.getPathName()» -> «ssi.path.getPathName()»; - «FOR ai : ssi.instances» - «instance(ai)» - «ENDFOR» + def private generate(Root root, SystemInstance sys) ''' + digraph «sys.name» { + rankdir=LR; + node [shape=box]; + «sys.path.getPathName()» [label="«sys.name»\n(«sys.name»)" style=filled color=red]; + «FOR ssi : sys.instances» + «ssi.path.getPathName()» [label="«ssi.name»\n(«ssi.subSystemClass.name»)" style=filled color=yellow]; + «sys.path.getPathName()» -> «ssi.path.getPathName()»; + «FOR ai : ssi.instances» + «instance(ai)» «ENDFOR» - } - ''' - } + «ENDFOR» + } + ''' def private String instance(AbstractInstance ai) { val parent = ai.eContainer as StructureInstance @@ -97,17 +75,6 @@ class InstanceDiagramGen { «ENDIF» ''' } - - def private runDot2Jpg(String path, String bat){ - var wdir = new File(path) - try { - val p = getRuntime.exec("cmd /C "+bat, null, wdir) - logger.logInfo(bat+" finished with "+p.waitFor) - } - catch (Exception e) { - e.printStackTrace(); - } - - } + }
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/MainGen.xtend b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/MainGen.xtend index 327be64bc..cfeff6610 100644 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/MainGen.xtend +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/gen/MainGen.xtend @@ -16,28 +16,22 @@ package org.eclipse.etrice.generator.doc.gen import com.google.inject.Inject import com.google.inject.Singleton -import org.eclipse.emf.ecore.resource.Resource import org.eclipse.etrice.core.genmodel.etricegen.Root -import org.eclipse.etrice.generator.generic.PrepareFileSystem +import org.eclipse.etrice.generator.base.io.IGeneratorFileIO +import org.eclipse.etrice.generator.base.args.Arguments + +import static org.eclipse.etrice.generator.doc.setup.DocGeneratorOptions.INCLUDE_IMAGES @Singleton class MainGen { @Inject InstanceDiagramGen instanceDiagramGen - @Inject PrepareFileSystem prepFS - @Inject DocGen docGen - - def void doGenerate(Resource resource) { - prepFS.prepare - for (e: resource.contents){ - if (e instanceof Root) { - doGenerate(e as Root) - } - } - } + @Inject AsciiDocGen docGen - def private void doGenerate(Root e) { - instanceDiagramGen.doGenerate(e); - docGen.doGenerate(e); + def void doGenerate(Root root, Arguments args, IGeneratorFileIO fileIO) { + val includeImages = args.get(INCLUDE_IMAGES) + + instanceDiagramGen.doGenerate(root, fileIO); + docGen.doGenerate(root, fileIO, includeImages); } }
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptions.java b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptions.java index 33a565fba..941e33e4f 100644 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptions.java +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptions.java @@ -25,17 +25,17 @@ public class DocGeneratorOptions extends AbstractGeneratorOptions { public static final String GROUP_ETRICE_DOC = "eTrice Documentation"; - public static final BooleanOption GEN_INST_DIAG = new BooleanOption( + public static final BooleanOption INCLUDE_IMAGES = new BooleanOption( GROUP_ETRICE_DOC, - "genInstDiag", - "generateInstanceDiagram", - "if specified then an instance diagram is created for each subsystem", + "include_images", + "includeImages", + "If specified images are included in the generated documentation", false); @Override public void configure(List<Option<?>> options) { super.configure(options); - options.add(GEN_INST_DIAG); + options.add(INCLUDE_IMAGES); } } diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptionsHelper.java b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptionsHelper.java deleted file mode 100644 index 40c13c615..000000000 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/DocGeneratorOptionsHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* -* Copyright (c) 2018 protos software gmbh (http://www.protos.de). -* All rights reserved. -* -* 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: -* Jan Belle (initial contribution) -* - *******************************************************************************/ - -package org.eclipse.etrice.generator.doc.setup; - -import org.eclipse.etrice.generator.base.AbstractGeneratorOptionsHelper; -import org.eclipse.etrice.generator.base.args.Arguments; - -public class DocGeneratorOptionsHelper extends AbstractGeneratorOptionsHelper { - - public boolean isGenerateInstanceDiagram(Arguments args) { - return args.get(DocGeneratorOptions.GEN_INST_DIAG); - } -} diff --git a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/GeneratorModule.java b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/GeneratorModule.java index c1d09a019..ae4e05482 100644 --- a/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/GeneratorModule.java +++ b/plugins/org.eclipse.etrice.generator.doc/src/org/eclipse/etrice/generator/doc/setup/GeneratorModule.java @@ -17,17 +17,17 @@ package org.eclipse.etrice.generator.doc.setup; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.etrice.core.genmodel.fsm.ICommonDataCalculator; import org.eclipse.etrice.core.genmodel.fsm.IDiagnostician; +import org.eclipse.etrice.core.room.util.CommonDataCalculator; import org.eclipse.etrice.generator.base.EMFSetup; import org.eclipse.etrice.generator.base.GenerationEMFDiagnostician; import org.eclipse.etrice.generator.base.IGenerator; import org.eclipse.etrice.generator.base.ITranslationProvider; import org.eclipse.etrice.generator.base.ModelLoader; import org.eclipse.etrice.generator.base.ModelValidator; -import org.eclipse.etrice.generator.base.io.GeneratorFileIO; import org.eclipse.etrice.generator.base.io.IGeneratorEMFSetup; import org.eclipse.etrice.generator.base.io.IGeneratorResourceLoader; -import org.eclipse.etrice.generator.base.logging.Logger; import org.eclipse.etrice.generator.base.setup.GeneratorName; import org.eclipse.etrice.generator.base.setup.GeneratorOptions; import org.eclipse.etrice.generator.base.validation.IGeneratorResourceValidator; @@ -53,11 +53,10 @@ public class GeneratorModule implements Module { binder.bind(IGenerator.class).to(Main.class); binder.bind(ResourceSet.class).to(ResourceSetImpl.class); - binder.bind(Logger.class).in(Singleton.class); - binder.bind(GeneratorFileIO.class).in(Singleton.class); binder.bind(IDiagnostician.class).to(Diagnostician.class); binder.bind(Diagnostician.class).in(Singleton.class); binder.bind(ITranslationProvider.class).to(DocTranslationProvider.class); + binder.bind(ICommonDataCalculator.class).to(CommonDataCalculator.class); binder.bind(EValidator.Registry.class).toInstance(EValidator.Registry.INSTANCE); binder.bind(org.eclipse.emf.ecore.util.Diagnostician.class).to(GenerationEMFDiagnostician.class).asEagerSingleton(); |