diff --git a/lang/qet_en.ts b/lang/qet_en.ts index 57a1c1c65..8e3372e75 100644 --- a/lang/qet_en.ts +++ b/lang/qet_en.ts @@ -461,127 +461,127 @@ Connecter un assistant IA - + Connect an AI assistant Un assistant IA (Claude, GitHub Copilot, Gemini…) peut ouvrir, vérifier et modifier vos schémas grâce au serveur MCP de QElectroTech, qui fonctionne sur cet ordinateur. Copiez le texte ci-dessous dans la configuration de votre assistant. <a href="%1">Guide détaillé</a> - + An AI assistant (Claude, GitHub Copilot, Gemini…) can open, check and edit your diagrams through QElectroTech's MCP server, which runs on this computer. Copy the text below into your assistant's configuration. <a href="%1">Detailed guide</a> <b>Le serveur MCP n'est pas installé avec cette version de QElectroTech.</b> Le guide explique comment l'obtenir. - + <b>The MCP server is not installed with this version of QElectroTech.</b> The guide explains how to get it. <b>Python n'est peut-être pas installé.</b> Seul le raccourci « python » du Microsoft Store a été trouvé : sans Python, il ouvre le Store au lieu de lancer le serveur. - + <b>Python may not be installed.</b> Only the Microsoft Store “python” shortcut was found: without Python, it opens the Store instead of starting the server. <b>Python est introuvable sur cet ordinateur</b> (commande « %1 »). Le serveur en a besoin. - + <b>Python was not found on this computer</b> (command “%1”). The server needs it. Relancez l'installateur de QElectroTech et cochez « Python pour l'assistant IA », ou installez Python depuis python.org. - + Run the QElectroTech installer again and tick “Python for the AI assistant”, or install Python from python.org. Installez Python 3 avec le gestionnaire de paquets de votre système. - + Install Python 3 with your system's package manager. Assistant : - + Assistant: Le dossier de vos schémas - + Your diagrams folder Parcourir… - + Browse… Dossier accessible : - + Folder it can use: Autoriser l'assistant à modifier les schémas - + Allow the assistant to edit diagrams L'assistant ne peut lire et écrire que dans ce dossier. Sans modification autorisée, il peut seulement lire, comparer et exporter. Un assistant lit le texte des projets (repères, notes…) : un texte écrit comme une instruction peut l'influencer. Laissez les modifications désactivées pour les schémas reçus d'autres personnes. - + The assistant can only read and write in this folder. Without editing allowed, it can only read, compare and export. An assistant reads the text in projects (labels, notes…): text written as an instruction can influence it. Leave editing off for diagrams you received from other people. Copier - + Copy Si le fichier contient déjà d'autres serveurs, ajoutez seulement l'entrée « qet ». - + If the file already lists other servers, add only the “qet” entry. Choisissez d'abord le dossier de vos schémas. - + Choose your diagrams folder first. Dossier accessible à l'assistant - + Folder the assistant can use Copié - + Copied Dans Claude Desktop : Paramètres → Développeur → Modifier la configuration. Puis quittez et relancez Claude. - + In Claude Desktop: Settings → Developer → Edit Config. Then quit and restart Claude. Enregistrez-le sous le nom .mcp.json dans le dossier de vos schémas. - + Save it as .mcp.json in your diagrams folder. Enregistrez-le sous le nom .vscode/mcp.json dans le dossier ouvert dans VS Code. Copilot utilise les outils en mode agent. - + Save it as .vscode/mcp.json in the folder open in VS Code. Copilot uses the tools in agent mode. Ajoutez-le au fichier .cursor/mcp.json de votre dossier personnel. - + Add it to the .cursor/mcp.json file in your home folder. Ajoutez-le au fichier .gemini/settings.json de votre dossier personnel. Gemini CLI demande de faire confiance au dossier la première fois. - + Add it to the .gemini/settings.json file in your home folder. Gemini CLI asks you to trust the folder the first time. Ajoutez-le au fichier .codex/config.toml de votre dossier personnel. - + Add it to the .codex/config.toml file in your home folder. Dans LM Studio : onglet Program → Install → Edit mcp.json. - + In LM Studio: Program tab → Install → Edit mcp.json. @@ -5335,12 +5335,12 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments Autoriser un assistant IA à agir sur le projet ouvert (mode direct) - + Allow an AI assistant to act on the open project (live mode) Un assistant connecté par le serveur MCP peut alors exécuter des scripts sur le projet ouvert, sous vos yeux. Un avertissement est affiché à chaque démarrage tant que ce réglage est activé. Prend effet au prochain démarrage ; le décocher coupe la connexion tout de suite. - + An assistant connected through the MCP server can then run scripts on the open project, as you watch. A warning is shown at every start while this setting is on. Takes effect at the next start; unticking it closes the connection at once. @@ -6777,7 +6777,7 @@ Please use the advanced editor for this. Mode direct - + Live mode @@ -6785,59 +6785,63 @@ Please use the advanced editor for this. Chaque action s'annule d'un Ctrl+Z, et le bouton « Arrêter » de la barre d'état coupe la connexion. -Ce réglage se trouve dans Configurer QElectroTech > Général. - +Ce réglage se trouve dans Configurer QElectroTech > Général > Projets. + Live mode is on: a connected AI assistant will be able to run scripts on the open project. + +Each action is undone with one Ctrl+Z, and the “Stop” button in the status bar closes the connection. + +This setting is in Configure QElectroTech > General > Projects. &Continuer - + &Continue &Pas pour cette session - + &Not this session &Désactiver - + &Turn off script - + script Assistant : %1 - + Assistant: %1 L'assistant veut exécuter un script - + The assistant wants to run a script « %1 » sur le projet ouvert. Une fois exécuté, Ctrl+Z l'annule. - + “%1” on the open project. Once it has run, Ctrl+Z undoes it. &Exécuter - + &Run &Refuser - + &Decline &Toujours pour cette session - + &Always this session @@ -6845,12 +6849,12 @@ Ce réglage se trouve dans Configurer QElectroTech > Général. Macro du %1 - + Macro of %1 projet fermé pendant l'enregistrement : pas de after.qet - + project closed during the recording: no after.qet @@ -9909,32 +9913,32 @@ Hold Ctrl while moving to place freely. Enregistrer une macro - + Record a macro Enregistre ce que vous faites sur le projet, pour qu'un assistant IA en fasse un script ; recliquez pour arrêter - + Records what you do on the project, for an AI assistant to make a script of; click again to stop Gérer les scripts… - + Manage scripts… Écrire un script et en faire un bouton avec une icône - + Write a script and make it a button with an icon Ouvrir le dossier des scripts - + Open the scripts folder Chaque fichier .js de ce dossier qui commence par un en-tête // ==QETScript== devient un bouton - + Every .js file in this folder that starts with a // ==QETScript== header becomes a button @@ -10246,7 +10250,7 @@ Hold Ctrl while moving to place freely. Scripts toolbar title - + Scripts @@ -10267,7 +10271,7 @@ Hold Ctrl while moving to place freely. Scripts - + Scripts @@ -10538,18 +10542,18 @@ Enable scripts? This setting can be changed in Configure QElectroTech > Gener Ignoré : %1 - + Ignored: %1 Arrêter - + Stop Arrêter l'enregistrement de la macro - + Stop recording the macro @@ -10562,7 +10566,7 @@ Enable scripts? This setting can be changed in Configure QElectroTech > Gener Macro enregistrée - + Macro recorded @@ -10577,53 +10581,53 @@ Pour en faire un script, demandez-le à votre assistant IA : le bouton ci-dessou &Copier la demande pour l'assistant - + &Copy the request for the assistant &Ouvrir le dossier - + &Open the folder Demande copiée : collez-la dans la fenêtre de l'assistant - + Request copied: paste it into the assistant's window Couper la connexion de l'assistant pour le reste de la session - + Close the assistant's connection for the rest of the session Mode direct : assistant connecté - + Live mode: assistant connected Mode direct : en attente d'un assistant - + Live mode: waiting for an assistant Assistant - + Assistant Demander avant d'exécuter un script écrit par l'assistant - + Ask before running a script the assistant wrote Pour cette session seulement : chaque démarrage redemande - + For this session only: every start asks again Mode direct : %1 %2 à %3 - + Live mode: %1 %2 at %3 @@ -11520,13 +11524,13 @@ the conditions are not valid Connecter un assistant IA... - + Connect an AI assistant... Affiche la configuration qui permet à un assistant IA d'utiliser QElectroTech status bar tip - + Shows the setup that lets an AI assistant use QElectroTech @@ -14237,12 +14241,12 @@ To enable it: Configure QElectroTech > General > Projects, or set the QET_ Assistant : %1 - + Assistant: %1 Script : %1 - + Script: %1 @@ -15258,7 +15262,7 @@ Create your own text using the following variables: Gérer les scripts - + Manage scripts @@ -15268,37 +15272,37 @@ Create your own text using the following variables: Supp&rimer - + &Delete Le texte du bouton - + The button's text vide : les initiales du nom ; builtin:<nom> : une icône du thème - + empty: the name's initials; builtin:<name>: an icon of the theme Choisir une image (SVG ou PNG)… - + Choose an image (SVG or PNG)… Toujours - + Always Avec une sélection - + With a selection Avec un conducteur sélectionné - + With a conductor selected @@ -15308,32 +15312,32 @@ Create your own text using the following variables: Icône : - + Icon: Info-bulle : - + Tooltip: Raccourci : - + Shortcut: Actif : - + Enabled: &Tester - + &Test Enregistre puis exécute le script sur le projet courant (Ctrl+Z annule l'exécution) - + Saves, then runs the script on the current project (Ctrl+Z undoes the run) @@ -15343,7 +15347,7 @@ Create your own text using the following variables: Ouvrir le &dossier - + Open the &folder @@ -15353,22 +15357,22 @@ Create your own text using the following variables: Script (l'objet qet ; qet.currentFolio() est le folio affiché) : - + Script (the qet object; qet.currentFolio() is the sheet shown): Pas de bouton : %1 - + No button: %1 Pas de bouton pour ce fichier : %1 - + No button for this file: %1 Nouveau script - + New script @@ -15377,57 +15381,61 @@ Create your own text using the following variables: var f = qet.currentFolio(); qet.addText(f, "Texte", 40, 40); - + // qet.currentFolio() is the sheet shown; one click is undone +// with a single Ctrl+Z. List of calls: qet.apiSignatures() +var f = qet.currentFolio(); +qet.addText(f, "Text", 40, 40); + Pas encore enregistré - + Not saved yet Le script doit avoir un nom. - + The script needs a name. Non enregistré : %1 - + Not saved: %1 Impossible d'écrire %1 - + Cannot write %1 Supprimer le script - + Delete the script Supprimer « %1 » et son bouton ? - + Delete “%1” and its button? Icône du script - + Script icon Images (*.svg *.png) - + Images (*.svg *.png) Impossible de copier %1 - + Cannot copy %1 Le script affiché n'est pas enregistré. Enregistrer ? - + The script shown is not saved. Save it? diff --git a/misc/qet-mcp/README.md b/misc/qet-mcp/README.md index d6b391456..963cddb99 100644 --- a/misc/qet-mcp/README.md +++ b/misc/qet-mcp/README.md @@ -44,7 +44,7 @@ here read the model. | `qet_about` | **start here** — where QElectroTech keeps things, what is switched on, the stored scripts, the calls a script can make (from `qet-assistant.json`) | | `qet_script_api` | **what a script can call** — every `qet.*` call of this build, and the header that makes a script a button | | `qet_script_test` | **try a script** on a copy of a project: what it would change, what it logged, its errors | -| `qet_script_install` | **make a button** — store a script (and an SVG icon) where QElectroTech shows it in Projet > Scripts and the Scripts toolbar | +| `qet_script_install` | **make a button** — store a script (and an SVG icon) where QElectroTech shows it in Project > Scripts and the Scripts toolbar | | `qet_script_list`, `qet_script_read`, `qet_script_remove` | the stored scripts: list, read one to change it, delete one | | `qet_recording_list`, `qet_recording_read`, `qet_recording_check`, `qet_recording_remove` | **macro recordings** — what you did by hand, and whether a script does the same | @@ -271,7 +271,7 @@ with `qet_about`. ## Script buttons QElectroTech turns every `.js` file in its scripts folder that starts with a -`// ==QETScript==` header into a command with an icon: in Projet > Scripts, +`// ==QETScript==` header into a command with an icon: in Project > Scripts, on the Scripts toolbar, in command search and in the shortcut bar. A person can write that file by hand; an assistant uses the tools above. Both end with the same file, and an open QElectroTech picks it up without a restart. @@ -304,7 +304,7 @@ stored script runs with the user's rights when they click it. ## Macro recordings: from something done by hand to a button -In QElectroTech, Projet > Scripts > Enregistrer une macro records what you +In QElectroTech, Project > Scripts > Record a macro records what you do on a project until you click it again. It saves the project before and after, and each step from the undo history with the folio after it. At Stop it offers to copy a ready-made request; paste that into the assistant. @@ -329,27 +329,29 @@ QElectroTech, in front of you, so you can watch, stop or undo: | | | |---|---| | `qet_live_status` | what is on screen: project, folio, selection, last undo step, stored scripts | -| `qet_live_run_script` | run script text on the open project: one undo step named "Assistant : …" | +| `qet_live_run_script` | run script text on the open project: one undo step named "Assistant: …" | | `qet_live_run_stored` | press a stored script's button | | `qet_live_command` | an editor command from an allow-list that opens no dialog: selection, zoom, rotate, snap, group, reset wires | | `qet_live_show_folio` | show another folio | | `qet_live_undo_last` | undo the newest step, only if the assistant made it | -| `qet_live_screenshot` | a picture of the folio on screen, as an MCP image | +| `qet_live_screenshot` | a picture of the folio on screen, as an MCP image, cropped to the folio | A script the assistant writes on the spot is shown to you first, with -*Exécuter*, *Refuser* or *Toujours pour cette session*; the Assistant +*Run*, *Decline* or *Always this session*; the Assistant panel lists everything it did. QElectroTech only listens when three things are true: 1. the server has `QET_ENABLE_SCRIPTING=1`, as for editing; -2. in QElectroTech, Configurer > Général > "Autoriser un assistant IA à agir - sur le projet ouvert" is ticked (off by default); -3. at this start, you answered *Continuer* to the warning QElectroTech shows +2. in QElectroTech, Settings > Configure QElectroTech > General, on the + Projects tab, "Allow an AI assistant to act on the open project (live + mode)" is ticked (off by default; in French, Configurer QElectroTech > + Général > Projets); +3. at this start, you answered *Continue* to the warning QElectroTech shows every time it starts with that setting on. While it listens, the status bar says so and shows the assistant's last -action, with an *Arrêter* button that closes the channel for the rest of +action, with a *Stop* button that closes the channel for the rest of the session. Each action is one Ctrl+Z. A script's `qet.showMessage()` is logged instead of opening a box nobody asked for. diff --git a/misc/qet-mcp/qet_mcp.py b/misc/qet-mcp/qet_mcp.py index ca9b597ba..080520a81 100755 --- a/misc/qet-mcp/qet_mcp.py +++ b/misc/qet-mcp/qet_mcp.py @@ -3064,13 +3064,15 @@ def _live_session() -> dict: if not info.get("running"): why = "QElectroTech is not running" elif not features.get("live_mode_setting"): - why = ("live mode is off: in QElectroTech, Configurer QElectroTech > " - "Général > \"Autoriser un assistant IA à agir sur le projet " - "ouvert\", then restart it") + why = ("live mode is off: in QElectroTech, tick Settings > Configure " + "QElectroTech > General > Projects > \"Allow an AI assistant to " + "act on the open project (live mode)\" (in French: Configurer " + "QElectroTech > Général > Projets), then restart it") else: why = ("live mode is on but not open for this session: answer " - "\"Continuer\" in the warning QElectroTech shows at start, or " - "restart it if \"Pas pour cette session\" or Arrêter was chosen") + "\"Continue\" (\"Continuer\") in the warning QElectroTech shows " + "at start, or restart it if \"Not this session\" or \"Stop\" " + "was chosen") raise ValueError(f"no QElectroTech is listening for an assistant: {why}.") return live diff --git a/misc/qet-mcp/test_qet_mcp.py b/misc/qet-mcp/test_qet_mcp.py index 3d933df2d..3cbd65932 100644 --- a/misc/qet-mcp/test_qet_mcp.py +++ b/misc/qet-mcp/test_qet_mcp.py @@ -3101,7 +3101,7 @@ class LiveClient(unittest.TestCase): with self.assertRaisesRegex(ValueError, "live mode is off"): m.tool_live_status() self.info(None) - with self.assertRaisesRegex(ValueError, "Continuer"): + with self.assertRaisesRegex(ValueError, "Continue"): m.tool_live_status() def test_requests_carry_the_token_and_the_script_id(self): diff --git a/sources/scripting/liveserver.cpp b/sources/scripting/liveserver.cpp index ce25e8ba1..6eb679c18 100644 --- a/sources/scripting/liveserver.cpp +++ b/sources/scripting/liveserver.cpp @@ -110,7 +110,8 @@ void LiveServer::askAndStart(QWidget *parent) "pourra exécuter des scripts sur le projet ouvert.\n\n" "Chaque action s'annule d'un Ctrl+Z, et le bouton " "« Arrêter » de la barre d'état coupe la connexion.\n\n" - "Ce réglage se trouve dans Configurer QElectroTech > Général."), + "Ce réglage se trouve dans Configurer QElectroTech > Général > " + "Projets."), QMessageBox::NoButton, parent); QPushButton *go = box.addButton(tr("&Continuer"), QMessageBox::AcceptRole); box.addButton(tr("&Pas pour cette session"), QMessageBox::RejectRole); @@ -465,7 +466,22 @@ QJsonObject LiveServer::screenshot() QETDiagramEditor *e = editor(); DiagramView *view = e ? e->currentDiagramView() : nullptr; if (!view) return failure(QStringLiteral("no folio is shown in QElectroTech")); - const QPixmap pixmap = view->grab(); + // Only the part of the folio (frame and title block) that is on + // screen: a tall or wide window around a zoomed-out folio would + // otherwise give mostly empty background. The whole viewport when + // the folio is scrolled out of sight. + QRect area = view->viewport()->rect(); + bool cropped = false; + if (Diagram *diagram = view->diagram()) { + const QRect folio = view->mapFromScene( + diagram->border_and_titleblock.borderAndTitleBlockRect()).boundingRect() + .adjusted(-1, -1, 1, 1).intersected(area); + if (!folio.isEmpty()) { + cropped = folio != area; + area = folio; + } + } + const QPixmap pixmap = view->viewport()->grab(area); QByteArray png; QBuffer buffer(&png); buffer.open(QIODevice::WriteOnly); @@ -473,6 +489,7 @@ QJsonObject LiveServer::screenshot() return {{QStringLiteral("ok"), true}, {QStringLiteral("width"), pixmap.width()}, {QStringLiteral("height"), pixmap.height()}, + {QStringLiteral("cropped_to_folio"), cropped}, {QStringLiteral("png_base64"), QString::fromLatin1(png.toBase64())}}; }