diff --git a/spec/workspace-spec.js b/spec/workspace-spec.js index b013ff47c..5437e4fb2 100644 --- a/spec/workspace-spec.js +++ b/spec/workspace-spec.js @@ -1076,6 +1076,127 @@ describe('Workspace', () => { }) }) + describe('pane containers', () => { + it('maintains the active pane and item globally across active pane containers', () => { + const leftDock = workspace.getLeftDock() + const leftItem1 = {element: document.createElement('div')} + const leftItem2 = {element: document.createElement('div')} + const leftItem3 = {element: document.createElement('div')} + const leftPane1 = leftDock.getActivePane() + leftPane1.addItems([leftItem1, leftItem2]) + const leftPane2 = leftPane1.splitDown({items: [leftItem3]}) + + const rightDock = workspace.getRightDock() + const rightItem1 = {element: document.createElement('div')} + const rightItem2 = {element: document.createElement('div')} + const rightItem3 = {element: document.createElement('div')} + const rightPane1 = rightDock.getActivePane() + rightPane1.addItems([rightItem1, rightItem2]) + const rightPane2 = rightPane1.splitDown({items: [rightItem3]}) + + const bottomDock = workspace.getBottomDock() + const bottomItem1 = {element: document.createElement('div')} + const bottomItem2 = {element: document.createElement('div')} + const bottomItem3 = {element: document.createElement('div')} + const bottomPane1 = bottomDock.getActivePane() + bottomPane1.addItems([bottomItem1, bottomItem2]) + const bottomPane2 = bottomPane1.splitDown({items: [bottomItem3]}) + + const center = workspace.getCenter() + const centerItem1 = {element: document.createElement('div')} + const centerItem2 = {element: document.createElement('div')} + const centerItem3 = {element: document.createElement('div')} + const centerPane1 = center.getActivePane() + centerPane1.addItems([centerItem1, centerItem2]) + const centerPane2 = centerPane1.splitDown({items: [centerItem3]}) + + const activePaneContainers = [] + const activePanes = [] + const activeItems = [] + workspace.onDidChangeActivePaneContainer((container) => activePaneContainers.push(container)) + workspace.onDidChangeActivePane((pane) => activePanes.push(pane)) + workspace.onDidChangeActivePaneItem((item) => activeItems.push(item)) + function clearEvents () { + activePaneContainers.length = 0 + activePanes.length = 0 + activeItems.length = 0 + } + + expect(workspace.getActivePaneContainer()).toBe(center) + expect(workspace.getActivePane()).toBe(centerPane2) + expect(workspace.getActivePaneItem()).toBe(centerItem3) + + leftDock.activate() + expect(workspace.getActivePaneContainer()).toBe(leftDock) + expect(workspace.getActivePane()).toBe(leftPane2) + expect(workspace.getActivePaneItem()).toBe(leftItem3) + expect(activePaneContainers).toEqual([leftDock]) + expect(activePanes).toEqual([leftPane2]) + expect(activeItems).toEqual([leftItem3]) + + clearEvents() + leftPane1.activate() + leftPane1.activate() + expect(workspace.getActivePaneContainer()).toBe(leftDock) + expect(workspace.getActivePane()).toBe(leftPane1) + expect(workspace.getActivePaneItem()).toBe(leftItem1) + expect(activePaneContainers).toEqual([]) + expect(activePanes).toEqual([leftPane1]) + expect(activeItems).toEqual([leftItem1]) + + clearEvents() + leftPane1.activateItem(leftItem2) + leftPane1.activateItem(leftItem2) + expect(workspace.getActivePaneContainer()).toBe(leftDock) + expect(workspace.getActivePane()).toBe(leftPane1) + expect(workspace.getActivePaneItem()).toBe(leftItem2) + expect(activePaneContainers).toEqual([]) + expect(activePanes).toEqual([]) + expect(activeItems).toEqual([leftItem2]) + + clearEvents() + expect(rightDock.getActivePane()).toBe(rightPane2) + rightPane1.activate() + rightPane1.activate() + expect(workspace.getActivePaneContainer()).toBe(rightDock) + expect(workspace.getActivePane()).toBe(rightPane1) + expect(workspace.getActivePaneItem()).toBe(rightItem1) + expect(activePaneContainers).toEqual([rightDock]) + expect(activePanes).toEqual([rightPane1]) + expect(activeItems).toEqual([rightItem1]) + + clearEvents() + rightPane1.activateItem(rightItem2) + expect(workspace.getActivePaneContainer()).toBe(rightDock) + expect(workspace.getActivePane()).toBe(rightPane1) + expect(workspace.getActivePaneItem()).toBe(rightItem2) + expect(activePaneContainers).toEqual([]) + expect(activePanes).toEqual([]) + expect(activeItems).toEqual([rightItem2]) + + clearEvents() + expect(bottomDock.getActivePane()).toBe(bottomPane2) + bottomPane2.activate() + bottomPane2.activate() + expect(workspace.getActivePaneContainer()).toBe(bottomDock) + expect(workspace.getActivePane()).toBe(bottomPane2) + expect(workspace.getActivePaneItem()).toBe(bottomItem3) + expect(activePaneContainers).toEqual([bottomDock]) + expect(activePanes).toEqual([bottomPane2]) + expect(activeItems).toEqual([bottomItem3]) + + clearEvents() + center.activate() + center.activate() + expect(workspace.getActivePaneContainer()).toBe(center) + expect(workspace.getActivePane()).toBe(centerPane2) + expect(workspace.getActivePaneItem()).toBe(centerItem3) + expect(activePaneContainers).toEqual([center]) + expect(activePanes).toEqual([centerPane2]) + expect(activeItems).toEqual([centerItem3]) + }) + }) + describe('the grammar-used hook', () => { it('fires when opening a file or changing the grammar of an open file', () => { let editor = null diff --git a/src/dock.js b/src/dock.js index 132150fca..30fd48180 100644 --- a/src/dock.js +++ b/src/dock.js @@ -33,6 +33,7 @@ module.exports = class Dock { this.deserializerManager = params.deserializerManager this.notificationManager = params.notificationManager this.viewRegistry = params.viewRegistry + this.didActivate = params.didActivate this.didHide = params.didHide this.paneContainer = new PaneContainer({ @@ -50,10 +51,13 @@ module.exports = class Dock { } this.subscriptions = new CompositeDisposable( - this.paneContainer.onDidActivatePane(() => this.open()), - this.paneContainer.observePanes(pane => { - pane.onDidRemoveItem(this.handleDidRemovePaneItem.bind(this)) - }) + this.paneContainer.onDidActivatePane(() => { + this.open() + this.didActivate(this) + }), + this.paneContainer.onDidDestroyPaneItem(this.handleDidRemovePaneItem.bind(this)), + this.paneContainer.onDidChangeActivePane((item) => params.didChangeActivePane(this, item)), + this.paneContainer.onDidChangeActivePaneItem((item) => params.didChangeActivePaneItem(this, item)) ) } @@ -94,7 +98,6 @@ module.exports = class Dock { } activate () { - this.open() this.getActivePane().activate() } diff --git a/src/pane-container.js b/src/pane-container.js index ad1872f1d..fce117c0f 100644 --- a/src/pane-container.js +++ b/src/pane-container.js @@ -52,8 +52,7 @@ class PaneContainer { deserialize (state, deserializerManager) { if (state.version !== SERIALIZATION_VERSION) return this.setRoot(deserializerManager.deserialize(state.root)) - const activePane = find(this.getRoot().getPanes(), pane => pane.id === state.activePaneId) - this.didActivatePane(activePane != null ? activePane : this.getPanes()[0]) + this.activePane = find(this.getRoot().getPanes(), pane => pane.id === state.activePaneId) || this.getPanes()[0] if (this.config.get('core.destroyEmptyPanes')) this.destroyEmptyPanes() } diff --git a/src/workspace-center.js b/src/workspace-center.js index efaf0654c..e2e9eac6c 100644 --- a/src/workspace-center.js +++ b/src/workspace-center.js @@ -3,11 +3,18 @@ const TextEditor = require('./text-editor') module.exports = class WorkspaceCenter { - constructor (paneContainer) { + constructor ({paneContainer, didActivate, didChangeActivePaneItem}) { this.paneContainer = paneContainer + this.didActivate = didActivate + this.paneContainer.onDidActivatePane(() => this.didActivate(this)) + this.paneContainer.onDidChangeActivePaneItem((item) => { + didChangeActivePaneItem(this, item) + }) } - activate () {} + activate () { + this.getActivePane().activate() + } getLocation () { return 'center' diff --git a/src/workspace.js b/src/workspace.js index 90c9d93e4..f6378341f 100644 --- a/src/workspace.js +++ b/src/workspace.js @@ -36,6 +36,9 @@ module.exports = class Workspace extends Model { this.updateDocumentEdited = this.updateDocumentEdited.bind(this) this.didDestroyPaneItem = this.didDestroyPaneItem.bind(this) this.didChangeActivePaneItem = this.didChangeActivePaneItem.bind(this) + this.didChangeActivePaneOnPaneContainer = this.didChangeActivePaneOnPaneContainer.bind(this) + this.didChangeActivePaneItemOnPaneContainer = this.didChangeActivePaneItemOnPaneContainer.bind(this) + this.didActivatePaneContainer = this.didActivatePaneContainer.bind(this) this.didHideDock = this.didHideDock.bind(this) this.packageManager = params.packageManager @@ -70,12 +73,17 @@ module.exports = class Workspace extends Model { this.defaultDirectorySearcher = new DefaultDirectorySearcher() this.consumeServices(this.packageManager) - this.center = new WorkspaceCenter(this.paneContainer) + this.center = new WorkspaceCenter({ + paneContainer: this.paneContainer, + didActivate: this.didActivatePaneContainer, + didChangeActivePaneItem: this.didChangeActivePaneItemOnPaneContainer + }) this.docks = { left: this.createDock('left'), right: this.createDock('right'), bottom: this.createDock('bottom') } + this.activePaneContainer = this.center this.panelContainers = { top: new PanelContainer({viewRegistry: this.viewRegistry, location: 'top'}), @@ -110,16 +118,15 @@ module.exports = class Workspace extends Model { deserializerManager: this.deserializerManager, notificationManager: this.notificationManager, viewRegistry: this.viewRegistry, - didHide: this.didHideDock + didHide: this.didHideDock, + didActivate: this.didActivatePaneContainer, + didChangeActivePane: this.didChangeActivePaneOnPaneContainer, + didChangeActivePaneItem: this.didChangeActivePaneItemOnPaneContainer }) dock.onDidDestroyPaneItem(this.didDestroyPaneItem) return dock } - didHideDock () { - this.getCenter().getActivePane().activate() - } - reset (packageManager) { this.packageManager = packageManager this.emitter.dispose() @@ -138,12 +145,17 @@ module.exports = class Workspace extends Model { }) this.paneContainer.onDidDestroyPaneItem(this.didDestroyPaneItem) - this.center = new WorkspaceCenter(this.paneContainer) + this.center = new WorkspaceCenter({ + paneContainer: this.paneContainer, + didActivate: this.didActivatePaneContainer, + didChangeActivePaneItem: this.didChangeActivePaneItemOnPaneContainer + }) this.docks = { left: this.createDock('left'), right: this.createDock('right'), bottom: this.createDock('bottom') } + this.activePaneContainer = this.center this.panelContainers = { top: new PanelContainer({viewRegistry: this.viewRegistry, location: 'top'}), @@ -212,6 +224,7 @@ module.exports = class Workspace extends Model { this.docks[location].deserialize(serialized, deserializerManager) } } + this.updateWindowTitle() } getPackageNamesWithActiveGrammars () { @@ -241,6 +254,32 @@ module.exports = class Workspace extends Model { return _.uniq(packageNames) } + didActivatePaneContainer (paneContainer) { + if (paneContainer !== this.getActivePaneContainer()) { + this.activePaneContainer = paneContainer + if (global.debug) debugger + this.emitter.emit('did-change-active-pane-container', this.activePaneContainer) + this.emitter.emit('did-change-active-pane', this.activePaneContainer.getActivePane()) + this.emitter.emit('did-change-active-pane-item', this.activePaneContainer.getActivePaneItem()) + } + } + + didChangeActivePaneOnPaneContainer (paneContainer, pane) { + if (paneContainer === this.getActivePaneContainer()) { + this.emitter.emit('did-change-active-pane', pane) + } + } + + didChangeActivePaneItemOnPaneContainer (paneContainer, item) { + if (paneContainer === this.getActivePaneContainer()) { + this.emitter.emit('did-change-active-pane-item', item) + } + } + + didHideDock () { + this.getCenter().activate() + } + setHoveredDock (hoveredDock) { this.hoveredDock = hoveredDock _.values(this.docks).forEach(dock => { @@ -395,6 +434,10 @@ module.exports = class Workspace extends Model { Section: Event Subscription */ + onDidChangeActivePaneContainer (callback) { + return this.emitter.on('did-change-active-pane-container', callback) + } + // Essential: Invoke the given callback with all current and future text // editors in the workspace. // @@ -434,7 +477,7 @@ module.exports = class Workspace extends Model { // // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. onDidChangeActivePaneItem (callback) { - return this.paneContainer.onDidChangeActivePaneItem(callback) + return this.emitter.on('did-change-active-pane-item', callback) } // Essential: Invoke the given callback when the active pane item stops @@ -462,7 +505,10 @@ module.exports = class Workspace extends Model { // * `item` The current active pane item. // // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - observeActivePaneItem (callback) { return this.paneContainer.observeActivePaneItem(callback) } + observeActivePaneItem (callback) { + callback(this.getActivePaneItem()) + return this.onDidChangeActivePaneItem(callback) + } // Essential: Invoke the given callback whenever an item is opened. Unlike // {::onDidAddPaneItem}, observers will be notified for items that are already @@ -541,7 +587,9 @@ module.exports = class Workspace extends Model { // * `pane` A {Pane} that is the current return value of {::getActivePane}. // // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - onDidChangeActivePane (callback) { return this.paneContainer.onDidChangeActivePane(callback) } + onDidChangeActivePane (callback) { + return this.emitter.on('did-change-active-pane', callback) + } // Extended: Invoke the given callback with the current active pane and when // the active pane changes. @@ -551,7 +599,10 @@ module.exports = class Workspace extends Model { // * `pane` A {Pane} that is the current return value of {::getActivePane}. // // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe. - observeActivePane (callback) { return this.paneContainer.observeActivePane(callback) } + observeActivePane (callback) { + callback(this.getActivePane()) + return this.onDidChangeActivePane(callback) + } // Extended: Invoke the given callback when a pane item is added to the // workspace. @@ -1065,7 +1116,7 @@ module.exports = class Workspace extends Model { // // Returns an pane item {Object}. getActivePaneItem () { - return this.paneContainer.getActivePaneItem() + return this.getActivePaneContainer().getActivePaneItem() } // Essential: Get all text editors in the workspace. @@ -1164,6 +1215,10 @@ module.exports = class Workspace extends Model { Section: Panes */ + getActivePaneContainer () { + return this.activePaneContainer + } + // Extended: Get all panes in the workspace. // // Returns an {Array} of {Pane}s. @@ -1175,7 +1230,7 @@ module.exports = class Workspace extends Model { // // Returns a {Pane}. getActivePane () { - return this.paneContainer.getActivePane() + return this.getActivePaneContainer().getActivePane() } // Extended: Make the next pane active.