Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/vs/base/browser/ui/list/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ export interface IRenderer<TElement, TTemplateData> {
disposeTemplate(templateData: TTemplateData): void;
}

export interface IListOpenEvent<T> {
elements: T[];
indexes: number[];
browserEvent?: UIEvent;
}

export interface IListEvent<T> {
elements: T[];
indexes: number[];
Expand Down
10 changes: 7 additions & 3 deletions src/vs/base/browser/ui/list/listPaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import 'vs/css!./list';
import { IDisposable } from 'vs/base/common/lifecycle';
import { range } from 'vs/base/common/arrays';
import { IDelegate, IRenderer, IListEvent } from './list';
import { IDelegate, IRenderer, IListEvent, IListOpenEvent } from './list';
import { List, IListStyles, IListOptions } from './listWidget';
import { IPagedModel } from 'vs/base/common/paging';
import Event, { mapEvent } from 'vs/base/common/event';
Expand Down Expand Up @@ -97,6 +97,10 @@ export class PagedList<T> {
return mapEvent(this.list.onFocusChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
}

get onOpen(): Event<IListOpenEvent<T>> {
return mapEvent(this.list.onOpen, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));
}

get onSelectionChange(): Event<IListEvent<T>> {
return mapEvent(this.list.onSelectionChange, ({ elements, indexes }) => ({ elements: elements.map(e => this._model.get(e)), indexes }));
}
Expand Down Expand Up @@ -126,8 +130,8 @@ export class PagedList<T> {
this.list.scrollTop = scrollTop;
}

open(indexes: number[]): void {
this.list.open(indexes);
open(indexes: number[], browserEvent?: UIEvent): void {
this.list.open(indexes, browserEvent);
}

setFocus(indexes: number[]): void {
Expand Down
44 changes: 34 additions & 10 deletions src/vs/base/browser/ui/list/listWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import Event, { Emitter, EventBufferer, chain, mapEvent, anyEvent } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IDelegate, IRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent } from './list';
import { IDelegate, IRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListOpenEvent } from './list';
import { ListView, IListViewOptions } from './listView';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
Expand Down Expand Up @@ -261,6 +261,7 @@ function isInputElement(e: HTMLElement): boolean {
class KeyboardController<T> implements IDisposable {

private disposables: IDisposable[];
private openController: IOpenController;

constructor(
private list: List<T>,
Expand All @@ -270,6 +271,8 @@ class KeyboardController<T> implements IDisposable {
const multipleSelectionSupport = !(options.multipleSelectionSupport === false);
this.disposables = [];

this.openController = options.openController || DefaultOpenController;

const onKeyDown = chain(domEvent(view.domNode, 'keydown'))
.filter(e => !isInputElement(e.target as HTMLElement))
.map(e => new StandardKeyboardEvent(e));
Expand All @@ -290,7 +293,10 @@ class KeyboardController<T> implements IDisposable {
e.preventDefault();
e.stopPropagation();
this.list.setSelection(this.list.getFocus());
this.list.open(this.list.getFocus());

if (this.openController.shouldOpen(e.browserEvent)) {
this.list.open(this.list.getFocus(), e.browserEvent);
}
}

private onUpArrow(e: StandardKeyboardEvent): void {
Expand Down Expand Up @@ -357,10 +363,15 @@ const DefaultMultipleSelectionContoller = {
isSelectionRangeChangeEvent
};

const DefaultOpenController = {
shouldOpen: (event: UIEvent) => true
};

class MouseController<T> implements IDisposable {

private multipleSelectionSupport: boolean;
private multipleSelectionController: IMultipleSelectionController<T> | undefined;
private multipleSelectionController: IMultipleSelectionController<T>;
private openController: IOpenController;
private didJustPressContextMenuKey: boolean = false;
private disposables: IDisposable[] = [];

Expand Down Expand Up @@ -406,6 +417,8 @@ class MouseController<T> implements IDisposable {
this.multipleSelectionController = options.multipleSelectionController || DefaultMultipleSelectionContoller;
}

this.openController = options.openController || DefaultOpenController;

view.onMouseDown(this.onMouseDown, this, this.disposables);
view.onMouseClick(this.onPointer, this, this.disposables);
view.onMouseDblClick(this.onDoubleClick, this, this.disposables);
Expand Down Expand Up @@ -458,7 +471,10 @@ class MouseController<T> implements IDisposable {

if (this.options.selectOnMouseDown) {
this.list.setSelection([focus]);
this.list.open([focus]);

if (this.openController.shouldOpen(e.browserEvent)) {
this.list.open([focus], e.browserEvent);
}
}
}

Expand All @@ -470,7 +486,10 @@ class MouseController<T> implements IDisposable {
if (!this.options.selectOnMouseDown) {
const focus = this.list.getFocus();
this.list.setSelection(focus);
this.list.open(focus);

if (this.openController.shouldOpen(e.browserEvent)) {
this.list.open(focus, e.browserEvent);
}
}
}

Expand Down Expand Up @@ -523,6 +542,10 @@ export interface IMultipleSelectionController<T> {
isSelectionRangeChangeEvent(event: IListMouseEvent<T> | IListTouchEvent<T>): boolean;
}

export interface IOpenController {
shouldOpen(event: UIEvent): boolean;
}

export interface IListOptions<T> extends IListViewOptions, IListStyles {
identityProvider?: IIdentityProvider<T>;
ariaLabel?: string;
Expand All @@ -533,6 +556,7 @@ export interface IListOptions<T> extends IListViewOptions, IListStyles {
verticalScrollMode?: ScrollbarVisibility;
multipleSelectionSupport?: boolean;
multipleSelectionController?: IMultipleSelectionController<T>;
openController?: IOpenController;
}

export interface IListStyles {
Expand Down Expand Up @@ -708,9 +732,9 @@ export class List<T> implements ISpliceable<T>, IDisposable {

readonly onContextMenu: Event<IListContextMenuEvent<T>> = Event.None;

private _onOpen = new Emitter<number[]>();
@memoize get onOpen(): Event<IListEvent<T>> {
return mapEvent(this._onOpen.event, indexes => this.toListEvent({ indexes }));
private _onOpen = new Emitter<IListOpenEvent<T>>();
@memoize get onOpen(): Event<IListOpenEvent<T>> {
return this._onOpen.event;
}

private _onPin = new Emitter<number[]>();
Expand Down Expand Up @@ -973,8 +997,8 @@ export class List<T> implements ISpliceable<T>, IDisposable {
return this.view.domNode;
}

open(indexes: number[]): void {
this._onOpen.fire(indexes);
open(indexes: number[], browserEvent?: UIEvent): void {
this._onOpen.fire({ indexes, elements: indexes.map(i => this.view.element(i)), browserEvent });
}

pin(indexes: number[]): void {
Expand Down
27 changes: 22 additions & 5 deletions src/vs/base/parts/tree/browser/treeDefaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ export enum ClickBehavior {
ON_MOUSE_UP
}

export enum OpenMode {
SINGLE_CLICK,
DOUBLE_CLICK
}

export interface IControllerOptions {
clickBehavior?: ClickBehavior;
openMode?: OpenMode;
keyboardSupport?: boolean;
}

Expand Down Expand Up @@ -82,7 +88,7 @@ export class DefaultController implements _.IController {

private options: IControllerOptions;

constructor(options: IControllerOptions = { clickBehavior: ClickBehavior.ON_MOUSE_UP, keyboardSupport: true }) {
constructor(options: IControllerOptions = { clickBehavior: ClickBehavior.ON_MOUSE_UP, keyboardSupport: true, openMode: OpenMode.SINGLE_CLICK }) {
this.options = options;

this.downKeyBindingDispatcher = new KeybindingDispatcher();
Expand Down Expand Up @@ -153,6 +159,7 @@ export class DefaultController implements _.IController {

protected onLeftClick(tree: _.ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
const payload = { origin: origin, originalEvent: eventish };
const isDoubleClick = (origin === 'mouse' && (<mouse.IMouseEvent>eventish).detail === 2);

if (tree.getInput() === element) {
tree.clearFocus(payload);
Expand All @@ -168,16 +175,26 @@ export class DefaultController implements _.IController {
tree.setSelection([element], payload);
tree.setFocus(element, payload);

if (tree.isExpanded(element)) {
tree.collapse(element).done(null, errors.onUnexpectedError);
} else {
tree.expand(element).done(null, errors.onUnexpectedError);
if (this.openOnSingleClick || isDoubleClick) {
if (tree.isExpanded(element)) {
tree.collapse(element).done(null, errors.onUnexpectedError);
} else {
tree.expand(element).done(null, errors.onUnexpectedError);
}
}
}

return true;
}

protected setOpenMode(openMode: OpenMode) {
this.options.openMode = openMode;
}

protected get openOnSingleClick(): boolean {
return this.options.openMode === OpenMode.SINGLE_CLICK;
}

public onContextMenu(tree: _.ITree, element: any, event: _.ContextMenuEvent): boolean {
if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
return false; // allow context menu on input fields
Expand Down
25 changes: 14 additions & 11 deletions src/vs/editor/contrib/referenceSearch/referencesWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { GestureEvent } from 'vs/base/browser/touch';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { FileLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import * as tree from 'vs/base/parts/tree/browser/tree';
import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults';
import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { Range, IRange } from 'vs/editor/common/core/range';
Expand All @@ -41,7 +40,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import URI from 'vs/base/common/uri';
import { TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model';
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { WorkbenchTree, WorkbenchTreeController } from 'vs/platform/list/browser/listService';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { Location } from 'vs/editor/common/modes';

Expand Down Expand Up @@ -218,7 +217,7 @@ class DataSource implements tree.IDataSource {
}
}

class Controller extends DefaultController {
class Controller extends WorkbenchTreeController {

private _onDidFocus = new Emitter<any>();
readonly onDidFocus: Event<any> = this._onDidFocus.event;
Expand All @@ -243,19 +242,22 @@ class Controller extends DefaultController {
}

public onMouseDown(tree: tree.ITree, element: any, event: IMouseEvent): boolean {
var isDoubleClick = event.detail === 2;
if (event.leftButton) {
if (element instanceof FileReferences) {
event.preventDefault();
event.stopPropagation();
return this._expandCollapse(tree, element);
if (this.openOnSingleClick || isDoubleClick) {
event.preventDefault();
event.stopPropagation();
return this._expandCollapse(tree, element);
}
}

var result = super.onClick(tree, element, event);
if (event.ctrlKey || event.metaKey || event.altKey) {
this._onDidOpenToSide.fire(element);
} else if (event.detail === 2) {
} else if (isDoubleClick) {
this._onDidSelect.fire(element);
} else {
} else if (this.openOnSingleClick) {
this._onDidFocus.fire(element);
}
return result;
Expand Down Expand Up @@ -631,7 +633,9 @@ export class ReferenceWidget extends PeekViewWidget {

// tree
container.div({ 'class': 'ref-tree inline' }, (div: Builder) => {
const controller = new Controller();
var controller = this._instantiationService.createInstance(Controller, {});
this._callOnDispose.push(controller);

var config = <tree.ITreeConfiguration>{
dataSource: this._instantiationService.createInstance(DataSource),
renderer: this._instantiationService.createInstance(Renderer),
Expand All @@ -641,8 +645,7 @@ export class ReferenceWidget extends PeekViewWidget {

var options: tree.ITreeOptions = {
twistiePixels: 20,
ariaLabel: nls.localize('treeAriaLabel', "References"),
keyboardSupport: false
ariaLabel: nls.localize('treeAriaLabel', "References")
};

this._tree = this._instantiationService.createInstance(WorkbenchTree, div.getHTMLElement(), config, options);
Expand Down
Loading