diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ea9467d9b4c9..a3bf971f60ec0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ [Breaking Changes:](#breaking_changes_1.15.0) - [editor-preview] `EditorPreviewWidget` now extends `EditorWidget` and `EditorPreviewManager` extends and overrides `EditorManager`. `instanceof` checks can no longer distinguish between preview and non-preview editors; use `.isPreview` field instead. [#9518](https://github.com/eclipse-theia/theia/pull/9517) +- [core] `outline-view-tree.ts` has been renamed to `outline-view-tree-model.ts` to match class name. [#9583](https://github.com/eclipse-theia/theia/pull/9583) ## v1.14.0 - 5/27/2021 diff --git a/packages/core/src/browser/tree/tree-widget.tsx b/packages/core/src/browser/tree/tree-widget.tsx index 085f2a9f6df73..892d73b5e826a 100644 --- a/packages/core/src/browser/tree/tree-widget.tsx +++ b/packages/core/src/browser/tree/tree-widget.tsx @@ -99,6 +99,12 @@ export interface TreeProps { * `true` if a tree widget contributes to the global selection. Defaults to `false`. */ readonly globalSelection?: boolean; + + /** + * `true` if the tree widget supports expansion only when clicking the expansion toggle. Defaults to `false`. + */ + readonly expandOnlyOnExpansionToggleClick?: boolean; + } /** @@ -531,7 +537,13 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { const nodeId = event.currentTarget.getAttribute('data-node-id'); if (nodeId) { const node = this.model.getNode(nodeId); - this.handleClickEvent(node, event); + if (node && this.props.expandOnlyOnExpansionToggleClick) { + if (this.isExpandable(node) && !this.hasShiftMask(event) && !this.hasCtrlCmdMask(event)) { + this.model.toggleNodeExpansion(node); + } + } else { + this.handleClickEvent(node, event); + } } event.stopPropagation(); } @@ -557,7 +569,8 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { return
+ onClick={this.toggle} + onDoubleClick={this.handleExpansionToggleDblClickEvent}>
; } @@ -1123,9 +1136,9 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { */ protected handleClickEvent(node: TreeNode | undefined, event: React.MouseEvent): void { if (node) { + const shiftMask = this.hasShiftMask(event); + const ctrlCmdMask = this.hasCtrlCmdMask(event); if (!!this.props.multiSelect) { - const shiftMask = this.hasShiftMask(event); - const ctrlCmdMask = this.hasCtrlCmdMask(event); if (SelectableTreeNode.is(node)) { if (shiftMask) { this.model.selectRange(node); @@ -1135,14 +1148,13 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { this.model.selectNode(node); } } - if (this.isExpandable(node) && !shiftMask && !ctrlCmdMask) { - this.model.toggleNodeExpansion(node); - } } else { if (SelectableTreeNode.is(node)) { this.model.selectNode(node); } - if (this.isExpandable(node) && !this.hasCtrlCmdMask(event) && !this.hasShiftMask(event)) { + } + if (!this.props.expandOnlyOnExpansionToggleClick) { + if (this.isExpandable(node) && !shiftMask && !ctrlCmdMask) { this.model.toggleNodeExpansion(node); } } @@ -1191,6 +1203,17 @@ export class TreeWidget extends ReactWidget implements StatefulWidget { event.preventDefault(); } + /** + * Handle the double-click mouse event on the expansion toggle. + * @param event the double-click mouse event. + */ + protected handleExpansionToggleDblClickEvent(event: React.MouseEvent): void { + if (this.props.expandOnlyOnExpansionToggleClick) { + // Ignore the double-click event. + event.stopPropagation(); + } + } + /** * Convert the tree node to context menu arguments. * @param node the selectable tree node. diff --git a/packages/outline-view/src/browser/outline-view-frontend-module.ts b/packages/outline-view/src/browser/outline-view-frontend-module.ts index a8969c12f753b..a110da6fa61bc 100644 --- a/packages/outline-view/src/browser/outline-view-frontend-module.ts +++ b/packages/outline-view/src/browser/outline-view-frontend-module.ts @@ -34,7 +34,7 @@ import { OutlineViewWidgetFactory, OutlineViewWidget } from './outline-view-widg 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'; +import { OutlineViewTreeModel } from './outline-view-tree-model'; export default new ContainerModule(bind => { bind(OutlineViewWidgetFactory).toFactory(ctx => @@ -61,7 +61,7 @@ export default new ContainerModule(bind => { function createOutlineViewWidget(parent: interfaces.Container): OutlineViewWidget { const child = createTreeContainer(parent); - child.rebind(TreeProps).toConstantValue({ ...defaultTreeProps, search: true }); + child.rebind(TreeProps).toConstantValue({ ...defaultTreeProps, expandOnlyOnExpansionToggleClick: true, search: true }); child.unbind(TreeWidget); child.bind(OutlineViewWidget).toSelf(); diff --git a/packages/outline-view/src/browser/outline-view-tree.ts b/packages/outline-view/src/browser/outline-view-tree-model.ts similarity index 77% rename from packages/outline-view/src/browser/outline-view-tree.ts rename to packages/outline-view/src/browser/outline-view-tree-model.ts index d75dd4ad8c2a6..759d92ed5f7f7 100644 --- a/packages/outline-view/src/browser/outline-view-tree.ts +++ b/packages/outline-view/src/browser/outline-view-tree-model.ts @@ -15,7 +15,7 @@ ********************************************************************************/ import { injectable, inject } from '@theia/core/shared/inversify'; -import { CompositeTreeNode, TreeModelImpl, TreeExpansionService, ExpandableTreeNode } from '@theia/core/lib/browser'; +import { CompositeTreeNode, TreeModelImpl, TreeExpansionService, ExpandableTreeNode, TreeNode } from '@theia/core/lib/browser'; @injectable() export class OutlineViewTreeModel extends TreeModelImpl { @@ -39,4 +39,16 @@ export class OutlineViewTreeModel extends TreeModelImpl { } return false; } + + /** + * The default behavior of `openNode` calls `doOpenNode` which by default + * toggles the expansion of the node. Overriding to prevent expansion, but + * allow for the `onOpenNode` event to still fire on a double-click event. + */ + openNode(raw?: TreeNode | undefined): void { + const node = raw || this.selectedNodes[0]; + if (node) { + this.onOpenNodeEmitter.fire(node); + } + } } diff --git a/packages/outline-view/src/browser/outline-view-widget.tsx b/packages/outline-view/src/browser/outline-view-widget.tsx index 12ac92459eb86..b2a897b564759 100644 --- a/packages/outline-view/src/browser/outline-view-widget.tsx +++ b/packages/outline-view/src/browser/outline-view-widget.tsx @@ -25,7 +25,7 @@ import { TreeModel, ExpandableTreeNode } from '@theia/core/lib/browser'; -import { OutlineViewTreeModel } from './outline-view-tree'; +import { OutlineViewTreeModel } from './outline-view-tree-model'; import { Message } from '@theia/core/shared/@phosphor/messaging'; import { Emitter } from '@theia/core'; import { CompositeTreeNode } from '@theia/core/lib/browser';