panel.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { Kernel, KernelMessage, Session } from '@jupyterlab/services';
  4. import { Token } from '@phosphor/coreutils';
  5. import { Message } from '@phosphor/messaging';
  6. import { ISignal, Signal } from '@phosphor/signaling';
  7. import { IClientSession, showErrorMessage } from '@jupyterlab/apputils';
  8. import { DocumentWidget } from '@jupyterlab/docregistry';
  9. import { RenderMimeRegistry } from '@jupyterlab/rendermime';
  10. import { INotebookModel } from './model';
  11. import { Notebook } from './widget';
  12. /**
  13. * The class name added to notebook panels.
  14. */
  15. const NOTEBOOK_PANEL_CLASS = 'jp-NotebookPanel';
  16. const NOTEBOOK_PANEL_TOOLBAR_CLASS = 'jp-NotebookPanel-toolbar';
  17. const NOTEBOOK_PANEL_NOTEBOOK_CLASS = 'jp-NotebookPanel-notebook';
  18. /**
  19. * A widget that hosts a notebook toolbar and content area.
  20. *
  21. * #### Notes
  22. * The widget keeps the document metadata in sync with the current
  23. * kernel on the context.
  24. */
  25. export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
  26. /**
  27. * Construct a new notebook panel.
  28. */
  29. constructor(options: DocumentWidget.IOptions<Notebook, INotebookModel>) {
  30. super(options);
  31. // Set up CSS classes
  32. this.addClass(NOTEBOOK_PANEL_CLASS);
  33. this.toolbar.addClass(NOTEBOOK_PANEL_TOOLBAR_CLASS);
  34. this.content.addClass(NOTEBOOK_PANEL_NOTEBOOK_CLASS);
  35. // Set up things related to the context
  36. this.content.model = this.context.model;
  37. this.context.session.kernelChanged.connect(this._onKernelChanged, this);
  38. void this.revealed.then(() => {
  39. // Set the document edit mode on initial open if it looks like a new document.
  40. if (this.content.widgets.length === 1) {
  41. let cellModel = this.content.widgets[0].model;
  42. if (cellModel.type === 'code' && cellModel.value.text === '') {
  43. this.content.mode = 'edit';
  44. }
  45. }
  46. });
  47. }
  48. /**
  49. * A signal emitted when the panel has been activated.
  50. */
  51. get activated(): ISignal<this, void> {
  52. return this._activated;
  53. }
  54. /**
  55. * The client session used by the panel.
  56. */
  57. get session(): IClientSession {
  58. return this.context.session;
  59. }
  60. /**
  61. * The content factory for the notebook.
  62. *
  63. * TODO: deprecate this in favor of the .content attribute
  64. *
  65. */
  66. get contentFactory(): Notebook.IContentFactory {
  67. return this.content.contentFactory;
  68. }
  69. /**
  70. * The rendermime instance for the notebook.
  71. *
  72. * TODO: deprecate this in favor of the .content attribute
  73. *
  74. */
  75. get rendermime(): RenderMimeRegistry {
  76. return this.content.rendermime;
  77. }
  78. /**
  79. * The notebook used by the widget.
  80. */
  81. readonly content: Notebook;
  82. /**
  83. * The model for the widget.
  84. */
  85. get model(): INotebookModel {
  86. return this.content ? this.content.model : null;
  87. }
  88. /**
  89. * Set URI fragment identifier.
  90. */
  91. setFragment(fragment: string) {
  92. void this.context.ready.then(() => {
  93. this.content.setFragment(fragment);
  94. });
  95. }
  96. /**
  97. * Dispose of the resources used by the widget.
  98. */
  99. dispose(): void {
  100. if (this.content.notebookConfig.kernelShutdown) {
  101. this.context.session.shutdown().catch(reason => {
  102. showErrorMessage('Kernel not shutdown', reason);
  103. });
  104. }
  105. this.content.dispose();
  106. super.dispose();
  107. }
  108. /**
  109. * Handle `'activate-request'` messages.
  110. */
  111. protected onActivateRequest(msg: Message): void {
  112. super.onActivateRequest(msg);
  113. // TODO: do we still need to emit this signal? Who is using it?
  114. this._activated.emit(void 0);
  115. }
  116. /**
  117. * Handle a change in the kernel by updating the document metadata.
  118. */
  119. private _onKernelChanged(
  120. sender: any,
  121. args: Session.IKernelChangedArgs
  122. ): void {
  123. if (!this.model || !args.newValue) {
  124. return;
  125. }
  126. let { newValue } = args;
  127. void newValue.ready.then(() => {
  128. if (this.model) {
  129. this._updateLanguage(newValue.info.language_info);
  130. }
  131. });
  132. void this._updateSpec(newValue);
  133. }
  134. /**
  135. * Update the kernel language.
  136. */
  137. private _updateLanguage(language: KernelMessage.ILanguageInfo): void {
  138. this.model.metadata.set('language_info', language);
  139. }
  140. /**
  141. * Update the kernel spec.
  142. */
  143. private _updateSpec(kernel: Kernel.IKernelConnection): Promise<void> {
  144. return kernel.getSpec().then(spec => {
  145. if (this.isDisposed) {
  146. return;
  147. }
  148. this.model.metadata.set('kernelspec', {
  149. name: kernel.name,
  150. display_name: spec.display_name,
  151. language: spec.language
  152. });
  153. });
  154. }
  155. private _activated = new Signal<this, void>(this);
  156. }
  157. /**
  158. * A namespace for `NotebookPanel` statics.
  159. */
  160. export namespace NotebookPanel {
  161. /**
  162. * A content factory interface for NotebookPanel.
  163. */
  164. export interface IContentFactory extends Notebook.IContentFactory {
  165. /**
  166. * Create a new content area for the panel.
  167. */
  168. createNotebook(options: Notebook.IOptions): Notebook;
  169. }
  170. /**
  171. * The default implementation of an `IContentFactory`.
  172. */
  173. export class ContentFactory extends Notebook.ContentFactory
  174. implements IContentFactory {
  175. /**
  176. * Create a new content area for the panel.
  177. */
  178. createNotebook(options: Notebook.IOptions): Notebook {
  179. return new Notebook(options);
  180. }
  181. }
  182. /**
  183. * Default content factory for the notebook panel.
  184. */
  185. export const defaultContentFactory: ContentFactory = new ContentFactory();
  186. /* tslint:disable */
  187. /**
  188. * The notebook renderer token.
  189. */
  190. export const IContentFactory = new Token<IContentFactory>(
  191. '@jupyterlab/notebook:IContentFactory'
  192. );
  193. /* tslint:enable */
  194. }