123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import { IRestorable, RestorablePool } from '@jupyterlab/statedb';
- import { IDisposable } from '@lumino/disposable';
- import { ISignal, Signal } from '@lumino/signaling';
- import { FocusTracker, Widget } from '@lumino/widgets';
- /**
- * A tracker that tracks widgets.
- *
- * @typeparam T - The type of widget being tracked. Defaults to `Widget`.
- */
- export interface IWidgetTracker<T extends Widget = Widget> extends IDisposable {
- /**
- * A signal emitted when a widget is added.
- */
- readonly widgetAdded: ISignal<this, T>;
- /**
- * The current widget is the most recently focused or added widget.
- *
- * #### Notes
- * It is the most recently focused widget, or the most recently added
- * widget if no widget has taken focus.
- */
- readonly currentWidget: T | null;
- /**
- * A signal emitted when the current instance changes.
- *
- * #### Notes
- * If the last instance being tracked is disposed, `null` will be emitted.
- */
- readonly currentChanged: ISignal<this, T | null>;
- /**
- * The number of instances held by the tracker.
- */
- readonly size: number;
- /**
- * A promise that is resolved when the widget tracker has been
- * restored from a serialized state.
- *
- * #### Notes
- * Most client code will not need to use this, since they can wait
- * for the whole application to restore. However, if an extension
- * wants to perform actions during the application restoration, but
- * after the restoration of another widget tracker, they can use
- * this promise.
- */
- readonly restored: Promise<void>;
- /**
- * A signal emitted when a widget is updated.
- */
- readonly widgetUpdated: ISignal<this, T>;
- /**
- * Find the first instance in the tracker that satisfies a filter function.
- *
- * @param - fn The filter function to call on each instance.
- *
- * #### Notes
- * If nothing is found, the value returned is `undefined`.
- */
- find(fn: (obj: T) => boolean): T | undefined;
- /**
- * Iterate through each instance in the tracker.
- *
- * @param fn - The function to call on each instance.
- */
- forEach(fn: (obj: T) => void): void;
- /**
- * Filter the instances in the tracker based on a predicate.
- *
- * @param fn - The function by which to filter.
- */
- filter(fn: (obj: T) => boolean): T[];
- /**
- * Check if this tracker has the specified instance.
- *
- * @param obj - The object whose existence is being checked.
- */
- has(obj: Widget): boolean;
- /**
- * Inject an instance into the widget tracker without the tracker handling
- * its restoration lifecycle.
- *
- * @param obj - The instance to inject into the tracker.
- */
- inject(obj: T): void;
- }
- /**
- * A class that keeps track of widget instances on an Application shell.
- *
- * @typeparam T - The type of widget being tracked. Defaults to `Widget`.
- *
- * #### Notes
- * The API surface area of this concrete implementation is substantially larger
- * than the widget tracker interface it implements. The interface is intended
- * for export by JupyterLab plugins that create widgets and have clients who may
- * wish to keep track of newly created widgets. This class, however, can be used
- * internally by plugins to restore state as well.
- */
- export class WidgetTracker<T extends Widget = Widget>
- implements IWidgetTracker<T>, IRestorable<T> {
- /**
- * Create a new widget tracker.
- *
- * @param options - The instantiation options for a widget tracker.
- */
- constructor(options: WidgetTracker.IOptions) {
- const focus = (this._focusTracker = new FocusTracker());
- const pool = (this._pool = new RestorablePool(options));
- this.namespace = options.namespace;
- focus.currentChanged.connect((_, current) => {
- if (current.newValue !== this.currentWidget) {
- pool.current = current.newValue;
- }
- }, this);
- pool.added.connect((_, widget) => {
- this._widgetAdded.emit(widget);
- }, this);
- pool.currentChanged.connect((_, widget) => {
- // If the pool's current reference is `null` but the focus tracker has a
- // current widget, update the pool to match the focus tracker.
- if (widget === null && focus.currentWidget) {
- pool.current = focus.currentWidget;
- return;
- }
- this.onCurrentChanged(widget);
- this._currentChanged.emit(widget);
- }, this);
- pool.updated.connect((_, widget) => {
- this._widgetUpdated.emit(widget);
- }, this);
- }
- /**
- * A namespace for all tracked widgets, (e.g., `notebook`).
- */
- readonly namespace: string;
- /**
- * A signal emitted when the current widget changes.
- */
- get currentChanged(): ISignal<this, T | null> {
- return this._currentChanged;
- }
- /**
- * The current widget is the most recently focused or added widget.
- *
- * #### Notes
- * It is the most recently focused widget, or the most recently added
- * widget if no widget has taken focus.
- */
- get currentWidget(): T | null {
- return this._pool.current || null;
- }
- /**
- * A promise resolved when the tracker has been restored.
- */
- get restored(): Promise<void> {
- return this._pool.restored;
- }
- /**
- * The number of widgets held by the tracker.
- */
- get size(): number {
- return this._pool.size;
- }
- /**
- * A signal emitted when a widget is added.
- *
- * #### Notes
- * This signal will only fire when a widget is added to the tracker. It will
- * not fire if a widget is injected into the tracker.
- */
- get widgetAdded(): ISignal<this, T> {
- return this._widgetAdded;
- }
- /**
- * A signal emitted when a widget is updated.
- */
- get widgetUpdated(): ISignal<this, T> {
- return this._widgetUpdated;
- }
- /**
- * Add a new widget to the tracker.
- *
- * @param widget - The widget being added.
- *
- * #### Notes
- * The widget passed into the tracker is added synchronously; its existence in
- * the tracker can be checked with the `has()` method. The promise this method
- * returns resolves after the widget has been added and saved to an underlying
- * restoration connector, if one is available.
- *
- * The newly added widget becomes the current widget unless the focus tracker
- * already had a focused widget.
- */
- async add(widget: T): Promise<void> {
- this._focusTracker.add(widget);
- await this._pool.add(widget);
- if (!this._focusTracker.activeWidget) {
- this._pool.current = widget;
- }
- }
- /**
- * Test whether the tracker is disposed.
- */
- get isDisposed(): boolean {
- return this._isDisposed;
- }
- /**
- * Dispose of the resources held by the tracker.
- */
- dispose(): void {
- if (this.isDisposed) {
- return;
- }
- this._isDisposed = true;
- this._pool.dispose();
- this._focusTracker.dispose();
- Signal.clearData(this);
- }
- /**
- * Find the first widget in the tracker that satisfies a filter function.
- *
- * @param - fn The filter function to call on each widget.
- *
- * #### Notes
- * If no widget is found, the value returned is `undefined`.
- */
- find(fn: (widget: T) => boolean): T | undefined {
- return this._pool.find(fn);
- }
- /**
- * Iterate through each widget in the tracker.
- *
- * @param fn - The function to call on each widget.
- */
- forEach(fn: (widget: T) => void): void {
- return this._pool.forEach(fn);
- }
- /**
- * Filter the widgets in the tracker based on a predicate.
- *
- * @param fn - The function by which to filter.
- */
- filter(fn: (widget: T) => boolean): T[] {
- return this._pool.filter(fn);
- }
- /**
- * Inject a foreign widget into the widget tracker.
- *
- * @param widget - The widget to inject into the tracker.
- *
- * #### Notes
- * Injected widgets will not have their state saved by the tracker.
- *
- * The primary use case for widget injection is for a plugin that offers a
- * sub-class of an extant plugin to have its instances share the same commands
- * as the parent plugin (since most relevant commands will use the
- * `currentWidget` of the parent plugin's widget tracker). In this situation,
- * the sub-class plugin may well have its own widget tracker for layout and
- * state restoration in addition to injecting its widgets into the parent
- * plugin's widget tracker.
- */
- inject(widget: T): Promise<void> {
- return this._pool.inject(widget);
- }
- /**
- * Check if this tracker has the specified widget.
- *
- * @param widget - The widget whose existence is being checked.
- */
- has(widget: Widget): boolean {
- return this._pool.has(widget as any);
- }
- /**
- * Restore the widgets in this tracker's namespace.
- *
- * @param options - The configuration options that describe restoration.
- *
- * @returns A promise that resolves when restoration has completed.
- *
- * #### Notes
- * This function should not typically be invoked by client code.
- * Its primary use case is to be invoked by a restorer.
- */
- async restore(options: IRestorable.IOptions<T>): Promise<any> {
- return this._pool.restore(options);
- }
- /**
- * Save the restore data for a given widget.
- *
- * @param widget - The widget being saved.
- */
- async save(widget: T): Promise<void> {
- return this._pool.save(widget);
- }
- /**
- * Handle the current change event.
- *
- * #### Notes
- * The default implementation is a no-op.
- */
- protected onCurrentChanged(value: T | null): void {
- /* no-op */
- }
- private _currentChanged = new Signal<this, T | null>(this);
- private _focusTracker: FocusTracker<T>;
- private _pool: RestorablePool<T>;
- private _isDisposed = false;
- private _widgetAdded = new Signal<this, T>(this);
- private _widgetUpdated = new Signal<this, T>(this);
- }
- /**
- * A namespace for `WidgetTracker` statics.
- */
- export namespace WidgetTracker {
- /**
- * The instantiation options for a widget tracker.
- */
- export interface IOptions {
- /**
- * A namespace for all tracked widgets, (e.g., `notebook`).
- */
- namespace: string;
- }
- }
|