@eclipse-glsp/client 1.1.0-next.93fd4ec.241 → 1.1.0-next.97e90c6.246

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/css/autocomplete-palette.css +22 -0
  2. package/css/glsp-sprotty.css +16 -1
  3. package/lib/base/auto-complete/auto-complete-widget.d.ts +8 -2
  4. package/lib/base/auto-complete/auto-complete-widget.d.ts.map +1 -1
  5. package/lib/base/auto-complete/auto-complete-widget.js +25 -6
  6. package/lib/base/auto-complete/auto-complete-widget.js.map +1 -1
  7. package/lib/features/accessibility/di.config.d.ts +21 -0
  8. package/lib/features/accessibility/di.config.d.ts.map +1 -0
  9. package/lib/features/accessibility/di.config.js +32 -0
  10. package/lib/features/accessibility/di.config.js.map +1 -0
  11. package/lib/features/accessibility/move-zoom/di.config.d.ts +23 -0
  12. package/lib/features/accessibility/move-zoom/di.config.d.ts.map +1 -0
  13. package/lib/features/accessibility/move-zoom/di.config.js +41 -0
  14. package/lib/features/accessibility/move-zoom/di.config.js.map +1 -0
  15. package/lib/features/accessibility/move-zoom/move-handler.d.ts +81 -0
  16. package/lib/features/accessibility/move-zoom/move-handler.d.ts.map +1 -0
  17. package/lib/features/accessibility/move-zoom/move-handler.js +173 -0
  18. package/lib/features/accessibility/move-zoom/move-handler.js.map +1 -0
  19. package/lib/features/accessibility/move-zoom/zoom-handler.d.ts +74 -0
  20. package/lib/features/accessibility/move-zoom/zoom-handler.d.ts.map +1 -0
  21. package/lib/features/accessibility/move-zoom/zoom-handler.js +159 -0
  22. package/lib/features/accessibility/move-zoom/zoom-handler.js.map +1 -0
  23. package/lib/features/accessibility/search/di.config.d.ts +20 -0
  24. package/lib/features/accessibility/search/di.config.d.ts.map +1 -0
  25. package/lib/features/accessibility/search/di.config.js +33 -0
  26. package/lib/features/accessibility/search/di.config.js.map +1 -0
  27. package/lib/features/accessibility/search/search-palette.d.ts +47 -0
  28. package/lib/features/accessibility/search/search-palette.d.ts.map +1 -0
  29. package/lib/features/accessibility/search/search-palette.js +155 -0
  30. package/lib/features/accessibility/search/search-palette.js.map +1 -0
  31. package/lib/features/accessibility/search/search-tool.d.ts +30 -0
  32. package/lib/features/accessibility/search/search-tool.d.ts.map +1 -0
  33. package/lib/features/accessibility/search/search-tool.js +73 -0
  34. package/lib/features/accessibility/search/search-tool.js.map +1 -0
  35. package/lib/features/accessibility/view-key-tools/deselect-key-tool.d.ts +35 -0
  36. package/lib/features/accessibility/view-key-tools/deselect-key-tool.d.ts.map +1 -0
  37. package/lib/features/accessibility/view-key-tools/deselect-key-tool.js +87 -0
  38. package/lib/features/accessibility/view-key-tools/deselect-key-tool.js.map +1 -0
  39. package/lib/features/accessibility/view-key-tools/di.config.d.ts +20 -0
  40. package/lib/features/accessibility/view-key-tools/di.config.d.ts.map +1 -0
  41. package/lib/features/accessibility/view-key-tools/di.config.js +35 -0
  42. package/lib/features/accessibility/view-key-tools/di.config.js.map +1 -0
  43. package/lib/features/accessibility/view-key-tools/movement-key-tool.d.ts +49 -0
  44. package/lib/features/accessibility/view-key-tools/movement-key-tool.d.ts.map +1 -0
  45. package/lib/features/accessibility/view-key-tools/movement-key-tool.js +131 -0
  46. package/lib/features/accessibility/view-key-tools/movement-key-tool.js.map +1 -0
  47. package/lib/features/accessibility/view-key-tools/zoom-key-tool.d.ts +43 -0
  48. package/lib/features/accessibility/view-key-tools/zoom-key-tool.d.ts.map +1 -0
  49. package/lib/features/accessibility/view-key-tools/zoom-key-tool.js +109 -0
  50. package/lib/features/accessibility/view-key-tools/zoom-key-tool.js.map +1 -0
  51. package/lib/features/autocomplete-palette/autocomplete-suggestion-providers.d.ts +35 -0
  52. package/lib/features/autocomplete-palette/autocomplete-suggestion-providers.d.ts.map +1 -0
  53. package/lib/features/autocomplete-palette/autocomplete-suggestion-providers.js +18 -0
  54. package/lib/features/autocomplete-palette/autocomplete-suggestion-providers.js.map +1 -0
  55. package/lib/features/autocomplete-palette/base-autocomplete-palette.d.ts +41 -0
  56. package/lib/features/autocomplete-palette/base-autocomplete-palette.d.ts.map +1 -0
  57. package/lib/features/autocomplete-palette/base-autocomplete-palette.js +82 -0
  58. package/lib/features/autocomplete-palette/base-autocomplete-palette.js.map +1 -0
  59. package/lib/index.d.ts +10 -3
  60. package/lib/index.d.ts.map +1 -1
  61. package/lib/index.js +59 -48
  62. package/lib/index.js.map +1 -1
  63. package/package.json +5 -3
  64. package/src/base/auto-complete/auto-complete-widget.ts +31 -7
  65. package/src/features/accessibility/di.config.ts +30 -0
  66. package/src/features/accessibility/move-zoom/di.config.ts +43 -0
  67. package/src/features/accessibility/move-zoom/move-handler.ts +198 -0
  68. package/src/features/accessibility/move-zoom/zoom-handler.ts +178 -0
  69. package/src/features/accessibility/search/di.config.ts +31 -0
  70. package/src/features/accessibility/search/search-palette.ts +181 -0
  71. package/src/features/accessibility/search/search-tool.ts +60 -0
  72. package/src/features/accessibility/view-key-tools/deselect-key-tool.ts +80 -0
  73. package/src/features/accessibility/view-key-tools/di.config.ts +33 -0
  74. package/src/features/accessibility/view-key-tools/movement-key-tool.ts +115 -0
  75. package/src/features/accessibility/view-key-tools/zoom-key-tool.ts +94 -0
  76. package/src/features/autocomplete-palette/autocomplete-suggestion-providers.ts +37 -0
  77. package/src/features/autocomplete-palette/base-autocomplete-palette.ts +88 -0
  78. package/src/index.ts +14 -3
