/********************************************************************************
 * Copyright (C) 2020 EclipseSource 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 { ContextMenuRenderer , LabelProvider , NodeProps , TreeModel , TreeNode , TreeProps , TreeWidget } from '@theia/core/lib/browser' ; import { FileStat } from '@theia/filesystem/lib/common/files' ; import { inject , injectable , postConstruct } from '@theia/core/shared/inversify' ; import * as React from '@theia/core/shared/react' ; import { PropertyDataService } from '../property-data-service' ; import { PropertyViewContentWidget } from '../property-view-content-widget' ; import { ResourcePropertiesCategoryNode , ResourcePropertiesItemNode , ResourcePropertiesRoot , ROOT_ID } from './resource-property-view-tree-items' ; import { nls } from '@theia/core/lib/common/nls' ; @ injectable ( ) export class ResourcePropertyViewTreeWidget extends TreeWidget implements PropertyViewContentWidget { static readonly ID = 'resource-properties-tree-widget' ; static readonly LABEL = 'Resource Properties Tree' ; protected propertiesTree : Map < string , ResourcePropertiesCategoryNode > ; protected currentSelection : Object | undefined ; @ inject ( LabelProvider ) protected readonly labelProvider : LabelProvider ; constructor ( @ inject ( TreeProps ) readonly props , @ inject ( TreeModel ) model , @ inject ( ContextMenuRenderer ) protected readonly contextMenuRenderer ) { super ( props , model , contextMenuRenderer ) ; model . root = { id : ROOT_ID , name : ResourcePropertyViewTreeWidget . LABEL , parent : undefined , visible : false , children : [ ] } as ResourcePropertiesRoot ; this . propertiesTree = new Map < string , ResourcePropertiesCategoryNode > ( ) ; } @ postConstruct ( ) protected init ( ) { super . init ( ) ; this . id = ResourcePropertyViewTreeWidget . ID + '-treeContainer' ; this . addClass ( 'treeContainer' ) ; this . fillPropertiesTree ( ) ; } protected updateNeeded ( selection ) { return this . currentSelection !== selection ; } updatePropertyViewContent ( propertyDataService ? , selection ? ) { if ( this . updateNeeded ( selection ) ) { this . currentSelection = selection ; if ( propertyDataService ) { propertyDataService . providePropertyData ( selection ) . then ( ( fileStatObject ? ) => { this . fillPropertiesTree ( fileStatObject ) ; } ) ; } } } protected fillPropertiesTree ( fileStatObject ? ) { if ( fileStatObject ) { this . propertiesTree . clear ( ) ; const infoNode = this . createCategoryNode ( 'info' , nls . localizeByDefault ( 'Info' ) ) ; this . propertiesTree . set ( 'info' , infoNode ) ; infoNode . children . push ( this . createResultLineNode ( 'isDirectory' , nls . localize ( 'theia/property-view/directory' , 'Directory' ) , fileStatObject . isDirectory , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'isFile' , nls . localize ( 'theia/property-view/file' , 'File' ) , fileStatObject . isFile , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'isSymbolicLink' , nls . localize ( 'theia/property-view/symbolicLink' , 'Symbolic link' ) , fileStatObject . isSymbolicLink , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'location' , nls . localize ( 'theia/property-view/location' , 'Location' ) , this . getLocationString ( fileStatObject ) , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'name' , nls . localize ( 'theia/property-view/name' , 'Name' ) , this . getFileName ( fileStatObject ) , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'path' , nls . localize ( 'theia/property-view/path' , 'Path' ) , this . getFilePath ( fileStatObject ) , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'lastModification' , nls . localize ( 'theia/property-view/lastModified' , 'Last modified' ) , this . getLastModificationString ( fileStatObject ) , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'created' , nls . localize ( 'theia/property-view/created' , 'Created' ) , this . getCreationTimeString ( fileStatObject ) , infoNode ) ) ; infoNode . children . push ( this . createResultLineNode ( 'size' , nls . localize ( 'theia/property-view/size' , 'Size' ) , this . getSizeString ( fileStatObject ) , infoNode ) ) ; this . refreshModelChildren ( ) ; } } protected getLocationString ( fileStat ) { return fileStat . resource . path . toString ( ) ; } protected getFileName ( fileStat ) { return this . labelProvider . getName ( fileStat . resource ) ; } protected getFilePath ( fileStat ) { return this . labelProvider . getLongName ( fileStat . resource ) ; } protected getLastModificationString ( fileStat ) { return fileStat . mtime ? new Date ( fileStat . mtime ) . toLocaleString ( ) : '' ; } protected getCreationTimeString ( fileStat ) { return fileStat . ctime ? new Date ( fileStat . ctime ) . toLocaleString ( ) : '' ; } protected getSizeString ( fileStat ) { return fileStat . size ? nls . localizeByDefault ( '{0} B' , fileStat . size . toString ( ) ) : '' ; } protected createCategoryNode ( categoryId , name ) { return { id : categoryId , parent : this . model . root as ResourcePropertiesRoot , name , children : [ ] , categoryId , selected : false , expanded : true } ; } protected createResultLineNode ( id , name , property , parent ) { return { id : `${ parent . id }::${ id }` , parent , name : name , property : property !== undefined ? String ( property ) : '' , selected : false } ; } /**
     * Rendering
     */ protected async refreshModelChildren ( ) { if ( ResourcePropertiesRoot . is ( this . model . root ) ) { this . model . root . children = Array . from ( this . propertiesTree . values ( ) ) ; this . model . refresh ( ) ; } } protected renderCaption ( node , props ) { if ( ResourcePropertiesCategoryNode . is ( node ) ) { return this . renderExpandableNode ( node ) ; } else if ( ResourcePropertiesItemNode . is ( node ) ) { return this . renderItemNode ( node ) ; } return undefined ; } protected renderExpandableNode ( node ) { return < React . Fragment > < div className = { `theia-resource-tree-node-icon ${ this . toNodeIcon ( node ) }` } > < /div> < div className = { 'theia-resource-tree-node-name theia-TreeNodeSegment theia-TreeNodeSegmentGrow' } > { this . toNodeName ( node ) } < /div> < /React.Fragment>; } protected renderItemNode ( node ) { return < React . Fragment > < div className = { `theia-resource-tree-node-icon ${ this . toNodeIcon ( node ) }` } > < /div> < div className = { 'theia-resource-tree-node-name theia-TreeNodeSegment theia-TreeNodeSegmentGrow' } > { this . toNodeName ( node ) } < /div> < div className = { 'theia-resource-tree-node-property theia-TreeNodeSegment theia-TreeNodeSegmentGrow' } > { this . toNodeDescription ( node ) } < /div> < /React.Fragment>; } protected createNodeAttributes ( node , props ) { return { ... super . createNodeAttributes ( node , props ) , title : this . getNodeTooltip ( node ) } ; } protected getNodeTooltip ( node ) { if ( ResourcePropertiesCategoryNode . is ( node ) ) { return this . labelProvider . getName ( node ) ; } else if ( ResourcePropertiesItemNode . is ( node ) ) { return `${ this . labelProvider . getName ( node ) }: ${ this . labelProvider . getLongName ( node ) }` ; } return undefined ; } }