@@ -1103,7 +1103,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11031103 const iconLabelName = getIconLabelNameFromHTMLElement ( originalEvent . target ) ;
11041104
11051105 if ( iconLabelName && iconLabelName . index < iconLabelName . count - 1 ) {
1106- const result = this . handleDragOver ( data , compressedTarget , targetIndex , originalEvent ) ;
1106+ const result = this . handleDragOver ( data , compressedTarget , targetIndex , targetSector , originalEvent ) ;
11071107
11081108 if ( result ) {
11091109 if ( iconLabelName . element !== this . compressedDragOverElement ) {
@@ -1127,10 +1127,10 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11271127 }
11281128
11291129 this . compressedDropTargetDisposable . dispose ( ) ;
1130- return this . handleDragOver ( data , target , targetIndex , originalEvent ) ;
1130+ return this . handleDragOver ( data , target , targetIndex , targetSector , originalEvent ) ;
11311131 }
11321132
1133- private handleDragOver ( data : IDragAndDropData , target : ExplorerItem | undefined , targetIndex : number | undefined , originalEvent : DragEvent ) : boolean | ITreeDragOverReaction {
1133+ private handleDragOver ( data : IDragAndDropData , target : ExplorerItem | undefined , targetIndex : number | undefined , targetSector : ListViewTargetSector | undefined , originalEvent : DragEvent ) : boolean | ITreeDragOverReaction {
11341134 const isCopy = originalEvent && ( ( originalEvent . ctrlKey && ! isMacintosh ) || ( originalEvent . altKey && isMacintosh ) ) ;
11351135 const isNative = data instanceof NativeDragAndDropData ;
11361136 const effectType = ( isNative || isCopy ) ? ListDragOverEffectType . Copy : ListDragOverEffectType . Move ;
@@ -1151,6 +1151,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11511151 // In-Explorer DND
11521152 else {
11531153 const items = FileDragAndDrop . getStatsFromDragAndDropData ( data as ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > ) ;
1154+ const isRootsReorder = items . every ( item => item . isRoot ) ;
11541155
11551156 if ( ! target ) {
11561157 // Dropping onto the empty area. Do not accept if items dragged are already
@@ -1159,6 +1160,11 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11591160 return false ;
11601161 }
11611162
1163+ // root is added after last root folder when hovering on empty background
1164+ if ( isRootsReorder ) {
1165+ return { accept : true , effect : { type : ListDragOverEffectType . Move , position : ListDragOverEffectPosition . After } } ;
1166+ }
1167+
11621168 return { accept : true , bubble : TreeDragOverBubble . Down , effect, autoExpand : false } ;
11631169 }
11641170
@@ -1171,17 +1177,12 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11711177 }
11721178
11731179 if ( items . some ( ( source ) => {
1174- if ( source . isRoot && target instanceof ExplorerItem && ! target . isRoot ) {
1175- return true ; // Root folder can not be moved to a non root file stat.
1180+ if ( source . isRoot ) {
1181+ return false ; // Root folders are handled seperately
11761182 }
11771183
11781184 if ( this . uriIdentityService . extUri . isEqual ( source . resource , target . resource ) ) {
1179- return true ; // Can not move anything onto itself
1180- }
1181-
1182- if ( source . isRoot && target instanceof ExplorerItem && target . isRoot ) {
1183- // Disable moving workspace roots in one another
1184- return false ;
1185+ return true ; // Can not move anything onto itself excpet for root folders
11851186 }
11861187
11871188 if ( ! isCopy && this . uriIdentityService . extUri . isEqual ( dirname ( source . resource ) , target . resource ) ) {
@@ -1196,6 +1197,24 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
11961197 } ) ) {
11971198 return false ;
11981199 }
1200+
1201+ // reordering roots
1202+ if ( isRootsReorder ) {
1203+ if ( ! target . isRoot ) {
1204+ return false ;
1205+ }
1206+
1207+ let dropEffectPosition : ListDragOverEffectPosition | undefined = undefined ;
1208+ switch ( targetSector ) {
1209+ case ListViewTargetSector . TOP :
1210+ case ListViewTargetSector . CENTER_TOP :
1211+ dropEffectPosition = ListDragOverEffectPosition . Before ; break ;
1212+ case ListViewTargetSector . CENTER_BOTTOM :
1213+ case ListViewTargetSector . BOTTOM :
1214+ dropEffectPosition = ListDragOverEffectPosition . After ; break ;
1215+ }
1216+ return { accept : true , effect : { type : ListDragOverEffectType . Move , position : dropEffectPosition } } ;
1217+ }
11991218 }
12001219
12011220 // All (target = model)
@@ -1268,6 +1287,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
12681287 // Find parent to add to
12691288 if ( ! target ) {
12701289 target = this . explorerService . roots [ this . explorerService . roots . length - 1 ] ;
1290+ targetSector = ListViewTargetSector . BOTTOM ;
12711291 }
12721292 if ( ! target . isDirectory && target . parent ) {
12731293 target = target . parent ;
@@ -1298,14 +1318,14 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
12981318
12991319 // In-Explorer DND (Move/Copy file)
13001320 else {
1301- await this . handleExplorerDrop ( data as ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > , resolvedTarget , originalEvent ) ;
1321+ await this . handleExplorerDrop ( data as ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > , resolvedTarget , targetIndex , targetSector , originalEvent ) ;
13021322 }
13031323 } catch ( error ) {
13041324 this . dialogService . error ( toErrorMessage ( error ) ) ;
13051325 }
13061326 }
13071327
1308- private async handleExplorerDrop ( data : ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > , target : ExplorerItem , originalEvent : DragEvent ) : Promise < void > {
1328+ private async handleExplorerDrop ( data : ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > , target : ExplorerItem , targetIndex : number | undefined , targetSector : ListViewTargetSector | undefined , originalEvent : DragEvent ) : Promise < void > {
13091329 const elementsData = FileDragAndDrop . getStatsFromDragAndDropData ( data ) ;
13101330 const distinctItems = new Map ( elementsData . map ( element => [ element , this . isCollapsed ( element ) ] ) ) ;
13111331
@@ -1353,7 +1373,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
13531373 }
13541374 }
13551375
1356- await this . doHandleRootDrop ( items . filter ( s => s . isRoot ) , target ) ;
1376+ await this . doHandleRootDrop ( items . filter ( s => s . isRoot ) , target , targetSector ) ;
13571377
13581378 const sources = items . filter ( s => ! s . isRoot ) ;
13591379 if ( isCopy ) {
@@ -1363,13 +1383,14 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
13631383 return this . doHandleExplorerDropOnMove ( sources , target ) ;
13641384 }
13651385
1366- private async doHandleRootDrop ( roots : ExplorerItem [ ] , target : ExplorerItem ) : Promise < void > {
1386+ private async doHandleRootDrop ( roots : ExplorerItem [ ] , target : ExplorerItem , targetSector : ListViewTargetSector | undefined ) : Promise < void > {
13671387 if ( roots . length === 0 ) {
13681388 return ;
13691389 }
13701390
13711391 const folders = this . contextService . getWorkspace ( ) . folders ;
13721392 let targetIndex : number | undefined ;
1393+ const sourceIndices : number [ ] = [ ] ;
13731394 const workspaceCreationData : IWorkspaceFolderCreationData [ ] = [ ] ;
13741395 const rootsToMove : IWorkspaceFolderCreationData [ ] = [ ] ;
13751396
@@ -1378,10 +1399,20 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
13781399 uri : folders [ index ] . uri ,
13791400 name : folders [ index ] . name
13801401 } ;
1402+
1403+ // Is current target
13811404 if ( target instanceof ExplorerItem && this . uriIdentityService . extUri . isEqual ( folders [ index ] . uri , target . resource ) ) {
13821405 targetIndex = index ;
13831406 }
13841407
1408+ // Is current source
1409+ for ( const root of roots ) {
1410+ if ( this . uriIdentityService . extUri . isEqual ( folders [ index ] . uri , root . resource ) ) {
1411+ sourceIndices . push ( index ) ;
1412+ break ;
1413+ }
1414+ }
1415+
13851416 if ( roots . every ( r => r . resource . toString ( ) !== folders [ index ] . uri . toString ( ) ) ) {
13861417 workspaceCreationData . push ( data ) ;
13871418 } else {
@@ -1390,6 +1421,20 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
13901421 }
13911422 if ( targetIndex === undefined ) {
13921423 targetIndex = workspaceCreationData . length ;
1424+ } else {
1425+ switch ( targetSector ) {
1426+ case ListViewTargetSector . BOTTOM :
1427+ case ListViewTargetSector . CENTER_BOTTOM :
1428+ targetIndex ++ ;
1429+ break ;
1430+ }
1431+ // Adjust target index if source was located before target.
1432+ // The move will cause the index to change
1433+ for ( const sourceIndex of sourceIndices ) {
1434+ if ( sourceIndex < targetIndex ) {
1435+ targetIndex -- ;
1436+ }
1437+ }
13931438 }
13941439
13951440 workspaceCreationData . splice ( targetIndex , 0 , ...rootsToMove ) ;
0 commit comments