/******************************************************************************** * Copyright (C) 2018 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 WITH Classpath-exception-2.0 ********************************************************************************/ import { inject, injectable, postConstruct } from 'inversify'; import { URI } from '@gedit/utils'; import { Emitter, Event, MaybePromise } from '@gedit/utils'; import { BaseWidget } from './widgets'; import { ApplicationShell, WidgetManager } from './shell'; import { OpenerOptions, OpenHandler } from '@gedit/application-common/lib/browser'; export type WidgetOpenMode = 'open' | 'reveal' | 'activate'; export interface WidgetOpenerOptions extends OpenerOptions { /** * Whether the widget should be only opened, revealed or activated. * By default is `activate`. */ mode?: WidgetOpenMode; /** * Specify how an opened widget should be added to the shell. * By default to the main area. */ widgetOptions?: ApplicationShell.WidgetOptions; } @injectable() export abstract class WidgetOpenHandler implements OpenHandler { /** * The widget open handler id. * * #### Implementation * - A widget factory for this id should be registered. * - Subclasses should not implement `WidgetFactory` * to avoid exposing capabilities to create a widget outside of `WidgetManager`. */ abstract readonly id: string; @inject(ApplicationShell) protected readonly shell: ApplicationShell; @inject(WidgetManager) protected readonly widgetManager: WidgetManager; protected readonly onCreatedEmitter = new Emitter(); /** * Emit when a new widget is created. */ readonly onCreated: Event = this.onCreatedEmitter.event; /** * All opened widgets. */ get all(): W[] { return this.widgetManager.getWidgets(this.id) as W[]; } abstract canHandle(uri: URI, options?: WidgetOpenerOptions): MaybePromise; /** * Open a widget for the given uri and options. * Reject if the given options is not an widget options or a widget cannot be opened. */ async open(uri: URI, options?: WidgetOpenerOptions): Promise { const widget = await this.getOrCreateWidget(uri, options); await this.doOpen(widget, options); return widget; } /** * Return an existing widget for the given uri. */ getByUri(uri: URI): Promise { return this.getWidget(uri); } /** * Return an existing widget for the given uri or creates a new one. * * It does not open a widget, use `open` instead. */ getOrCreateByUri(uri: URI): Promise { return this.getOrCreateWidget(uri); } async closeAll(options?: ApplicationShell.CloseOptions): Promise { const closed = await Promise.all(this.all.map(widget => this.shell.closeWidget(widget.id, options))); return closed.filter(widget => !!widget) as W[]; } @postConstruct() protected init(): void { this.widgetManager.onDidCreateWidget(({factoryId, widget}) => { if (factoryId === this.id) { this.onCreatedEmitter.fire(widget as W); } }); } protected async doOpen(widget: W, options?: WidgetOpenerOptions): Promise { const op: WidgetOpenerOptions = { mode: 'activate', ...options }; if (!widget.isAttached) { this.shell.addWidget(widget, op.widgetOptions || {area: 'main'}); } if (op.mode === 'activate') { await this.shell.activateWidget(widget.id); } else if (op.mode === 'reveal') { await this.shell.revealWidget(widget.id); } } protected getWidget(uri: URI, options?: WidgetOpenerOptions): Promise { const widgetOptions = this.createWidgetOptions(uri, options); return this.widgetManager.getWidget(this.id, widgetOptions) as Promise; } protected getOrCreateWidget(uri: URI, options?: WidgetOpenerOptions): Promise { const widgetOptions = this.createWidgetOptions(uri, options); return this.widgetManager.getOrCreateWidget(this.id, widgetOptions) as Promise; } protected abstract createWidgetOptions(uri: URI, options?: WidgetOpenerOptions): Object; }