aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/graph/GraphStore.ts
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/graph/GraphStore.ts')
-rw-r--r--subprojects/frontend/src/graph/GraphStore.ts146
1 files changed, 130 insertions, 16 deletions
diff --git a/subprojects/frontend/src/graph/GraphStore.ts b/subprojects/frontend/src/graph/GraphStore.ts
index b59bfb7d..f81b4db4 100644
--- a/subprojects/frontend/src/graph/GraphStore.ts
+++ b/subprojects/frontend/src/graph/GraphStore.ts
@@ -6,10 +6,48 @@
6 6
7import { makeAutoObservable, observable } from 'mobx'; 7import { makeAutoObservable, observable } from 'mobx';
8 8
9import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; 9import type {
10 RelationMetadata,
11 SemanticsSuccessResult,
12} from '../xtext/xtextServiceResults';
10 13
11export type Visibility = 'all' | 'must' | 'none'; 14export type Visibility = 'all' | 'must' | 'none';
12 15
16export function getDefaultVisibility(
17 metadata: RelationMetadata | undefined,
18): Visibility {
19 if (metadata === undefined || metadata.arity <= 0 || metadata.arity > 2) {
20 return 'none';
21 }
22 const { detail } = metadata;
23 switch (detail.type) {
24 case 'class':
25 case 'reference':
26 case 'opposite':
27 return 'all';
28 case 'predicate':
29 return detail.error ? 'must' : 'none';
30 default:
31 return 'none';
32 }
33}
34
35export function isVisibilityAllowed(
36 metadata: RelationMetadata | undefined,
37 visibility: Visibility,
38): boolean {
39 if (metadata === undefined || metadata.arity <= 0 || metadata.arity > 2) {
40 return visibility === 'none';
41 }
42 const { detail } = metadata;
43 if (detail.type === 'predicate' && detail.error) {
44 // We can't display may matches of error predicates,
45 // because they have none by definition.
46 return visibility !== 'all';
47 }
48 return true;
49}
50
13export default class GraphStore { 51export default class GraphStore {
14 semantics: SemanticsSuccessResult = { 52 semantics: SemanticsSuccessResult = {
15 nodes: [], 53 nodes: [],
@@ -17,35 +55,111 @@ export default class GraphStore {
17 partialInterpretation: {}, 55 partialInterpretation: {},
18 }; 56 };
19 57
58 relationMetadata = new Map<string, RelationMetadata>();
59
20 visibility = new Map<string, Visibility>(); 60 visibility = new Map<string, Visibility>();
21 61
62 abbreviate = true;
63
22 constructor() { 64 constructor() {
23 makeAutoObservable(this, { 65 makeAutoObservable(this, {
24 semantics: observable.ref, 66 semantics: observable.ref,
25 }); 67 });
26 } 68 }
27 69
28 getVisiblity(relation: string): Visibility { 70 getVisibility(relation: string): Visibility {
29 return this.visibility.get(relation) ?? 'none'; 71 const visibilityOverride = this.visibility.get(relation);
72 if (visibilityOverride !== undefined) {
73 return visibilityOverride;
74 }
75 return this.getDefaultVisibility(relation);
76 }
77
78 getDefaultVisibility(relation: string): Visibility {
79 const metadata = this.relationMetadata.get(relation);
80 return getDefaultVisibility(metadata);
81 }
82
83 isVisibilityAllowed(relation: string, visibility: Visibility): boolean {
84 const metadata = this.relationMetadata.get(relation);
85 return isVisibilityAllowed(metadata, visibility);
86 }
87
88 setVisibility(relation: string, visibility: Visibility): void {
89 const metadata = this.relationMetadata.get(relation);
90 if (metadata === undefined || !isVisibilityAllowed(metadata, visibility)) {
91 return;
92 }
93 const defaultVisiblity = getDefaultVisibility(metadata);
94 if (defaultVisiblity === visibility) {
95 this.visibility.delete(relation);
96 } else {
97 this.visibility.set(relation, visibility);
98 }
99 }
100
101 cycleVisibility(relation: string): void {
102 const metadata = this.relationMetadata.get(relation);
103 if (metadata === undefined) {
104 return;
105 }
106 switch (this.getVisibility(relation)) {
107 case 'none':
108 if (isVisibilityAllowed(metadata, 'must')) {
109 this.setVisibility(relation, 'must');
110 }
111 break;
112 case 'must':
113 {
114 const next = isVisibilityAllowed(metadata, 'all') ? 'all' : 'none';
115 this.setVisibility(relation, next);
116 }
117 break;
118 default:
119 this.setVisibility(relation, 'none');
120 break;
121 }
122 }
123
124 hideAll(): void {
125 this.relationMetadata.forEach((metadata, name) => {
126 if (getDefaultVisibility(metadata) === 'none') {
127 this.visibility.delete(name);
128 } else {
129 this.visibility.set(name, 'none');
130 }
131 });
132 }
133
134 resetFilter(): void {
135 this.visibility.clear();
136 }
137
138 getName({ name, simpleName }: { name: string; simpleName: string }): string {
139 return this.abbreviate ? simpleName : name;
140 }
141
142 toggleAbbrevaite(): void {
143 this.abbreviate = !this.abbreviate;
30 } 144 }
31 145
32 setSemantics(semantics: SemanticsSuccessResult) { 146 setSemantics(semantics: SemanticsSuccessResult) {
33 this.semantics = semantics; 147 this.semantics = semantics;
34 this.visibility.clear(); 148 this.relationMetadata.clear();
35 const names = new Set<string>(); 149 this.semantics.relations.forEach((metadata) => {
36 this.semantics.relations.forEach(({ name, detail }) => { 150 this.relationMetadata.set(metadata.name, metadata);
37 names.add(name);
38 if (!this.visibility.has(name)) {
39 const newVisibility = detail.type === 'builtin' ? 'none' : 'all';
40 this.visibility.set(name, newVisibility);
41 }
42 }); 151 });
43 const oldNames = new Set<string>(); 152 const toRemove = new Set<string>();
44 this.visibility.forEach((_, key) => oldNames.add(key)); 153 this.visibility.forEach((value, key) => {
45 oldNames.forEach((key) => { 154 if (
46 if (!names.has(key)) { 155 !this.isVisibilityAllowed(key, value) ||
47 this.visibility.delete(key); 156 this.getDefaultVisibility(key) === value
157 ) {
158 toRemove.add(key);
48 } 159 }
49 }); 160 });
161 toRemove.forEach((key) => {
162 this.visibility.delete(key);
163 });
50 } 164 }
51} 165}