1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package cz.zcu.mre.sparkle.gui.query;
21
22 import cz.zcu.mre.sparkle.Messages;
23 import cz.zcu.mre.sparkle.data.*;
24 import cz.zcu.mre.sparkle.data.AbstractTermsStorage.StorageChangeListener;
25 import cz.zcu.mre.sparkle.data.resourceStorage.ResourcesStorage;
26 import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
27 import static cz.zcu.mre.sparkle.gui.query.QueryFormPane.QUERY_PARTS.*;
28 import cz.zcu.mre.sparkle.gui.query.autoComplete.AutoCompleteListHandler;
29 import cz.zcu.mre.sparkle.gui.query.autoComplete.ExpressionAutoCompleteListHandler;
30 import cz.zcu.mre.sparkle.gui.query.autoComplete.VariablesAutoCompleteListHandler;
31 import cz.zcu.mre.sparkle.gui.query.helpers.*;
32 import cz.zcu.mre.sparkle.gui.query.modifiers.GroupGraphPatternPane;
33 import cz.zcu.mre.sparkle.gui.query.modifiers.LimitOffsetClausePane;
34 import cz.zcu.mre.sparkle.gui.query.modifiers.OrderByClausePane;
35 import cz.zcu.mre.sparkle.gui.query.modifiers.ValuesClausePane;
36 import cz.zcu.mre.sparkle.gui.query.modifiers.groupBy.GroupByClausePane;
37 import cz.zcu.mre.sparkle.gui.query.modifiers.having.HavingClausePane;
38 import cz.zcu.mre.sparkle.gui.query.queryMainParts.FromClausePane;
39 import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
40 import cz.zcu.mre.sparkle.gui.query.queryTypes.ask.AskQueryFormPane;
41 import cz.zcu.mre.sparkle.gui.query.queryTypes.construct.ConstructQueryFormPane;
42 import cz.zcu.mre.sparkle.gui.query.queryTypes.describe.DescribeQueryFormPane;
43 import cz.zcu.mre.sparkle.gui.query.queryTypes.select.SelectQueryFormPane;
44 import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
45 import cz.zcu.mre.sparkle.gui.tools.Components;
46 import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
47 import cz.zcu.mre.sparkle.tools.*;
48 import java.io.File;
49 import java.io.IOException;
50 import java.io.Serializable;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Set;
54 import java.util.logging.Level;
55 import java.util.logging.Logger;
56 import javafx.beans.InvalidationListener;
57 import javafx.beans.property.BooleanProperty;
58 import javafx.beans.property.SimpleBooleanProperty;
59 import javafx.collections.FXCollections;
60 import javafx.collections.MapChangeListener.Change;
61 import javafx.collections.ObservableList;
62 import javafx.scene.control.ScrollPane;
63 import javafx.scene.layout.VBox;
64 import javafx.scene.paint.Color;
65 import javax.xml.parsers.ParserConfigurationException;
66 import javax.xml.transform.TransformerException;
67 import org.antlr.v4.runtime.ParserRuleContext;
68 import org.antlr.v4.runtime.misc.ParseCancellationException;
69 import org.antlr.v4.runtime.tree.ParseTree;
70 import org.antlr.v4.runtime.tree.ParseTreeWalker;
71 import org.w3c.dom.Element;
72 import org.w3c.dom.NodeList;
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public abstract class QueryFormPane<QueryResultType>
87 extends VBox
88 implements PartialQueryGenerator, PrefixesUser, VariablesGenerator, Changeable, Saveable {
89
90 private final Set<InvalidationListener> observers = new HashSet<>();
91
92 public static final String XML_ELEMENT_NAME = "Sparkle";
93 public static final String XML_QUERY_TYPE = "type";
94 public static final String XML_TAB_COLOR = "tabColor";
95
96 public enum QUERY_PARTS {
97 FIRST_CLAUSE, FROM_CLAUSE, WHERE_CLAUSE, ORDER_BY_CLAUSE, GROUP_BY_CLAUSE, HAVING_CLAUSE,
98 LIMIT_OFFSET_CLAUSE, VALUES_CLAUSE
99
100 }
101
102 private final Storage localStorage;
103 private final String paneType;
104
105 private PrefixesStorage queryPrefixesStorage;
106 private FunctionsStorage queryFunctionsStorage;
107 private DataTypesStorage queryDataTypesStorage;
108 private ResourcesStorage queryResourcesStorage;
109
110 private final ObservableList<String> variables = FXCollections.observableArrayList();
111 private final ObservableList<String> sortedVariables = variables.sorted(String.CASE_INSENSITIVE_ORDER);
112 private final Set<VariablesCollector> variablesCollectors = new HashSet<>();
113
114 private final ReferenceKeeper keeper = new ReferenceKeeper();
115 private final Set<String> addedLocalPrefixes = new HashSet<>();
116
117 private DataAgent dataAgent;
118
119 private MainForm mainForm;
120 private final BooleanProperty deleteProperty = new SimpleBooleanProperty(false);
121 private static Color obtainedColor = null;
122
123 private ScrollPane scrollPane;
124
125
126
127
128 public final AutoCompleteListHandler DEFAULT_EXPRESSION_AUTOCOMPLETE_LIST_HANDLER
129 = new ExpressionAutoCompleteListHandler(this);
130
131
132
133 public final AutoCompleteListHandler DEFAULT_VARIABLES_AUTOCOMPLETE_LIST_HANDLER
134 = new VariablesAutoCompleteListHandler(this);
135
136
137
138
139
140
141
142
143 public QueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
144 String paneType) {
145 this.localStorage = localStorage;
146 this.paneType = paneType;
147
148 init(mainForm, dataAgent, localStorage);
149 try {
150
151 load(null);
152 } catch (final LoadException e) {
153
154 }
155 setupWatches();
156 }
157
158
159
160
161
162
163
164
165
166
167
168 protected QueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
169 final Object root, String paneType)
170 throws LoadException {
171
172 this.localStorage = localStorage;
173 this.paneType = paneType;
174 init(mainForm, dataAgent, localStorage);
175
176 if (root instanceof Element) {
177
178 Element rootNode = (Element) root;
179 loadStorages(rootNode);
180 load(rootNode);
181
182 } else if (root instanceof ParserRuleContext) {
183 ParserRuleContext prContext = (ParserRuleContext) root;
184 loadPrefixes(prContext);
185 load(prContext);
186 }
187 setupWatches();
188 }
189
190
191
192
193
194
195
196
197
198 private void init(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage) {
199
200 Components.load(this);
201 this.mainForm = mainForm;
202 this.dataAgent = dataAgent;
203
204 queryPrefixesStorage = new PrefixesStorage();
205 setupPrefixesStorage(localStorage.getPrefixesStorage());
206
207 queryResourcesStorage = new ResourcesStorage(dataAgent, queryPrefixesStorage);
208 setupTermsStorage(localStorage.getResourcesStorage(), queryResourcesStorage);
209
210 queryDataTypesStorage = new DataTypesStorage(dataAgent, queryPrefixesStorage);
211 setupTermsStorage(localStorage.getDataTypesStorage(), queryDataTypesStorage);
212
213 queryFunctionsStorage = new FunctionsStorage(dataAgent, queryPrefixesStorage);
214 setupTermsStorage(localStorage.getFunctionsStorage(), queryFunctionsStorage);
215
216 addVariablesCollector(new VariablesCollector() {
217 @Override
218 public final void onVariableRemoved(final String variableName) {
219 variables.remove(variableName);
220 }
221
222 @Override
223 public final void onVariableChanged(final String oldVariableName, final String newVariableName) {
224 variables.set(variables.indexOf(oldVariableName), newVariableName);
225 }
226
227 @Override
228 public final void onVariableAdded(final String variableName) {
229 variables.add(variableName);
230 }
231 });
232
233 scrollPane = new ScrollPane(this);
234 scrollPane.setFitToWidth(true);
235 scrollPane.setPannable(true);
236
237 }
238
239
240
241
242
243
244
245
246 private <StorageEntryType extends Serializable> void setupTermsStorage(
247 final AbstractTermsStorage<StorageEntryType> localStorage,
248 final AbstractTermsStorage<StorageEntryType> queryStorage) {
249
250 final Set<StorageEntryType> termsToAdd = localStorage.getAllTerms();
251 termsToAdd.removeAll(queryStorage.getAllTerms());
252
253 queryStorage.addFrom(localStorage);
254
255
256 localStorage.addListener(keeper.toWeak(new StorageChangeListener<StorageEntryType>() {
257 private final Set<StorageEntryType> addedLocalTerms = new HashSet<>(termsToAdd);
258
259 @Override
260 public final void changed(final StorageEntryType term, final boolean added) {
261 if (added && addedLocalTerms.add(term)) {
262 queryStorage.addTerm(term);
263 return;
264 }
265 if (!added && addedLocalTerms.remove(term)) {
266 queryStorage.removeTerm(term);
267 }
268 }
269 }));
270 }
271
272
273
274
275
276
277
278 private void setupPrefixesStorage(final PrefixesStorage localPrefixesStorage) {
279 final Set<String> prefixesToAdd = localPrefixesStorage.getPrefixesUsed(false);
280 prefixesToAdd.removeAll(queryPrefixesStorage.getPrefixesUsed(false));
281 addedLocalPrefixes.addAll(prefixesToAdd);
282
283 queryPrefixesStorage.add(localPrefixesStorage);
284
285 localPrefixesStorage
286 .getPrefixToIri()
287 .addListener(keeper.toWeak((final Change<? extends String, ? extends String> change) -> {
288
289 final boolean changed = change.wasRemoved() && change.wasAdded();
290 final boolean canChange = addedLocalPrefixes.contains(change.getKey());
291
292 if (change.wasRemoved() && addedLocalPrefixes.remove(change.getKey())
293 && !getPrefixesUsed(false).contains(change.getKey())) {
294
295 queryPrefixesStorage.removeNsPrefix(change.getKey());
296 }
297 if (!changed || canChange) {
298 if (!canChange && queryPrefixesStorage.getPrefixToIri().containsKey(change.getKey())) {
299 return;
300 }
301 if (change.wasAdded() && addedLocalPrefixes.add(change.getKey())) {
302 String altIri = localPrefixesStorage.getIriToAlternativeIri().get(change.getValueAdded());
303 queryPrefixesStorage.setNsPrefix(change.getKey(), change.getValueAdded(), altIri);
304 }
305 }
306 }));
307
308 queryPrefixesStorage.getPrefixToIri()
309 .addListener(keeper.toWeak((final Change<? extends String, ? extends String> change) -> {
310
311 if (change.wasRemoved()) {
312 addedLocalPrefixes.remove(change.getKey());
313 }
314 }));
315 }
316
317
318
319
320 private void setupWatches() {
321 watch(queryResourcesStorage);
322 watch(queryDataTypesStorage);
323 watch(queryFunctionsStorage);
324 watch(queryPrefixesStorage);
325 watch(dataAgent);
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343 @SafeVarargs
344 protected final VariablesCollector createCollector(final Set<String> relatedVariablesSet,
345 final Set<String>... otherVariablesSets) {
346 return new VariablesCollector() {
347 @Override
348 public void onVariableRemoved(final String variableName) {
349 if (relatedVariablesSet.remove(variableName) && !someSetContains(variableName, otherVariablesSets)) {
350 notifyVariableRemoved(variableName);
351 }
352 }
353
354 @Override
355 public void onVariableChanged(final String oldVariableName, final String newVariableName) {
356 relatedVariablesSet.remove(oldVariableName);
357 final boolean added = relatedVariablesSet.add(newVariableName);
358
359 if (someSetContains(oldVariableName, otherVariablesSets)) {
360 if (added && !someSetContains(newVariableName, otherVariablesSets)) {
361 notifyVariableAdded(newVariableName);
362 }
363 } else if (added && !someSetContains(newVariableName, otherVariablesSets)) {
364 notifyVariableChanged(oldVariableName, newVariableName);
365 } else {
366 notifyVariableRemoved(oldVariableName);
367 }
368 }
369
370 @Override
371 public void onVariableAdded(final String variableName) {
372 if (relatedVariablesSet.add(variableName) && !someSetContains(variableName, otherVariablesSets)) {
373 notifyVariableAdded(variableName);
374 }
375 }
376 };
377 }
378
379
380
381
382
383
384
385
386
387 @SafeVarargs
388 private static <E> boolean someSetContains(final E item, final Set<E>... sets) {
389 for (final Set<E> set : sets) {
390 if (set.contains(item)) {
391 return true;
392 }
393 }
394 return false;
395 }
396
397 @Override
398 public final Set<String> getVariables() {
399 final Set<String> vars = new HashSet<>();
400 getChildren().stream().filter((node) -> (node instanceof SimpleVariablesGenerator)).forEach((node) -> vars.addAll(((SimpleVariablesGenerator) node).getVariables()));
401
402 return vars;
403 }
404
405 @Override
406 public final void addVariablesCollector(final VariablesCollector collector) {
407 variablesCollectors.add(collector);
408 }
409
410 @Override
411 public final void removeVariablesCollector(final VariablesCollector collector) {
412 variablesCollectors.remove(collector);
413 }
414
415 @Override
416 public final void notifyVariableAdded(final String variableName) {
417 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(variableName));
418 }
419
420 @Override
421 public final void notifyVariableRemoved(final String variableName) {
422 variablesCollectors.stream().forEach((collector) -> collector.onVariableRemoved(variableName));
423 }
424
425 @Override
426 public final void notifyVariableChanged(final String oldVariableName, final String newVariableName) {
427 variablesCollectors.stream().forEach((collector) -> collector.onVariableChanged(oldVariableName, newVariableName));
428 }
429
430
431
432
433
434
435
436
437
438 public final String generateNewVariableName(String prefix, String suffix) {
439 String varName;
440 if ((prefix == null) || prefix.trim().isEmpty()) {
441 prefix = Messages.getString("AUTO_VARIABLE_PREFIX");
442 }
443 if ((suffix == null) || suffix.trim().isEmpty()) {
444 suffix = "";
445 }
446
447 int num = 0;
448 do {
449 num++;
450 varName = prefix + num + suffix;
451 } while (variables.contains(varName));
452
453 return varName;
454 }
455
456
457
458
459 public final String getQuery() {
460 final StringBuilder queryBuilder = new StringBuilder();
461
462 getPrefixesUsed(false).stream().forEach((prefix) -> {
463 final String iri = queryPrefixesStorage.getPrefixToIri().get(prefix);
464 appendPrologue(queryBuilder, prefix, iri);
465 });
466
467 queryBuilder.append(getQueryPart());
468 return queryBuilder.toString();
469 }
470
471
472
473
474
475
476
477
478 public static void appendPrologue(StringBuilder queryBuilder, String prefix, String iri) {
479 if (iri != null) {
480 queryBuilder.append("PREFIX ");
481 queryBuilder.append(prefix);
482 queryBuilder.append(Definitions.PREFIXED_NAME_PREFIX_DELIMITER);
483 queryBuilder.append(' ');
484 queryBuilder.append(Definitions.IRI_PREFIX);
485 queryBuilder.append(iri);
486 queryBuilder.append(Definitions.IRI_SUFFIX);
487 queryBuilder.append('\n');
488 }
489 }
490
491
492
493
494
495
496
497
498
499 public final void save(final File file) throws ParserConfigurationException, TransformerException {
500 QueryFormPaneSave.save(file, this);
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519 public static QueryFormPane<?> load(
520 final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
521 final File file)
522 throws ParserConfigurationException, TransformerException, Saveable.LoadException,
523 ParseCancellationException, IOException {
524
525 return QueryFormPaneLoad.load(mainForm, dataAgent, localStorage, file);
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 public static QueryFormPane<?> load(
544 final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
545 final String queryString)
546 throws ParserConfigurationException, TransformerException, Saveable.LoadException,
547 ParseCancellationException {
548
549 return QueryFormPaneLoad.load(mainForm, dataAgent, localStorage, queryString);
550 }
551
552
553
554
555
556
557
558
559
560 protected static void loadElement(final Element root, final Saveable element) throws LoadException {
561 final String tagName = element.getXMLElementName();
562
563
564
565
566
567
568
569 final NodeList nodeList = root.getChildNodes();
570 int nodesCount = nodeList.getLength();
571 if (nodesCount > 0) {
572 for (int nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) {
573
574 final org.w3c.dom.Node childNode = nodeList.item(nodeIndex);
575 if (childNode instanceof Element) {
576 Element child = (Element) childNode;
577 if (child.getTagName().equalsIgnoreCase(tagName)) {
578 element.load(child);
579 }
580 }
581 }
582 } else {
583 throw new LoadException(tagName);
584 }
585 }
586
587
588
589
590
591
592
593
594
595 protected void loadQueryPartsElements(Element root, List<Object> queryFormParts) throws LoadException {
596 loadElement(root, (FromClausePane) getPane(queryFormParts, FROM_CLAUSE));
597 loadElement(root, (WhereClausePane) getPane(queryFormParts, WHERE_CLAUSE));
598 loadElement(root, ((OrderByClausePane) getPane(queryFormParts, ORDER_BY_CLAUSE)));
599 loadElement(root, ((GroupByClausePane) getPane(queryFormParts, GROUP_BY_CLAUSE)));
600 loadElement(root, ((HavingClausePane) getPane(queryFormParts, HAVING_CLAUSE)));
601 loadElement(root, ((LimitOffsetClausePane) getPane(queryFormParts, LIMIT_OFFSET_CLAUSE)));
602 loadElement(root, ((ValuesClausePane) getPane(queryFormParts, VALUES_CLAUSE)));
603 }
604
605 void saveStorages(final Element root) {
606 Saveable.defaultSave(root, queryPrefixesStorage, queryFunctionsStorage, queryDataTypesStorage, queryResourcesStorage);
607 }
608
609 private void loadStorages(final Element root) throws LoadException {
610 loadElement(root, queryPrefixesStorage);
611 loadElement(root, queryFunctionsStorage);
612 loadElement(root, queryDataTypesStorage);
613 loadElement(root, queryResourcesStorage);
614 }
615
616 public void loadPrefixes(final ParserRuleContext prContext) {
617 ParseTreeWalker.DEFAULT.walk(new SparqlParserBaseListener() {
618 @Override
619 public void enterPrefixDecl(SparqlParser.PrefixDeclContext ctx) {
620 try {
621 queryPrefixesStorage.load(ctx);
622 } catch (LoadException ex) {
623 Logger.getLogger(QueryFormPane.class.getName()).log(Level.SEVERE, null, ex);
624 }
625 }
626 }, prContext);
627 }
628
629
630
631
632
633
634
635
636
637 protected Object getPane(List<Object> queryFormParts, QUERY_PARTS paneType) {
638 return queryFormParts.get(paneType.ordinal());
639 }
640
641
642
643
644
645
646 public ObservableList<String> getNetVariables() {
647 return this.sortedVariables;
648 }
649
650 public BooleanProperty getDeleteProperty() {
651 return this.deleteProperty;
652 }
653
654 public void setDeleteProperty() {
655 this.deleteProperty.set(true);
656 }
657
658 public MainForm getMainForm() {
659 return this.mainForm;
660 }
661
662 public static void setObtainedColor(String colorText) {
663 try {
664 obtainedColor = Color.web(colorText);
665 } catch (Exception e) {
666 obtainedColor = null;
667 }
668 }
669
670 public Color getObtainedColor() {
671 return obtainedColor;
672 }
673
674 public final DataAgent getDataAgent() {
675 return dataAgent;
676 }
677
678 public final ResourcesStorage getQueryResourcesStorage() {
679 return queryResourcesStorage;
680 }
681
682 public final DataTypesStorage getQueryDataTypesStorage() {
683 return queryDataTypesStorage;
684 }
685
686 public final FunctionsStorage getQueryFunctionsStorage() {
687 return queryFunctionsStorage;
688 }
689
690 public final PrefixesStorage getQueryPrefixesStorage() {
691 return queryPrefixesStorage;
692 }
693
694 public final void setQueryPrefixesStorage(PrefixesStorage queryPrefixesStorage) {
695 this.queryPrefixesStorage = queryPrefixesStorage;
696 }
697
698
699
700
701
702
703 public ObservableList<String> getSortedVariables() {
704 return this.getNetVariables();
705 }
706
707 @Override
708 public String getXMLElementName() {
709 return XML_ELEMENT_NAME;
710 }
711
712 protected abstract String getXMLQueryType();
713
714
715
716
717
718
719 public abstract List<SubSelectPane> getSubSelectPanes();
720
721
722
723
724
725
726
727
728
729 protected abstract void setVariables(ParseTree root) throws LoadException;
730
731 public Storage getLocalStorage() {
732 return localStorage;
733 }
734
735 public ScrollPane getScrollPane() {
736 return scrollPane;
737 }
738
739 @Override
740 public final Set<InvalidationListener> getObservers() {
741 return observers;
742 }
743
744 public String getPaneType() {
745 return paneType;
746 }
747 }