Theia 属性视图

许多 IDE(例如传统的 Eclipse IDE)都具有全局、可扩展属性视图的概念,它显示IDE 中与当前选择有关 的附加信息。这些 IDE 中大量使用属性视图来显示元素的详细信息,例如图表编辑器、复杂树编辑器或文件资源管理器。主要思想是在 IDE 中拥有一个全局的、通用的属性视图,但允许特定的实现使用特定的附加信息来扩展全局属性视图的内容。

@theia/property-view 扩展提供了一个基于 Theia 全局选择的通用全局属性视图。属性视图组件可以通过菜单 View->Properties 或快捷键 Shift+Alt+P 打开/切换。它默认位于底部停靠区。

 

此扩展中实现了以下两个默认内容组件:

EmptyPropertyViewWidget:如果无法提供其他组件,则会显示一条简单消息(无可用属性)。
ResourcePropertyViewWidget:显示在文件资源管理器或monaco 编辑器中选中的文件的附加信息(例如位置、名称、上次修改时间)。


创建自定义属性视图

要提供特定的属性视图,必须实现一个 PropertyViewDataService 来收集选择的属性数据,以及一个 PropertyViewWidgetProvider ,它提供合适的内容组件来显示属性视图组件内特定选择的属性数据。

这是一个关于如何实现附加属性视图的简短示例,它根据文件资源管理器中的选择在简单的 React 组件中显示名称以及它是文件还是目录(假设没有 ResourcePropertyViewWidget):

FileInfoPropertyDataService 收集文件信息并提供自定义对象:

custom-data-service.ts:

export interface FileInfoPropertyObject {
    name: string;
    isDirectory: boolean;
}

@injectable()
export class FileInfoPropertyDataService implements PropertyDataService {

    readonly id = 'fileinfo';
    readonly label = 'FileInfoPropertyDataService';

    @inject(LabelProvider) protected readonly labelProvider: LabelProvider;

    canHandleSelection(selection: Object | undefined): number {
        return this.isFileSelection(selection) ? 1 : 0;
    }

    private isFileSelection(selection: Object | undefined): boolean {
        return !!selection && Array.isArray(selection) && FileSelection.is(selection[0]);
    }

    async providePropertyData(selection: Object | undefined): Promise<FileInfoPropertyObject | undefined> {
        if (this.isFileSelection(selection) && Array.isArray(selection)) {
            return {
                name: this.labelProvider.getName(selection[0].fileStat.resource),
                isDirectory: (selection[0].fileStat as FileStat).isDirectory
            };
        }
        return Promise.reject();
    }
}

 

FileInfoPropertyWidget 是一个简单的 React Widget 并显示所选节点以及它是文件还是目录:

custom-content-widget.tsx:

export class FileInfoPropertyViewWidget extends ReactWidget implements PropertyViewContentWidget {

    static readonly ID = 'file-info-property-view';
    static readonly LABEL = 'File Information';

    protected currentFileInfo: FileInfoPropertyObject;

    constructor() {
        super();
        this.id = FileInfoPropertyViewWidget.ID;
        this.title.label = FileInfoPropertyViewWidget.LABEL;
        this.title.caption = FileInfoPropertyViewWidget.LABEL;
        this.title.closable = false;
        this.node.tabIndex = 0;
    }

    updatePropertyViewContent(propertyDataService?: PropertyDataService, selection?: Object | undefined): void {
        if (propertyDataService) {
            propertyDataService.providePropertyData(selection).then((fileInfo: FileInfoPropertyObject) => this.currentFileInfo = fileInfo);
        }
        this.update();
    }

    protected render(): React.ReactNode {
        return (<div>
            {`Selected node in explorer: ${this.currentFileInfo.name} ${this.currentFileInfo.isDirectory ? '(Directory)' : '(File)'}`
    }
        </div>);
    }
}

FileInfoPropertyViewWidgetProvider 负责根据选择提供正确的 PropertyViewContentWidget:

custom-widget-provider.ts:

@injectable()
export class FileInfoPropertyViewWidgetProvider extends DefaultPropertyViewWidgetProvider {

    override readonly id = 'fileinfo';
    override readonly label = 'FileInfoPropertyViewWidgetProvider';

    private fileInfoWidget: FileInfoPropertyViewWidget;

    constructor() {
        super();
        this.fileInfoWidget = new FileInfoPropertyViewWidget();
    }

    override canHandle(selection: Object | undefined): number {
        return this.isFileSelection(selection) ? 1 : 0;
    }

    private isFileSelection(selection: Object | undefined): boolean {
        return !!selection && Array.isArray(selection) && FileSelection.is(selection[0]);
    }

    override provideWidget(selection: Object | undefined): Promise<FileInfoPropertyViewWidget> {
        return Promise.resolve(this.fileInfoWidget);
    }

    override updateContentWidget(selection: Object | undefined): void {
        this.getPropertyDataService(selection).then(service => this.fileInfoWidget.updatePropertyViewContent(service, selection));
    }
}

在应用程序的前端模块中,FileInfoPropertyDataService 以及 FileInfoPropertyViewWidgetProvider 注册如下:

bind(PropertyDataService).to(FileInfoPropertyDataService).inSingletonScope();
bind(PropertyViewWidgetProvider).to(FileInfoPropertyViewWidgetProvider).inSingletonScope();

遵循这几个步骤应该让读者了解如何实现自己的由特定的 PropertyViewWidgetProvider 和 PropertyViewDataService 组成的属性视图。

生成的属性视图将显示如下:

 

posted @ 2022-07-29 11:42  theiaide  阅读(195)  评论(0编辑  收藏  举报