Skip to content

Commit

Permalink
[tree] fix handling global selection
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <anton.kosyakov@typefox.io>

Signed-off-by: Doron Nahari doron.nahari@sap.com
  • Loading branch information
akosyakov committed Mar 29, 2019
1 parent 65178c3 commit d2b5a24
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 40 deletions.
37 changes: 37 additions & 0 deletions packages/core/src/browser/tree/tree-widget-selection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/********************************************************************************
* Copyright (C) 2019 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { TreeWidget } from './tree-widget';
import { SelectableTreeNode } from './tree-selection';

export type TreeWidgetSelection = ReadonlyArray<Readonly<SelectableTreeNode>> & {
source: TreeWidget
};
export namespace TreeWidgetSelection {
export function isSource(selection: Object | undefined, source: TreeWidget) {
return getSource(selection) === source;
}
export function getSource(selection: Object | undefined): TreeWidget | undefined {
return is(selection) ? selection.source : undefined;
}
export function is(selection: Object | undefined): selection is TreeWidgetSelection {
// tslint:disable-next-line:no-any
return Array.isArray(selection) && ('source' in selection) && <any>selection['source'] instanceof TreeWidget;
}
export function create(source: TreeWidget): TreeWidgetSelection {
return Object.assign(source.model.selectedNodes, { source });
}
}
33 changes: 32 additions & 1 deletion packages/core/src/browser/tree/tree-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { injectable, inject, postConstruct } from 'inversify';
import { Message } from '@phosphor/messaging';
import { Disposable, MenuPath } from '../../common';
import { Disposable, MenuPath, SelectionService } from '../../common';
import { Key, KeyCode, KeyModifier } from '../keys';
import { ContextMenuRenderer } from '../context-menu-renderer';
import { StatefulWidget } from '../shell';
Expand All @@ -35,6 +35,7 @@ import { TopDownTreeIterator } from './tree-iterator';
import { SearchBox, SearchBoxFactory, SearchBoxProps } from './search-box';
import { TreeSearch } from './tree-search';
import { ElementExt } from '@phosphor/domutils';
import { TreeWidgetSelection } from './tree-widget-selection';

const debounce = require('lodash.debounce');

Expand Down Expand Up @@ -83,6 +84,11 @@ export interface TreeProps {
* 'true' if the selected node should be auto scrolled only if the widget is active. Otherwise, `false`. Defaults to `false`.
*/
readonly scrollIfActive?: boolean

/**
* `true` if a tree widget contributes to the global selection. Defaults to `false`.
*/
readonly globalSelection?: boolean;
}

