@@ -147,6 +147,7 @@ type MoveGroupOrPanelOptions = {
147
147
position : Position ;
148
148
index ?: number ;
149
149
} ;
150
+ keepEmptyGroups ?: boolean ;
150
151
} ;
151
152
152
153
export interface FloatingGroupOptions {
@@ -219,6 +220,7 @@ export interface IDockviewComponent extends IBaseGrid<DockviewGroupPanel> {
219
220
onWillClose ?: ( event : { id : string ; window : Window } ) => void ;
220
221
}
221
222
) : Promise < boolean > ;
223
+ fromJSON ( data : any , options ?: { keepExistingPanels : boolean } ) : void ;
222
224
}
223
225
224
226
export class DockviewComponent
@@ -381,17 +383,17 @@ export class DockviewComponent
381
383
this . updateWatermark ( ) ;
382
384
} ) ,
383
385
this . onDidAdd ( ( event ) => {
384
- if ( ! this . _moving ) {
386
+ if ( ! this . _isEventSuppressionEnabled ) {
385
387
this . _onDidAddGroup . fire ( event ) ;
386
388
}
387
389
} ) ,
388
390
this . onDidRemove ( ( event ) => {
389
- if ( ! this . _moving ) {
391
+ if ( ! this . _isEventSuppressionEnabled ) {
390
392
this . _onDidRemoveGroup . fire ( event ) ;
391
393
}
392
394
} ) ,
393
395
this . onDidActiveChange ( ( event ) => {
394
- if ( ! this . _moving ) {
396
+ if ( ! this . _isEventSuppressionEnabled ) {
395
397
this . _onDidActiveGroupChange . fire ( event ) ;
396
398
}
397
399
} ) ,
@@ -675,13 +677,13 @@ export class DockviewComponent
675
677
676
678
if ( ! options ?. overridePopoutGroup && isGroupAddedToDom ) {
677
679
if ( itemToPopout instanceof DockviewPanel ) {
678
- this . movingLock ( ( ) => {
680
+ this . runWithSuppressedEvents ( ( ) => {
679
681
const panel =
680
682
referenceGroup . model . removePanel ( itemToPopout ) ;
681
683
group . model . openPanel ( panel ) ;
682
684
} ) ;
683
685
} else {
684
- this . movingLock ( ( ) =>
686
+ this . runWithSuppressedEvents ( ( ) =>
685
687
moveGroupWithoutDestroying ( {
686
688
from : referenceGroup ,
687
689
to : group ,
@@ -773,7 +775,7 @@ export class DockviewComponent
773
775
isGroupAddedToDom &&
774
776
this . getPanel ( referenceGroup . id )
775
777
) {
776
- this . movingLock ( ( ) =>
778
+ this . runWithSuppressedEvents ( ( ) =>
777
779
moveGroupWithoutDestroying ( {
778
780
from : group ,
779
781
to : referenceGroup ,
@@ -830,15 +832,15 @@ export class DockviewComponent
830
832
group = this . createGroup ( ) ;
831
833
this . _onDidAddGroup . fire ( group ) ;
832
834
833
- this . movingLock ( ( ) =>
835
+ this . runWithSuppressedEvents ( ( ) =>
834
836
this . removePanel ( item , {
835
837
removeEmptyGroup : true ,
836
838
skipDispose : true ,
837
839
skipSetActiveGroup : true ,
838
840
} )
839
841
) ;
840
842
841
- this . movingLock ( ( ) =>
843
+ this . runWithSuppressedEvents ( ( ) =>
842
844
group . model . openPanel ( item , { skipSetGroupActive : true } )
843
845
) ;
844
846
} else {
@@ -857,7 +859,7 @@ export class DockviewComponent
857
859
858
860
if ( ! skip ) {
859
861
if ( popoutReferenceGroup ) {
860
- this . movingLock ( ( ) =>
862
+ this . runWithSuppressedEvents ( ( ) =>
861
863
moveGroupWithoutDestroying ( {
862
864
from : item ,
863
865
to : popoutReferenceGroup ,
@@ -1219,7 +1221,47 @@ export class DockviewComponent
1219
1221
return result ;
1220
1222
}
1221
1223
1222
- fromJSON ( data : SerializedDockview ) : void {
1224
+ fromJSON (
1225
+ data : SerializedDockview ,
1226
+ options ?: { keepExistingPanels : boolean }
1227
+ ) : void {
1228
+ const existingPanels = new Map < string , IDockviewPanel > ( ) ;
1229
+ const tempGroup = this . createGroup ( ) ;
1230
+ this . _groups . delete ( tempGroup . api . id ) ;
1231
+
1232
+ if ( options ?. keepExistingPanels ) {
1233
+ /**
1234
+ * What are we doing here?
1235
+ *
1236
+ * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
1237
+ * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
1238
+ */
1239
+
1240
+ const newPanels = Object . keys ( data . panels ) ;
1241
+
1242
+ for ( const panel of this . panels ) {
1243
+ if ( newPanels . includes ( panel . api . id ) ) {
1244
+ existingPanels . set ( panel . api . id , panel ) ;
1245
+ }
1246
+ }
1247
+
1248
+ this . runWithSuppressedEvents ( ( ) => {
1249
+ Array . from ( existingPanels . values ( ) ) . forEach ( ( panel ) => {
1250
+ this . moveGroupOrPanel ( {
1251
+ from : {
1252
+ groupId : panel . api . group . api . id ,
1253
+ panelId : panel . api . id ,
1254
+ } ,
1255
+ to : {
1256
+ group : tempGroup ,
1257
+ position : 'center' ,
1258
+ } ,
1259
+ keepEmptyGroups : true ,
1260
+ } ) ;
1261
+ } ) ;
1262
+ } ) ;
1263
+ }
1264
+
1223
1265
this . clear ( ) ;
1224
1266
1225
1267
if ( typeof data !== 'object' || data === null ) {
@@ -1260,11 +1302,23 @@ export class DockviewComponent
1260
1302
* In running this section first we avoid firing lots of 'add' events in the event of a failure
1261
1303
* due to a corruption of input data.
1262
1304
*/
1263
- const panel = this . _deserializer . fromJSON (
1264
- panels [ child ] ,
1265
- group
1266
- ) ;
1267
- createdPanels . push ( panel ) ;
1305
+
1306
+ const existingPanel = existingPanels . get ( child ) ;
1307
+
1308
+ if ( existingPanel ) {
1309
+ this . runWithSuppressedEvents ( ( ) => {
1310
+ tempGroup . model . removePanel ( existingPanel ) ;
1311
+ } ) ;
1312
+
1313
+ createdPanels . push ( existingPanel ) ;
1314
+ existingPanel . updateFromStateModel ( panels [ child ] ) ;
1315
+ } else {
1316
+ const panel = this . _deserializer . fromJSON (
1317
+ panels [ child ] ,
1318
+ group
1319
+ ) ;
1320
+ createdPanels . push ( panel ) ;
1321
+ }
1268
1322
}
1269
1323
1270
1324
this . _onDidAddGroup . fire ( group ) ;
@@ -1276,10 +1330,21 @@ export class DockviewComponent
1276
1330
typeof activeView === 'string' &&
1277
1331
activeView === panel . id ;
1278
1332
1279
- group . model . openPanel ( panel , {
1280
- skipSetActive : ! isActive ,
1281
- skipSetGroupActive : true ,
1282
- } ) ;
1333
+ const hasExisting = existingPanels . has ( panel . api . id ) ;
1334
+
1335
+ if ( hasExisting ) {
1336
+ this . runWithSuppressedEvents ( ( ) => {
1337
+ group . model . openPanel ( panel , {
1338
+ skipSetActive : ! isActive ,
1339
+ skipSetGroupActive : true ,
1340
+ } ) ;
1341
+ } ) ;
1342
+ } else {
1343
+ group . model . openPanel ( panel , {
1344
+ skipSetActive : ! isActive ,
1345
+ skipSetGroupActive : true ,
1346
+ } ) ;
1347
+ }
1283
1348
}
1284
1349
1285
1350
if ( ! group . activePanel && group . panels . length > 0 ) {
@@ -1892,16 +1957,21 @@ export class DockviewComponent
1892
1957
return re ;
1893
1958
}
1894
1959
1895
- private _moving = false ;
1960
+ private _isEventSuppressionEnabled = false ;
1896
1961
1897
- movingLock < T > ( func : ( ) => T ) : T {
1898
- const isMoving = this . _moving ;
1962
+ /**
1963
+ * Code that runs within the provided function will not cause any events to fire. This is useful if you want
1964
+ * to move things around as an intermediate step without raises any associated events
1965
+ */
1966
+ runWithSuppressedEvents < T > ( func : ( ) => T ) : T {
1967
+ const isMoving = this . _isEventSuppressionEnabled ;
1899
1968
1900
1969
try {
1901
- this . _moving = true ;
1970
+ this . _isEventSuppressionEnabled = true ;
1902
1971
return func ( ) ;
1903
1972
} finally {
1904
- this . _moving = isMoving ;
1973
+ // return to the original state which isn't necessarily false since calls may be nested
1974
+ this . _isEventSuppressionEnabled = isMoving ;
1905
1975
}
1906
1976
}
1907
1977
@@ -1940,24 +2010,24 @@ export class DockviewComponent
1940
2010
* Dropping a panel within another group
1941
2011
*/
1942
2012
1943
- const removedPanel : IDockviewPanel | undefined = this . movingLock (
1944
- ( ) =>
2013
+ const removedPanel : IDockviewPanel | undefined =
2014
+ this . runWithSuppressedEvents ( ( ) =>
1945
2015
sourceGroup . model . removePanel ( sourceItemId , {
1946
2016
skipSetActive : false ,
1947
2017
skipSetActiveGroup : true ,
1948
2018
} )
1949
- ) ;
2019
+ ) ;
1950
2020
1951
2021
if ( ! removedPanel ) {
1952
2022
throw new Error ( `No panel with id ${ sourceItemId } ` ) ;
1953
2023
}
1954
2024
1955
- if ( sourceGroup . model . size === 0 ) {
2025
+ if ( ! options . keepEmptyGroups && sourceGroup . model . size === 0 ) {
1956
2026
// remove the group and do not set a new group as active
1957
2027
this . doRemoveGroup ( sourceGroup , { skipActive : true } ) ;
1958
2028
}
1959
2029
1960
- this . movingLock ( ( ) =>
2030
+ this . runWithSuppressedEvents ( ( ) =>
1961
2031
destinationGroup . model . openPanel ( removedPanel , {
1962
2032
index : destinationIndex ,
1963
2033
skipSetGroupActive : true ,
@@ -2028,7 +2098,7 @@ export class DockviewComponent
2028
2098
) ! ;
2029
2099
2030
2100
const removedPanel : IDockviewPanel | undefined =
2031
- this . movingLock ( ( ) =>
2101
+ this . runWithSuppressedEvents ( ( ) =>
2032
2102
popoutGroup . popoutGroup . model . removePanel (
2033
2103
popoutGroup . popoutGroup . panels [ 0 ] ,
2034
2104
{
@@ -2041,7 +2111,7 @@ export class DockviewComponent
2041
2111
this . doRemoveGroup ( sourceGroup , { skipActive : true } ) ;
2042
2112
2043
2113
const newGroup = this . createGroupAtLocation ( targetLocation ) ;
2044
- this . movingLock ( ( ) =>
2114
+ this . runWithSuppressedEvents ( ( ) =>
2045
2115
newGroup . model . openPanel ( removedPanel , {
2046
2116
skipSetActive : true ,
2047
2117
} )
@@ -2056,7 +2126,7 @@ export class DockviewComponent
2056
2126
}
2057
2127
2058
2128
// source group will become empty so delete the group
2059
- const targetGroup = this . movingLock ( ( ) =>
2129
+ const targetGroup = this . runWithSuppressedEvents ( ( ) =>
2060
2130
this . doRemoveGroup ( sourceGroup , {
2061
2131
skipActive : true ,
2062
2132
skipDispose : true ,
@@ -2073,7 +2143,9 @@ export class DockviewComponent
2073
2143
updatedReferenceLocation ,
2074
2144
destinationTarget
2075
2145
) ;
2076
- this . movingLock ( ( ) => this . doAddGroup ( targetGroup , location ) ) ;
2146
+ this . runWithSuppressedEvents ( ( ) =>
2147
+ this . doAddGroup ( targetGroup , location )
2148
+ ) ;
2077
2149
this . doSetGroupAndPanelActive ( targetGroup ) ;
2078
2150
2079
2151
this . _onDidMovePanel . fire ( {
@@ -2086,7 +2158,7 @@ export class DockviewComponent
2086
2158
* create a new group, add the panels to that new group and add the new group in an appropiate position
2087
2159
*/
2088
2160
const removedPanel : IDockviewPanel | undefined =
2089
- this . movingLock ( ( ) =>
2161
+ this . runWithSuppressedEvents ( ( ) =>
2090
2162
sourceGroup . model . removePanel ( sourceItemId , {
2091
2163
skipSetActive : false ,
2092
2164
skipSetActiveGroup : true ,
@@ -2104,7 +2176,7 @@ export class DockviewComponent
2104
2176
) ;
2105
2177
2106
2178
const group = this . createGroupAtLocation ( dropLocation ) ;
2107
- this . movingLock ( ( ) =>
2179
+ this . runWithSuppressedEvents ( ( ) =>
2108
2180
group . model . openPanel ( removedPanel , {
2109
2181
skipSetGroupActive : true ,
2110
2182
} )
@@ -2127,7 +2199,7 @@ export class DockviewComponent
2127
2199
if ( target === 'center' ) {
2128
2200
const activePanel = from . activePanel ;
2129
2201
2130
- const panels = this . movingLock ( ( ) =>
2202
+ const panels = this . runWithSuppressedEvents ( ( ) =>
2131
2203
[ ...from . panels ] . map ( ( p ) =>
2132
2204
from . model . removePanel ( p . id , {
2133
2205
skipSetActive : true ,
@@ -2139,7 +2211,7 @@ export class DockviewComponent
2139
2211
this . doRemoveGroup ( from , { skipActive : true } ) ;
2140
2212
}
2141
2213
2142
- this . movingLock ( ( ) => {
2214
+ this . runWithSuppressedEvents ( ( ) => {
2143
2215
for ( const panel of panels ) {
2144
2216
to . model . openPanel ( panel , {
2145
2217
skipSetActive : panel !== activePanel ,
@@ -2213,7 +2285,7 @@ export class DockviewComponent
2213
2285
const activePanel = this . activePanel ;
2214
2286
2215
2287
if (
2216
- ! this . _moving &&
2288
+ ! this . _isEventSuppressionEnabled &&
2217
2289
activePanel !== this . _onDidActivePanelChange . value
2218
2290
) {
2219
2291
this . _onDidActivePanelChange . fire ( activePanel ) ;
@@ -2234,7 +2306,7 @@ export class DockviewComponent
2234
2306
}
2235
2307
2236
2308
if (
2237
- ! this . _moving &&
2309
+ ! this . _isEventSuppressionEnabled &&
2238
2310
activePanel !== this . _onDidActivePanelChange . value
2239
2311
) {
2240
2312
this . _onDidActivePanelChange . fire ( activePanel ) ;
@@ -2311,19 +2383,19 @@ export class DockviewComponent
2311
2383
this . _onUnhandledDragOverEvent . fire ( event ) ;
2312
2384
} ) ,
2313
2385
view . model . onDidAddPanel ( ( event ) => {
2314
- if ( this . _moving ) {
2386
+ if ( this . _isEventSuppressionEnabled ) {
2315
2387
return ;
2316
2388
}
2317
2389
this . _onDidAddPanel . fire ( event . panel ) ;
2318
2390
} ) ,
2319
2391
view . model . onDidRemovePanel ( ( event ) => {
2320
- if ( this . _moving ) {
2392
+ if ( this . _isEventSuppressionEnabled ) {
2321
2393
return ;
2322
2394
}
2323
2395
this . _onDidRemovePanel . fire ( event . panel ) ;
2324
2396
} ) ,
2325
2397
view . model . onDidActivePanelChange ( ( event ) => {
2326
- if ( this . _moving ) {
2398
+ if ( this . _isEventSuppressionEnabled ) {
2327
2399
return ;
2328
2400
}
2329
2401
if ( event . panel !== this . activePanel ) {
0 commit comments