Script buttons: stored scripts become commands with an icon

Every .js file in the "scripts" folder of the user's data folder that
starts with a // ==QETScript== header becomes a command: in Projet >
Scripts, as a button on a new Scripts toolbar, and, because it is
registered with ShortcutManager as diagrameditor.script.<file name>, in
the shortcut settings, the shortcut bar (S) and command search. The
header gives its name, icon (a file next to the script or a theme icon;
a tile with its initials otherwise), tooltip, default shortcut and when
it is enabled (always, with a selection, with a conductor selected).

The folder is watched, so a script added, edited or deleted while QET is
open appears, changes or goes without a restart. A file with a header
that cannot be used gets no button; the Scripts menu lists it with the
reason. The menu also opens the folder, and holds "Exécuter un script…".

A click runs the script on the current project as one undo step named
after it, and asks to switch scripting on first, like "Exécuter un
script…" does: scripting stays off by default.

ShortcutManager::unregisterAction() takes a command out of the lists
when its script is deleted, and lets it come back under a new name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-02 09:01:02 +13:00
parent b7ce89944e
commit e03e523069
12 changed files with 737 additions and 28 deletions
+5 -3
View File
@@ -113,7 +113,8 @@ namespace {
constexpr int kScriptTimeoutMs = 30000;
}
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view)
bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *view,
const QString &title)
{
// Checked here as well as at each caller, deliberately: this is the
// one function that actually evaluates JavaScript, so it is the one
@@ -173,7 +174,8 @@ bool runOnProject(const QString &scriptPath, QETProject *project, DiagramView *v
QUndoStack *stack = (view && project) ? project->undoStack() : nullptr;
if (stack) {
stack->beginMacro(QObject::tr("Script : %1")
.arg(QFileInfo(scriptPath).completeBaseName()));
.arg(title.isEmpty() ? QFileInfo(scriptPath).completeBaseName()
: title));
api->setUndoGrouped(true);
}
@@ -229,7 +231,7 @@ int run(const QStringList &)
return 1;
}
bool runOnProject(const QString &, QETProject *, DiagramView *)
bool runOnProject(const QString &, QETProject *, DiagramView *, const QString &)
{
err << "This build of QElectroTech was compiled without the Qt Qml "
"module, so JavaScript scripting is not available.\n";