aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com>2017-01-20 08:45:08 +0100
committerJuergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com>2017-01-20 08:45:08 +0100
commitf9a67d7525727367181fe4d819c898d1ab32ca22 (patch)
tree3d66ba8a38d8b792c1c71a62a1c142ab9785671c
parent92dc0631922f8b2faaf1c1772d0f8534b884f326 (diff)
parentd3f8ef9d2576b473bf16681e092ff5d7b93ae641 (diff)
Merge branch 'release/1.0b2'1.0b2
-rw-r--r--INSTALL.md5
-rw-r--r--README.md18
-rw-r--r--builtin/qtcpp/templates/abstractinterface.cpp8
-rw-r--r--builtin/qtcpp/templates/abstractinterface.h5
-rw-r--r--builtin/qtcpp/templates/struct.cpp74
-rw-r--r--builtin/qtcpp/templates/struct.h22
-rw-r--r--builtin/qtcpp/templates/structmodel.cpp6
-rwxr-xr-xcli.py1
-rw-r--r--docs/index.rst3
-rw-r--r--docs/motivation.rst66
-rw-r--r--docs/qtqml.rst6
-rw-r--r--docs/usage.rst12
-rw-r--r--qface/__about__.py2
13 files changed, 200 insertions, 28 deletions
diff --git a/INSTALL.md b/INSTALL.md
index b5e82ae..4863afc 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,5 +1,10 @@
# Installation
+Typical installation as a library
+
+ pip3 install qface
+
+# Install for Development
Installing as python executable using pip3 (python3)
git clone git@github.com:Pelagicore/qface.git
diff --git a/README.md b/README.md
index b73e2ce..d0041d1 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![Build Status](https://travis-ci.org/Pelagicore/qface.svg?branch=develop)](https://travis-ci.org/Pelagicore/qface)
[![Documentation Status](https://readthedocs.org/projects/qface/badge/?version=latest)](http://qface.readthedocs.io/en/latest/?badge=latest)
-QFace is an generator framework based on a common modern IDL. It is not a generator a such but enforces a common IDL format and provides a library to write your own generator. It is actually very easy to create your own generator and generate your custom solution based on your needs from the same IDL.
+QFace is a generator framework based on a common modern IDL. It is not a generator as such but enforces a common IDL format and provides a library to write your own generator. It is actually very easy to create your own generator and generate your custom solution based on your needs from the same IDL.
The IDL is designed after the Qt/QML interface and as such is optimized to generate source code used with Qt C++ or Qt QML, but it is not limited to this use case.
@@ -13,6 +13,22 @@ QFace is written out of the learnings of using IDLs in other large projects. Oft
Please see the INSTALL and USAGE guides for more information.
+## Install
+
+To install the qface library you need to have python3 and pip installed.
+
+```sh
+pip3 install qface
+```
+
+## Download
+
+If you are looking for the examples and the builtin generators you need to download the code.
+
+```sh
+git clone git@github.com:Pelagicore/qface.git
+```
+
## Copyright and license
Copyright (C) 2016 Pelagicore AG
diff --git a/builtin/qtcpp/templates/abstractinterface.cpp b/builtin/qtcpp/templates/abstractinterface.cpp
index e0ac7cc..ff1ef87 100644
--- a/builtin/qtcpp/templates/abstractinterface.cpp
+++ b/builtin/qtcpp/templates/abstractinterface.cpp
@@ -18,12 +18,11 @@
{
}
-{{class}}::~{{class}}()
-{
+{{class}}::~{{class}}()
+{
}
{% for property in interface.properties %}
-{% if not property.is_readonly %}
void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
{
if(m_{{property}} == {{property}}) {
@@ -32,7 +31,6 @@ void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
m_{{property}} = {{property}};
emit {{property}}Changed();
}
-{% endif %}
{{property|returnType}} {{class}}::{{property}}() const
{
@@ -40,7 +38,7 @@ void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
}
{% endfor %}
-{%- for operation in interface.operations %}
+{%- for operation in interface.operations %}
{{operation|returnType}} {{class}}::{{operation}}({{operation.parameters|map('parameterType')|join(', ')}})
{
{% for parameter in operation.parameters %}
diff --git a/builtin/qtcpp/templates/abstractinterface.h b/builtin/qtcpp/templates/abstractinterface.h
index d6921ca..c004f29 100644
--- a/builtin/qtcpp/templates/abstractinterface.h
+++ b/builtin/qtcpp/templates/abstractinterface.h
@@ -15,7 +15,8 @@ class {{class}} : public QObject
{
Q_OBJECT
{% for property in interface.properties %}
- Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} NOTIFY {{property}}Changed)
+ Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} {% if not property.is_readonly %}
+WRITE set{{property|upperfirst}} {% endif %}NOTIFY {{property}}Changed)
{% endfor %}
public:
@@ -29,9 +30,7 @@ public Q_SLOTS:
public:
{% for property in interface.properties %}
-{% if not property.is_readonly %}
virtual void set{{property|upperfirst}}({{ property|parameterType }});
-{% endif %}
{% endfor %}
public:
diff --git a/builtin/qtcpp/templates/struct.cpp b/builtin/qtcpp/templates/struct.cpp
index 5b132ec..70dd967 100644
--- a/builtin/qtcpp/templates/struct.cpp
+++ b/builtin/qtcpp/templates/struct.cpp
@@ -9,13 +9,83 @@
#include "{{class|lower}}.h"
+
+// Shared Data
+
+class {{class}}Data : public QSharedData
+{
+public:
+ {{class}}Data()
+ : QSharedData()
+ {% for field in struct.fields %}
+ , {{field}}({{field|defaultValue}})
+ {% endfor %}
+ {
+ }
+ {{class}}Data(const {{class}}Data &other)
+ : QSharedData(other)
+ {% for field in struct.fields %}
+ , {{field}}(other.{{field}})
+ {% endfor %}
+ {
+ }
+
+public:
+{% for field in struct.fields %}
+ {{field|returnType}} {{field}};
+{% endfor %}
+};
+
+// Class
{{struct.comment}}
+{{class}}::{{class}}()
+ : d(new {{class}}Data)
+{
+}
+
+{{class}}::{{class}}(const {{class}} &other)
+ : d(other.d)
+{
+}
+
+{{class}}::~{{class}}()
+{
+}
+
+{% for field in struct.fields %}
+void {{class}}::set{{field|upperfirst}}({{field|parameterType}})
+{
+ d->{{field}} = {{field}};
+}
+{{field|returnType}} {{class}}::{{field}}() const
+{
+ return d->{{field}};
+}
+
+{% endfor %}
+
+
+
+{{class}} {{class}}::clone()
+{
+ {{class}} other(*this);
+ other.d.detach();
+ return other;
+}
+
bool {{class}}::operator==(const {{class}} &other) const
{
return (
{%- for field in struct.fields %}{{ ampersand() }}
- m_{{field}} == other.m_{{field}}
- {%- endfor %} );
+ {{field}}() == other.{{field}}()
+ {%- endfor %}
+ );
+}
+
+{{class}} &{{class}}::operator=(const {{class}} &other)
+{
+ d = other.d;
+ return *this;
}
diff --git a/builtin/qtcpp/templates/struct.h b/builtin/qtcpp/templates/struct.h
index 2e0d6d1..7c6a4e6 100644
--- a/builtin/qtcpp/templates/struct.h
+++ b/builtin/qtcpp/templates/struct.h
@@ -9,19 +9,35 @@
#include <QtCore>
+
+class {{class}}Data;
+
class {{class}}
{
Q_GADGET
{% for field in struct.fields %}
- Q_PROPERTY({{field|returnType}} {{field}} MEMBER m_{{field}})
+ Q_PROPERTY({{field|returnType}} {{field}} READ {{field}} WRITE set{{field|upperfirst}})
{% endfor %}
public:
+ {{class}}();
+ {{class}}(const {{class}} &other);
+ ~{{class}}();
+
+ Q_INVOKABLE {{class}} clone();
+
+ bool operator==(const {{class}} &other) const;
+ {{class}} &operator=(const {{class}} &other);
+
{% for field in struct.fields %}
- {{field|returnType}} m_{{field}};
+ void set{{field|upperfirst}}({{field|parameterType}});
+ {{field|returnType}} {{field}}() const;
+
{% endfor %}
- bool operator==(const {{class}} &other) const;
+
+private:
+ QExplicitlySharedDataPointer <{{class}}Data> d;
};
Q_DECLARE_METATYPE({{class}})
diff --git a/builtin/qtcpp/templates/structmodel.cpp b/builtin/qtcpp/templates/structmodel.cpp
index 3f13cb6..2759dae 100644
--- a/builtin/qtcpp/templates/structmodel.cpp
+++ b/builtin/qtcpp/templates/structmodel.cpp
@@ -40,7 +40,7 @@ QVariant {{class}}::data(const QModelIndex &index, int role) const
switch(role) {
{% for field in struct.fields %}
case Roles::{{field|upperfirst}}:
- return QVariant::fromValue({{struct|lower}}.m_{{field}});
+ return QVariant::fromValue({{struct|lower}}.{{field}}());
{% endfor %}
}
return QVariant();
@@ -58,7 +58,7 @@ void {{class}}::insert(int row, const Qml{{struct}} &{{struct|lower}})
row = 0;
if (row >= m_data.count())
row = m_data.count();
-
+
beginInsertRows(QModelIndex(), row, row);
m_data.insert(row, {{struct|lower}});
endInsertRows();
@@ -78,7 +78,7 @@ void {{class}}::append(const Qml{{struct}} &{{struct|lower}})
}
void {{class}}::update(int row, const Qml{{struct}} &{{struct|lower}})
-{
+{
if(row < 0 || row >= m_data.count()) {
return;
}
diff --git a/cli.py b/cli.py
index 0c4a9d1..4bbeaa1 100755
--- a/cli.py
+++ b/cli.py
@@ -153,6 +153,7 @@ def _generate_reload(generator, input, output):
print('watch:', path)
observer.schedule(event_handler, path, recursive=True)
for entry in input:
+ entry = entry.dirname().expand().abspath()
print('watch:', entry)
observer.schedule(event_handler, entry, recursive=True)
path = Path(__file__).parent / 'qface'
diff --git a/docs/index.rst b/docs/index.rst
index fa2d5be..d2a2e6d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,11 +6,12 @@ QFace is a flexible Qt API generator. It uses a common IDL format (called QDL) t
.. toctree::
:maxdepth: 1
+ motivation
usage
+ builtin
grammar
domain
extending
- builtin
api
diff --git a/docs/motivation.rst b/docs/motivation.rst
new file mode 100644
index 0000000..f5c4b8e
--- /dev/null
+++ b/docs/motivation.rst
@@ -0,0 +1,66 @@
+==========
+Motivation
+==========
+
+QFace is an attempt to establish one interface description language with an easy to use code generator framework. QFace as an interface description language is Qt friendly but not limited to Qt. The hope is that many projects can agree on this interface language and many interesting generators will be created and we all can learn from how other projects generate code from the same IDL.
+
+The IDL
+=======
+
+The IDL uses common API concept such as modules, interfaces, properties, structs and enums/flags. Additional it knows about lists and models. A list is an array of primitive or complex types. A model is an indicator for large data sets which are typical used vian a defined interface or via pagination.
+
+The data types provided by QFace can be divided into primitive and complex types:
+
+Primitive Types
+
+* bool
+* int
+* real
+* string
+* var
+
+Complex Types
+
+* Interface
+* Struct
+* Enum
+* Flag
+* Array
+* Model
+
+The language as such does not provide any support for maps or dictionaries. The keys in dictionaries require a hash which can not always be guaranteed to be available.
+
+Defining APIs
+=============
+
+There are many opinions how to define APIs and what is the best way. The hope is if enough people use the same IDL there will be a large set of generators and at the end maybe one common way how to write your QML plugin and export the API.
+
+There are often discussions about if an interface shall be an object or better a singleton. Or if an array shall be exposed as a list or a variant list or even a QmlListProperty or always as a model. Structured data can be exposed using a QVariant or QJSValue or nowadays as a gadget or as a QObject if property notifications are required. Exposing structured data via QObject leads to memory management issues.
+
+Large Projects
+==============
+
+In larger projects there is the need to interface a large set of operating services and make them available to QML. It is less about defining new visual items in C++ more about creating an abstraction of a service and make it available to the HMI developer inside QML.
+
+This can be a challenge when you create many of these plugins and in the middle of the project you figure out you have issues with your current design. Or if the customer in the next project wants to use a different HMI technology. All the knowledge is inside these plugins.
+
+With QFace these companies can be certain that QFace does not lock them into the HMI technology and smaller design issues can be fixed by fixing the generator.
+
+Remote Services
+===============
+
+Some projects use network communication to communicate from the HMI to the services, which might run on a different process or event networked device. QFace was not designed for remote services, as it does not define any storage types (e.g. int32, int16, int64) it knows only an int and does not define how large the int shall be. For this QFace need to rely on the author of the generators to have a defined protocol to exchange data.
+
+Complex APIs
+============
+
+QFace is by design limited by its features. QFace shall be easy to use and the syntax easy to remember, so that also none experts can write their interface files.
+
+QFace does not suppot unions or extending from other interfaces or that a struct extends other structs. If you look for these features than QFace is probably the wring choice.
+
+Limitations
+===========
+
+As every code generation tool QFace is also limited to how much information you place inside your interface files. So there might be areas where code generation just do not make sense, than QFace will also not help.
+
+QFace allows you to use annotation which can add meta information to the interface files. But the genertor needs to be designed to understand this meta information. Only the structure of these annotations are defined not the information they carry. Annotations might helpt to add information to an interface document to better control the code generation process.
diff --git a/docs/qtqml.rst b/docs/qtqml.rst
index b5795b4..e7e1ae1 100644
--- a/docs/qtqml.rst
+++ b/docs/qtqml.rst
@@ -7,16 +7,16 @@ The Qt QML Code generator creates a pure QML implementation of the provided QFac
This allows developers to start early with an QML only implementation and later switch to an QtCPP based implementation, without changing the HMI code.
.. note::
-
+
As the HMI is limited to the API there might still be differences in behavior of the two implementations. This is in the nature of APIs and might lead to different result.
For each module the genrator creates a module JS file, which contains the enums and factory methods for the structure. A structure is in the pure QML implementation just a JS object with correct attributes set.
The interfaces are generates as QtObject types and contain the typical properties, operations and signals.
-.. ruby:: Code Generation
+.. rubric:: Code Generation
-.. code-block:: yml
+.. code-block:: yaml
for each module:
- qmldir
diff --git a/docs/usage.rst b/docs/usage.rst
index 7c4d78d..974ae7e 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -9,20 +9,20 @@ QFace requires one or more IDL files as input file and a generator to produce ou
.. image:: qface_concept.png
-There are several ways to call the generator.
+There are several ways to call the generator.
-Invokation
+Invocation
==========
-Direct Invokation
+Direct Invocation
-----------------
You can call the generator directly by using the provided script. All generator should at minimum expect a series of inputs and one output path. This is normally recommended for production.
.. code-block:: sh
- ./csvgen.py input output
+ ./csv.py src dst
Via qface invokation
--------------------
@@ -34,9 +34,9 @@ To use an existing generator just provide the path to the generator script.
.. code-block:: sh
qface generate --generator ./csvgen.py input output
-
-To suse live reloading on changes just use the reload option:
+
+To use live reloading on changes just use the reload option:
.. code-block:: sh
diff --git a/qface/__about__.py b/qface/__about__.py
index e4da80f..e900ebc 100644
--- a/qface/__about__.py
+++ b/qface/__about__.py
@@ -9,5 +9,5 @@ except NameError:
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
__uri__ = "https://pelagicore.github.io/qface/"
-__version__ = "1.0b1"
+__version__ = "1.0b2"
__author__ = "JRyannel"