Commit f4127f2a authored by Leander Schulten's avatar Leander Schulten
Browse files

Add Properties to the ModuleView(you can add,edit,delete them and use them in code)

parent 41d26db6
......@@ -2,6 +2,8 @@ import QtQuick 2.11
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
import custom.licht 1.0
import QtQuick.Controls.Material 2.2
import QtQuick.Dialogs 1.2
Item{
id: root
......@@ -11,23 +13,10 @@ Item{
anchors.top : parent.top
anchors.bottom: parent.bottom
width: 300
//interactive: false
id: swipeView
/*function switchTab(){
if(tab1.x===0){
tab1.x = -width;
tab2.x = 0;
}else{
tab1.x = 0;
tab2.x = width;
}
}*/
Page{
id:tab1
Behavior on x {
NumberAnimation { easing.type: Easing.InOutCubic; easing.amplitude: 9; easing.period: 50.0; duration: 200 }
}
width: parent.width
anchors.top: parent.top
anchors.bottom: parent.bottom
......@@ -45,9 +34,6 @@ Item{
text: modelData.name + " (" + moduleTypeModel[modelData.type] + ')'
onClicked: {
listView.currentIndex = index;
// for (var prop in moduleTypeModel) {
// print(prop += " (" + typeof(moduleTypeModel[prop]) + ") = " + moduleTypeModel[prop]);
// }
}
}
highlight: Rectangle{
......@@ -72,60 +58,18 @@ Item{
id: buttonRemove
text:"Remove"
font.pixelSize: 15
onClicked: {
var index = listView.currentIndex;
if(index === 0){
listView.currentIndex = 1;
}else{
listView.currentIndex = index - 1;
}
ModelManager.removeModule(index);
}
}
}
}
/*Page{
x: 9999 // far far away, nobody should see this Component at Lunch time
id:tab2
Behavior on x {
NumberAnimation { easing.type: Easing.InOutCubic; easing.amplitude: 9; easing.period: 50.0; duration: 200 }
}
width: parent.width
anchors.top: parent.top
anchors.bottom: parent.bottom
//height: 500
//width: 300
//clip: true
//anchors.fill: parent
header: ItemDelegate{
id:backDelegate
text: "Back"
onClicked: swipeView.switchTab()
}
ListView{
id:listView2
delegate: ItemDelegate{
width: parent.width
text: " test : " + itemData.name +"("+itemData.description+")"
onClicked: listView.currentIndex = index
}
highlight: Rectangle{
color: "blue"
opacity: 0.7
}
model: devicePrototypeModel
}
footer: RowLayout{
Button{
Layout.preferredWidth: listView.width/2 -5
Layout.leftMargin: 5
id: buttonAdd2
text:"Add"
font.pixelSize: 15
}
Button{
Layout.preferredWidth: listView.width/2 -10
Layout.rightMargin: 10
id: buttonRemove2
text:"Remove"
font.pixelSize: 15
}
}
}*/
}
GridLayout{
......@@ -172,23 +116,82 @@ Item{
ListView{
id: propertyView
Layout.fillWidth: true
anchors.bottomMargin: -20
clip: true
Layout.preferredHeight: Math.max(50,Math.min(model.rowCount() * 20,120))
onModelChanged:{ for (var prop in model) {
print(prop += " (" + typeof(model[prop]) + ") = " + model[prop]);
}
}
model: listView.currentItem.itemData.properties
delegate: ItemDelegate{
text: name
id:delegate
property var modelEntry : modelData
text: modelData.name
width: propertyView.width
height: 20
}
Layout.preferredHeight: 50
model: ListModel{
ListElement{
name: "Prop1"
Component.onCompleted: console.log(modelEntry)
onClicked: {
dialog.prop = modelEntry;
dialog.visible = true;
}
ListElement{
name: "Prop2"
Button{
id:removeProp
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: addProp.left
anchors.topMargin: -4
anchors.bottomMargin: -4
Material.elevation: 0
width: height
onClicked: listView.currentItem.itemData.removeProperty(delegate.modelEntry)
Image {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
height: 24
width: 24
source: "icons/remove.svg"
}
}
ListElement{
name: "Prop2"
Button{
id: addProp
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.topMargin: -4
anchors.bottomMargin: -4
width: height
Material.elevation: 0
onClicked: {
dialog.prop = listView.currentItem.itemData.createNewProperty();
dialog.visible = true;
}
Image {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
height: 24
width: 24
source: "icons/add.svg"
}
}
}
Button{
visible: propertyView.count === 0
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
width: height
Material.elevation: 0
onClicked: {
dialog.prop = listView.currentItem.itemData.createNewProperty();
dialog.visible = true;
}
Image {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
height: 24
width: 24
source: "icons/add.svg"
}
}
}
......@@ -224,6 +227,10 @@ Item{
codeEditor.deselect();
codeEditor.cursorPosition = pos;
}
onInformation:{
informationDialog.text = text
informationDialog.visible = true;
}
}
}
}
......@@ -237,5 +244,117 @@ Item{
}
MessageDialog{
id: informationDialog
}
Dialog{
property var prop;
onPropChanged: print(prop.typ)
modality: Qt.WindowModal
title: "Add/Change Property"
width:300
id: dialog
contentItem: Pane {
GridLayout{
anchors.fill: parent
columns: 2
Label{
text: "Name"
}
TextInputField{
id:name
Layout.fillWidth: true
text:dialog.prop.name
validator: RegExpValidator{
regExp: /[a-z][a-z_0-9]*$/i
}
}
Label{
text:"Beschreibung"
}
TextInputField{
id:besch
Layout.fillWidth: true
text:dialog.prop.description
}
Label{
text:"Typ"
}
ComboBox{
currentIndex: dialog.prop.type
id:type
model: modolePropertyTypeList
Layout.fillWidth: true
onCurrentIndexChanged: {
// "Int" << "Long" << "Float" << "Double" << "Bool" << "String";
minVal.enabled = currentIndex>=0 && currentIndex <=3;
maxVal.enabled = currentIndex>=0 && currentIndex <=3;
defaultVal.enabled = currentIndex>=0 && currentIndex <=4;
if(currentIndex === 4){
defaultVal.validator.top = 1;
defaultVal.validator.bottom = 0;
}else{
defaultVal.validator.top = 2^31;
defaultVal.validator.bottom = -2^31;
}
}
}
Label{
text:"min value"
}
TextInputField{
Layout.fillWidth: true
id: minVal
validator: IntValidator{}
text:type.currentIndex === 4 ? "0" : type.currentIndex === 5 ? "" : dialog.prop.minValue
}
Label{
text:"max value"
}
TextInputField{
Layout.fillWidth: true
id:maxVal
validator: IntValidator{}
text:type.currentIndex === 4 ? "1" : type.currentIndex === 5 ? "" : dialog.prop.maxValue
}
Label{
text:"default value"
}
TextInputField{
text: type.currentIndex !== 5 ? dialog.prop.defaultValue : ""
Layout.fillWidth: true
id:defaultVal
enabled: type.currentIndex !== 5
validator: IntValidator{
top: dialog.prop.maxValue
bottom: dialog.prop.minValue
}
}
RowLayout{
Layout.columnSpan: 2
Button{
Layout.fillWidth: true
text:"Abbrechen"
onClicked: dialog.visible = false
}
Button{
Layout.fillWidth: true
text:"Übernehmen"
onClicked: {
dialog.visible = false
dialog.prop.name = name.text;
dialog.prop.description = besch.text;
dialog.prop.type = type.currentIndex;
if(minVal.text.length!==0)dialog.prop.minValue = minVal.text
if(maxVal.text.length!==0)dialog.prop.maxValue = maxVal.text
if(defaultVal.text.length!==0)dialog.prop.defaultValue = defaultVal.text
}
}
}
}
}
}
}
......@@ -21,7 +21,7 @@ CodeHighlighter::CodeHighlighter(QTextDocument * parent):QSyntaxHighlighter (par
<< "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b"
<< "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b"
<< "\\bvoid\\b" << "\\bvolatile\\b" << "\\bbool\\b"
<< "\\bauto\\b" << "\\bfor\\b" << "\\bwhile\\b" ;
<< "\\bauto\\b" << "\\bfor\\b" << "\\bwhile\\b" << "\\breturn\\b" ;
foreach (const QString &pattern, keywordPatterns) {
rule.pattern = QRegularExpression(pattern);
rule.format = keywordFormat;
......@@ -63,7 +63,7 @@ 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";
code += "ProgramState doStep(time_diff_t diff_ms){\n\treturn {false/*finished*/,true/*output changed*/};\n}\n\n";
return code;
}
......@@ -233,9 +233,92 @@ QTextStream& writeConstructor(QTextStream& out, const Modules::detail::PropertyI
return out;
}
std::vector<int> findPropertyInsertionPoints(const QString &userCode){
std::vector<int> pos;
int lastIndex = 0;
while (lastIndex>=0) {
int index = userCode.indexOf("filter",lastIndex);
if(index<0)
index = userCode.indexOf("doStep",lastIndex);
if(index>=0){
lastIndex = index = userCode.indexOf("{",index) + 1;
pos.push_back(lastIndex);
}else{
lastIndex = -1;
}
}
return pos;
}
void writeLocalPropertiesAssigments(QTextStream& out, const Modules::PropertiesVector & vec){
for(const auto p : vec){
switch (p->getType()) {
case Modules::Property::Int:
case Modules::Property::Double:
case Modules::Property::Float:
case Modules::Property::Long:
out << "\tauto " << p->getName() << " = _" << p->getName() << ".asNumeric<" << toName(p->getType()) << ">()->getValue();\n";
break;
case Modules::Property::Bool:
out << "\tauto " << p->getName() << " = _" << p->getName() << ".asBool()->getValue();\n";
break;
case Modules::Property::String:
out << "\tauto " << p->getName() << " = _" << p->getName() << ".asString()->getString();\n";
break;
}
}
}
QTextStream& writeUserCode(QTextStream& out, QString userCode, const Modules::PropertiesVector & vec){
using namespace Modules;
auto positions = findPropertyInsertionPoints(userCode);
if(positions.size()==0){
out << userCode;
}else if(positions.size()==1){
out << userCode.leftRef(positions[0]) << '\n';
writeLocalPropertiesAssigments(out,vec);
out << userCode.rightRef(userCode.length() - positions[0]);
}else{
positions.insert(positions.begin(),0);
for(unsigned int i = 1 ; i < positions.size(); ++i){
out << userCode.midRef(positions[i-1],positions[i]-positions[i-1]) << '\n';
writeLocalPropertiesAssigments(out,vec);
}
out << userCode.mid(positions.back());
}
return out;
}
QString getPropertiesNumericContructors(const Modules::PropertiesVector & vec){
QString s = ":";
for(const auto p : vec){
switch (p->getType()) {
case Modules::Property::Int:
case Modules::Property::Double:
case Modules::Property::Float:
case Modules::Property::Long:
s += "_" + p->getName() + "("+ QString::number(p->getMinValue())+","+QString::number(p->getMaxValue())+","+QString::number(p->getDefaultValue()) +"),";
break;
case Modules::Property::Bool:
s += "_" + p->getName() + "("+ QString::number(p->getDefaultValue()) +"),";
}
}
if(s.length()==1)
return "";
return s.remove(s.length()-1,1);
}
void CodeEditorHelper::compile(){
if(!module)
return;
for(const auto p1 : module->getProperties()){
for(const auto p2 : module->getProperties()){
if(p1 != p2 && p1->getName() == p2->getName()){
emit information("Es gibt mehrere Properties mit dem Namen : " + p1->getName() +"\nBreche Compilieren ab.");
return;
}
}
}
Settings s;
QFile file( s.getModuleDirPath() + "/" + module->getName() + ".cpp" );
file.remove();
......@@ -259,8 +342,10 @@ void CodeEditorHelper::compile(){
return;
}
stream << "#include <programms/module.h>" << endl;
stream << "#include <cmath>"<<endl;
stream << "" << endl;
stream << "using namespace Modules;" << endl;
stream << "using namespace std;" << endl;
stream << "" << endl;
if(module->getType() == Modules::Module::Filter){
stream << "class Impl : public Typed" << typeName << "<"<<valueName<<","<<valueName<<">{"<< endl;
......@@ -271,7 +356,7 @@ void CodeEditorHelper::compile(){
writeDeclaration(stream,p);
}
stream << "public:" << endl;
stream << "Impl(){" << endl;
stream << "Impl()" << getPropertiesNumericContructors(module->getProperties()) <<"{" << endl;
for(const auto &p : module->getProperties()){
writeConstructor(stream,p);
}
......@@ -280,7 +365,7 @@ void CodeEditorHelper::compile(){
stream << "return \"" << module->getName()<< "\";" << endl;
stream << "}" << endl;
stream << "" << endl;
stream << document->toPlainText();
writeUserCode(stream,document->toPlainText(),module->getProperties()); // write Code from document
stream << "" << endl;
stream << "};" << endl; // class end
stream << "" << endl;
......@@ -308,15 +393,20 @@ void CodeEditorHelper::compile(){
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 << " 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");
auto result = Modules::Compiler::compileToLibrary(file,module->getName()+".dll");
if(result.first){
QFileInfo finfo = file;
emit information(result.second.replace(finfo.absoluteFilePath(),""));
}else
emit information("Compilieren erfolgreich.");
}
}
......@@ -90,6 +90,7 @@ public:
return documentWrapper;
}
signals:
void information(QString text);
void moduleChanged();
void documentChanged();
void insertText(QString newText, int pos);
......
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 13H5v-2h14v2z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11H7v-2h10v2z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M19 13H5v-2h14v2z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
......@@ -91,6 +91,8 @@ int main(int argc, char *argv[])
qRegisterMetaType<DMXChannelFilter::Operation>("Operation");
qmlRegisterUncreatableType<UserManagment>("custom.licht",1,0,"Permission","Singletone in c++");
qRegisterMetaType<UserManagment::Permission>("Permission");
qRegisterMetaType<Modules::detail::PropertyInformation::Type>("Type");
qRegisterMetaType<Modules::PropertiesVector*>("PropertiesVector*");
Settings settings;
settings.setJsonSettingsFilePath("QTJSONFile.json");
QFile file(settings.getJsonSettingsFilePath());
......@@ -117,6 +119,16 @@ int main(int argc, char *argv[])
moduleTypeList.append(_metaEnum.key(i));
}
QStringList modolePropertyTypeList;
modolePropertyTypeList << "Int" << "Long" << "Float" << "Double" << "Bool" << "String";
// Does not work: do it manually
/*const QMetaObject &_momProp = Modules::detail::PropertyInformation::staticMetaObject;
qDebug() << "Enum count" <<_momProp.enumeratorCount();
QMetaEnum _metaEnumP =_momProp.enumerator(mo.indexOfEnumerator("Type"));
for (int i = 0; i < _metaEnumP.keyCount(); ++i) {
modolePropertyTypeList.append(_metaEnumP.key(i));
}*/
app.connect(&app,&QGuiApplication::lastWindowClosed,[&](){
QFile savePath(settings.getJsonSettingsFilePath());
ApplicationData::saveData(savePath);
......@@ -143,6 +155,7 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("devicePrototypeModel",IDBaseDataModel<DevicePrototype>::singletone());
engine.rootContext()->setContextProperty("modulesModel",Modules::ModuleManager::singletone()->getModules());
engine.rootContext()->setContextProperty("moduleTypeModel",moduleTypeList);
engine.rootContext()->setContextProperty("modolePropertyTypeList",modolePropertyTypeList);
engine.rootContext()->setContextProperty("deviceModel",IDBaseDataModel<Device>::singletone());
engine.rootContext()->setContextProperty("programmModel",IDBaseDataModel<Programm>::singletone());
engine.rootContext()->setContextProperty("programmPrototypeModel",IDBaseDataModel<ProgrammPrototype>::singletone());
......
......@@ -45,6 +45,12 @@ public:
qDebug() << "count : "<<Modules::ModuleManager::singletone()->getModules()->size();
return true;
}
Q_INVOKABLE void removeModule(int index){
const auto vec = Modules::ModuleManager::singletone()->getModules();
if(index>=0 && index < vec->size()){
delete vec->erase(index);
}
}
};
......
......@@ -54,11 +54,18 @@ public:
r[ModelDataRole] = "modelData";
return r;
}
Type erase(typename std::vector<Type>::const_iterator i){
void erase(typename std::vector<Type>::const_iterator i){
const auto pos = i-model.begin();