@eclipse-glsp/client 2.2.0-next.329 → 2.2.0-next.330

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 (174) hide show
  1. package/css/change-bounds.css +15 -0
  2. package/css/glsp-sprotty.css +17 -0
  3. package/lib/base/drag-aware-mouse-listener.d.ts +5 -2
  4. package/lib/base/drag-aware-mouse-listener.d.ts.map +1 -1
  5. package/lib/base/drag-aware-mouse-listener.js +11 -0
  6. package/lib/base/drag-aware-mouse-listener.js.map +1 -1
  7. package/lib/base/feedback/css-feedback.d.ts +4 -0
  8. package/lib/base/feedback/css-feedback.d.ts.map +1 -1
  9. package/lib/base/feedback/css-feedback.js +4 -0
  10. package/lib/base/feedback/css-feedback.js.map +1 -1
  11. package/lib/base/feedback/feeback-emitter.d.ts +67 -0
  12. package/lib/base/feedback/feeback-emitter.d.ts.map +1 -0
  13. package/lib/base/feedback/feeback-emitter.js +109 -0
  14. package/lib/base/feedback/feeback-emitter.js.map +1 -0
  15. package/lib/base/feedback/feedback-action-dispatcher.d.ts +17 -5
  16. package/lib/base/feedback/feedback-action-dispatcher.d.ts.map +1 -1
  17. package/lib/base/feedback/feedback-action-dispatcher.js +23 -3
  18. package/lib/base/feedback/feedback-action-dispatcher.js.map +1 -1
  19. package/lib/base/feedback/index.d.ts +1 -0
  20. package/lib/base/feedback/index.d.ts.map +1 -1
  21. package/lib/base/feedback/index.js +1 -0
  22. package/lib/base/feedback/index.js.map +1 -1
  23. package/lib/base/selection-service.d.ts +3 -2
  24. package/lib/base/selection-service.d.ts.map +1 -1
  25. package/lib/base/selection-service.js.map +1 -1
  26. package/lib/features/accessibility/element-navigation/local-element-navigator.d.ts +3 -3
  27. package/lib/features/accessibility/element-navigation/local-element-navigator.d.ts.map +1 -1
  28. package/lib/features/accessibility/element-navigation/local-element-navigator.js.map +1 -1
  29. package/lib/features/accessibility/move-zoom/move-handler.d.ts +4 -2
  30. package/lib/features/accessibility/move-zoom/move-handler.d.ts.map +1 -1
  31. package/lib/features/accessibility/move-zoom/move-handler.js +10 -4
  32. package/lib/features/accessibility/move-zoom/move-handler.js.map +1 -1
  33. package/lib/features/accessibility/resize-key-tool/resize-key-handler.d.ts +4 -2
  34. package/lib/features/accessibility/resize-key-tool/resize-key-handler.d.ts.map +1 -1
  35. package/lib/features/accessibility/resize-key-tool/resize-key-handler.js +11 -3
  36. package/lib/features/accessibility/resize-key-tool/resize-key-handler.js.map +1 -1
  37. package/lib/features/change-bounds/model.d.ts +8 -8
  38. package/lib/features/change-bounds/model.d.ts.map +1 -1
  39. package/lib/features/change-bounds/model.js +17 -5
  40. package/lib/features/change-bounds/model.js.map +1 -1
  41. package/lib/features/change-bounds/movement-restrictor.d.ts +3 -2
  42. package/lib/features/change-bounds/movement-restrictor.d.ts.map +1 -1
  43. package/lib/features/change-bounds/movement-restrictor.js.map +1 -1
  44. package/lib/features/element-template/mouse-tracking-element-position-listener.d.ts +15 -5
  45. package/lib/features/element-template/mouse-tracking-element-position-listener.d.ts.map +1 -1
  46. package/lib/features/element-template/mouse-tracking-element-position-listener.js +27 -38
  47. package/lib/features/element-template/mouse-tracking-element-position-listener.js.map +1 -1
  48. package/lib/features/helper-lines/helper-line-manager-default.d.ts +4 -2
  49. package/lib/features/helper-lines/helper-line-manager-default.d.ts.map +1 -1
  50. package/lib/features/helper-lines/helper-line-manager-default.js +8 -12
  51. package/lib/features/helper-lines/helper-line-manager-default.js.map +1 -1
  52. package/lib/features/hints/type-hint-provider.d.ts +3 -0
  53. package/lib/features/hints/type-hint-provider.d.ts.map +1 -1
  54. package/lib/features/hints/type-hint-provider.js +10 -1
  55. package/lib/features/hints/type-hint-provider.js.map +1 -1
  56. package/lib/features/select/select-mouse-listener.d.ts +4 -3
  57. package/lib/features/select/select-mouse-listener.d.ts.map +1 -1
  58. package/lib/features/select/select-mouse-listener.js.map +1 -1
  59. package/lib/features/tools/base-tools.d.ts +23 -4
  60. package/lib/features/tools/base-tools.d.ts.map +1 -1
  61. package/lib/features/tools/base-tools.js +11 -6
  62. package/lib/features/tools/base-tools.js.map +1 -1
  63. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.d.ts +1 -35
  64. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.d.ts.map +1 -1
  65. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js +5 -206
  66. package/lib/features/tools/change-bounds/change-bounds-tool-feedback.js.map +1 -1
  67. package/lib/features/tools/change-bounds/change-bounds-tool-module.d.ts +1 -0
  68. package/lib/features/tools/change-bounds/change-bounds-tool-module.d.ts.map +1 -1
  69. package/lib/features/tools/change-bounds/change-bounds-tool-module.js +1 -0
  70. package/lib/features/tools/change-bounds/change-bounds-tool-module.js.map +1 -1
  71. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts +67 -0
  72. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.d.ts.map +1 -0
  73. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js +227 -0
  74. package/lib/features/tools/change-bounds/change-bounds-tool-move-feedback.js.map +1 -0
  75. package/lib/features/tools/change-bounds/change-bounds-tool.d.ts +34 -24
  76. package/lib/features/tools/change-bounds/change-bounds-tool.d.ts.map +1 -1
  77. package/lib/features/tools/change-bounds/change-bounds-tool.js +172 -180
  78. package/lib/features/tools/change-bounds/change-bounds-tool.js.map +1 -1
  79. package/lib/features/tools/change-bounds/index.d.ts +1 -0
  80. package/lib/features/tools/change-bounds/index.d.ts.map +1 -1
  81. package/lib/features/tools/change-bounds/index.js +1 -0
  82. package/lib/features/tools/change-bounds/index.js.map +1 -1
  83. package/lib/features/tools/change-bounds/view.d.ts +1 -1
  84. package/lib/features/tools/change-bounds/view.d.ts.map +1 -1
  85. package/lib/features/tools/change-bounds/view.js +3 -0
  86. package/lib/features/tools/change-bounds/view.js.map +1 -1
  87. package/lib/features/tools/deletion/delete-tool.d.ts +16 -1
  88. package/lib/features/tools/deletion/delete-tool.d.ts.map +1 -1
  89. package/lib/features/tools/deletion/delete-tool.js +5 -2
  90. package/lib/features/tools/deletion/delete-tool.js.map +1 -1
  91. package/lib/features/tools/edge-creation/dangling-edge-feedback.d.ts +17 -1
  92. package/lib/features/tools/edge-creation/dangling-edge-feedback.d.ts.map +1 -1
  93. package/lib/features/tools/edge-creation/dangling-edge-feedback.js +3 -1
  94. package/lib/features/tools/edge-creation/dangling-edge-feedback.js.map +1 -1
  95. package/lib/features/tools/edge-creation/edge-creation-tool-feedback.d.ts +3 -1
  96. package/lib/features/tools/edge-creation/edge-creation-tool-feedback.d.ts.map +1 -1
  97. package/lib/features/tools/edge-creation/edge-creation-tool-feedback.js +4 -7
  98. package/lib/features/tools/edge-creation/edge-creation-tool-feedback.js.map +1 -1
  99. package/lib/features/tools/edge-creation/edge-creation-tool.d.ts +20 -2
  100. package/lib/features/tools/edge-creation/edge-creation-tool.d.ts.map +1 -1
  101. package/lib/features/tools/edge-creation/edge-creation-tool.js +23 -18
  102. package/lib/features/tools/edge-creation/edge-creation-tool.js.map +1 -1
  103. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts +3 -1
  104. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.d.ts.map +1 -1
  105. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js +5 -8
  106. package/lib/features/tools/edge-edit/edge-edit-tool-feedback.js.map +1 -1
  107. package/lib/features/tools/edge-edit/edge-edit-tool.d.ts +4 -4
  108. package/lib/features/tools/edge-edit/edge-edit-tool.d.ts.map +1 -1
  109. package/lib/features/tools/edge-edit/edge-edit-tool.js +27 -44
  110. package/lib/features/tools/edge-edit/edge-edit-tool.js.map +1 -1
  111. package/lib/features/tools/marquee-selection/marquee-mouse-tool.d.ts +3 -2
  112. package/lib/features/tools/marquee-selection/marquee-mouse-tool.d.ts.map +1 -1
  113. package/lib/features/tools/marquee-selection/marquee-mouse-tool.js +4 -2
  114. package/lib/features/tools/marquee-selection/marquee-mouse-tool.js.map +1 -1
  115. package/lib/features/tools/node-creation/node-creation-tool.d.ts +14 -5
  116. package/lib/features/tools/node-creation/node-creation-tool.d.ts.map +1 -1
  117. package/lib/features/tools/node-creation/node-creation-tool.js +58 -24
  118. package/lib/features/tools/node-creation/node-creation-tool.js.map +1 -1
  119. package/lib/features/validation/marker-navigator.d.ts +7 -6
  120. package/lib/features/validation/marker-navigator.d.ts.map +1 -1
  121. package/lib/features/validation/marker-navigator.js.map +1 -1
  122. package/lib/features/validation/validate.d.ts +2 -5
  123. package/lib/features/validation/validate.d.ts.map +1 -1
  124. package/lib/features/validation/validate.js +4 -16
  125. package/lib/features/validation/validate.js.map +1 -1
  126. package/lib/utils/gmodel-util.d.ts +27 -2
  127. package/lib/utils/gmodel-util.d.ts.map +1 -1
  128. package/lib/utils/gmodel-util.js +30 -1
  129. package/lib/utils/gmodel-util.js.map +1 -1
  130. package/lib/utils/layout-utils.d.ts +8 -7
  131. package/lib/utils/layout-utils.d.ts.map +1 -1
  132. package/lib/utils/layout-utils.js +2 -4
  133. package/lib/utils/layout-utils.js.map +1 -1
  134. package/lib/utils/viewpoint-util.d.ts +4 -4
  135. package/lib/utils/viewpoint-util.d.ts.map +1 -1
  136. package/lib/utils/viewpoint-util.js.map +1 -1
  137. package/package.json +3 -3
  138. package/src/base/drag-aware-mouse-listener.ts +16 -2
  139. package/src/base/feedback/css-feedback.ts +4 -0
  140. package/src/base/feedback/feeback-emitter.ts +112 -0
  141. package/src/base/feedback/feedback-action-dispatcher.ts +41 -6
  142. package/src/base/feedback/index.ts +1 -0
  143. package/src/base/selection-service.spec.ts +5 -0
  144. package/src/base/selection-service.ts +2 -3
  145. package/src/features/accessibility/element-navigation/local-element-navigator.ts +4 -4
  146. package/src/features/accessibility/move-zoom/move-handler.ts +10 -5
  147. package/src/features/accessibility/resize-key-tool/resize-key-handler.ts +11 -7
  148. package/src/features/change-bounds/model.ts +25 -13
  149. package/src/features/change-bounds/movement-restrictor.ts +5 -4
  150. package/src/features/element-template/mouse-tracking-element-position-listener.ts +44 -44
  151. package/src/features/helper-lines/helper-line-manager-default.ts +12 -21
  152. package/src/features/hints/type-hint-provider.spec.ts +4 -1
  153. package/src/features/hints/type-hint-provider.ts +9 -2
  154. package/src/features/select/select-mouse-listener.ts +4 -3
  155. package/src/features/tools/base-tools.ts +15 -8
  156. package/src/features/tools/change-bounds/change-bounds-tool-feedback.ts +6 -232
  157. package/src/features/tools/change-bounds/change-bounds-tool-module.ts +1 -0
  158. package/src/features/tools/change-bounds/change-bounds-tool-move-feedback.ts +254 -0
  159. package/src/features/tools/change-bounds/change-bounds-tool.ts +217 -226
  160. package/src/features/tools/change-bounds/index.ts +1 -0
  161. package/src/features/tools/change-bounds/view.tsx +4 -1
  162. package/src/features/tools/deletion/delete-tool.ts +6 -6
  163. package/src/features/tools/edge-creation/dangling-edge-feedback.ts +7 -4
  164. package/src/features/tools/edge-creation/edge-creation-tool-feedback.ts +9 -9
  165. package/src/features/tools/edge-creation/edge-creation-tool.ts +33 -23
  166. package/src/features/tools/edge-edit/edge-edit-tool-feedback.ts +8 -8
  167. package/src/features/tools/edge-edit/edge-edit-tool.ts +42 -49
  168. package/src/features/tools/marquee-selection/marquee-mouse-tool.ts +7 -6
  169. package/src/features/tools/node-creation/node-creation-tool.ts +69 -25
  170. package/src/features/validation/marker-navigator.ts +6 -8
  171. package/src/features/validation/validate.ts +5 -20
  172. package/src/utils/gmodel-util.ts +44 -1
  173. package/src/utils/layout-utils.ts +9 -20
  174. package/src/utils/viewpoint-util.ts +3 -4