@@ -0,0 +1,43 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { BindingContext } from '@eclipse-glsp/protocol';
18
+ import { ContainerModule } from 'inversify';
19
+ import { configureActionHandler } from 'sprotty';
20
+ import { MoveElementAction, MoveElementHandler, MoveViewportAction, MoveViewportHandler } from './move-handler';
21
+ import { ZoomElementAction, ZoomElementHandler, ZoomViewportAction, ZoomViewportHandler } from './zoom-handler';
22
+
23
+ /**
24
+ * Handles move and zoom actions.
25
+ */
26
+ export const glspMoveZoomModule = new ContainerModule((bind, unbind, isBound, rebind) => {
27
+ const context = { bind, unbind, isBound, rebind };
28
+ configureMoveZoom(context);
29
+ });
30
+
31
+ export function configureMoveZoom(context: BindingContext): void {
32
+ context.bind(MoveViewportHandler).toSelf().inSingletonScope();
33
+ context.bind(MoveElementHandler).toSelf().inSingletonScope();
34
+
35
+ context.bind(ZoomViewportHandler).toSelf().inSingletonScope();
36
+ context.bind(ZoomElementHandler).toSelf().inSingletonScope();
37
+
38
+ configureActionHandler(context, MoveViewportAction.KIND, MoveViewportHandler);
39
+ configureActionHandler(context, MoveElementAction.KIND, MoveElementHandler);
40
+
41
+ configureActionHandler(context, ZoomViewportAction.KIND, ZoomViewportHandler);
42
+ configureActionHandler(context, ZoomElementAction.KIND, ZoomElementHandler);
43
+ }
@@ -0,0 +1,198 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { Action, ChangeBoundsOperation, Point, SetViewportAction, Viewport } from '@eclipse-glsp/protocol';
18
+ import { inject, injectable } from 'inversify';
19
+ import { throttle } from 'lodash';
20
+ import { findParentByFeature, IActionDispatcher, IActionHandler, ICommand, isViewport, SModelRoot } from 'sprotty';
21
+ import { EditorContextService } from '../../../base/editor-context-service';
22
+ import { TYPES } from '../../../base/types';
23
+ import { getElements, isSelectableAndBoundsAware, SelectableBoundsAware } from '../../../utils/smodel-util';
24
+
25
+ /**
26
+ * Action for triggering moving of the viewport.
27
+ */
28
+ export interface MoveViewportAction extends Action {
29
+ kind: typeof MoveViewportAction.KIND;
30
+ /**
31
+ * used to specify the amount to be moved in the x-axis
32
+ */
33
+ moveX: number;
34
+ /**
35
+ * used to specify the amount to be moved in the y-axis
36
+ */
37
+ moveY: number;
38
+ }
39
+
40
+ export namespace MoveViewportAction {
41
+ export const KIND = 'moveViewportAction';
42
+
43
+ export function is(object: any): object is MoveViewportAction {
44
+ return Action.hasKind(object, KIND);
45
+ }
46
+
47
+ export function create(moveX: number, moveY: number): MoveViewportAction {
48
+ return { kind: KIND, moveX, moveY };
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Action for triggering moving of elements.
54
+ */
55
+ export interface MoveElementAction extends Action {
56
+ kind: typeof MoveElementAction.KIND;
57
+ /**
58
+ * used to specify the elements to be zoomed in/out
59
+ */
60
+ elementIds: string[];
61
+ /**
62
+ * used to specify the amount to be moved in the x-axis
63
+ */
64
+ moveX: number;
65
+ /**
66
+ * used to specify the amount to be moved in the y-axis
67
+ */
68
+ moveY: number;
69
+ }
70
+
71
+ export namespace MoveElementAction {
72
+ export const KIND = 'moveElementAction';
73
+
74
+ export function is(object: any): object is MoveElementAction {
75
+ return Action.hasKind(object, KIND);
76
+ }
77
+
78
+ export function create(elementIds: string[], moveX: number, moveY: number): MoveElementAction {
79
+ return { kind: KIND, elementIds, moveX, moveY };
80
+ }
81
+ }
82
+
83
+ /* The MoveViewportHandler class is an implementation of the IActionHandler interface that handles
84
+ moving of the viewport. */
85
+ @injectable()
86
+ export class MoveViewportHandler implements IActionHandler {
87
+ @inject(EditorContextService)
88
+ protected editorContextService: EditorContextService;
89
+
90
+ @inject(TYPES.IActionDispatcher) protected dispatcher: IActionDispatcher;
91
+ protected readonly throttledHandleViewportMove = throttle((action: MoveViewportAction) => this.handleMoveViewport(action), 150);
92
+
93
+ handle(action: Action): void | Action | ICommand {
94
+ if (MoveViewportAction.is(action)) {
95
+ this.throttledHandleViewportMove(action);
96
+ }
97
+ }
98
+
99
+ handleMoveViewport(action: MoveViewportAction): void {
100
+ const viewport = findParentByFeature(this.editorContextService.modelRoot, isViewport);
101
+ if (!viewport) {
102
+ return;
103
+ }
104
+ this.dispatcher.dispatch(this.moveViewport(viewport, action.moveX, action.moveY));
105
+ }
106
+
107
+ protected moveViewport(viewport: SModelRoot & Viewport, offsetX: number, offSetY: number): SetViewportAction {
108
+ const newViewport: Viewport = {
109
+ scroll: {
110
+ x: viewport.scroll.x + offsetX,
111
+ y: viewport.scroll.y + offSetY
112
+ },
113
+ zoom: viewport.zoom
114
+ };
115
+
116
+ return SetViewportAction.create(viewport.id, newViewport, { animate: true });
117
+ }
118
+ }
119
+
120
+ /* The MoveElementHandler class is an implementation of the IActionHandler interface that handles
121
+ moving elements. */
122
+ @injectable()
123
+ export class MoveElementHandler implements IActionHandler {
124
+ @inject(EditorContextService)
125
+ protected editorContextService: EditorContextService;
126
+ @inject(TYPES.IActionDispatcher) protected dispatcher: IActionDispatcher;
127
+ protected readonly throttledHandleElementMove = throttle((action: MoveElementAction) => this.handleMoveElement(action), 150);
128
+
129
+ handle(action: Action): void | Action | ICommand {
130
+ if (MoveElementAction.is(action)) {
131
+ this.throttledHandleElementMove(action);
132
+ }
133
+ }
134
+
135
+ handleMoveElement(action: MoveElementAction): void {
136
+ const viewport = findParentByFeature(this.editorContextService.modelRoot, isViewport);
137
+ if (!viewport) {
138
+ return;
139
+ }
140
+
141
+ const elements = getElements(this.editorContextService.modelRoot.index, action.elementIds, isSelectableAndBoundsAware);
142
+
143
+ this.dispatcher.dispatchAll(this.move(viewport, elements, action.moveX, action.moveY));
144
+ }
145
+
146
+ protected getBounds(element: SelectableBoundsAware, offSetX: number, offSetY: number): Point {
147
+ return { x: element.bounds.x + offSetX, y: element.bounds.y + offSetY };
148
+ }
149
+
150
+ protected adaptViewport(
151
+ viewport: SModelRoot & Viewport,
152
+ newPoint: Point,
153
+ moveX: number,
154
+ moveY: number
155
+ ): MoveViewportAction | undefined {
156
+ if (
157
+ newPoint.x < viewport.scroll.x ||
158
+ newPoint.x > viewport.scroll.x + viewport.canvasBounds.width ||
159
+ newPoint.y < viewport.scroll.y ||
160
+ newPoint.y > viewport.scroll.y + viewport.canvasBounds.height
161
+ ) {
162
+ return MoveViewportAction.create(moveX, moveY);
163
+ }
164
+ return;
165
+ }
166
+
167
+ protected moveElement(element: SelectableBoundsAware, offSetX: number, offSetY: number): ChangeBoundsOperation {
168
+ return ChangeBoundsOperation.create([
169
+ {
170
+ elementId: element.id,
171
+ newSize: {
172
+ width: element.bounds.width,
173
+ height: element.bounds.height
174
+ },
175
+ newPosition: {
176
+ x: element.bounds.x + offSetX,
177
+ y: element.bounds.y + offSetY
178
+ }
179
+ }
180
+ ]);
181
+ }
182
+
183
+ protected move(viewport: SModelRoot & Viewport, selectedElements: SelectableBoundsAware[], deltaX: number, deltaY: number): Action[] {
184
+ const results: Action[] = [];
185
+
186
+ if (selectedElements.length !== 0) {
187
+ selectedElements.forEach(currentElement => {
188
+ results.push(this.moveElement(currentElement, deltaX, deltaY));
189
+ const newPosition = this.getBounds(currentElement, deltaX, deltaY);
190
+ const viewportAction = this.adaptViewport(viewport, newPosition, deltaX, deltaY);
191
+ if (viewportAction) {
192
+ results.push(viewportAction);
193
+ }
194
+ });
195
+ }
196
+ return results;
197
+ }
198
+ }
@@ -0,0 +1,178 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { Action, Bounds, Point, SetViewportAction, Viewport } from '@eclipse-glsp/protocol';
18
+ import { inject, injectable } from 'inversify';
19
+ import { throttle } from 'lodash';
20
+ import {
21
+ findParentByFeature,
22
+ IActionDispatcher,
23
+ IActionHandler,
24
+ ICommand,
25
+ isViewport,
26
+ SChildElement,
27
+ SModelElement,
28
+ SModelRoot
29
+ } from 'sprotty';
30
+ import { EditorContextService } from '../../../base/editor-context-service';
31
+ import { TYPES } from '../../../base/types';
32
+ import { getElements, isSelectableAndBoundsAware, SelectableBoundsAware } from '../../../utils/smodel-util';
33
+
34
+ /**
35
+ * Action for triggering zooming of the viewport.
36
+ */
37
+ export interface ZoomViewportAction extends Action {
38
+ kind: typeof ZoomViewportAction.KIND;
39
+ /**
40
+ * used to specify the amount by which the viewport should be zoomed
41
+ */
42
+ zoomFactor: number;
43
+ }
44
+
45
+ export namespace ZoomViewportAction {
46
+ export const KIND = 'zoomViewportAction';
47
+
48
+ export function is(object: any): object is ZoomViewportAction {
49
+ return Action.hasKind(object, KIND);
50
+ }
51
+
52
+ export function create(zoomFactor: number): ZoomViewportAction {
53
+ return { kind: KIND, zoomFactor };
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Action for triggering zooming of the elements..
59
+ */
60
+ export interface ZoomElementAction extends Action {
61
+ kind: typeof ZoomElementAction.KIND;
62
+ /**
63
+ * used to specify the elements to be zoomed in/out
64
+ */
65
+ elementIds: string[];
66
+ /**
67
+ * used to specify the amount by which the viewport should be zoomed
68
+ */
69
+ zoomFactor: number;
70
+ }
71
+
72
+ export namespace ZoomElementAction {
73
+ export const KIND = 'zoomElementAction';
74
+
75
+ export function is(object: any): object is ZoomElementAction {
76
+ return Action.hasKind(object, KIND);
77
+ }
78
+
79
+ export function create(elementIds: string[], zoomFactor: number): ZoomElementAction {
80
+ return { kind: KIND, elementIds, zoomFactor };
81
+ }
82
+ }
83
+
84
+ /* The ZoomViewportHandler class is an implementation of the IActionHandler interface that handles
85
+ zooming in and out of a viewport. */
86
+ @injectable()
87
+ export class ZoomViewportHandler implements IActionHandler {
88
+ @inject(EditorContextService)
89
+ protected editorContextService: EditorContextService;
90
+
91
+ static readonly defaultZoomInFactor = 1.1;
92
+ static readonly defaultZoomOutFactor = 0.9;
93
+
94
+ @inject(TYPES.IActionDispatcher) protected dispatcher: IActionDispatcher;
95
+ protected readonly throttledHandleViewportZoom = throttle((action: ZoomViewportAction) => this.handleZoomViewport(action), 150);
96
+
97
+ handle(action: Action): void {
98
+ if (ZoomViewportAction.is(action)) {
99
+ this.throttledHandleViewportZoom(action);
100
+ }
101
+ }
102
+
103
+ handleZoomViewport(action: ZoomViewportAction): void {
104
+ const viewport = findParentByFeature(this.editorContextService.modelRoot, isViewport);
105
+ if (!viewport) {
106
+ return;
107
+ }
108
+ this.dispatcher.dispatch(this.setNewZoomFactor(viewport, action.zoomFactor));
109
+ }
110
+
111
+ protected setNewZoomFactor(viewport: SModelRoot & Viewport, zoomFactor: number): SetViewportAction {
112
+ const newZoom = viewport.zoom * zoomFactor;
113
+
114
+ const newViewport = {
115
+ scroll: viewport.scroll,
116
+ zoom: newZoom
117
+ };
118
+
119
+ return SetViewportAction.create(viewport.id, newViewport, { animate: true });
120
+ }
121
+ }
122
+
123
+ /* The ZoomElementHandler class is an implementation of the IActionHandler interface that handles
124
+ zooming in and out of elements. */
125
+ @injectable()
126
+ export class ZoomElementHandler implements IActionHandler {
127
+ @inject(EditorContextService)
128
+ protected editorContextService: EditorContextService;
129
+ @inject(TYPES.IActionDispatcher) protected dispatcher: IActionDispatcher;
130
+ protected readonly throttledHandleElementZoom = throttle((action: ZoomElementAction) => this.handleZoomElement(action), 150);
131
+
132
+ handle(action: Action): void | Action | ICommand {
133
+ if (ZoomElementAction.is(action)) {
134
+ this.throttledHandleElementZoom(action);
135
+ }
136
+ }
137
+
138
+ handleZoomElement(action: ZoomElementAction): void {
139
+ const viewport = findParentByFeature(this.editorContextService.modelRoot, isViewport);
140
+ if (!viewport) {
141
+ return;
142
+ }
143
+
144
+ const elements = getElements(this.editorContextService.modelRoot.index, action.elementIds, isSelectableAndBoundsAware);
145
+ const center = this.getCenter(viewport, elements);
146
+ this.dispatcher.dispatch(this.setNewZoomFactor(viewport, action.zoomFactor, center));
147
+ }
148
+
149
+ protected getCenter(viewport: SModelRoot & Viewport, selectedElements: SelectableBoundsAware[]): Point {
150
+ // Get bounds of elements based on the viewport
151
+ const allBounds = selectedElements.map(e => this.boundsInViewport(viewport, e, e.bounds));
152
+ const mergedBounds = allBounds.reduce((b0, b1) => Bounds.combine(b0, b1));
153
+ return Bounds.center(mergedBounds);
154
+ }
155
+
156
+ // copy from center-fit.ts, translates the children bounds to the viewport bounds
157
+ protected boundsInViewport(viewport: SModelRoot & Viewport, element: SModelElement, bounds: Bounds): Bounds {
158
+ if (element instanceof SChildElement && element.parent !== viewport) {
159
+ return this.boundsInViewport(viewport, element.parent, element.parent.localToParent(bounds) as Bounds);
160
+ } else {
161
+ return bounds;
162
+ }
163
+ }
164
+
165
+ protected setNewZoomFactor(viewport: SModelRoot & Viewport, zoomFactor: number, point: Point): SetViewportAction {
166
+ const newZoom = viewport.zoom * zoomFactor;
167
+
168
+ const newViewport = {
169
+ scroll: {
170
+ x: point.x - (0.5 * viewport.canvasBounds.width) / newZoom,
171
+ y: point.y - (0.5 * viewport.canvasBounds.height) / newZoom
172
+ },
173
+ zoom: newZoom
174
+ };
175
+
176
+ return SetViewportAction.create(viewport.id, newViewport, { animate: true });
177
+ }
178
+ }
@@ -0,0 +1,31 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { bindAsService, BindingContext } from '@eclipse-glsp/protocol';
18
+ import { ContainerModule } from 'inversify';
19
+ import { TYPES } from '../../../base/types';
20
+ import { SearchAutocompletePalette } from './search-palette';
21
+ import { SearchAutocompletePaletteTool } from './search-tool';
22
+
23
+ export const glspSearchPaletteModule = new ContainerModule((bind, _unbind, isBound, rebind) => {
24
+ const context = { bind, isBound, rebind };
25
+ configureSearchPaletteModule(context);
26
+ });
27
+
28
+ export function configureSearchPaletteModule(context: Pick<BindingContext, 'bind'>): void {
29
+ bindAsService(context, TYPES.IUIExtension, SearchAutocompletePalette);
30
+ bindAsService(context, TYPES.IDefaultTool, SearchAutocompletePaletteTool);
31
+ }
@@ -0,0 +1,181 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 Business Informatics Group (TU Wien) and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { Action, CenterAction, SelectAction, SelectAllAction } from '@eclipse-glsp/protocol';
18
+ import { injectable } from 'inversify';
19
+ import { isEqual } from 'lodash';
20
+ import { codiconCSSString, isNameable, LabeledAction, name, SEdge, SModelElement, SModelRoot, SNode } from 'sprotty';
21
+ import { toArray } from 'sprotty/lib/utils/iterable';
22
+ import { AutocompleteSuggestion, IAutocompleteSuggestionProvider } from '../../autocomplete-palette/autocomplete-suggestion-providers';
23
+ import { BaseAutocompletePalette } from '../../autocomplete-palette/base-autocomplete-palette';
24
+
25
+ import { applyCssClasses, deleteCssClasses } from '../../tool-feedback/css-feedback';
26
+
27
+ const CSS_SEARCH_HIDDEN = 'search-hidden';
28
+ const CSS_SEARCH_HIGHLIGHTED = 'search-highlighted';
29
+
30
+ export class RevealNamedElementAutocompleteSuggestionProvider implements IAutocompleteSuggestionProvider {
31
+ async retrieveSuggestions(root: Readonly<SModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
32
+ const nameables = toArray(root.index.all().filter(element => isNameable(element)));
33
+ return nameables.map(nameable => ({
34
+ element: nameable,
35
+ action: new LabeledAction(
36
+ `[${nameable.type}] ${name(nameable) ?? '<no-name>'}`,
37
+ this.getActions(nameable),
38
+ codiconCSSString('eye')
39
+ )
40
+ }));
41
+ }
42
+
43
+ protected getActions(nameable: SModelElement): Action[] {
44
+ return [SelectAction.create({ selectedElementsIDs: [nameable.id] }), CenterAction.create([nameable.id], { retainZoom: true })];
45
+ }
46
+ }
47
+
48
+ export class RevealEdgeElementAutocompleteSuggestionProvider implements IAutocompleteSuggestionProvider {
49
+ async retrieveSuggestions(root: Readonly<SModelRoot>, text: string): Promise<AutocompleteSuggestion[]> {
50
+ const edges = toArray(root.index.all().filter(element => element instanceof SEdge)) as SEdge[];
51
+ return edges.map(edge => ({
52
+ element: edge,
53
+ action: new LabeledAction(
54
+ `[${edge.type}] ` + this.getEdgeLabel(root, edge),
55
+ this.getActions(edge),
56
+ codiconCSSString('arrow-both')
57
+ )
58
+ }));
59
+ }
60
+ protected getActions(edge: SEdge): Action[] {
61
+ return [SelectAction.create({ selectedElementsIDs: [edge.id] }), CenterAction.create([edge.sourceId, edge.targetId])];
62
+ }
63
+ protected getEdgeLabel(root: Readonly<SModelRoot>, edge: SEdge): string {
64
+ let sourceName = '';
65
+ let targetName = '';
66
+
67
+ const sourceNode = root.index.getById(edge.sourceId);
68
+ const targetNode = root.index.getById(edge.targetId);
69
+
70
+ if (sourceNode !== undefined) {
71
+ sourceName = name(sourceNode) ?? sourceNode.type;
72
+ }
73
+ if (targetNode !== undefined) {
74
+ targetName = name(targetNode) ?? targetNode.type;
75
+ }
76
+
77
+ return sourceName + ' -> ' + targetName;
78
+ }
79
+ }
80
+ @injectable()
81
+ export class SearchAutocompletePalette extends BaseAutocompletePalette {
82
+ static readonly ID = 'search-autocomplete-palette';
83
+
84
+ protected cachedSuggestions: AutocompleteSuggestion[] = [];
85
+
86
+ id(): string {
87
+ return SearchAutocompletePalette.ID;
88
+ }
89
+
90
+ protected override initializeContents(containerElement: HTMLElement): void {
91
+ super.initializeContents(containerElement);
92
+
93
+ this.autocompleteWidget.inputField.placeholder = 'Search for elements';
94
+ }
95
+ protected getSuggestionProviders(root: Readonly<SModelRoot>, input: string): IAutocompleteSuggestionProvider[] {
96
+ return [new RevealNamedElementAutocompleteSuggestionProvider(), new RevealEdgeElementAutocompleteSuggestionProvider()];
97
+ }
98
+ protected async retrieveSuggestions(root: Readonly<SModelRoot>, input: string): Promise<LabeledAction[]> {
99
+ const providers = this.getSuggestionProviders(root, input);
100
+ const suggestions = (await Promise.all(providers.map(provider => provider.retrieveSuggestions(root, input)))).flat(1);
101
+
102
+ this.cachedSuggestions = suggestions;
103
+
104
+ return suggestions.map(s => s.action);
105
+ }
106
+
107
+ protected override async visibleSuggestionsChanged(root: Readonly<SModelRoot>, labeledActions: LabeledAction[]): Promise<void> {
108
+ await this.applyCSS(this.getHiddenElements(root, this.getSuggestionsFromLabeledActions(labeledActions)), CSS_SEARCH_HIDDEN);
109
+ await this.deleteCSS(
110
+ this.getSuggestionsFromLabeledActions(labeledActions).map(s => s.element),
111
+ CSS_SEARCH_HIDDEN
112
+ );
113
+ }
114
+
115
+ protected override async selectedSuggestionChanged(
116
+ root: Readonly<SModelRoot>,
117
+ labeledAction?: LabeledAction | undefined
118
+ ): Promise<void> {
119
+ await this.deleteAllCSS(root, CSS_SEARCH_HIGHLIGHTED);
120
+ if (labeledAction !== undefined) {
121
+ const suggestions = this.getSuggestionsFromLabeledActions([labeledAction]);
122
+
123
+ const actions: CenterAction[] = [];
124
+ suggestions.map(currElem => actions.push(CenterAction.create([currElem.element.id], { animate: true, retainZoom: true })));
125
+
126
+ this.actionDispatcher.dispatchAll(actions);
127
+ await this.applyCSS(
128
+ suggestions.map(s => s.element),
129
+ CSS_SEARCH_HIGHLIGHTED
130
+ );
131
+ }
132
+ }
133
+
134
+ public override show(root: Readonly<SModelRoot>, ...contextElementIds: string[]): void {
135
+ this.actionDispatcher.dispatch(SelectAllAction.create(false));
136
+
137
+ super.show(root, ...contextElementIds);
138
+ }
139
+
140
+ public override hide(): void {
141
+ if (this.root !== undefined) {
142
+ this.deleteAllCSS(this.root, CSS_SEARCH_HIDDEN);
143
+ this.deleteAllCSS(this.root, CSS_SEARCH_HIGHLIGHTED);
144
+ this.autocompleteWidget.inputField.value = '';
145
+ }
146
+
147
+ super.hide();
148
+ }
149
+
150
+ protected applyCSS(elements: SModelElement[], cssClass: string): Promise<void> {
151
+ const actions = elements.map(element => applyCssClasses(element, cssClass));
152
+ return this.actionDispatcher.dispatchAll(actions);
153
+ }
154
+
155
+ protected deleteCSS(elements: SModelElement[], cssClass: string): Promise<void> {
156
+ const actions = elements.map(element => deleteCssClasses(element, cssClass));
157
+ return this.actionDispatcher.dispatchAll(actions);
158
+ }
159
+
160
+ protected deleteAllCSS(root: Readonly<SModelRoot>, cssClass: string): Promise<void> {
161
+ const actions = toArray(root.index.all().map(element => deleteCssClasses(element, cssClass)));
162
+ return this.actionDispatcher.dispatchAll(actions);
163
+ }
164
+
165
+ protected getSuggestionsFromLabeledActions(labeledActions: LabeledAction[]): AutocompleteSuggestion[] {
166
+ return this.cachedSuggestions.filter(c => labeledActions.find(s => isEqual(s, c.action)));
167
+ }
168
+
169
+ protected getHiddenSuggestionsFromLabeledActions(labeledActions: LabeledAction[]): AutocompleteSuggestion[] {
170
+ return this.cachedSuggestions.filter(c => !labeledActions.find(s => isEqual(s, c.action)));
171
+ }
172
+
173
+ protected getHiddenElements(root: Readonly<SModelRoot>, suggestions: AutocompleteSuggestion[]): SModelElement[] {
174
+ return toArray(
175
+ root.index
176
+ .all()
177
+ .filter(element => element instanceof SNode || element instanceof SEdge)
178
+ .filter(element => suggestions.find(suggestion => suggestion.element.id === element.id) === undefined)
179
+ );
180
+ }
181
+ }