// ***************************************************************************** // Copyright (C) 2023 TypeFox and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** import { nls, URI } from '@theia/core'; import { WidgetFactory, NavigatableWidgetOptions, LabelProvider } from '@theia/core/lib/browser'; import { inject, injectable } from '@theia/core/shared/inversify'; import { NotebookEditorWidget, NotebookEditorWidgetContainerFactory, NotebookEditorProps, NOTEBOOK_EDITOR_ID_PREFIX } from './notebook-editor-widget'; import { NotebookService } from './service/notebook-service'; import { NotebookModelResolverService } from './service/notebook-model-resolver-service'; import { Deferred } from '@theia/core/lib/common/promise-util'; import { NotebookModel } from './view-model/notebook-model'; export interface NotebookEditorWidgetOptions extends NavigatableWidgetOptions { notebookType: string; } @injectable() export class NotebookEditorWidgetFactory implements WidgetFactory { static createID(uri: URI, counter?: number): string { return NOTEBOOK_EDITOR_ID_PREFIX + uri.toString() + (counter !== undefined ? `:${counter}` : ''); } readonly id: string = NotebookEditorWidget.ID; @inject(NotebookService) protected readonly notebookService: NotebookService; @inject(NotebookModelResolverService) protected readonly notebookModelResolver: NotebookModelResolverService; @inject(LabelProvider) protected readonly labelProvider: LabelProvider; @inject(NotebookEditorWidgetContainerFactory) protected readonly createNotebookEditorWidget: (props: NotebookEditorProps) => NotebookEditorWidget; async createWidget(options?: NotebookEditorWidgetOptions): Promise { if (!options) { throw new Error('no options found for widget. Need at least uri and notebookType'); } const uri = new URI(options.uri); await this.notebookService.willOpenNotebook(options.notebookType); const editor = await this.createEditor(uri, options.notebookType); // Set the widget ID with counter to support multiple instances editor.id = NotebookEditorWidgetFactory.createID(uri, options.counter); this.setLabels(editor, uri); const labelListener = this.labelProvider.onDidChange(event => { if (event.affects(uri)) { this.setLabels(editor, uri); } }); editor.onDidDispose(() => labelListener.dispose()); return editor; } protected async createEditor(uri: URI, notebookType: string): Promise { const notebookData = new Deferred(); const resolverError = new Deferred(); this.notebookModelResolver.resolve(uri, notebookType).then(model => { notebookData.resolve(model); }).catch((reason: Error) => { resolverError.resolve(reason.message); }); return this.createNotebookEditorWidget({ uri, notebookType, notebookData: notebookData.promise, error: resolverError.promise }); } protected setLabels(editor: NotebookEditorWidget, uri: URI): void { editor.title.caption = uri.path.fsPath(); if (editor.model?.readOnly) { editor.title.caption += ` • ${nls.localizeByDefault('Read-only')}`; } const icon = this.labelProvider.getIcon(uri); editor.title.label = this.labelProvider.getName(uri); editor.title.iconClass = icon + ' file-icon'; } }