pxDoc extensibility
- Common extensibility tasks on the UI project
- pxDoc - Common Libraries and Plugins
Common extensibility tasks on the UI project
In this section, we will present some of the extensibility capabilities of pxDoc, based on examples:
- Adapt the Command class of the UI project to directly bind variable styles with a stylesheet
- Adapt the generation launching wizard to your needs
Adapt the generation launching wizard
Introduction
You might want to provide many generation parameters for your document generator, and users must be able to feed these generation parameters in the generation wizard (e.g. Title, Company name and Version of the document in the following examples).
You will taylor the generation launching wizard to propose this option
Adapt the Wizard class
First, you will add a page to the wizard by adding some code to the Wizard class
The Wizard class can be found in the src folder of the UI project linked to your generator.
Adapt the following code to your generator name, to add a new page to the generation wizard:
package mygenerator.ui; /** * Wizard class */ public class MyGeneratorWizard extends AbstractMyGeneratorWizard { @Override public void addPages() { super.addPages(); addPage(new OptionPage("Custom Options")); } }
Create a new page in the Wizard
Now, you will create the new Wizard page containing text fields for the required properties in a class named OptionPage.
You will need to provide an implementation for 3 methods of the interface IPxDocWizardPage:
- void fillLauncher(PxDocLauncher pLauncher): this method will be called for every IPxdocWizardPage of the generation wizard, filling your parameter values in the PxDocLauncher object.
- IDialogSettings buildDialogSettings(): builds a IDialogSettings, that can be provided as default options for the next generation.
- void loadDialogSettings(IDialogSettings pSettings): loads the previously built and saved IDialogSettings and initialize page widgets accordingly.
The code below defines the input text fields and send the content as properties to the pxDoc Launcher.
package mygenerator.ui; import org.eclipse.jface.dialogs.DialogSettings; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import fr.pragmaticmodeling.pxdoc.runtime.launcher.PxDocLauncher; import fr.pragmaticmodeling.pxdoc.runtime.ui.eclipse.IPxDocWizardPage; import fr.pragmaticmodeling.pxdoc.runtime.ui.eclipse.wizard.IPxDocWizard; import fr.pragmaticmodeling.pxdoc.runtime.util.PxDocLauncherHelper; /** * Wizard class */ public class OptionPage extends WizardPage implements IPxDocWizardPage { private static final String SETTINGS_ID = "SampleOptionsPage_Settings"; private static final String SOCIETY = "society"; private static final String DOCUMENT_TITLE = "title"; private static final String DOCUMENT_VERSION = "version"; private Text societyName; private Text titleText; private Text versionText; /** * Modify implementation of pxDoc Wizard * ------------------------------------- */ protected IPxDocWizard getPxDocWizard() { return (IPxDocWizard) getWizard(); } @Override public void fillLauncher(PxDocLauncher pLauncher) { PxDocLauncherHelper.addProperty(pLauncher, SOCIETY, societyName.getText()); PxDocLauncherHelper.addProperty(pLauncher, DOCUMENT_TITLE, titleText.getText()); PxDocLauncherHelper.addProperty(pLauncher, DOCUMENT_VERSION, versionText.getText()); } public OptionPage(String pageName) { super(pageName); setTitle("Sample Option Page"); setDescription("Illustrates how to implement a custom wizard page with generation parameters."); } /** * Design of the new Wizard page * -------------------------- */ @Override public void createControl(Composite parent) { Composite composite = new Composite(parent, SWT.NULL); GridLayout gridLayout = new GridLayout(2, false); composite.setLayout(gridLayout); // Document title Label titleLabel = new Label(composite, SWT.WRAP); titleLabel.setText("Document Title :"); titleText = new Text(composite, SWT.BORDER); titleText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); titleText.setMessage("A title for your document"); // Document version Label versionLabel = new Label(composite, SWT.WRAP); versionLabel.setText("Document Version :"); versionText = new Text(composite, SWT.BORDER); versionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); versionText.setMessage("1.0"); // Society Label societyLabel = new Label(composite, SWT.WRAP); societyLabel.setText("Society :"); societyName = new Text(composite, SWT.BORDER); societyName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); societyName.setMessage("Society Name"); composite.pack(); // set the composite as the control for this page setControl(composite); } @Override public String getSectionId() { return SETTINGS_ID; } @Override public IDialogSettings buildDialogSettings() { DialogSettings settings = new DialogSettings(SETTINGS_ID); settings.put(SOCIETY, societyName.getText()); settings.put(DOCUMENT_TITLE, titleText.getText()); settings.put(DOCUMENT_VERSION, versionText.getText()); return settings; } @Override public void loadDialogSettings(IDialogSettings pSettings) { if (pSettings != null) { // society String name = pSettings.get(SOCIETY); if (name == null) { name = ""; } societyName.setText(name); // title String title = pSettings.get(DOCUMENT_TITLE); if (title == null) { title = ""; } titleText.setText(title); // version String version = pSettings.get(DOCUMENT_VERSION); if (version == null) { version = ""; } versionText.setText(version); } } }
Use the properties in your Generator
In your generator, you can get the properties and use them as you want:
package mygenerator /** * MyGenerator empty pxDoc generator. */ pxDocGenerator MyGenerator { root template main(Object model) { document { var specTitle = getProperty("title") as String var societyName = getProperty("society") as String var version = getProperty("version") as String specTitle § societyName § version } } }
Result
Your new Wizard page is created and the properties are sent to the document:
Bind variable styles before deploying a generator
Use case
The use case is the following: you have developed a Generator using variable styles, but you do not want your final user to have to choose a stylesheet nor to bind the styles before the generation. Before deploying your Generator (as a feature, plugin,...), you will just need to modify the code of the Command class as below.
Example with a generator named MyGenerator using the variable styles MyStyle1 and MyStyle2: these styles will be bound to Heading1 and Heading2 of the deployed stylesheet MyStylesheet.
package mygenerator.ui; import com.google.inject.Inject; import fr.pragmaticmodeling.pxdoc.runtime.IPxDocGenerator; import fr.pragmaticmodeling.pxdoc.runtime.IStylesheetsRegistry; import fr.pragmaticmodeling.pxdoc.runtime.launcher.PxDocLauncher; import fr.pragmaticmodeling.pxdoc.runtime.util.PxDocLauncherHelper; public class MyGeneratorCommand extends AbstractMyGeneratorCommand { @Inject IStylesheetsRegistry stylesheetRegistry; @Override protected void initLauncher(PxDocLauncher launcher) { super.initLauncher(launcher); IPxDocGenerator pxDocGenerator = getPxDocGenerator(); pxDocGenerator.setStylesheet(stylesheetRegistry.getStylesheet("MyStylesheet")); PxDocLauncherHelper.addStyleBinding(pxDocGenerator, "MyStyle1", "Heading1"); PxDocLauncherHelper.addStyleBinding(pxDocGenerator, "MyStyle2", "Heading2"); } }
pxDoc - Common Libraries and Plugins
pxDoc Common Libraries and Plugins are a set of pxDoc Modules and/or Java classes or interfaces providing useful extensions capabilities, that can be reused in any pxDoc Generator. Among others, you can:
- query and include diagrams from your models,
- provide generic templates for EMF model,
- manipulate images (convert to AWT, split large images on several pages...)
- ...
The language renderers are part of the pxDoc common plugins but they are described in a dedicated section.
Importing sources into your workspace
You can of course import the common libraries in your workspace to get a view on the common Modules and libraries included in pxDoc
Common Services / org.pragmaticmodeling.pxdoc.common.lib
CommonServices.pxdoc Module
The CommonServices.pxdoc module provides generic templates and functions that can be used by every documentation generator:
|
CommonServices setup
OPTIONAL - When using the CommonServices module in your generator, you can inject your custom instance of IDescriptionProvider (see example below).
The IDescriptionProvider Interface
Among all properties that an object can hold, its human readable descriptions play a particular role. They are usually generated early when documenting an object, while other business properties are treated differently in following document sections. The IDescriptionProvider interface gives the ability to return a description for every object processed by a pxDoc generator, as well as the expected description format (e.g., html, raw text, markdown...) It is also responsible to provide a valid bookmark id for every object processed during generation, and decide which objects should be generated with a bookmark. |
The class DefaultDescriptionProvider is the default implementation of IDescriptionProvider. It returns null as a description for every object, but is able to generate valid bookmarks for every object.
If you plan to use the CommonServices module, you will need to :
- provide your own IDescriptionProvider by subclassing DefaultDescriptionProvider and provide your own implementations of the getDescription*(*) methods.
- inject your IDescriptionProvider instance to the CommonServices when starting the generation (in the root template):
root template main(Object model) { // Commons lib configuration : set a description provider able to get information about object description descriptionProvider = new MyDescriptionProvider(this) document { // content... } }
EMF Services / org.pragmaticmodeling.pxdoc.emf.lib
The EmfServices module is a set of templates and functions that allow to generate documentation for any EMF EObject. It takes benefit of the reflective EMF API to transform EObjects into documentation. It defines two ways of EObject-to-doc transformation:
You can get your documentation for an EObject by invoking the genericDoc template: var int level = 1 var boolean recursive = true apply genericDoc(anEObject, DocKind.^table, level, recursive) With:
|
And because some EObject's attributes are too technical, or rarely/never used, the EmfServices module provide a way to filter some EStructuralFeature from the generation. This is the role of the field excludedFeatures, which you can access the following way:
root template main(Object model) { // exclude some EClasses excludedEClasses += EcorePackage.Literals.EANNOTATION // exclude EStructualFeatures excludedFeatures += EcorePackage.Literals.ECLASSIFIER__DEFAULT_VALUE excludedFeatures += EcorePackage.Literals.EMODEL_ELEMENT__EANNOTATIONS document { // content... } }
The EmfServices.pxdoc files contains comments to explain each template. Do not hesitate to have a look at it.
You can also refer to the EMF Example to see how these templates can be used.
EmfServices setup
OPTIONAL - When using the EmfServices module in your generator, you can inject your custom instances of:
- labelProvider = myLabelProvider
- contentProvider = myContentProvider
OPTIONAL - You can also define filters to exclude some model elements or features from the generation, by adding EClass or EStructuralFeature to the two following sets:
- excludedEClasses += MyEmfPackage.Literals.MY_CLASS
- excludedFeatures += MyEmfPackage.Literals.MY_CLASS__FEATURE
Diagram Services / org.pragmaticmodeling.pxdoc.diagrams.lib
pxDoc Diagrams metamodel
A very simple EMF metamodel has been defined to manipulate diagrams in pxDoc. It is composed of a root object Diagrams, which contains a list of Diagram.
pxDoc Diagrams runtime
The diagrams library provides a set of interfaces to query diagrams from an object.
The diagrams library provides a set of interfaces to query diagrams from an object:
|
The Diagram library provides useful templates to include diagrams.
You can also find samples in the examples provided with the pxDoc enablers
DiagramServices.pxdoc Module
Diagram queries with queryDiagrams(Object)
Samples of queries:
// diagrams owned by the 'model' object var List<Diagram> ownedDiagrams = queryDiagrams(model).execute; // all diagrams owned directly and indirectly by the 'model' object var allOwnedDiagrams = queryDiagrams(model).searchNested.execute; // diagrams owned by the 'model' object, with some content var ownedNonEmptyDiagrams = queryDiagrams(model).notEmpty.execute; // look for a diagram owned by 'model' and named 'A diagram name' var diagramsByName = queryDiagrams(model).name('A diagram name').execute; // look for a diagram owned by 'model' with name staring with 'ABC' var diagramsByNameStartingWith = queryDiagrams(model).nameStartsWith('ABC').execute; // diagrams by type var diagramsByType_CDB = queryDiagrams(model).type('CDB').execute; var diagramsByType_ES = queryDiagrams(model).type('ES').execute; var diagramsByType_CDI = queryDiagrams(model).type('CDI').execute; // diagrams with type 'CDB' and name starting with 'MyString' var cdbStartingWithMyString = queryDiagrams(model).type('CDB').nameStartsWith('MyString').execute;
Include diagrams with the includeDiagram(Diagram) template
You can use the includeDiagram template to include your diagrams:
// To insert the diagram image by yourself: for (diagram : myDiagrams) { // use the pxdoc 'image' keyword with diagram image file path // stored in the 'path' diagram attribute (was 'data' in pxDoc v1.1 and previous). image path:diagram.path // add a title with a style #Figure keepWithNext align:center { diagram.name } // include diagram documentation if any if (!diagram.documentation.empty) { #BodyText {diagram.documentation} } }
And you can get the source diagram object to extract some information from it (get the semantic elements...):
for (diagram : myDiagrams) { //Below, 'MyDiagramType' to be replace according to your environment: 'DDiagram' for Sirius, 'Diagram' for Papyrus... var myDiagramObject=diagram.diagramObject as MyDiagramType // Do whatever you need with the object... }
DiagramServices setup
REQUIRED - When using the DiagramServices module in your generator, you must inject an IDiagramProvider suited to your target platform.
diagramProvider = myToolDiagramProvider
Images Services / org.pragmaticmodeling.pxdoc.images.lib
Set of function allowing to:
|