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.modifiers;
21
22 import cz.zcu.mre.sparkle.Messages;
23 import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
24 import cz.zcu.mre.sparkle.gui.query.autoComplete.AutoCompleteListHandler;
25 import cz.zcu.mre.sparkle.gui.query.triplePane.TriplePane;
26 import cz.zcu.mre.sparkle.gui.query.autoComplete.PrefixedNamesAutoCompleteListHandler;
27 import cz.zcu.mre.sparkle.gui.query.clause.SingleClausePane;
28 import cz.zcu.mre.sparkle.gui.query.helpers.*;
29 import cz.zcu.mre.sparkle.gui.query.other.TypedTextField;
30 import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
31 import cz.zcu.mre.sparkle.gui.query.queryTypes.construct.ConstructClausePane;
32 import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
33 import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectQueryFormPane;
34 import cz.zcu.mre.sparkle.gui.tools.Components;
35 import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
36 import cz.zcu.mre.sparkle.gui.tools.ShortCutHandler;
37 import cz.zcu.mre.sparkle.gui.tools.ShortCutHandler.Modifier;
38 import cz.zcu.mre.sparkle.tools.*;
39 import cz.zcu.mre.sparkle.tools.SparqlParser;
40 import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils;
41 import javafx.beans.InvalidationListener;
42 import javafx.beans.binding.BooleanExpression;
43 import javafx.beans.property.BooleanProperty;
44 import javafx.beans.property.ObjectProperty;
45 import javafx.beans.property.SimpleBooleanProperty;
46 import javafx.beans.property.SimpleObjectProperty;
47 import javafx.beans.value.ChangeListener;
48 import javafx.collections.FXCollections;
49 import javafx.collections.ListChangeListener.Change;
50 import javafx.collections.ObservableList;
51 import javafx.event.ActionEvent;
52 import javafx.event.EventHandler;
53 import javafx.fxml.FXML;
54 import javafx.scene.Node;
55 import javafx.scene.control.Button;
56 import javafx.scene.control.CheckBox;
57 import javafx.scene.input.Dragboard;
58 import javafx.scene.input.KeyCode;
59 import javafx.scene.input.TransferMode;
60 import javafx.scene.layout.HBox;
61 import javafx.scene.layout.Region;
62 import javafx.scene.layout.VBox;
63 import javafx.scene.shape.Path;
64 import org.antlr.v4.runtime.misc.ParseCancellationException;
65 import org.antlr.v4.runtime.tree.ParseTree;
66 import org.w3c.dom.Element;
67 import org.w3c.dom.NodeList;
68 import javax.xml.parsers.ParserConfigurationException;
69 import javax.xml.transform.TransformerException;
70 import java.util.*;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73 import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.getFieldType;
74 import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.searchNode;
75
76
77
78
79
80
81
82
83
84
85
86
87 public class GroupGraphPatternPane
88 extends VBox
89 implements VariableConstraintsGenerator, PrefixesUser, VariablesGenerator, VariablesCollector, Saveable,
90 Changeable {
91
92 private static final Logger LOG = LoggerFactory.getLogger(GroupGraphPatternPane.class);
93
94 private static final String XML_GROUP_TYPE_FILTER_NOT_EXISTS = "filterNotExists";
95 private static final String XML_GROUP_TYPE_FILTER_EXISTS = "filterExists";
96 private static final String XML_GROUP_TYPE_MINUS = "minus";
97 private static final String XML_GRAPH_TEXT = "graph.text";
98 private static final String XML_GRAPH_TYPE = "graph.type";
99 private static final String XML_GROUP_TYPE_GRAPH = "graph";
100 private static final String XML_GROUP_TYPE_OPTIONAL = "optional";
101 private static final String XML_GROUP_TYPE_UNION = "union";
102 private static final String XML_GROUP_TYPE = "type";
103 private static final String XML_ELEMENT_NAME = "GroupGraph";
104 private static final boolean INVISIBLE_GROUP = false;
105 private static final boolean VISIBLE_GROUP = true;
106
107 @FXML
108 private VBox container;
109 @FXML
110 private CheckBox optionalCheckBox, unionCheckBox, graphCheckBox, minusCheckBox, filterExistsCheckBox,
111 filterNotExistsCheckBox;
112 @FXML
113 private Button removeButton, moveUpButton, moveDownButton, addFilterButton, addBindButton, addGroupButton,
114 addSubSelectButton, addValuesButton;
115 @FXML
116 private Path arrow;
117 @FXML
118 private Region springRegion;
119 @FXML
120 private HBox graphFieldContainer;
121
122 private BooleanExpression arrowVisibilityCondition;
123
124 private final TypedTextField graphField;
125 private final AutoCompleteListHandler nodesAutoCompleteListHandler;
126 private final ObservableList<Node> siblings;
127 private final QueryFormPane<?> parentQueryFormPane;
128 private final BooleanProperty enableFilters = new SimpleBooleanProperty();
129 private final BooleanProperty enableSubSelect = new SimpleBooleanProperty();
130 private final BooleanProperty enableGroups = new SimpleBooleanProperty();
131 private final BooleanProperty enableOnlyGraphGroup = new SimpleBooleanProperty();
132 private final BooleanProperty isNotRootGroup = new SimpleBooleanProperty();
133 private final BooleanProperty enableVariables = new SimpleBooleanProperty();
134 private final BooleanProperty enableBlankNodes = new SimpleBooleanProperty();
135 private final BooleanProperty enableValues = new SimpleBooleanProperty();
136 private final Set<VariablesCollector> variablesCollectors = new HashSet<>();
137 private final ObjectProperty<EventHandler<ObjectRelatedActionEvent<GroupGraphPatternPane>>> onRemovalRequested
138 = new SimpleObjectProperty<>();
139 private final GroupGraphPatternPane parentGroupGraphPatternPane;
140 private final ReferenceKeeper keeper = new ReferenceKeeper();
141 private final Set<InvalidationListener> observers = new HashSet<>();
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160 @SuppressWarnings("unchecked")
161 protected GroupGraphPatternPane(final QueryFormPane<?> parentQueryFormPane,
162 final GroupGraphPatternPane parentGroupGraphPatternPane, final boolean enableGroups,
163 final boolean enableFilters, final boolean enableOnlyGraphGroup, final boolean enableVariables,
164 final boolean enableBlankNodes, final boolean enableSubSelect, final boolean enableValues) {
165 Components.load(this);
166
167 this.enableGroups.set(enableGroups);
168 this.enableOnlyGraphGroup.set(enableOnlyGraphGroup);
169 this.enableFilters.set(enableFilters);
170 this.enableSubSelect.set(enableSubSelect);
171 this.parentQueryFormPane = parentQueryFormPane;
172 this.enableVariables.set(enableVariables);
173 this.enableBlankNodes.set(enableBlankNodes);
174 this.enableValues.set(enableValues);
175
176
177 autoWatch(container.getChildren(),
178 FXCollections.observableArrayList(TriplePane.class,
179 GroupGraphPatternPane.class,
180 FilterPane.class));
181
182
183 isNotRootGroup.set(parentGroupGraphPatternPane != null);
184 Utils.makeInvisibleUnmanaged(optionalCheckBox, unionCheckBox, unionCheckBox, removeButton, moveUpButton,
185 moveDownButton, addGroupButton,
186 addFilterButton, addBindButton, graphFieldContainer, graphCheckBox, springRegion,
187 minusCheckBox, filterExistsCheckBox, filterNotExistsCheckBox);
188
189 final BooleanProperty groupTypeNotSelected = new SimpleBooleanProperty();
190 groupTypeNotSelected.bind(graphCheckBox.selectedProperty().not().and(optionalCheckBox.selectedProperty().not())
191 .and(unionCheckBox.selectedProperty().not())
192 .and(graphCheckBox.selectedProperty().not())
193 .and(minusCheckBox.selectedProperty().not())
194 .and(filterExistsCheckBox.selectedProperty().not())
195 .and(filterNotExistsCheckBox.selectedProperty().not()));
196
197 graphFieldContainer.visibleProperty().bind(graphCheckBox.selectedProperty());
198 springRegion.visibleProperty().bind(graphCheckBox.selectedProperty().not());
199
200 removeButton.visibleProperty().bind(isNotRootGroup);
201 moveUpButton.visibleProperty().bind(isNotRootGroup);
202 moveDownButton.visibleProperty().bind(isNotRootGroup);
203
204 addFilterButton.visibleProperty().bind(this.enableFilters);
205 addBindButton.visibleProperty().bind(this.enableFilters);
206 addSubSelectButton.visibleProperty().bind(this.enableSubSelect);
207 addValuesButton.visibleProperty().bind(this.enableValues);
208
209 nodesAutoCompleteListHandler
210 = new PrefixedNamesAutoCompleteListHandler(parentQueryFormPane.getQueryResourcesStorage(), false, true);
211 AutoCompleteListHandler variablesAutoCompleteListHandler
212 = parentQueryFormPane.DEFAULT_VARIABLES_AUTOCOMPLETE_LIST_HANDLER;
213
214
215 if (enableOnlyGraphGroup) {
216 optionalCheckBox.visibleProperty().set(INVISIBLE_GROUP);
217 unionCheckBox.visibleProperty().set(INVISIBLE_GROUP);
218 graphCheckBox.visibleProperty().bind(isNotRootGroup);
219 minusCheckBox.visibleProperty().set(INVISIBLE_GROUP);
220 filterExistsCheckBox.visibleProperty().set(INVISIBLE_GROUP);
221 filterNotExistsCheckBox.visibleProperty().set(INVISIBLE_GROUP);
222 if (isNotRootGroup.get()) {
223 addGroupButton.visibleProperty().set(INVISIBLE_GROUP);
224 } else {
225 addGroupButton.visibleProperty().set(VISIBLE_GROUP);
226 }
227 graphField = new TypedTextField(parentQueryFormPane.getQueryPrefixesStorage(), true, FieldType.IRI,
228 FieldType.PrefixedName);
229 } else {
230 optionalCheckBox.visibleProperty()
231 .bind(isNotRootGroup.and(optionalCheckBox.selectedProperty().or(groupTypeNotSelected)));
232 unionCheckBox.visibleProperty()
233 .bind(isNotRootGroup.and(unionCheckBox.selectedProperty().or(groupTypeNotSelected)));
234 graphCheckBox.visibleProperty()
235 .bind(isNotRootGroup.and(graphCheckBox.selectedProperty().or(groupTypeNotSelected)));
236 minusCheckBox.visibleProperty()
237 .bind(isNotRootGroup.and(minusCheckBox.selectedProperty().or(groupTypeNotSelected)));
238 filterExistsCheckBox.visibleProperty().bind(isNotRootGroup.and(filterExistsCheckBox.selectedProperty()
239 .or(groupTypeNotSelected)));
240 filterNotExistsCheckBox.visibleProperty().bind(isNotRootGroup.and(filterNotExistsCheckBox.selectedProperty()
241 .or(groupTypeNotSelected)));
242
243 addGroupButton.visibleProperty().bind(this.enableGroups);
244 graphField = new TypedTextField(parentQueryFormPane.getQueryPrefixesStorage(), true, FieldType.Variable,
245 FieldType.PrefixedName, FieldType.IRI);
246 graphField.setAutoCompleteListHandler(FieldType.Variable, variablesAutoCompleteListHandler);
247 }
248
249 graphField.setAutoCompleteListHandler(FieldType.PrefixedName, nodesAutoCompleteListHandler);
250 graphField.setPlaceholder(Messages.getString("GRAPH"));
251 graphField.addVariablesCollector(this);
252 graphFieldContainer.getChildren().add(graphField);
253 graphCheckBox.selectedProperty().addListener((observable, oldValue, newValue)
254 -> {
255 if (newValue) {
256 graphField.getVariables().forEach(this::notifyVariableAdded);
257 } else {
258 graphField.getVariables().forEach(this::notifyVariableRemoved);
259 }
260 });
261
262 this.parentGroupGraphPatternPane = parentGroupGraphPatternPane;
263 if (parentGroupGraphPatternPane == null) {
264 siblings = null;
265 } else {
266 siblings = parentGroupGraphPatternPane.container.getChildren();
267 siblings.addListener(this::onPanePositionChanged);
268 }
269
270
271 createProtectingListeners();
272
273
274 watch(optionalCheckBox.selectedProperty());
275 watch(unionCheckBox.selectedProperty());
276 watch(graphCheckBox.selectedProperty());
277 watch(minusCheckBox.selectedProperty());
278 watch(filterExistsCheckBox.selectedProperty());
279 watch(filterNotExistsCheckBox.selectedProperty());
280 watch(graphField);
281
282 addArrowVisiblePropertyBinding(hoverProperty());
283 addArrowVisiblePropertyBinding(graphField.textFieldFocusedProperty());
284
285 createShortCuts(enableGroups, enableFilters);
286
287 setOnDragOver((event)
288 -> {
289 if ((event.getGestureSource() != this) && event.getDragboard().hasContent(TriplePane.DRAG_FORMAT)) {
290 event.acceptTransferModes(TransferMode.MOVE);
291 }
292 event.consume();
293 });
294
295 setOnDragDropped((event)
296 -> {
297 final Dragboard db = event.getDragboard();
298 boolean success = false;
299 if (db.hasContent(TriplePane.DRAG_FORMAT)) {
300 try {
301 addTriple(null, false).fromXML((String) db.getContent(TriplePane.DRAG_FORMAT));
302 success = true;
303 } catch (final TransformerException | ParserConfigurationException | LoadException e) {
304 LOG.error("Exception: ", e);
305 }
306 }
307 event.setDropCompleted(success);
308 event.consume();
309 });
310 }
311
312
313
314
315
316 private void createProtectingListeners() {
317 unionCheckBox.selectedProperty().addListener(keeper.toWeak((observable, oldValue, newValue)
318 -> {
319 if (newValue) {
320 final int myIndex = siblings.indexOf(GroupGraphPatternPane.this);
321 if (myIndex < 1) {
322 return;
323 }
324
325 final Node node = siblings.get(myIndex - 1);
326 if (!(node instanceof GroupGraphPatternPane)) {
327 return;
328 }
329
330 final GroupGraphPatternPane pane = (GroupGraphPatternPane) node;
331 pane.optionalCheckBox.setSelected(false);
332 pane.graphCheckBox.setSelected(false);
333 }
334 }));
335
336 final ChangeListener<Boolean> protectingListener = (observable, oldValue, newValue)
337 -> {
338 if (newValue) {
339 final int myIndex = siblings.indexOf(GroupGraphPatternPane.this);
340 if (myIndex == -1) {
341 return;
342 }
343
344 final int othersIndex = myIndex + 1;
345 if (othersIndex == siblings.size()) {
346 return;
347 }
348
349 final Node node = siblings.get(othersIndex);
350 if (!(node instanceof GroupGraphPatternPane)) {
351 return;
352 }
353
354 final GroupGraphPatternPane pane = (GroupGraphPatternPane) node;
355 pane.unionCheckBox.setSelected(false);
356 }
357 };
358
359 graphCheckBox.selectedProperty().addListener(keeper.toWeak(protectingListener));
360 optionalCheckBox.selectedProperty().addListener(keeper.toWeak(protectingListener));
361 }
362
363 private void createShortCuts(final boolean enableGroups, final boolean enableFilters) {
364
365 if (enableGroups) {
366 new ShortCutHandler(KeyCode.G, Modifier.CONTROL) {
367 @Override
368 public final boolean handle(final Object source) {
369 return addGroupGraphPatternPane() != null;
370 }
371 }.attach(this);
372 }
373
374
375 if (enableFilters) {
376 new ShortCutHandler(KeyCode.F, Modifier.CONTROL) {
377 @Override
378 public final boolean handle(final Object source) {
379 final FilterPane fp = addFilter();
380 if (fp != null) {
381 fp.requestFocus();
382 return true;
383 }
384 return false;
385 }
386 }.attach(this);
387 }
388
389
390 new ShortCutHandler(KeyCode.T, Modifier.CONTROL) {
391 @Override
392 public final boolean handle(final Object source) {
393 final TriplePane tp = addTriple(null, true);
394 if (tp != null) {
395 tp.requestFocus();
396 return true;
397 }
398 return false;
399 }
400 }.attach(this);
401 }
402
403 public final GroupGraphPatternPane getParentGroupGraphPatternPane() {
404 return parentGroupGraphPatternPane;
405 }
406
407
408
409
410
411
412
413
414
415
416 public final TriplePane addTriple(final TriplePane addAfter, final boolean checkValues) {
417 final ObservableList<Node> children = container.getChildren();
418
419 final TriplePane triplePane
420 = new TriplePane(this, children, checkValues, enableVariables.get(), enableBlankNodes.get());
421 triplePane.addVariablesCollector(this);
422
423 final int addIndex;
424 if (addAfter == null) {
425 addIndex = children.size();
426 } else {
427 final int addAfterIndex = children.indexOf(addAfter);
428 if (addAfterIndex == -1) {
429 addIndex = children.size();
430 } else {
431 addIndex = addAfterIndex + 1;
432 }
433 }
434
435 children.add(addIndex, triplePane);
436
437 addArrowVisiblePropertyBinding(triplePane.getArrow().visibleProperty());
438
439 triplePane.setOnRemovalRequested(keeper.toWeak((final ObjectRelatedActionEvent<TriplePane> event)
440 -> {
441 children.remove(event.relatedObject);
442
443 final Set<String> variablesRemoved = event.relatedObject.getVariables();
444 variablesRemoved.removeAll(getVariables());
445
446 variablesRemoved.stream().forEach(this::notifyVariableRemoved);
447 }));
448
449 return triplePane;
450 }
451
452 private VBox getContainer() {
453 return this.container;
454 }
455
456
457
458
459
460
461 public final GroupGraphPatternPane addGroupGraphPatternPane() {
462 final GroupGraphPatternPane groupPane
463 = new GroupGraphPatternPane(parentQueryFormPane, this, enableGroups.get(), enableFilters.get(),
464 enableOnlyGraphGroup.get(), enableVariables.get(), enableBlankNodes.get(),
465 enableSubSelect.get(), enableValues.get());
466 groupPane.addVariablesCollector(this);
467 container.getChildren().add(groupPane);
468 addArrowVisiblePropertyBinding(groupPane.getArrow().visibleProperty());
469
470 groupPane.setOnRemovalRequested(keeper.toWeak((final ObjectRelatedActionEvent<GroupGraphPatternPane> event)
471 -> {
472 event.relatedObject.getSubSelectPanes().stream().forEach(SubSelectPane::removeButtonOnAction);
473 container.getChildren().remove(event.relatedObject);
474
475 final Set<String> variablesRemoved = event.relatedObject.getVariables();
476 variablesRemoved.removeAll(getVariables());
477
478 variablesRemoved.stream().forEach(this::notifyVariableRemoved);
479 }));
480
481 return groupPane;
482 }
483
484
485
486
487
488
489 public ValuesPane addValuesPane() {
490 ValuesPane valuesPane = new ValuesPane(parentQueryFormPane, container.getChildren());
491 addArrowVisiblePropertyBinding(valuesPane.getArrow().visibleProperty());
492 valuesPane.setOnRemovalRequested(keeper.toWeak(
493 (final ObjectRelatedActionEvent<ValuesPane> event) -> container.getChildren()
494 .remove(event.relatedObject)));
495 valuesPane.requestFocus();
496 valuesPane.addVariablesCollector(this);
497
498 container.getChildren().add(valuesPane);
499
500 return valuesPane;
501 }
502
503
504
505
506
507
508 private SubSelectPane addSubSelectPane() {
509 final SubSelectPane subSelectPane
510 = new SubSelectPane(parentQueryFormPane, container.getChildren(), this);
511
512 addArrowVisiblePropertyBinding(subSelectPane.getArrow().visibleProperty());
513 subSelectPane.setOnRemovalRequested(keeper.toWeak(
514 (final ObjectRelatedActionEvent<SubSelectPane> event)
515 -> container.getChildren().remove(event.relatedObject)));
516 subSelectPane.requestFocus();
517
518 container.getChildren().add(subSelectPane);
519
520 return subSelectPane;
521 }
522
523
524
525
526
527
528 private FilterPane addFilter() {
529 final ObservableList<Node> children = container.getChildren();
530 final FilterPane filterPane = new FilterPane(parentQueryFormPane, children);
531
532 container.getChildren().add(filterPane);
533 addArrowVisiblePropertyBinding(filterPane.getArrow().visibleProperty());
534
535 filterPane.setOnRemovalRequested(
536 keeper.toWeak((final ObjectRelatedActionEvent<SingleClausePane> event) -> container.getChildren()
537 .remove(event.relatedObject)));
538
539 filterPane.requestFocus();
540
541 return filterPane;
542 }
543
544 public final BindPane addBind() {
545 final ObservableList<Node> children = container.getChildren();
546 final BindPane bindPane = new BindPane(parentQueryFormPane, children);
547 bindPane.addVariablesCollector(this);
548
549 container.getChildren().add(bindPane);
550 addArrowVisiblePropertyBinding(bindPane.getArrow().visibleProperty());
551
552 bindPane.setOnRemovalRequested(
553 keeper.toWeak((final ObjectRelatedActionEvent<SingleClausePane> event) -> container.getChildren()
554 .remove(event.relatedObject)));
555
556 bindPane.requestFocus();
557
558 return bindPane;
559 }
560
561 private Path getArrow() {
562 return arrow;
563 }
564
565 private void addArrowVisiblePropertyBinding(final BooleanExpression property) {
566 if (arrowVisibilityCondition == null) {
567 arrowVisibilityCondition = property;
568 } else {
569 arrowVisibilityCondition = arrowVisibilityCondition.or(property);
570 }
571
572 arrow.visibleProperty().bind(arrowVisibilityCondition);
573 }
574
575 public final QueryFormPane<?> getParentQueryFormPane() {
576 return parentQueryFormPane;
577 }
578
579 @FXML
580 @SuppressWarnings("unused")
581 private void addGroupButtonOnAction() {
582 addGroupGraphPatternPane();
583 }
584
585 @FXML
586 @SuppressWarnings("unused")
587 private void addTripleButtonOnAction() {
588 addTriple(null, true).requestFocus();
589 }
590
591 @FXML
592 @SuppressWarnings("unused")
593 private void addFilterButtonOnAction() {
594 addFilter();
595 }
596
597 @FXML
598 @SuppressWarnings("unused")
599 private void addBindButtonOnAction() {
600 addBind();
601 }
602
603 @FXML
604 @SuppressWarnings("unused")
605 private void addValuesButtonOnAction() {
606 addValuesPane().addInitialValues();
607 }
608
609 @FXML
610 @SuppressWarnings("unused")
611 private void addSubSelectButtonOnAction() {
612 SubSelectPane pane = addSubSelectPane();
613 pane.bindCheckingChanges();
614 ((SubSelectQueryFormPane) pane.getQueryPane()).runVariableColletors();
615 }
616
617 @FXML
618 @SuppressWarnings("unused")
619 private void moveUpButtonOnAction(final ActionEvent event) {
620 if (siblings == null) {
621 return;
622 }
623 final int currentPosition = siblings.indexOf(this);
624 if (currentPosition == -1) {
625 return;
626 }
627 if (unionCheckBox.isSelected()) {
628 final Node nodeAbove = siblings.get(currentPosition - 1);
629 if ((nodeAbove instanceof GroupGraphPatternPane)
630 && !((GroupGraphPatternPane) nodeAbove).unionCheckBox.isSelected()) {
631 unionCheckBox.setSelected(false);
632 }
633 }
634
635 siblings.remove(currentPosition);
636 siblings.add(currentPosition - 1, this);
637 }
638
639 @FXML
640 @SuppressWarnings("unused")
641 private void moveDownButtonOnAction(final ActionEvent event) {
642 if (siblings == null) {
643 return;
644 }
645 final int currentPosition = siblings.indexOf(this);
646 if ((currentPosition > -1) && (currentPosition < (siblings.size() - 1))) {
647 siblings.remove(currentPosition);
648 siblings.add(currentPosition + 1, this);
649 }
650 }
651
652
653
654
655
656
657
658
659 private void onPanePositionChanged(final Change<? extends Node> change) {
660 final ObservableList<? extends Node> list = change.getList();
661 final int index = list.indexOf(this);
662 if (index >= 0) {
663 moveUpButton.setDisable(index == 0);
664 moveDownButton.setDisable((index + 1) >= list.size());
665 }
666 unionCheckBox.setDisable((index < 1) || !(list.get(index - 1) instanceof GroupGraphPatternPane));
667 }
668
669
670
671
672
673
674 private void appendGroupModifier(final StringBuilder sb) {
675 if (unionCheckBox.isSelected()) {
676 sb.append("UNION ");
677 } else if (optionalCheckBox.isSelected()) {
678 sb.append("OPTIONAL ");
679 } else if (graphCheckBox.isSelected()) {
680 sb.append("GRAPH ").append(graphField.getValue()).append(" ");
681 } else if (minusCheckBox.isSelected()) {
682 sb.append("MINUS ");
683 } else if (filterExistsCheckBox.isSelected()) {
684 sb.append("FILTER EXISTS ");
685 } else if (filterNotExistsCheckBox.isSelected()) {
686 sb.append("FILTER NOT EXISTS ");
687 }
688 }
689
690 @Override
691 public final String getQueryPart() {
692 if (container.getChildren().size() > 0) {
693 final StringBuilder sb = new StringBuilder();
694 appendGroupModifier(sb);
695 sb.append("{ ");
696 container.getChildren().stream().filter((node) -> (node instanceof PartialQueryGenerator))
697 .forEach((node) -> sb.append(((PartialQueryGenerator) node).getQueryPart()));
698
699 sb.append("} ");
700 return sb.toString();
701 } else {
702 return "{}";
703 }
704 }
705
706 @Override
707 public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
708 final HashSet<String> prefixes = new HashSet<>();
709
710 if (graphCheckBox.isSelected()) {
711 prefixes.addAll(graphField.getPrefixesUsed(appendDelimiter));
712 }
713
714 container.getChildren().stream().filter((node) -> (node instanceof PrefixesUser)).forEach((node) -> prefixes.addAll(((PrefixesUser) node).getPrefixesUsed(appendDelimiter)));
715
716 return prefixes;
717 }
718
719 @Override
720 public final Set<String> getVariables() {
721 final Set<String> vars = new HashSet<>();
722
723 if (graphCheckBox.isSelected()) {
724 vars.addAll(graphField.getVariables());
725 }
726
727 container.getChildren().stream().filter((node) -> (node instanceof SimpleVariablesGenerator))
728 .forEach((node) -> vars.addAll(((SimpleVariablesGenerator) node).getVariables()));
729 return vars;
730 }
731
732 @Override
733 public final void onVariableAdded(final String variableName) {
734 notifyVariableAdded(variableName);
735 }
736
737 @Override
738 public final void onVariableRemoved(final String variableName) {
739 notifyVariableRemoved(variableName);
740 }
741
742 @Override
743 public final void notifyVariableRemoved(final String variableName) {
744 if (getVariables().contains(variableName)) {
745 return;
746 }
747 variablesCollectors.stream().forEach((collector) -> collector.onVariableRemoved(variableName));
748 }
749
750 @Override
751 public final void notifyVariableAdded(final String variableName) {
752 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(variableName));
753 }
754
755 @Override
756 public final void addVariablesCollector(final VariablesCollector collector) {
757 variablesCollectors.add(collector);
758 }
759
760 @Override
761 public final void removeVariablesCollector(final VariablesCollector collector) {
762 variablesCollectors.remove(collector);
763 }
764
765 @Override
766 public final void onVariableChanged(final String oldVariableName, final String newVariableName) {
767 notifyVariableChanged(oldVariableName, newVariableName);
768 }
769
770 @Override
771 public final void notifyVariableChanged(final String oldVariableName, final String newVariableName) {
772 if (getVariables().contains(oldVariableName)) {
773 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(newVariableName));
774 } else {
775 variablesCollectors.stream().forEach((collector) -> collector.onVariableChanged(oldVariableName, newVariableName));
776 }
777 }
778
779
780 @FXML
781 @SuppressWarnings("unused")
782 private void removeButtonOnAction(final ActionEvent event) {
783 if (onRemovalRequested.get() != null) {
784 onRemovalRequested.get().handle(new ObjectRelatedActionEvent<>(event.getSource(), event.getTarget(), this));
785 }
786 }
787
788 public final ObjectProperty<EventHandler<ObjectRelatedActionEvent<GroupGraphPatternPane>>> onRemovalRequestedProperty() {
789 return onRemovalRequested;
790 }
791
792 private void setOnRemovalRequested(
793 final EventHandler<ObjectRelatedActionEvent<GroupGraphPatternPane>> handler) {
794 onRemovalRequested.set(handler);
795 }
796
797 public final EventHandler<ObjectRelatedActionEvent<GroupGraphPatternPane>> getOnRemovalRequested() {
798 return onRemovalRequested.get();
799 }
800
801 @Override
802 public final void fillInVariableConstraints(String variableName, final VariableConstraintsGenerator nodeToSkip,
803 final Set<String> prefixes,
804 final Set<String> constraints, final Set<String> dependingVariables) {
805 if (!getVariables().contains(variableName)) {
806 return;
807 }
808
809
810 final StringBuilder sb = new StringBuilder();
811 appendGroupModifier(sb);
812 sb.append("{ ");
813
814 final Set<String> groupConstraints = new HashSet<>();
815
816 for (final Node node : container.getChildren()) {
817 if (!(node instanceof VariableConstraintsGenerator)) {
818 continue;
819 }
820
821 final Set<String> dependenciesToProcess = new HashSet<>();
822 final Set<String> processedDependencies = new HashSet<>();
823
824 dependenciesToProcess.add(variableName);
825
826 do {
827 variableName = dependenciesToProcess.iterator().next();
828 dependenciesToProcess.remove(variableName);
829 processedDependencies.add(variableName);
830
831 final VariableConstraintsGenerator g = (VariableConstraintsGenerator) node;
832 final Set<String> localConstraints = new HashSet<>();
833 final Set<String> localDependencies = new HashSet<>();
834 final Set<String> localPrefixes = new HashSet<>();
835 g.fillInVariableConstraints(variableName, nodeToSkip, localPrefixes, localConstraints,
836 localDependencies);
837
838 if (localConstraints.isEmpty() && (node != nodeToSkip)) {
839 continue;
840 }
841
842 if (node != nodeToSkip) {
843 localConstraints.stream().filter((string) -> (!groupConstraints.contains(string))).map((string) -> {
844 groupConstraints.add(string);
845 return string;
846 }).forEach(sb::append);
847
848 prefixes.addAll(localPrefixes);
849 }
850
851 localDependencies.removeAll(processedDependencies);
852 dependenciesToProcess.addAll(localDependencies);
853 } while (!dependenciesToProcess.isEmpty());
854 }
855
856 sb.append("} ");
857
858 constraints.add(sb.toString());
859 }
860
861 private ObservableList<Node> getGroupGraphPatternPaneChildren() {
862 return container.getChildren();
863 }
864
865 public List<SubSelectPane> getSubSelectPanes() {
866 List<SubSelectPane> results = new LinkedList<>();
867 Queue<GroupGraphPatternPane> nodeQueue = new LinkedList<>();
868 nodeQueue.add(this);
869
870 while (!nodeQueue.isEmpty()) {
871 GroupGraphPatternPane pane = nodeQueue.remove();
872 ObservableList<Node> nodes = pane.getGroupGraphPatternPaneChildren();
873
874 nodes.stream().forEach((node) -> {
875 if (node instanceof SubSelectPane) {
876 results.add((SubSelectPane) node);
877 } else if (node instanceof GroupGraphPatternPane) {
878 nodeQueue.add((GroupGraphPatternPane) node);
879 }
880 });
881 }
882
883 return results;
884 }
885
886 @Override
887 public final void save(final Element e) {
888 Saveable.defaultSave(e, container.getChildren());
889
890 if (unionCheckBox.isSelected()) {
891 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_UNION);
892 } else if (optionalCheckBox.isSelected()) {
893 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_OPTIONAL);
894 } else if (graphCheckBox.isSelected()) {
895 final FieldType fieldType = graphField.getFieldType();
896 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_GRAPH);
897 e.setAttribute(XML_GRAPH_TYPE, fieldType.name().toLowerCase());
898 e.setAttribute(XML_GRAPH_TEXT, graphField.getText().trim());
899 } else if (minusCheckBox.isSelected()) {
900 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_MINUS);
901 } else if (filterExistsCheckBox.isSelected()) {
902 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_FILTER_EXISTS);
903 } else if (filterNotExistsCheckBox.isSelected()) {
904 e.setAttribute(XML_GROUP_TYPE, XML_GROUP_TYPE_FILTER_NOT_EXISTS);
905 }
906 }
907
908 @Override
909 public final void load(final Object e) throws LoadException {
910 unionCheckBox.setSelected(false);
911 optionalCheckBox.setSelected(false);
912 graphCheckBox.setSelected(false);
913 minusCheckBox.setSelected(false);
914 filterExistsCheckBox.setSelected(false);
915 filterNotExistsCheckBox.setSelected(false);
916
917 if (e instanceof Element) {
918 addGroupGraphPattern((Element) e);
919 } else if (e instanceof ParseTree) {
920 addGroupGraphPattern((ParseTree) e);
921 }
922 }
923
924 private void addGroupGraphPattern(Element e) throws LoadException {
925 if (e.hasAttribute(XML_GROUP_TYPE)) {
926 final String groupTypeString = e.getAttribute(XML_GROUP_TYPE);
927 if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_UNION)) {
928 if (unionCheckBox.isDisabled()) {
929 throw new LoadException(e, XML_GROUP_TYPE);
930 }
931 unionCheckBox.setSelected(true);
932 } else if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_OPTIONAL)) {
933 optionalCheckBox.setSelected(true);
934 } else if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_GRAPH)) {
935 final String graphTypeString = e.getAttribute(XML_GRAPH_TYPE);
936 final FieldType graphType = FieldType.valueOfIgnoreCase(graphTypeString);
937 if ((graphType == null) || (!graphType.oneOf(graphField.getAllowedFieldTypes()))) {
938 throw new LoadException(e, XML_GRAPH_TYPE);
939 }
940 graphCheckBox.setSelected(true);
941 graphField.setFieldType(graphType);
942 graphField.setText(e.getAttribute(XML_GRAPH_TEXT));
943 } else if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_MINUS)) {
944 minusCheckBox.setSelected(true);
945 } else if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_FILTER_EXISTS)) {
946 filterExistsCheckBox.setSelected(true);
947 } else if (groupTypeString.equalsIgnoreCase(XML_GROUP_TYPE_FILTER_NOT_EXISTS)) {
948 filterNotExistsCheckBox.setSelected(true);
949 }
950 }
951
952 final NodeList nodes = e.getChildNodes();
953 final int nodesCount = nodes.getLength();
954 for (int nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) {
955 final org.w3c.dom.Node childNode = nodes.item(nodeIndex);
956 if (childNode instanceof Element) {
957 final Element childElement = (Element) childNode;
958 final String tagName = childElement.getTagName();
959 if (tagName.equals(GroupGraphPatternPane.XML_ELEMENT_NAME)) {
960 loadGroupGraph(childElement);
961 continue;
962 }
963 if (tagName.equals(TriplePane.XML_ELEMENT_NAME)) {
964 addTriple(null, false).load(childElement);
965 continue;
966 }
967 if (tagName.equals(FilterPane.XML_ELEMENT_NAME)) {
968 loadFilter(childElement);
969 }
970
971 if (tagName.equals(SubSelectPane.XML_ELEMENT_NAME)) {
972 addSubSelectPane().load(childElement);
973 }
974
975 if (tagName.equals(ValuesPane.XML_ELEMENT_NAME)) {
976 addValuesPane().load(childElement);
977 }
978
979 if (tagName.equals(BindPane.XML_ELEMENT_NAME)) {
980 addBind().load(childElement);
981 }
982 }
983 }
984 }
985
986 private void addGroupGraphPattern(ParseTree e) throws LoadException {
987 ParseTree parentNode = e.getParent();
988 if (parentNode instanceof SparqlParser.OptionalGraphPatternContext) {
989 optionalCheckBox.setSelected(true);
990 } else if (parentNode instanceof SparqlParser.GraphGraphPatternContext
991 || parentNode instanceof SparqlParser.QuadsNotTriplesContext) {
992 ParseTree graphName = searchNode(parentNode, SparqlParser.VarOrIRIContext.class);
993 if (graphName != null) {
994
995 final FieldType graphType = getFieldType(graphName);
996 if ((graphType == null) || (!graphType.oneOf(graphField.getAllowedFieldTypes()))) {
997 throw new ParseCancellationException("error during loading field type of: \"" + XML_GROUP_TYPE_GRAPH
998 + "\" - unsupported field type");
999 }
1000 graphCheckBox.setSelected(true);
1001 graphField.setFieldType(graphType);
1002
1003 graphField.setText(SparqlParserUtils.clearNodeValue(graphName.getText(), graphType));
1004 }
1005 } else if (parentNode instanceof SparqlParser.MinusGraphPatternContext) {
1006 minusCheckBox.setSelected(true);
1007 } else if (parentNode instanceof SparqlParser.ExistsFunctionContext) {
1008 filterExistsCheckBox.setSelected(true);
1009 } else if (parentNode instanceof SparqlParser.NotExistsFunctionContext) {
1010 filterNotExistsCheckBox.setSelected(true);
1011 } else if (parentNode instanceof SparqlParser.GroupOrUnionGraphPatternContext) {
1012 if (unionCheckBox.isDisabled()) {
1013 throw new ParseCancellationException("error during loading field type of: \"" + XML_GROUP_TYPE_UNION
1014 + "\" - unsupported field type");
1015 }
1016 unionCheckBox.setSelected(true);
1017 }
1018 }
1019
1020 private void loadGroupGraph(final Element e) throws LoadException {
1021 addGroupGraphPatternPane().load(e);
1022 }
1023
1024 public void loadFilter(final Object e) throws LoadException {
1025 if (e instanceof Element) {
1026 addFilter().load(e);
1027 } else if (e instanceof String) {
1028 addFilter().load(e);
1029 }
1030 }
1031
1032 public void loadSubSelect(final ParseTree e) throws LoadException {
1033 addSubSelectPane().load(e);
1034 }
1035
1036 @Override
1037 public String getXMLElementName() {
1038 return XML_ELEMENT_NAME;
1039 }
1040
1041 @Override
1042 public final Set<InvalidationListener> getObservers() {
1043 return observers;
1044 }
1045 }