@@ -1103,7 +1103,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1103
1103
const iconLabelName = getIconLabelNameFromHTMLElement ( originalEvent . target ) ;
1104
1104
1105
1105
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 ) ;
1107
1107
1108
1108
if ( result ) {
1109
1109
if ( iconLabelName . element !== this . compressedDragOverElement ) {
@@ -1127,10 +1127,10 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1127
1127
}
1128
1128
1129
1129
this . compressedDropTargetDisposable . dispose ( ) ;
1130
- return this . handleDragOver ( data , target , targetIndex , originalEvent ) ;
1130
+ return this . handleDragOver ( data , target , targetIndex , targetSector , originalEvent ) ;
1131
1131
}
1132
1132
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 {
1134
1134
const isCopy = originalEvent && ( ( originalEvent . ctrlKey && ! isMacintosh ) || ( originalEvent . altKey && isMacintosh ) ) ;
1135
1135
const isNative = data instanceof NativeDragAndDropData ;
1136
1136
const effectType = ( isNative || isCopy ) ? ListDragOverEffectType . Copy : ListDragOverEffectType . Move ;
@@ -1151,6 +1151,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1151
1151
// In-Explorer DND
1152
1152
else {
1153
1153
const items = FileDragAndDrop . getStatsFromDragAndDropData ( data as ElementsDragAndDropData < ExplorerItem , ExplorerItem [ ] > ) ;
1154
+ const isRootsReorder = items . every ( item => item . isRoot ) ;
1154
1155
1155
1156
if ( ! target ) {
1156
1157
// Dropping onto the empty area. Do not accept if items dragged are already
@@ -1159,6 +1160,11 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1159
1160
return false ;
1160
1161
}
1161
1162
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
+
1162
1168
return { accept : true , bubble : TreeDragOverBubble . Down , effect, autoExpand : false } ;
1163
1169
}
1164
1170
@@ -1171,17 +1177,12 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1171
1177
}
1172
1178
1173
1179
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
1176
1182
}
1177
1183
1178
1184
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
1185
1186
}
1186
1187
1187
1188
if ( ! isCopy && this . uriIdentityService . extUri . isEqual ( dirname ( source . resource ) , target . resource ) ) {
@@ -1196,6 +1197,24 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1196
1197
} ) ) {
1197
1198
return false ;
1198
1199
}
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
+ }
1199
1218
}
1200
1219
1201
1220
// All (target = model)
@@ -1268,6 +1287,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1268
1287
// Find parent to add to
1269
1288
if ( ! target ) {
1270
1289
target = this . explorerService . roots [ this . explorerService . roots . length - 1 ] ;
1290
+ targetSector = ListViewTargetSector . BOTTOM ;
1271
1291
}
1272
1292
if ( ! target . isDirectory && target . parent ) {
1273
1293
target = target . parent ;
@@ -1298,14 +1318,14 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1298
1318
1299
1319
// In-Explorer DND (Move/Copy file)
1300
1320
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 ) ;
1302
1322
}
1303
1323
} catch ( error ) {
1304
1324
this . dialogService . error ( toErrorMessage ( error ) ) ;
1305
1325
}
1306
1326
}
1307
1327
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 > {
1309
1329
const elementsData = FileDragAndDrop . getStatsFromDragAndDropData ( data ) ;
1310
1330
const distinctItems = new Map ( elementsData . map ( element => [ element , this . isCollapsed ( element ) ] ) ) ;
1311
1331
@@ -1353,7 +1373,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1353
1373
}
1354
1374
}
1355
1375
1356
- await this . doHandleRootDrop ( items . filter ( s => s . isRoot ) , target ) ;
1376
+ await this . doHandleRootDrop ( items . filter ( s => s . isRoot ) , target , targetSector ) ;
1357
1377
1358
1378
const sources = items . filter ( s => ! s . isRoot ) ;
1359
1379
if ( isCopy ) {
@@ -1363,13 +1383,14 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1363
1383
return this . doHandleExplorerDropOnMove ( sources , target ) ;
1364
1384
}
1365
1385
1366
- private async doHandleRootDrop ( roots : ExplorerItem [ ] , target : ExplorerItem ) : Promise < void > {
1386
+ private async doHandleRootDrop ( roots : ExplorerItem [ ] , target : ExplorerItem , targetSector : ListViewTargetSector | undefined ) : Promise < void > {
1367
1387
if ( roots . length === 0 ) {
1368
1388
return ;
1369
1389
}
1370
1390
1371
1391
const folders = this . contextService . getWorkspace ( ) . folders ;
1372
1392
let targetIndex : number | undefined ;
1393
+ const sourceIndices : number [ ] = [ ] ;
1373
1394
const workspaceCreationData : IWorkspaceFolderCreationData [ ] = [ ] ;
1374
1395
const rootsToMove : IWorkspaceFolderCreationData [ ] = [ ] ;
1375
1396
@@ -1378,10 +1399,20 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1378
1399
uri : folders [ index ] . uri ,
1379
1400
name : folders [ index ] . name
1380
1401
} ;
1402
+
1403
+ // Is current target
1381
1404
if ( target instanceof ExplorerItem && this . uriIdentityService . extUri . isEqual ( folders [ index ] . uri , target . resource ) ) {
1382
1405
targetIndex = index ;
1383
1406
}
1384
1407
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
+
1385
1416
if ( roots . every ( r => r . resource . toString ( ) !== folders [ index ] . uri . toString ( ) ) ) {
1386
1417
workspaceCreationData . push ( data ) ;
1387
1418
} else {
@@ -1390,6 +1421,20 @@ export class FileDragAndDrop implements ITreeDragAndDrop<ExplorerItem> {
1390
1421
}
1391
1422
if ( targetIndex === undefined ) {
1392
1423
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
+ }
1393
1438
}
1394
1439
1395
1440
workspaceCreationData . splice ( targetIndex , 0 , ...rootsToMove ) ;
0 commit comments