@eclipse-glsp/client 0.10.0-next.c94277c.176 → 1.0.0
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.
- package/css/decoration.css +5 -1
- package/css/glsp-sprotty.css +39 -0
- package/css/tool-palette.css +2 -2
- package/lib/base/container-modules.js +8 -8
- package/lib/base/container-modules.js.map +1 -1
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts +5 -7
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.d.ts.map +1 -1
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js +7 -14
- package/lib/features/context-menu/selection-service-aware-context-menu-mouse-listener.js.map +1 -1
- package/lib/features/hover/hover.d.ts +1 -2
- package/lib/features/hover/hover.d.ts.map +1 -1
- package/lib/features/hover/hover.js +2 -15
- package/lib/features/hover/hover.js.map +1 -1
- package/lib/features/mouse-tool/mouse-tool.d.ts +0 -1
- package/lib/features/mouse-tool/mouse-tool.d.ts.map +1 -1
- package/lib/features/mouse-tool/mouse-tool.js +0 -3
- package/lib/features/mouse-tool/mouse-tool.js.map +1 -1
- package/lib/features/select/select-mouse-listener.d.ts +3 -1
- package/lib/features/select/select-mouse-listener.d.ts.map +1 -1
- package/lib/features/select/select-mouse-listener.js +62 -0
- package/lib/features/select/select-mouse-listener.js.map +1 -1
- package/lib/features/source-model-watcher/di.config.d.ts +4 -0
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.d.ts.map +1 -1
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js +4 -4
- package/lib/features/{model-source-watcher → source-model-watcher}/di.config.js.map +1 -1
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts → source-model-watcher/source-model-changed-action-handler.d.ts} +9 -9
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.d.ts.map → source-model-watcher/source-model-changed-action-handler.d.ts.map} +1 -1
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.js → source-model-watcher/source-model-changed-action-handler.js} +19 -19
- package/lib/features/{model-source-watcher/model-source-changed-action-handler.js.map → source-model-watcher/source-model-changed-action-handler.js.map} +1 -1
- package/lib/features/validation/issue-marker.d.ts +11 -5
- package/lib/features/validation/issue-marker.d.ts.map +1 -1
- package/lib/features/validation/issue-marker.js +25 -5
- package/lib/features/validation/issue-marker.js.map +1 -1
- package/lib/features/validation/validate.d.ts.map +1 -1
- package/lib/features/validation/validate.js +6 -3
- package/lib/features/validation/validate.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +11 -11
- package/lib/index.js.map +1 -1
- package/lib/views/glsp-projection-view.d.ts +30 -0
- package/lib/views/glsp-projection-view.d.ts.map +1 -0
- package/lib/views/glsp-projection-view.js +142 -0
- package/lib/views/glsp-projection-view.js.map +1 -0
- package/lib/views/index.d.ts +1 -0
- package/lib/views/index.d.ts.map +1 -1
- package/lib/views/index.js +1 -0
- package/lib/views/index.js.map +1 -1
- package/package.json +4 -4
- package/src/base/container-modules.ts +2 -2
- package/src/features/context-menu/selection-service-aware-context-menu-mouse-listener.ts +19 -25
- package/src/features/hover/hover.ts +2 -24
- package/src/features/mouse-tool/mouse-tool.ts +0 -4
- package/src/features/select/select-mouse-listener.ts +81 -1
- package/src/features/{model-source-watcher → source-model-watcher}/di.config.ts +5 -5
- package/src/features/{model-source-watcher/model-source-changed-action-handler.ts → source-model-watcher/source-model-changed-action-handler.ts} +12 -12
- package/src/features/validation/issue-marker.ts +34 -12
- package/src/features/validation/validate.ts +6 -4
- package/src/index.ts +3 -3
- package/src/views/glsp-projection-view.tsx +166 -0
- package/src/views/index.ts +2 -0
- package/lib/features/model-source-watcher/di.config.d.ts +0 -4
|
@@ -15,53 +15,47 @@
|
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import { Action } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, optional } from 'inversify';
|
|
18
|
-
import {
|
|
19
|
-
ContextMenuProviderRegistry,
|
|
20
|
-
findParentByFeature,
|
|
21
|
-
IContextMenuServiceProvider,
|
|
22
|
-
isSelectable,
|
|
23
|
-
MouseListener,
|
|
24
|
-
SModelElement
|
|
25
|
-
} from 'sprotty';
|
|
18
|
+
import { ContextMenuProviderRegistry, IContextMenuServiceProvider, MouseListener, SModelElement } from 'sprotty';
|
|
26
19
|
import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
|
|
27
20
|
import { TYPES } from '../../base/types';
|
|
28
21
|
import { SelectionService } from '../select/selection-service';
|
|
29
22
|
|
|
30
23
|
@injectable()
|
|
31
24
|
export class SelectionServiceAwareContextMenuMouseListener extends MouseListener {
|
|
32
|
-
@inject(TYPES.IContextMenuServiceProvider)
|
|
33
|
-
@
|
|
34
|
-
|
|
25
|
+
@inject(TYPES.IContextMenuServiceProvider)
|
|
26
|
+
@optional()
|
|
27
|
+
protected readonly contextMenuService?: IContextMenuServiceProvider;
|
|
28
|
+
|
|
29
|
+
@inject(TYPES.IContextMenuProviderRegistry)
|
|
30
|
+
@optional()
|
|
31
|
+
protected readonly menuProvider?: ContextMenuProviderRegistry;
|
|
32
|
+
|
|
33
|
+
@inject(TYPES.SelectionService)
|
|
34
|
+
protected selectionService: SelectionService;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Opens the context menu
|
|
37
|
+
* Opens the context menu.
|
|
38
38
|
*/
|
|
39
|
-
override
|
|
40
|
-
|
|
41
|
-
return this.openContextMenu(event, target);
|
|
42
|
-
}
|
|
43
|
-
return [];
|
|
39
|
+
override contextMenu(target: SModelElement, event: MouseEvent): (Action | Promise<Action>)[] {
|
|
40
|
+
return this.openContextMenu(target, event);
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
/**
|
|
47
44
|
* Opens the context menu.
|
|
48
45
|
*
|
|
49
|
-
* - query the element on the click-target
|
|
50
|
-
* - select the element
|
|
51
46
|
* - query the context menu service and the context menu elements
|
|
52
47
|
* - show the context menu
|
|
53
48
|
* - send a focus state change to indicate that the diagram becomes inactive, once the context menu is shown
|
|
54
49
|
*
|
|
55
50
|
* When the context menu is closed, we focus the diagram element again.
|
|
56
51
|
*/
|
|
57
|
-
protected openContextMenu(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (selectableTarget) {
|
|
61
|
-
selectableTarget.selected = true;
|
|
62
|
-
this.selectionService.updateSelection(target.root, [selectableTarget.id], []);
|
|
52
|
+
protected openContextMenu(target: SModelElement, event: MouseEvent): Promise<Action>[] {
|
|
53
|
+
if (!this.contextMenuService || !this.menuProvider) {
|
|
54
|
+
return [];
|
|
63
55
|
}
|
|
64
56
|
|
|
57
|
+
const mousePosition = { x: event.x, y: event.y };
|
|
58
|
+
|
|
65
59
|
const result = Promise.all([this.contextMenuService(), this.menuProvider.getItems(target.root, mousePosition)])
|
|
66
60
|
.then(([menuService, menuItems]) => menuService.show(menuItems, mousePosition, () => this.focusEventTarget(event)))
|
|
67
61
|
.then((): Action => FocusStateChangedAction.create(false));
|
|
@@ -23,20 +23,11 @@ import {
|
|
|
23
23
|
SModelRootSchema
|
|
24
24
|
} from '@eclipse-glsp/protocol';
|
|
25
25
|
import { injectable } from 'inversify';
|
|
26
|
-
import {
|
|
27
|
-
EMPTY_ROOT,
|
|
28
|
-
HoverFeedbackAction,
|
|
29
|
-
HoverMouseListener,
|
|
30
|
-
IActionHandler,
|
|
31
|
-
ICommand,
|
|
32
|
-
SIssueMarker,
|
|
33
|
-
SIssueSeverity,
|
|
34
|
-
SModelElement
|
|
35
|
-
} from 'sprotty';
|
|
26
|
+
import { EMPTY_ROOT, HoverFeedbackAction, HoverMouseListener, IActionHandler, ICommand, SModelElement } from 'sprotty';
|
|
36
27
|
import { FocusStateChangedAction } from '../../base/actions/focus-change-action';
|
|
37
28
|
import { EnableDefaultToolsAction, EnableToolsAction } from '../../base/tool-manager/tool-actions';
|
|
38
29
|
import { EdgeCreationTool } from '../tools/edge-creation-tool';
|
|
39
|
-
import { GIssueMarker } from '../validation/issue-marker';
|
|
30
|
+
import { getSeverity, GIssueMarker } from '../validation/issue-marker';
|
|
40
31
|
@injectable()
|
|
41
32
|
export class GlspHoverMouseListener extends HoverMouseListener implements IActionHandler {
|
|
42
33
|
protected enableHover = true;
|
|
@@ -117,16 +108,3 @@ export class GlspHoverMouseListener extends HoverMouseListener implements IActio
|
|
|
117
108
|
return bounds;
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
|
-
|
|
121
|
-
export function getSeverity(marker: SIssueMarker): SIssueSeverity {
|
|
122
|
-
let currentSeverity: SIssueSeverity = 'info';
|
|
123
|
-
for (const severity of marker.issues.map(s => s.severity)) {
|
|
124
|
-
if (severity === 'error') {
|
|
125
|
-
return severity;
|
|
126
|
-
}
|
|
127
|
-
if (severity === 'warning' && currentSeverity === 'info') {
|
|
128
|
-
currentSeverity = severity;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return currentSeverity;
|
|
132
|
-
}
|
|
@@ -49,10 +49,6 @@ export class RankingMouseTool extends MouseTool implements IMouseTool {
|
|
|
49
49
|
this.rankedMouseListeners = groupBy(this.mouseListeners, listener => getRank(listener));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
contextMenu(model: SModelRoot, event: MouseEvent): void {
|
|
53
|
-
event.preventDefault();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
52
|
protected override handleEvent<K extends MouseListenerMethods>(methodName: K, model: SModelRoot, event: MouseEvent): void {
|
|
57
53
|
this.focusOnMouseEvent(methodName, model);
|
|
58
54
|
const element = this.getTargetElement(model, event);
|
|
@@ -13,7 +13,21 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import {
|
|
16
|
+
import { Action, SelectAction } from '@eclipse-glsp/protocol';
|
|
17
|
+
import {
|
|
18
|
+
BringToFrontAction,
|
|
19
|
+
findParentByFeature,
|
|
20
|
+
isCtrlOrCmd,
|
|
21
|
+
isSelectable,
|
|
22
|
+
SButton,
|
|
23
|
+
SelectMouseListener,
|
|
24
|
+
SModelElement,
|
|
25
|
+
SModelRoot,
|
|
26
|
+
SRoutableElement,
|
|
27
|
+
SRoutingHandle,
|
|
28
|
+
SwitchEditModeAction
|
|
29
|
+
} from 'sprotty';
|
|
30
|
+
import { toArray } from 'sprotty/lib/utils/iterable';
|
|
17
31
|
import { DEFAULT_RANK, Ranked } from '../rank/model';
|
|
18
32
|
|
|
19
33
|
/**
|
|
@@ -22,4 +36,70 @@ import { DEFAULT_RANK, Ranked } from '../rank/model';
|
|
|
22
36
|
*/
|
|
23
37
|
export class RankedSelectMouseListener extends SelectMouseListener implements Ranked {
|
|
24
38
|
rank: number = DEFAULT_RANK - 1; /* we want to be executed before all default mouse listeners */
|
|
39
|
+
|
|
40
|
+
override mouseDown(target: SModelElement, event: MouseEvent): Action[] {
|
|
41
|
+
const result: Action[] = [];
|
|
42
|
+
if (this.buttonHandlerRegistry !== undefined && target instanceof SButton && target.enabled) {
|
|
43
|
+
const buttonHandler = this.buttonHandlerRegistry.get(target.type);
|
|
44
|
+
if (buttonHandler !== undefined) {
|
|
45
|
+
return buttonHandler.buttonPressed(target);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const selectableTarget = findParentByFeature(target, isSelectable);
|
|
49
|
+
if (selectableTarget !== undefined || target instanceof SModelRoot) {
|
|
50
|
+
this.hasDragged = false;
|
|
51
|
+
let deselect: SModelElement[] = [];
|
|
52
|
+
// multi-selection?
|
|
53
|
+
if (!isCtrlOrCmd(event)) {
|
|
54
|
+
deselect = toArray(
|
|
55
|
+
target.root.index
|
|
56
|
+
.all()
|
|
57
|
+
.filter(
|
|
58
|
+
element =>
|
|
59
|
+
isSelectable(element) &&
|
|
60
|
+
element.selected &&
|
|
61
|
+
!(selectableTarget instanceof SRoutingHandle && element === (selectableTarget.parent as SModelElement))
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (selectableTarget !== undefined) {
|
|
66
|
+
if (!selectableTarget.selected) {
|
|
67
|
+
this.wasSelected = false;
|
|
68
|
+
result.push(
|
|
69
|
+
SelectAction.create({
|
|
70
|
+
selectedElementsIDs: [selectableTarget.id],
|
|
71
|
+
deselectedElementsIDs: deselect.map(e => e.id)
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
result.push(BringToFrontAction.create([selectableTarget.id]));
|
|
75
|
+
const routableDeselect = deselect.filter(e => e instanceof SRoutableElement).map(e => e.id);
|
|
76
|
+
if (selectableTarget instanceof SRoutableElement) {
|
|
77
|
+
result.push(
|
|
78
|
+
SwitchEditModeAction.create({
|
|
79
|
+
elementsToActivate: [selectableTarget.id],
|
|
80
|
+
elementsToDeactivate: routableDeselect
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
} else if (routableDeselect.length > 0) {
|
|
84
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: routableDeselect }));
|
|
85
|
+
}
|
|
86
|
+
} else if (isCtrlOrCmd(event)) {
|
|
87
|
+
this.wasSelected = false;
|
|
88
|
+
result.push(SelectAction.create({ deselectedElementsIDs: [selectableTarget.id] }));
|
|
89
|
+
if (selectableTarget instanceof SRoutableElement) {
|
|
90
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: [selectableTarget.id] }));
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
this.wasSelected = true;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
result.push(SelectAction.create({ deselectedElementsIDs: deselect.map(e => e.id) }));
|
|
97
|
+
const routableDeselect = deselect.filter(e => e instanceof SRoutableElement).map(e => e.id);
|
|
98
|
+
if (routableDeselect.length > 0) {
|
|
99
|
+
result.push(SwitchEditModeAction.create({ elementsToDeactivate: routableDeselect }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
25
105
|
}
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import {
|
|
16
|
+
import { SourceModelChangedAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { ContainerModule } from 'inversify';
|
|
18
18
|
import { configureActionHandler } from 'sprotty';
|
|
19
|
-
import {
|
|
19
|
+
import { SourceModelChangedActionHandler } from './source-model-changed-action-handler';
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
configureActionHandler({ bind, isBound },
|
|
21
|
+
const sourceModelWatcherModule = new ContainerModule((bind, _unbind, isBound) => {
|
|
22
|
+
configureActionHandler({ bind, isBound }, SourceModelChangedAction.KIND, SourceModelChangedActionHandler);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
export default
|
|
25
|
+
export default sourceModelWatcherModule;
|
|
@@ -13,43 +13,43 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Action,
|
|
16
|
+
import { Action, ServerMessageAction, ServerStatusAction, SourceModelChangedAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, optional } from 'inversify';
|
|
18
18
|
import { IActionDispatcher, IActionHandler, ViewerOptions } from 'sprotty';
|
|
19
19
|
import { TYPES } from '../../base/types';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* An external handler of the model
|
|
22
|
+
* An external handler of the source model change event.
|
|
23
23
|
*
|
|
24
24
|
* This allows external applications to react specifically to this event, e.g. by bringing up the diagram,
|
|
25
25
|
* check their dirty state, show a dialog, etc.
|
|
26
26
|
*/
|
|
27
27
|
@injectable()
|
|
28
|
-
export abstract class
|
|
28
|
+
export abstract class ExternalSourceModelChangedHandler {
|
|
29
29
|
/**
|
|
30
|
-
* Notifies about a change of the model
|
|
30
|
+
* Notifies about a change of the source model.
|
|
31
31
|
* @returns actions to be dispatched after the notification.
|
|
32
32
|
*/
|
|
33
|
-
abstract
|
|
33
|
+
abstract notifySourceModelChange(sourceModelName: string, options: ViewerOptions): Promise<Action[]>;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
@injectable()
|
|
37
|
-
export class
|
|
37
|
+
export class SourceModelChangedActionHandler implements IActionHandler {
|
|
38
38
|
@inject(TYPES.IActionDispatcher)
|
|
39
39
|
protected dispatcher: IActionDispatcher;
|
|
40
40
|
|
|
41
41
|
@inject(TYPES.ViewerOptions)
|
|
42
42
|
protected options: ViewerOptions;
|
|
43
43
|
|
|
44
|
-
@inject(
|
|
44
|
+
@inject(ExternalSourceModelChangedHandler)
|
|
45
45
|
@optional()
|
|
46
|
-
protected externalModelSourceChangedHandler?:
|
|
46
|
+
protected externalModelSourceChangedHandler?: ExternalSourceModelChangedHandler;
|
|
47
47
|
|
|
48
48
|
handle(action: Action): void {
|
|
49
|
-
if (
|
|
49
|
+
if (SourceModelChangedAction.is(action)) {
|
|
50
50
|
if (this.externalModelSourceChangedHandler) {
|
|
51
51
|
this.externalModelSourceChangedHandler
|
|
52
|
-
.
|
|
52
|
+
.notifySourceModelChange(action.sourceModelName, this.options)
|
|
53
53
|
.then(actions => this.dispatcher.dispatchAll(actions));
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
@@ -57,8 +57,8 @@ export class ModelSourceChangedActionHandler implements IActionHandler {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
protected showSimpleNotification(action:
|
|
61
|
-
const message = `The model
|
|
60
|
+
protected showSimpleNotification(action: SourceModelChangedAction): void {
|
|
61
|
+
const message = `The source model ${action.sourceModelName} has changed. You might want to consider reloading.`;
|
|
62
62
|
const timeout = 0;
|
|
63
63
|
const severity = 'WARNING';
|
|
64
64
|
this.dispatcher.dispatchAll([
|
|
@@ -13,14 +13,23 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { Marker, MarkerKind } from '@eclipse-glsp/protocol';
|
|
17
|
-
import { SDecoration, SIssue, SIssueMarker, SParentElement } from 'sprotty';
|
|
16
|
+
import { Bounds, Marker, MarkerKind } from '@eclipse-glsp/protocol';
|
|
17
|
+
import { isBoundsAware, Projectable, SDecoration, SIssue, SIssueMarker, SIssueSeverity, SParentElement } from 'sprotty';
|
|
18
18
|
|
|
19
|
-
export class GIssueMarker extends SIssueMarker {
|
|
19
|
+
export class GIssueMarker extends SIssueMarker implements Projectable {
|
|
20
20
|
constructor() {
|
|
21
21
|
super();
|
|
22
22
|
this.features = new Set<symbol>(SDecoration.DEFAULT_FEATURES);
|
|
23
23
|
}
|
|
24
|
+
projectionCssClasses: string[];
|
|
25
|
+
projectedBounds?: Bounds;
|
|
26
|
+
override issues: SIssue[] = [];
|
|
27
|
+
override type = 'marker';
|
|
28
|
+
|
|
29
|
+
computeProjectionCssClasses(): void {
|
|
30
|
+
const severityCss = getSeverity(this);
|
|
31
|
+
this.projectionCssClasses = ['sprotty-issue', 'sprotty-' + severityCss];
|
|
32
|
+
}
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
/**
|
|
@@ -31,14 +40,15 @@ export class GIssueMarker extends SIssueMarker {
|
|
|
31
40
|
* @returns the child `SIssueMarker` or a new `SIssueMarker` if no such child exists.
|
|
32
41
|
*/
|
|
33
42
|
export function getOrCreateSIssueMarker(modelElement: SParentElement): SIssueMarker {
|
|
34
|
-
let issueMarker:
|
|
43
|
+
let issueMarker: GIssueMarker | undefined;
|
|
35
44
|
|
|
36
45
|
issueMarker = getSIssueMarker(modelElement);
|
|
37
46
|
|
|
38
47
|
if (issueMarker === undefined) {
|
|
39
48
|
issueMarker = new GIssueMarker();
|
|
40
|
-
|
|
41
|
-
|
|
49
|
+
if (isBoundsAware(modelElement)) {
|
|
50
|
+
issueMarker.projectedBounds = modelElement.parentToLocal(modelElement.bounds);
|
|
51
|
+
}
|
|
42
52
|
modelElement.add(issueMarker);
|
|
43
53
|
}
|
|
44
54
|
|
|
@@ -51,11 +61,11 @@ export function getOrCreateSIssueMarker(modelElement: SParentElement): SIssueMar
|
|
|
51
61
|
* @param modelElement for which the `SIssueMarker` should be retrieved.
|
|
52
62
|
* @returns the child `SIssueMarker` or `undefined` if no such child exists.
|
|
53
63
|
*/
|
|
54
|
-
export function getSIssueMarker(modelElement: SParentElement):
|
|
55
|
-
let issueMarker:
|
|
64
|
+
export function getSIssueMarker(modelElement: SParentElement): GIssueMarker | undefined {
|
|
65
|
+
let issueMarker: GIssueMarker | undefined;
|
|
56
66
|
|
|
57
67
|
for (const child of modelElement.children) {
|
|
58
|
-
if (child instanceof
|
|
68
|
+
if (child instanceof GIssueMarker) {
|
|
59
69
|
issueMarker = child;
|
|
60
70
|
}
|
|
61
71
|
}
|
|
@@ -69,8 +79,8 @@ export function getSIssueMarker(modelElement: SParentElement): SIssueMarker | un
|
|
|
69
79
|
* @param marker `Marker` for that an `SIssue` should be created.
|
|
70
80
|
* @returns the created `SIssue`.
|
|
71
81
|
*/
|
|
72
|
-
export function createSIssue(marker: Marker): SIssue {
|
|
73
|
-
const issue
|
|
82
|
+
export function createSIssue(marker: Marker, parent?: SParentElement): SIssue {
|
|
83
|
+
const issue = new SIssue();
|
|
74
84
|
issue.message = marker.description;
|
|
75
85
|
|
|
76
86
|
switch (marker.kind) {
|
|
@@ -87,6 +97,18 @@ export function createSIssue(marker: Marker): SIssue {
|
|
|
87
97
|
break;
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
|
-
|
|
91
100
|
return issue;
|
|
92
101
|
}
|
|
102
|
+
|
|
103
|
+
export function getSeverity(marker: SIssueMarker): SIssueSeverity {
|
|
104
|
+
let currentSeverity: SIssueSeverity = 'info';
|
|
105
|
+
for (const severity of marker.issues.map(s => s.severity)) {
|
|
106
|
+
if (severity === 'error') {
|
|
107
|
+
return severity;
|
|
108
|
+
}
|
|
109
|
+
if (severity === 'warning' && currentSeverity === 'info') {
|
|
110
|
+
currentSeverity = severity;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return currentSeverity;
|
|
114
|
+
}
|
|
@@ -19,10 +19,9 @@ import { CommandExecutionContext, CommandReturn, IActionDispatcher, IActionHandl
|
|
|
19
19
|
import { EditorContextService } from '../../base/editor-context-service';
|
|
20
20
|
import { TYPES } from '../../base/types';
|
|
21
21
|
import { removeCssClasses } from '../../utils/smodel-util';
|
|
22
|
-
import { getSeverity } from '../hover/hover';
|
|
23
22
|
import { IFeedbackActionDispatcher, IFeedbackEmitter } from '../tool-feedback/feedback-action-dispatcher';
|
|
24
23
|
import { FeedbackCommand } from '../tool-feedback/model';
|
|
25
|
-
import { createSIssue, getOrCreateSIssueMarker, getSIssueMarker } from './issue-marker';
|
|
24
|
+
import { createSIssue, getOrCreateSIssueMarker, getSeverity, getSIssueMarker, GIssueMarker } from './issue-marker';
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
27
|
* Feedback emitter sending actions for visualizing model validation feedback and
|
|
@@ -151,6 +150,9 @@ export class ApplyMarkersCommand extends FeedbackCommand {
|
|
|
151
150
|
const issueMarker = getOrCreateSIssueMarker(modelElement);
|
|
152
151
|
const issue = createSIssue(marker);
|
|
153
152
|
issueMarker.issues.push(issue);
|
|
153
|
+
if (issueMarker instanceof GIssueMarker) {
|
|
154
|
+
issueMarker.computeProjectionCssClasses();
|
|
155
|
+
}
|
|
154
156
|
addMaxSeverityCSSClassToIssueParent(modelElement, issueMarker);
|
|
155
157
|
}
|
|
156
158
|
});
|
|
@@ -160,7 +162,6 @@ export class ApplyMarkersCommand extends FeedbackCommand {
|
|
|
160
162
|
|
|
161
163
|
function addMaxSeverityCSSClassToIssueParent(modelElement: SParentElement, issueMarker: SIssueMarker): void {
|
|
162
164
|
const maxSeverityCSSClass = getSeverity(issueMarker);
|
|
163
|
-
|
|
164
165
|
if (!modelElement.cssClasses) {
|
|
165
166
|
modelElement.cssClasses = [maxSeverityCSSClass];
|
|
166
167
|
} else {
|
|
@@ -170,7 +171,8 @@ function addMaxSeverityCSSClassToIssueParent(modelElement: SParentElement, issue
|
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
function removeCSSClassFromIssueParent(modelElement: SParentElement, issueMarker: SIssueMarker): void {
|
|
173
|
-
|
|
174
|
+
const severity = getSeverity(issueMarker);
|
|
175
|
+
removeCssClasses(modelElement, [severity]);
|
|
174
176
|
}
|
|
175
177
|
|
|
176
178
|
/**
|
package/src/index.ts
CHANGED
|
@@ -22,11 +22,11 @@ import glspEditLabelModule from './features/edit-label/di.config';
|
|
|
22
22
|
import modelHintsModule from './features/hints/di.config';
|
|
23
23
|
import glspHoverModule from './features/hover/di.config';
|
|
24
24
|
import layoutModule from './features/layout/di.config';
|
|
25
|
-
import modelSourceWatcherModule from './features/model-source-watcher/di.config';
|
|
26
25
|
import glspMouseToolModule from './features/mouse-tool/di.config';
|
|
27
26
|
import { navigationModule } from './features/navigation/di.config';
|
|
28
27
|
import saveModule from './features/save/di.config';
|
|
29
28
|
import glspSelectModule from './features/select/di.config';
|
|
29
|
+
import sourceModelWatcherModule from './features/source-model-watcher/di.config';
|
|
30
30
|
import toolFeedbackModule from './features/tool-feedback/di.config';
|
|
31
31
|
import paletteModule from './features/tool-palette/di.config';
|
|
32
32
|
import { enableDefaultToolsOnFocusLossModule, toolsModule } from './features/tools/di.config';
|
|
@@ -66,7 +66,6 @@ export * from './features/hints/model';
|
|
|
66
66
|
export * from './features/hints/type-hints';
|
|
67
67
|
export * from './features/hover/hover';
|
|
68
68
|
export * from './features/layout/layout-elements-action';
|
|
69
|
-
export * from './features/model-source-watcher/model-source-changed-action-handler';
|
|
70
69
|
export * from './features/mouse-tool/mouse-tool';
|
|
71
70
|
export * from './features/navigation/navigation-action-handler';
|
|
72
71
|
export * from './features/navigation/navigation-target-resolver';
|
|
@@ -74,6 +73,7 @@ export * from './features/rank/model';
|
|
|
74
73
|
export * from './features/reconnect/model';
|
|
75
74
|
export * from './features/save/model';
|
|
76
75
|
export * from './features/save/save-keylistener';
|
|
76
|
+
export * from './features/source-model-watcher/source-model-changed-action-handler';
|
|
77
77
|
export * from './features/tool-feedback/change-bounds-tool-feedback';
|
|
78
78
|
export * from './features/tool-feedback/creation-tool-feedback';
|
|
79
79
|
export * from './features/tool-feedback/css-feedback';
|
|
@@ -121,6 +121,6 @@ export {
|
|
|
121
121
|
navigationModule,
|
|
122
122
|
markerNavigatorModule,
|
|
123
123
|
glspDecorationModule,
|
|
124
|
-
modelSourceWatcherModule,
|
|
124
|
+
sourceModelWatcherModule as modelSourceWatcherModule,
|
|
125
125
|
glspViewportModule
|
|
126
126
|
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2017-2018 TypeFox 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
|
+
/** @jsx html */
|
|
18
|
+
import { Bounds } from '@eclipse-glsp/protocol';
|
|
19
|
+
import { injectable } from 'inversify';
|
|
20
|
+
import { h, VNode, VNodeStyle } from 'snabbdom';
|
|
21
|
+
import {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
html,
|
|
24
|
+
IViewArgs,
|
|
25
|
+
ProjectedViewportView,
|
|
26
|
+
ProjectionParams,
|
|
27
|
+
RenderingContext,
|
|
28
|
+
setClass,
|
|
29
|
+
ViewportRootElement,
|
|
30
|
+
ViewProjection
|
|
31
|
+
} from 'sprotty';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Special viewport root view that renders horizontal and vertical projection bars for quick navigation.
|
|
35
|
+
*/
|
|
36
|
+
@injectable()
|
|
37
|
+
export class GLSPProjectionView extends ProjectedViewportView {
|
|
38
|
+
override render(model: Readonly<ViewportRootElement>, context: RenderingContext, args?: IViewArgs): VNode {
|
|
39
|
+
return (
|
|
40
|
+
<div class-sprotty-graph={true} style={{ width: '100%' }}>
|
|
41
|
+
{this.renderSvg(model, context, args)}
|
|
42
|
+
{this.renderProjections(model, context, args)}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected override renderSvg(model: Readonly<ViewportRootElement>, context: RenderingContext, args?: IViewArgs): VNode {
|
|
48
|
+
const transform = `scale(${model.zoom}) translate(${-model.scroll.x},${-model.scroll.y})`;
|
|
49
|
+
const ns = 'http://www.w3.org/2000/svg';
|
|
50
|
+
const svg = h('svg', { ns, style: { height: '100%' } }, h('g', { ns, attrs: { transform } }, context.renderChildren(model)));
|
|
51
|
+
return svg;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected override renderProjectionBar(
|
|
55
|
+
projections: ViewProjection[],
|
|
56
|
+
model: Readonly<ViewportRootElement>,
|
|
57
|
+
modelBounds: Bounds,
|
|
58
|
+
orientation: 'horizontal' | 'vertical'
|
|
59
|
+
): VNode {
|
|
60
|
+
const params: ProjectionParams = { modelBounds, orientation } as ProjectionParams;
|
|
61
|
+
// NOTE: Here we assume that the projection bars have the same size as the diagram canvas,
|
|
62
|
+
// i.e. they are drawn as overlay above the canvas.
|
|
63
|
+
params.factor =
|
|
64
|
+
orientation === 'horizontal' ? model.canvasBounds.width / modelBounds.width : model.canvasBounds.height / modelBounds.height;
|
|
65
|
+
params.zoomedFactor = params.factor / model.zoom;
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
class-sprotty-projection-bar={true}
|
|
69
|
+
class-horizontal={orientation === 'horizontal'}
|
|
70
|
+
class-vertical={orientation === 'vertical'}
|
|
71
|
+
class-bordered-projection-bar={true}
|
|
72
|
+
>
|
|
73
|
+
{this.renderViewport(model, params)}
|
|
74
|
+
{projections.map(p => this.renderProjection(p, model, params))}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected override renderViewport(model: Readonly<ViewportRootElement>, params: ProjectionParams): VNode {
|
|
80
|
+
let canvasSize;
|
|
81
|
+
let viewportPos: number;
|
|
82
|
+
if (params.orientation === 'horizontal') {
|
|
83
|
+
canvasSize = model.canvasBounds.width;
|
|
84
|
+
viewportPos = (model.scroll.x - params.modelBounds.x) * params.factor;
|
|
85
|
+
} else {
|
|
86
|
+
canvasSize = model.canvasBounds.height;
|
|
87
|
+
viewportPos = (model.scroll.y - params.modelBounds.y) * params.factor;
|
|
88
|
+
}
|
|
89
|
+
let viewportSize = canvasSize * params.zoomedFactor;
|
|
90
|
+
if (viewportPos < 0) {
|
|
91
|
+
viewportSize += viewportPos;
|
|
92
|
+
viewportPos = 0;
|
|
93
|
+
} else if (viewportPos > canvasSize) {
|
|
94
|
+
viewportPos = canvasSize;
|
|
95
|
+
}
|
|
96
|
+
if (viewportSize < 0) {
|
|
97
|
+
viewportSize = 0;
|
|
98
|
+
} else if (viewportPos + viewportSize > canvasSize) {
|
|
99
|
+
viewportSize = canvasSize - viewportPos;
|
|
100
|
+
}
|
|
101
|
+
if (Math.abs(viewportSize - canvasSize) < 1) {
|
|
102
|
+
viewportSize = 0;
|
|
103
|
+
}
|
|
104
|
+
const style: VNodeStyle =
|
|
105
|
+
params.orientation === 'horizontal'
|
|
106
|
+
? {
|
|
107
|
+
left: `${viewportPos}px`,
|
|
108
|
+
width: `${viewportSize}px`,
|
|
109
|
+
border: 'none'
|
|
110
|
+
}
|
|
111
|
+
: {
|
|
112
|
+
top: `${viewportPos}px`,
|
|
113
|
+
height: `${viewportSize}px`,
|
|
114
|
+
border: 'none'
|
|
115
|
+
};
|
|
116
|
+
return <div class-sprotty-viewport={viewportSize !== 0} class-projection-scroll-bar={true} style={style} />;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected override renderProjection(projection: ViewProjection, model: Readonly<ViewportRootElement>, params: ProjectionParams): VNode {
|
|
120
|
+
let canvasSize;
|
|
121
|
+
let projPos;
|
|
122
|
+
let projSize: number;
|
|
123
|
+
if (params.orientation === 'horizontal') {
|
|
124
|
+
canvasSize = model.canvasBounds.width;
|
|
125
|
+
projPos = (projection.projectedBounds.x - params.modelBounds.x) * params.factor;
|
|
126
|
+
projSize = projection.projectedBounds.width * params.factor;
|
|
127
|
+
} else {
|
|
128
|
+
canvasSize = model.canvasBounds.height;
|
|
129
|
+
projPos = (projection.projectedBounds.y - params.modelBounds.y) * params.factor;
|
|
130
|
+
projSize = projection.projectedBounds.height * params.factor;
|
|
131
|
+
}
|
|
132
|
+
if (projPos < 0) {
|
|
133
|
+
projSize += projPos;
|
|
134
|
+
projPos = 0;
|
|
135
|
+
} else if (projPos > canvasSize) {
|
|
136
|
+
projPos = canvasSize;
|
|
137
|
+
}
|
|
138
|
+
if (projSize < 0) {
|
|
139
|
+
projSize = 0;
|
|
140
|
+
} else if (projPos + projSize > canvasSize) {
|
|
141
|
+
projSize = canvasSize - projPos;
|
|
142
|
+
}
|
|
143
|
+
const style: VNodeStyle =
|
|
144
|
+
params.orientation === 'horizontal'
|
|
145
|
+
? {
|
|
146
|
+
left: `${projPos}px`,
|
|
147
|
+
width: `${projSize}px`,
|
|
148
|
+
height: '60%'
|
|
149
|
+
}
|
|
150
|
+
: {
|
|
151
|
+
top: `${projPos}px`,
|
|
152
|
+
height: `${projSize}px`,
|
|
153
|
+
width: '60%'
|
|
154
|
+
};
|
|
155
|
+
const result = (
|
|
156
|
+
<div
|
|
157
|
+
id={`${params.orientation}-projection:${projection.elementId}`}
|
|
158
|
+
class-sprotty-projection={true}
|
|
159
|
+
class-glsp-projection={true}
|
|
160
|
+
style={style}
|
|
161
|
+
/>
|
|
162
|
+
);
|
|
163
|
+
projection.cssClasses.forEach(cl => setClass(result, cl, true));
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
}
|
package/src/views/index.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
export * from './base-view-module';
|
|
17
17
|
export * from './compartments';
|
|
18
18
|
export * from './glsp-edge-view';
|
|
19
|
+
export * from './glsp-projection-view';
|
|
19
20
|
export * from './issue-marker-view';
|
|
20
21
|
export * from './rounded-corner';
|
|
21
22
|
export * from './rounded-corner-view';
|
|
23
|
+
|