{
+ void _token;
+ webviewPanel.webview.options = {
+ enableScripts: true
+ };
+ webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);
+ function updateWebview() {
+ void webviewPanel.webview.postMessage({
+ type: 'update',
+ text: document.getText()
+ });
+ }
+ const changeDocumentSubscription = vscode.workspace.onDidChangeTextDocument(
+ (e) => {
+ if (e.document.uri.toString() === document.uri.toString()) {
+ updateWebview();
+ }
+ }
+ );
+
+ webviewPanel.onDidDispose(() => {
+ changeDocumentSubscription.dispose();
+ });
+
+ webviewPanel.webview.onDidReceiveMessage(async (e: { type: string }) => {
+ switch (e.type) {
+ case 'run':
+ if (!designerClient.isRunning()) {
+ await designerClient.start();
+ }
+ // wait for the client to connect
+ while (!designerServer.isClientConnected()) {
+ await new Promise((resolve) => setTimeout(resolve, 100));
+ }
+ designerServer.sendFile(document.uri.fsPath);
+ break;
+ default:
+ throw new Error('Unknown message type');
+ }
+ });
+
+ updateWebview();
+ return Promise.resolve();
+ }
+
+ private getHtmlForWebview(webview: vscode.Webview): string {
+ // Use a nonce to whitelist which scripts can be run
+ const nonce = getNonce();
+ const scriptUri = getUri(webview, this.context.extensionUri, [
+ 'out',
+ 'editors',
+ 'ui',
+ 'webview-ui',
+ 'main.js'
+ ]);
+
+ // prettier-ignore
+ const html =
+ `
+
+
+
+
+ Open this file with Qt Designer
+
+
+
+
+ Open this file with Qt Designer
+
+
+
+ `;
+ return html;
+ }
+}
diff --git a/src/editors/ui/webview-ui/main.ts b/src/editors/ui/webview-ui/main.ts
new file mode 100644
index 0000000..064803c
--- /dev/null
+++ b/src/editors/ui/webview-ui/main.ts
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
+
+import {
+ provideVSCodeDesignSystem,
+ vsCodeButton
+} from '@vscode/webview-ui-toolkit';
+
+declare function acquireVsCodeApi(): { postMessage(message: unknown): void };
+
+provideVSCodeDesignSystem().register(vsCodeButton());
+
+const vscode = acquireVsCodeApi();
+
+window.addEventListener('load', main);
+
+function main() {
+ const buttons = document.querySelectorAll('vscode-button');
+ if (buttons.length === 0) {
+ throw new Error('No buttons found');
+ }
+ const openWithDesignerButton = document.getElementById(
+ 'openWithDesignerButton'
+ );
+ if (openWithDesignerButton) {
+ openWithDesignerButton.focus();
+ }
+ function onOpenWithDesignerButtonClick() {
+ vscode.postMessage({
+ type: 'run'
+ });
+ }
+ openWithDesignerButton?.addEventListener(
+ 'click',
+ onOpenWithDesignerButtonClick
+ );
+
+ openWithDesignerButton?.addEventListener('keydown', function (event) {
+ if (event.key === 'Enter') {
+ event.preventDefault();
+ onOpenWithDesignerButtonClick();
+ }
+ });
+ document.addEventListener('keydown', function (event) {
+ // if any arrow key is pressed, focus the this button
+ if (
+ event.key === 'ArrowUp' ||
+ event.key === 'ArrowDown' ||
+ event.key === 'ArrowLeft' ||
+ event.key === 'ArrowRight'
+ ) {
+ event.preventDefault();
+ openWithDesignerButton?.focus();
+ }
+ });
+}
diff --git a/src/editors/util.ts b/src/editors/util.ts
new file mode 100644
index 0000000..58f5777
--- /dev/null
+++ b/src/editors/util.ts
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
+
+import { Uri, Webview } from 'vscode';
+
+export function getNonce() {
+ let text = '';
+ const possible =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ for (let i = 0; i < 32; i++) {
+ text += possible.charAt(Math.floor(Math.random() * possible.length));
+ }
+ return text;
+}
+
+export function getUri(
+ webview: Webview,
+ extensionUri: Uri,
+ pathList: string[]
+) {
+ return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList));
+}
diff --git a/src/extension.ts b/src/extension.ts
index cf703bc..d51de3f 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -11,7 +11,6 @@ import {
} from './commands/register-qt-path';
import { initCMakeKits } from './commands/detect-qt-cmake';
import { registerProFile } from './commands/file-ext-pro';
-import { registerQrcFile } from './commands/file-ext-qrc';
import { registerQdocFile } from './commands/file-ext-qdoc';
import { registerUiFile } from './commands/file-ext-ui';
import { registerKitDirectoryCommand } from './commands/kit-directory';
@@ -20,6 +19,9 @@ import { initStateManager } from './state';
import { configChecker } from './util/config';
import { registerResetQtExtCommand } from './commands/reset-qt-ext';
import { registerNatvisCommand } from './commands/natvis';
+import { designerServer } from './designer-server';
+import { designerClient } from './designer-client';
+import { UIEditorProvider } from './editors/ui/ui-editor';
export async function activate(context: vscode.ExtensionContext) {
const promiseActivateCMake = vscode.extensions
@@ -29,17 +31,19 @@ export async function activate(context: vscode.ExtensionContext) {
initCMakeKits(context);
initStateManager(context);
+ designerServer.start();
+
registerUiFile(context);
registerQtCommand(context);
context.subscriptions.push(
registerProFile(),
- registerQrcFile(),
registerQdocFile(),
registerKitDirectoryCommand(),
registerMinGWgdbCommand(),
registerResetQtExtCommand(),
- ...registerNatvisCommand()
+ ...registerNatvisCommand(),
+ UIEditorProvider.register(context)
);
registerConfigWatchers(context);
@@ -65,5 +69,7 @@ function registerConfigWatchers(context: vscode.ExtensionContext) {
}
export function deactivate() {
+ designerServer.stop();
+ designerClient.stop();
console.log('Deactivating vscode-qt-tools');
}
diff --git a/tsconfig.json b/tsconfig.json
index 4f1649e..e23f5e1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,7 @@
"target": "ES2020",
"types": ["node"],
"outDir": "out",
- "lib": ["ES2020"],
+ "lib": ["ES2020", "DOM"],
"sourceMap": true,
"rootDir": "src",
"strict": true /* enable all strict type-checking options */