mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-04 09:54:13 +02:00
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:
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <QtTest>
|
||||
|
||||
#include <QAction>
|
||||
|
||||
#include "scripting/scriptheader.h"
|
||||
#include "shortcutmanager.h"
|
||||
|
||||
// The header that turns a stored script into a button, and taking a
|
||||
// command out of ShortcutManager again when its script is deleted.
|
||||
class tst_scriptheader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
static QString script(const QString &lines)
|
||||
{
|
||||
return QStringLiteral("// ==QETScript==\n") + lines
|
||||
+ QStringLiteral("// ==/QETScript==\nqet.log('x');\n");
|
||||
}
|
||||
|
||||
private slots:
|
||||
void fullHeader()
|
||||
{
|
||||
const ScriptHeader h = ScriptHeader::parse(script(QStringLiteral(
|
||||
"// @name Add revision note\n"
|
||||
"// @icon note.svg\n"
|
||||
"// @tooltip Puts a note on the folio\n"
|
||||
"// @shortcut Ctrl+Alt+R\n"
|
||||
"// @context selection\n"
|
||||
"// @api 1\n")), QStringLiteral("add-note"));
|
||||
QVERIFY2(h.isValid(), qPrintable(h.error));
|
||||
QCOMPARE(h.id, QStringLiteral("add-note"));
|
||||
QCOMPARE(h.name, QStringLiteral("Add revision note"));
|
||||
QCOMPARE(h.icon, QStringLiteral("note.svg"));
|
||||
QCOMPARE(h.tooltip, QStringLiteral("Puts a note on the folio"));
|
||||
QCOMPARE(h.shortcut, QStringLiteral("Ctrl+Alt+R"));
|
||||
QCOMPARE(h.context, QStringLiteral("selection"));
|
||||
QCOMPARE(h.api, 1);
|
||||
}
|
||||
|
||||
void nameAloneIsEnough()
|
||||
{
|
||||
const ScriptHeader h = ScriptHeader::parse(
|
||||
script(QStringLiteral("// @name Just a name\n")), QStringLiteral("a"));
|
||||
QVERIFY2(h.isValid(), qPrintable(h.error));
|
||||
QCOMPARE(h.context, QStringLiteral("canvas"));
|
||||
QVERIFY(h.icon.isEmpty());
|
||||
}
|
||||
|
||||
void refused_data()
|
||||
{
|
||||
QTest::addColumn<QString>("text");
|
||||
QTest::addColumn<QString>("error");
|
||||
QTest::newRow("no header") << QStringLiteral("qet.log('x');\n")
|
||||
<< QStringLiteral("no // ==QETScript== header");
|
||||
QTest::newRow("no name") << script(QStringLiteral("// @icon x.svg\n"))
|
||||
<< QStringLiteral("@name is required");
|
||||
QTest::newRow("typo") << script(QStringLiteral("// @name A\n// @shortcutt Ctrl+K\n"))
|
||||
<< QStringLiteral("unknown header key @shortcutt");
|
||||
QTest::newRow("context") << script(QStringLiteral("// @name A\n// @context wires\n"))
|
||||
<< QStringLiteral("@context must be one of: canvas, selection, conductor");
|
||||
QTest::newRow("api") << script(QStringLiteral("// @name A\n// @api 2\n"))
|
||||
<< QStringLiteral("@api 2 is not supported by this version (1 is)");
|
||||
}
|
||||
|
||||
void refused()
|
||||
{
|
||||
QFETCH(QString, text);
|
||||
QFETCH(QString, error);
|
||||
const ScriptHeader h = ScriptHeader::parse(text, QStringLiteral("a"));
|
||||
QVERIFY(!h.isValid());
|
||||
QCOMPARE(h.error, error);
|
||||
}
|
||||
|
||||
// Only the header block counts: a "// @name" further down is code.
|
||||
void onlyTheBlock()
|
||||
{
|
||||
const ScriptHeader h = ScriptHeader::parse(
|
||||
script(QStringLiteral("// @name Real\n"))
|
||||
+ QStringLiteral("// @name Not this one\n// @bogus key\n"),
|
||||
QStringLiteral("a"));
|
||||
QVERIFY2(h.isValid(), qPrintable(h.error));
|
||||
QCOMPARE(h.name, QStringLiteral("Real"));
|
||||
}
|
||||
|
||||
// Two windows register one id; the id stays until both are gone, and a
|
||||
// script that comes back under a new name is listed by that name.
|
||||
void unregisterAction()
|
||||
{
|
||||
ShortcutManager &m = ShortcutManager::instance();
|
||||
const QString id = QStringLiteral("diagrameditor.script.tst");
|
||||
auto listed = [&m, &id]() -> QString {
|
||||
for (const ShortcutManager::ShortcutInfo &info : m.allShortcuts())
|
||||
if (info.id == id) return info.description;
|
||||
return QString();
|
||||
};
|
||||
|
||||
QAction a(QStringLiteral("Old name")), b(QStringLiteral("Old name"));
|
||||
m.registerAction(&a, id, QStringLiteral("Scripts"), QKeySequence());
|
||||
m.registerAction(&b, id, QStringLiteral("Scripts"), QKeySequence());
|
||||
QCOMPARE(listed(), QStringLiteral("Old name"));
|
||||
|
||||
m.unregisterAction(&a, id);
|
||||
QCOMPARE(listed(), QStringLiteral("Old name"));
|
||||
QCOMPARE(m.action(id, nullptr), &b);
|
||||
|
||||
m.unregisterAction(&b, id);
|
||||
QVERIFY(listed().isEmpty());
|
||||
QCOMPARE(m.action(id, nullptr), nullptr);
|
||||
|
||||
QAction c(QStringLiteral("New name"));
|
||||
m.registerAction(&c, id, QStringLiteral("Scripts"), QKeySequence());
|
||||
QCOMPARE(listed(), QStringLiteral("New name"));
|
||||
m.unregisterAction(&c, id);
|
||||
|
||||
// unknown id: nothing to do, nothing breaks
|
||||
m.unregisterAction(&c, QStringLiteral("diagrameditor.script.none"));
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_scriptheader)
|
||||
#include "tst_scriptheader.moc"
|
||||
Reference in New Issue
Block a user