diff --git a/src/plugins/score-lib-process/Process/Script/MultiScriptEditor.hpp b/src/plugins/score-lib-process/Process/Script/MultiScriptEditor.hpp index 52aac03382..5c053aa91e 100644 --- a/src/plugins/score-lib-process/Process/Script/MultiScriptEditor.hpp +++ b/src/plugins/score-lib-process/Process/Script/MultiScriptEditor.hpp @@ -27,6 +27,7 @@ class SCORE_LIB_PROCESS_EXPORT MultiScriptDialog : public QDialog void setText(int idx, const QString& str); void setError(const QString& str); void clearError(); + void openInExternalEditor(const QString& editorPath); protected: virtual void on_accepted() = 0; diff --git a/src/plugins/score-lib-process/Process/Script/ScriptEditor.cpp b/src/plugins/score-lib-process/Process/Script/ScriptEditor.cpp index 5e49d6227b..2f6011f403 100644 --- a/src/plugins/score-lib-process/Process/Script/ScriptEditor.cpp +++ b/src/plugins/score-lib-process/Process/Script/ScriptEditor.cpp @@ -3,11 +3,20 @@ #include "MultiScriptEditor.hpp" #include "ScriptWidget.hpp" +#include +#include + #include +#include #include +#include #include +#include #include +#include #include +#include +#include #include #include @@ -36,6 +45,22 @@ ScriptDialog::ScriptDialog( lay->setStretch(1, 1); auto bbox = new QDialogButtonBox{ QDialogButtonBox::Ok | QDialogButtonBox::Reset | QDialogButtonBox::Close, this}; + if(auto editorPath = QSettings{}.value("Skin/DefaultEditor").toString(); + !editorPath.isEmpty()) + { + auto openExternalBtn = new QPushButton{tr("Edit in default editor"), this}; + connect(openExternalBtn, &QPushButton::clicked, this, [this, editorPath] { + openInExternalEditor(editorPath); + }); + bbox->addButton(openExternalBtn, QDialogButtonBox::HelpRole); + openExternalBtn->setToolTip( + tr("Edit in the default editor set in Score Settings > User Interface")); + auto icon = makeIcons( + QStringLiteral(":/icons/undock_on.png"), + QStringLiteral(":/icons/undock_off.png"), + QStringLiteral(":/icons/undock_off.png")); + openExternalBtn->setIcon(icon); + } bbox->button(QDialogButtonBox::Ok)->setText(tr("Compile")); bbox->button(QDialogButtonBox::Reset)->setText(tr("Clear log")); connect(bbox->button(QDialogButtonBox::Reset), &QPushButton::clicked, this, [this] { @@ -105,6 +130,23 @@ MultiScriptDialog::MultiScriptDialog(const score::DocumentContext& ctx, QWidget* connect( bbox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::close); + + if(auto editorPath = QSettings{}.value("Skin/DefaultEditor").toString(); + !editorPath.isEmpty()) + { + auto openExternalBtn = new QPushButton{tr("Edit in default editor"), this}; + connect(openExternalBtn, &QPushButton::clicked, this, [this, editorPath] { + openInExternalEditor(editorPath); + }); + bbox->addButton(openExternalBtn, QDialogButtonBox::HelpRole); + openExternalBtn->setToolTip( + tr("Edit in the default editor set in Score Settings > User Interface")); + auto icon = makeIcons( + QStringLiteral(":/icons/undock_on.png"), + QStringLiteral(":/icons/undock_off.png"), + QStringLiteral(":/icons/undock_off.png")); + openExternalBtn->setIcon(icon); + } } void MultiScriptDialog::addTab( @@ -150,4 +192,109 @@ void MultiScriptDialog::clearError() m_error->clear(); } +void ScriptDialog::openInExternalEditor(const QString& editorPath) +{ + + if(editorPath.isEmpty()) + { + QMessageBox::warning( + this, tr("Error"), tr("no 'Default editor' configured in score settings")); + return; + } + + const QString tempFile = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + + "/ossia_script_temp.js"; + QFile file(tempFile); + if(!file.open(QIODevice::WriteOnly)) + { + QMessageBox::warning(this, tr("Error"), tr("failed to create temporary file.")); + return; + } + + file.write(this->text().toUtf8()); + + auto& w = score::FileWatch::instance(); + m_fileHandle = std::make_shared>([this, tempFile]() { + QFile file(tempFile); + if(file.open(QIODevice::ReadOnly)) + { + QString updatedContent = QString::fromUtf8(file.readAll()); + + QMetaObject::invokeMethod(m_textedit, [this, updatedContent]() { + if(m_textedit) + { + m_textedit->setPlainText(updatedContent); + } + }); + } + }); + w.add(tempFile, m_fileHandle); + + if(!QProcess::startDetached(editorPath, QStringList{tempFile})) + { + QMessageBox::warning(this, tr("Error"), tr("failed to launch external editor")); + } +} + +void ScriptDialog::stopWatchingFile(const QString& tempFile) +{ + if(tempFile.isEmpty()) + { + return; + } + + auto& w = score::FileWatch::instance(); + w.remove(tempFile, m_fileHandle); + m_fileHandle.reset(); +} +void MultiScriptDialog::openInExternalEditor(const QString& editorPath) +{ + if(editorPath.isEmpty()) + { + QMessageBox::warning( + this, tr("Error"), tr("no 'Default editor' configured in score settings")); + return; + } + + if(!QFile::exists(editorPath)) + { + QMessageBox::warning( + this, tr("Error"), tr("the configured external editor does not exist.")); + return; + } + + QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + QDir dir(tempDir); + QStringList openedFiles; + + for(int i = 0; i < m_tabs->count(); ++i) + { + QString tabName = m_tabs->tabText(i); + QString tempFile = tempDir + "/" + tabName + ".js"; + + QFile file(tempFile); + if(!file.open(QIODevice::WriteOnly)) + { + QMessageBox::warning(this, tr("Error"), tr("failed to create temporary files.")); + return; + } + + QWidget* widget = m_tabs->widget(i); + QTextEdit* textedit = qobject_cast(widget); + + if(textedit) + { + QString content = textedit->document()->toPlainText(); + file.write(content.toUtf8()); + } + + openedFiles.append(tempFile); + } + + if(!openedFiles.isEmpty() && !QProcess::startDetached(editorPath, openedFiles)) + { + QMessageBox::warning(this, tr("Error"), tr("Failed to launch external editor")); + } +} + } diff --git a/src/plugins/score-lib-process/Process/Script/ScriptEditor.hpp b/src/plugins/score-lib-process/Process/Script/ScriptEditor.hpp index 1de5d989a4..cd36db7092 100644 --- a/src/plugins/score-lib-process/Process/Script/ScriptEditor.hpp +++ b/src/plugins/score-lib-process/Process/Script/ScriptEditor.hpp @@ -28,6 +28,8 @@ class SCORE_LIB_PROCESS_EXPORT ScriptDialog : public QDialog void setText(const QString& str); void setError(int line, const QString& str); + void openInExternalEditor(const QString& editorPath); + void stopWatchingFile(const QString& tempFile); protected: virtual void on_accepted() = 0; @@ -35,6 +37,9 @@ class SCORE_LIB_PROCESS_EXPORT ScriptDialog : public QDialog const score::DocumentContext& m_context; QTextEdit* m_textedit{}; QPlainTextEdit* m_error{}; + +private: + std::shared_ptr> m_fileHandle; }; template