/******************************************************************************** * 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 { Title } from '@phosphor/widgets'; import { AttachedProperty } from '@phosphor/properties'; import { DockPanel, Menu, TabBar, Widget } from '@phosphor/widgets'; import { CommandRegistry } from '@phosphor/commands'; import { VirtualElement, h } from '@phosphor/virtualdom'; import { PreferenceScope } from '@devpodio/core/lib/browser'; import { EditorWidget } from '@devpodio/editor/lib/browser'; import { WorkspaceService } from '@devpodio/workspace/lib/browser/workspace-service'; import URI from '@devpodio/core/lib/common/uri'; import { FileAccess, FileSystem } from '@devpodio/filesystem/lib/common'; export class PreferencesEditorWidgetTitle extends Title { clickableText?: string; clickableTextTooltip?: string; clickableTextCallback?: (value: string) => void; } export class PreferencesEditorWidget extends EditorWidget { scope: PreferenceScope | undefined; get title(): PreferencesEditorWidgetTitle { return new AttachedProperty({ name: 'title', create: owner => new PreferencesEditorWidgetTitle({ owner }), }).get(this); } } export class PreferenceEditorTabHeaderRenderer extends TabBar.Renderer { constructor( private readonly workspaceService: WorkspaceService, private readonly fileSystem: FileSystem ) { super(); } renderTab(data: TabBar.IRenderData): VirtualElement { const title = data.title; const key = this.createTabKey(data); const style = this.createTabStyle(data); const className = this.createTabClass(data); return h.li({ key, className, title: title.caption, style }, this.renderIcon(data), this.renderLabel(data), this.renderCloseIcon(data) ); } renderLabel(data: TabBar.IRenderData): VirtualElement { const clickableTitle = data.title.owner.title; if (clickableTitle.clickableText) { return h.div( h.span({ className: 'p-TabBar-tabLabel' }, data.title.label), h.span({ className: 'p-TabBar-tabLabel p-TabBar-tab-secondary-label', title: clickableTitle.clickableTextTooltip, onclick: event => { const editorUri = data.title.owner.editor.uri; this.refreshContextMenu(editorUri.parent.parent.toString(), clickableTitle.clickableTextCallback || (() => { })) .then(menu => menu.open(event.x, event.y)); } }, clickableTitle.clickableText) ); } return super.renderLabel(data); } protected async refreshContextMenu(activeMenuId: string, menuItemAction: (value: string) => void): Promise { const commands = new CommandRegistry(); const menu = new Menu({ commands }); const roots = this.workspaceService.tryGetRoots().map(r => r.uri); for (const root of roots) { if (await this.canAccessSettings(root)) { const commandId = `switch_folder_pref_editor_to_${root}`; if (!commands.hasCommand(commandId)) { const rootUri = new URI(root); const isActive = rootUri.toString() === activeMenuId; commands.addCommand(commandId, { label: rootUri.displayName, iconClass: isActive ? 'fa fa-check' : '', execute: () => { if (!isActive) { menuItemAction(root); } } }); } menu.addItem({ type: 'command', command: commandId }); } } return menu; } private async canAccessSettings(folderUriStr: string): Promise { const folderUri = new URI(folderUriStr); const settingsUriStr = folderUri.resolve('.theia').resolve('settings.json').toString(); if (await this.fileSystem.exists(settingsUriStr)) { return this.fileSystem.access(settingsUriStr, FileAccess.Constants.R_OK); } return this.fileSystem.access(folderUriStr, FileAccess.Constants.W_OK); } } export class PreferenceEditorContainerTabBarRenderer extends DockPanel.Renderer { constructor( private readonly workspaceService: WorkspaceService, private readonly fileSystem: FileSystem ) { super(); } createTabBar(): TabBar { const bar = new TabBar({ renderer: new PreferenceEditorTabHeaderRenderer(this.workspaceService, this.fileSystem) }); bar.addClass('p-DockPanel-tabBar'); return bar; } }