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.gui.query.QueryFormPane;
23 import cz.zcu.mre.sparkle.gui.query.clause.SingleClausePane;
24 import cz.zcu.mre.sparkle.gui.query.clause.SingleValuesDataClausePane;
25 import cz.zcu.mre.sparkle.gui.query.clause.SingleValuesVariableClausePane;
26 import cz.zcu.mre.sparkle.gui.query.helpers.*;
27 import cz.zcu.mre.sparkle.gui.tools.Components;
28 import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
29 import cz.zcu.mre.sparkle.tools.*;
30 import cz.zcu.mre.sparkle.tools.SparqlParser;
31 import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserNode;
32 import javafx.beans.InvalidationListener;
33 import javafx.beans.property.BooleanProperty;
34 import javafx.beans.property.IntegerProperty;
35 import javafx.beans.property.SimpleBooleanProperty;
36 import javafx.beans.property.SimpleIntegerProperty;
37 import javafx.collections.ObservableList;
38 import javafx.event.ActionEvent;
39 import javafx.fxml.FXML;
40 import javafx.geometry.Pos;
41 import javafx.scene.Node;
42 import javafx.scene.control.Button;
43 import javafx.scene.control.Label;
44 import javafx.scene.layout.FlowPane;
45 import javafx.scene.layout.HBox;
46 import javafx.scene.layout.VBox;
47 import javafx.scene.shape.LineTo;
48 import javafx.scene.shape.MoveTo;
49 import javafx.scene.shape.Path;
50 import org.antlr.v4.runtime.tree.ParseTree;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.NodeList;
54 import java.util.*;
55 import static cz.zcu.mre.sparkle.tools.Definitions.*;
56 import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.getTreeChild;
57
58
59
60
61
62
63
64
65
66
67 public class ValuesClausePane
68 extends VBox
69 implements PartialQueryGenerator, VariablesGenerator, VariablesCollector, PrefixesUser, Saveable, Changeable {
70
71 private static final String XML_ELEMENT_NAME = "Values";
72 private static final String XML_VALUES_NODE_NAME = "ValuesNode";
73
74 @FXML
75 private Button addValuesButton;
76
77 @FXML
78 private FlowPane variablesFlowPane, dataFlowPane;
79
80 private final QueryFormPane<?> parentQueryFormPane;
81 private final Set<VariablesCollector> variablesCollectors = new HashSet<>();
82 private final ReferenceKeeper keeper = new ReferenceKeeper();
83 private final Set<InvalidationListener> observers = new HashSet<>();
84 private Label leftBracketOfVarQueryPart, rightBracketOfVarQueryPart, leftCurlyBracketOfVarQueryPart,
85 rightCurlyBracketOfVarQueryPart;
86 private final IntegerProperty countOfVariables = new SimpleIntegerProperty(0);
87 private final BooleanProperty removableProperty = new SimpleBooleanProperty(false);
88 private final Button addVariableButton = new Button("+ Variable");
89 private final Button addDataButton = new Button("+ Data");
90
91 public ValuesClausePane(final QueryFormPane<?> parentQueryFormPane) {
92 Components.load(this);
93
94 this.parentQueryFormPane = parentQueryFormPane;
95
96 setLabels();
97
98 addVariableButton.setOnAction((ActionEvent event) -> addValuesVariable());
99 addDataButton.setOnAction((ActionEvent event) -> addValuesData(true));
100
101 countOfVariables.addListener((observable, oldValue, newValue) -> {
102 int newValueInt = newValue.intValue();
103 if (newValueInt == 0) {
104 dataFlowPane.getChildren().clear();
105 dataFlowPane.getChildren()
106 .addAll(addDataButton, leftCurlyBracketOfVarQueryPart, rightCurlyBracketOfVarQueryPart);
107 this.getChildren().add(0, addValuesButton);
108 this.removableProperty.set(true);
109 } else if (oldValue.intValue() == 0 && newValueInt > 0) {
110 this.getChildren().remove(addValuesButton);
111 this.removableProperty.set(false);
112 }
113 });
114
115 variablesFlowPane.getChildren()
116 .addAll(addVariableButton, leftBracketOfVarQueryPart, rightBracketOfVarQueryPart);
117 dataFlowPane.getChildren()
118 .addAll(addDataButton, leftCurlyBracketOfVarQueryPart, rightCurlyBracketOfVarQueryPart);
119
120
121 autoWatch(variablesFlowPane.getChildren(), SingleValuesVariableClausePane.class);
122 autoWatch(dataFlowPane.getChildren(), SingleValuesDataClausePane.class);
123 }
124
125
126
127
128 private void setLabels() {
129 leftBracketOfVarQueryPart = new Label(LEFT_BRACKET);
130 rightBracketOfVarQueryPart = new Label(RIGHT_BRACKET);
131 leftCurlyBracketOfVarQueryPart = new Label(LEFT_CURLY_BRACKET);
132 rightCurlyBracketOfVarQueryPart = new Label(RIGHT_CURLY_BRACKET);
133
134
135 leftBracketOfVarQueryPart.visibleProperty().bind(countOfVariables.isNotEqualTo(0));
136 rightBracketOfVarQueryPart.visibleProperty().bind(leftBracketOfVarQueryPart.visibleProperty());
137 leftCurlyBracketOfVarQueryPart.visibleProperty().bind(leftBracketOfVarQueryPart.visibleProperty());
138 rightCurlyBracketOfVarQueryPart.visibleProperty().bind(leftBracketOfVarQueryPart.visibleProperty());
139 addVariableButton.visibleProperty().bind(leftBracketOfVarQueryPart.visibleProperty());
140 addDataButton.visibleProperty().bind(leftBracketOfVarQueryPart.visibleProperty());
141 }
142
143 public void addInitialValues() {
144 this.addVariableButton.fire();
145 this.addDataButton.fire();
146 }
147
148 public BooleanProperty getRemovableProperty() {
149 return this.removableProperty;
150 }
151
152 @FXML
153 private void addValuesButtonOnAction(final ActionEvent event) {
154 addValuesVariable().requestFocus();
155 }
156
157
158
159
160
161
162 private SingleValuesVariableClausePane addValuesVariable() {
163 final SingleValuesVariableClausePane pane = new SingleValuesVariableClausePane(parentQueryFormPane);
164 final ObservableList<Node> children = variablesFlowPane.getChildren();
165 children.add(children.indexOf(rightBracketOfVarQueryPart), pane);
166
167 this.countOfVariables.set(this.countOfVariables.get() + 1);
168
169 dataFlowPane.getChildren().stream().filter((dataChild) -> (dataChild instanceof HBox)).forEach((dataChild) -> {
170 HBox element = (HBox) dataChild;
171 addValuesDataTextField(element, element.getChildren().size() - 1);
172 });
173
174 pane.addVariablesCollector(this);
175 pane.setOnRemovalRequested(keeper.toWeak((final ObjectRelatedActionEvent<SingleClausePane> e) -> {
176 setValuesOrder(pane);
177 variablesFlowPane.getChildren().remove(e.relatedObject);
178 ((SingleValuesVariableClausePane) e.relatedObject).getVariables().stream().forEach(this::onVariableRemoved);
179 this.countOfVariables.set(this.countOfVariables.get() - 1);
180 }));
181 return pane;
182 }
183
184
185
186
187
188
189 private void setValuesOrder(final SingleValuesVariableClausePane pane) {
190 int indexOfVariable = 0;
191 for (Node node : variablesFlowPane.getChildren()) {
192 if (node instanceof SingleValuesVariableClausePane) {
193 if (node == pane) {
194 break;
195 }
196 indexOfVariable++;
197 }
198 }
199
200 for (Node node : dataFlowPane.getChildren()) {
201 if (node instanceof HBox) {
202 final List<Node> nodesToRemove = new LinkedList<>();
203 ObservableList<Node> hBoxChildren = ((HBox) node).getChildren();
204 int indexOfHBox = 0;
205 for (Node hBoxChild : hBoxChildren) {
206 if (hBoxChild instanceof SingleValuesDataClausePane) {
207 if (indexOfHBox == indexOfVariable) {
208 nodesToRemove.add(hBoxChild);
209 break;
210 }
211 indexOfHBox++;
212 }
213 }
214 hBoxChildren.removeAll(nodesToRemove);
215 }
216 }
217 }
218
219
220
221
222
223
224
225
226
227 private SingleValuesDataClausePane addValuesDataTextField(final HBox hBox, int position) {
228 SingleValuesDataClausePane pane = new SingleValuesDataClausePane(parentQueryFormPane);
229 hBox.getChildren().add(position, pane);
230 return pane;
231 }
232
233
234
235
236
237
238
239
240
241
242 private HBox addValuesData(final boolean addTextFields) {
243 final Label rightBracket = new Label(RIGHT_BRACKET);
244 final HBox hBox = new HBox(new Label(" ("), rightBracket);
245 hBox.setId("guiFontStyle");
246 hBox.setAlignment(Pos.CENTER_LEFT);
247 final Button removeButton = getRemoveButton();
248 final int indexOfNewPane = dataFlowPane.getChildren().indexOf(rightCurlyBracketOfVarQueryPart);
249 removeButton.setOnAction((ActionEvent event) -> {
250 dataFlowPane.getChildren().remove(hBox);
251 dataFlowPane.getChildren().remove(removeButton);
252 });
253 dataFlowPane.getChildren().add(indexOfNewPane, removeButton);
254 dataFlowPane.getChildren().add(indexOfNewPane, hBox);
255
256 if (addTextFields) {
257 final int indexOfRightBracket = hBox.getChildren().indexOf(rightBracket);
258 for (int i = 0; i < this.countOfVariables.get(); i++) {
259 hBox.getChildren().add(indexOfRightBracket, new SingleValuesDataClausePane(parentQueryFormPane));
260 }
261 }
262
263 return hBox;
264 }
265
266 @Override
267 public final Set<String> getVariables() {
268 final Set<String> result = new HashSet<>();
269 variablesFlowPane.getChildren().stream().filter((node) -> (node instanceof SimpleVariablesGenerator))
270 .forEach((node) -> result.addAll(((SimpleVariablesGenerator) node).getVariables()));
271
272 return result;
273 }
274
275 private Button getRemoveButton() {
276 Button removeButton = new Button();
277
278 Path path = new Path();
279 path.setStrokeWidth(1.5);
280 path.getElements().add(new MoveTo(-3.0, -3.0));
281 path.getElements().add(new LineTo(3.0, 3.0));
282 path.getElements().add(new MoveTo(-3.0, 3.0));
283 path.getElements().add(new LineTo(3.0, -3.0));
284
285 removeButton.setGraphic(path);
286 return removeButton;
287 }
288
289 @Override
290 public final void onVariableAdded(final String variableName) {
291 notifyVariableAdded(variableName);
292 }
293
294 @Override
295 public final void onVariableChanged(final String oldVariableName, final String newVariableName) {
296 notifyVariableChanged(oldVariableName, newVariableName);
297 }
298
299 @Override
300 public final void onVariableRemoved(final String variableName) {
301 notifyVariableRemoved(variableName);
302 }
303
304 @Override
305 public final void notifyVariableAdded(final String variableName) {
306 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(variableName));
307 }
308
309 @Override
310 public final void notifyVariableChanged(final String oldVariableName, final String newVariableName) {
311 if (getVariables().contains(oldVariableName)) {
312 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(newVariableName));
313 } else {
314 variablesCollectors.stream().forEach((collector) -> collector.onVariableChanged(oldVariableName, newVariableName));
315 }
316 }
317
318 @Override
319 public final void notifyVariableRemoved(final String variableName) {
320 if (getVariables().contains(variableName)) {
321 return;
322 }
323 variablesCollectors.stream().forEach((collector) -> collector.onVariableRemoved(variableName));
324 }
325
326 @Override
327 public final void addVariablesCollector(final VariablesCollector collector) {
328 variablesCollectors.add(collector);
329 }
330
331 @Override
332 public final void removeVariablesCollector(final VariablesCollector collector) {
333 variablesCollectors.remove(collector);
334 }
335
336 @Override
337 public final String getQueryPart() {
338 final StringBuilder sb = new StringBuilder();
339
340 variablesFlowPane.getChildren().stream().filter((node) -> (node instanceof PartialQueryGenerator)).
341 forEach((node) -> sb.append(((PartialQueryGenerator) node).getQueryPart()));
342
343 if (sb.length() > 0) {
344 sb.insert(0, "VALUES (");
345 sb.append(RIGHT_BRACKET).append(LEFT_CURLY_BRACKET);
346 dataFlowPane.getChildren().stream().filter((node) -> (node instanceof HBox)).map((node) -> {
347 StringBuilder hBoxSB = new StringBuilder();
348 ((HBox) node).getChildren().stream().filter((hBoxChild) -> (hBoxChild instanceof PartialQueryGenerator))
349 .forEach((hBoxChild) -> hBoxSB.append(((PartialQueryGenerator) hBoxChild).getQueryPart())
350 .append(Definitions.SPACE));
351 return hBoxSB;
352 }).filter((hBoxSB) -> (hBoxSB.length() > 0)).forEach((hBoxSB) -> sb.append(LEFT_BRACKET).append(hBoxSB.toString()).append(Definitions.RIGHT_BRACKET));
353 sb.append(RIGHT_CURLY_BRACKET);
354 }
355 return sb.toString();
356 }
357
358 @Override
359 public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
360 final Set<String> result = new HashSet<>();
361 dataFlowPane.getChildren().stream().filter((child) -> (child instanceof HBox))
362 .map((child) -> ((HBox) child).getChildren()).forEach((hBoxChildren) -> hBoxChildren.stream().filter((hBoxChild) -> (hBoxChild instanceof PrefixesUser)).forEach((hBoxChild) -> result.addAll(((PrefixesUser) hBoxChild).getPrefixesUsed(appendDelimiter))));
363 return result;
364 }
365
366 private List<SingleValuesDataClausePane> getDataOfVariable(final int variablePosition,
367 final ObservableList<Node> dataChildren) {
368 final List<SingleValuesDataClausePane> results = new LinkedList<>();
369 for (Node dataChild : dataChildren) {
370 if (dataChild instanceof HBox) {
371 int dataPosition = 0;
372 ObservableList<Node> hBoxChildren = ((HBox) dataChild).getChildren();
373 for (Node hBoxChild : hBoxChildren) {
374 if (hBoxChild instanceof SingleValuesDataClausePane) {
375 if (dataPosition == variablePosition) {
376 results.add((SingleValuesDataClausePane) hBoxChild);
377 break;
378 }
379 dataPosition++;
380 }
381 }
382
383 }
384 }
385 return results;
386 }
387
388 @Override
389 public final void save(final Element e) {
390 final Document doc = e.getOwnerDocument();
391 int variableIndex = 0;
392 for (Node variableChild : variablesFlowPane.getChildren()) {
393 if (variableChild instanceof SingleValuesVariableClausePane) {
394 final Element element = doc.createElement(XML_VALUES_NODE_NAME);
395 ((SingleValuesVariableClausePane) variableChild).save(element);
396 e.appendChild(element);
397 Saveable.defaultSave(element, getDataOfVariable(variableIndex, dataFlowPane.getChildren()));
398 variableIndex++;
399 }
400 }
401 }
402
403
404
405
406
407
408
409
410 private List<Element> getValuesData(org.w3c.dom.Node childNode) {
411 final NodeList valuesDataNodes = childNode.getChildNodes();
412 final int valuesDataNodeCount = valuesDataNodes.getLength();
413 final List<Element> elementList = new LinkedList<>();
414 for (int j = 0; j < valuesDataNodeCount; j++) {
415 final org.w3c.dom.Node valuesDataNode = valuesDataNodes.item(j);
416 if (valuesDataNode instanceof Element) {
417 final Element valuesDataElement = (Element) valuesDataNode;
418 if (valuesDataElement.hasAttribute(SingleValuesDataClausePane.XML_VALUES_DATA_TEXT)
419 && valuesDataElement.hasAttribute(SingleValuesDataClausePane.XML_VALUES_DATA_TYPE)) {
420 elementList.add(valuesDataElement);
421 }
422 }
423 }
424 return elementList;
425 }
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440 private int loadVariablesDataAndGetDataCount(final Element e, final int variableCount, final NodeList nodes,
441 final List<List<Element>> dataOfVariables) throws LoadException {
442 int countOfDataGroup = -1;
443 for (int i = 0; i < variableCount; i++) {
444 final org.w3c.dom.Node childNode = nodes.item(i);
445 if (childNode instanceof Element) {
446 final Element eNode = (Element) childNode;
447 if (eNode.hasAttribute(SingleValuesVariableClausePane.XML_VALUES_VARIABLE_TEXT)
448 && eNode.hasAttribute(SingleValuesVariableClausePane.XML_VALUES_VARIABLE_TYPE)) {
449 addValuesVariable().load(childNode);
450
451 final List<Element> elementList = getValuesData(childNode);
452 dataOfVariables.add(elementList);
453
454 if (countOfDataGroup < 0) {
455 countOfDataGroup = elementList.size();
456 } else {
457 if (countOfDataGroup != elementList.size()) {
458 throw new LoadException(e, "Some of loaded data are missing or damaged.");
459 }
460 }
461 } else {
462 throw new LoadException(e, "Some of the attributes is missing.");
463 }
464 }
465 }
466 return countOfDataGroup;
467 }
468
469 @Override
470 public final void load(final Object e) throws Saveable.LoadException {
471 if (e instanceof Element) {
472 final Element eNode = (Element) e;
473 final NodeList nodes = eNode.getElementsByTagName(XML_VALUES_NODE_NAME);
474 final int nodesCount = nodes.getLength();
475
476 if (nodesCount > 0) {
477 final List<List<Element>> dataOfVariables = new ArrayList<>(nodesCount);
478 final int listSize = loadVariablesDataAndGetDataCount(eNode, nodesCount, nodes, dataOfVariables);
479 for (int i = 0; i < listSize; i++) {
480 final HBox currentHBox = addValuesData(false);
481 for (int j = 0; j < nodesCount; j++) {
482 addValuesDataTextField(currentHBox, currentHBox.getChildren().size() - 1)
483 .load(dataOfVariables.get(j).get(i));
484 }
485 }
486 }
487 } else if (e instanceof ParseTree) {
488 final Stack<SparqlParserNode> nodeStack = new Stack<>();
489 nodeStack.push(new SparqlParserNode((ParseTree) e));
490 while (!nodeStack.isEmpty()) {
491 SparqlParserNode currentNode = nodeStack.pop();
492 ParseTree nodeData = currentNode.getNodeData();
493 if (nodeData instanceof SparqlParser.InlineDataOneVarContext
494 || nodeData instanceof SparqlParser.InlineDataFullContext) {
495 addNewValuesFromFile(nodeData);
496 break;
497 } else {
498 nodeStack.push(currentNode);
499 getTreeChild(currentNode, nodeStack);
500 }
501 }
502 }
503 }
504
505
506
507
508
509
510
511
512
513
514 private void processDataBlockValue(ParseTree valueOfDataBlock, final String previousValue,
515 final HBox currentDataBlock) throws LoadException {
516 if (valueOfDataBlock.getText().equals(RIGHT_BRACKET)) {
517 if (previousValue != null && previousValue.equals(LEFT_BRACKET)) {
518 final HBox hBoxOfNIL = currentDataBlock != null ? currentDataBlock : addValuesData(false);
519 addValuesDataTextField(hBoxOfNIL, hBoxOfNIL.getChildren().size() - 1).load(valueOfDataBlock.getText());
520 }
521 } else {
522 addValuesDataTextField(currentDataBlock, currentDataBlock.getChildren().size() - 1).load(valueOfDataBlock);
523 }
524 }
525
526
527
528
529
530
531
532
533
534
535 private void processDataBlockValues(final SparqlParser.DataBlockValueWithBracketContext dataBlockValues)
536 throws LoadException {
537 String previousNode = null;
538 final HBox dataBlock = addValuesData(false);
539 for (ParseTree valueOfDataBlock : dataBlockValues.children) {
540 if (valueOfDataBlock instanceof SparqlParser.DataBlockValueContext
541 || valueOfDataBlock.getText().equals(RIGHT_BRACKET)) {
542 processDataBlockValue(valueOfDataBlock, previousNode, dataBlock);
543 }
544 previousNode = valueOfDataBlock.getText();
545 }
546 }
547
548
549
550
551
552
553
554
555 private void addNewValuesFromFile(final ParseTree rootNode) throws LoadException {
556 String valueOfPreviousNode = null;
557 for (int i = 0; i < rootNode.getChildCount(); i++) {
558 final ParseTree child = rootNode.getChild(i);
559 if (child instanceof SparqlParser.VarContext) {
560 addValuesVariable().load(child);
561 } else if (child instanceof SparqlParser.DataBlockValueWithBracketContext) {
562 processDataBlockValues((SparqlParser.DataBlockValueWithBracketContext) child);
563 } else if (child instanceof SparqlParser.DataBlockValueContext) {
564 processDataBlockValue(child, valueOfPreviousNode, addValuesData(false));
565 } else if (child.getText().equals(RIGHT_BRACKET) && valueOfPreviousNode != null
566 && valueOfPreviousNode.equals(LEFT_BRACKET)) {
567 addValuesVariable().load(child.getText());
568 }
569 valueOfPreviousNode = child.getText();
570 }
571 }
572
573 @Override
574 public final String getXMLElementName() {
575 return XML_ELEMENT_NAME;
576 }
577
578 @Override
579 public Set<InvalidationListener> getObservers() {
580 return observers;
581 }
582 }