@@ -18,20 +18,25 @@ import {
18
18
  CreateNodeOperation,
19
19
  GModelElement,
20
20
  GNode,
21
+ GhostElement,
21
22
  Point,
22
23
  TYPES,
23
24
  TriggerNodeCreationAction,
24
25
  findParentByFeature,
25
- isCtrlOrCmd
26
+ isCtrlOrCmd,
27
+ isMoveable
26
28
  } from '@eclipse-glsp/sprotty';
27
29
  import { inject, injectable, optional } from 'inversify';
28
30
  import '../../../../css/ghost-element.css';
31
+ import { FeedbackEmitter } from '../../../base';
29
32
  import { DragAwareMouseListener } from '../../../base/drag-aware-mouse-listener';
30
33
  import { CSS_GHOST_ELEMENT, CSS_HIDDEN, CursorCSS, cursorFeedbackAction } from '../../../base/feedback/css-feedback';
31
34
  import { EnableDefaultToolsAction } from '../../../base/tool-manager/tool';
35
+ import { MoveableElement, isValidMove } from '../../../utils';
32
36
  import { getAbsolutePosition } from '../../../utils/viewpoint-util';
33
37
  import { IMovementRestrictor } from '../../change-bounds/movement-restrictor';
34
38
  import { PositionSnapper } from '../../change-bounds/position-snapper';
