mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-29 22:24: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:
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
QElectroTech is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
QElectroTech is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QET_SCRIPT_API_H
|
||||
#define QET_SCRIPT_API_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class QETProject;
|
||||
|
||||
/**
|
||||
@brief The QetScriptApi class
|
||||
The object a script sees as `qet` (bugtracker #162): a small,
|
||||
deliberately read-mostly surface over an open project, for scripted
|
||||
batch/CI work and human-written macros.
|
||||
|
||||
@b Scope, on purpose: this reads the model (folio count, titles, element
|
||||
and conductor counts -- the same data the `--info` CLI export already
|
||||
reports) and can trigger the same export/save operations the `--export-*`
|
||||
CLI flags already do. It does not create or edit diagram geometry, does
|
||||
not touch the undo stack, and does not drive the GUI. Those are all
|
||||
explicitly out of scope for this first version; see the discussion on
|
||||
bugtracker #162.
|
||||
|
||||
Export/save methods are thin wrappers around CLIExport::run() -- the
|
||||
exact same, already-tested code path the `--export-*` flags use -- built
|
||||
from the project's own file path, not the live in-memory instance. That
|
||||
keeps this file free of any dependency on cli_export.cpp's internals,
|
||||
at the cost of re-opening the project from disk for each call: fine for
|
||||
the batch/CI use case this targets, and for the headless `--run` entry
|
||||
point it's exactly what a second `--export-*` invocation would have
|
||||
done anyway. A macro acting on unsaved GUI edits should call save()
|
||||
first.
|
||||
*/
|
||||
class QetScriptApi : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QetScriptApi(QETProject *project, QObject *parent = nullptr);
|
||||
|
||||
// -- read the model --
|
||||
Q_INVOKABLE QString projectTitle() const;
|
||||
Q_INVOKABLE QString filePath() const;
|
||||
Q_INVOKABLE int folioCount() const;
|
||||
Q_INVOKABLE QString folioTitle(int index) const;
|
||||
Q_INVOKABLE int elementCount(int folioIndex) const;
|
||||
Q_INVOKABLE int conductorCount(int folioIndex) const;
|
||||
|
||||
// -- export / save: thin wrappers around the --export-* CLI paths --
|
||||
Q_INVOKABLE bool exportPdf(const QString &output, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportPng(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportSvg(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportCables(const QString &output);
|
||||
Q_INVOKABLE bool exportWires(const QString &output);
|
||||
Q_INVOKABLE bool exportBom(const QString &output);
|
||||
Q_INVOKABLE bool exportWiring(const QString &output);
|
||||
Q_INVOKABLE bool exportNets(const QString &output);
|
||||
Q_INVOKABLE bool exportLinks(const QString &output);
|
||||
Q_INVOKABLE bool exportInfo(const QString &output);
|
||||
Q_INVOKABLE bool setTitleBlock(const QString &output, const QStringList &assignments);
|
||||
Q_INVOKABLE bool save(const QString &output);
|
||||
|
||||
// -- logging: a script has no console of its own --
|
||||
Q_INVOKABLE void log(const QString &message);
|
||||
|
||||
private:
|
||||
bool runFlag(const QString &flag, const QStringList &args);
|
||||
|
||||
QETProject *m_project;
|
||||
};
|
||||
|
||||
#endif // QET_SCRIPT_API_H
|
||||
Reference in New Issue
Block a user