mirror of
https://github.com/atom/atom.git
synced 2026-02-05 12:15:07 -05:00
`onDidChangeActivePaneItem` is called synchronously when the active pane item changes, and several non-critical actions preform work on that event. Critical UI feedback, like changing the active tab, needs to happen synchronously, but most other functionality should be run asynchronously.
244 lines
6.5 KiB
CoffeeScript
244 lines
6.5 KiB
CoffeeScript
{find, flatten} = require 'underscore-plus'
|
|
{Emitter, CompositeDisposable} = require 'event-kit'
|
|
Gutter = require './gutter'
|
|
Model = require './model'
|
|
Pane = require './pane'
|
|
ItemRegistry = require './item-registry'
|
|
|
|
module.exports =
|
|
class PaneContainer extends Model
|
|
atom.deserializers.add(this)
|
|
|
|
@version: 1
|
|
|
|
root: null
|
|
stoppedChangingActivePaneItemDelay: 100
|
|
stoppedChangingActivePaneItemTimeout: null
|
|
|
|
@deserialize: (state) ->
|
|
container = Object.create(@prototype) # allows us to pass a self reference to our child before invoking constructor
|
|
state.root = atom.deserializers.deserialize(state.root, {container})
|
|
state.destroyEmptyPanes = atom.config.get('core.destroyEmptyPanes')
|
|
state.activePane = find state.root.getPanes(), (pane) -> pane.id is state.activePaneId
|
|
@call(container, state) # run constructor
|
|
container
|
|
|
|
constructor: (params) ->
|
|
super
|
|
|
|
@activePane = params?.activePane
|
|
|
|
@emitter = new Emitter
|
|
@subscriptions = new CompositeDisposable
|
|
|
|
@itemRegistry = new ItemRegistry
|
|
|
|
@setRoot(params?.root ? new Pane)
|
|
@setActivePane(@getPanes()[0]) unless @getActivePane()
|
|
|
|
@destroyEmptyPanes() if params?.destroyEmptyPanes
|
|
|
|
@monitorActivePaneItem()
|
|
@monitorPaneItems()
|
|
|
|
serialize: (params) ->
|
|
deserializer: 'PaneContainer'
|
|
version: @constructor.version
|
|
root: @root?.serialize()
|
|
activePaneId: @activePane.id
|
|
|
|
onDidChangeRoot: (fn) ->
|
|
@emitter.on 'did-change-root', fn
|
|
|
|
observeRoot: (fn) ->
|
|
fn(@getRoot())
|
|
@onDidChangeRoot(fn)
|
|
|
|
onDidAddPane: (fn) ->
|
|
@emitter.on 'did-add-pane', fn
|
|
|
|
observePanes: (fn) ->
|
|
fn(pane) for pane in @getPanes()
|
|
@onDidAddPane ({pane}) -> fn(pane)
|
|
|
|
onDidDestroyPane: (fn) ->
|
|
@emitter.on 'did-destroy-pane', fn
|
|
|
|
onWillDestroyPane: (fn) ->
|
|
@emitter.on 'will-destroy-pane', fn
|
|
|
|
onDidChangeActivePane: (fn) ->
|
|
@emitter.on 'did-change-active-pane', fn
|
|
|
|
observeActivePane: (fn) ->
|
|
fn(@getActivePane())
|
|
@onDidChangeActivePane(fn)
|
|
|
|
onDidAddPaneItem: (fn) ->
|
|
@emitter.on 'did-add-pane-item', fn
|
|
|
|
observePaneItems: (fn) ->
|
|
fn(item) for item in @getPaneItems()
|
|
@onDidAddPaneItem ({item}) -> fn(item)
|
|
|
|
onDidChangeActivePaneItem: (fn) ->
|
|
@emitter.on 'did-change-active-pane-item', fn
|
|
|
|
onDidStopChangingActivePaneItem: (fn) ->
|
|
@emitter.on 'did-stop-changing-active-pane-item', fn
|
|
|
|
observeActivePaneItem: (fn) ->
|
|
fn(@getActivePaneItem())
|
|
@onDidChangeActivePaneItem(fn)
|
|
|
|
onWillDestroyPaneItem: (fn) ->
|
|
@emitter.on 'will-destroy-pane-item', fn
|
|
|
|
onDidDestroyPaneItem: (fn) ->
|
|
@emitter.on 'did-destroy-pane-item', fn
|
|
|
|
getRoot: -> @root
|
|
|
|
setRoot: (@root) ->
|
|
@root.setParent(this)
|
|
@root.setContainer(this)
|
|
@emitter.emit 'did-change-root', @root
|
|
if not @getActivePane()? and @root instanceof Pane
|
|
@setActivePane(@root)
|
|
|
|
replaceChild: (oldChild, newChild) ->
|
|
throw new Error("Replacing non-existent child") if oldChild isnt @root
|
|
@setRoot(newChild)
|
|
|
|
getPanes: ->
|
|
@getRoot().getPanes()
|
|
|
|
getPaneItems: ->
|
|
@getRoot().getItems()
|
|
|
|
getActivePane: ->
|
|
@activePane
|
|
|
|
setActivePane: (activePane) ->
|
|
if activePane isnt @activePane
|
|
unless activePane in @getPanes()
|
|
throw new Error("Setting active pane that is not present in pane container")
|
|
|
|
@activePane = activePane
|
|
@emitter.emit 'did-change-active-pane', @activePane
|
|
@activePane
|
|
|
|
getActivePaneItem: ->
|
|
@getActivePane().getActiveItem()
|
|
|
|
paneForURI: (uri) ->
|
|
find @getPanes(), (pane) -> pane.itemForURI(uri)?
|
|
|
|
paneForItem: (item) ->
|
|
find @getPanes(), (pane) -> item in pane.getItems()
|
|
|
|
saveAll: ->
|
|
pane.saveItems() for pane in @getPanes()
|
|
return
|
|
|
|
confirmClose: (options) ->
|
|
allSaved = true
|
|
|
|
for pane in @getPanes()
|
|
for item in pane.getItems()
|
|
unless pane.promptToSaveItem(item, options)
|
|
allSaved = false
|
|
break
|
|
|
|
allSaved
|
|
|
|
activateNextPane: ->
|
|
panes = @getPanes()
|
|
if panes.length > 1
|
|
currentIndex = panes.indexOf(@activePane)
|
|
nextIndex = (currentIndex + 1) % panes.length
|
|
panes[nextIndex].activate()
|
|
true
|
|
else
|
|
false
|
|
|
|
activatePreviousPane: ->
|
|
panes = @getPanes()
|
|
if panes.length > 1
|
|
currentIndex = panes.indexOf(@activePane)
|
|
previousIndex = currentIndex - 1
|
|
previousIndex = panes.length - 1 if previousIndex < 0
|
|
panes[previousIndex].activate()
|
|
true
|
|
else
|
|
false
|
|
|
|
destroyEmptyPanes: ->
|
|
pane.destroy() for pane in @getPanes() when pane.items.length is 0
|
|
return
|
|
|
|
willDestroyPaneItem: (event) ->
|
|
@emitter.emit 'will-destroy-pane-item', event
|
|
|
|
didDestroyPaneItem: (event) ->
|
|
@emitter.emit 'did-destroy-pane-item', event
|
|
|
|
didAddPane: (event) ->
|
|
@emitter.emit 'did-add-pane', event
|
|
|
|
willDestroyPane: (event) ->
|
|
@emitter.emit 'will-destroy-pane', event
|
|
|
|
didDestroyPane: (event) ->
|
|
@emitter.emit 'did-destroy-pane', event
|
|
|
|
# Called by Model superclass when destroyed
|
|
destroyed: ->
|
|
@cancelStoppedChangingActivePaneItemTimeout()
|
|
pane.destroy() for pane in @getPanes()
|
|
@subscriptions.dispose()
|
|
@emitter.dispose()
|
|
|
|
cancelStoppedChangingActivePaneItemTimeout: ->
|
|
if @stoppedChangingActivePaneItemTimeout?
|
|
clearTimeout(@stoppedChangingActivePaneItemTimeout)
|
|
|
|
monitorActivePaneItem: ->
|
|
childSubscription = null
|
|
|
|
@subscriptions.add @observeActivePane (activePane) =>
|
|
if childSubscription?
|
|
@subscriptions.remove(childSubscription)
|
|
childSubscription.dispose()
|
|
|
|
childSubscription = activePane.observeActiveItem (activeItem) =>
|
|
@emitter.emit 'did-change-active-pane-item', activeItem
|
|
@cancelStoppedChangingActivePaneItemTimeout()
|
|
stoppedChangingActivePaneItemCallback = =>
|
|
@stoppedChangingActivePaneItemTimeout = null
|
|
@emitter.emit 'did-stop-changing-active-pane-item', activeItem
|
|
@stoppedChangingActivePaneItemTimeout =
|
|
setTimeout(
|
|
stoppedChangingActivePaneItemCallback,
|
|
@stoppedChangingActivePaneItemDelay)
|
|
|
|
@subscriptions.add(childSubscription)
|
|
|
|
monitorPaneItems: ->
|
|
@subscriptions.add @observePanes (pane) =>
|
|
for item, index in pane.getItems()
|
|
@addedPaneItem(item, pane, index)
|
|
|
|
pane.onDidAddItem ({item, index, moved}) =>
|
|
@addedPaneItem(item, pane, index) unless moved
|
|
|
|
pane.onDidRemoveItem ({item, moved}) =>
|
|
@removedPaneItem(item) unless moved
|
|
|
|
addedPaneItem: (item, pane, index) ->
|
|
@itemRegistry.addItem(item)
|
|
@emitter.emit 'did-add-pane-item', {item, pane, index}
|
|
|
|
removedPaneItem: (item) ->
|
|
@itemRegistry.removeItem(item)
|