diff options
Diffstat (limited to 'subprojects/frontend/src/graph/GraphStore.ts')
-rw-r--r-- | subprojects/frontend/src/graph/GraphStore.ts | 146 |
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 | ||
7 | import { makeAutoObservable, observable } from 'mobx'; | 7 | import { makeAutoObservable, observable } from 'mobx'; |
8 | 8 | ||
9 | import type { SemanticsSuccessResult } from '../xtext/xtextServiceResults'; | 9 | import type { |
10 | RelationMetadata, | ||
11 | SemanticsSuccessResult, | ||
12 | } from '../xtext/xtextServiceResults'; | ||
10 | 13 | ||
11 | export type Visibility = 'all' | 'must' | 'none'; | 14 | export type Visibility = 'all' | 'must' | 'none'; |
12 | 15 | ||
16 | export 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 | |||
35 | export 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 | |||
13 | export default class GraphStore { | 51 | export 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 | } |