@@ -206,6 +206,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
206
206
private treeContainer : HTMLElement | undefined ;
207
207
private _messageValue : string | undefined ;
208
208
private _canSelectMany : boolean = false ;
209
+ private _manuallyManageCheckboxes : boolean = false ;
209
210
private messageElement : HTMLElement | undefined ;
210
211
private tree : Tree | undefined ;
211
212
private treeLabels : ResourceLabels | undefined ;
@@ -349,6 +350,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
349
350
node = node ?? self . root ;
350
351
node . children = await ( node instanceof Root ? dataProvider . getChildren ( ) : dataProvider . getChildren ( node ) ) ;
351
352
children = node . children ?? [ ] ;
353
+ children . forEach ( child => child . parent = node ) ;
352
354
}
353
355
if ( node instanceof Root ) {
354
356
const oldEmpty = this . _isEmpty ;
@@ -447,6 +449,14 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
447
449
}
448
450
}
449
451
452
+ get manuallyManageCheckboxes ( ) : boolean {
453
+ return this . _manuallyManageCheckboxes ;
454
+ }
455
+
456
+ set manuallyManageCheckboxes ( manuallyManageCheckboxes : boolean ) {
457
+ this . _manuallyManageCheckboxes = manuallyManageCheckboxes ;
458
+ }
459
+
450
460
get hasIconForParentNode ( ) : boolean {
451
461
return this . _hasIconForParentNode ;
452
462
}
@@ -610,6 +620,68 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
610
620
this . _register ( focusTracker . onDidBlur ( ( ) => this . focused = false ) ) ;
611
621
}
612
622
623
+ private updateCheckboxes ( items : ITreeItem [ ] ) {
624
+ const additionalItems : ITreeItem [ ] = [ ] ;
625
+
626
+ if ( ! this . manuallyManageCheckboxes ) {
627
+ for ( const item of items ) {
628
+ if ( item . checkbox !== undefined ) {
629
+
630
+ function checkChildren ( currentItem : ITreeItem ) {
631
+ for ( const child of ( currentItem . children ?? [ ] ) ) {
632
+ if ( child . checkbox !== undefined && currentItem . checkbox !== undefined ) {
633
+ child . checkbox . isChecked = currentItem . checkbox . isChecked ;
634
+ additionalItems . push ( child ) ;
635
+ checkChildren ( child ) ;
636
+ }
637
+ }
638
+ }
639
+ checkChildren ( item ) ;
640
+
641
+ const visitedParents : Set < ITreeItem > = new Set ( ) ;
642
+ function checkParents ( currentItem : ITreeItem ) {
643
+ if ( currentItem . parent && ( currentItem . parent . checkbox !== undefined ) && currentItem . parent . children ) {
644
+ if ( visitedParents . has ( currentItem . parent ) ) {
645
+ return ;
646
+ } else {
647
+ visitedParents . add ( currentItem . parent ) ;
648
+ }
649
+
650
+ let someUnchecked = false ;
651
+ let someChecked = false ;
652
+ for ( const child of currentItem . parent . children ) {
653
+ if ( someUnchecked && someChecked ) {
654
+ break ;
655
+ }
656
+ if ( child . checkbox !== undefined ) {
657
+ if ( child . checkbox . isChecked ) {
658
+ someChecked = true ;
659
+ } else {
660
+ someUnchecked = true ;
661
+ }
662
+ }
663
+ }
664
+ if ( someChecked && ! someUnchecked ) {
665
+ currentItem . parent . checkbox . isChecked = true ;
666
+ additionalItems . push ( currentItem . parent ) ;
667
+ checkParents ( currentItem . parent ) ;
668
+ } else if ( someUnchecked && ! someChecked ) {
669
+ currentItem . parent . checkbox . isChecked = false ;
670
+ additionalItems . push ( currentItem . parent ) ;
671
+ checkParents ( currentItem . parent ) ;
672
+ }
673
+ }
674
+ }
675
+ checkParents ( item ) ;
676
+ }
677
+ }
678
+ }
679
+ items = items . concat ( additionalItems ) ;
680
+ items . forEach ( item => this . tree ?. rerender ( item ) ) ;
681
+ this . _onDidChangeCheckboxState . fire ( items ) ;
682
+ }
683
+
684
+
613
685
protected createTree ( ) {
614
686
const actionViewItemProvider = createActionViewItem . bind ( undefined , this . instantiationService ) ;
615
687
const treeMenus = this . _register ( this . instantiationService . createInstance ( TreeMenus , this . id ) ) ;
@@ -618,8 +690,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
618
690
const aligner = new Aligner ( this . themeService ) ;
619
691
const checkboxStateHandler = this . _register ( new CheckboxStateHandler ( ) ) ;
620
692
this . _register ( checkboxStateHandler . onDidChangeCheckboxState ( items => {
621
- items . forEach ( item => this . tree ?. rerender ( item ) ) ;
622
- this . _onDidChangeCheckboxState . fire ( items ) ;
693
+ this . updateCheckboxes ( items ) ;
623
694
} ) ) ;
624
695
const renderer = this . instantiationService . createInstance ( TreeRenderer , this . id , treeMenus , this . treeLabels , actionViewItemProvider , aligner , checkboxStateHandler ) ;
625
696
const widgetAriaLabel = this . _title ;
0 commit comments