Skip to content

Commit

Permalink
Add support for sub heading in view-container-part
Browse files Browse the repository at this point in the history
Signed-off-by: Aaron Rhodes <[email protected]>
  • Loading branch information
Aaron Rhodes authored and westbury committed Aug 31, 2021
1 parent 5abda1f commit 7442150
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 2 deletions.
9 changes: 9 additions & 0 deletions packages/core/src/browser/style/view-container.css
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,19 @@
}

.theia-view-container .part > .header .label {
flex: 0;
white-space: nowrap;
text-overflow: ellipsis;
}

.theia-view-container .part > .header .description {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding-left: var(--theia-ui-padding);
text-transform: none;
opacity: 0.6;
}

.theia-view-container .part > .body {
Expand Down
36 changes: 35 additions & 1 deletion packages/core/src/browser/view-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ export class ViewContainerIdentifier {
progressLocationId?: string;
}

export interface DescriptionWidget {
description: string;
onDidChangeDescription: Emitter<void>;
}

export namespace DescriptionWidget {
export function is(arg: Object | undefined): arg is DescriptionWidget {
return !!arg && typeof arg === 'object' && 'onDidChangeDescription' in arg;
}
}

/**
* A view container holds an arbitrary number of widgets inside a split panel.
* Each widget is wrapped in a _part_ that displays the widget title and toolbar
Expand Down Expand Up @@ -704,6 +715,8 @@ export class ViewContainerPart extends BaseWidget {
readonly onTitleChanged = this.onTitleChangedEmitter.event;
protected readonly onDidFocusEmitter = new Emitter<this>();
readonly onDidFocus = this.onDidFocusEmitter.event;
protected readonly onDidChangeDescriptionEmitter = new Emitter<void>();
readonly onDidChangeDescription = this.onDidChangeDescriptionEmitter.event;

protected readonly toolbar: TabBarToolbar;

Expand Down Expand Up @@ -732,6 +745,11 @@ export class ViewContainerPart extends BaseWidget {
this.wrapped.title.changed.connect(fireTitleChanged);
this.toDispose.push(Disposable.create(() => this.wrapped.title.changed.disconnect(fireTitleChanged)));

if (DescriptionWidget.is(this.wrapped)) {
const fireDescriptionChanged = () => this.onDidChangeDescriptionEmitter.fire(undefined);
this.toDispose.push(this.wrapped?.onDidChangeDescription.event(fireDescriptionChanged));
}

const { header, body, disposable } = this.createContent();
this.header = header;
this.body = body;
Expand All @@ -747,6 +765,7 @@ export class ViewContainerPart extends BaseWidget {
this.collapsedEmitter,
this.contextMenuEmitter,
this.onTitleChangedEmitter,
this.onDidChangeDescriptionEmitter,
this.registerContextMenu(),
this.onDidFocusEmitter,
// focus event does not bubble, capture it
Expand Down Expand Up @@ -892,15 +911,29 @@ export class ViewContainerPart extends BaseWidget {

const title = document.createElement('span');
title.classList.add('label', 'noselect');

const description = document.createElement('span');
description.classList.add('description');

const updateTitle = () => title.innerText = this.wrapped.title.label;
const updateCaption = () => title.title = this.wrapped.title.caption || this.wrapped.title.label;
const updateDescription = () => {
description.innerText = DescriptionWidget.is(this.wrapped) && !this.collapsed && this.wrapped.description || '';
};

updateTitle();
updateCaption();
updateDescription();

disposable.pushAll([
this.onTitleChanged(updateTitle),
this.onTitleChanged(updateCaption)
this.onTitleChanged(updateCaption),
this.onDidChangeDescription(updateDescription),
this.onCollapsed(updateDescription),
]);
header.appendChild(title);
header.appendChild(description);

return {
header,
disposable
Expand Down Expand Up @@ -998,6 +1031,7 @@ export namespace ViewContainerPart {
collapsed: boolean;
hidden: boolean;
relativeSize?: number;
description?: string;
}

export function closestPart(element: Element | EventTarget | null, selector: string = 'div.part'): Element | undefined {
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ export interface TreeViewsMain {
$reveal(treeViewId: string, elementParentChain: string[], options: TreeViewRevealOptions): Promise<any>;
$setMessage(treeViewId: string, message: string): void;
$setTitle(treeViewId: string, title: string): void;
$setDescription(treeViewId: string, description: string): void;
}

export interface TreeViewsExt {
Expand Down
16 changes: 15 additions & 1 deletion packages/plugin-ext/src/main/browser/view/plugin-view-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { ViewContextKeyService } from './view-context-key-service';
import { StatefulWidget } from '@theia/core/lib/browser/shell/shell-layout-restorer';
import { Message } from '@theia/core/shared/@phosphor/messaging';
import { TreeViewWidget } from './tree-view-widget';
import { DescriptionWidget } from '@theia/core/lib/browser/view-container';
import { Emitter } from '@theia/core/lib/common';

@injectable()
export class PluginViewWidgetIdentifier {
Expand All @@ -30,7 +32,7 @@ export class PluginViewWidgetIdentifier {
}

@injectable()
export class PluginViewWidget extends Panel implements StatefulWidget {
export class PluginViewWidget extends Panel implements StatefulWidget, DescriptionWidget {

@inject(MenuModelRegistry)
protected readonly menus: MenuModelRegistry;
Expand All @@ -50,6 +52,8 @@ export class PluginViewWidget extends Panel implements StatefulWidget {
this.node.style.height = '100%';
}

public onDidChangeDescription: Emitter<void> = new Emitter<void>();

@postConstruct()
protected init(): void {
this.id = this.options.id;
Expand Down Expand Up @@ -112,6 +116,16 @@ export class PluginViewWidget extends Panel implements StatefulWidget {
this.updateWidgetMessage();
}

private _description: string = '';
get description(): string {
return this._description;
}

set description(description: string) {
this._description = description;
this.onDidChangeDescription.fire();
}

private updateWidgetMessage(): void {
const widget = this.widgets[0];
if (widget) {
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-ext/src/main/browser/view/tree-views-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable {
}
}

async $setDescription(treeViewId: string, description: string): Promise<void> {
const viewPanel = await this.viewRegistry.getView(treeViewId);
if (viewPanel) {
viewPanel.description = description;
}
}

protected handleTreeEvents(treeViewId: string, treeViewWidget: TreeViewWidget): void {
this.toDispose.push(treeViewWidget.model.onExpansionChanged(event => {
this.proxy.$setExpanded(treeViewId, event.id, event.expanded);
Expand Down
16 changes: 16 additions & 0 deletions packages/plugin-ext/src/plugin/tree/tree-views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export class TreeViewsExtImpl implements TreeViewsExt {
set title(title: string) {
treeView.title = title;
},
get description(): string {
return treeView.description;
},
set description(description: string) {
treeView.description = description;
},
reveal: (element: T, revealOptions?: Partial<TreeViewRevealOptions>): Thenable<void> =>
treeView.reveal(element, revealOptions),

Expand Down Expand Up @@ -227,6 +233,16 @@ class TreeViewExtImpl<T> implements Disposable {
this.proxy.$setTitle(this.treeViewId, title);
}

private _description: string = '';
get description(): string {
return this._description;
}

set description(description: string) {
this._description = description;
this.proxy.$setDescription(this.treeViewId, this._description);
}

getTreeItem(treeItemId: string): T | undefined {
const element = this.nodes.get(treeItemId);
return element && element.value;
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4827,6 +4827,12 @@ declare module '@theia/plugin' {
*/
title?: string;

/**
* An optional human-readable subheading that will be rendered next to the main title.
* Setting the description to null, undefined, or empty string will remove the message from the view.
*/
description?: string;

/**
* Reveal an element. By default revealed element is selected.
*
Expand Down

0 comments on commit 7442150

Please sign in to comment.