From 77af0b7db96bfe34dd64467334be18d23cbb5cf2 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 7 Aug 2024 10:54:05 +0200 Subject: [PATCH] feat: Handle QTextEdit in the ScriptDialogItem (#141) Fixes KDAB#27 to use the syntax highlighting of the "data.foo" widget, just use the name of the extension like "cpp", "js" or "py" in the "data.fooSyntax" property --- examples/ex_script_dialog.qml | 18 ++++++++--- examples/ex_script_dialog.ui | 59 +++++++++++++++++++--------------- src/core/CMakeLists.txt | 1 + src/core/scriptdialogitem.cpp | 60 +++++++++++++++++++++++++++++++++++ src/core/scriptdialogitem.h | 7 ++++ 5 files changed, 114 insertions(+), 31 deletions(-) diff --git a/examples/ex_script_dialog.qml b/examples/ex_script_dialog.qml index 259f0596..233c6cf3 100644 --- a/examples/ex_script_dialog.qml +++ b/examples/ex_script_dialog.qml @@ -26,6 +26,12 @@ ScriptDialog { // Defined the possible choices for the comboBoxfine data.comboBoxModel = ["1", "2", "3"] data.comboBox = "2" + // Initialize textEdit and plainTextEdit with example text and syntax + data.textEdit = "// Example C++ code\nint main() {\n return 0;\n}" + data.textEditSyntax = "cpp" + data.plainTextEdit = "// Example JavaScript code\nfunction hello() {\n console.log('Hello');\n}" + data.plainTextEditSyntax = "js" + } function showData() { @@ -36,6 +42,8 @@ ScriptDialog { Message.log("SpinBox data: " + data.spinBox) Message.log("DoubleSpinBox data: " + data.doubleSpinBox) Message.log("ComboBox data: " + data.comboBox) + Message.log("TextEdit data: " + data.textEdit) + Message.log("PlainTextEdit data: " + data.plainTextEdit) } // Function called when the user click on the OK button @@ -46,21 +54,21 @@ ScriptDialog { // Function called when the user click on the Cancel button onRejected: { - // Logging when the Cancel button is clicked + // Logging when the Cancel button is clicked Message.log("Cancel button is clicked") } // Function called when a button is clicked - onClicked:(name)=>{ - if (name == "pushButton"){ + onClicked: (name) => { + if (name === "pushButton") { Message.log("PushButton is clicked") - } - else if (name == "toolButton"){ + } else if (name === "toolButton") { Message.log("ToolButton is clicked") } } // Function to automatically test the script, useful for automated testing // It runs the script without user interaction + function test_script() { showData(); close(); diff --git a/examples/ex_script_dialog.ui b/examples/ex_script_dialog.ui index a368f9eb..2ebb2d07 100644 --- a/examples/ex_script_dialog.ui +++ b/examples/ex_script_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 407 - 374 + 291 + 471 @@ -28,6 +28,23 @@ + + + + toolButton + + + + + + + true + + + ToolButton + + + @@ -100,47 +117,37 @@ - - - - Qt::Vertical - - - - 20 - 249 - - - - - + dialogButtonBox - + QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - true - + + + + + + + + - ToolButton + textEdit - - + + - toolButton + plainTextEdit diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2c2d3045..ef367584 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -117,6 +117,7 @@ target_link_libraries( PUBLIC nlohmann_json::nlohmann_json pugixml::pugixml kdalgorithms + KF5SyntaxHighlighting Qt::Core Qt::CorePrivate Qt::Qml diff --git a/src/core/scriptdialogitem.cpp b/src/core/scriptdialogitem.cpp index e2402edb..ee68c2ab 100644 --- a/src/core/scriptdialogitem.cpp +++ b/src/core/scriptdialogitem.cpp @@ -15,7 +15,13 @@ #include "settings.h" #include "utils/log.h" +#include +#include +#include +#include + #include +#include #include #include #include @@ -29,10 +35,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -552,6 +560,22 @@ void ScriptDialogItem::createProperties(QWidget *dialogWidget) completer->setModel(comboBox->model()); comboBox->setCompleter(completer); } + } else if (auto textEdit = qobject_cast(widget)) { + m_data->addProperty(widget->objectName().toLocal8Bit(), "QString", QMetaType::QString, + textEdit->toPlainText()); + connect(textEdit, &QTextEdit::textChanged, this, [this, textEdit]() { + m_data->setProperty(sender()->objectName().toLocal8Bit(), textEdit->toPlainText()); + }); + m_data->addProperty((widget->objectName() + "Syntax").toLocal8Bit(), "QString", QMetaType::QString, + QString()); + } else if (auto plainTextEdit = qobject_cast(widget)) { + m_data->addProperty(widget->objectName().toLocal8Bit(), "QString", QMetaType::QString, + plainTextEdit->toPlainText()); + connect(plainTextEdit, &QPlainTextEdit::textChanged, this, [this, plainTextEdit]() { + m_data->setProperty(sender()->objectName().toLocal8Bit(), plainTextEdit->toPlainText()); + }); + m_data->addProperty((widget->objectName() + "Syntax").toLocal8Bit(), "QString", QMetaType::QString, + QString()); } } @@ -580,6 +604,16 @@ void ScriptDialogItem::changeValue(const QString &key, const QVariant &value) } else if (auto comboBox = qobject_cast(widget)) { comboBox->setCurrentText(value.toString()); return; + } else if (auto textEdit = qobject_cast(widget)) { + QString valueString = value.toString(); + if (textEdit->toPlainText() != valueString) + textEdit->setPlainText(value.toString()); + return; + } else if (auto plainTextEdit = qobject_cast(widget)) { + QString valueString = value.toString(); + if (plainTextEdit->toPlainText() != valueString) + plainTextEdit->setPlainText(value.toString()); + return; } // It may be a combobox model @@ -593,6 +627,16 @@ void ScriptDialogItem::changeValue(const QString &key, const QVariant &value) return; } + // It may be a syntax rule + if (key.endsWith("Syntax")) { + if (auto textEdit = findChild(key.left(key.length() - 6))) { + applySyntaxHighlighting(textEdit->document(), value.toString()); + } else if (auto plainTextEdit = findChild(key.left(key.length() - 6))) { + applySyntaxHighlighting(plainTextEdit->document(), value.toString()); + } + return; + } + if (!widget) { spdlog::warn("No widget found for the key '{}'.", key.toStdString()); } else { @@ -601,6 +645,22 @@ void ScriptDialogItem::changeValue(const QString &key, const QVariant &value) } } +void ScriptDialogItem::applySyntaxHighlighting(QTextDocument *document, const QString &syntax) +{ + if (!syntax.isEmpty()) { + auto highlighter = new KSyntaxHighlighting::SyntaxHighlighter(document); + static KSyntaxHighlighting::Repository repository; + highlighter->setTheme(repository.themeForPalette(QApplication::palette())); + const auto definition = repository.definitionForFileName("." + syntax); + if (!definition.isValid()) { + qWarning() << "No valid syntax definition for file extension" << syntax; + delete highlighter; + return; + } + highlighter->setDefinition(definition); + } +} + void ScriptDialogItem::appendChild(QQmlListProperty *list, QObject *obj) { if (auto that = qobject_cast(list->object)) { diff --git a/src/core/scriptdialogitem.h b/src/core/scriptdialogitem.h index 7b6b26a0..df67622b 100644 --- a/src/core/scriptdialogitem.h +++ b/src/core/scriptdialogitem.h @@ -18,6 +18,11 @@ #include class ScriptProgressDialog; +class QTextDocument; + +namespace KSyntaxHighlighting { +class SyntaxHighlighter; +} namespace Core { @@ -85,6 +90,8 @@ public slots: static qsizetype countChildren(QQmlListProperty *list); static void clearChildren(QQmlListProperty *list); + void applySyntaxHighlighting(QTextDocument *document, const QString &syntax); + private: DynamicObject *m_data; std::vector m_children;