Inhaltsverzeichnis
Tutorial: Menü- und Toolbar-Integration
Dieses Tutorial zeigt, wie ein Add-in seine Commands in die Menüleiste, die Toolbar, die ActionBar und die QuickBar der Shell integriert. Der Schwerpunkt liegt auf dem Merge-Verfahren: Wie werden Beiträge mehrerer Add-ins zusammengeführt, und wie steuern group, order und when das Ergebnis.
Zurück zur Übersicht.
Ausgangssituation
Drei Add-ins sollen ihre Funktionalität in die Shell einbringen:
- Assets — Anlageverwaltung (Öffnen, Speichern, Drucken)
- Reports — Berichtswesen (Monatsbericht, Jahresbericht)
- Export — Datenexport (CSV, PDF)
Jedes Add-in hat ein eigenes Top-Level-Menü, und alle drei tragen Buttons zur Haupt-Toolbar und zur ActionBar bei.
Schritt 1: Top-Level-Menüs anlegen
Jedes Add-in deklariert ein Submenü und platziert es in der Menüleiste:
Assets:
"submenus": [ { "id": "assets", "label": "Assets" } ], "menus": { "menuBar": [ { "submenu": "assets", "group": "modules", "order": 100 } ], "assets": [ { "command": "assets.open", "group": "file", "order": 1 }, { "command": "assets.save", "group": "file", "order": 2 }, { "command": "assets.print", "group": "output", "order": 1 } ] }
Reports:
"submenus": [ { "id": "reports", "label": "Berichte" } ], "menus": { "menuBar": [ { "submenu": "reports", "group": "modules", "order": 200 } ], "reports": [ { "command": "reports.monthly", "group": "standard", "order": 1 }, { "command": "reports.yearly", "group": "standard", "order": 2 }, { "command": "reports.custom", "group": "custom", "order": 1 } ] }
Export:
"submenus": [ { "id": "export", "label": "Export" } ], "menus": { "menuBar": [ { "submenu": "export", "group": "tools", "order": 100 } ], "export": [ { "command": "export.csv", "group": "formats", "order": 1 }, { "command": "export.pdf", "group": "formats", "order": 2 } ] }
Ergebnis in der Menüleiste
[ Datei ] [ Assets ] [ Berichte ] [ Export ] [ Hilfe ]
(modules/100) (modules/200) (tools/100)
Assets und Berichte stehen nebeneinander, weil beide die Gruppe modules verwenden. Innerhalb der Gruppe bestimmt order die Reihenfolge (100 < 200). Export steht in der Gruppe tools, die alphabetisch nach modules kommt.
Ergebnis im Assets-Menü
Assets ├── Anlage öffnen (file / 1) ├── Anlage speichern (file / 2) ├── ───────────────── (Trennstrich) └── Drucken (output / 1)
Die Gruppen file und output werden durch einen Trennstrich getrennt.
Schritt 2: In bestehende Menüs einfügen
Ein Add-in kann auch in ein Menü eines anderen Add-ins einfügen. Das Export-Add-in möchte etwa einen Eintrag im Assets-Menü platzieren:
"menus": { "assets": [ { "command": "export.asset-csv", "group": "output", "order": 2, "when": "activeDocument == assets.editor" } ] }
Dieser Eintrag landet in der Gruppe output des Assets-Menüs, direkt nach dem Drucken-Eintrag (order 2 > 1). Er ist nur sichtbar, wenn ein Asset-Editor aktiv ist.
Assets ├── Anlage öffnen (file / 1) ├── Anlage speichern (file / 2) ├── ───────────────── ├── Drucken (output / 1) └── Als CSV exportieren (output / 2) ← Vom Export-Add-in
Dieses Cross-Plugin-Merging funktioniert, weil der Host alle Manifest-Beiträge sammelt und nach Location-Schlüssel zusammenführt. Dem Assets-Menü ist es egal, von welchem Add-in der Eintrag kommt — die Sortierung nach Gruppe und Order gilt einheitlich.
Schritt 3: Toolbar-Integration
Die drei Add-ins tragen Buttons zu verschiedenen Toolbar-Bereichen bei:
Haupt-Toolbar (immer sichtbar):
// Assets { "toolbarId": "main", "command": "assets.open", "icon": "media/asset.svg", "group": "modules", "order": 1 } // Reports { "toolbarId": "main", "command": "reports.monthly", "icon": "media/report.svg", "group": "modules", "order": 2 }
ActionBar (kontextabhängig):
// Assets — nur sichtbar bei aktivem Asset-Editor { "toolbarId": "actionbar", "command": "assets.save", "icon": "media/save.svg", "when": "activeDocument == assets.editor && isDirty" } { "toolbarId": "actionbar", "command": "assets.print", "icon": "media/print.svg", "when": "activeDocument == assets.editor" } // Export — nur sichtbar bei aktivem Asset-Editor { "toolbarId": "actionbar", "command": "export.asset-csv", "icon": "media/csv.svg", "when": "activeDocument == assets.editor" }
QuickBar (benutzerdefinierbar):
// Assets — Schnellzugriff { "toolbarId": "quickbar", "command": "assets.open", "icon": "media/asset.svg" }
Ergebnis
Haupt-Toolbar:
[ Asset öffnen ] [ Monatsbericht ]
(modules/1) (modules/2)
ActionBar (wenn Asset-Editor aktiv und dirty):
[ Speichern ] [ Drucken ] [ CSV Export ]
Die ActionBar-Buttons erscheinen und verschwinden automatisch, wenn der Benutzer zwischen Tabs wechselt. Das liegt an den when-Ausdrücken, die der Host bei jedem Kontextwechsel neu auswertet.
Schritt 4: CommandPalette
Standardmäßig erscheinen alle Commands in der CommandPalette. Commands, die nur über andere Wege erreichbar sein sollen, werden ausgeblendet:
"menus": { "commandPalette": [ { "command": "assets.internal.cleanup", "when": "false" } ] }
Der Ausdruck when: „false“ ist immer falsch — der Command erscheint nie in der Palette. Er bleibt aber über ExecuteCommand und Menüs erreichbar.
Schritt 5: Kontextmenüs
Kontextmenüs für TreeView-Elemente verwenden den Ort view/item/context:
"menus": { "view/item/context": [ { "command": "assets.nav.open", "when": "view == assets.navigator && viewItem == asset", "group": "navigation", "order": 1 }, { "command": "export.asset-csv", "when": "view == assets.navigator && viewItem == asset", "group": "export", "order": 1 }, { "command": "assets.nav.delete", "when": "view == assets.navigator && viewItem == asset", "group": "modification", "order": 1 } ] }
Das Kontextmenü für einen Asset-Baumknoten:
├── Anlage öffnen (navigation / 1) ← Vom Assets-Add-in ├── ───────────────── ├── Als CSV exportieren (export / 1) ← Vom Export-Add-in ├── ───────────────── └── Löschen (modification / 1) ← Vom Assets-Add-in
Auch hier werden Beiträge verschiedener Add-ins nach Gruppe und Order zusammengeführt. Das Export-Add-in fügt seinen Eintrag in das Kontextmenü des Assets-Navigators ein, ohne dass das Assets-Add-in davon wissen muss.
Zusammenfassung der Merge-Regeln
- Jeder Beitrag hat einen Ort (Location):
menuBar,commandPalette,view/title,view/item/contextoder eine Submenu-Id. - Innerhalb eines Orts sortiert der Host nach Gruppe (alphabetisch), dann nach Order (numerisch).
- Zwischen verschiedenen Gruppen fügt der Host einen Trennstrich ein.
- When-Ausdrücke steuern die Sichtbarkeit dynamisch. Ändert sich ein Kontextwert, aktualisiert der Host sofort alle betroffenen Einträge.
- Cross-Plugin-Merging funktioniert automatisch: Ein Add-in kann in das Menü oder Kontextmenü eines anderen Add-ins einfügen, indem es denselben Location-Schlüssel verwendet.
- Die Installationsreihenfolge spielt keine Rolle. Das Ergebnis ist deterministisch, weil es nur von Gruppe und Order abhängt.
Zurück zur Übersicht.