提交 4728d11f 编写于 作者: J Joao Moreno

markers panel: finally mouse and keyboard navigation

very very hacky
上级 afe13242
......@@ -6,15 +6,14 @@
import 'vs/css!./tree';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IListOptions, List, IIdentityProvider, IMultipleSelectionController, IListStyles } from 'vs/base/browser/ui/list/listWidget';
import { IVirtualDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list';
import { IVirtualDelegate, IRenderer, IListMouseEvent, IListEvent } from 'vs/base/browser/ui/list/list';
import { append, $ } from 'vs/base/browser/dom';
import { Event, Relay, chain, mapEvent } from 'vs/base/common/event';
import { Event, Relay, chain } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { ITreeModel, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
import { ISpliceable } from 'vs/base/common/sequence';
import { IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel';
import { memoize } from 'vs/base/common/decorators';
export function createComposedTreeListOptions<T, N extends { element: T }>(options?: IListOptions<T>): IListOptions<N> {
if (!options) {
......@@ -161,6 +160,7 @@ function isInputElement(e: HTMLElement): boolean {
}
export interface ITreeOptions<T, TFilterData = void> extends IListOptions<T>, IIndexTreeModelOptions<T, TFilterData> { }
export interface ITreeEvent<T, TFilterData> extends IListEvent<ITreeNode<T, TFilterData>> { }
export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable {
......@@ -170,14 +170,8 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
readonly onDidChangeCollapseState: Event<ITreeNode<T, TFilterData>>;
readonly onDidChangeRenderNodeCount: Event<ITreeNode<T, TFilterData>>;
@memoize get onDidChangeFocus(): Event<T[]> {
return mapEvent(this.view.onFocusChange, e => e.elements.map(e => e.element));
}
@memoize get onDidChangeSelection(): Event<T[]> {
return mapEvent(this.view.onSelectionChange, e => e.elements.map(e => e.element));
}
readonly onDidChangeFocus: Event<ITreeEvent<T, TFilterData>>;
readonly onDidChangeSelection: Event<ITreeEvent<T, TFilterData>>;
get onDidFocus(): Event<void> { return this.view.onDidFocus; }
get onDidBlur(): Event<void> { return this.view.onDidBlur; }
......@@ -196,6 +190,9 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.disposables.push(...treeRenderers);
this.view = new List(container, treeDelegate, treeRenderers, createComposedTreeListOptions<T, ITreeNode<T, TFilterData>>(options));
this.onDidChangeFocus = this.view.onFocusChange;
this.onDidChangeSelection = this.view.onSelectionChange;
this.model = this.createModel(this.view, options);
onDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;
this.onDidChangeCollapseState = this.model.onDidChangeCollapseState;
......@@ -270,9 +267,9 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
this.model.refilter();
}
setSelection(elements: TRef[]): void {
setSelection(elements: TRef[], browserEvent?: UIEvent): void {
const indexes = elements.map(e => this.model.getListIndex(e));
this.view.setSelection(indexes);
this.view.setSelection(indexes, browserEvent);
}
getSelection(): T[] {
......
......@@ -33,7 +33,7 @@ import { attachInputBoxStyler, attachListStyler, computeStyles, defaultListStyle
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys';
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
import { ITreeOptions as ITreeOptions2 } from 'vs/base/browser/ui/tree/abstractTree';
import { ITreeOptions as ITreeOptions2, ITreeEvent } from 'vs/base/browser/ui/tree/abstractTree';
import { ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
export type ListWidget = List<any> | PagedList<any> | ITree | ObjectTree<any, any>;
......@@ -565,6 +565,84 @@ export class TreeResourceNavigator extends Disposable {
}
}
export interface IOpenEvent<T> {
editorOptions: IEditorOptions;
sideBySide: boolean;
element: T;
}
export interface IResourceResultsNavigationOptions {
openOnFocus: boolean;
}
export class ObjectTreeResourceNavigator<T, TFilterData> extends Disposable {
private readonly _openResource: Emitter<IOpenEvent<T>> = new Emitter<IOpenEvent<T>>();
readonly openResource: Event<IOpenEvent<T>> = this._openResource.event;
constructor(private tree: WorkbenchObjectTree<T, TFilterData>, private options?: IResourceResultsNavigationOptions) {
super();
this.registerListeners();
}
private registerListeners(): void {
if (this.options && this.options.openOnFocus) {
this._register(this.tree.onDidChangeFocus(e => this.onFocus(e)));
}
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
}
private onFocus(e: ITreeEvent<T, TFilterData>): void {
const focus = this.tree.getFocus();
this.tree.setSelection(focus, e.browserEvent);
const isMouseEvent = e.browserEvent instanceof MouseEvent;
const isDoubleClick = isMouseEvent && e.browserEvent && e.browserEvent.detail === 2;
if (!isMouseEvent || this.tree.openOnSingleClick || isDoubleClick) {
this._openResource.fire({
editorOptions: {
preserveFocus: true,
pinned: false,
revealIfVisible: true
},
sideBySide: false,
element: focus[0]
});
}
}
private onSelection(e: ITreeEvent<T, TFilterData>): void {
const isMouseEvent = e.browserEvent && e.browserEvent instanceof MouseEvent;
if (!isMouseEvent || this.tree.openOnSingleClick) {
return;
}
const isDoubleClick = isMouseEvent && e.browserEvent && e.browserEvent.detail === 2;
if (!isMouseEvent || this.tree.openOnSingleClick || isDoubleClick) {
if (isDoubleClick && e.browserEvent) {
e.browserEvent.preventDefault(); // focus moves to editor, we need to prevent default
}
const sideBySide = e.browserEvent && e.browserEvent instanceof KeyboardEvent && (e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey);
this._openResource.fire({
editorOptions: {
preserveFocus: isDoubleClick,
pinned: isDoubleClick,
revealIfVisible: true
},
sideBySide,
element: this.tree.getSelection()[0]
});
}
}
}
export interface IHighlighter {
getHighlights(tree: ITree, element: any, pattern: string): FuzzyScore;
getHighlightsStorageKey?(element: any): any;
......@@ -810,6 +888,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
private hasDoubleSelection: IContextKey<boolean>;
private hasMultiSelection: IContextKey<boolean>;
private _openOnSingleClick: boolean;
private _useAltAsMultipleSelectionModifier: boolean;
constructor(
......@@ -820,7 +899,7 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@IThemeService themeService: IThemeService,
@IConfigurationService private configurationService: IConfigurationService
@IConfigurationService configurationService: IConfigurationService
) {
super(container, delegate, renderers, {
keyboardSupport: false,
......@@ -839,9 +918,10 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
this._openOnSingleClick = useSingleClickToOpen(configurationService);
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
this.disposables.push(combinedDisposable([
this.disposables.push(
this.contextKeyService,
(listService as ListService).register(this),
attachListStyler(this, themeService),
......@@ -858,18 +938,21 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
const focus = this.getFocus();
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
})
]));
}),
configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(openModeSettingKey)) {
this._openOnSingleClick = useSingleClickToOpen(configurationService);
}
this.registerListeners();
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
}
})
);
}
private registerListeners(): void {
this.disposables.push(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(this.configurationService);
}
}));
get openOnSingleClick(): boolean {
return this._openOnSingleClick;
}
get useAltAsMultipleSelectionModifier(): boolean {
......
......@@ -30,7 +30,7 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { Iterator } from 'vs/base/common/iterator';
import { ITreeElement, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { debounceEvent, Relay } from 'vs/base/common/event';
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { WorkbenchObjectTree, ObjectTreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { IExpression, getEmptyExpression } from 'vs/base/common/glob';
import { mixin, deepClone } from 'vs/base/common/objects';
......@@ -325,10 +325,10 @@ export class MarkersPanel extends Panel {
// relatedInformationFocusContextKey.set(false);
// }));
// const markersNavigator = this._register(new TreeResourceNavigator(this.tree, { openOnFocus: true }));
// this._register(debounceEvent(markersNavigator.openResource, (last, event) => event, 75, true)(options => {
// this.openFileAtElement(options.element, options.editorOptions.preserveFocus, options.sideBySide, options.editorOptions.pinned);
// }));
const markersNavigator = this._register(new ObjectTreeResourceNavigator(this.tree, { openOnFocus: true }));
this._register(debounceEvent(markersNavigator.openResource, (last, event) => event, 75, true)(options => {
this.openFileAtElement(options.element, options.editorOptions.preserveFocus, options.sideBySide, options.editorOptions.pinned);
}));
}
// TODO@joao
......
......@@ -61,8 +61,9 @@ export class Controller extends WorkbenchTreeController {
return false;
}
// TODO@Joao
public onContextMenu(tree: WorkbenchTree, element: any, event: tree.ContextMenuEvent): boolean {
tree.setFocus(element, { preventOpenOnFocus: true });
tree.setFocus(element/* , { preventOpenOnFocus: true } */);
const anchor = { x: event.posx, y: event.posy };
this.contextMenuService.showContextMenu({
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册