Merge from vscode e5834d3280fcd04898efeac32b9cf1b893f9b127 (#9385)

* Merge from vscode e5834d3280fcd04898efeac32b9cf1b893f9b127

* distro
This commit is contained in:
Anthony Dresser
2020-02-28 00:37:06 -08:00
committed by GitHub
parent 70851716f7
commit 5d13ebf0d2
143 changed files with 1711 additions and 934 deletions

View File

@@ -25,9 +25,10 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IViewDescriptorService, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewsService, FocusedViewContext, ViewContainerLocation } from 'vs/workbench/common/views';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchExtensions.WorkbenchActions);
const viewCategory = nls.localize('view', "View");
@@ -534,6 +535,7 @@ export class MoveFocusedViewAction extends Action {
@IQuickInputService private quickInputService: IQuickInputService,
@IContextKeyService private contextKeyService: IContextKeyService,
@INotificationService private notificationService: INotificationService,
@IActivityBarService private activityBarService: IActivityBarService,
@IViewletService private viewletService: IViewletService
) {
super(id, label);
@@ -542,58 +544,64 @@ export class MoveFocusedViewAction extends Action {
run(): Promise<void> {
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const focusedView = FocusedViewContext.getValue(this.contextKeyService);
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
if (focusedView === undefined || focusedView.trim() === '') {
if (focusedViewId === undefined || focusedViewId.trim() === '') {
this.notificationService.error(nls.localize('moveFocusedView.error.noFocusedView', "There is no view currently focused."));
return Promise.resolve();
}
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedView);
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(focusedViewId);
if (!viewDescriptor || !viewDescriptor.canMoveView) {
this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable {0}.", focusedView));
this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable."));
return Promise.resolve();
}
const quickPick = this.quickInputService.createQuickPick();
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a destination area for the view...");
quickPick.autoFocusOnList = true;
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View");
quickPick.items = [
{
id: 'sidebar',
label: nls.localize('sidebar', "Sidebar")
},
{
id: 'panel',
const pinnedViewlets = this.activityBarService.getPinnedViewletIds();
const items: Array<IQuickPickItem | IQuickPickSeparator> = this.viewletService.getViewlets()
.filter(viewlet => {
if (viewlet.id === this.viewDescriptorService.getViewContainer(focusedViewId)!.id) {
return false;
}
return !viewContainerRegistry.get(viewlet.id)!.rejectAddedViews && pinnedViewlets.indexOf(viewlet.id) !== -1;
})
.map(viewlet => {
return {
id: viewlet.id,
label: viewlet.name,
};
});
if (this.viewDescriptorService.getViewLocation(focusedViewId) !== ViewContainerLocation.Panel) {
items.unshift({
type: 'separator',
label: nls.localize('sidebar', "Side Bar")
});
items.push({
type: 'separator',
label: nls.localize('panel', "Panel")
}
];
});
items.push({
id: '_.panel.newcontainer',
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
});
}
quickPick.items = items;
quickPick.onDidAccept(() => {
const destination = quickPick.selectedItems[0];
if (destination.id === 'panel') {
quickPick.hide();
if (destination.id === '_.panel.newcontainer') {
this.viewDescriptorService.moveViewToLocation(viewDescriptor!, ViewContainerLocation.Panel);
this.viewsService.openView(focusedView, true);
return;
} else if (destination.id === 'sidebar') {
quickPick.placeholder = nls.localize('moveFocusedView.selectDestinationContainer', "Select a destination view group...");
quickPick.items = this.viewletService.getViewlets().map(viewlet => {
return {
id: viewlet.id,
label: viewlet.name
};
});
return;
this.viewsService.openView(focusedViewId, true);
} else if (destination.id) {
quickPick.hide();
this.viewDescriptorService.moveViewsToContainer([viewDescriptor], viewContainerRegistry.get(destination.id)!);
this.viewsService.openView(focusedView, true);
return;
this.viewsService.openView(focusedViewId, true);
}
quickPick.hide();
@@ -605,7 +613,7 @@ export class MoveFocusedViewAction extends Action {
}
}
registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL), 'View: Move Focused View', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL), 'View: Move Focused View', viewCategory, FocusedViewContext.notEqualsTo(''));
// --- Resize View

View File

@@ -27,6 +27,10 @@
margin-bottom: auto;
}
.monaco-workbench .activitybar > .content > .composite-bar-excess {
height: 100%;
}
.monaco-workbench .activitybar .menubar {
width: 100%;
height: 35px;

View File

@@ -17,13 +17,14 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Widget } from 'vs/base/browser/ui/widget';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
import { ITheme } from 'vs/platform/theme/common/themeService';
import { LocalSelectionTransfer, DragAndDropObserver } from 'vs/workbench/browser/dnd';
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { Emitter } from 'vs/base/common/event';
import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
import { ICompositeDragAndDrop, CompositeDragAndDropData } from 'vs/base/parts/composite/browser/compositeDnd';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
export interface ICompositeBarItem {
id: string;
@@ -38,7 +39,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
constructor(
private viewDescriptorService: IViewDescriptorService,
private targetContainerLocation: ViewContainerLocation,
private openComposite: (id: string, focus?: boolean) => void,
private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | undefined>,
private moveComposite: (from: string, to: string) => void,
private getVisibleCompositeIds: () => string[]
) { }
@@ -52,9 +53,14 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
if (targetCompositeId) {
if (currentLocation !== this.targetContainerLocation && this.targetContainerLocation !== ViewContainerLocation.Panel) {
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
if (destinationContainer) {
this.viewDescriptorService.moveViewsToContainer(this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView), destinationContainer);
this.openComposite(targetCompositeId, true);
if (destinationContainer && !destinationContainer.rejectAddedViews) {
const viewsToMove = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.filter(vd => vd.canMoveView);
this.viewDescriptorService.moveViewsToContainer(viewsToMove, destinationContainer);
this.openComposite(targetCompositeId, true).then(composite => {
if (composite && viewsToMove.length === 1) {
composite.openView(viewsToMove[0].id, true);
}
});
}
} else {
this.moveComposite(dragData.id, targetCompositeId);
@@ -73,10 +79,14 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
if (viewDescriptor && viewDescriptor.canMoveView) {
if (targetCompositeId) {
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
if (destinationContainer) {
if (destinationContainer && !destinationContainer.rejectAddedViews) {
if (this.targetContainerLocation === ViewContainerLocation.Sidebar) {
this.viewDescriptorService.moveViewsToContainer([viewDescriptor], destinationContainer);
this.openComposite(targetCompositeId, true);
this.openComposite(targetCompositeId, true).then(composite => {
if (composite) {
composite.openView(viewDescriptor.id, true);
}
});
} else {
this.viewDescriptorService.moveViewToLocation(viewDescriptor, this.targetContainerLocation);
this.moveComposite(this.viewDescriptorService.getViewContainer(viewDescriptor.id)!.id, targetCompositeId);
@@ -91,13 +101,25 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
this.moveComposite(newCompositeId, targetId);
}
this.openComposite(newCompositeId, true);
this.openComposite(newCompositeId, true).then(composite => {
if (composite) {
composite.openView(viewDescriptor.id, true);
}
});
}
}
}
}
onDragEnter(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): boolean {
return this.canDrop(data, targetCompositeId);
}
onDragOver(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent): boolean {
return this.canDrop(data, targetCompositeId);
}
private canDrop(data: CompositeDragAndDropData, targetCompositeId: string | undefined): boolean {
const dragData = data.getData();
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
@@ -134,6 +156,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
if (this.targetContainerLocation === ViewContainerLocation.Sidebar) {
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
return !!destinationContainer &&
!destinationContainer.rejectAddedViews &&
this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors.some(vd => vd.canMoveView);
}
// ... from sidebar to the panel
@@ -155,10 +178,9 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
}
// ... into a destination
return true;
const destinationContainer = viewContainerRegistry.get(targetCompositeId);
return !!destinationContainer && !destinationContainer.rejectAddedViews;
}
return false;
}
}
@@ -200,6 +222,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
constructor(
items: ICompositeBarItem[],
private options: ICompositeBarOptions,
@IThemeService private readonly themeService: IThemeService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
@@ -228,6 +251,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
create(parent: HTMLElement): HTMLElement {
const actionBarDiv = parent.appendChild($('.composite-bar'));
const excessDiv = parent.appendChild($('.composite-bar-excess'));
this.compositeSwitcherBar = this._register(new ActionBar(actionBarDiv, {
actionViewItemProvider: (action: IAction) => {
@@ -254,58 +278,99 @@ export class CompositeBar extends Widget implements ICompositeBar {
this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e)));
// Allow to drop at the end to move composites to the end
this._register(addDisposableListener(parent, EventType.DROP, (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
EventHelper.stop(e, true);
this._register(new DragAndDropObserver(excessDiv, {
onDragOver: (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data)) {
const draggedCompositeId = data[0].id;
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data)) {
const draggedCompositeId = data[0].id;
this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e);
}
}
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
this.compositeTransfer.clearData(DraggedViewIdentifier.prototype);
this.options.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), undefined, e);
}
}
}));
this._register(addDisposableListener(parent, EventType.DRAG_OVER, (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data)) {
const draggedCompositeId = data[0].id;
// Check if drop is allowed
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e)) {
e.dataTransfer.dropEffect = 'none';
// Check if drop is allowed
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e)) {
e.dataTransfer.dropEffect = 'none';
}
}
}
}
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
EventHelper.stop(e, true);
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
// Check if drop is allowed
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), undefined, e)) {
e.dataTransfer.dropEffect = 'none';
// Check if drop is allowed
if (e.dataTransfer && !this.options.dndHandler.onDragOver(new CompositeDragAndDropData('view', draggedViewId), undefined, e)) {
e.dataTransfer.dropEffect = 'none';
}
}
}
}
},
onDragEnter: (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data)) {
const draggedCompositeId = data[0].id;
// Check if drop is allowed
const validDropTarget = this.options.dndHandler.onDragEnter(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e);
this.updateFromDragging(excessDiv, validDropTarget);
}
}
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
// Check if drop is allowed
const validDropTarget = this.options.dndHandler.onDragEnter(new CompositeDragAndDropData('view', draggedViewId), undefined, e);
this.updateFromDragging(excessDiv, validDropTarget);
}
}
},
onDragLeave: (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) ||
this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
this.updateFromDragging(excessDiv, false);
}
},
onDragEnd: (e: DragEvent) => {
// no-op, will not be called
},
onDrop: (e: DragEvent) => {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
EventHelper.stop(e, true);
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data)) {
const draggedCompositeId = data[0].id;
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e);
this.updateFromDragging(excessDiv, false);
}
}
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
this.compositeTransfer.clearData(DraggedViewIdentifier.prototype);
this.options.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), undefined, e);
this.updateFromDragging(excessDiv, false);
}
}
},
}));
return actionBarDiv;
@@ -410,6 +475,13 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
}
private updateFromDragging(element: HTMLElement, isDragging: boolean): void {
const theme = this.themeService.getTheme();
const dragBackground = this.options.colors(theme).dragAndDropBackground;
element.style.backgroundColor = isDragging && dragBackground ? dragBackground.toString() : '';
}
private resetActiveComposite(compositeId: string) {
const defaultCompositeId = this.options.getDefaultCompositeId();

View File

@@ -544,14 +544,16 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
if (this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype)) {
const data = this.compositeTransfer.getData(DraggedCompositeIdentifier.prototype);
if (Array.isArray(data) && data[0].id !== this.activity.id) {
this.updateFromDragging(container, true);
const validDropTarget = this.dndHandler.onDragEnter(new CompositeDragAndDropData('composite', data[0].id), this.activity.id, e);
this.updateFromDragging(container, validDropTarget);
}
}
if (this.compositeTransfer.hasData(DraggedViewIdentifier.prototype)) {
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data) && data[0].id !== this.activity.id) {
this.updateFromDragging(container, true);
const validDropTarget = this.dndHandler.onDragEnter(new CompositeDragAndDropData('view', data[0].id), this.activity.id, e);
this.updateFromDragging(container, validDropTarget);
}
}
},
@@ -616,6 +618,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
const data = this.compositeTransfer.getData(DraggedViewIdentifier.prototype);
if (Array.isArray(data)) {
const draggedViewId = data[0].id;
this.updateFromDragging(container, false);
this.compositeTransfer.clearData(DraggedViewIdentifier.prototype);
this.dndHandler.drop(new CompositeDragAndDropData('view', draggedViewId), this.activity.id, e);
}

