Commit 60d40b47 authored by Alex Diev's avatar Alex Diev
Browse files

Merge branch '44-add-templating-engine' into 'master'

Resolve "Add templating engine"

Closes #44

See merge request esa/taste3!102
parents 3f2d362d 49ebdc73
Pipeline #1523 failed with stage
......@@ -5,7 +5,7 @@ build_debian10_gcc:
stage: build
tags:
- docker
image: registry.git.vikingsoftware.com/vs/ci-images/debian_10_cpp:latest
image: registry.git.vikingsoftware.com/esa/taste3-ci-image:latest
script:
- mkdir -p build; cd build
- qmake -recursive ..
......
# taste3
ESA's TASTE (https://taste.tools/) evolution (v3?)
\ No newline at end of file
ESA's TASTE (https://taste.tools/) evolution (v3?)
It is required Grantlee as a Qt implementation of string template engine of Django syntax.
Sources of Grantlee are avalable from here https://github.com/steveire/grantlee
To build Grantlee, you need at least Qt5.3 (with development packages), CMake 3.1 and
some additional packages:
sudo apt install lcov cccc doxygen cmake
The current Grantlee release (v.5.2.0) has a problem with escape sequences.
Therefore you must apply a patch before:
cp <TASTE_DIR>/grantlee/fix_escape.diff <GRANTLEE_DIR>
cd <GRANTLEE_DIR>
git apply grantlee.diff
To build Taste correctly Grantlee should be installed into QTDIR directory:
export QTDIR=$(qmake -query QT_INSTALL_PREFIX)
export CMAKE_PREFIX_PATH=$QTDIR:$CMAKE_PREFIX_PATH
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$QTDIR ..
cmake --build .
cmake --build . --target install
......@@ -30,6 +30,11 @@ macx {
CONFIG -= app_bundle
}
GRANTLEE_LIB_DIR = $$[QT_INSTALL_LIBS]
DEFINES += GRANTLEE_LIB_DIR='\\"$$GRANTLEE_LIB_DIR\\"'
LIBS += -L/$$GRANTLEE_LIB_DIR -lGrantlee_Templates
SOURCES += \
app/commandlineparser.cpp \
app/commandsstack.cpp \
......@@ -67,6 +72,11 @@ SOURCES += \
logging/logcategory.cpp \
logging/loghandler.cpp \
main.cpp \
templating/aadlobjecttemplateproperty.cpp \
templating/previewdialog.cpp \
templating/stringtemplate.cpp \
templating/templatehighlighter.cpp \
templating/xmlhighlighter.cpp \
reports/bugreportdialog.cpp \
reports/bugreporthandler.cpp \
settings/appoptions.cpp \
......@@ -173,6 +183,11 @@ HEADERS += \
dummy/dummytabdocument.h \
logging/logcategory.h \
logging/loghandler.h \
templating/aadlobjecttemplateproperty.h \
templating/previewdialog.h \
templating/stringtemplate.h \
templating/templatehighlighter.h \
templating/xmlhighlighter.h \
reports/bugreportdialog.h \
reports/bugreporthandler.h \
settings/appoptions.h \
......@@ -266,3 +281,15 @@ DISTFILES += \
RESOURCES += \
resources.qrc \
tab_interface/tab_interface_resources.qrc
OTHER_FILES += templating/xml_templates/*.tmplt
SOURCE_DIR = $$absolute_path(templating/xml_templates)
DEST_DIR = $$OUT_PWD
win32 {
SOURCE_DIR ~= s,/,\\,g
DEST_DIR ~= s,/,\\,g
}
QMAKE_POST_LINK += $$QMAKE_COPY_DIR $$shell_quote($$SOURCE_DIR) $$shell_quote($$DEST_DIR)
......@@ -63,6 +63,18 @@ QCommandLineOption CommandLineParser::positionalArg(CommandLineParser::Positiona
QCoreApplication::translate("CommandLineParser", "Open an AADL XML <file> on startup."),
QCoreApplication::translate("CommandLineParser", "file"));
}
case CommandLineParser::Positional::OpenStringTemplateFile: {
return QCommandLineOption(
{ "t", "open-template" },
QCoreApplication::translate("CommandLineParser", "Open a string template <file> on startup (-o option is required)."),
QCoreApplication::translate("CommandLineParser", "file"));
}
case CommandLineParser::Positional::ExportToFile: {
return QCommandLineOption(
{ "e", "export-to-xml" },
QCoreApplication::translate("CommandLineParser", "Export a parsed string template into xml <file> on startup (-t option is required)."),
QCoreApplication::translate("CommandLineParser", "file"));
}
case CommandLineParser::Positional::ListScriptableActions: {
return QCommandLineOption(
{ "l", "list-actions" },
......
......@@ -32,6 +32,8 @@ public:
{
DropUnsavedChangesSilently,
OpenAADLXMLFile,
OpenStringTemplateFile,
ExportToFile,
ListScriptableActions,
Unknown
......
/*
/*
Copyright (C) 2019 European Space Agency - <maxime.perrotin@esa.int>
This library is free software; you can redistribute it and/or
......@@ -27,11 +27,13 @@
#include "settings/appoptions.h"
#include "settings/settingsmanager.h"
#include "tab_aadl/aadltabdocument.h"
#include "tab_aadl/aadlobjectfunctiontype.h"
#include "tab_concurrency/concurrencytabdocument.h"
#include "tab_data/datatabdocument.h"
#include "tab_deployment/deploymenttabdocument.h"
#include "tab_interface/interfacetabdocument.h"
#include "tab_msc/msctabdocument.h"
#include "templating/previewdialog.h"
#include "ui_mainwindow.h"
#include <QCloseEvent>
......@@ -117,6 +119,8 @@ void MainWindow::initMenuFile()
m_menuFile->addSeparator();
m_actSaveSceneRender = m_menuFile->addAction(tr("Render Scene..."), this, &MainWindow::onSaveRenderRequested);
m_menuFile->addSeparator();
m_actExportByTemplate = m_menuFile->addAction(tr("Export by template..."), this, &MainWindow::onExportByTemplateRequested);
m_menuFile->addSeparator();
m_actQuit = m_menuFile->addAction(tr("Quit"), this, &MainWindow::onQuitRequested, QKeySequence::Quit);
common::registerAction(Q_FUNC_INFO, m_actOpenFile, "Open file", "Show Open File dialog");
......@@ -211,6 +215,19 @@ void MainWindow::onSaveRenderRequested()
}
}
/**
* @brief MainWindow::onExportByTemplateRequested handles "Export By Template" action
*/
void MainWindow::onExportByTemplateRequested()
{
const QString& templateFileName = QFileDialog::getOpenFileName(this, tr("Choose a template file for export"),
QStringLiteral("./xml_templates"), QStringLiteral("*.tmplt"));
if (templateFileName.isEmpty())
return;
parseTemplateFile(templateFileName);
}
void MainWindow::onQuitRequested()
{
AppOptions::MainWindow.State.write(saveState());
......@@ -332,6 +349,59 @@ void MainWindow::updateActions()
m_actSaveSceneRender->setEnabled(renderAvailable);
}
/**
* @brief MainWindow::parseTemplateFile parses teplate file by a string template engine
* and shows result in Preview dialog.
* @param templateFileName template file name
* @return whether template is parsed successfully
*/
bool MainWindow::parseTemplateFile(const QString &templateFileName)
{
QFileInfo fileInfo(templateFileName);
if (!fileInfo.exists()) {
qWarning() << "File" << templateFileName << "does not exist";
return false;
}
if (document::InterfaceTabDocument *doc = qobject_cast<document::InterfaceTabDocument *>(m_docsManager->docById(TABDOC_ID_InterfaceView))) {
QHash<QString, QVariantList> grouppedObjects;
for (const auto aadlObject : doc->objects()) {
QString aadlGroupType;
switch (aadlObject->aadlType()) {
case aadl::AADLObject::AADLObjectType::AADLFunctionType:
case aadl::AADLObject::AADLObjectType::AADLFunction: {
if (qobject_cast<aadl::AADLObjectFunctionType *>(aadlObject->parentObject()))
continue;
aadlGroupType = QStringLiteral("Functions");
break;
}
case aadl::AADLObject::AADLObjectType::AADLIface:
aadlGroupType = QStringLiteral("Interfaces");
break;
case aadl::AADLObject::AADLObjectType::AADLComment: {
if (qobject_cast<aadl::AADLObjectFunctionType *>(aadlObject->parentObject()))
continue;
aadlGroupType = QStringLiteral("Comments");
break;
}
case aadl::AADLObject::AADLObjectType::AADLConnection:
aadlGroupType = QStringLiteral("Connections");
break;
default:
continue;
}
grouppedObjects[aadlGroupType] << QVariant::fromValue(aadlObject);
}
if (!m_previewDialog)
m_previewDialog = new templating::PreviewDialog(this);
return m_previewDialog->parseTemplate(grouppedObjects, templateFileName);
}
return false;
}
/*!
* \brief MainWindow::processCommandLineArg handles initial option from command line
* \returns true if an option is handled
......@@ -350,6 +420,14 @@ bool MainWindow::processCommandLineArg(CommandLineParser::Positional arg, const
return false;
}
case CommandLineParser::Positional::OpenStringTemplateFile:
if (!value.isEmpty())
return parseTemplateFile(value);
return false;
case CommandLineParser::Positional::ExportToFile:
if (!value.isEmpty() && m_previewDialog)
return m_previewDialog->saveResultToFile(value);
return false;
case CommandLineParser::Positional::ListScriptableActions: {
ctx::ActionsManager::listRegisteredActions();
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
......
......@@ -39,6 +39,10 @@ namespace document {
class DocumentsManager;
}
namespace templating {
class PreviewDialog;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
......@@ -65,11 +69,14 @@ protected:
void updateActions();
void saveSceneRender(const QString &filePath) const;
bool parseTemplateFile(const QString &templateFileName);
protected Q_SLOTS:
void onOpenFileRequested();
void onCreateFileRequested();
bool onCloseFileRequested();
void onSaveRenderRequested();
void onExportByTemplateRequested();
void onQuitRequested();
void onAboutRequested();
void onTabSwitched(int);
......@@ -79,10 +86,12 @@ private:
static constexpr int TABDOC_ID_InterfaceView { 0 };
Ui::MainWindow *ui { nullptr };
QTabWidget *m_tabWidget;
QTabWidget *m_tabWidget { nullptr };
QPointer<QToolBar> m_docToolbar;
document::DocumentsManager *m_docsManager;
document::DocumentsManager *m_docsManager { nullptr };
QPointer<document::AbstractTabDocument> m_currentDocument;
templating::PreviewDialog *m_previewDialog { nullptr };
QUndoGroup *m_undoGroup { nullptr };
bool m_dropUnsavedChangesSilently { false };
......@@ -94,6 +103,7 @@ private:
QAction *m_actCreateFile { nullptr };
QAction *m_actCloseFile { nullptr };
QAction *m_actSaveSceneRender { nullptr };
QAction *m_actExportByTemplate { nullptr };
QAction *m_actQuit { nullptr };
QAction *m_actUndo { nullptr };
......
......@@ -17,8 +17,8 @@
#include "aadlobject.h"
#include "aadlcommonprops.h"
#include "aadlobjectsmodel.h"
#include "templating/aadlobjecttemplateproperty.h"
#include <QPointer>
#include <QVector>
......@@ -161,6 +161,15 @@ QHash<QString, QVariant> AADLObject::attrs() const
return d->m_attrs;
}
/**
* @brief AADLObject::templateAttributes returns list of attribues for using in string templates.
* @return list of attribues.
*/
QVariantList AADLObject::templateAttributes() const
{
return templating::generateTemplateProperties(d->m_attrs);
}
void AADLObject::setAttrs(const QHash<QString, QVariant> &attrs)
{
if (d->m_attrs != attrs) {
......@@ -203,6 +212,15 @@ QHash<QString, QVariant> AADLObject::props() const
return d->m_props;
}
/**
* @brief AADLObject::templateProperties returns list of properties for using in string templates.
* @return list of properties.
*/
QVariantList AADLObject::templateProperties() const
{
return templating::generateTemplateProperties(d->m_props);
}
void AADLObject::setProps(const QHash<QString, QVariant> &props)
{
if (props != d->m_props) {
......
......@@ -34,6 +34,8 @@ class AADLObject : public QObject
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(common::Id id READ id WRITE setId NOTIFY idChanged)
Q_PROPERTY(QVariantList properties READ templateProperties) //!< Property list for string templates
Q_PROPERTY(QVariantList attributes READ templateAttributes) //!< Attribute list for string templates
public:
enum class AADLObjectType
......@@ -66,6 +68,7 @@ public:
// <Required_Interface name="run_forrest" kind="SPORADIC_OPERATION">
QHash<QString, QVariant> attrs() const;
QVariantList templateAttributes() const;
void setAttrs(const QHash<QString, QVariant> &attrs);
QVariant attr(const QString &name, const QVariant &defaultValue = QVariant()) const;
virtual void setAttr(const QString &name, const QVariant &val);
......@@ -73,6 +76,7 @@ public:
// "properties" - XML children <Property>
QHash<QString, QVariant> props() const;
QVariantList templateProperties() const;
void setProps(const QHash<QString, QVariant> &props);
QVariant prop(const QString &name, const QVariant &defaultValue = QVariant()) const;
virtual void setProp(const QString &name, const QVariant &val);
......
......@@ -17,12 +17,16 @@
#include "aadlobjectcomment.h"
#include "aadlobjectfunctiontype.h"
namespace taste3 {
namespace aadl {
AADLObjectComment::AADLObjectComment(const QString &title, QObject *parent)
: AADLObject(title, parent)
{
if (AADLObjectFunctionType *root = qobject_cast<AADLObjectFunctionType *>(parent))
root->addChild(this);
}
AADLObjectComment::~AADLObjectComment() {}
......
......@@ -58,6 +58,11 @@ AADLObject::AADLObjectType AADLObjectConnection::aadlType() const
return AADLObject::AADLObjectType::AADLConnection;
}
QString AADLObjectConnection::sourceName() const
{
return source() ? source()->title() : QString();
}
AADLObject *AADLObjectConnection::source() const
{
return d->m_source;
......@@ -68,6 +73,11 @@ void AADLObjectConnection::setSource(AADLObject *source)
setAttr(meta::Props::token(meta::Props::Token::from), source ? source->title() : QString());
}
QString AADLObjectConnection::targetName() const
{
return target() ? target()->title() : QString();
}
AADLObject *AADLObjectConnection::target() const
{
return d->m_target;
......@@ -182,6 +192,26 @@ void AADLObjectConnection::setAttr(const QString &name, const QVariant &val)
updateAttributes();
}
bool AADLObjectConnection::sourceInterfaceIsRequired() const
{
return sourceInterface() ? sourceInterface()->isRequired() : false;
}
bool AADLObjectConnection::sourceInterfaceIsProvided() const
{
return sourceInterface() ? sourceInterface()->isProvided() : false;
}
bool AADLObjectConnection::targetInterfaceIsRequired() const
{
return targetInterface() ? targetInterface()->isRequired() : false;
}
bool AADLObjectConnection::targetInterfaceIsProvided() const
{
return targetInterface() ? targetInterface()->isProvided() : false;
}
void AADLObjectConnection::inheritLabel()
{
handleLabelInheritance(AADLObjectConnection::LabelInheritancePolicy::Set);
......
......@@ -30,6 +30,14 @@ struct AADLObjectConnectionPrivate;
class AADLObjectConnection : public AADLObject
{
Q_OBJECT
Q_PROPERTY(QString source READ sourceName)
Q_PROPERTY(QString target READ targetName)
Q_PROPERTY(QString siName READ sourceInterfaceName)
Q_PROPERTY(QString tiName READ targetInterfaceName)
Q_PROPERTY(bool siIsRequired READ sourceInterfaceIsRequired)
Q_PROPERTY(bool siIsProvided READ sourceInterfaceIsProvided)
Q_PROPERTY(bool tiIsRequired READ targetInterfaceIsRequired)
Q_PROPERTY(bool tiIsProvided READ targetInterfaceIsProvided)
public:
explicit AADLObjectConnection(AADLObject *source, AADLObject *target, AADLObjectIface *ifaceSource,
AADLObjectIface *ifaceTarget, QObject *parent = nullptr);
......@@ -37,9 +45,11 @@ public:
AADLObjectType aadlType() const override;
QString sourceName() const;
AADLObject *source() const;
void setSource(AADLObject *source);
QString targetName() const;
AADLObject *target() const;
void setTarget(AADLObject *target);
......@@ -53,6 +63,11 @@ public:
void setAttr(const QString &name, const QVariant &val) override;
bool sourceInterfaceIsRequired() const;
bool sourceInterfaceIsProvided() const;
bool targetInterfaceIsRequired() const;
bool targetInterfaceIsProvided() const;
void inheritLabel();
void uninheritLabel();
......
......@@ -42,7 +42,7 @@ AADLObjectFunction::AADLObjectFunction(const QString &title, QObject *parent)
: AADLObjectFunctionType(title, parent)
, d(new AADLObjectFunctionPrivate)
{
setAttr(meta::Props::token(meta::Props::Token::is_type), "NO");
setAttr(meta::Props::token(meta::Props::Token::is_type), QStringLiteral("NO"));
setAttr(meta::Props::token(meta::Props::Token::instance_of), QVariant());
}
......
......@@ -36,7 +36,10 @@ AADLObjectFunctionType::AADLObjectFunctionType(const QString &title, QObject *pa
, d(new AADLObjectFunctionTypePrivate)
{
setAttr(meta::Props::token(meta::Props::Token::language), QVariant());
setAttr(meta::Props::token(meta::Props::Token::is_type), "YES");
setAttr(meta::Props::token(meta::Props::Token::is_type), QStringLiteral("YES"));
if (AADLObjectFunctionType *root = qobject_cast<AADLObjectFunctionType *>(parent))
root->addChild(this);
}
AADLObjectFunctionType::~AADLObjectFunctionType() {}
......@@ -153,6 +156,38 @@ QVector<AADLObjectIface *> AADLObjectFunctionType::interfaces() const
return ris() + pis();
}
QVariantList AADLObjectFunctionType::templateInterfaces() const
{
QVariantList ifaceList;
for (AADLObjectIface *iface : interfaces())
ifaceList << QVariant::fromValue(iface);
return ifaceList;
}
QVariantList AADLObjectFunctionType::templateFunctions() const
{
QVariantList functions;
for (const auto child : d->m_children) {
if (child->aadlType() == AADLObject::AADLObjectType::AADLFunction ||
child->aadlType() == AADLObject::AADLObjectType::AADLFunctionType) {
functions << QVariant::fromValue(child);
}
}
return functions;
}
QVariantList AADLObjectFunctionType::templateComments() const
{
QVariantList comments;
for (const auto child : d->m_children) {
if (child->aadlType() == AADLObject::AADLObjectType::AADLComment)
comments << QVariant::fromValue(child);
}
return comments;
}
QString AADLObjectFunctionType::language() const
{
return attr(meta::Props::token(meta::Props::Token::language)).toString();
......
......@@ -33,6 +33,9 @@ struct AADLObjectFunctionTypePrivate;
class AADLObjectFunctionType : public AADLObject
{
Q_OBJECT
Q_PROPERTY(QVariantList interfaces READ templateInterfaces) //!< Iinterface list for string templates
Q_PROPERTY(QVariantList functions READ templateFunctions) //!< Function list for string templates
Q_PROPERTY(QVariantList comments READ templateComments) //!< Comment list for string templates
public:
explicit AADLObjectFunctionType(const QString &title = QString(), QObject *parent = nullptr);
~AADLObjectFunctionType() override;
......@@ -55,6 +58,10 @@ public:
bool removeInterface(AADLObjectIface *iface);
QVector<AADLObjectIface *> interfaces() const;
QVariantList templateInterfaces() const;
QVariantList templateFunctions() const;
QVariantList templateComments() const;
QString language() const;
void setLanguage(const QString &lang);
......
......@@ -140,6 +140,14 @@ QVector<IfaceParameter> AADLObjectIface::params() const
return d->m_params;
}
QVariantList AADLObjectIface::paramList() const
{
QVariantList list;
for (const auto &param : d->m_params)
list << QVariant::fromValue(param);
return list;
}
void AADLObjectIface::setParams(const QVector<IfaceParameter> &params)
{
if (d->m_params != params)
......
......@@ -38,6 +38,9 @@ class AADLObjectIface : public AADLObject
{
Q_OBJECT
Q_PROPERTY(AADLObjectIface::IfaceType direction READ direction)
Q_PROPERTY(bool isProvided READ isProvided)
Q_PROPERTY(bool isRequired READ isRequired)
Q_PROPERTY(QVariantList params READ paramList)
public:
enum class IfaceType
......@@ -99,6 +102,7 @@ public:
bool setKind(OperationKind k);
QVector<IfaceParameter> params() const;
QVariantList paramList() const;
void setParams(const QVector<IfaceParameter> &params);
void addParam(const IfaceParameter &param);
......
......@@ -258,6 +258,12 @@ AADLObjectConnection *AADLObjectsModel::getConnectionForIface(const common::Id &
return nullptr;
}
const QHash<common::Id, AADLObject *> &AADLObjectsModel::objects() const
{
return d->m_objects;
}
QVector<AADLObjectConnection *> AADLObjectsModel::getConnectionsForIface(const common::Id &id) const
{
QVector<AADLObjectConnection *> result;
......
......@@ -60,6 +60,7 @@ public:
AADLObjectConnection *getConnectionForIface(const common::Id &id) const;
QVector<AADLObjectConnection *> getConnectionsForIface(const common::Id &id) const;
const QHash<common::Id, AADLObject *> &objects() const;
QList<AADLObject *> visibleObjects() const;
Q_SIGNALS:
......
......@@ -27,6 +27,9 @@ namespace aadl {
class BasicParameter
{
Q_GADGET