11/********************************************************************************
2- * Copyright (c) 2019-2024 EclipseSource and others.
2+ * Copyright (c) 2019-2025 EclipseSource and others.
33 *
44 * This program and the accompanying materials are made available under the
55 * terms of the Eclipse Public License v. 2.0 which is available at
1414 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
1515 ********************************************************************************/
1616import {
17+ BoundsAwareViewportCommand ,
1718 CommandExecutionContext ,
1819 CommandStack ,
1920 Disposable ,
@@ -23,7 +24,11 @@ import {
2324 ICommand ,
2425 LazyInjector ,
2526 SetModelCommand ,
26- UpdateModelCommand
27+ SetViewportCommand ,
28+ UpdateModelCommand ,
29+ Viewport ,
30+ almostEquals ,
31+ isViewport
2732} from '@eclipse-glsp/sprotty' ;
2833import { inject , injectable , preDestroy } from 'inversify' ;
2934import { EditorContextService } from './editor-context-service' ;
@@ -33,6 +38,7 @@ export class GLSPCommandStack extends CommandStack implements Disposable {
3338 @inject ( LazyInjector )
3439 protected lazyInjector : LazyInjector ;
3540 protected toDispose = new DisposableCollection ( ) ;
41+ protected currentViewport ?: Readonly < Viewport > ;
3642
3743 @preDestroy ( )
3844 dispose ( ) : void {
@@ -95,13 +101,40 @@ export class GLSPCommandStack extends CommandStack implements Disposable {
95101 }
96102 override async execute ( command : ICommand ) : Promise < GModelRoot > {
97103 const result = await super . execute ( command ) ;
98- if ( command instanceof SetModelCommand || command instanceof UpdateModelCommand ) {
104+ if ( this . isModelChangeCommand ( command ) ) {
99105 this . notifyListeners ( result ) ;
106+ } else if ( this . isViewportChangeCommand ( command ) ) {
107+ this . notifyListeners ( result , true ) ;
100108 }
101109 return result ;
102110 }
103111
104- protected notifyListeners ( root : Readonly < GModelRoot > ) : void {
105- this . editorContext . notifyModelRootChanged ( root , this ) ;
112+ protected isModelChangeCommand ( command : ICommand ) : boolean {
113+ return command instanceof SetModelCommand || command instanceof UpdateModelCommand ;
114+ }
115+
116+ protected isViewportChangeCommand ( command : ICommand ) : boolean {
117+ return command instanceof SetViewportCommand || command instanceof BoundsAwareViewportCommand ;
118+ }
119+
120+ protected notifyListeners ( root : Readonly < GModelRoot > , isViewportChange = false ) : void {
121+ if ( ! isViewportChange ) {
122+ this . currentViewport = isViewport ( root ) ? { scroll : root . scroll , zoom : root . zoom } : undefined ;
123+ this . editorContext . notifyModelRootChanged ( root , this ) ;
124+ } else if ( isViewport ( root ) && this . hasViewportChanged ( root ) ) {
125+ this . currentViewport = { scroll : root . scroll , zoom : root . zoom } ;
126+ this . editorContext . notifyViewportChanged ( root , this ) ;
127+ }
128+ }
129+
130+ protected hasViewportChanged ( newViewport : Readonly < Viewport > ) : boolean {
131+ if ( ! this . currentViewport ) {
132+ return true ;
133+ }
134+ return ! (
135+ almostEquals ( newViewport . zoom , this . currentViewport . zoom ) &&
136+ almostEquals ( newViewport . scroll . x , this . currentViewport . scroll . x ) &&
137+ almostEquals ( newViewport . scroll . y , this . currentViewport . scroll . y )
138+ ) ;
106139 }
107140}
0 commit comments