提交 f9460332 编写于 作者: S Sandeep Somavarapu

Fix #41535

上级 4b55cf7b
......@@ -151,7 +151,7 @@ export class WorkbenchPagedList<T> extends PagedList<T> {
export class WorkbenchTree extends Tree {
readonly contextKeyService: IContextKeyService;
private disposables: IDisposable[] = [];
protected disposables: IDisposable[] = [];
private listDoubleSelection: IContextKey<boolean>;
constructor(
......
......@@ -6,6 +6,7 @@
import { localize } from 'vs/nls';
import * as vscode from 'vscode';
import { basename } from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { debounceEvent } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
......@@ -189,6 +190,7 @@ class ExtHostTreeView<T> extends Disposable {
handle,
parentHandle,
label: extensionTreeItem.label,
resourceUri: extensionTreeItem.resourceUri,
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0,
contextValue: extensionTreeItem.contextValue,
icon,
......@@ -197,17 +199,18 @@ class ExtHostTreeView<T> extends Disposable {
};
}
private createHandle(element: T, { label }: vscode.TreeItem, parentHandle?: TreeItemHandle): TreeItemHandle {
private createHandle(element: T, { label, resourceUri }: vscode.TreeItem, parentHandle?: TreeItemHandle): TreeItemHandle {
if (typeof element === 'string') {
return `${ExtHostTreeView.ID_HANDLE_PREFIX}/${element}`;
}
const prefix = parentHandle ? parentHandle : ExtHostTreeView.LABEL_HANDLE_PREFIX;
label = label.indexOf('/') !== -1 ? label.replace('/', '//') : label;
let elementId = label ? label : basename(resourceUri.path);
elementId = elementId.indexOf('/') !== -1 ? elementId.replace('/', '//') : elementId;
const existingHandle = this.nodes.has(element) ? this.nodes.get(element).handle : void 0;
for (let labelCount = 0; labelCount <= this.getChildrenHandles(parentHandle).length; labelCount++) {
const handle = `${prefix}/${labelCount}:${label}`;
for (let counter = 0; counter <= this.getChildrenHandles(parentHandle).length; counter++) {
const handle = `${prefix}/${counter}:${elementId}`;
if (!this.elements.has(handle) || existingHandle === handle) {
return handle;
}
......
......@@ -3,24 +3,78 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.custom-view-tree-node-item {
/* File icon themeable tree style */
.file-icon-themable-tree .monaco-tree-row .content {
display: flex;
height: 22px;
line-height: 22px;
}
.custom-view-tree-node-item > .custom-view-tree-node-item-icon {
.file-icon-themable-tree .monaco-tree-row .content::before {
background-size: 16px;
background-position: left center;
background-position: 50% 50%;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
-webkit-font-smoothing: antialiased;
display: inline-block;
vertical-align: top;
content: ' ';
}
.file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before {
display: none;
}
.file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded.svg");
}
.file-icon-themable-tree .monaco-tree-row.has-children .content::before {
display: inline-block;
background-image: url("collapsed.svg");
}
.vs-dark .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded-dark.svg");
}
.vs-dark .file-icon-themable-tree .monaco-tree-row.has-children .content::before {
background-image: url("collapsed-dark.svg");
}
.hc-black .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded-hc.svg");
}
.hc-black .file-icon-themable-tree .monaco-tree-row.has-children .content::before {
background-image: url("collapsed-hc.svg");
}
.file-icon-themable-tree.hide-arrows .monaco-tree-row .content::before {
display: none;
}
.custom-view-tree-node-item {
display: flex;
height: 22px;
line-height: 22px;
}
.custom-view-tree-node-item > .custom-view-tree-node-item-resourceLabel {
flex: 1;
}
.custom-view-tree-node-item > .custom-view-tree-node-item-label {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
}
.custom-view-tree-node-item > .custom-view-tree-node-item-icon {
background-size: 16px;
background-position: left center;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
-webkit-font-smoothing: antialiased;
}
\ No newline at end of file
......@@ -24,10 +24,15 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { TreeViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IViewletViewOptions, IViewOptions, TreeViewsViewletPanel, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { TreeItemCollapsibleState, ITreeItem, ITreeViewDataProvider, TreeViewItemHandleArg } from 'vs/workbench/common/views';
import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import URI from 'vs/base/common/uri';
import { basename } from 'vs/base/common/paths';
import { FileKind } from 'vs/platform/files/common/files';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
export class TreeView extends TreeViewsViewletPanel {
......@@ -45,7 +50,7 @@ export class TreeView extends TreeViewsViewletPanel {
@IContextMenuService contextMenuService: IContextMenuService,
@IInstantiationService private instantiationService: IInstantiationService,
@IListService private listService: IListService,
@IThemeService private themeService: IThemeService,
@IThemeService private themeService: IWorkbenchThemeService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IExtensionService private extensionService: IExtensionService,
@ICommandService private commandService: ICommandService
......@@ -53,7 +58,7 @@ export class TreeView extends TreeViewsViewletPanel {
super({ ...(options as IViewOptions), ariaHeaderLabel: options.name }, keybindingService, contextMenuService);
this.menus = this.instantiationService.createInstance(Menus, this.id);
this.menus.onDidChangeTitle(() => this.updateActions(), this, this.disposables);
this.themeService.onThemeChange(() => this.tree.refresh() /* soft refresh */, this, this.disposables);
themeService.onThemeChange(() => this.tree.refresh() /* soft refresh */, this, this.disposables);
if (options.expanded) {
this.activate();
}
......@@ -87,7 +92,7 @@ export class TreeView extends TreeViewsViewletPanel {
const dataSource = this.instantiationService.createInstance(TreeDataSource, this.id);
const renderer = this.instantiationService.createInstance(TreeRenderer);
const controller = this.instantiationService.createInstance(TreeController, this.id, this.menus);
const tree = new WorkbenchTree(
const tree = new FileIconThemableWorkbenchTree(
container.getHTMLElement(),
{ dataSource, renderer, controller },
{ keyboardSupport: false },
......@@ -263,8 +268,9 @@ class TreeDataSource implements IDataSource {
}
interface ITreeExplorerTemplateData {
icon: Builder;
label: Builder;
label: HTMLElement;
resourceLabel: ResourceLabel;
icon: HTMLElement;
}
class TreeRenderer implements IRenderer {
......@@ -272,7 +278,10 @@ class TreeRenderer implements IRenderer {
private static readonly ITEM_HEIGHT = 22;
private static readonly TREE_TEMPLATE_ID = 'treeExplorer';
constructor( @IThemeService private themeService: IThemeService) {
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService
) {
}
public getHeight(tree: ITree, element: any): number {
......@@ -284,33 +293,43 @@ class TreeRenderer implements IRenderer {
}
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): ITreeExplorerTemplateData {
const el = $(container);
const item = $('.custom-view-tree-node-item');
item.appendTo(el);
const el = DOM.append(container, DOM.$('.custom-view-tree-node-item'));
const icon = $('.custom-view-tree-node-item-icon').appendTo(item);
const label = $('.custom-view-tree-node-item-label').appendTo(item);
const link = $('a.label').appendTo(label);
const icon = DOM.append(el, DOM.$('.custom-view-tree-node-item-icon'));
const label = DOM.append(el, DOM.$('.custom-view-tree-node-item-label'));
const resourceLabelContainer = DOM.append(el, DOM.$('.custom-view-tree-node-item-resourceLabelContainer'));
const resourceLabel = this.instantiationService.createInstance(ResourceLabel, resourceLabelContainer, { supportHighlights: true });
return { label: link, icon };
return { label, resourceLabel, icon };
}
public renderElement(tree: ITree, node: ITreeItem, templateId: string, templateData: ITreeExplorerTemplateData): void {
templateData.label.text(node.label).title(node.label);
const resource = node.resourceUri ? URI.revive(node.resourceUri) : null;
const name = node.label || basename(resource.path);
const theme = this.themeService.getTheme();
const icon = theme.type === LIGHT ? node.icon : node.iconDark;
if (icon) {
templateData.icon.getHTMLElement().style.backgroundImage = `url('${icon}')`;
DOM.addClass(templateData.icon.getHTMLElement(), 'custom-view-tree-node-item-icon');
templateData.resourceLabel.clear();
templateData.label.textContent = '';
DOM.removeClass(templateData.label, 'custom-view-tree-node-item-label');
DOM.removeClass(templateData.resourceLabel.element, 'custom-view-tree-node-item-resourceLabel');
DOM.removeClass(templateData.icon, 'custom-view-tree-node-item-icon');
if (resource && !icon) {
templateData.resourceLabel.setLabel({ name, resource }, { fileKind: node.collapsibleState === TreeItemCollapsibleState.Collapsed || node.collapsibleState === TreeItemCollapsibleState.Expanded ? FileKind.FOLDER : FileKind.FILE });
DOM.addClass(templateData.resourceLabel.element, 'custom-view-tree-node-item-resourceLabel');
} else {
templateData.icon.getHTMLElement().style.backgroundImage = '';
DOM.removeClass(templateData.icon.getHTMLElement(), 'custom-view-tree-node-item-icon');
templateData.label.textContent = name;
DOM.addClass(templateData.label, 'custom-view-tree-node-item-label');
templateData.icon.style.backgroundImage = `url('${icon}')`;
if (icon) {
DOM.addClass(templateData.icon, 'custom-view-tree-node-item-icon');
}
}
}
public disposeTemplate(tree: ITree, templateId: string, templateData: ITreeExplorerTemplateData): void {
templateData.resourceLabel.dispose();
}
}
......
......@@ -27,7 +27,9 @@ import { IContextKeyService, IContextKeyChangeEvent } from 'vs/platform/contextk
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IPanelOptions } from 'vs/base/browser/ui/splitview/panelview';
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService';
import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree';
export interface IViewOptions extends IPanelOptions {
id: string;
......@@ -96,14 +98,12 @@ export abstract class ViewsViewletPanel extends ViewletPanel {
}
// TODO@isidor @sandeep remove this class
export abstract class TreeViewsViewletPanel extends ViewsViewletPanel {
readonly id: string;
readonly name: string;
protected treeContainer: HTMLElement;
// TODO@sandeep why is tree here? isn't this coming only from TreeView
protected tree: WorkbenchTree;
protected isDisposed: boolean;
private dragHandler: DelayedDragHandler;
......@@ -722,3 +722,28 @@ export class PersistentViewsViewlet extends ViewsViewlet {
Object.keys(viewsStates).forEach(id => this.viewsStates.set(id, <IViewState>viewsStates[id]));
}
}
export class FileIconThemableWorkbenchTree extends WorkbenchTree {
constructor(
container: HTMLElement,
configuration: ITreeConfiguration,
options: ITreeOptions,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@IThemeService themeService: IWorkbenchThemeService
) {
super(container, configuration, { ...options, ...{ showTwistie: false, twistiePixels: 12 } }, contextKeyService, listService, themeService);
DOM.addClass(container, 'file-icon-themable-tree');
DOM.addClass(container, 'show-file-icons');
const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => {
DOM.toggleClass(container, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons);
DOM.toggleClass(container, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true);
};
this.disposables.push(themeService.onDidFileIconThemeChange(onFileIconThemeChange));
onFileIconThemeChange(themeService.getFileIconTheme());
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
import { Command } from 'vs/editor/common/modes';
import { UriComponents } from 'vs/base/common/uri';
export type TreeViewItemHandleArg = {
$treeViewId: string,
......@@ -24,12 +25,14 @@ export interface ITreeItem {
parentHandle: string;
label: string;
label?: string;
icon?: string;
iconDark?: string;
resourceUri?: UriComponents;
contextValue?: string;
command?: Command;
......
......@@ -58,55 +58,6 @@
display: none;
}
.explorer-folders-view .monaco-tree-row .content {
display: flex;
}
.explorer-folders-view .monaco-tree-row .content::before {
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
display: inline-block;
vertical-align: top;
content: ' ';
}
.explorer-folders-view.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before {
display: none;
}
.explorer-folders-view .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded.svg");
}
.explorer-folders-view .monaco-tree-row.has-children .content::before {
display: inline-block;
background-image: url("collapsed.svg");
}
.vs-dark .explorer-folders-view .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded-dark.svg");
}
.vs-dark .explorer-folders-view .monaco-tree-row.has-children .content::before {
background-image: url("collapsed-dark.svg");
}
.hc-black .explorer-folders-view .monaco-tree-row.has-children.expanded .content::before {
background-image: url("expanded-hc.svg");
}
.hc-black .explorer-folders-view .monaco-tree-row.has-children .content::before {
background-image: url("collapsed-hc.svg");
}
.explorer-folders-view.hide-arrows .monaco-tree-row .content::before {
display: none;
}
.explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row:hover > .monaco-action-bar,
.explorer-viewlet .explorer-open-editors .monaco-list.focused .monaco-list-row.focused > .monaco-action-bar,
.explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row.dirty > .monaco-action-bar {
......
......@@ -24,7 +24,7 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import * as DOM from 'vs/base/browser/dom';
import { CollapseAction } from 'vs/workbench/browser/viewlet';
import { TreeViewsViewletPanel, IViewletViewOptions, IViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IViewletViewOptions, IViewOptions, TreeViewsViewletPanel, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IPartService } from 'vs/workbench/services/part/common/partService';
......@@ -39,7 +39,7 @@ import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ResourceContextKey } from 'vs/workbench/common/resources';
import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources';
import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { isLinux } from 'vs/base/common/platform';
import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations';
import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService';
......@@ -156,7 +156,6 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
public renderBody(container: HTMLElement): void {
this.treeContainer = super.renderViewTree(container);
DOM.addClass(this.treeContainer, 'explorer-folders-view');
DOM.addClass(this.treeContainer, 'show-file-icons');
this.tree = this.createViewer($(this.treeContainer));
......@@ -164,15 +163,8 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
this.toolbar.setActions(this.getActions(), this.getSecondaryActions())();
}
const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => {
DOM.toggleClass(this.treeContainer, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons);
DOM.toggleClass(this.treeContainer, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true);
};
this.disposables.push(this.themeService.onDidFileIconThemeChange(onFileIconThemeChange));
this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(e => this.refreshFromEvent(e.added)));
this.disposables.push(this.contextService.onDidChangeWorkbenchState(e => this.refreshFromEvent()));
onFileIconThemeChange(this.themeService.getFileIconTheme());
}
public getActions(): IAction[] {
......@@ -404,7 +396,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
const dnd = this.instantiationService.createInstance(FileDragAndDrop);
const accessibilityProvider = this.instantiationService.createInstance(FileAccessibilityProvider);
this.explorerViewer = new WorkbenchTree(container.getHTMLElement(), {
this.explorerViewer = new FileIconThemableWorkbenchTree(container.getHTMLElement(), {
dataSource,
renderer,
controller,
......@@ -415,8 +407,6 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
}, {
autoExpandSingleChildren: true,
ariaLabel: nls.localize('treeAriaLabel', "Files Explorer"),
twistiePixels: 12,
showTwistie: false,
keyboardSupport: false
}, this.contextKeyService, this.listService, this.themeService);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册