|
@@ -2,7 +2,7 @@
|
|
|
// Distributed under the terms of the Modified BSD License.
|
|
|
|
|
|
import {
|
|
|
- ArrayExt, each, find, toArray
|
|
|
+ ArrayExt, each, find, IIterator, iter, toArray
|
|
|
} from '@phosphor/algorithm';
|
|
|
|
|
|
import {
|
|
@@ -44,6 +44,12 @@ const CURRENT_CLASS = 'jp-mod-current';
|
|
|
const ACTIVE_CLASS = 'jp-mod-active';
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * The default rank of items added to a sidebar.
|
|
|
+ */
|
|
|
+const DEFAULT_RANK = 500;
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* The application shell for JupyterLab.
|
|
|
*/
|
|
@@ -117,21 +123,31 @@ class ApplicationShell extends Widget {
|
|
|
this._tracker.activeChanged.connect(this._onActiveChanged, this);
|
|
|
|
|
|
// Connect main layout change listener.
|
|
|
- this._dockPanel.layoutModified.connect(this._save, this);
|
|
|
+ this._dockPanel.layoutModified.connect(() => {
|
|
|
+ this._layoutModified.emit(void 0);
|
|
|
+ this._save();
|
|
|
+ }, this);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A signal emitted when main area's current focus changes.
|
|
|
+ * A signal emitted when main area's active focus changes.
|
|
|
*/
|
|
|
- get currentChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
|
|
|
- return this._currentChanged;
|
|
|
+ get activeChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
|
|
|
+ return this._activeChanged;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A signal emitted when main area's active focus changes.
|
|
|
+ * The active widget in the shell's main area.
|
|
|
*/
|
|
|
- get activeChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
|
|
|
- return this._activeChanged;
|
|
|
+ get activeWidget(): Widget | null {
|
|
|
+ return this._tracker.activeWidget;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A signal emitted when main area's current focus changes.
|
|
|
+ */
|
|
|
+ get currentChanged(): ISignal<this, ApplicationShell.IChangedArgs> {
|
|
|
+ return this._currentChanged;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -142,28 +158,20 @@ class ApplicationShell extends Widget {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The active widget in the shell's main area.
|
|
|
+ * A signal emitted when the main area's layout is modified.
|
|
|
*/
|
|
|
- get activeWidget(): Widget | null {
|
|
|
- return this._tracker.activeWidget;
|
|
|
+ get layoutModified(): ISignal<this, void> {
|
|
|
+ return this._layoutModified;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * True if the given area is empty.
|
|
|
+ * The main dock area's user interface mode.
|
|
|
*/
|
|
|
- isEmpty(area: ApplicationShell.Area): boolean {
|
|
|
- switch (area) {
|
|
|
- case 'left':
|
|
|
- return this._leftHandler.stackedPanel.widgets.length === 0;
|
|
|
- case 'main':
|
|
|
- return this._dockPanel.isEmpty;
|
|
|
- case 'top':
|
|
|
- return this._topPanel.widgets.length === 0;
|
|
|
- case 'right':
|
|
|
- return this._rightHandler.stackedPanel.widgets.length === 0;
|
|
|
- default:
|
|
|
- return true;
|
|
|
- }
|
|
|
+ get mode(): DockPanel.Mode {
|
|
|
+ return this._dockPanel.mode;
|
|
|
+ }
|
|
|
+ set mode(mode: DockPanel.Mode) {
|
|
|
+ this._dockPanel.mode = mode;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -174,7 +182,7 @@ class ApplicationShell extends Widget {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Activate a widget in it's area.
|
|
|
+ * Activate a widget in its area.
|
|
|
*/
|
|
|
activateById(id: string): void {
|
|
|
if (this._leftHandler.has(id)) {
|
|
@@ -260,7 +268,7 @@ class ApplicationShell extends Widget {
|
|
|
console.error('widgets added to app shell must have unique id property');
|
|
|
return;
|
|
|
}
|
|
|
- let rank = 'rank' in options ? options.rank : 100;
|
|
|
+ let rank = 'rank' in options ? options.rank : DEFAULT_RANK;
|
|
|
this._leftHandler.addWidget(widget, rank);
|
|
|
this._save();
|
|
|
}
|
|
@@ -293,7 +301,7 @@ class ApplicationShell extends Widget {
|
|
|
console.error('widgets added to app shell must have unique id property');
|
|
|
return;
|
|
|
}
|
|
|
- let rank = 'rank' in options ? options.rank : 100;
|
|
|
+ let rank = 'rank' in options ? options.rank : DEFAULT_RANK;
|
|
|
this._rightHandler.addWidget(widget, rank);
|
|
|
this._save();
|
|
|
}
|
|
@@ -340,6 +348,24 @@ class ApplicationShell extends Widget {
|
|
|
each(toArray(this._dockPanel.widgets()), widget => { widget.close(); });
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * True if the given area is empty.
|
|
|
+ */
|
|
|
+ isEmpty(area: ApplicationShell.Area): boolean {
|
|
|
+ switch (area) {
|
|
|
+ case 'left':
|
|
|
+ return this._leftHandler.stackedPanel.widgets.length === 0;
|
|
|
+ case 'main':
|
|
|
+ return this._dockPanel.isEmpty;
|
|
|
+ case 'top':
|
|
|
+ return this._topPanel.widgets.length === 0;
|
|
|
+ case 'right':
|
|
|
+ return this._rightHandler.stackedPanel.widgets.length === 0;
|
|
|
+ default:
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Set the layout data store for the application shell.
|
|
|
*/
|
|
@@ -357,11 +383,16 @@ class ApplicationShell extends Widget {
|
|
|
|
|
|
// Rehydrate the main area.
|
|
|
if (mainArea) {
|
|
|
- if (mainArea.dock) {
|
|
|
- this._dockPanel.restoreLayout(mainArea.dock);
|
|
|
+ const { currentWidget, dock, mode } = mainArea;
|
|
|
+
|
|
|
+ if (dock) {
|
|
|
+ this._dockPanel.restoreLayout(dock);
|
|
|
}
|
|
|
- if (mainArea.currentWidget) {
|
|
|
- this.activateById(mainArea.currentWidget.id);
|
|
|
+ if (currentWidget) {
|
|
|
+ this.activateById(currentWidget.id);
|
|
|
+ }
|
|
|
+ if (mode) {
|
|
|
+ this._dockPanel.mode = mode;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -392,6 +423,24 @@ class ApplicationShell extends Widget {
|
|
|
this._rightHandler.sideBar.currentChanged.connect(this._save, this);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the widgets for an application area.
|
|
|
+ */
|
|
|
+ widgets(area: ApplicationShell.Area): IIterator<Widget> {
|
|
|
+ switch (area) {
|
|
|
+ case 'main':
|
|
|
+ return this._dockPanel.widgets();
|
|
|
+ case 'left':
|
|
|
+ return iter(this._leftHandler.sideBar.titles.map(t => t.owner));
|
|
|
+ case 'right':
|
|
|
+ return iter(this._rightHandler.sideBar.titles.map(t => t.owner));
|
|
|
+ case 'top':
|
|
|
+ return this._topPanel.children();
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* Return the TabBar that has the currently active Widget or null.
|
|
|
*/
|
|
@@ -465,7 +514,8 @@ class ApplicationShell extends Widget {
|
|
|
let data: ApplicationShell.ILayout = {
|
|
|
mainArea: {
|
|
|
currentWidget: this._tracker.currentWidget,
|
|
|
- dock: this._dockPanel.saveLayout()
|
|
|
+ dock: this._dockPanel.saveLayout(),
|
|
|
+ mode: this._dockPanel.mode
|
|
|
},
|
|
|
leftArea: this._leftHandler.dehydrate(),
|
|
|
rightArea: this._rightHandler.dehydrate()
|
|
@@ -503,18 +553,19 @@ class ApplicationShell extends Widget {
|
|
|
this._activeChanged.emit(args);
|
|
|
}
|
|
|
|
|
|
+ private _activeChanged = new Signal<this, ApplicationShell.IChangedArgs>(this);
|
|
|
+ private _currentChanged = new Signal<this, ApplicationShell.IChangedArgs>(this);
|
|
|
private _database: ApplicationShell.ILayoutDB = null;
|
|
|
private _dockPanel: DockPanel;
|
|
|
private _hboxPanel: BoxPanel;
|
|
|
private _hsplitPanel: SplitPanel;
|
|
|
private _isRestored = false;
|
|
|
+ private _layoutModified = new Signal<this, void>(this);
|
|
|
private _leftHandler: Private.SideBarHandler;
|
|
|
private _restored = new PromiseDelegate<ApplicationShell.ILayout>();
|
|
|
private _rightHandler: Private.SideBarHandler;
|
|
|
- private _topPanel: Panel;
|
|
|
private _tracker = new FocusTracker<Widget>();
|
|
|
- private _currentChanged = new Signal<this, ApplicationShell.IChangedArgs>(this);
|
|
|
- private _activeChanged = new Signal<this, ApplicationShell.IChangedArgs>(this);
|
|
|
+ private _topPanel: Panel;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -607,6 +658,11 @@ namespace ApplicationShell {
|
|
|
* The contents of the main application dock panel.
|
|
|
*/
|
|
|
readonly dock: DockLayout.ILayoutConfig | null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The document mode (i.e., multiple/single) of the main dock panel.
|
|
|
+ */
|
|
|
+ readonly mode: DockPanel.Mode | null;
|
|
|
};
|
|
|
|
|
|
/**
|