Commit 0af94c01 authored by Leander Schulten's avatar Leander Schulten
Browse files

rename Programm to Programm

replace ProgrammTemplate through TypedProgram
Adds Module class which holds name code and properties of one module
Make Modules save and loadable
Add Compiler for Windows
Add Compiler Settings to Settings view/system
Improve ModuleView
Improve ModelVector
CodeEditorHelpen can now Compile code
parent 4faaf029
......@@ -52,14 +52,11 @@ SOURCES += \
programms/programblock.cpp \
programms/compiler.cpp \
test/testmodulsystem.cpp \
<<<<<<< HEAD
programms/controller.cpp \
programms/dmxprogram.cpp \
programms/dmxprogramblock.cpp \
programms/json_storage.cpp
=======
programms/json_storage.cpp \
codeeditorhelper.cpp
>>>>>>> Add Module View and make bug fixes
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
......@@ -112,20 +109,17 @@ HEADERS += \
programms/modulemanager.h \
programms/programblock.h \
programms/property.hpp \
programms/programm.hpp \
programms/filter.hpp \
programms/consumer.hpp \
programms/compiler.h \
test/testmodulsystem.h \
<<<<<<< HEAD
programms/controller.h \
programms/dmxprogram.h \
programms/dmxprogramblock.h \
programms/storage.hpp \
programms/json_storage.h
=======
codeeditorhelper.h
>>>>>>> Add Module View and make bug fixes
programms/json_storage.h \
codeeditorhelper.h \
programms/program.hpp
# Default rules for deployment.
......@@ -135,11 +129,11 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
DISTFILES +=
QMAKE_CXXFLAGS += -fsanitize=address
# QMAKE_CXXFLAGS += -fsanitize=address
# QMAKE_CXXFLAGS += -fno-omit-frame-pointer
QMAKE_CXXFLAGS += -Wshadow
#QMAKE_CXXFLAGS += -lasan
LIBS += -lasan
# QMAKE_CXXFLAGS += -Wshadow
# QMAKE_CXXFLAGS += -lasan
# LIBS += -lasan
win32-g++{
LIBS += -L$$PWD/'lib/boost' -lboost_coroutine -lboost_context
......
......@@ -13,7 +13,7 @@ Item{
width: 300
//interactive: false
id: swipeView
function switchTab(){
/*function switchTab(){
if(tab1.x===0){
tab1.x = -width;
tab2.x = 0;
......@@ -21,7 +21,7 @@ Item{
tab1.x = 0;
tab2.x = width;
}
}
}*/
Page{
id:tab1
......@@ -36,20 +36,25 @@ Item{
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
id:listView
delegate: ItemDelegate{
property var itemData : modelData
width: parent.width
text: itemData.name +"("+itemData.description+")"
height: 60
text: modelData.name + " (" + moduleTypeModel[modelData.type] + ')'
onClicked: {
listView.currentIndex = index;
swipeView.switchTab();
// for (var prop in moduleTypeModel) {
// print(prop += " (" + typeof(moduleTypeModel[prop]) + ") = " + moduleTypeModel[prop]);
// }
}
}
highlight: Rectangle{
color: "blue"
opacity: 0.7
}
model: deviceModel
model: modulesModel
}
footer: RowLayout{
......@@ -59,6 +64,7 @@ Item{
id: buttonAdd
text:"Add"
font.pixelSize: 15
onClicked: {ModelManager.addModule(); console.log("test");}
}
Button{
Layout.preferredWidth: listView.width/2-10
......@@ -69,7 +75,7 @@ Item{
}
}
}
Page{
/*Page{
x: 9999 // far far away, nobody should see this Component at Lunch time
id:tab2
Behavior on x {
......@@ -92,7 +98,7 @@ Item{
id:listView2
delegate: ItemDelegate{
width: parent.width
text: itemData.name +"("+itemData.description+")"
text: " test : " + itemData.name +"("+itemData.description+")"
onClicked: listView.currentIndex = index
}
......@@ -119,7 +125,7 @@ Item{
font.pixelSize: 15
}
}
}
}*/
}
GridLayout{
......@@ -135,6 +141,9 @@ Item{
}
TextInputField{
Layout.fillWidth: true
enabled: listView.currentIndex !== -1
text: listView.currentItem ? listView.currentItem.itemData.name : "Select one Module"
onTextChanged: listView.currentItem.itemData.name = text;
}
Label{
......@@ -142,14 +151,19 @@ Item{
}
TextInputField{
Layout.fillWidth: true
enabled: listView.currentIndex !== -1
text: listView.currentItem ? listView.currentItem.itemData.description : "Select one Module"
onTextChanged: listView.currentItem.itemData.description = text;
}
Label{
text: "Type:"
}
ComboBox{
model: ["Program", "Loopprogram", "Filter","Consumer"]
model: moduleTypeModel
Layout.preferredWidth: 200
currentIndex: listView.currentItem.itemData.type
onCurrentIndexChanged: listView.currentItem.itemData.type = currentIndex
}
Label{
......@@ -188,15 +202,22 @@ Item{
Layout.columnSpan: 2
Layout.fillHeight: true
Layout.fillWidth: true
onHoveredChanged: if(!hovered)listView.currentItem.itemData.code = codeEditor.text
TextArea{
font.family: "Liberation Mono"
font.pointSize: 10
tabStopDistance: 16
id: codeEditor
selectByMouse: true
text: listView.currentItem.itemData.code
//onTextChanged: listView.currentItem.itemData.code = text
CodeEditorHelper{
id:codeEditorHelper
module: listView.currentItem.itemData
document: codeEditor.textDocument
onInsertText: {
console.log(newText)
codeEditor.insert(codeEditor.cursorPosition,newText);
// Hack to display all new text, sometimes new text disappear
codeEditor.selectAll();
......@@ -210,6 +231,7 @@ Item{
Layout.columnSpan: 2
Layout.fillWidth: true
text: "Compile, test and save"
onClicked: codeEditorHelper.compile()
}
}
......
......@@ -82,6 +82,34 @@ Pane{
}
}
}
Label{
Layout.fillWidth: true
text: "Compiler File Path:"
}
TextInputField{
Layout.fillWidth: true
text: Settings.compilerPath
onAccepted: Settings.compilerPath = text;
Button{
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: -5
anchors.bottomMargin: -5
anchors.bottom: parent.bottom
text: "File Chooser"
onClicked: {
fileDialog.selectFolder = false;
fileDialog.selectMultiple = false;
fileDialog.folder = Settings.compilerPath;
fileDialog.open();
fileDialog.addSelection(Settings.compilerPath);
fileDialog.callback = function(file){
console.log(file);
Settings.compilerPath = file;
};
}
}
}
Label{
Layout.fillWidth: true
text: "Compiler Flags:"
......
......@@ -12,6 +12,7 @@
#include "controlpanel.h"
#include "mapview.h"
#include <QCryptographicHash>
#include "programms/modulemanager.h"
namespace ApplicationData{
......@@ -54,6 +55,10 @@ QByteArray saveData(){
QJsonObject u;
MapView::getLastCreated()->writeJsonObject(u);
o.insert("MapView",u);
}{
QJsonObject u;
Modules::ModuleManager::singletone()->writeJsonObject(u);
o.insert("ModuleManager",u);
}
return QJsonDocument(o).toJson();
}
......@@ -93,6 +98,10 @@ std::function<void()> loadData(QByteArray data){
qDebug()<<"password : "<<password;
qDebug()<<"hash : "<<QCryptographicHash::hash(QString("admin").toLatin1(),QCryptographicHash::Sha3_256);
}
{
QJsonObject ob = o["ModuleManager"].toObject();
Modules::ModuleManager::singletone()->loadModules(ob);
}
password=QCryptographicHash::hash(QString("admin").toLatin1(),QCryptographicHash::Sha3_256);
return [=](){
ControlPanel::getLastCreated()->loadFromJsonObject(o["ControlPanel"].toObject());
......
#include "codeeditorhelper.h"
#include <QTextCursor>
#include <QtQuick>
#include "settings.h"
#include "programms/compiler.h"
CodeHighlighter::CodeHighlighter(QTextDocument * parent):QSyntaxHighlighter (parent)
{
......@@ -58,6 +60,28 @@ CodeEditorHelper::CodeEditorHelper(){
}
QString generateProgrammCode(){
QString code = "int getProgrammLengthInMS(){\n\treturn Program::Infinite;\n}\n\n";
code += "void start(){\n\t\n}\n\n";
code += "ProgrammState doStep(time_diff_t diff_ms){\n\treturn {false/*finished*/,true/*output changed*/};\n}\n\n";
return code;
}
QString generateFilterCode(){
QString code = "unsigned int computeOutputLength(unsigned int inputLength){\n\treturn inputLength;\n}\n\n";
code += "void filter(){\n\t\n}\n\n";
code += "bool doStep(time_diff_t diff_ms){\n\treturn false/*output changed*/;\n}\n\n";
return code;
}
void CodeEditorHelper::typeChanged(){
if(module->getType()==Modules::Module::Program){
emit insertText(generateProgrammCode(),0);
}else if(module->getType()==Modules::Module::Filter){
emit insertText(generateFilterCode(),0);
}
}
int CodeEditorHelper::countTabs(int startPos){
int counter = 0;
while (startPos>=0 && document->characterAt(startPos) != QChar::ParagraphSeparator) {
......@@ -85,6 +109,8 @@ void CodeEditorHelper::contentsChange(int from, int charsRemoved, int charsAdded
emit insertText(newText,from + tabs+ 2);
}else{
int tabs = countTabs(from-1);
if(tabs==0)
return;
QString newText;
qDebug()<<"write2 : "<<tabs;
for(int i = 0 ; i< tabs;++i)
......@@ -145,3 +171,152 @@ void CodeHighlighter::highlightBlock(const QString &text)
startIndex = text.indexOf(commentStartExpression, startIndex + commentLength);
}
}
QString toName(Modules::Module::Type t){
switch (t) {
case Modules::Module::Filter:
return "Filter";
case Modules::Module::Program:
return "Program";
case Modules::Module::LoopProgram:
return "LoopProgram";
default:
return "wrong_type";
}
}
QString toName(Modules::ValueType t){
switch (t) {
case Modules::Brightness:
return "brightness_t";
case Modules::RGB:
return "rgb_t";
default:
return "wrong_type";
}
}
QString toName(Modules::Property::Type t){
switch (t) {
case Modules::Property::Bool:
return "bool";
case Modules::Property::Double:
return "double";
case Modules::Property::Float:
return "float";
case Modules::Property::Int:
return "int";
case Modules::Property::Long:
return "long";
case Modules::Property::String:
return "std::string";
default:
return "wrong_type";
}
}
QTextStream& writeDeclaration(QTextStream& out, const Modules::detail::PropertyInformation *p){
using namespace Modules;
if(p->getType() == Property::Bool){
out << "BoolProperty _"<< p->getName()<< ';' << endl;
}else if(p->getType() == Property::String){
out << "StringProperty _"<< p->getName()<< " = \"\";" << endl;
}else{
out << "NumericProperty<"<< toName(p->getType())<<"> _"<<p->getName()<<";"<<endl;
}
return out;
}
QTextStream& writeConstructor(QTextStream& out, const Modules::detail::PropertyInformation *p){
using namespace Modules;
out << "properties.push_back(& _"<< p->getName()<< ");" << endl;
out << "_" << p->getName() << ".setName(\""<< p->getName() << "\");" << endl;
out << "_" << p->getName() << ".setDescription(\""<< p->getDescription() << "\");" << endl;
return out;
}
void CodeEditorHelper::compile(){
if(!module)
return;
Settings s;
QFile file( s.getModuleDirPath() + "/" + module->getName() + ".cpp" );
file.remove();
if ( file.open(QIODevice::ReadWrite) )
{
QString typeName = toName(module->getType());
QString valueName = toName(module->getValueType());
QTextStream stream( &file );
stream << "#define MODULE_LIBRARY" << endl;
switch (module->getType()) {
case Modules::Module::Filter:
stream << "#define HAVE_FILTER" << endl;
break;
case Modules::Module::Program:
stream << "#define HAVE_PROGRAM" << endl;
break;
case Modules::Module::LoopProgram:
stream << "#define HAVE_LOOP_PROGRAM" << endl;
break;
default:
return;
}
stream << "#include <programms/module.h>" << endl;
stream << "" << endl;
stream << "using namespace Modules;" << endl;
stream << "" << endl;
if(module->getType() == Modules::Module::Filter){
stream << "class Impl : public Typed" << typeName << "<"<<valueName<<","<<valueName<<">{"<< endl;
}else{
stream << "class Impl : public Typed" << typeName << "<"<<valueName<<">{"<< endl;
}
for(const auto &p : module->getProperties()){
writeDeclaration(stream,p);
}
stream << "public:" << endl;
stream << "Impl(){" << endl;
for(const auto &p : module->getProperties()){
writeConstructor(stream,p);
}
stream << "}" << endl;
stream << "const char* getName()const final override{" << endl;
stream << "return \"" << module->getName()<< "\";" << endl;
stream << "}" << endl;
stream << "" << endl;
stream << document->toPlainText();
stream << "" << endl;
stream << "};" << endl; // class end
stream << "" << endl;
stream << "" << endl;
stream << "unsigned int getNumberOf"<<typeName<<"(){" << endl;
stream << " return 1;" << endl;
stream << "}" << endl;
stream << "" << endl;
stream << "char const * getNameOf"<<typeName<<"(unsigned int index){" << endl;
stream << "switch (index) {" << endl;
stream << "case 0:" << endl;
stream << "return \""<<module->getName()<<"\";" << endl;
stream << "default:" << endl;
stream << "return \"Wrong index\";" << endl;
stream << "}" << endl;
stream << "}" << endl;
stream << "" << endl;
stream << "char const * getDescriptionOf"<<typeName<<"(unsigned int index){" << endl;
stream << "switch (index) {" << endl;
stream << "case 0:" << endl;
stream << "return \""<<module->getDescription()<<"\";" << endl;
stream << "default:" << endl;
stream << "return \"Wrong index\";" << endl;
stream << "}" << endl;
stream << "}" << endl;
stream << "" << endl;
stream << typeName << " * create(unsigned int index){ " << endl;
stream << "switch (index) {" << endl;
stream << "case 0:" << endl;
stream << "return new Impl;" << endl;
stream << "default:" << endl;
stream << "return nullptr;" << endl;
stream << "}" << endl;
stream << "}" << endl;
stream.flush();
file.close();
Modules::Compiler::compileToLibrary(file,module->getName()+".dll");
}
}
......@@ -6,6 +6,7 @@
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QRegularExpression>
#include <programms/modulemanager.h>
// Highlight code from https://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html
class CodeHighlighter : public QSyntaxHighlighter{
......@@ -37,18 +38,37 @@ class CodeEditorHelper : public QObject
{
QQuickTextDocument* documentWrapper = nullptr;
QTextDocument * document = nullptr;
QMetaObject::Connection typeConnection;
Q_PROPERTY(QQuickTextDocument* document READ getDocument WRITE setDocument NOTIFY documentChanged)
Q_PROPERTY(Modules::Module* module READ getModule WRITE setModule NOTIFY moduleChanged)
Q_OBJECT
/** Wird automatisch gelöscht, wenn das textdocument zerstört wird
* @brief highlighter
*/
CodeHighlighter * highlighter = nullptr;
Modules::Module * module = nullptr;
protected:
int countTabs(int startPos);
public:
void setModule( Modules::Module* _module){
if(_module != module){
module = _module;
QObject::disconnect(typeConnection);
if(module)
typeConnection = QObject::connect(module,&Modules::Module::typeChanged,this,&CodeEditorHelper::typeChanged);
emit moduleChanged();
}
}
Modules::Module *getModule() const {
return module;
}
CodeEditorHelper();
Q_INVOKABLE void compile();
void setDocument( QQuickTextDocument* _document){
if(_document != documentWrapper){
documentWrapper = _document;
......@@ -70,9 +90,11 @@ public:
return documentWrapper;
}
signals:
void moduleChanged();
void documentChanged();
void insertText(QString newText, int pos);
protected:
void typeChanged();
void contentsChange(int from, int charsRemoved, int charsAdded);
};
......
......@@ -41,6 +41,7 @@ int main(int argc, char *argv[])
testModulSystem.runTest();
return 0;*/
class CatchingErrorApplication : public QGuiApplication{
public:
CatchingErrorApplication(int &argc, char **argv):QGuiApplication(argc,argv){}
......@@ -109,6 +110,12 @@ int main(int argc, char *argv[])
for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) {
dataList.append(metaEnum.key(i));
}
QStringList moduleTypeList;
const QMetaObject &_mom = Modules::Module::staticMetaObject;
QMetaEnum _metaEnum =_mom.enumerator(mo.indexOfEnumerator("Type"));
for (int i = 0; i < _metaEnum.keyCount(); ++i) {
moduleTypeList.append(_metaEnum.key(i));
}
app.connect(&app,&QGuiApplication::lastWindowClosed,[&](){
QFile savePath(settings.getJsonSettingsFilePath());
......@@ -134,6 +141,8 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("ErrorNotifier",ErrorNotifier::get());
engine.setObjectOwnership(ErrorNotifier::get(),QQmlEngine::CppOwnership);
engine.rootContext()->setContextProperty("devicePrototypeModel",IDBaseDataModel<DevicePrototype>::singletone());
engine.rootContext()->setContextProperty("modulesModel",Modules::ModuleManager::singletone()->getModules());
engine.rootContext()->setContextProperty("moduleTypeModel",moduleTypeList);
engine.rootContext()->setContextProperty("deviceModel",IDBaseDataModel<Device>::singletone());
engine.rootContext()->setContextProperty("programmModel",IDBaseDataModel<Programm>::singletone());
engine.rootContext()->setContextProperty("programmPrototypeModel",IDBaseDataModel<ProgrammPrototype>::singletone());
......
......@@ -5,6 +5,7 @@
#include "device.h"
#include "programmprototype.h"
#include "programm.h"
#include "programms/modulemanager.h"
class ModelManager : public QObject{
Q_OBJECT
......@@ -39,6 +40,11 @@ public:
new Programm(name,description);
return true;
}
Q_INVOKABLE bool addModule(){
Modules::ModuleManager::singletone()->getModules()->push_back(new Modules::Module());
qDebug() << "count : "<<Modules::ModuleManager::singletone()->getModules()->size();
return true;
}
};
......
......@@ -13,14 +13,23 @@ class ModelVector : public QAbstractListModel{
/**
* @brief model The Vector holding the data
*/
std::vector<Type*> model;
std::vector<Type> model;
Type get(int index, std::true_type)const{
return model[index];
}
Type* get(int index, std::false_type)const{
return const_cast<Type*>(&model[index]);
}
public:
enum{
ModelDataRole = Qt::UserRole+1,
};
const std::vector<Type*>& getVector()const{return model;}
std::vector<Type*>& getVector(){return model;}
typename std::vector<Type*>::size_type size()const{return model.size();}
const std::vector<Type>& getVector()const{return model;}
std::vector<Type>& getVector(){return model;}
typename std::vector<Type>::size_type size()const{return model.size();}
virtual int rowCount(const QModelIndex &) const override{return static_cast<int>(model.size());}
/**
* @brief data Return always, if the index is valid, a QVarient that contains the data at the vector
......@@ -31,7 +40,7 @@ public:
virtual QVariant data(const QModelIndex &index, int role) const override{
Q_UNUSED(role);
if(index.row()>=0&&index.row()<int(model.size())){
return QVariant::fromValue(model[index.row()]);
return QVariant::fromValue(get(index.row(),std::is_pointer<Type>()));
}
return QVariant();
}
......@@ -45,7 +54,7 @@ public:
r[ModelDataRole] = "modelData";
return r;
}
Type* erase(typename std::vector<Type*>::const_iterator i){
Type erase(typename std::vector<Type>::const_iterator i){
const auto pos = i-model.begin();
beginRemoveRows(QModelIndex(),pos,pos);
auto result = *model.erase(i);
......@@ -61,28 +70,61 @@ public:
* @brief endPushBack Call this function if you have started push_backing with beginPushBack and are finisched
*/
void endPushBack(){endInsertRows();}
typename std::vector<Type*>::const_iterator cbegin()const{
typename std::vector<Type>::const_iterator cbegin()const{