39
+ import { RemoveTemplateElementsAction } from '../../element-template';
35
40
  import { AddTemplateElementsAction, getTemplateElementId } from '../../element-template/add-template-element';
36
41
  import { MouseTrackingElementPositionListener, PositioningTool } from '../../element-template/mouse-tracking-element-position-listener';
37
42
  import { Containable, isContainable } from '../../hints/model';
@@ -53,34 +58,39 @@ export class NodeCreationTool extends BaseCreationTool<TriggerNodeCreationAction
53
58
  doEnable(): void {
54
59
  let trackingListener: MouseTrackingElementPositionListener | undefined;
55
60
  const ghostElement = this.triggerAction.ghostElement;
56
- if (ghostElement) {
57
- trackingListener = new MouseTrackingElementPositionListener(getTemplateElementId(ghostElement.template), this, 'middle');
58
- this.toDisposeOnDisable.push(
59
- this.registerFeedback(
60
- [AddTemplateElementsAction.create({ templates: [ghostElement.template], addClasses: [CSS_HIDDEN, CSS_GHOST_ELEMENT] })],
61
- ghostElement
62
- ),
63
- this.mouseTool.registerListener(trackingListener)
64
- );
61
+ const ghostElementId = ghostElement ? getTemplateElementId(ghostElement.template) : undefined;
62
+ if (ghostElement && ghostElementId) {
63
+ trackingListener = new MouseTrackingElementPositionListener(ghostElementId, this, 'middle');
64
+ this.toDisposeOnDisable.push(trackingListener, this.mouseTool.registerListener(trackingListener));
65
65
  }
66
66
 
67
+ const toolListener = new NodeCreationToolMouseListener(this.triggerAction, this, ghostElement);
67
68
  this.toDisposeOnDisable.push(
68
- this.mouseTool.registerListener(new NodeCreationToolMouseListener(this.triggerAction, this, trackingListener)),
69
- this.registerFeedback([cursorFeedbackAction(CursorCSS.NODE_CREATION)], this, [cursorFeedbackAction()])
69
+ toolListener,
70
+ this.mouseTool.registerListener(toolListener),
71
+ this.createFeedbackEmitter().add(cursorFeedbackAction(CursorCSS.NODE_CREATION), cursorFeedbackAction()).submit()
70
72
  );
71
73
  }
72
74
  }