export interface NodeProps {
Expand Down Expand Up @@ -126,6 +132,9 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {

protected decorations: Map<string, TreeDecoration.Data[]> = new Map();

@inject(SelectionService)
protected readonly selectionService: SelectionService;

constructor(
@inject(TreeProps) readonly props: TreeProps,
@inject(TreeModel) readonly model: TreeModel,
Expand Down Expand Up @@ -179,6 +188,25 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {
this.updateRows();
this.updateDecorations();
});
if (this.props.globalSelection) {
this.toDispose.pushAll([
this.model.onSelectionChanged(() => {
if (this.node.contains(document.activeElement)) {
this.updateGlobalSelection();
}
}),
Disposable.create(() => {
const selection = this.selectionService.selection;
if (TreeWidgetSelection.isSource(selection, this)) {
this.selectionService.selection = undefined;
}
})
]);
}
}

protected updateGlobalSelection(): void {
this.selectionService.selection = TreeWidgetSelection.create(this);
}

protected rows = new Map<string, TreeWidget.NodeRow>();
Expand Down Expand Up @@ -244,6 +272,9 @@ export class TreeWidget extends ReactWidget implements StatefulWidget {

protected onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
if (this.props.globalSelection) {
this.updateGlobalSelection();
}
this.node.focus();
if (this.model.selectedNodes.length === 0) {
const root = this.model.root;
Expand Down
3 changes: 2 additions & 1 deletion packages/navigator/src/browser/navigator-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export const FILE_NAVIGATOR_PROPS = <TreeProps>{
...defaultTreeProps,
contextMenuPath: NAVIGATOR_CONTEXT_MENU,
multiSelect: true,
search: true
search: true,
globalSelection: true
};

export function createFileNavigatorContainer(parent: interfaces.Container): Container {
Expand Down
22 changes: 5 additions & 17 deletions packages/navigator/src/browser/navigator-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { injectable, inject, postConstruct } from 'inversify';
import { Message } from '@phosphor/messaging';
import URI from '@theia/core/lib/common/uri';
import { CommandService, SelectionService, Disposable } from '@theia/core/lib/common';
import { CommandService, SelectionService } from '@theia/core/lib/common';
import { CommonCommands, CorePreferences } from '@theia/core/lib/browser';
import {
ContextMenuRenderer, ExpandableTreeNode,
Expand Down Expand Up @@ -71,33 +71,21 @@ export class FileNavigatorWidget extends FileTreeWidget {
super.init();
this.updateSelectionContextKeys();
this.toDispose.pushAll([
this.model.onSelectionChanged(selection => {
if (this.shell.activeWidget === this) {
this.selectionService.selection = selection;
}
this.updateSelectionContextKeys();
}),
this.model.onSelectionChanged(() =>
this.updateSelectionContextKeys()
),
this.model.onExpansionChanged(node => {
if (node.expanded && node.children.length === 1) {
const child = node.children[0];
if (ExpandableTreeNode.is(child) && !child.expanded) {
this.model.expandNode(child);
}
}
}),
Disposable.create(() => {
if (this.selectionService.selection === this) {
this.selectionService.selection = undefined;
}

})
]);
}

protected onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
this.selectionService.selection = this.model.selectedNodes;
}

protected async initialize(): Promise<void> {
await this.model.updateRoot();
const root = this.model.root;
Expand Down
24 changes: 3 additions & 21 deletions packages/plugin-ext/src/main/browser/view/tree-views-main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { MenuPath } from '@theia/core/lib/common/menu';
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { ContextKeyService, ContextKey } from '@theia/core/lib/browser/context-key-service';
import { Disposable, SelectionService } from '@theia/core/lib/common';
import { SelectionService } from '@theia/core/lib/common';

export const TREE_NODE_HYPERLINK = 'theia-TreeNodeHyperlink';
export const VIEW_ITEM_CONTEXT_MENU: MenuPath = ['view-item-context-menu'];
Expand Down Expand Up @@ -105,7 +105,8 @@ export class TreeViewsMainImpl implements TreeViewsMain {

createTreeViewContainer(dataProvider: TreeViewDataProviderMain): Container {
const child = createTreeContainer(this.container, {
contextMenuPath: VIEW_ITEM_CONTEXT_MENU
contextMenuPath: VIEW_ITEM_CONTEXT_MENU,
globalSelection: true
});

child.bind(TreeViewDataProviderMain).toConstantValue(dataProvider);
Expand Down Expand Up @@ -228,21 +229,7 @@ export class TreeViewWidget extends TreeWidget {
@inject(ContextMenuRenderer) readonly contextMenuRenderer: ContextMenuRenderer,
@inject(TreeViewDataProviderMain) readonly dataProvider: TreeViewDataProviderMain,
@inject(SelectionService) readonly selectionService: SelectionService) {

super(treeProps, model, contextMenuRenderer);

this.toDispose.pushAll([
this.model.onSelectionChanged(selection => {
if (this.node.contains(document.activeElement)) {
this.selectionService.selection = selection;
}
}),
Disposable.create(() => {
if (this.selectionService.selection === this.model.selectedNodes) {
this.selectionService.selection = undefined;
}
})
]);
}

protected onAfterAttach(msg: Message): void {
Expand All @@ -264,11 +251,6 @@ export class TreeViewWidget extends TreeWidget {
});
}

protected onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
this.selectionService.selection = this.model.selectedNodes;
}

public updateWidget() {
this.updateRows();

Expand Down

0 comments on commit d2b5a24

Please sign in to comment.