@@ -176,22 +176,22 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
176
176
private _hasIconForParentNode = false ;
177
177
private _hasIconForLeafNode = false ;
178
178
179
- private readonly collapseAllContextKey : RawContextKey < boolean > ;
180
- private readonly collapseAllContext : IContextKey < boolean > ;
181
- private readonly collapseAllToggleContextKey : RawContextKey < boolean > ;
182
- private readonly collapseAllToggleContext : IContextKey < boolean > ;
183
- private readonly refreshContextKey : RawContextKey < boolean > ;
184
- private readonly refreshContext : IContextKey < boolean > ;
179
+ private collapseAllContextKey : RawContextKey < boolean > | undefined ;
180
+ private collapseAllContext : IContextKey < boolean > | undefined ;
181
+ private collapseAllToggleContextKey : RawContextKey < boolean > | undefined ;
182
+ private collapseAllToggleContext : IContextKey < boolean > | undefined ;
183
+ private refreshContextKey : RawContextKey < boolean > | undefined ;
184
+ private refreshContext : IContextKey < boolean > | undefined ;
185
185
186
186
private focused : boolean = false ;
187
187
private domNode ! : HTMLElement ;
188
- private treeContainer ! : HTMLElement ;
188
+ private treeContainer : HTMLElement | undefined ;
189
189
private _messageValue : string | undefined ;
190
190
private _canSelectMany : boolean = false ;
191
- private messageElement ! : HTMLDivElement ;
191
+ private messageElement : HTMLElement | undefined ;
192
192
private tree : Tree | undefined ;
193
193
private treeLabels : ResourceLabels | undefined ;
194
- private treeViewDnd : CustomTreeViewDragAndDrop ;
194
+ private treeViewDnd : CustomTreeViewDragAndDrop | undefined ;
195
195
private _container : HTMLElement | undefined ;
196
196
197
197
private root : ITreeItem ;
@@ -242,13 +242,30 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
242
242
) {
243
243
super ( ) ;
244
244
this . root = new Root ( ) ;
245
- this . collapseAllContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .enableCollapseAll` , false , localize ( 'treeView.enableCollapseAll' , "Whether the the tree view with id {0} enables collapse all." , this . id ) ) ;
246
- this . collapseAllContext = this . collapseAllContextKey . bindTo ( contextKeyService ) ;
247
- this . collapseAllToggleContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .toggleCollapseAll` , false , localize ( 'treeView.toggleCollapseAll' , "Whether collapse all is toggled for the tree view with id {0}." , this . id ) ) ;
248
- this . collapseAllToggleContext = this . collapseAllToggleContextKey . bindTo ( contextKeyService ) ;
249
- this . refreshContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .enableRefresh` , false , localize ( 'treeView.enableRefresh' , "Whether the tree view with id {0} enables refresh." , this . id ) ) ;
250
- this . refreshContext = this . refreshContextKey . bindTo ( contextKeyService ) ;
245
+ // Try not to add anything that could be costly to this constructor. It gets called once per tree view
246
+ // during startup, and anything added here can affect performance.
247
+ }
248
+
249
+ private _isInitialized : boolean = false ;
250
+ private initialize ( ) {
251
+ if ( this . _isInitialized ) {
252
+ return ;
253
+ }
254
+ this . _isInitialized = true ;
255
+
256
+ // Remember when adding to this method that it isn't called until the the view is visible, meaning that
257
+ // properties could be set and events could be fired before we're initialized and that this needs to be handled.
258
+
259
+ this . contextKeyService . bufferChangeEvents ( ( ) => {
260
+ this . initializeShowCollapseAllAction ( ) ;
261
+ this . initializeCollapseAllToggle ( ) ;
262
+ this . initializeShowRefreshAction ( ) ;
263
+ } ) ;
264
+
251
265
this . treeViewDnd = this . instantiationService . createInstance ( CustomTreeViewDragAndDrop , this . id ) ;
266
+ if ( this . _dragAndDropController ) {
267
+ this . treeViewDnd . controller = this . _dragAndDropController ;
268
+ }
252
269
253
270
this . _register ( this . themeService . onDidFileIconThemeChange ( ( ) => this . tree ?. rerender ( ) ) ) ;
254
271
this . _register ( this . themeService . onDidColorThemeChange ( ( ) => this . tree ?. rerender ( ) ) ) ;
@@ -280,7 +297,9 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
280
297
}
281
298
set dragAndDropController ( dnd : ITreeViewDragAndDropController | undefined ) {
282
299
this . _dragAndDropController = dnd ;
283
- this . treeViewDnd . controller = dnd ;
300
+ if ( this . treeViewDnd ) {
301
+ this . treeViewDnd . controller = dnd ;
302
+ }
284
303
}
285
304
286
305
private _dataProvider : ITreeViewDataProvider | undefined ;
@@ -418,20 +437,40 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
418
437
return this . isVisible ;
419
438
}
420
439
440
+ private initializeShowCollapseAllAction ( startingValue : boolean = false ) {
441
+ if ( ! this . collapseAllContext ) {
442
+ this . collapseAllContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .enableCollapseAll` , startingValue , localize ( 'treeView.enableCollapseAll' , "Whether the the tree view with id {0} enables collapse all." , this . id ) ) ;
443
+ this . collapseAllContext = this . collapseAllContextKey . bindTo ( this . contextKeyService ) ;
444
+ }
445
+ return true ;
446
+ }
447
+
421
448
get showCollapseAllAction ( ) : boolean {
422
- return ! ! this . collapseAllContext . get ( ) ;
449
+ this . initializeShowCollapseAllAction ( ) ;
450
+ return ! ! this . collapseAllContext ?. get ( ) ;
423
451
}
424
452
425
453
set showCollapseAllAction ( showCollapseAllAction : boolean ) {
426
- this . collapseAllContext . set ( showCollapseAllAction ) ;
454
+ this . initializeShowCollapseAllAction ( showCollapseAllAction ) ;
455
+ this . collapseAllContext ?. set ( showCollapseAllAction ) ;
456
+ }
457
+
458
+
459
+ private initializeShowRefreshAction ( startingValue : boolean = false ) {
460
+ if ( ! this . refreshContext ) {
461
+ this . refreshContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .enableRefresh` , startingValue , localize ( 'treeView.enableRefresh' , "Whether the tree view with id {0} enables refresh." , this . id ) ) ;
462
+ this . refreshContext = this . refreshContextKey . bindTo ( this . contextKeyService ) ;
463
+ }
427
464
}
428
465
429
466
get showRefreshAction ( ) : boolean {
430
- return ! ! this . refreshContext . get ( ) ;
467
+ this . initializeShowRefreshAction ( ) ;
468
+ return ! ! this . refreshContext ?. get ( ) ;
431
469
}
432
470
433
471
set showRefreshAction ( showRefreshAction : boolean ) {
434
- this . refreshContext . set ( showRefreshAction ) ;
472
+ this . initializeShowRefreshAction ( showRefreshAction ) ;
473
+ this . refreshContext ?. set ( showRefreshAction ) ;
435
474
}
436
475
437
476
private registerActions ( ) {
@@ -478,6 +517,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
478
517
}
479
518
480
519
setVisibility ( isVisible : boolean ) : void {
520
+ this . initialize ( ) ;
481
521
isVisible = ! ! isVisible ;
482
522
if ( this . isVisible === isVisible ) {
483
523
return ;
@@ -548,7 +588,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
548
588
const renderer = this . instantiationService . createInstance ( TreeRenderer , this . id , treeMenus , this . treeLabels , actionViewItemProvider , aligner ) ;
549
589
const widgetAriaLabel = this . _title ;
550
590
551
- this . tree = this . _register ( this . instantiationService . createInstance ( Tree , this . id , this . treeContainer , new TreeViewDelegate ( ) , [ renderer ] ,
591
+ this . tree = this . _register ( this . instantiationService . createInstance ( Tree , this . id , this . treeContainer ! , new TreeViewDelegate ( ) , [ renderer ] ,
552
592
dataSource , {
553
593
identityProvider : new TreeViewIdentityProvider ( ) ,
554
594
accessibilityProvider : {
@@ -709,9 +749,12 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
709
749
}
710
750
711
751
private showMessage ( message : string ) : void {
752
+ this . _messageValue = message ;
753
+ if ( ! this . messageElement ) {
754
+ return ;
755
+ }
712
756
this . messageElement . classList . remove ( 'hide' ) ;
713
757
this . resetMessageElement ( ) ;
714
- this . _messageValue = message ;
715
758
if ( ! isFalsyOrWhitespace ( this . _message ) ) {
716
759
this . messageElement . textContent = this . _messageValue ;
717
760
}
@@ -720,18 +763,20 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
720
763
721
764
private hideMessage ( ) : void {
722
765
this . resetMessageElement ( ) ;
723
- this . messageElement . classList . add ( 'hide' ) ;
766
+ this . messageElement ? .classList . add ( 'hide' ) ;
724
767
this . layout ( this . _height , this . _width ) ;
725
768
}
726
769
727
770
private resetMessageElement ( ) : void {
728
- DOM . clearNode ( this . messageElement ) ;
771
+ if ( this . messageElement ) {
772
+ DOM . clearNode ( this . messageElement ) ;
773
+ }
729
774
}
730
775
731
776
private _height : number = 0 ;
732
777
private _width : number = 0 ;
733
778
layout ( height : number , width : number ) {
734
- if ( height && width ) {
779
+ if ( height && width && this . messageElement && this . treeContainer ) {
735
780
this . _height = height ;
736
781
this . _width = width ;
737
782
const treeHeight = height - DOM . getTotalHeight ( this . messageElement ) ;
@@ -831,23 +876,31 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
831
876
}
832
877
}
833
878
879
+ private initializeCollapseAllToggle ( ) {
880
+ if ( ! this . collapseAllToggleContext ) {
881
+ this . collapseAllToggleContextKey = new RawContextKey < boolean > ( `treeView.${ this . id } .toggleCollapseAll` , false , localize ( 'treeView.toggleCollapseAll' , "Whether collapse all is toggled for the tree view with id {0}." , this . id ) ) ;
882
+ this . collapseAllToggleContext = this . collapseAllToggleContextKey . bindTo ( this . contextKeyService ) ;
883
+ }
884
+ }
885
+
834
886
private updateCollapseAllToggle ( ) {
835
887
if ( this . showCollapseAllAction ) {
836
- this . collapseAllToggleContext . set ( ! ! this . root . children && ( this . root . children . length > 0 ) &&
888
+ this . initializeCollapseAllToggle ( ) ;
889
+ this . collapseAllToggleContext ?. set ( ! ! this . root . children && ( this . root . children . length > 0 ) &&
837
890
this . root . children . some ( value => value . collapsibleState !== TreeItemCollapsibleState . None ) ) ;
838
891
}
839
892
}
840
893
841
894
private updateContentAreas ( ) : void {
842
895
const isTreeEmpty = ! this . root . children || this . root . children . length === 0 ;
843
896
// Hide tree container only when there is a message and tree is empty and not refreshing
844
- if ( this . _messageValue && isTreeEmpty && ! this . refreshing ) {
897
+ if ( this . _messageValue && isTreeEmpty && ! this . refreshing && this . treeContainer ) {
845
898
// If there's a dnd controller then hiding the tree prevents it from being dragged into.
846
899
if ( ! this . dragAndDropController ) {
847
900
this . treeContainer . classList . add ( 'hide' ) ;
848
901
}
849
902
this . domNode . setAttribute ( 'tabindex' , '0' ) ;
850
- } else {
903
+ } else if ( this . treeContainer ) {
851
904
this . treeContainer . classList . remove ( 'hide' ) ;
852
905
this . domNode . removeAttribute ( 'tabindex' ) ;
853
906
}
0 commit comments