View File

@@ -147,6 +147,7 @@ class StateChange {
encoding: boolean = false;
EOL: boolean = false;
tabFocusMode: boolean = false;
columnSelectionMode: boolean = false;
screenReaderMode: boolean = false;
metadata: boolean = false;
@@ -157,6 +158,7 @@ class StateChange {
this.encoding = this.encoding || other.encoding;
this.EOL = this.EOL || other.EOL;
this.tabFocusMode = this.tabFocusMode || other.tabFocusMode;
this.columnSelectionMode = this.columnSelectionMode || other.columnSelectionMode;
this.screenReaderMode = this.screenReaderMode || other.screenReaderMode;
this.metadata = this.metadata || other.metadata;
}
@@ -168,21 +170,23 @@ class StateChange {
|| this.encoding
|| this.EOL
|| this.tabFocusMode
|| this.columnSelectionMode
|| this.screenReaderMode
|| this.metadata;
}
}
interface StateDelta {
selectionStatus?: string;
mode?: string;
encoding?: string;
EOL?: string;
indentation?: string;
tabFocusMode?: boolean;
screenReaderMode?: boolean;
metadata?: string | undefined;
}
type StateDelta = (
{ type: 'selectionStatus'; selectionStatus: string | undefined; }
| { type: 'mode'; mode: string | undefined; }
| { type: 'encoding'; encoding: string | undefined; }
| { type: 'EOL'; EOL: string | undefined; }
| { type: 'indentation'; indentation: string | undefined; }
| { type: 'tabFocusMode'; tabFocusMode: boolean; }
| { type: 'columnSelectionMode'; columnSelectionMode: boolean; }
| { type: 'screenReaderMode'; screenReaderMode: boolean; }
| { type: 'metadata'; metadata: string | undefined; }
);
class State {
@@ -204,6 +208,9 @@ class State {
private _tabFocusMode: boolean | undefined;
get tabFocusMode(): boolean | undefined { return this._tabFocusMode; }
private _columnSelectionMode: boolean | undefined;
get columnSelectionMode(): boolean | undefined { return this._columnSelectionMode; }
private _screenReaderMode: boolean | undefined;
get screenReaderMode(): boolean | undefined { return this._screenReaderMode; }
@@ -213,56 +220,63 @@ class State {
update(update: StateDelta): StateChange {
const change = new StateChange();
if ('selectionStatus' in update) {
if (update.type === 'selectionStatus') {
if (this._selectionStatus !== update.selectionStatus) {
this._selectionStatus = update.selectionStatus;
change.selectionStatus = true;
}
}
if ('indentation' in update) {
if (update.type === 'indentation') {
if (this._indentation !== update.indentation) {
this._indentation = update.indentation;
change.indentation = true;
}
}
if ('mode' in update) {
if (update.type === 'mode') {
if (this._mode !== update.mode) {
this._mode = update.mode;
change.mode = true;
}
}
if ('encoding' in update) {
if (update.type === 'encoding') {
if (this._encoding !== update.encoding) {
this._encoding = update.encoding;
change.encoding = true;
}
}
if ('EOL' in update) {
if (update.type === 'EOL') {
if (this._EOL !== update.EOL) {
this._EOL = update.EOL;
change.EOL = true;
}
}
if ('tabFocusMode' in update) {
if (update.type === 'tabFocusMode') {
if (this._tabFocusMode !== update.tabFocusMode) {
this._tabFocusMode = update.tabFocusMode;
change.tabFocusMode = true;
}
}
if ('screenReaderMode' in update) {
if (update.type === 'columnSelectionMode') {
if (this._columnSelectionMode !== update.columnSelectionMode) {
this._columnSelectionMode = update.columnSelectionMode;
change.columnSelectionMode = true;
}
}
if (update.type === 'screenReaderMode') {
if (this._screenReaderMode !== update.screenReaderMode) {
this._screenReaderMode = update.screenReaderMode;
change.screenReaderMode = true;
}
}
if ('metadata' in update) {
if (update.type === 'metadata') {
if (this._metadata !== update.metadata) {
this._metadata = update.metadata;
change.metadata = true;
@@ -282,6 +296,7 @@ const nlsEOLCRLF = nls.localize('endOfLineCarriageReturnLineFeed', "CRLF");
export class EditorStatus extends Disposable implements IWorkbenchContribution {
private readonly tabFocusModeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly columnSelectionModeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly screenRedearModeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly indentationElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly selectionElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
@@ -402,6 +417,22 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
}
private updateColumnSelectionModeElement(visible: boolean): void {
if (visible) {
if (!this.columnSelectionModeElement.value) {
this.columnSelectionModeElement.value = this.statusbarService.addEntry({
text: nls.localize('columnSelectionModeEnabled', "Column Selection"),
tooltip: nls.localize('disableColumnSelectionMode', "Disable Column Selection Mode"),
command: 'editor.action.toggleColumnSelection',
backgroundColor: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_BACKGROUND),
color: themeColorFromId(STATUS_BAR_PROMINENT_ITEM_FOREGROUND)
}, 'status.editor.columnSelectionMode', nls.localize('status.editor.columnSelectionMode', "Column Selection Mode"), StatusbarAlignment.RIGHT, 100.8);
}
} else {
this.columnSelectionModeElement.clear();
}
}
private updateScreenReaderModeElement(visible: boolean): void {
if (visible) {
if (!this.screenRedearModeElement.value) {
@@ -544,6 +575,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
private doRenderNow(changed: StateChange): void {
this.updateTabFocusModeElement(!!this.state.tabFocusMode);
this.updateColumnSelectionModeElement(!!this.state.columnSelectionMode);
this.updateScreenReaderModeElement(!!this.state.screenReaderMode);
this.updateIndentationElement(this.state.indentation);
this.updateSelectionElement(this.state.selectionStatus && !this.state.screenReaderMode ? this.state.selectionStatus : undefined);
@@ -583,6 +615,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
const activeCodeEditor = activeControl ? withNullAsUndefined(getCodeEditor(activeControl.getControl())) : undefined;
// Update all states
this.onColumnSelectionModeChange(activeCodeEditor);
this.onScreenReaderModeChange(activeCodeEditor);
this.onSelectionChange(activeCodeEditor);
this.onModeChange(activeCodeEditor, activeInput);
@@ -600,6 +633,9 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
// Hook Listener for Configuration changes
this.activeEditorListeners.add(activeCodeEditor.onDidChangeConfiguration((event: ConfigurationChangedEvent) => {
if (event.hasChanged(EditorOption.columnSelection)) {
this.onColumnSelectionModeChange(activeCodeEditor);
}
if (event.hasChanged(EditorOption.accessibilitySupport)) {
this.onScreenReaderModeChange(activeCodeEditor);
}
@@ -668,14 +704,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
private onModeChange(editorWidget: ICodeEditor | undefined, editorInput: IEditorInput | undefined): void {
let info: StateDelta = { mode: undefined };
let info: StateDelta = { type: 'mode', mode: undefined };
// We only support text based editors
if (editorWidget && editorInput && toEditorWithModeSupport(editorInput)) {
const textModel = editorWidget.getModel();
if (textModel) {
const modeId = textModel.getLanguageIdentifier().language;
info = { mode: withNullAsUndefined(this.modeService.getLanguageName(modeId)) };
info.mode = withNullAsUndefined(this.modeService.getLanguageName(modeId));
}
}
@@ -683,7 +719,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
private onIndentationChange(editorWidget: ICodeEditor | undefined): void {
const update: StateDelta = { indentation: undefined };
const update: StateDelta = { type: 'indentation', indentation: undefined };
if (editorWidget) {
const model = editorWidget.getModel();
@@ -701,7 +737,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
private onMetadataChange(editor: IBaseEditor | undefined): void {
const update: StateDelta = { metadata: undefined };
const update: StateDelta = { type: 'metadata', metadata: undefined };
if (editor instanceof BaseBinaryResourceEditor || editor instanceof BinaryResourceDiffEditor) {
update.metadata = editor.getMetadata();
@@ -710,6 +746,16 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.updateState(update);
}
private onColumnSelectionModeChange(editorWidget: ICodeEditor | undefined): void {
const info: StateDelta = { type: 'columnSelectionMode', columnSelectionMode: false };
if (editorWidget && editorWidget.getOption(EditorOption.columnSelection)) {
info.columnSelectionMode = true;
}
this.updateState(info);
}
private onScreenReaderModeChange(editorWidget: ICodeEditor | undefined): void {
let screenReaderMode = false;
@@ -733,7 +779,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.screenReaderNotification.close();
}
this.updateState({ screenReaderMode: screenReaderMode });
this.updateState({ type: 'screenReaderMode', screenReaderMode: screenReaderMode });
}
private onSelectionChange(editorWidget: ICodeEditor | undefined): void {
@@ -773,11 +819,11 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
}
this.updateState({ selectionStatus: this.getSelectionLabel(info) });
this.updateState({ type: 'selectionStatus', selectionStatus: this.getSelectionLabel(info) });
}
private onEOLChange(editorWidget: ICodeEditor | undefined): void {
const info: StateDelta = { EOL: undefined };
const info: StateDelta = { type: 'EOL', EOL: undefined };
if (editorWidget && !editorWidget.getOption(EditorOption.readOnly)) {
const codeEditorModel = editorWidget.getModel();
@@ -794,7 +840,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
return;
}
const info: StateDelta = { encoding: undefined };
const info: StateDelta = { type: 'encoding', encoding: undefined };
// We only support text based editors that have a model associated
// This ensures we do not show the encoding picker while an editor
@@ -828,7 +874,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
private onTabFocusModeChange(): void {
const info: StateDelta = { tabFocusMode: TabFocus.getTabFocusMode() };
const info: StateDelta = { type: 'tabFocusMode', tabFocusMode: TabFocus.getTabFocusMode() };
this.updateState(info);
}

View File

@@ -26,10 +26,8 @@ export class ClearNotificationAction extends Action {
super(id, label, 'codicon-close');
}
run(notification: INotificationViewItem): Promise<any> {
async run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(CLEAR_NOTIFICATION, notification);
return Promise.resolve();
}
}
@@ -46,10 +44,8 @@ export class ClearAllNotificationsAction extends Action {
super(id, label, 'codicon-clear-all');
}
run(notification: INotificationViewItem): Promise<any> {
async run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(CLEAR_ALL_NOTIFICATIONS);
return Promise.resolve();
}
}
@@ -63,13 +59,11 @@ export class HideNotificationsCenterAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'codicon-close');
super(id, label, 'codicon-chevron-down');
}
run(notification: INotificationViewItem): Promise<any> {
async run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(HIDE_NOTIFICATIONS_CENTER);
return Promise.resolve();
}
}
@@ -86,10 +80,8 @@ export class ExpandNotificationAction extends Action {
super(id, label, 'codicon-chevron-up');
}
run(notification: INotificationViewItem): Promise<any> {
async run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(EXPAND_NOTIFICATION, notification);
return Promise.resolve();
}
}
@@ -106,10 +98,8 @@ export class CollapseNotificationAction extends Action {
super(id, label, 'codicon-chevron-down');
}
run(notification: INotificationViewItem): Promise<any> {
async run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(COLLAPSE_NOTIFICATION, notification);
return Promise.resolve();
}
}

View File

@@ -100,6 +100,9 @@ export class NotificationsCenter extends Themable implements INotificationsCente
// Theming
this.updateStyles();
// Mark as visible
this.model.notifications.forEach(notification => notification.updateVisibility(true));
// Context Key
this.notificationsCenterVisibleContextKey.set(true);
@@ -115,7 +118,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
clearAllAction.enabled = false;
} else {
notificationsCenterTitle.textContent = localize('notifications', "Notifications");
clearAllAction.enabled = true;
clearAllAction.enabled = this.model.notifications.some(notification => !notification.hasProgress);
}
}
@@ -172,20 +175,22 @@ export class NotificationsCenter extends Themable implements INotificationsCente
return; // only if visible
}
let focusGroup = false;
let focusEditor = false;
// Update notifications list based on event
const [notificationsList, notificationsCenterContainer] = assertAllDefined(this.notificationsList, this.notificationsCenterContainer);
switch (e.kind) {
case NotificationChangeType.ADD:
notificationsList.updateNotificationsList(e.index, 0, [e.item]);
e.item.updateVisibility(true);
break;
case NotificationChangeType.CHANGE:
notificationsList.updateNotificationsList(e.index, 1, [e.item]);
break;
case NotificationChangeType.REMOVE:
focusGroup = isAncestor(document.activeElement, notificationsCenterContainer);
focusEditor = isAncestor(document.activeElement, notificationsCenterContainer);
notificationsList.updateNotificationsList(e.index, 1);
e.item.updateVisibility(false);
break;
}
@@ -197,7 +202,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
this.hide();
// Restore focus to editor group if we had focus
if (focusGroup) {
if (focusEditor) {
this.editorGroupService.activeGroup.focus();
}
}
@@ -208,13 +213,16 @@ export class NotificationsCenter extends Themable implements INotificationsCente
return; // already hidden
}
const focusGroup = isAncestor(document.activeElement, this.notificationsCenterContainer);
const focusEditor = isAncestor(document.activeElement, this.notificationsCenterContainer);
// Hide
this._isVisible = false;
removeClass(this.notificationsCenterContainer, 'visible');
this.notificationsList.hide();
// Mark as hidden
this.model.notifications.forEach(notification => notification.updateVisibility(false));
// Context Key
this.notificationsCenterVisibleContextKey.set(false);
@@ -222,7 +230,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
this._onDidChangeVisibility.fire();
// Restore focus to editor group if we had focus
if (focusGroup) {
if (focusEditor) {
this.editorGroupService.activeGroup.focus();
}
}

View File

@@ -75,6 +75,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl
// Show Notifications Cneter
CommandsRegistry.registerCommand(SHOW_NOTIFICATIONS_CENTER, () => {
toasts.hide();
center.show();
});
@@ -92,6 +93,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl
if (center.isVisible) {
center.hide();
} else {
toasts.hide();
center.show();
}
});

View File

@@ -46,7 +46,7 @@ export class NotificationsStatus extends Disposable {
if (!this.isNotificationsCenterVisible) {
if (e.kind === NotificationChangeType.ADD) {
this.newNotificationsCount++;
} else if (e.kind === NotificationChangeType.REMOVE) {
} else if (e.kind === NotificationChangeType.REMOVE && this.newNotificationsCount > 0) {
this.newNotificationsCount--;
}
}
@@ -69,8 +69,9 @@ export class NotificationsStatus extends Disposable {
}
}
// Show the bell with a dot if there are unread or in-progress notifications
const statusProperties: IStatusbarEntry = {
text: `${this.newNotificationsCount === 0 ? '$(bell)' : '$(bell-dot)'}${notificationsInProgress > 0 ? ' $(sync~spin)' : ''}`,
text: `${notificationsInProgress > 0 || this.newNotificationsCount > 0 ? '$(bell-dot)' : '$(bell)'}`,
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
tooltip: this.getTooltip(notificationsInProgress),
showBeak: this.isNotificationsCenterVisible

View File

@@ -179,11 +179,8 @@ export class NotificationsToasts extends Themable implements INotificationsToast
const toast: INotificationToast = { item, list: notificationList, container: notificationToastContainer, toast: notificationToast, toDispose: itemDisposables };
this.mapNotificationToToast.set(item, toast);
itemDisposables.add(toDisposable(() => {
if (this.isToastVisible(toast) && notificationsToastsContainer) {
notificationsToastsContainer.removeChild(toast.container);
}
}));
// When disposed, remove as visible
itemDisposables.add(toDisposable(() => this.updateToastVisibility(toast, false)));
// Make visible
notificationList.show();
@@ -236,6 +233,9 @@ export class NotificationsToasts extends Themable implements INotificationsToast
addClass(notificationToast, 'notification-fade-in-done');
}));
// Mark as visible
item.updateVisibility(true);
// Events
if (!this._isVisible) {
this._isVisible = true;
@@ -292,12 +292,13 @@ export class NotificationsToasts extends Themable implements INotificationsToast
}
private removeToast(item: INotificationViewItem): void {
let focusEditor = false;
const notificationToast = this.mapNotificationToToast.get(item);
let focusGroup = false;
if (notificationToast) {
const toastHasDOMFocus = isAncestor(document.activeElement, notificationToast.container);
if (toastHasDOMFocus) {
focusGroup = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor
focusEditor = !(this.focusNext() || this.focusPrevious()); // focus next if any, otherwise focus editor
}
// Listeners
@@ -317,7 +318,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
this.doHide();
// Move focus back to editor group as needed
if (focusGroup) {
if (focusEditor) {
this.editorGroupService.activeGroup.focus();
}
}
@@ -346,11 +347,11 @@ export class NotificationsToasts extends Themable implements INotificationsToast
}
hide(): void {
const focusGroup = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false;
const focusEditor = this.notificationsToastsContainer ? isAncestor(document.activeElement, this.notificationsToastsContainer) : false;
this.removeToasts();
if (focusGroup) {
if (focusEditor) {
this.editorGroupService.activeGroup.focus();
}
}
@@ -459,12 +460,12 @@ export class NotificationsToasts extends Themable implements INotificationsToast
notificationToasts.push(toast);
break;
case ToastVisibility.HIDDEN:
if (!this.isToastVisible(toast)) {
if (!this.isToastInDOM(toast)) {
notificationToasts.push(toast);
}
break;
case ToastVisibility.VISIBLE:
if (this.isToastVisible(toast)) {
if (this.isToastInDOM(toast)) {
notificationToasts.push(toast);
}
break;
@@ -530,7 +531,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
// In order to measure the client height, the element cannot have display: none
toast.container.style.opacity = '0';
this.setVisibility(toast, true);
this.updateToastVisibility(toast, true);
heightToGive -= toast.container.offsetHeight;
@@ -542,7 +543,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
}
// Hide or show toast based on context
this.setVisibility(toast, makeVisible);
this.updateToastVisibility(toast, makeVisible);
toast.container.style.opacity = '';
if (makeVisible) {
@@ -551,20 +552,24 @@ export class NotificationsToasts extends Themable implements INotificationsToast
});
}
private setVisibility(toast: INotificationToast, visible: boolean): void {
if (this.isToastVisible(toast) === visible) {
private updateToastVisibility(toast: INotificationToast, visible: boolean): void {
if (this.isToastInDOM(toast) === visible) {
return;
}
// Update visibility in DOM
const notificationsToastsContainer = assertIsDefined(this.notificationsToastsContainer);
if (visible) {
notificationsToastsContainer.appendChild(toast.container);
} else {
notificationsToastsContainer.removeChild(toast.container);
}
// Update visibility in model
toast.item.updateVisibility(visible);
}
private isToastVisible(toast: INotificationToast): boolean {
private isToastInDOM(toast: INotificationToast): boolean {
return !!toast.container.parentElement;
}
}

View File

@@ -62,6 +62,10 @@
}
.monaco-workbench .part.panel > .composite.title > .composite-bar-excess {
width: 100%;
}
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar {
line-height: 27px; /* matches panel titles in settings */
height: 35px;

View File

@@ -36,6 +36,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewDescriptorService, IViewDescriptorCollection, ViewContainerLocation } from 'vs/workbench/common/views';
import { MenuId } from 'vs/platform/actions/common/actions';
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
interface ICachedPanel {
id: string;
@@ -143,7 +144,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(),
hidePart: () => this.layoutService.setPanelHidden(true),
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
(id: string, focus?: boolean) => this.openPanel(id, focus),
(id: string, focus?: boolean) => (<unknown>this.openPanel(id, focus)) as Promise<IPaneComposite | undefined>, // {{SQL CARBON EDIT}} strict-null-check
(from: string, to: string) => this.compositeBar.move(from, to),
() => this.getPinnedPanels().map(p => p.id)
),

View File

@@ -255,7 +255,10 @@ export abstract class ViewPane extends Pane implements IView {
this._onDidFocus.fire();
}));
this._register(focusTracker.onDidBlur(() => {
this.focusedViewContextKey.reset();
if (this.focusedViewContextKey.get() === this.id) {
this.focusedViewContextKey.reset();
}
this._onDidBlur.fire();
}));
}
@@ -1006,7 +1009,8 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
}
if (!this.areExtensionsReady) {
if (this.visibleViewsCountFromCache === undefined) {
return true;
// TODO @sbatten fix hack for #91367
return this.viewDescriptorService.getViewContainerLocation(this.viewContainer) === ViewContainerLocation.Panel;
}
// Check in cache so that view do not jump. See #29609
return this.visibleViewsCountFromCache === 1;