From 2b9aeb26ff2333106e5c06d90473d7e61589b688 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 6 Mar 2019 16:14:04 +0100 Subject: [PATCH 1/7] wip: scm views --- .../browser/parts/views/viewsViewlet.ts | 2 +- .../contrib/scm/browser/scm.contribution.ts | 10 +- .../contrib/scm/browser/scmViewlet.ts | 826 ++++++++++-------- 3 files changed, 457 insertions(+), 381 deletions(-) diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 804e934a8ce..e9479024182 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -43,7 +43,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView private readonly visibleViewsCountFromCache: number; private readonly visibleViewsStorageId: string; - private readonly viewsModel: PersistentContributableViewsModel; + protected readonly viewsModel: PersistentContributableViewsModel; private viewDisposables: IDisposable[] = []; constructor( diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 9172c0ab736..a380c9fe4e6 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -14,7 +14,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { StatusUpdater, StatusBarController } from './scmActivity'; -import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; +import { SCMViewlet, MainPanel } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -24,6 +24,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { IPartService } from 'vs/workbench/services/part/common/partService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { SCMService } from 'vs/workbench/contrib/scm/common/scmService'; +import { ViewsRegistry, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views'; class OpenSCMViewletAction extends ShowViewletAction { @@ -38,16 +39,15 @@ class OpenSCMViewletAction extends ShowViewletAction { Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(DirtyDiffWorkbenchController, LifecyclePhase.Restored); -const viewletDescriptor = new ViewletDescriptor( +Registry.as(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor( SCMViewlet, VIEWLET_ID, localize('source control', "Source Control"), 'scm', 2 -); +)); -Registry.as(ViewletExtensions.Viewlets) - .registerViewlet(viewletDescriptor); +// ViewsRegistry.registerViews([{ id: MainPanel.ID, name: MainPanel.TITLE, ctor: MainPanel, order: 10, weight: 40, canToggleVisibility: true }], VIEW_CONTAINER); Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 203d662dfb5..f016776f5d5 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -6,15 +6,15 @@ import 'vs/css!./media/scmViewlet'; import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; -import { domEvent, stop } from 'vs/base/browser/event'; +import { domEvent } from 'vs/base/browser/event'; import { basename } from 'vs/base/common/resources'; -import { IDisposable, dispose, combinedDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { PanelViewlet, ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { append, $, addClass, toggleClass, trackFocus, Dimension, addDisposableListener, removeClass } from 'vs/base/browser/dom'; +import { IDisposable, dispose, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; +import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { VIEWLET_ID, VIEW_CONTAINER, ISCMService, ISCMRepository, ISCMResourceGroup, ISCMResource, InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; +import { VIEWLET_ID, ISCMService, ISCMRepository, ISCMResourceGroup, ISCMResource, InputValidationType, VIEW_CONTAINER } from 'vs/workbench/contrib/scm/common/scm'; import { ResourceLabels, IResourceLabel, IResourceLabelsContainer } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -27,7 +27,7 @@ import { MenuItemAction, IMenuService, MenuId, IMenu } from 'vs/platform/actions import { IAction, Action, IActionItem, ActionRunner } from 'vs/base/common/actions'; import { fillInContextMenuActions, ContextAwareMenuItemActionItem, fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { SCMMenus } from './scmMenus'; -import { ActionBar, IActionItemProvider, Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; import { isSCMResource } from './scmUtil'; import { attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; @@ -35,7 +35,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { Command } from 'vs/editor/common/modes'; import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { format } from 'vs/base/common/strings'; import { ISpliceable, ISequence, ISplice } from 'vs/base/common/sequence'; import { firstIndex, equals } from 'vs/base/common/arrays'; @@ -44,10 +43,13 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ThrottledDelayer } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IViewDescriptorRef, PersistentContributableViewsModel, IAddedViewDescriptorRef } from 'vs/workbench/browser/parts/views/views'; -import { IViewDescriptor, IViewsViewlet, IView } from 'vs/workbench/common/views'; -import { IPanelDndController, Panel } from 'vs/base/browser/ui/splitview/panelview'; import * as platform from 'vs/base/common/platform'; +import { ViewContainerViewlet, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { ViewsRegistry, IViewDescriptor } from 'vs/workbench/common/views'; +import { hash } from 'vs/base/common/hash'; +import { ContributableViewsModel } from 'vs/workbench/browser/parts/views/views'; export interface ISpliceEvent { index: number; @@ -57,13 +59,17 @@ export interface ISpliceEvent { export interface IViewModel { readonly repositories: ISCMRepository[]; - readonly selectedRepositories: ISCMRepository[]; readonly onDidSplice: Event>; + readonly selectedRepositories: ISCMRepository[]; + readonly onDidChangeSelectedRepositories: Event; + + setSelection(repositories: ISCMRepository[]): void; + isVisible(): boolean; readonly onDidChangeVisibility: Event; - hide(repository: ISCMRepository): void; + // hide(repository: ISCMRepository): void; } class ProvidersListDelegate implements IListVirtualDelegate { @@ -215,17 +221,19 @@ class ProviderRenderer implements IListRenderer; private visibilityDisposables: IDisposable[] = []; private previousSelection: ISCMRepository[] | undefined = undefined; - private _onSelectionChange = new Emitter(); - readonly onSelectionChange: Event = this._onSelectionChange.event; constructor( protected viewModel: IViewModel, + options: IViewletPanelOptions, @IKeybindingService protected keybindingService: IKeybindingService, @IContextMenuService protected contextMenuService: IContextMenuService, @ISCMService protected scmService: ISCMService, @@ -234,7 +242,7 @@ class MainPanel extends ViewletPanel { @IMenuService private readonly menuService: IMenuService, @IConfigurationService configurationService: IConfigurationService ) { - super({ id: 'scm.mainPanel', title: localize('scm providers', "Source Control Providers") }, keybindingService, contextMenuService, configurationService); + super(options, keybindingService, contextMenuService, configurationService); this.updateBodySize(); } @@ -357,24 +365,25 @@ class MainPanel extends ViewletPanel { this.previousSelection = e.elements; } - this._onSelectionChange.fire(e.elements); + this.viewModel.setSelection(e.elements); + // this._onSelectionChange.fire(e.elements); } private restoreSelection(): void { - let selection: number[] | undefined; + // let selection: number[] | undefined; - if (this.previousSelection) { - selection = this.previousSelection - .map(r => this.viewModel.repositories.indexOf(r)) - .filter(i => i > -1); - } + // if (this.previousSelection) { + // selection = this.previousSelection + // .map(r => this.viewModel.repositories.indexOf(r)) + // .filter(i => i > -1); + // } - if (!selection || selection.length === 0) { - selection = [0]; - } + // if (!selection || selection.length === 0) { + // selection = [0]; + // } - this.list.setSelection(selection); - this.list.setFocus([selection[0]]); + // this.list.setSelection(selection); + // this.list.setFocus([selection[0]]); } dispose(): void { @@ -740,9 +749,9 @@ export class RepositoryPanel extends ViewletPanel { protected contextKeyService: IContextKeyService; constructor( - id: string, readonly repository: ISCMRepository, - private viewModel: IViewModel, + private readonly viewModel: IViewModel, + options: IViewletPanelOptions, @IKeybindingService protected keybindingService: IKeybindingService, @IThemeService protected themeService: IThemeService, @IContextMenuService protected contextMenuService: IContextMenuService, @@ -755,12 +764,13 @@ export class RepositoryPanel extends ViewletPanel { @IContextKeyService contextKeyService: IContextKeyService, @IMenuService protected menuService: IMenuService ) { - super({ id, title: repository.provider.label }, keybindingService, contextMenuService, configurationService); - this.menus = instantiationService.createInstance(SCMMenus, repository.provider); + super(options, keybindingService, contextMenuService, configurationService); + + this.menus = instantiationService.createInstance(SCMMenus, this.repository.provider); this.menus.onDidChangeTitle(this._onDidChangeTitleArea.fire, this._onDidChangeTitleArea, this.disposables); this.contextKeyService = contextKeyService.createScoped(this.element); - this.contextKeyService.createKey('scmRepository', repository); + this.contextKeyService.createKey('scmRepository', this.repository); } render(): void { @@ -783,25 +793,25 @@ export class RepositoryPanel extends ViewletPanel { super.renderHeaderTitle(container, title); addClass(container, 'scm-provider'); append(container, $('span.type', undefined, type)); - const onContextMenu = Event.map(stop(domEvent(container, 'contextmenu')), e => new StandardMouseEvent(e)); - onContextMenu(this.onContextMenu, this, this.disposables); + // const onContextMenu = Event.map(stop(domEvent(container, 'contextmenu')), e => new StandardMouseEvent(e)); + // onContextMenu(this.onContextMenu, this, this.disposables); } - private onContextMenu(event: StandardMouseEvent): void { - if (this.viewModel.selectedRepositories.length <= 1) { - return; - } + // private onContextMenu(event: StandardMouseEvent): void { + // if (this.viewModel.selectedRepositories.length <= 1) { + // return; + // } - this.contextMenuService.showContextMenu({ - getAnchor: () => ({ x: event.posx, y: event.posy }), - getActions: () => [{ - id: `scm.hideRepository`, - label: localize('hideRepository', "Hide"), - enabled: true, - run: () => this.viewModel.hide(this.repository) - }], - }); - } + // this.contextMenuService.showContextMenu({ + // getAnchor: () => ({ x: event.posx, y: event.posy }), + // getActions: () => [{ + // id: `scm.hideRepository`, + // label: localize('hideRepository', "Hide"), + // enabled: true, + // run: () => this.viewModel.hide(this.repository) + // }], + // }); + // } protected renderBody(container: HTMLElement): void { const focusTracker = trackFocus(container); @@ -1032,29 +1042,41 @@ export class RepositoryPanel extends ViewletPanel { } } -class SCMPanelDndController implements IPanelDndController { +// class SCMPanelDndController implements IPanelDndController { - canDrag(panel: Panel): boolean { - return !(panel instanceof MainPanel) && !(panel instanceof RepositoryPanel); - } +// canDrag(panel: Panel): boolean { +// return !(panel instanceof MainPanel) && !(panel instanceof RepositoryPanel); +// } - canDrop(panel: Panel, overPanel: Panel): boolean { - return !(overPanel instanceof MainPanel) && !(overPanel instanceof RepositoryPanel); +// canDrop(panel: Panel, overPanel: Panel): boolean { +// return !(overPanel instanceof MainPanel) && !(overPanel instanceof RepositoryPanel); +// } +// } + +class RepositoryViewDescriptor implements IViewDescriptor { + + readonly ctorDescriptor: { ctor: any, arguments?: any[] }; + readonly canToggleVisibility = true; + + constructor(readonly id: string, readonly name: string, readonly repository: ISCMRepository, viewModel: IViewModel) { + this.ctorDescriptor = { ctor: RepositoryPanel, arguments: [repository, viewModel] }; } } -export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewlet { +export class SCMViewlet extends ViewContainerViewlet implements IViewModel { - private el: HTMLElement; + private static readonly STATE_KEY = 'workbench.scm.views.state'; + + // private el: HTMLElement; private menus: SCMMenus; - private mainPanel: MainPanel | null = null; - private cachedMainPanelHeight: number | undefined; - private mainPanelDisposable: IDisposable = Disposable.None; + // private mainPanel: MainPanel | null = null; + // private cachedMainPanelHeight: number | undefined; + // private mainPanelDisposable: IDisposable = Disposable.None; private _repositories: ISCMRepository[] = []; - private repositoryPanels: RepositoryPanel[] = []; - private singlePanelTitleActionsDisposable: IDisposable = Disposable.None; + // private repositoryPanels: RepositoryPanel[] = []; + // private singlePanelTitleActionsDisposable: IDisposable = Disposable.None; private disposables: IDisposable[] = []; - private lastFocusedRepository: ISCMRepository | undefined; + // private lastFocusedRepository: ISCMRepository | undefined; private _onDidSplice = new Emitter>(); readonly onDidSplice: Event> = this._onDidSplice.event; @@ -1062,11 +1084,40 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle private _height: number | undefined = undefined; get height(): number | undefined { return this._height; } - get repositories(): ISCMRepository[] { return this._repositories; } - get selectedRepositories(): ISCMRepository[] { return this.repositoryPanels.map(p => p.repository); } + get repositories(): ISCMRepository[] { + return this._repositories; + } - private contributedViews: PersistentContributableViewsModel; - private contributedViewDisposables: IDisposable[] = []; + get selectedRepositories(): ISCMRepository[] { + return this.panels.filter(panel => panel instanceof RepositoryPanel) + .map(panel => (panel as RepositoryPanel).repository); + } + + get onDidChangeSelectedRepositories(): Event { + return Event.None; + // return this.onDidAddViews + } + + setSelection(repositories: ISCMRepository[]): void { + const visibleViewDescriptors = this.viewsModel.visibleViewDescriptors; + + const toSetVisible = this.viewsModel.viewDescriptors + .filter(d => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) > -1 && visibleViewDescriptors.indexOf(d) === -1); + + const toSetInvisible = visibleViewDescriptors + .filter(d => d instanceof RepositoryViewDescriptor && repositories.indexOf(d.repository) === -1); + + for (const viewDescriptor of toSetVisible) { + this.viewsModel.setVisible(viewDescriptor.id, true); + } + + for (const viewDescriptor of toSetInvisible) { + this.viewsModel.setVisible(viewDescriptor.id, false); + } + } + + // private contributedViews: PersistentContributableViewsModel; + // private contributedViewDisposables: IDisposable[] = []; constructor( @IPartService partService: IPartService, @@ -1074,65 +1125,94 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle @ISCMService protected scmService: ISCMService, @IInstantiationService protected instantiationService: IInstantiationService, @IContextViewService protected contextViewService: IContextViewService, - @IContextKeyService contextKeyService: IContextKeyService, @IKeybindingService protected keybindingService: IKeybindingService, @INotificationService protected notificationService: INotificationService, @IContextMenuService protected contextMenuService: IContextMenuService, @IThemeService protected themeService: IThemeService, @ICommandService protected commandService: ICommandService, @IStorageService storageService: IStorageService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IExtensionService extensionService: IExtensionService, + @IWorkspaceContextService protected contextService: IWorkspaceContextService, ) { - super(VIEWLET_ID, { showHeaderInTitleWhenSingleView: true, dnd: new SCMPanelDndController() }, configurationService, partService, contextMenuService, telemetryService, themeService, storageService); + super(VIEWLET_ID, SCMViewlet.STATE_KEY, true, configurationService, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); this.menus = instantiationService.createInstance(SCMMenus, undefined); this.menus.onDidChangeTitle(this.updateTitleArea, this, this.disposables); - this.contributedViews = instantiationService.createInstance(PersistentContributableViewsModel, VIEW_CONTAINER, 'scm.views'); - this.disposables.push(this.contributedViews); + ViewsRegistry.registerViews([{ + id: MainPanel.ID, + name: MainPanel.TITLE, + ctorDescriptor: { ctor: MainPanel, arguments: [this] }, + canToggleVisibility: true + }], VIEW_CONTAINER); + + // this.contributedViews = instantiationService.createInstance(PersistentContributableViewsModel, VIEW_CONTAINER, 'scm.views'); + // this.disposables.push(this.contributedViews); } create(parent: HTMLElement): void { super.create(parent); - this.el = parent; - addClass(this.el, 'scm-viewlet'); - addClass(this.el, 'empty'); - append(parent, $('div.empty-message', undefined, localize('no open repo', "No source control providers registered."))); + addClass(parent, 'scm-viewlet'); + + // this.el = parent; + // addClass(this.el, 'scm-viewlet'); + // addClass(this.el, 'empty'); + // append(parent, $('div.empty-message', undefined, localize('no open repo', "No source control providers registered."))); this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables); this.scmService.repositories.forEach(r => this.onDidAddRepository(r)); - const onDidUpdateConfiguration = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowProviders')); - onDidUpdateConfiguration(this.onDidChangeRepositories, this, this.disposables); + // const onDidUpdateConfiguration = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowProviders')); + // onDidUpdateConfiguration(this.onDidChangeRepositories, this, this.disposables); - this.onDidChangeRepositories(); + // this.onDidChangeRepositories(); - this.contributedViews.onDidAdd(this.onDidAddContributedViews, this, this.disposables); - this.contributedViews.onDidRemove(this.onDidRemoveContributedViews, this, this.disposables); + // // this.contributedViews.onDidAdd(this.onDidAddContributedViews, this, this.disposables); + // // this.contributedViews.onDidRemove(this.onDidRemoveContributedViews, this, this.disposables); - let index = this.getContributedViewsStartIndex(); - const contributedViews: IAddedViewDescriptorRef[] = this.contributedViews.visibleViewDescriptors.map(viewDescriptor => { - const size = this.contributedViews.getSize(viewDescriptor.id); - const collapsed = this.contributedViews.isCollapsed(viewDescriptor.id); - return { viewDescriptor, index: index++, size, collapsed }; - }); - if (contributedViews.length) { - this.onDidAddContributedViews(contributedViews); - } + // // let index = this.getContributedViewsStartIndex(); + // // const contributedViews: IAddedViewDescriptorRef[] = this.contributedViews.visibleViewDescriptors.map(viewDescriptor => { + // // const size = this.contributedViews.getSize(viewDescriptor.id); + // // const collapsed = this.contributedViews.isCollapsed(viewDescriptor.id); + // // return { viewDescriptor, index: index++, size, collapsed }; + // // }); + // // if (contributedViews.length) { + // // this.onDidAddContributedViews(contributedViews); + // // } - this.onDidSashChange(this.saveContributedViewSizes, this, this.disposables); + // // this.onDidSashChange(this.saveContributedViewSizes, this, this.disposables); } + private static _repositoryCounter = 0; + private onDidAddRepository(repository: ISCMRepository): void { const index = this._repositories.length; this._repositories.push(repository); this._onDidSplice.fire({ index, deleteCount: 0, elements: [repository] }); - this.onDidChangeRepositories(); + // this.onDidChangeRepositories(); - if (!this.mainPanel) { - this.onSelectionChange(this.repositories); - } + // if (!this.mainPanel) { + // this.onSelectionChange(this.repositories); + // } + + // this.instantiationService.createInstance(RepositoryPanel, , r, this) + + // Find a way to get a decent ID + const repoId = repository.provider.rootUri ? repository.provider.rootUri.toString() : `#${SCMViewlet._repositoryCounter++}`; + const id = `scm:repository:${repository.provider.label}:${repoId}`; + + // if (repository.provider.rootUri) { + // id = `scm.repository.${hash(repository.provider.label)}.${hash(repository.provider.rootUri.toString())}`; + // } else { + // id = `scm.repository.${repository.provider.label}.#${hash(repository.provider.rootUri.toString())}`; + // } + + // const id = `scm.repository.${repository.provider.label}.${SCMViewlet.counter++}`; + const title = repository.provider.rootUri ? basename(repository.provider.rootUri) : repository.provider.label; + + ViewsRegistry.registerViews([new RepositoryViewDescriptor(id, title, repository, this)], VIEW_CONTAINER); } private onDidRemoveRepository(repository: ISCMRepository): void { @@ -1144,77 +1224,73 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle this._repositories.splice(index, 1); this._onDidSplice.fire({ index, deleteCount: 1, elements: [] }); - this.onDidChangeRepositories(); - - if (!this.mainPanel) { - this.onSelectionChange(this.repositories); - } + // this.onDidChangeRepositories(); } - private onDidChangeRepositories(): void { - toggleClass(this.el, 'empty', this.scmService.repositories.length === 0); + // private onDidChangeRepositories(): void { + // toggleClass(this.el, 'empty', this.scmService.repositories.length === 0); - if (this.scmService.repositories.length === 0) { - this.el.tabIndex = 0; - } else { - this.el.removeAttribute('tabIndex'); - } + // if (this.scmService.repositories.length === 0) { + // this.el.tabIndex = 0; + // } else { + // this.el.removeAttribute('tabIndex'); + // } - const shouldMainPanelAlwaysBeVisible = this.configurationService.getValue('scm.alwaysShowProviders'); - const shouldMainPanelBeVisible = shouldMainPanelAlwaysBeVisible || this.scmService.repositories.length > 1; + // const shouldMainPanelAlwaysBeVisible = this.configurationService.getValue('scm.alwaysShowProviders'); + // const shouldMainPanelBeVisible = shouldMainPanelAlwaysBeVisible || this.scmService.repositories.length > 1; - if (!!this.mainPanel === shouldMainPanelBeVisible) { - return; - } + // if (!!this.mainPanel === shouldMainPanelBeVisible) { + // return; + // } - if (shouldMainPanelBeVisible) { - this.mainPanel = this.instantiationService.createInstance(MainPanel, this); - this.mainPanel.render(); - this.addPanels([{ panel: this.mainPanel, size: this.mainPanel.minimumSize, index: 0 }]); + // if (shouldMainPanelBeVisible) { + // this.mainPanel = this.instantiationService.createInstance(MainPanel, this); + // this.mainPanel.render(); + // this.addPanels([{ panel: this.mainPanel, size: this.mainPanel.minimumSize, index: 0 }]); - const selectionChangeDisposable = this.mainPanel.onSelectionChange(this.onSelectionChange, this); - this.onSelectionChange(this.mainPanel.getSelection()); + // const selectionChangeDisposable = this.mainPanel.onSelectionChange(this.onSelectionChange, this); + // this.onSelectionChange(this.mainPanel.getSelection()); - this.mainPanelDisposable = toDisposable(() => { - this.removePanels([this.mainPanel!]); - selectionChangeDisposable.dispose(); - this.mainPanel!.dispose(); - }); - } else { - this.mainPanelDisposable.dispose(); - this.mainPanelDisposable = Disposable.None; - this.mainPanel = null; - } - } + // this.mainPanelDisposable = toDisposable(() => { + // this.removePanels([this.mainPanel!]); + // selectionChangeDisposable.dispose(); + // this.mainPanel!.dispose(); + // }); + // } else { + // this.mainPanelDisposable.dispose(); + // this.mainPanelDisposable = Disposable.None; + // this.mainPanel = null; + // } + // } - private getContributedViewsStartIndex(): number { - return (this.mainPanel ? 1 : 0) + this.repositoryPanels.length; - } + // private getContributedViewsStartIndex(): number { + // return (this.mainPanel ? 1 : 0) + this.repositoryPanels.length; + // } - focus(): void { - if (this.scmService.repositories.length === 0) { - this.el.focus(); - } else { - super.focus(); - } - } + // focus(): void { + // if (this.scmService.repositories.length === 0) { + // this.el.focus(); + // } else { + // super.focus(); + // } + // } - setVisible(visible: boolean): void { - super.setVisible(visible); + // setVisible(visible: boolean): void { + // super.setVisible(visible); - if (!visible) { - this.cachedMainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; - } + // if (!visible) { + // this.cachedMainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; + // } - const start = this.getContributedViewsStartIndex(); + // // const start = this.getContributedViewsStartIndex(); - for (let i = 0; i < this.contributedViews.visibleViewDescriptors.length; i++) { - const panel = this.panels[start + i] as ViewletPanel; - panel.setVisible(visible); - } + // // for (let i = 0; i < this.contributedViews.visibleViewDescriptors.length; i++) { + // // const panel = this.panels[start + i] as ViewletPanel; + // // panel.setVisible(visible); + // // } - this.repositoryPanels.forEach(panel => panel.setVisible(visible)); - } + // this.repositoryPanels.forEach(panel => panel.setVisible(visible)); + // } getOptimalWidth(): number { return 400; @@ -1231,282 +1307,282 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle } } - getActions(): IAction[] { - if (this.isSingleView()) { - return this.panels[0].getActions(); - } + // getActions(): IAction[] { + // if (this.isSingleView()) { + // return this.panels[0].getActions(); + // } - return this.menus.getTitleActions(); - } + // return this.menus.getTitleActions(); + // } - getSecondaryActions(): IAction[] { - if (this.isSingleView()) { - return this.panels[0].getSecondaryActions(); - } else { - return this.menus.getTitleSecondaryActions(); - } - } + // getSecondaryActions(): IAction[] { + // if (this.isSingleView()) { + // return this.panels[0].getSecondaryActions(); + // } else { + // return this.menus.getTitleSecondaryActions(); + // } + // } - getActionItem(action: IAction): IActionItem | null { - if (!(action instanceof MenuItemAction)) { - return null; - } + // getActionItem(action: IAction): IActionItem | null { + // if (!(action instanceof MenuItemAction)) { + // return null; + // } - return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); - } + // return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); + // } - private didLayout = false; - layout(dimension: Dimension): void { - super.layout(dimension); - this._height = dimension.height; + // private didLayout = false; + // layout(dimension: Dimension): void { + // super.layout(dimension); + // this._height = dimension.height; - if (this.didLayout) { - // this.saveViewSizes(); - } else { - this.didLayout = true; - this.restoreContributedViewSizes(); - } - } + // if (this.didLayout) { + // // this.saveViewSizes(); + // } else { + // this.didLayout = true; + // this.restoreContributedViewSizes(); + // } + // } - movePanel(from: ViewletPanel, to: ViewletPanel): void { - const start = this.getContributedViewsStartIndex(); - const fromIndex = firstIndex(this.panels, panel => panel === from) - start; - const toIndex = firstIndex(this.panels, panel => panel === to) - start; - const fromViewDescriptor = this.contributedViews.viewDescriptors[fromIndex]; - const toViewDescriptor = this.contributedViews.viewDescriptors[toIndex]; + // movePanel(from: ViewletPanel, to: ViewletPanel): void { + // const start = this.getContributedViewsStartIndex(); + // const fromIndex = firstIndex(this.panels, panel => panel === from) - start; + // const toIndex = firstIndex(this.panels, panel => panel === to) - start; + // const fromViewDescriptor = this.contributedViews.viewDescriptors[fromIndex]; + // const toViewDescriptor = this.contributedViews.viewDescriptors[toIndex]; - super.movePanel(from, to); - this.contributedViews.move(fromViewDescriptor.id, toViewDescriptor.id); - } + // super.movePanel(from, to); + // this.contributedViews.move(fromViewDescriptor.id, toViewDescriptor.id); + // } - private onSelectionChange(repositories: ISCMRepository[]): void { - const wasSingleView = this.isSingleView(); - const contributableViewsHeight = this.getContributableViewsSize(); + // private onSelectionChange(repositories: ISCMRepository[]): void { + // const wasSingleView = this.isSingleView(); + // // const contributableViewsHeight = this.getContributableViewsSize(); - // Collect unselected panels - const panelsToRemove = this.repositoryPanels - .filter(p => repositories.every(r => p.repository !== r)); + // // Collect unselected panels + // const panelsToRemove = this.repositoryPanels + // .filter(p => repositories.every(r => p.repository !== r)); - // Collect panels still selected - const repositoryPanels = this.repositoryPanels - .filter(p => repositories.some(r => p.repository === r)); + // // Collect panels still selected + // const repositoryPanels = this.repositoryPanels + // .filter(p => repositories.some(r => p.repository === r)); - // Collect new selected panels - const newRepositoryPanels = repositories - .filter(r => this.repositoryPanels.every(p => p.repository !== r)) - .map((r, index) => { - const panel = this.instantiationService.createInstance(RepositoryPanel, `scm.repository.${r.provider.label}.${index}`, r, this); - panel.render(); - panel.setVisible(true); - return panel; - }); + // // Collect new selected panels + // const newRepositoryPanels = repositories + // .filter(r => this.repositoryPanels.every(p => p.repository !== r)) + // .map((r, index) => { + // const panel = this.instantiationService.createInstance(RepositoryPanel, `scm.repository.${r.provider.label}.${index}`, r, this); + // panel.render(); + // panel.setVisible(true); + // return panel; + // }); - // Add new selected panels - let index = repositoryPanels.length + (this.mainPanel ? 1 : 0); - this.repositoryPanels = [...repositoryPanels, ...newRepositoryPanels]; - newRepositoryPanels.forEach(panel => { - this.addPanels([{ panel, size: panel.minimumSize, index: index++ }]); - panel.repository.focus(); - panel.onDidFocus(() => this.lastFocusedRepository = panel.repository); + // // Add new selected panels + // let index = repositoryPanels.length + (this.mainPanel ? 1 : 0); + // this.repositoryPanels = [...repositoryPanels, ...newRepositoryPanels]; + // newRepositoryPanels.forEach(panel => { + // this.addPanels([{ panel, size: panel.minimumSize, index: index++ }]); + // panel.repository.focus(); + // panel.onDidFocus(() => this.lastFocusedRepository = panel.repository); - if (this.lastFocusedRepository === panel.repository) { - panel.focus(); - } - }); + // if (this.lastFocusedRepository === panel.repository) { + // panel.focus(); + // } + // }); - // Remove unselected panels - this.removePanels(panelsToRemove); + // // Remove unselected panels + // this.removePanels(panelsToRemove); - // Restore main panel height - if (this.mainPanel && this.isVisible() && typeof this.cachedMainPanelHeight === 'number') { - this.resizePanel(this.mainPanel, this.cachedMainPanelHeight); - this.cachedMainPanelHeight = undefined; - } + // // Restore main panel height + // if (this.mainPanel && this.isVisible() && typeof this.cachedMainPanelHeight === 'number') { + // this.resizePanel(this.mainPanel, this.cachedMainPanelHeight); + // this.cachedMainPanelHeight = undefined; + // } - // Resize all panels equally - const height = typeof this.height === 'number' ? this.height : 1000; - const mainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; - const size = (height - mainPanelHeight - contributableViewsHeight) / repositories.length; - for (const panel of this.repositoryPanels) { - this.resizePanel(panel, size); - } + // // Resize all panels equally + // const height = typeof this.height === 'number' ? this.height : 1000; + // const mainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; + // const size = (height - mainPanelHeight/* - contributableViewsHeight */) / repositories.length; + // for (const panel of this.repositoryPanels) { + // this.resizePanel(panel, size); + // } - // Resize contributed view sizes - this.restoreContributedViewSizes(); + // // Resize contributed view sizes + // // this.restoreContributedViewSizes(); - // React to menu changes for single view mode - if (wasSingleView !== this.isSingleView()) { - this.singlePanelTitleActionsDisposable.dispose(); + // // React to menu changes for single view mode + // if (wasSingleView !== this.isSingleView()) { + // this.singlePanelTitleActionsDisposable.dispose(); - if (this.isSingleView()) { - this.singlePanelTitleActionsDisposable = this.panels[0].onDidChangeTitleArea(this.updateTitleArea, this); - } + // if (this.isSingleView()) { + // this.singlePanelTitleActionsDisposable = this.panels[0].onDidChangeTitleArea(this.updateTitleArea, this); + // } - this.updateTitleArea(); - } + // this.updateTitleArea(); + // } - if (this.isVisible()) { - panelsToRemove.forEach(p => p.repository.setSelected(false)); - newRepositoryPanels.forEach(p => p.repository.setSelected(true)); - } - } + // if (this.isVisible()) { + // panelsToRemove.forEach(p => p.repository.setSelected(false)); + // newRepositoryPanels.forEach(p => p.repository.setSelected(true)); + // } + // } - private getContributableViewsSize(): number { - let value = 0; + // private getContributableViewsSize(): number { + // let value = 0; - for (let i = this.getContributedViewsStartIndex(); i < this.length; i++) { - value += this.getPanelSize(this.panels[i]); - } + // for (let i = this.getContributedViewsStartIndex(); i < this.length; i++) { + // value += this.getPanelSize(this.panels[i]); + // } - return value; - } + // return value; + // } - onDidAddContributedViews(added: IAddedViewDescriptorRef[]): void { - const start = this.getContributedViewsStartIndex(); - const panelsToAdd: { panel: ViewletPanel, size: number, index: number }[] = []; + // onDidAddContributedViews(added: IAddedViewDescriptorRef[]): void { + // const start = this.getContributedViewsStartIndex(); + // const panelsToAdd: { panel: ViewletPanel, size: number, index: number }[] = []; - for (const { viewDescriptor, collapsed, index, size } of added) { - const panel = this.instantiationService.createInstance(viewDescriptor.ctorDescriptor.ctor, { - id: viewDescriptor.id, - title: viewDescriptor.name, - actionRunner: this.getActionRunner(), - expanded: !collapsed - }) as ViewletPanel; - panel.render(); - panel.setVisible(true); - const contextMenuDisposable = addDisposableListener(panel.draggableElement, 'contextmenu', e => { - e.stopPropagation(); - e.preventDefault(); - this.onViewHeaderContextMenu(new StandardMouseEvent(e), viewDescriptor); - }); + // for (const { viewDescriptor, collapsed, index, size } of added) { + // const panel = this.instantiationService.createInstance(viewDescriptor.ctor, { + // id: viewDescriptor.id, + // title: viewDescriptor.name, + // actionRunner: this.getActionRunner(), + // expanded: !collapsed + // }) as ViewletPanel; + // panel.render(); + // panel.setVisible(true); + // const contextMenuDisposable = addDisposableListener(panel.draggableElement, 'contextmenu', e => { + // e.stopPropagation(); + // e.preventDefault(); + // this.onViewHeaderContextMenu(new StandardMouseEvent(e), viewDescriptor); + // }); - const collapseDisposable = Event.latch(Event.map(panel.onDidChange, () => !panel.isExpanded()))(collapsed => { - this.contributedViews.setCollapsed(viewDescriptor.id, collapsed); - }); + // const collapseDisposable = Event.latch(Event.map(panel.onDidChange, () => !panel.isExpanded()))(collapsed => { + // this.contributedViews.setCollapsed(viewDescriptor.id, collapsed); + // }); - this.contributedViewDisposables.splice(index, 0, combinedDisposable([contextMenuDisposable, collapseDisposable])); - panelsToAdd.push({ panel, size: size || panel.minimumSize, index: start + index }); - } + // this.contributedViewDisposables.splice(index, 0, combinedDisposable([contextMenuDisposable, collapseDisposable])); + // panelsToAdd.push({ panel, size: size || panel.minimumSize, index: start + index }); + // } - this.addPanels(panelsToAdd); - } + // this.addPanels(panelsToAdd); + // } - private onViewHeaderContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void { - const actions: IAction[] = []; - actions.push({ - id: `${viewDescriptor.id}.removeView`, - label: localize('hideView', "Hide"), - enabled: viewDescriptor.canToggleVisibility, - run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) - }); + // private onViewHeaderContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void { + // const actions: IAction[] = []; + // actions.push({ + // id: `${viewDescriptor.id}.removeView`, + // label: localize('hideView', "Hide"), + // enabled: viewDescriptor.canToggleVisibility, + // run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) + // }); - const otherActions = this.getContextMenuActions(); - if (otherActions.length) { - actions.push(...[new Separator(), ...otherActions]); - } + // const otherActions = this.getContextMenuActions(); + // if (otherActions.length) { + // actions.push(...[new Separator(), ...otherActions]); + // } - let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; - this.contextMenuService.showContextMenu({ - getAnchor: () => anchor, - getActions: () => actions - }); - } + // let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; + // this.contextMenuService.showContextMenu({ + // getAnchor: () => anchor, + // getActions: () => actions + // }); + // } - getContextMenuActions(): IAction[] { - const result: IAction[] = []; - const viewToggleActions = this.contributedViews.viewDescriptors.map(viewDescriptor => ({ - id: `${viewDescriptor.id}.toggleVisibility`, - label: viewDescriptor.name, - checked: this.contributedViews.isVisible(viewDescriptor.id), - enabled: viewDescriptor.canToggleVisibility, - run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) - })); + // getContextMenuActions(): IAction[] { + // const result: IAction[] = []; + // const viewToggleActions = this.contributedViews.viewDescriptors.map(viewDescriptor => ({ + // id: `${viewDescriptor.id}.toggleVisibility`, + // label: viewDescriptor.name, + // checked: this.contributedViews.isVisible(viewDescriptor.id), + // enabled: viewDescriptor.canToggleVisibility, + // run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) + // })); - result.push(...viewToggleActions); - const parentActions = super.getContextMenuActions(); - if (viewToggleActions.length && parentActions.length) { - result.push(new Separator()); - } - result.push(...parentActions); - return result; - } + // result.push(...viewToggleActions); + // const parentActions = super.getContextMenuActions(); + // if (viewToggleActions.length && parentActions.length) { + // result.push(new Separator()); + // } + // result.push(...parentActions); + // return result; + // } - onDidRemoveContributedViews(removed: IViewDescriptorRef[]): void { - removed = removed.sort((a, b) => b.index - a.index); - const start = this.getContributedViewsStartIndex(); - const panelsToRemove: ViewletPanel[] = []; + // onDidRemoveContributedViews(removed: IViewDescriptorRef[]): void { + // removed = removed.sort((a, b) => b.index - a.index); + // const start = this.getContributedViewsStartIndex(); + // const panelsToRemove: ViewletPanel[] = []; - for (const { index } of removed) { - const [disposable] = this.contributedViewDisposables.splice(index, 1); - disposable.dispose(); - panelsToRemove.push(this.panels[start + index]); - } + // for (const { index } of removed) { + // const [disposable] = this.contributedViewDisposables.splice(index, 1); + // disposable.dispose(); + // panelsToRemove.push(this.panels[start + index]); + // } - this.removePanels(panelsToRemove); - dispose(panelsToRemove); - } + // this.removePanels(panelsToRemove); + // dispose(panelsToRemove); + // } - private saveContributedViewSizes(): void { - const start = this.getContributedViewsStartIndex(); + // private saveContributedViewSizes(): void { + // const start = this.getContributedViewsStartIndex(); - for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { - const viewDescriptor = this.contributedViews.viewDescriptors[i]; - const size = this.getPanelSize(this.panels[start + i]); + // for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { + // const viewDescriptor = this.contributedViews.viewDescriptors[i]; + // const size = this.getPanelSize(this.panels[start + i]); - this.contributedViews.setSize(viewDescriptor.id, size); - } - } + // this.contributedViews.setSize(viewDescriptor.id, size); + // } + // } - private restoreContributedViewSizes(): void { - if (!this.didLayout) { - return; - } + // private restoreContributedViewSizes(): void { + // if (!this.didLayout) { + // return; + // } - const start = this.getContributedViewsStartIndex(); + // const start = this.getContributedViewsStartIndex(); - for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { - const panel = this.panels[start + i]; - const viewDescriptor = this.contributedViews.viewDescriptors[i]; - const size = this.contributedViews.getSize(viewDescriptor.id); + // for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { + // const panel = this.panels[start + i]; + // const viewDescriptor = this.contributedViews.viewDescriptors[i]; + // const size = this.contributedViews.getSize(viewDescriptor.id); - if (typeof size === 'number') { - this.resizePanel(panel, size); - } - } - } + // if (typeof size === 'number') { + // this.resizePanel(panel, size); + // } + // } + // } - protected isSingleView(): boolean { - return super.isSingleView() && this.repositoryPanels.length + this.contributedViews.visibleViewDescriptors.length === 1; - } + // protected isSingleView(): boolean { + // return super.isSingleView() && this.repositoryPanels.length /* + this.contributedViews.visibleViewDescriptors.length */ === 1; + // } - openView(id: string, focus?: boolean): IView { - if (focus) { - this.focus(); - } - let panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; - if (!panel) { - this.contributedViews.setVisible(id, true); - } - panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; - panel.setExpanded(true); - if (focus) { - panel.focus(); - } - return panel; - } + // openView(id: string, focus?: boolean): IView { + // if (focus) { + // this.focus(); + // } + // let panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; + // if (!panel) { + // // this.contributedViews.setVisible(id, true); + // } + // panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; + // panel.setExpanded(true); + // if (focus) { + // panel.focus(); + // } + // return panel; + // } - hide(repository: ISCMRepository): void { - if (!this.mainPanel) { - return; - } + // hide(repository: ISCMRepository): void { + // if (!this.mainPanel) { + // return; + // } - this.mainPanel.hide(repository); - } + // this.mainPanel.hide(repository); + // } dispose(): void { this.disposables = dispose(this.disposables); - this.contributedViewDisposables = dispose(this.contributedViewDisposables); - this.mainPanelDisposable.dispose(); + // this.contributedViewDisposables = dispose(this.contributedViewDisposables); + // this.mainPanelDisposable.dispose(); super.dispose(); } } From 0955124cd70e06c3d6cb49e95d69fea359784bed Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 08:42:05 +0100 Subject: [PATCH 2/7] dispose menus --- src/vs/workbench/contrib/scm/browser/scmViewlet.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index f016776f5d5..86ca285af35 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -767,6 +767,7 @@ export class RepositoryPanel extends ViewletPanel { super(options, keybindingService, contextMenuService, configurationService); this.menus = instantiationService.createInstance(SCMMenus, this.repository.provider); + this.disposables.push(this.menus); this.menus.onDidChangeTitle(this._onDidChangeTitleArea.fire, this._onDidChangeTitleArea, this.disposables); this.contextKeyService = contextKeyService.createScoped(this.element); From 2f74d3a82d6cb81a65809f7b7d0eb0ef2ecc2964 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 11:01:20 +0100 Subject: [PATCH 3/7] fix panel view layout order --- src/vs/base/browser/ui/splitview/panelview.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index e83b324542d..735c201e8db 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -133,7 +133,6 @@ export abstract class Panel implements IView { this._expanded = !!expanded; this.updateHeader(); - this._onDidChange.fire(expanded ? this.expandedSize : undefined); if (expanded) { if (typeof this.animationTimer === 'number') { @@ -146,6 +145,7 @@ export abstract class Panel implements IView { }, 200); } + this._onDidChange.fire(expanded ? this.expandedSize : undefined); return true; } From 8e5484fec599f3d751570440f69e40d3aaae55a7 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 11:04:03 +0100 Subject: [PATCH 4/7] wip: more SCM views migration --- .../contrib/scm/browser/scm.contribution.ts | 9 +- .../contrib/scm/browser/scmViewlet.ts | 565 +++--------------- 2 files changed, 88 insertions(+), 486 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index a380c9fe4e6..31e4fb3124b 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -14,7 +14,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { StatusUpdater, StatusBarController } from './scmActivity'; -import { SCMViewlet, MainPanel } from 'vs/workbench/contrib/scm/browser/scmViewlet'; +import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -24,7 +24,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { IPartService } from 'vs/workbench/services/part/common/partService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { SCMService } from 'vs/workbench/contrib/scm/common/scmService'; -import { ViewsRegistry, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views'; class OpenSCMViewletAction extends ShowViewletAction { @@ -47,8 +46,6 @@ Registry.as(ViewletExtensions.Viewlets).registerViewlet(new Vie 2 )); -// ViewsRegistry.registerViews([{ id: MainPanel.ID, name: MainPanel.TITLE, ctor: MainPanel, order: 10, weight: 40, canToggleVisibility: true }], VIEW_CONTAINER); - Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); @@ -74,9 +71,7 @@ Registry.as(ConfigurationExtensions.Configuration).regis type: 'object', properties: { 'scm.alwaysShowProviders': { - type: 'boolean', - description: localize('alwaysShowProviders', "Controls whether to always show the Source Control Provider section."), - default: false + deprecationMessage: localize('alwaysShowProviders.deprecated', "This setting is deprecated. You can control the SCM Providers view just like any other view, using the context menu in the SCM view.") }, 'scm.diffDecorations': { type: 'string', diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 86ca285af35..0c7e1f35dc2 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -44,12 +44,10 @@ import { ThrottledDelayer } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import * as platform from 'vs/base/common/platform'; -import { ViewContainerViewlet, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ViewsRegistry, IViewDescriptor } from 'vs/workbench/common/views'; -import { hash } from 'vs/base/common/hash'; -import { ContributableViewsModel } from 'vs/workbench/browser/parts/views/views'; export interface ISpliceEvent { index: number; @@ -61,15 +59,12 @@ export interface IViewModel { readonly repositories: ISCMRepository[]; readonly onDidSplice: Event>; - readonly selectedRepositories: ISCMRepository[]; - readonly onDidChangeSelectedRepositories: Event; - - setSelection(repositories: ISCMRepository[]): void; + readonly visibleRepositories: ISCMRepository[]; + readonly onDidChangeVisibleRepositories: Event; + setVisibleRepositories(repositories: ISCMRepository[]): void; isVisible(): boolean; readonly onDidChangeVisibility: Event; - - // hide(repository: ISCMRepository): void; } class ProvidersListDelegate implements IListVirtualDelegate { @@ -183,13 +178,6 @@ class ProviderRenderer implements IListRenderer this.statusbarService.addEntry({ - // text: c.title, - // tooltip: `${repository.provider.label} - ${c.tooltip}`, - // command: c.id, - // arguments: c.arguments - // }, MainThreadStatusBarAlignment.LEFT, 10000)); - const actions: IAction[] = []; const disposeActions = () => dispose(actions); disposables.push({ dispose: disposeActions }); @@ -229,8 +217,6 @@ export class MainPanel extends ViewletPanel { private list: List; private visibilityDisposables: IDisposable[] = []; - private previousSelection: ISCMRepository[] | undefined = undefined; - constructor( protected viewModel: IViewModel, options: IViewletPanelOptions, @@ -251,22 +237,6 @@ export class MainPanel extends ViewletPanel { this.list.domFocus(); } - hide(repository: ISCMRepository): void { - const selectedElements = this.list.getSelectedElements(); - const index = selectedElements.indexOf(repository); - - if (index === -1) { - return; - } - - const selection = this.list.getSelection(); - this.list.setSelection([...selection.slice(0, index), ...selection.slice(index + 1)]); - } - - getSelection(): ISCMRepository[] { - return this.list.getSelectedElements(); - } - protected renderBody(container: HTMLElement): void { const delegate = new ProvidersListDelegate(); const renderer = this.instantiationService.createInstance(ProviderRenderer); @@ -276,8 +246,11 @@ export class MainPanel extends ViewletPanel { renderer.onDidRenderElement(e => this.list.updateWidth(this.viewModel.repositories.indexOf(e)), null, this.disposables); this.list.onSelectionChange(this.onListSelectionChange, this, this.disposables); + this.list.onFocusChange(this.onListFocusChange, this, this.disposables); this.list.onContextMenu(this.onListContextMenu, this, this.disposables); + this.viewModel.onDidChangeVisibleRepositories(this.updateListSelection, this, this.disposables); + this.viewModel.onDidChangeVisibility(this.onDidChangeVisibility, this, this.disposables); this.onDidChangeVisibility(this.viewModel.isVisible()); @@ -295,15 +268,8 @@ export class MainPanel extends ViewletPanel { } private splice(index: number, deleteCount: number, repositories: ISCMRepository[] = []): void { - const wasEmpty = this.list.length === 0; - this.list.splice(index, deleteCount, repositories); this.updateBodySize(); - - // Automatically select the first one - if (wasEmpty && this.list.length > 0) { - this.restoreSelection(); - } } protected layoutBody(height: number, width: number): void { @@ -311,16 +277,9 @@ export class MainPanel extends ViewletPanel { } private updateBodySize(): void { - const count = this.viewModel.repositories.length; - - if (count <= 5) { - const size = count * 22; - this.minimumBodySize = size; - this.maximumBodySize = size; - } else { - this.minimumBodySize = 5 * 22; - this.maximumBodySize = Number.POSITIVE_INFINITY; - } + const size = Math.min(this.viewModel.repositories.length, 10) * 22; + this.minimumBodySize = size; + this.maximumBodySize = size; } private onListContextMenu(e: IListContextMenuEvent): void { @@ -355,35 +314,37 @@ export class MainPanel extends ViewletPanel { } private onListSelectionChange(e: IListEvent): void { - // select one repository if the selected one is gone - if (e.elements.length === 0 && this.list.length > 0) { - this.restoreSelection(); - return; + if (e.elements.length > 0 && e.browserEvent) { + this.viewModel.setVisibleRepositories(e.elements); } - - if (e.elements.length > 0) { - this.previousSelection = e.elements; - } - - this.viewModel.setSelection(e.elements); - // this._onSelectionChange.fire(e.elements); } - private restoreSelection(): void { - // let selection: number[] | undefined; + private onListFocusChange(e: IListEvent): void { + if (e.elements.length > 0) { + e.elements[0].focus(); + } + } - // if (this.previousSelection) { - // selection = this.previousSelection - // .map(r => this.viewModel.repositories.indexOf(r)) - // .filter(i => i > -1); - // } + private updateListSelection(): void { + const set = new Set(); - // if (!selection || selection.length === 0) { - // selection = [0]; - // } + for (const repository of this.viewModel.visibleRepositories) { + set.add(repository); + } - // this.list.setSelection(selection); - // this.list.setFocus([selection[0]]); + const selection: number[] = []; + + for (let i = 0; i < this.list.length; i++) { + if (set.has(this.list.element(i))) { + selection.push(i); + } + } + + this.list.setSelection(selection); + + if (selection.length > 0) { + this.list.setFocus([selection[0]]); + } } dispose(): void { @@ -962,6 +923,8 @@ export class RepositoryPanel extends ViewletPanel { } else { this.list.domFocus(); } + + this.repository.focus(); } } @@ -1043,23 +1006,20 @@ export class RepositoryPanel extends ViewletPanel { } } -// class SCMPanelDndController implements IPanelDndController { - -// canDrag(panel: Panel): boolean { -// return !(panel instanceof MainPanel) && !(panel instanceof RepositoryPanel); -// } - -// canDrop(panel: Panel, overPanel: Panel): boolean { -// return !(overPanel instanceof MainPanel) && !(overPanel instanceof RepositoryPanel); -// } -// } - class RepositoryViewDescriptor implements IViewDescriptor { + private static counter = 0; + + readonly id: string; + readonly name: string; readonly ctorDescriptor: { ctor: any, arguments?: any[] }; readonly canToggleVisibility = true; - constructor(readonly id: string, readonly name: string, readonly repository: ISCMRepository, viewModel: IViewModel) { + constructor(readonly repository: ISCMRepository, viewModel: IViewModel, readonly hideByDefault: boolean) { + const repoId = repository.provider.rootUri ? repository.provider.rootUri.toString() : `#${RepositoryViewDescriptor.counter++}`; + this.id = `scm:repository:${repository.provider.label}:${repoId}`; + this.name = repository.provider.rootUri ? basename(repository.provider.rootUri) : repository.provider.label; + this.ctorDescriptor = { ctor: RepositoryPanel, arguments: [repository, viewModel] }; } } @@ -1068,16 +1028,9 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { private static readonly STATE_KEY = 'workbench.scm.views.state'; - // private el: HTMLElement; private menus: SCMMenus; - // private mainPanel: MainPanel | null = null; - // private cachedMainPanelHeight: number | undefined; - // private mainPanelDisposable: IDisposable = Disposable.None; private _repositories: ISCMRepository[] = []; - // private repositoryPanels: RepositoryPanel[] = []; - // private singlePanelTitleActionsDisposable: IDisposable = Disposable.None; - private disposables: IDisposable[] = []; - // private lastFocusedRepository: ISCMRepository | undefined; + private viewDescriptors: RepositoryViewDescriptor[] = []; private _onDidSplice = new Emitter>(); readonly onDidSplice: Event> = this._onDidSplice.event; @@ -1089,17 +1042,17 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { return this._repositories; } - get selectedRepositories(): ISCMRepository[] { + get visibleRepositories(): ISCMRepository[] { return this.panels.filter(panel => panel instanceof RepositoryPanel) .map(panel => (panel as RepositoryPanel).repository); } - get onDidChangeSelectedRepositories(): Event { - return Event.None; - // return this.onDidAddViews + get onDidChangeVisibleRepositories(): Event { + const modificationEvent = Event.debounce(Event.any(this.viewsModel.onDidAdd, this.viewsModel.onDidRemove), () => null, 0); + return Event.map(modificationEvent, () => this.visibleRepositories); } - setSelection(repositories: ISCMRepository[]): void { + setVisibleRepositories(repositories: ISCMRepository[]): void { const visibleViewDescriptors = this.viewsModel.visibleViewDescriptors; const toSetVisible = this.viewsModel.viewDescriptors @@ -1139,7 +1092,7 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { super(VIEWLET_ID, SCMViewlet.STATE_KEY, true, configurationService, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); this.menus = instantiationService.createInstance(SCMMenus, undefined); - this.menus.onDidChangeTitle(this.updateTitleArea, this, this.disposables); + this.menus.onDidChangeTitle(this.updateTitleArea, this, this.toDispose); ViewsRegistry.registerViews([{ id: MainPanel.ID, @@ -1147,9 +1100,6 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { ctorDescriptor: { ctor: MainPanel, arguments: [this] }, canToggleVisibility: true }], VIEW_CONTAINER); - - // this.contributedViews = instantiationService.createInstance(PersistentContributableViewsModel, VIEW_CONTAINER, 'scm.views'); - // this.disposables.push(this.contributedViews); } create(parent: HTMLElement): void { @@ -1161,59 +1111,21 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { // addClass(this.el, 'empty'); // append(parent, $('div.empty-message', undefined, localize('no open repo', "No source control providers registered."))); - this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); - this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables); + this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); + this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.toDispose); this.scmService.repositories.forEach(r => this.onDidAddRepository(r)); - - // const onDidUpdateConfiguration = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowProviders')); - // onDidUpdateConfiguration(this.onDidChangeRepositories, this, this.disposables); - - // this.onDidChangeRepositories(); - - // // this.contributedViews.onDidAdd(this.onDidAddContributedViews, this, this.disposables); - // // this.contributedViews.onDidRemove(this.onDidRemoveContributedViews, this, this.disposables); - - // // let index = this.getContributedViewsStartIndex(); - // // const contributedViews: IAddedViewDescriptorRef[] = this.contributedViews.visibleViewDescriptors.map(viewDescriptor => { - // // const size = this.contributedViews.getSize(viewDescriptor.id); - // // const collapsed = this.contributedViews.isCollapsed(viewDescriptor.id); - // // return { viewDescriptor, index: index++, size, collapsed }; - // // }); - // // if (contributedViews.length) { - // // this.onDidAddContributedViews(contributedViews); - // // } - - // // this.onDidSashChange(this.saveContributedViewSizes, this, this.disposables); } - private static _repositoryCounter = 0; - private onDidAddRepository(repository: ISCMRepository): void { const index = this._repositories.length; this._repositories.push(repository); + + const viewDescriptor = new RepositoryViewDescriptor(repository, this, this._repositories.length > 1); + ViewsRegistry.registerViews([viewDescriptor], VIEW_CONTAINER); + this.viewDescriptors.push(viewDescriptor); + this._onDidSplice.fire({ index, deleteCount: 0, elements: [repository] }); - // this.onDidChangeRepositories(); - - // if (!this.mainPanel) { - // this.onSelectionChange(this.repositories); - // } - - // this.instantiationService.createInstance(RepositoryPanel, , r, this) - - // Find a way to get a decent ID - const repoId = repository.provider.rootUri ? repository.provider.rootUri.toString() : `#${SCMViewlet._repositoryCounter++}`; - const id = `scm:repository:${repository.provider.label}:${repoId}`; - - // if (repository.provider.rootUri) { - // id = `scm.repository.${hash(repository.provider.label)}.${hash(repository.provider.rootUri.toString())}`; - // } else { - // id = `scm.repository.${repository.provider.label}.#${hash(repository.provider.rootUri.toString())}`; - // } - - // const id = `scm.repository.${repository.provider.label}.${SCMViewlet.counter++}`; - const title = repository.provider.rootUri ? basename(repository.provider.rootUri) : repository.provider.label; - - ViewsRegistry.registerViews([new RepositoryViewDescriptor(id, title, repository, this)], VIEW_CONTAINER); + this.updateTitleArea(); } private onDidRemoveRepository(repository: ISCMRepository): void { @@ -1223,9 +1135,13 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { return; } + ViewsRegistry.deregisterViews([this.viewDescriptors[index]], VIEW_CONTAINER); + this._repositories.splice(index, 1); + this.viewDescriptors.splice(index, 1); + this._onDidSplice.fire({ index, deleteCount: 1, elements: [] }); - // this.onDidChangeRepositories(); + this.updateTitleArea(); } // private onDidChangeRepositories(): void { @@ -1236,62 +1152,24 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { // } else { // this.el.removeAttribute('tabIndex'); // } - - // const shouldMainPanelAlwaysBeVisible = this.configurationService.getValue('scm.alwaysShowProviders'); - // const shouldMainPanelBeVisible = shouldMainPanelAlwaysBeVisible || this.scmService.repositories.length > 1; - - // if (!!this.mainPanel === shouldMainPanelBeVisible) { - // return; // } - // if (shouldMainPanelBeVisible) { - // this.mainPanel = this.instantiationService.createInstance(MainPanel, this); - // this.mainPanel.render(); - // this.addPanels([{ panel: this.mainPanel, size: this.mainPanel.minimumSize, index: 0 }]); + focus(): void { + const repository = this.visibleRepositories[0]; - // const selectionChangeDisposable = this.mainPanel.onSelectionChange(this.onSelectionChange, this); - // this.onSelectionChange(this.mainPanel.getSelection()); + if (repository) { + const panel = this.panels + .filter(panel => panel instanceof RepositoryPanel && panel.repository === repository)[0] as RepositoryPanel | undefined; - // this.mainPanelDisposable = toDisposable(() => { - // this.removePanels([this.mainPanel!]); - // selectionChangeDisposable.dispose(); - // this.mainPanel!.dispose(); - // }); - // } else { - // this.mainPanelDisposable.dispose(); - // this.mainPanelDisposable = Disposable.None; - // this.mainPanel = null; - // } - // } - - // private getContributedViewsStartIndex(): number { - // return (this.mainPanel ? 1 : 0) + this.repositoryPanels.length; - // } - - // focus(): void { - // if (this.scmService.repositories.length === 0) { - // this.el.focus(); - // } else { - // super.focus(); - // } - // } - - // setVisible(visible: boolean): void { - // super.setVisible(visible); - - // if (!visible) { - // this.cachedMainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; - // } - - // // const start = this.getContributedViewsStartIndex(); - - // // for (let i = 0; i < this.contributedViews.visibleViewDescriptors.length; i++) { - // // const panel = this.panels[start + i] as ViewletPanel; - // // panel.setVisible(visible); - // // } - - // this.repositoryPanels.forEach(panel => panel.setVisible(visible)); - // } + if (panel) { + panel.focus(); + } else { + super.focus(); + } + } else { + super.focus(); + } + } getOptimalWidth(): number { return 400; @@ -1300,7 +1178,7 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { getTitle(): string { const title = localize('source control', "Source Control"); - if (this.repositories.length === 1) { + if (this.visibleRepositories.length === 1) { const [repository] = this.repositories; return localize('viewletTitle', "{0}: {1}", title, repository.provider.label); } else { @@ -1308,282 +1186,11 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { } } - // getActions(): IAction[] { - // if (this.isSingleView()) { - // return this.panels[0].getActions(); - // } + getActionItem(action: IAction): IActionItem | null { + if (!(action instanceof MenuItemAction)) { + return null; + } - // return this.menus.getTitleActions(); - // } - - // getSecondaryActions(): IAction[] { - // if (this.isSingleView()) { - // return this.panels[0].getSecondaryActions(); - // } else { - // return this.menus.getTitleSecondaryActions(); - // } - // } - - // getActionItem(action: IAction): IActionItem | null { - // if (!(action instanceof MenuItemAction)) { - // return null; - // } - - // return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); - // } - - // private didLayout = false; - // layout(dimension: Dimension): void { - // super.layout(dimension); - // this._height = dimension.height; - - // if (this.didLayout) { - // // this.saveViewSizes(); - // } else { - // this.didLayout = true; - // this.restoreContributedViewSizes(); - // } - // } - - // movePanel(from: ViewletPanel, to: ViewletPanel): void { - // const start = this.getContributedViewsStartIndex(); - // const fromIndex = firstIndex(this.panels, panel => panel === from) - start; - // const toIndex = firstIndex(this.panels, panel => panel === to) - start; - // const fromViewDescriptor = this.contributedViews.viewDescriptors[fromIndex]; - // const toViewDescriptor = this.contributedViews.viewDescriptors[toIndex]; - - // super.movePanel(from, to); - // this.contributedViews.move(fromViewDescriptor.id, toViewDescriptor.id); - // } - - // private onSelectionChange(repositories: ISCMRepository[]): void { - // const wasSingleView = this.isSingleView(); - // // const contributableViewsHeight = this.getContributableViewsSize(); - - // // Collect unselected panels - // const panelsToRemove = this.repositoryPanels - // .filter(p => repositories.every(r => p.repository !== r)); - - // // Collect panels still selected - // const repositoryPanels = this.repositoryPanels - // .filter(p => repositories.some(r => p.repository === r)); - - // // Collect new selected panels - // const newRepositoryPanels = repositories - // .filter(r => this.repositoryPanels.every(p => p.repository !== r)) - // .map((r, index) => { - // const panel = this.instantiationService.createInstance(RepositoryPanel, `scm.repository.${r.provider.label}.${index}`, r, this); - // panel.render(); - // panel.setVisible(true); - // return panel; - // }); - - // // Add new selected panels - // let index = repositoryPanels.length + (this.mainPanel ? 1 : 0); - // this.repositoryPanels = [...repositoryPanels, ...newRepositoryPanels]; - // newRepositoryPanels.forEach(panel => { - // this.addPanels([{ panel, size: panel.minimumSize, index: index++ }]); - // panel.repository.focus(); - // panel.onDidFocus(() => this.lastFocusedRepository = panel.repository); - - // if (this.lastFocusedRepository === panel.repository) { - // panel.focus(); - // } - // }); - - // // Remove unselected panels - // this.removePanels(panelsToRemove); - - // // Restore main panel height - // if (this.mainPanel && this.isVisible() && typeof this.cachedMainPanelHeight === 'number') { - // this.resizePanel(this.mainPanel, this.cachedMainPanelHeight); - // this.cachedMainPanelHeight = undefined; - // } - - // // Resize all panels equally - // const height = typeof this.height === 'number' ? this.height : 1000; - // const mainPanelHeight = this.mainPanel ? this.getPanelSize(this.mainPanel) : 0; - // const size = (height - mainPanelHeight/* - contributableViewsHeight */) / repositories.length; - // for (const panel of this.repositoryPanels) { - // this.resizePanel(panel, size); - // } - - // // Resize contributed view sizes - // // this.restoreContributedViewSizes(); - - // // React to menu changes for single view mode - // if (wasSingleView !== this.isSingleView()) { - // this.singlePanelTitleActionsDisposable.dispose(); - - // if (this.isSingleView()) { - // this.singlePanelTitleActionsDisposable = this.panels[0].onDidChangeTitleArea(this.updateTitleArea, this); - // } - - // this.updateTitleArea(); - // } - - // if (this.isVisible()) { - // panelsToRemove.forEach(p => p.repository.setSelected(false)); - // newRepositoryPanels.forEach(p => p.repository.setSelected(true)); - // } - // } - - // private getContributableViewsSize(): number { - // let value = 0; - - // for (let i = this.getContributedViewsStartIndex(); i < this.length; i++) { - // value += this.getPanelSize(this.panels[i]); - // } - - // return value; - // } - - // onDidAddContributedViews(added: IAddedViewDescriptorRef[]): void { - // const start = this.getContributedViewsStartIndex(); - // const panelsToAdd: { panel: ViewletPanel, size: number, index: number }[] = []; - - // for (const { viewDescriptor, collapsed, index, size } of added) { - // const panel = this.instantiationService.createInstance(viewDescriptor.ctor, { - // id: viewDescriptor.id, - // title: viewDescriptor.name, - // actionRunner: this.getActionRunner(), - // expanded: !collapsed - // }) as ViewletPanel; - // panel.render(); - // panel.setVisible(true); - // const contextMenuDisposable = addDisposableListener(panel.draggableElement, 'contextmenu', e => { - // e.stopPropagation(); - // e.preventDefault(); - // this.onViewHeaderContextMenu(new StandardMouseEvent(e), viewDescriptor); - // }); - - // const collapseDisposable = Event.latch(Event.map(panel.onDidChange, () => !panel.isExpanded()))(collapsed => { - // this.contributedViews.setCollapsed(viewDescriptor.id, collapsed); - // }); - - // this.contributedViewDisposables.splice(index, 0, combinedDisposable([contextMenuDisposable, collapseDisposable])); - // panelsToAdd.push({ panel, size: size || panel.minimumSize, index: start + index }); - // } - - // this.addPanels(panelsToAdd); - // } - - // private onViewHeaderContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void { - // const actions: IAction[] = []; - // actions.push({ - // id: `${viewDescriptor.id}.removeView`, - // label: localize('hideView', "Hide"), - // enabled: viewDescriptor.canToggleVisibility, - // run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) - // }); - - // const otherActions = this.getContextMenuActions(); - // if (otherActions.length) { - // actions.push(...[new Separator(), ...otherActions]); - // } - - // let anchor: { x: number, y: number } = { x: event.posx, y: event.posy }; - // this.contextMenuService.showContextMenu({ - // getAnchor: () => anchor, - // getActions: () => actions - // }); - // } - - // getContextMenuActions(): IAction[] { - // const result: IAction[] = []; - // const viewToggleActions = this.contributedViews.viewDescriptors.map(viewDescriptor => ({ - // id: `${viewDescriptor.id}.toggleVisibility`, - // label: viewDescriptor.name, - // checked: this.contributedViews.isVisible(viewDescriptor.id), - // enabled: viewDescriptor.canToggleVisibility, - // run: () => this.contributedViews.setVisible(viewDescriptor.id, !this.contributedViews.isVisible(viewDescriptor.id)) - // })); - - // result.push(...viewToggleActions); - // const parentActions = super.getContextMenuActions(); - // if (viewToggleActions.length && parentActions.length) { - // result.push(new Separator()); - // } - // result.push(...parentActions); - // return result; - // } - - // onDidRemoveContributedViews(removed: IViewDescriptorRef[]): void { - // removed = removed.sort((a, b) => b.index - a.index); - // const start = this.getContributedViewsStartIndex(); - // const panelsToRemove: ViewletPanel[] = []; - - // for (const { index } of removed) { - // const [disposable] = this.contributedViewDisposables.splice(index, 1); - // disposable.dispose(); - // panelsToRemove.push(this.panels[start + index]); - // } - - // this.removePanels(panelsToRemove); - // dispose(panelsToRemove); - // } - - // private saveContributedViewSizes(): void { - // const start = this.getContributedViewsStartIndex(); - - // for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { - // const viewDescriptor = this.contributedViews.viewDescriptors[i]; - // const size = this.getPanelSize(this.panels[start + i]); - - // this.contributedViews.setSize(viewDescriptor.id, size); - // } - // } - - // private restoreContributedViewSizes(): void { - // if (!this.didLayout) { - // return; - // } - - // const start = this.getContributedViewsStartIndex(); - - // for (let i = 0; i < this.contributedViews.viewDescriptors.length; i++) { - // const panel = this.panels[start + i]; - // const viewDescriptor = this.contributedViews.viewDescriptors[i]; - // const size = this.contributedViews.getSize(viewDescriptor.id); - - // if (typeof size === 'number') { - // this.resizePanel(panel, size); - // } - // } - // } - - // protected isSingleView(): boolean { - // return super.isSingleView() && this.repositoryPanels.length /* + this.contributedViews.visibleViewDescriptors.length */ === 1; - // } - - // openView(id: string, focus?: boolean): IView { - // if (focus) { - // this.focus(); - // } - // let panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; - // if (!panel) { - // // this.contributedViews.setVisible(id, true); - // } - // panel = this.panels.filter(panel => panel instanceof ViewletPanel && panel.id === id)[0]; - // panel.setExpanded(true); - // if (focus) { - // panel.focus(); - // } - // return panel; - // } - - // hide(repository: ISCMRepository): void { - // if (!this.mainPanel) { - // return; - // } - - // this.mainPanel.hide(repository); - // } - - dispose(): void { - this.disposables = dispose(this.disposables); - // this.contributedViewDisposables = dispose(this.contributedViewDisposables); - // this.mainPanelDisposable.dispose(); - super.dispose(); + return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } } From b36a855c6acc4a7086d3270ecf842707626c7e4d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 15:49:54 +0100 Subject: [PATCH 5/7] wip: scm using contributable views --- .../contrib/scm/browser/media/scmViewlet.css | 2 + .../contrib/scm/browser/scm.contribution.ts | 4 +- .../contrib/scm/browser/scmViewlet.ts | 134 +++++++++++------- 3 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css index 848ee89aee3..b2427cf10ad 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css @@ -13,6 +13,8 @@ } .scm-viewlet .empty-message { + box-sizing: border-box; + height: 100%; padding: 10px 22px 0 22px; } diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index 31e4fb3124b..ca5316dc066 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -71,7 +71,9 @@ Registry.as(ConfigurationExtensions.Configuration).regis type: 'object', properties: { 'scm.alwaysShowProviders': { - deprecationMessage: localize('alwaysShowProviders.deprecated', "This setting is deprecated. You can control the SCM Providers view just like any other view, using the context menu in the SCM view.") + type: 'boolean', + description: localize('alwaysShowProviders', "Controls whether to always show the Source Control Provider section."), + default: false }, 'scm.diffDecorations': { type: 'string', diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 0c7e1f35dc2..7e6ad0c7f25 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -10,7 +10,7 @@ import { domEvent } from 'vs/base/browser/event'; import { basename } from 'vs/base/common/resources'; import { IDisposable, dispose, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; +import { append, $, addClass, toggleClass, trackFocus, removeClass, addClasses } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListContextMenuEvent, IListEvent, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list'; @@ -215,7 +215,6 @@ export class MainPanel extends ViewletPanel { static readonly TITLE = localize('scm providers', "Source Control Providers"); private list: List; - private visibilityDisposables: IDisposable[] = []; constructor( protected viewModel: IViewModel, @@ -232,11 +231,6 @@ export class MainPanel extends ViewletPanel { this.updateBodySize(); } - focus(): void { - super.focus(); - this.list.domFocus(); - } - protected renderBody(container: HTMLElement): void { const delegate = new ProvidersListDelegate(); const renderer = this.instantiationService.createInstance(ProviderRenderer); @@ -251,25 +245,23 @@ export class MainPanel extends ViewletPanel { this.viewModel.onDidChangeVisibleRepositories(this.updateListSelection, this, this.disposables); - this.viewModel.onDidChangeVisibility(this.onDidChangeVisibility, this, this.disposables); - this.onDidChangeVisibility(this.viewModel.isVisible()); + this.viewModel.onDidSplice(({ index, deleteCount, elements }) => this.splice(index, deleteCount, elements), null, this.disposables); + this.splice(0, 0, this.viewModel.repositories); this.disposables.push(this.list); - } - private onDidChangeVisibility(visible: boolean): void { - if (visible) { - this.viewModel.onDidSplice(({ index, deleteCount, elements }) => this.splice(index, deleteCount, elements), null, this.visibilityDisposables); - this.splice(0, 0, this.viewModel.repositories); - } else { - this.visibilityDisposables = dispose(this.visibilityDisposables); - this.splice(0, this.list.length); - } + this.updateListSelection(); } private splice(index: number, deleteCount: number, repositories: ISCMRepository[] = []): void { this.list.splice(index, deleteCount, repositories); - this.updateBodySize(); + + const empty = this.list.length === 0; + const size = Math.min(this.viewModel.repositories.length, 10) * 22; + this.minimumBodySize = size; + this.maximumBodySize = empty ? Number.POSITIVE_INFINITY : size; + + toggleClass(this.element, 'empty', empty); } protected layoutBody(height: number, width: number): void { @@ -277,9 +269,6 @@ export class MainPanel extends ViewletPanel { } private updateBodySize(): void { - const size = Math.min(this.viewModel.repositories.length, 10) * 22; - this.minimumBodySize = size; - this.maximumBodySize = size; } private onListContextMenu(e: IListContextMenuEvent): void { @@ -346,11 +335,6 @@ export class MainPanel extends ViewletPanel { this.list.setFocus([selection[0]]); } } - - dispose(): void { - this.visibilityDisposables = dispose(this.visibilityDisposables); - super.dispose(); - } } interface ResourceGroupTemplate { @@ -1024,12 +1008,30 @@ class RepositoryViewDescriptor implements IViewDescriptor { } } +class MainPanelDescriptor implements IViewDescriptor { + + readonly id = MainPanel.ID; + readonly name = MainPanel.TITLE; + readonly ctorDescriptor: { ctor: any, arguments?: any[] }; + readonly canToggleVisibility = true; + readonly hideByDefault = true; + + constructor(viewModel: IViewModel) { + this.ctorDescriptor = { ctor: MainPanel, arguments: [viewModel] }; + } +} + export class SCMViewlet extends ViewContainerViewlet implements IViewModel { private static readonly STATE_KEY = 'workbench.scm.views.state'; + private repositoryCount = 0; + private el: HTMLElement; + private message: HTMLElement; private menus: SCMMenus; private _repositories: ISCMRepository[] = []; + + private mainPanelDescriptor = new MainPanelDescriptor(this); private viewDescriptors: RepositoryViewDescriptor[] = []; private _onDidSplice = new Emitter>(); @@ -1094,22 +1096,21 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { this.menus = instantiationService.createInstance(SCMMenus, undefined); this.menus.onDidChangeTitle(this.updateTitleArea, this, this.toDispose); - ViewsRegistry.registerViews([{ - id: MainPanel.ID, - name: MainPanel.TITLE, - ctorDescriptor: { ctor: MainPanel, arguments: [this] }, - canToggleVisibility: true - }], VIEW_CONTAINER); + this.message = $('.empty-message', { tabIndex: 0 }, localize('no open repo', "No source control providers registered.")); + + configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('scm.alwaysShowProviders')) { + this.onDidChangeRepositories(); + } + }); } create(parent: HTMLElement): void { super.create(parent); - addClass(parent, 'scm-viewlet'); - // this.el = parent; - // addClass(this.el, 'scm-viewlet'); - // addClass(this.el, 'empty'); - // append(parent, $('div.empty-message', undefined, localize('no open repo', "No source control providers registered."))); + this.el = parent; + addClasses(parent, 'scm-viewlet', 'empty'); + append(parent, this.message); this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.toDispose); @@ -1120,12 +1121,14 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { const index = this._repositories.length; this._repositories.push(repository); - const viewDescriptor = new RepositoryViewDescriptor(repository, this, this._repositories.length > 1); + const viewDescriptor = new RepositoryViewDescriptor(repository, this, false); ViewsRegistry.registerViews([viewDescriptor], VIEW_CONTAINER); this.viewDescriptors.push(viewDescriptor); this._onDidSplice.fire({ index, deleteCount: 0, elements: [repository] }); this.updateTitleArea(); + + this.onDidChangeRepositories(); } private onDidRemoveRepository(repository: ISCMRepository): void { @@ -1142,32 +1145,53 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { this._onDidSplice.fire({ index, deleteCount: 1, elements: [] }); this.updateTitleArea(); + + this.onDidChangeRepositories(); } - // private onDidChangeRepositories(): void { - // toggleClass(this.el, 'empty', this.scmService.repositories.length === 0); + private onDidChangeRepositories(): void { + const repositoryCount = this.repositories.length; - // if (this.scmService.repositories.length === 0) { - // this.el.tabIndex = 0; - // } else { - // this.el.removeAttribute('tabIndex'); - // } - // } + if (this.repositoryCount === 0 && repositoryCount !== 0) { + ViewsRegistry.registerViews([this.mainPanelDescriptor], VIEW_CONTAINER); + } else if (this.repositoryCount !== 0 && repositoryCount === 0) { + ViewsRegistry.deregisterViews([this.mainPanelDescriptor], VIEW_CONTAINER); + } + + const alwaysShowProviders = this.configurationService.getValue('scm.alwaysShowProviders') || false; + + if (alwaysShowProviders && repositoryCount > 0) { + this.viewsModel.setVisible(MainPanel.ID, true); + } else if (!alwaysShowProviders && repositoryCount === 1) { + this.viewsModel.setVisible(MainPanel.ID, false); + } else if (this.repositoryCount < 2 && repositoryCount >= 2) { + this.viewsModel.setVisible(MainPanel.ID, true); + } else if (this.repositoryCount >= 2 && repositoryCount === 1) { + this.viewsModel.setVisible(MainPanel.ID, false); + } + + toggleClass(this.el, 'empty', repositoryCount === 0); + this.repositoryCount = repositoryCount; + } focus(): void { - const repository = this.visibleRepositories[0]; + if (this.repositoryCount) { + this.message.focus(); + } else { + const repository = this.visibleRepositories[0]; - if (repository) { - const panel = this.panels - .filter(panel => panel instanceof RepositoryPanel && panel.repository === repository)[0] as RepositoryPanel | undefined; + if (repository) { + const panel = this.panels + .filter(panel => panel instanceof RepositoryPanel && panel.repository === repository)[0] as RepositoryPanel | undefined; - if (panel) { - panel.focus(); + if (panel) { + panel.focus(); + } else { + super.focus(); + } } else { super.focus(); } - } else { - super.focus(); } } From aec580615088e163e1e1d2e66aae08a5b48ddae8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 16:01:33 +0100 Subject: [PATCH 6/7] scm: fix actions context --- src/vs/workbench/browser/composite.ts | 7 +++++++ src/vs/workbench/browser/parts/compositePart.ts | 13 +++++++++++++ src/vs/workbench/contrib/scm/browser/scmViewlet.ts | 9 ++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index 4fc60b1cc1d..482d47ce222 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -173,6 +173,13 @@ export abstract class Composite extends Component implements IComposite { return null; } + /** + * Provide a context to be passed to the toolbar. + */ + getActionsContext(): any { + return null; + } + /** * Returns the instance of IActionRunner to use with this composite for the * composite tool bar. diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index a9a2883e398..a5bd326a1e7 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -342,6 +342,9 @@ export abstract class CompositePart extends Part { primaryActions.push(...this.getActions()); secondaryActions.push(...this.getSecondaryActions()); + // Update context + this.toolBar.context = this.actionsContextProvider(); + // Return fn to set into toolbar return this.toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions)); } @@ -438,6 +441,16 @@ export abstract class CompositePart extends Part { return null; } + protected actionsContextProvider(): any { + + // Check Active Composite + if (this.activeComposite) { + return this.activeComposite.getActionsContext(); + } + + return null; + } + createContentArea(parent: HTMLElement): HTMLElement { const contentContainer = append(parent, $('.content')); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 7e6ad0c7f25..3e6e7a22e81 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -1072,9 +1072,6 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { } } - // private contributedViews: PersistentContributableViewsModel; - // private contributedViewDisposables: IDisposable[] = []; - constructor( @IPartService partService: IPartService, @ITelemetryService telemetryService: ITelemetryService, @@ -1217,4 +1214,10 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { return new ContextAwareMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService); } + + getActionsContext(): any { + if (this.visibleRepositories.length === 1) { + return this.repositories[0].provider; + } + } } From ae185fc6cef6c747ccd4fe8cf303fb65f556dcfd Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 7 Mar 2019 16:20:59 +0100 Subject: [PATCH 7/7] fix order for default scm views --- src/vs/workbench/contrib/scm/browser/scmViewlet.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 3e6e7a22e81..4d53b1429a0 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -998,6 +998,7 @@ class RepositoryViewDescriptor implements IViewDescriptor { readonly name: string; readonly ctorDescriptor: { ctor: any, arguments?: any[] }; readonly canToggleVisibility = true; + readonly order = -500; constructor(readonly repository: ISCMRepository, viewModel: IViewModel, readonly hideByDefault: boolean) { const repoId = repository.provider.rootUri ? repository.provider.rootUri.toString() : `#${RepositoryViewDescriptor.counter++}`; @@ -1015,6 +1016,7 @@ class MainPanelDescriptor implements IViewDescriptor { readonly ctorDescriptor: { ctor: any, arguments?: any[] }; readonly canToggleVisibility = true; readonly hideByDefault = true; + readonly order = -1000; constructor(viewModel: IViewModel) { this.ctorDescriptor = { ctor: MainPanel, arguments: [viewModel] };