mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-17 19:34:13 +02:00
Add JavaScript scripting: --run and "Run Script..." (bugtracker #162)
Following up on my own comments there: a deliberately small, mostly read-only scripting surface, exposed to scripts as a single global `qet` object (QetScriptApi) built on QJSEngine rather than an embedded Python interpreter -- no new toolchain to package (QJSEngine ships in every Qt SDK QET already targets, via the Qml module), no GIL, no version pinning, automatic reflection of the QObject-derived core classes' own methods with no hand-written binding layer. ## What a script can do - Read the model: project title, file path, folio count/titles, element/conductor counts per folio. - Trigger the same operations the --export-* CLI flags already do (pdf/png/svg/cables/wires/bom/wiring/nets/links/info), plus set-titleblock and save -- thin wrappers around CLIExport::run(), reusing its already-tested logic rather than duplicating it. Deliberately NOT in this version: creating or editing diagram geometry, undo integration, driving the GUI. All explicitly out of scope per the discussion on #162. ## Two entry points, both built and tested - `qelectrotech --run script.js project.qet` -- headless/CI. - Projet > "Exécuter un script..." -- an interactive macro against the currently open project. Export/save calls act on the project's file on disk (see QetScriptApi's class comment for why), so unsaved GUI edits aren't visible to the script; save first if that matters. ## Optional dependency, not a hard requirement Qt::Qml is probed the same way QtPdf already is in this codebase: QUIET, non-fatal, behind a QET_HAS_SCRIPTING compile definition. A build without it compiles and links identically; the CLI flag and menu action are simply absent (main.cpp) or compile to a clear "not available" stderr message rather than silently disappearing (qetscripting.cpp), matching the existing QtPdf pattern rather than introducing a new one. One real bug caught building this, not assumed away: my first pass conditionally excluded the new source files from QET_SRC_FILES behind `if(QET_HAS_SCRIPTING)` inside qet_compilation_vars.cmake -- but that file is included before QET_HAS_SCRIPTING is set in the top-level CMakeLists.txt, so the variable didn't exist yet at that point and the files were silently never compiled, only caught by an undefined-symbol link error. Fixed by following the QtPdf file's own precedent: compile the files unconditionally, guard their Qt::Qml-dependent content internally instead. ## Verified Qt6, build clean, ctest 6/6. - Headless: a script reading project/folio/element/conductor counts, calling exportInfo() and exportPdf() against a real project -- correct JSON, a real single-page PDF confirmed with `file`. Error paths: a thrown script exception reports file:line:message and exit 1; missing script/project arguments exit 2 (matching CLIExport's own usage-error convention); a missing project file is reported and does not hang. - Corpus: the same read-model script run against all 24 shipped example projects, 0 failures. - GUI: "Exécuter un script..." opens a real file dialog filtered to *.js, running the picked script against the live open project produced the exact expected JSON export file, and the application was still fully responsive afterward. Refs #162. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qetdiagrameditor.h"
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
#include "scripting/qetscripting.h"
|
||||
#endif
|
||||
#include <QCoreApplication>
|
||||
#include "ElementsCollection/elementscollectionwidget.h"
|
||||
#include "QWidgetAnimation/qwidgetanimation.h"
|
||||
@@ -549,6 +552,15 @@ void QETDiagramEditor::setUpActions()
|
||||
m_terminal_numbering = new QAction(QET::Icons::TerminalStrip, tr("Numérotation automatique des bornes"), this);
|
||||
connect(m_terminal_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_terminalNumbering);
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
// Run a JavaScript macro against the current project (bugtracker #162).
|
||||
m_run_script = new QAction(tr("Exécuter un script..."), this);
|
||||
m_run_script->setStatusTip(
|
||||
tr("Exécute un script JavaScript sur le projet courant (voir qet.*"
|
||||
" dans le script pour l'API disponible)"));
|
||||
connect(m_run_script, &QAction::triggered, this, &QETDiagramEditor::slot_runScript);
|
||||
#endif
|
||||
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
|
||||
connect(m_export_project_db, &QAction::triggered, [this]() {
|
||||
@@ -1002,6 +1014,9 @@ void QETDiagramEditor::setUpMenu()
|
||||
menu_project -> addAction(m_project_export_wiring_list);
|
||||
menu_project -> addAction(m_project_wiring_list_view);
|
||||
menu_project -> addAction(m_terminal_numbering);
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
menu_project -> addAction(m_run_script);
|
||||
#endif
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
menu_project -> addSeparator();
|
||||
menu_project -> addAction(m_export_project_db);
|
||||
@@ -1856,6 +1871,9 @@ void QETDiagramEditor::slot_updateActions()
|
||||
m_project_export_wiring_list -> setEnabled(opened_project);
|
||||
m_project_wiring_list_view -> setEnabled(opened_project);
|
||||
m_terminal_numbering -> setEnabled(editable_project);
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
m_run_script -> setEnabled(opened_project);
|
||||
#endif
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db -> setEnabled(editable_project);
|
||||
#endif
|
||||
@@ -2970,3 +2988,29 @@ void QETDiagramEditor::slot_terminalNumbering() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
/**
|
||||
@brief QETDiagramEditor::slot_runScript
|
||||
Run a JavaScript macro against the current project (bugtracker #162).
|
||||
See QetScriptApi for what a script can do -- read-mostly: folio/element/
|
||||
conductor counts and the same export operations the --export-* CLI
|
||||
flags provide. Export/save calls inside the script act on this
|
||||
project's file on disk, so unsaved edits in the open editor are not
|
||||
visible to the script; save first if that matters.
|
||||
*/
|
||||
void QETDiagramEditor::slot_runScript() {
|
||||
QETProject *project = currentProject();
|
||||
if (!project) return;
|
||||
|
||||
const QString script_path = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("Exécuter un script"),
|
||||
QString(),
|
||||
tr("Scripts JavaScript (*.js);;Tous les fichiers (*)")
|
||||
);
|
||||
if (script_path.isEmpty()) return;
|
||||
|
||||
QetScripting::runOnProject(script_path, project);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user