/********************************************************************************
 * Copyright (C) 2018 TypeFox 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 { injectable } from 'inversify' ; import { Tree , TreeNode } from './tree' ; import { Event , Emitter , Disposable , DisposableCollection , MaybePromise } from '../../common' ; import { WidgetDecoration } from '../widget-decoration' ; /**
 * The  TreeDecorator allows adapting the look and the style of the tree items within a widget. Changes are reflected in
 * the form of `decoration data`. This `decoration data` is a map storing  TreeDecoration . Data for affected tree nodes (using the unique node id as key).
 * It is important to notice that there is no common contribution point for `TreeDecorators`. Instead, each  TreeDecoratorService is
 * supposed to declare its own contribution provider for `TreeDecorators`.
 *
 * ### Example usage
 * A simple tree decorator that changes the background color of each tree node to `red`.
 *
 * ```typescript
 *  injectable export interface TreeDecorator { /**
     * The unique identifier of the decorator. Ought to be unique in the application.
     */ readonly id : string ; /**
     * Fired when this decorator has calculated all the `decoration data` for the tree nodes.
     */ readonly onDidChangeDecorations : Event < ( tree : Tree ) => Map < string , TreeDecoration . Data > > ; param tree returns decorations ( tree ) : MaybePromise < Map < string , TreeDecoration . Data > > ; } export const TreeDecoratorService = Symbol ( 'TreeDecoratorService' ) ; /**
 * The  TreeDecoratorService manages a set of known {link TreeDecorator}s and emits events when
 * any of the known decorators has changes. Typically, a `TreeDecoratorService` provides a contribution point that can be used to
 * register  TreeDecorator s exclusively for this service.
 *
 * ### Example usage
 * ```typescript
 * export const MyTreeDecorator = Symbol('MyTreeDecorator');
 *
 *  injectable named export interface TreeDecoratorService extends Disposable { /**
     * Fired when any of the available tree decorators has changes.
     */ readonly onDidChangeDecorations : Event < void > ; param tree returns getDecorations ( tree ) : MaybePromise < Map < string , TreeDecoration . Data [ ] > > ; param decorations returns deflateDecorators ( decorations ) : object ; returns inflateDecorators ( state ) : Map < string , TreeDecoration . Data [ ] > ; } /**
 * The default tree decorator service. Does nothing at all. One has to rebind to a concrete implementation
 * if decorators have to be supported in the tree widget.
 */ @ injectable ( ) export class NoopTreeDecoratorService implements TreeDecoratorService { protected readonly emitter = new Emitter < void > ( ) ; readonly onDidChangeDecorations = this . emitter . event ; dispose ( ) { this . emitter . dispose ( ) ; } getDecorations ( ) { return new Map ( ) ; } deflateDecorators ( ) { return { } ; } inflateDecorators ( ) { return new Map ( ) ; } } /**
 * Abstract decorator service implementation which emits events from all known tree decorators and caches the current state.
 */ @ injectable ( ) export abstract class AbstractTreeDecoratorService implements TreeDecoratorService { protected readonly onDidChangeDecorationsEmitter = new Emitter < void > ( ) ; readonly onDidChangeDecorations = this . onDidChangeDecorationsEmitter . event ; protected readonly toDispose = new DisposableCollection ( ) ; constructor ( protected readonly decorators ) { this . toDispose . push ( this . onDidChangeDecorationsEmitter ) ; this . toDispose . pushAll ( this . decorators . map ( decorator => decorator . onDidChangeDecorations ( data => this . onDidChangeDecorationsEmitter . fire ( undefined ) ) ) ) ; } dispose ( ) { this . toDispose . dispose ( ) ; } async getDecorations ( tree ) { const changes = new Map ( ) ; for ( const decorator of this . decorators ) { for ( const [ id , data ] of ( await decorator . decorations ( tree ) ) . entries ( ) ) { if ( changes . has ( id ) ) { changes . get ( id ) ! . push ( data ) ; } else { changes . set ( id , [ data ] ) ; } } } return changes ; } deflateDecorators ( decorations ) { const state = Object . create ( null ) ; for ( const [ id , data ] of decorations ) { state [ id ] = data ; } return state ; } inflateDecorators ( state ) { const decorators = new Map < string , TreeDecoration . Data [ ] > ( ) ; for ( const id of Object . keys ( state ) ) { decorators . set ( id , state [ id ] ) ; } return decorators ; } } deprecated export import TreeDecoration = WidgetDecoration ; export interface DecoratedTreeNode extends TreeNode { /**
     * The additional tree decoration data attached to the tree node itself.
     */ readonly decorationData : TreeDecoration . Data ; } export namespace DecoratedTreeNode { /**
     * Type-guard for decorated tree nodes.
     */ export function is ( node ) { return ! ! node && 'decorationData' in node ; } }