Skip to content

Commit

Permalink
Fixed #5670: implemented "collapse all" in the Outline widget
Browse files Browse the repository at this point in the history
- Added a "collapse all" toolbar item to the Outline widget.
- Created `OutlineViewTreeModel` class in order to override the default `collapseAll` function and `onExpansionChanged` event handler in the default tree model.

Signed-off-by: fangnx <naxin.fang@ericsson.com>
  • Loading branch information
fangnx authored and fangnx committed Aug 7, 2019
1 parent bd04424 commit d5d8eac
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [task] fixed the problem where a detected task can be customized more than once [#5777](https://github.com/theia-ide/theia/pull/5777)
- [task] displayed the customized tasks as "configured tasks" in the task quick open [#5777](https://github.com/theia-ide/theia/pull/5777)
- [task] allowed users to override any task properties other than the ones used in the task definition [#5777](https://github.com/theia-ide/theia/pull/5777)
- [outline] added `OutlineViewTreeModel` for the outline view tree widget [#5687](https://github.com/theia-ide/theia/pull/5687)

Breaking changes:

Expand Down
21 changes: 16 additions & 5 deletions packages/core/src/browser/tree/tree-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,7 @@ export class TreeModelImpl implements TreeModel, SelectionProvider<ReadonlyArray
this.toDispose.push(this.expansionService);
this.toDispose.push(this.expansionService.onExpansionChanged(node => {
this.fireChanged();
if (!node.expanded && [...this.selectedNodes].some(selectedNode => CompositeTreeNode.isAncestor(node, selectedNode))) {
if (SelectableTreeNode.isVisible(node)) {
this.selectNode(node);
}
}
this.handleExpansion(node);
}));

this.toDispose.push(this.onOpenNodeEmitter);
Expand All @@ -173,6 +169,21 @@ export class TreeModelImpl implements TreeModel, SelectionProvider<ReadonlyArray
this.toDispose.dispose();
}

protected handleExpansion(node: Readonly<ExpandableTreeNode>): void {
this.selectIfAncestorOfSelected(node);
}

/**
* Select the given node if it is the ancestor of a selected node.
*/
protected selectIfAncestorOfSelected(node: Readonly<ExpandableTreeNode>): void {
if (!node.expanded && [...this.selectedNodes].some(selectedNode => CompositeTreeNode.isAncestor(node, selectedNode))) {
if (SelectableTreeNode.isVisible(node)) {
this.selectNode(node);
}
}
}

get root(): TreeNode | undefined {
return this.tree.root;
}
Expand Down
51 changes: 49 additions & 2 deletions packages/outline-view/src/browser/outline-view-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@

import { injectable } from 'inversify';
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
import { OutlineViewWidget } from './outline-view-widget';
import { FrontendApplicationContribution, FrontendApplication } from '@theia/core/lib/browser/frontend-application';
import { Command, CommandRegistry } from '@theia/core/lib/common/command';
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { Widget } from '@theia/core/lib/browser/widgets';
import { OutlineViewWidget } from './outline-view-widget';
import { CompositeTreeNode } from '@theia/core/lib/browser/tree';

export const OUTLINE_WIDGET_FACTORY_ID = 'outline-view';

export namespace OutlineViewCommands {
export const COLLAPSE_ALL: Command = {
id: 'outlineView.collapse.all',
iconClass: 'collapse-all'
};
}

@injectable()
export class OutlineViewContribution extends AbstractViewContribution<OutlineViewWidget> implements FrontendApplicationContribution {
export class OutlineViewContribution extends AbstractViewContribution<OutlineViewWidget> implements FrontendApplicationContribution, TabBarToolbarContribution {

constructor() {
super({
Expand All @@ -40,4 +51,40 @@ export class OutlineViewContribution extends AbstractViewContribution<OutlineVie
async initializeLayout(app: FrontendApplication): Promise<void> {
await this.openView();
}

registerCommands(commands: CommandRegistry): void {
super.registerCommands(commands);
commands.registerCommand(OutlineViewCommands.COLLAPSE_ALL, {
isEnabled: widget => this.withWidget(widget, () => true),
isVisible: widget => this.withWidget(widget, () => true),
execute: () => this.collapseAllItems()
});
}

registerToolbarItems(toolbar: TabBarToolbarRegistry): void {
toolbar.registerItem({
id: OutlineViewCommands.COLLAPSE_ALL.id,
command: OutlineViewCommands.COLLAPSE_ALL.id,
tooltip: 'Collapse All',
priority: 0
});
}

/**
* Collapse all nodes in the outline view tree.
*/
protected async collapseAllItems(): Promise<void> {
const { model } = await this.widget;
const root = model.root;
if (CompositeTreeNode.is(root)) {
model.collapseAll(root);
}
}

protected withWidget<T>(widget: Widget | undefined = this.tryGetWidget(), cb: (widget: OutlineViewWidget) => T): T | false {
if (widget instanceof OutlineViewWidget && widget.id === OUTLINE_WIDGET_FACTORY_ID) {
return cb(widget);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ import {
bindViewContribution,
TreeProps,
defaultTreeProps,
TreeDecoratorService
TreeDecoratorService,
TreeModel,
TreeModelImpl
} from '@theia/core/lib/browser';
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { OutlineViewWidgetFactory, OutlineViewWidget } from './outline-view-widget';
import '../../src/browser/styles/index.css';
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
import { OutlineDecoratorService, OutlineTreeDecorator } from './outline-decorator-service';
import { OutlineViewTreeModel } from './outline-view-tree';

export default new ContainerModule(bind => {
bind(OutlineViewWidgetFactory).toFactory(ctx =>
Expand All @@ -42,6 +46,7 @@ export default new ContainerModule(bind => {

bindViewContribution(bind, OutlineViewContribution);
bind(FrontendApplicationContribution).toService(OutlineViewContribution);
bind(TabBarToolbarContribution).toService(OutlineViewContribution);
});

function createOutlineViewWidget(parent: interfaces.Container): OutlineViewWidget {
Expand All @@ -52,6 +57,10 @@ function createOutlineViewWidget(parent: interfaces.Container): OutlineViewWidge
child.unbind(TreeWidget);
child.bind(OutlineViewWidget).toSelf();

child.unbind(TreeModelImpl);
child.bind(OutlineViewTreeModel).toSelf();
child.rebind(TreeModel).toService(OutlineViewTreeModel);

child.bind(OutlineDecoratorService).toSelf().inSingletonScope();
child.rebind(TreeDecoratorService).toDynamicValue(ctx => ctx.container.get(OutlineDecoratorService)).inSingletonScope();
bindContributionProvider(child, OutlineTreeDecorator);
Expand Down
36 changes: 36 additions & 0 deletions packages/outline-view/src/browser/outline-view-tree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/********************************************************************************
* Copyright (C) 2019 Ericsson 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 { injectable, inject } from 'inversify';
import { CompositeTreeNode, TreeModelImpl, TreeExpansionService, ExpandableTreeNode } from '@theia/core/lib/browser';

@injectable()
export class OutlineViewTreeModel extends TreeModelImpl {

@inject(TreeExpansionService) protected readonly expansionService: TreeExpansionService;

protected handleExpansion(node: Readonly<ExpandableTreeNode>): void {
// Do not select anything in order to preserve focus on the editor.
}

async collapseAll(raw?: Readonly<CompositeTreeNode>): Promise<boolean> {
const node = raw || this.selectedNodes[0];
if (CompositeTreeNode.is(node)) {
return this.expansionService.collapseAll(node);
}
return false;
}
}
3 changes: 2 additions & 1 deletion packages/outline-view/src/browser/outline-view-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
TreeModel,
ExpandableTreeNode
} from '@theia/core/lib/browser';
import { OutlineViewTreeModel } from './outline-view-tree';
import { Message } from '@phosphor/messaging';
import { Emitter } from '@theia/core';
import { CompositeTreeNode } from '@theia/core/lib/browser';
Expand All @@ -50,7 +51,7 @@ export class OutlineViewWidget extends TreeWidget {

constructor(
@inject(TreeProps) protected readonly treeProps: TreeProps,
@inject(TreeModel) model: TreeModel,
@inject(OutlineViewTreeModel) model: OutlineViewTreeModel,
@inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer
) {
super(treeProps, model, contextMenuRenderer);
Expand Down

0 comments on commit d5d8eac

Please sign in to comment.