aboutsummaryrefslogtreecommitdiffstats
path: root/qt-ui/src/editors/ui/ui-editor.ts
blob: 0dd940a54b2509e94613270cfcfe5b984f6d4c9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only

import * as vscode from 'vscode';

import { askForKitSelection, createLogger, QtWorkspaceType } from 'qt-lib';
import { getNonce, getUri } from '@/editors/util';
import { projectManager } from '@/extension';
import { delay } from '@/util';
import { EXTENSION_ID } from '@/constants';

const logger = createLogger('ui-editor');

export class UIEditorProvider implements vscode.CustomTextEditorProvider {
  constructor(private readonly context: vscode.ExtensionContext) {}

  private static readonly viewType = `${EXTENSION_ID}.uiEditor`;
  public static register(context: vscode.ExtensionContext): vscode.Disposable {
    const provider = new UIEditorProvider(context);
    const providerRegistration = vscode.window.registerCustomEditorProvider(
      UIEditorProvider.viewType,
      provider
    );
    return providerRegistration;
  }
  public async resolveCustomTextEditor(
    document: vscode.TextDocument,
    webviewPanel: vscode.WebviewPanel,
    _token: vscode.CancellationToken
  ): Promise<void> {
    void _token;
    webviewPanel.webview.options = {
      enableScripts: true
    };
    webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview);
    webviewPanel.webview.onDidReceiveMessage(async (e: { type: string }) => {
      const project = projectManager.findProjectContainingFile(document.uri);
      if (project === undefined) {
        logger.error('Project not found');
        throw new Error('Project not found');
      }
      const designerServer = project.designerServer;
      const designerClient = project.designerClient;

      switch (e.type) {
        case 'run':
          if (designerClient === undefined) {
            // User may not have selected the kit.
            // We can check and ask for kit selection.
            if (project.workspaceType === QtWorkspaceType.CMakeExt) {
              askForKitSelection();
            }
            logger.error('Designer client not found');
            throw new Error('Designer client not found');
          }
          if (!designerClient.isRunning()) {
            logger.info(`Starting designer client:${designerClient.exe}`);
            designerServer.closeClient();
            designerClient.start(designerServer.getPort());
          }
          // wait for the client to connect
          while (!designerServer.isClientConnected()) {
            await delay(100);
          }
          designerServer.sendFile(document.uri.fsPath);
          logger.info('File sent to designer server: ' + document.uri.fsPath);
          break;
        default:
          logger.error('Unknown message type');
          throw new Error('Unknown message type');
      }
    });
    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 =
    `<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Open this file with Qt Widgets Designer</title>
      <style>
        body {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          height: 100vh;
          margin: 0;
        }
    </style>
    </head>
    <body>
      <div>
        <vscode-button id="openWithDesignerButton" tabindex="0">Open this file with Qt Widgets Designer</vscode-button>
      </div>
      <script type="module" nonce="${nonce}" src="${scriptUri.toString()}"></script>
    </body>
    </html>`;
    return html;
  }
}