73
75
 
74
- @injectable()
75
76
  export class NodeCreationToolMouseListener extends DragAwareMouseListener {
76
77
  protected container?: GModelElement & Containable;
78
+ protected cursorFeedback: FeedbackEmitter;
79
+ protected ghostElementFeedback: FeedbackEmitter;
80
+ protected ghostElementId?: string;
77
81
 
78
82
  constructor(
79
83
  protected triggerAction: TriggerNodeCreationAction,
80
84
  protected tool: NodeCreationTool,
81
- protected trackingListener?: MouseTrackingElementPositionListener
85
+ protected ghostElement?: GhostElement
82
86
  ) {
83
87
  super();
88
+ this.cursorFeedback = tool.createFeedbackEmitter();
89
+ this.ghostElementFeedback = tool.createFeedbackEmitter();
90
+ if (ghostElement) {
91
+ this.ghostElementId = getTemplateElementId(ghostElement.template);
92
+ }
93
+ this.createGhostElement();
84
94
  }
85
95
 
86
96
  protected creationAllowed(elementTypeId: string): boolean | undefined {
@@ -98,24 +108,48 @@ export class NodeCreationToolMouseListener extends DragAwareMouseListener {
98
108
  }
99
109
 
100
110
  if (this.creationAllowed(this.elementTypeId)) {
101
- const containerId = this.container ? this.container.id : undefined;
102
- const location = this.getInsertPosition(target, event);
103
- result.push(CreateNodeOperation.create(this.elementTypeId, { location, containerId, args: this.triggerAction.args }));
111
+ const location = this.getValidInsertPosition(target, event);
112
+ if (location) {
113
+ const containerId = this.container?.id;
114
+ result.push(CreateNodeOperation.create(this.elementTypeId, { location, containerId, args: this.triggerAction.args }));
115
+ }
104
116
  if (!isCtrlOrCmd(event)) {
117
+ // we no longer want to show the ghost element AFTER the next update
118
+ this.ghostElementFeedback.discard();
105
119
  result.push(EnableDefaultToolsAction.create());
106
120
  } else {
107
- this.tool.deregisterFeedback(this);
121
+ // we continue in stamp mode so we keep the ghost but dispose everything else
122
+ this.disposeAllButGhostElement();
108
123
  }
109
124
  }
110
125
  return result;
111
126
  }
112
127
 
113
- protected getInsertPosition(target: GModelElement, event: MouseEvent): Point {
114
- if (this.trackingListener) {
115
- const trackedPosition = this.trackingListener.currentPosition;
116
- if (trackedPosition) {
117
- return trackedPosition;
118
- }
128
+ protected createGhostElement(): void {
129
+ if (!this.ghostElement) {
130
+ return;
131
+ }
132
+ const templates = [this.ghostElement.template];
133
+ this.ghostElementFeedback
134
+ .add(
135
+ AddTemplateElementsAction.create({ templates, addClasses: [CSS_HIDDEN, CSS_GHOST_ELEMENT] }),
136
+ RemoveTemplateElementsAction.create({ templates })
137
+ )
138
+ .submit();
139
+ }
140
+
141
+ protected getGhostElement(): MoveableElement | undefined {
142
+ if (!this.ghostElementId) {
143
+ return undefined;
144
+ }
145
+ const ghostElement = this.container?.index.getById(this.ghostElementId);
146
+ return ghostElement && isMoveable(ghostElement) ? ghostElement : undefined;
147
+ }
148
+
149
+ protected getValidInsertPosition(target: GModelElement, event: MouseEvent): Point | undefined {
150
+ const ghostElement = this.getGhostElement();
151
+ if (ghostElement) {
152
+ return isValidMove(ghostElement, ghostElement.position, this.tool.movementRestrictor) ? ghostElement.position : undefined;
119
153
  }
120
154
  const location = getAbsolutePosition(target, event);
121
155
 
@@ -132,8 +166,18 @@ export class NodeCreationToolMouseListener extends DragAwareMouseListener {
132
166
  const feedback = this.creationAllowed(this.elementTypeId)
133
167
  ? cursorFeedbackAction(CursorCSS.NODE_CREATION)
134
168
  : cursorFeedbackAction(CursorCSS.OPERATION_NOT_ALLOWED);
135
- this.tool.registerFeedback([feedback]);
169
+ this.cursorFeedback.add(feedback).submit();
136
170
  }
137
171
  return [];
138
172
  }
173
+
174
+ protected disposeAllButGhostElement(): void {
175
+ this.cursorFeedback.dispose();
176
+ super.dispose();
177
+ }
178
+
179
+ override dispose(): void {
180
+ this.ghostElementFeedback.dispose();
181
+ this.disposeAllButGhostElement();
182
+ }
139
183
  }
@@ -15,7 +15,6 @@
15
15
  ********************************************************************************/
16
16
  import {
17
17
  Action,
18
- BoundsAware,
19
18
  CenterAction,
20
19
  GIssueSeverity,
21
20
  GModelElement,
@@ -26,7 +25,6 @@ import {
26
25
  MenuItem,
27
26
  Point,
28
27
  SelectAction,
29
- Selectable,
30
28
  TYPES,
31
29
  findParentByFeature,
32
30
  hasArrayProp,
@@ -38,7 +36,7 @@ import {
38
36
  import { inject, injectable } from 'inversify';
39
37
  import { GLSPActionDispatcher } from '../../base/action-dispatcher';
40
38
  import { SelectionService } from '../../base/selection-service';
41
- import { getElements, isSelectableAndBoundsAware } from '../../utils/gmodel-util';
39
+ import { BoundsAwareModelElement, SelectableElement, getElements, isSelectableAndBoundsAware } from '../../utils/gmodel-util';
42
40
  import { MarkerPredicates, collectIssueMarkers } from '../../utils/marker';
43
41
  import { GIssueMarker } from './issue-marker';
44
42
 
@@ -110,7 +108,7 @@ export class MarkerNavigator {
110
108
 
111
109
  next(
112
110
  root: Readonly<GModelRoot>,
113
- current?: GModelElement & BoundsAware,
111
+ current?: BoundsAwareModelElement,
114
112
  predicate: (marker: GIssueMarker) => boolean = MarkerPredicates.ALL
115
113
  ): GIssueMarker | undefined {
116
114
  const markers = this.getMarkers(root, predicate);
@@ -122,7 +120,7 @@ export class MarkerNavigator {
122
120
 
123
121
  previous(
124
122
  root: Readonly<GModelRoot>,
125
- current?: GModelElement & BoundsAware,
123
+ current?: BoundsAwareModelElement,
126
124
  predicate: (marker: GIssueMarker) => boolean = MarkerPredicates.ALL
127
125
  ): GIssueMarker | undefined {
128
126
  const markers = this.getMarkers(root, predicate);
@@ -137,7 +135,7 @@ export class MarkerNavigator {
137
135
  return markers.filter(predicate).sort(this.markerComparator.compare);
138
136
  }
139
137
 
140
- protected getNextIndex(current: GModelElement & BoundsAware, markers: GIssueMarker[]): number {
138
+ protected getNextIndex(current: BoundsAwareModelElement, markers: GIssueMarker[]): number {
141
139
  for (let index = 0; index < markers.length; index++) {
142
140
  if (this.markerComparator.compare(markers[index], current) > 0) {
143
141
  return index;
@@ -146,7 +144,7 @@ export class MarkerNavigator {
146
144
  return 0;
147
145
  }
148
146
 
149
- protected getPreviousIndex(current: GModelElement & BoundsAware, markers: GIssueMarker[]): number {
147
+ protected getPreviousIndex(current: BoundsAwareModelElement, markers: GIssueMarker[]): number {
150
148
  for (let index = markers.length - 1; index >= 0; index--) {
151
149
  if (this.markerComparator.compare(markers[index], current) < 0) {
152
150
  return index;
@@ -182,7 +180,7 @@ export class NavigateToMarkerActionHandler implements IActionHandler {
182
180
  }
183
181
  }
184
182
 
185
- protected getSelectedElements(action: NavigateToMarkerAction): (GModelElement & Selectable)[] {
183
+ protected getSelectedElements(action: NavigateToMarkerAction): SelectableElement[] {
186
184
  if (action.selectedElementIds && action.selectedElementIds.length > 0) {
187
185
  return getElements(this.selectionService.getModelRoot().index, action.selectedElementIds, isSelectable);
188
186
  }
@@ -28,6 +28,7 @@ import {
28
28
  hasArrayProp
29
29
  } from '@eclipse-glsp/sprotty';
30
30
  import { inject, injectable, optional } from 'inversify';
31
+ import { FeedbackEmitter } from '../../base';
31
32
  import { EditorContextService } from '../../base/editor-context-service';
32
33
  import { IFeedbackActionDispatcher, IFeedbackEmitter } from '../../base/feedback/feedback-action-dispatcher';
33
34
  import { FeedbackCommand } from '../../base/feedback/feedback-command';
@@ -42,7 +43,7 @@ import { GIssueMarker, createGIssue, getGIssueMarker, getOrCreateGIssueMarker, g
42
43
  export class ValidationFeedbackEmitter implements IFeedbackEmitter {
43
44
  @inject(TYPES.IFeedbackActionDispatcher) protected feedbackActionDispatcher: IFeedbackActionDispatcher;
44
45
 
45
- protected registeredFeedbackByReason: Map<string, { action: ApplyMarkersAction; emitter: IFeedbackEmitter }> = new Map();
46
+ protected registeredFeedbackByReason: Map<string, FeedbackEmitter> = new Map();
46
47
 
47
48
  /**
48
49
  * Register the action that should be emitted for visualizing validation feedback.
@@ -51,25 +52,9 @@ export class ValidationFeedbackEmitter implements IFeedbackEmitter {
51
52
  */
52
53
  registerValidationFeedbackAction(action: ApplyMarkersAction, reason = ''): void {
53
54
  // De-register feedback and clear existing markers with the same reason
54
- const previousFeedbackWithSameReason = this.registeredFeedbackByReason.get(reason);
55
- let emitter: IFeedbackEmitter | undefined;
56
- if (previousFeedbackWithSameReason) {
57
- emitter = previousFeedbackWithSameReason.emitter;
58
- const deleteMarkersAction = DeleteMarkersAction.create(previousFeedbackWithSameReason.action.markers);
59
- this.feedbackActionDispatcher.deregisterFeedback(emitter, [deleteMarkersAction]);
60
- }
61
-
62
- if (!emitter) {
63
- emitter = this.createEmitter(reason);
64
- }
65
-
66
- // Register new action responsible for applying markers and re-applying them when the model is updated
67
- this.registeredFeedbackByReason.set(reason, { action, emitter });
68
- this.feedbackActionDispatcher.registerFeedback(emitter, [action]);
69
- }
70
-
71
- protected createEmitter(reason: string): IFeedbackEmitter {
72
- return { id: 'validationFeedbackEmitter_' + reason };
55
+ const emitter = this.registeredFeedbackByReason.get(reason)?.dispose() ?? this.feedbackActionDispatcher.createEmitter();
56
+ emitter.add(action, () => DeleteMarkersAction.create(action.markers)).submit();
57
+ this.registeredFeedbackByReason.set(reason, emitter);
73
58
  }
74
59
  }
75
60
 
@@ -25,6 +25,7 @@ import {
25
25
  GParentElement,
26
26
  GRoutableElement,
27
27
  GRoutingHandle,
28
+ Locateable,
28
29
  ModelIndexImpl,
29
30
  Point,
30
31
  RoutedPoint,
@@ -194,17 +195,30 @@ export function isRoutingHandle(element: GModelElement | undefined): element is
194
195
  export function isSelectableAndBoundsAware(element: GModelElement): element is SelectableBoundsAware {
195
196
  return isSelectable(element) && isBoundsAware(element);
196
197
  }
198
+ /**
199
+ * Union type to describe {@link GModelElement}s that implement the {@link Selectable} feature.
200
+ */
201
+ export type SelectableElement = GModelElement & Selectable;
197
202
 
198
203
  /**
199
204
  * Union type to describe {@link GModelElement}s that implement the {@link Selectable} and {@link BoundsAware} feature.
200
205
  */
201
- export type SelectableBoundsAware = GModelElement & BoundsAware & Selectable;
206
+ export type SelectableBoundsAware = SelectableElement & BoundsAware;
202
207
 
203
208
  /**
204
209
  * Union type to describe {@link GModelElement}s that implement the {@link BoundsAware} feature.
205
210
  */
206
211
  export type BoundsAwareModelElement = GModelElement & BoundsAware;
207
212
 
213
+ /**
214
+ * Union type to describe {@link GModelElement}s that implement the {@link Locateable} feature.
215
+ */
216
+ export type MoveableElement = GModelElement & Locateable;
217
+
218
+ export interface Resizable extends BoundsAware, Selectable {}
219
+
220
+ export interface ResizableModelElement extends GParentElement, Resizable {}
221
+
208
222
  /**
209
223
  * Helper function to translate a given {@link GModelElement} into its corresponding {@link ElementAndBounds} representation.
210
224
  * @param element The element to translate.
@@ -373,3 +387,32 @@ export function getDescendantIds(element?: GModelElement, skip?: (t: GModelEleme
373
387
  }
374
388
  return ids;
375
389
  }
390
+
391
+ /**
392
+ * Returns a filter function that checks if the given element is not a descendant of any of the given elements.
393
+ *
394
+ * @param elements The elements that the element should not be a descendant of.
395
+ * @returns the filter function
396
+ */
397
+ export function isNotDescendantOfAnyElement<T extends GModelElement>(elements: FluentIterable<T>): (element: T) => boolean {
398
+ const elementsSet = new Set<GModelElement>(elements);
399
+ return (element: T): boolean => {
400
+ let parent: GModelElement = element;
401
+ while (parent instanceof GChildElement) {
402
+ parent = parent.parent;
403
+ if (elementsSet.has(parent)) {
404
+ return false;
405
+ }
406
+ }
407
+ return true;
408
+ };
409
+ }
410
+
411
+ /**
412
+ * Removes any descendants of the given elements from the given elements.
413
+ * @param elements The elements to filter.
414
+ * @returns the filtered elements
415
+ */
416
+ export function removeDescendants<T extends GModelElement>(elements: FluentIterable<T>): FluentIterable<T> {
417
+ return elements.filter(isNotDescendantOfAnyElement(elements));
418
+ }
@@ -13,19 +13,11 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import {
17
- BoundsAware,
18
- Dimension,
19
- ElementAndBounds,
20
- ElementMove,
21
- ModelLayoutOptions,
22
- Point,
23
- GModelElement,
24
- Writable
25
- } from '@eclipse-glsp/sprotty';
16
+ import { Dimension, ElementAndBounds, ElementMove, GModelElement, ModelLayoutOptions, Point, Writable } from '@eclipse-glsp/sprotty';
26
17
  import { IMovementRestrictor } from '../features/change-bounds/movement-restrictor';
18
+ import { BoundsAwareModelElement } from './gmodel-util';
27
19
 
28
- export function minWidth(element: GModelElement & BoundsAware): number {
20
+ export function minWidth(element: BoundsAwareModelElement): number {
29
21
  const layoutOptions = getLayoutOptions(element);
30
22
  if (layoutOptions !== undefined && typeof layoutOptions.minWidth === 'number') {
31
23
  return layoutOptions.minWidth;
@@ -33,7 +25,7 @@ export function minWidth(element: GModelElement & BoundsAware): number {
33
25
  return 1;
34
26
  }
35
27
 
36
- export function minHeight(element: GModelElement & BoundsAware): number {
28
+ export function minHeight(element: BoundsAwareModelElement): number {
37
29
  const layoutOptions = getLayoutOptions(element);
38
30
  if (layoutOptions !== undefined && typeof layoutOptions.minHeight === 'number') {
39
31
  return layoutOptions.minHeight;
@@ -49,19 +41,16 @@ export function getLayoutOptions(element: GModelElement): ModelLayoutOptions | u
49
41
  return undefined;
50
42
  }
51
43
 
52
- export function isValidSize(element: GModelElement & BoundsAware, size: Dimension): boolean {
44
+ export function isValidSize(element: BoundsAwareModelElement, size: Dimension): boolean {
53
45
  return size.width >= minWidth(element) && size.height >= minHeight(element);
54
46
  }
55
47
 
56
- export function isValidMove(element: GModelElement & BoundsAware, newPosition?: Point, movementRestrictor?: IMovementRestrictor): boolean {
57
- if (movementRestrictor) {
58
- return movementRestrictor.validate(element, newPosition);
59
- }
60
- return true;
48
+ export function isValidMove(element: GModelElement, newPosition?: Point, movementRestrictor?: IMovementRestrictor): boolean {
49
+ return movementRestrictor?.validate(element, newPosition) ?? true;
61
50
  }
62
51
 
63
52
  export function toValidElementMove(
64
- element: GModelElement & BoundsAware,
53
+ element: BoundsAwareModelElement,
65
54
  move: ElementMove,
66
55
  movementRestrictor?: IMovementRestrictor
67
56
  ): ElementMove | undefined {
@@ -72,7 +61,7 @@ export function toValidElementMove(
72
61
  }
73
62
 
74
63
  export function toValidElementAndBounds(
75
- element: GModelElement & BoundsAware,
64
+ element: BoundsAwareModelElement,
76
65
  bounds: Writable<ElementAndBounds>,
77
66
  movementRestrictor?: IMovementRestrictor
78
67
  ): ElementAndBounds | undefined {
@@ -16,7 +16,6 @@
16
16
 
17
17
  import {
18
18
  Bounds,
19
- BoundsAware,
20
19
  Dimension,
21
20
  GChildElement,
22
21
  GModelElement,
@@ -74,7 +73,7 @@ export function getViewportBounds(target: GModelElement, bounds: Bounds): Bounds
74
73
  *
75
74
  * @param target A bounds-aware element from the diagram
76
75
  */
77
- export function toAbsoluteBounds(element: GModelElement & BoundsAware): Bounds {
76
+ export function toAbsoluteBounds(element: BoundsAwareModelElement): Bounds {
78
77
  const location = isAlignable(element) ? element.alignment : Point.ORIGIN;
79
78
  const x = location.x;
80
79
  const y = location.y;
@@ -89,7 +88,7 @@ export function toAbsoluteBounds(element: GModelElement & BoundsAware): Bounds {
89
88
  *
90
89
  * @param target A bounds-aware element from the diagram
91
90
  */
92
- export function toAbsolutePosition(target: GModelElement & BoundsAware): Point {
91
+ export function toAbsolutePosition(target: BoundsAwareModelElement): Point {
93
92
  return toAbsoluteBounds(target);
94
93
  }
95
94
 
@@ -99,7 +98,7 @@ export function toAbsolutePosition(target: GModelElement & BoundsAware): Point {
99
98
  *
100
99
  * @param target A bounds-aware element from the diagram
101
100
  */
102
- export function toAbsoluteSize(target: GModelElement & BoundsAware): Dimension {
101
+ export function toAbsoluteSize(target: BoundsAwareModelElement): Dimension {
103
102
  return toAbsoluteBounds(target);
104
103
  }
105
104