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.triplePane;
21
22 import cz.zcu.mre.sparkle.Messages;
23 import cz.zcu.mre.sparkle.data.DataAgent;
24 import cz.zcu.mre.sparkle.data.DataHelper;
25 import cz.zcu.mre.sparkle.gui.dialogs.MessageDialog;
26 import cz.zcu.mre.sparkle.gui.dialogs.query.PathDepthDialog;
27 import cz.zcu.mre.sparkle.gui.dialogs.query.PathsDialog;
28 import cz.zcu.mre.sparkle.gui.dialogs.PropertiesDialog;
29 import cz.zcu.mre.sparkle.gui.dialogs.other.ErrorDialog;
30 import cz.zcu.mre.sparkle.gui.dialogs.other.ProgressDialog;
31 import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
32 import cz.zcu.mre.sparkle.gui.query.autoComplete.AutoCompleteListHandler;
33 import cz.zcu.mre.sparkle.gui.query.autoComplete.PrefixedNamesAutoCompleteListHandler;
34 import cz.zcu.mre.sparkle.gui.query.helpers.*;
35 import cz.zcu.mre.sparkle.gui.query.modifiers.GroupGraphPatternPane;
36 import cz.zcu.mre.sparkle.gui.query.other.TypedTextField;
37 import cz.zcu.mre.sparkle.gui.tools.Components;
38 import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
39 import cz.zcu.mre.sparkle.tools.CancellableConsumer;
40 import cz.zcu.mre.sparkle.tools.Changeable;
41 import cz.zcu.mre.sparkle.tools.Definitions;
42 import cz.zcu.mre.sparkle.tools.Saveable;
43 import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserTriple;
44 import cz.zcu.mre.sparkle.tools.sparqlValidation.SparqlValidationUtils;
45 import javafx.beans.InvalidationListener;
46 import javafx.beans.Observable;
47 import javafx.beans.binding.BooleanExpression;
48 import javafx.beans.property.*;
49 import javafx.beans.property.Property;
50 import javafx.beans.value.ChangeListener;
51 import javafx.beans.value.ObservableBooleanValue;
52 import javafx.collections.ListChangeListener.Change;
53 import javafx.collections.ObservableList;
54 import javafx.collections.transformation.SortedList;
55 import javafx.concurrent.Task;
56 import javafx.event.ActionEvent;
57 import javafx.event.EventHandler;
58 import javafx.fxml.FXML;
59 import javafx.scene.Node;
60 import javafx.scene.control.*;
61 import javafx.scene.input.ClipboardContent;
62 import javafx.scene.input.DataFormat;
63 import javafx.scene.input.Dragboard;
64 import javafx.scene.input.TransferMode;
65 import javafx.scene.layout.HBox;
66 import javafx.scene.layout.VBox;
67 import javafx.scene.shape.Path;
68 import javafx.stage.Window;
69 import org.apache.jena.query.Query;
70 import org.apache.jena.query.QuerySolution;
71 import org.apache.jena.rdf.model.*;
72 import org.apache.jena.vocabulary.RDFS;
73 import org.w3c.dom.Document;
74 import org.w3c.dom.Element;
75 import org.w3c.dom.NodeList;
76 import javax.xml.parsers.DocumentBuilderFactory;
77 import javax.xml.parsers.ParserConfigurationException;
78 import javax.xml.transform.TransformerException;
79 import javax.xml.transform.TransformerFactory;
80 import javax.xml.transform.TransformerFactoryConfigurationError;
81 import javax.xml.transform.dom.DOMResult;
82 import javax.xml.transform.dom.DOMSource;
83 import javax.xml.transform.stream.StreamResult;
84 import javax.xml.transform.stream.StreamSource;
85 import java.io.StringReader;
86 import java.io.StringWriter;
87 import java.util.*;
88 import java.util.concurrent.ExecutionException;
89 import java.util.logging.Level;
90 import java.util.logging.Logger;
91 import java.util.regex.Matcher;
92 import static cz.zcu.mre.sparkle.tools.Definitions.DATA_TYPE_PREFIX;
93 import static cz.zcu.mre.sparkle.tools.Definitions.LANG_PREFIX;
94 import static cz.zcu.mre.sparkle.tools.Utils.*;
95 import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.FIELD_TYPE;
96
97
98
99
100
101
102
103
104
105 public final class TriplePane
106 extends VBox
107 implements VariableConstraintsGenerator, PrefixesUser, VariablesGenerator, VariablesCollector, Saveable,
108 Changeable {
109
110 private static final Logger LOG = Logger.getLogger(TriplePane.class.getName());
111
112 private static final String XML_FIELD_TYPE = "type";
113 static final String XML_FIELD_TEXT = "text";
114 static final String XML_LITERAL_DATA_TYPE = "datatype";
115 static final String XML_LITERAL_LANG = "lang";
116 private static final String XML_SUBTRIPLES_ELEMENT_NAME = "Subtriples";
117 static final String XML_OBJECT_ELEMENT_NAME = "Object";
118 public static final String XML_PREDICATE_ELEMENT_NAME = "Predicate";
119 public static final String XML_SUBJECT_ELEMENT_NAME = "Subject";
120 public static final String XML_ELEMENT_NAME = "Triple";
121 public static final DataFormat DRAG_FORMAT = new DataFormat("sparkle.triple");
122 private static final String XML_SUBTRIPLE_ELEMENT_NAME = "Subtriple";
123 private static final int RANDOM_VARIABLE_LENGTH = 12;
124 private static final int BLANK_NODE_LENGTH = 3;
125
126 private String prefferedlanguage;
127
128
129
130
131 private final TriplePaneShortcuts shortcuts;
132
133 @FXML
134 private HBox subjectFieldContainer;
135 @FXML
136 private HBox propertyFieldContainer;
137 @FXML
138 private HBox objectFieldContainer;
139
140 @FXML
141 private VBox container;
142
143 @FXML
144 private TextField langTextField;
145 @FXML
146 private Button addSubTripleButton, moveDownButton, moveUpButton, findPathButton, findPropertiesButton;
147
148 @FXML
149 private ComboBox<String> objectDataTypeComboBox;
150 @FXML
151 private ContextMenu prefixesContextMenu;
152 @FXML
153 private Path arrow;
154
155 @FXML
156 private MenuButton literalTypeMenuButton;
157 @FXML
158 private MenuItem plainStringLiteralMenuItem, typedLiteralMenuItem, localizedStringLiteralMenuItem;
159
160 private BooleanExpression arrowVisibilityCondition;
161 private final ObjectProperty<TriplePane> parentTriplePaneProperty = new SimpleObjectProperty<>(null);
162
163 private final AutoCompleteListHandler variablesAutoCompleteListHandler, propertiesAutoCompleteListHandler,
164 resourcesAutoCompleteListHandler;
165
166 private final ObservableList<Node> siblings;
167
168 private final QueryFormPane<?> parentQueryFormPane;
169 private final GroupGraphPatternPane parentGroupGraphPatternPane;
170 private final Set<VariablesCollector> variablesCollectors = new HashSet<>();
171 private final ObjectProperty<EventHandler<ObjectRelatedActionEvent<TriplePane>>> onRemovalRequested
172 = new SimpleObjectProperty<>();
173
174 private final ObjectProperty<LiteralType> literalTypeProperty = new SimpleObjectProperty<>();
175
176 private final ReferenceKeeper objectFieldTypePropertyRefKeeper = new ReferenceKeeper();
177
178 private final TypedTextField subjectField, propertyField, objectField;
179
180 private final Set<InvalidationListener> observers = new HashSet<>();
181 private final BooleanProperty enableVariables = new SimpleBooleanProperty();
182 private final BooleanProperty enableBlankNodes = new SimpleBooleanProperty();
183
184 public TriplePane(final GroupGraphPatternPane parentPane, final ObservableList<Node> siblings,
185 final boolean checkValues, final boolean enableVariables, final boolean enableBlankNodes) {
186 this(parentPane, siblings, null, checkValues, enableVariables, enableBlankNodes);
187 }
188
189 public TriplePane(final GroupGraphPatternPane parentPane, final ObservableList<Node> siblings,
190 final TriplePane parentTriplePane, final boolean checkValues, final boolean enableVariables,
191 final boolean enableBlankNodes) {
192 Components.load(this);
193
194 shortcuts = new TriplePaneShortcuts(this);
195
196 this.parentGroupGraphPatternPane = parentPane;
197 this.parentQueryFormPane = parentPane.getParentQueryFormPane();
198 this.siblings = siblings;
199 this.enableVariables.set(enableVariables);
200 this.enableBlankNodes.set(enableBlankNodes);
201 parentTriplePaneProperty.set(parentTriplePane);
202
203
204 autoWatch(container.getChildren(), TriplePane.class);
205
206 if (siblings != null) {
207 siblings.addListener(this::onPanePositionChanged);
208 }
209
210 makeInvisibleUnmanaged(container, objectDataTypeComboBox, literalTypeMenuButton, langTextField, findPathButton,
211 findPropertiesButton);
212
213 setupContainer();
214
215 variablesAutoCompleteListHandler = parentQueryFormPane.DEFAULT_VARIABLES_AUTOCOMPLETE_LIST_HANDLER;
216
217 propertiesAutoCompleteListHandler
218 = new PrefixedNamesAutoCompleteListHandler(parentQueryFormPane, true, false, this);
219
220 resourcesAutoCompleteListHandler
221 = new PrefixedNamesAutoCompleteListHandler(parentQueryFormPane.getQueryResourcesStorage(), false, true);
222
223 subjectField
224 = SubjectField.initSubjectField(this, parentTriplePane, checkValues, enableVariables, enableBlankNodes);
225 propertyField = PropertyField.initPropertyField(this, checkValues, enableVariables);
226 objectField = ObjectField.setupObjectField(this, checkValues, enableVariables, enableBlankNodes);
227
228
229 initButtons();
230
231 addArrowVisiblePropertyBinding(hoverProperty().or(
232 subjectField.textFieldFocusedProperty().or(propertyField.textFieldFocusedProperty())
233 .or(objectField.textFieldFocusedProperty())));
234
235
236
237
238 parentQueryFormPane.getQueryDataTypesStorage().addListener(
239 objectFieldTypePropertyRefKeeper.toWeak((term, added) -> updateDataTypeComboBox()));
240
241
242 setupWatch();
243 setupDrag();
244 }
245
246
247
248
249 private void initButtons() {
250 addSubTripleButton.disableProperty().bind(parentTriplePaneProperty.isNotNull());
251 findPathButton
252 .visibleProperty()
253 .bind(parentTriplePaneProperty
254 .isNull()
255 .and(propertyField.fieldTypeProperty().isEqualTo(FieldType.PrefixedName)
256 .or(propertyField.fieldTypeProperty().isEqualTo(FieldType.IRI)))
257 .and(subjectField.fieldTypeProperty().isEqualTo(FieldType.Variable)));
258 findPathButton.disableProperty().bind(subjectField.fieldContentIsValidProperty().not()
259 .or(propertyField.fieldContentIsValidProperty().not()));
260 findPropertiesButton.visibleProperty()
261 .bind(propertyField.fieldTypeProperty().isEqualTo(FieldType.PrefixedName));
262 findPropertiesButton.disableProperty().bind(subjectField.fieldContentIsValidProperty().not());
263 }
264
265
266
267
268 private void setupWatch() {
269 watch(subjectField);
270 watch(propertyField);
271 watch(objectField);
272 watch(literalTypeProperty);
273 watch(objectDataTypeComboBox.valueProperty());
274 }
275
276
277
278
279 private void setupDrag() {
280 setOnDragDetected((event) -> {
281 final Dragboard dragboard = startDragAndDrop(TransferMode.MOVE);
282 final ClipboardContent content = new ClipboardContent();
283 try {
284 content.put(DRAG_FORMAT, toXML());
285 dragboard.setContent(content);
286 } catch (final TransformerException | ParserConfigurationException e) {
287 LOG.log(Level.SEVERE, "Exception: ", e);
288 }
289 event.consume();
290 });
291
292 setOnDragDone((event) -> {
293 if (event.getTransferMode() == TransferMode.MOVE) {
294 removeButtonOnAction(new ActionEvent());
295 }
296 event.consume();
297 });
298 }
299
300
301
302
303 private void setupContainer() {
304 container.getChildren().addListener(
305 (final Observable observable) -> container.setVisible(container.getChildren().size() > 0));
306
307 container.setVisible(container.getChildren().size() > 0);
308 }
309
310
311
312
313 void updateDataTypeComboBox() {
314 final ObservableList<String> items
315 = new SortedList<>(parentQueryFormPane.getQueryDataTypesStorage().getAllDataTypes(),
316 String.CASE_INSENSITIVE_ORDER);
317 if (objectDataTypeComboBox.itemsProperty().isBound()) {
318 return;
319 }
320
321 final String selectedItem = objectDataTypeComboBox.getValue();
322
323 objectDataTypeComboBox.setItems(items);
324
325 if (items.isEmpty()) {
326 return;
327 }
328
329 if (objectDataTypeComboBox.valueProperty().isBound()) {
330 return;
331 }
332
333 final int selectedItemIndex = items.indexOf(selectedItem);
334 if ((selectedItem != null) && (selectedItemIndex != -1)) {
335 objectDataTypeComboBox.setValue(selectedItem);
336 return;
337 }
338
339 objectDataTypeComboBox.setValue(objectDataTypeComboBox.getItems().get(0));
340 }
341
342
343
344
345
346 public final Path getArrow() {
347 return arrow;
348 }
349
350 private void addArrowVisiblePropertyBinding(final BooleanExpression property) {
351 if (arrowVisibilityCondition == null) {
352 arrowVisibilityCondition = property;
353 } else {
354 arrowVisibilityCondition = arrowVisibilityCondition.or(property);
355 }
356
357 arrow.visibleProperty().bind(arrowVisibilityCondition);
358 }
359
360
361
362
363
364
365 public TriplePane addSubTriple(boolean checkValues) {
366 final ObservableList<Node> containerChildren = container.getChildren();
367 final TriplePane subTriplePane
368 = new TriplePane(parentGroupGraphPatternPane, containerChildren, this, checkValues, enableVariables.get(),
369 enableBlankNodes.get());
370 subTriplePane.addVariablesCollector(this);
371 containerChildren.add(subTriplePane);
372 addArrowVisiblePropertyBinding(subTriplePane.getArrow().visibleProperty());
373
374 subTriplePane.setOnRemovalRequested(
375 objectFieldTypePropertyRefKeeper
376 .toWeak((final ObjectRelatedActionEvent<TriplePane> e) -> removeTriple(e.relatedObject)));
377
378 return subTriplePane;
379 }
380
381
382
383
384 private void removeTriple(final TriplePane triplePane) {
385 container.getChildren().remove(triplePane);
386 final Set<String> variablesToRemove = triplePane.getVariables();
387 variablesToRemove.removeAll(getVariables());
388 variablesToRemove.forEach(this::notifyVariableRemoved);
389 }
390
391
392
393
394
395 @FXML
396 protected void addSubTripleButtonOnAction(final ActionEvent event) {
397 addSubTriple(true).requestFocus();
398 }
399
400
401
402
403 @FXML
404 void setPlainStringLiteralType() {
405 literalTypeMenuButton.setText(plainStringLiteralMenuItem.getText());
406 literalTypeProperty.set(LiteralType.PlainString);
407 }
408
409
410
411
412 @FXML
413 void setTypedLiteralType() {
414 literalTypeMenuButton.setText(typedLiteralMenuItem.getText());
415 literalTypeProperty.set(LiteralType.Typed);
416 }
417
418
419
420
421 @FXML
422 void setLocalizedStringLiteralType() {
423 literalTypeMenuButton.setText(localizedStringLiteralMenuItem.getText());
424 literalTypeProperty.set(LiteralType.LocalizedString);
425 }
426
427
428
429
430 @FXML
431 private void removeButtonOnAction(final ActionEvent event) {
432 if (onRemovalRequested.get() != null) {
433 onRemovalRequested.get().handle(new ObjectRelatedActionEvent<>(event.getSource(), event.getTarget(), this));
434 }
435 }
436
437
438
439
440
441 public final ObjectProperty<EventHandler<ObjectRelatedActionEvent<TriplePane>>> onRemovalRequestedProperty() {
442 return onRemovalRequested;
443 }
444
445
446
447
448
449 public final void setOnRemovalRequested(final EventHandler<ObjectRelatedActionEvent<TriplePane>> handler) {
450 onRemovalRequested.set(handler);
451 }
452
453
454
455
456
457 public final EventHandler<ObjectRelatedActionEvent<TriplePane>> getOnRemovalRequested() {
458 return onRemovalRequested.get();
459 }
460
461
462
463
464 @FXML
465 private void moveUpButtonOnAction(final ActionEvent event) {
466 if (siblings == null) {
467 return;
468 }
469 final int currentPosition = siblings.indexOf(this);
470 if (currentPosition > 0) {
471 siblings.remove(currentPosition);
472 siblings.add(currentPosition - 1, this);
473 }
474 }
475
476
477
478
479 @FXML
480 private void moveDownButtonOnAction(final ActionEvent event) {
481 if (siblings == null) {
482 return;
483 }
484 final int currentPosition = siblings.indexOf(this);
485 if ((currentPosition > -1) && (currentPosition < (siblings.size() - 1))) {
486 siblings.remove(currentPosition);
487 siblings.add(currentPosition + 1, this);
488 }
489 }
490
491
492
493
494 private void onPanePositionChanged(final Change<? extends Node> change) {
495 final ObservableList<? extends Node> list = change.getList();
496 final int index = list.indexOf(this);
497 if (index >= 0) {
498 moveUpButton.setDisable(index == 0);
499 moveDownButton.setDisable((index + 1) >= list.size());
500 }
501 }
502
503
504
505
506 @Override
507 public final String getQueryPart() {
508 final StringBuilder sb = new StringBuilder();
509
510 if (getParentTriplePane() == null) {
511 sb.append(subjectField.getValue());
512 sb.append(' ');
513 }
514
515 sb.append(propertyField.getValue());
516 sb.append(' ');
517
518 sb.append(objectField.getValue());
519 sb.append(' ');
520
521 if (objectField.getFieldType() == FieldType.Literal) {
522 switch (literalTypeProperty.get()) {
523 case Typed:
524 final String dataType = objectDataTypeComboBox.getValue();
525 if ((dataType != null) && !dataType.isEmpty()) {
526 sb.append(literalTypeMenuButton.getText());
527 sb.append(dataType);
528 }
529 break;
530
531 case LocalizedString:
532 final String lang = langTextField.getText().trim();
533 if (!lang.isEmpty()) {
534 sb.append(literalTypeMenuButton.getText());
535 sb.append(lang);
536 }
537 break;
538
539 default:
540 break;
541 }
542
543 }
544
545 sb.append(' ');
546
547 if (getParentTriplePane() != null) {
548 return sb.toString();
549 }
550
551
552 container.getChildren().stream().filter((node) -> (node instanceof TriplePane)).forEach((node) -> {
553 sb.append("; ");
554
555 String queryPart = ((TriplePane) node).getQueryPart();
556
557
558
559
560
561 sb.append(queryPart);
562
563 });
564
565 sb.append(". ");
566
567 return sb.toString();
568 }
569
570
571
572
573 @Override
574 public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
575 final HashSet<String> prefixes = new HashSet<>();
576 prefixes.addAll(subjectField.getPrefixesUsed(appendDelimiter));
577 prefixes.addAll(propertyField.getPrefixesUsed(appendDelimiter));
578 prefixes.addAll(objectField.getPrefixesUsed(appendDelimiter));
579
580 if ((objectField.getFieldType() == FieldType.Literal) && (literalTypeProperty.get() == LiteralType.Typed)) {
581 final String type = objectDataTypeComboBox.getValue();
582 if ((type != null) && !type.isEmpty()) {
583 final String prefix = extractPrefix(type);
584 if ((prefix != null) && !prefix.isEmpty()) {
585 prefixes.add(appendDelimiter ? prefix + Definitions.PREFIXED_NAME_PREFIX_DELIMITER : prefix);
586 }
587 }
588 }
589
590 container.getChildren().stream().filter((node) -> (node instanceof PrefixesUser)).forEach((node) -> prefixes.addAll(((PrefixesUser) node).getPrefixesUsed(false)));
591
592 return prefixes;
593 }
594
595
596
597
598 @Override
599 public final Set<String> getVariables() {
600 final Set<String> result = new HashSet<>();
601 result.addAll(subjectField.getVariables());
602 result.addAll(propertyField.getVariables());
603 result.addAll(objectField.getVariables());
604
605 container.getChildren().stream().filter((node) -> (node instanceof SimpleVariablesGenerator))
606 .forEach((node) -> result.addAll(((SimpleVariablesGenerator) node).getVariables()));
607 return result;
608 }
609
610 @Override
611 public final void onVariableAdded(final String variableName) {
612 notifyVariableAdded(variableName);
613 }
614
615 @Override
616 public final void onVariableRemoved(final String variableName) {
617 notifyVariableRemoved(variableName);
618 }
619
620 @Override
621 public final void notifyVariableRemoved(final String variableName) {
622 if (getVariables().contains(variableName)) {
623 return;
624 }
625 variablesCollectors.stream().forEach((collector) -> collector.onVariableRemoved(variableName));
626 }
627
628 @Override
629 public final void notifyVariableAdded(final String variableName) {
630 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(variableName));
631 }
632
633 @Override
634 public final void addVariablesCollector(final VariablesCollector collector) {
635 variablesCollectors.add(collector);
636 }
637
638 @Override
639 public final void removeVariablesCollector(final VariablesCollector collector) {
640 variablesCollectors.remove(collector);
641 }
642
643 @Override
644 public final void onVariableChanged(final String oldVariableName, final String newVariableName) {
645 notifyVariableChanged(oldVariableName, newVariableName);
646 }
647
648 @Override
649 public final void notifyVariableChanged(final String oldVariableName, final String newVariableName) {
650 if (getVariables().contains(oldVariableName)) {
651 variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(newVariableName));
652 } else {
653 variablesCollectors.stream().forEach((collector) -> collector.onVariableChanged(oldVariableName, newVariableName));
654 }
655 }
656
657 @Override
658 public final void requestFocus() {
659 if (getParentTriplePane() == null) {
660 subjectField.requestFocus();
661 } else {
662 propertyField.requestFocus();
663 }
664 }
665
666 @FXML
667 private void dataTypeComboBoxOnShowing() {
668 updateDataTypeComboBox();
669 }
670
671 public TriplePane getParentTriplePane() {
672 return parentTriplePaneProperty.get();
673 }
674
675 private Window getWindow() {
676 return parentQueryFormPane.getMainForm().getMainTabPane().getScene().getWindow();
677 }
678
679 private void saveDepth(int depth) {
680 this.parentQueryFormPane.getMainForm().setDepth(depth);
681 }
682
683
684
685
686
687
688 private int getDepth() {
689 int depth = 0;
690 while (depth < 1) {
691 try {
692 final PathDepthDialog pathDepthDialog = PathDepthDialog
693 .open(getWindow(), Messages.getString("PATH_DEPTH"),
694 Integer.toString(
695 this.parentQueryFormPane.getMainForm().getDepth()));
696
697 if (pathDepthDialog == null || pathDepthDialog.getResult() == null) {
698 return 0;
699 }
700 String depthString = pathDepthDialog.getResult();
701 prefferedlanguage = pathDepthDialog.getPreferredLanguage();
702
703 if (depthString.equals(Definitions.BLANK_NODE_PREFIX)) {
704 return depth;
705 }
706 final int obtainedNumber = Integer.parseInt(depthString);
707 if (obtainedNumber > depth) {
708 depth = obtainedNumber;
709 } else {
710 throw new NumberFormatException();
711 }
712 } catch (NumberFormatException e) {
713 MessageDialog.open(getWindow(), Messages.getString("WARNING"),
714 Messages.getString("INSERT_INTEGER"));
715 }
716 }
717 saveDepth(depth);
718
719 return depth;
720 }
721
722
723
724
725 @FXML
726 private void findPropertiesButtonOnAction() {
727 int obtainedDepth = getDepth();
728 if (obtainedDepth < 1) {
729 return;
730 }
731 final int depth = obtainedDepth + 1;
732
733 final SimpleBooleanProperty cancelled = new SimpleBooleanProperty(false);
734 final List<String> paths;
735 try {
736 paths = ProgressDialog.performTask(getWindow(), new Task<List<String>>() {
737 @Override
738 protected final List<String> call() throws Exception {
739 updateMessage(Messages.getString("SEARCHING_PATHS"));
740 List<RDFNode> modelNodes = getWantedGraphElement(cancelled);
741 if (modelNodes.isEmpty()) {
742 return null;
743 }
744 List<String> paths = new ArrayList<>();
745 modelNodes.stream().forEach((modelNode) -> paths.addAll(
746 getPaths(parentQueryFormPane.getDataAgent().getFullModel(), depth,
747 modelNode.asResource(), prefferedlanguage,
748 cancelled)));
749 if (cancelled.get() || paths.isEmpty()) {
750 return null;
751 }
752
753 Set<String> pathSet = new HashSet<>(paths);
754 paths.clear();
755 paths.addAll(pathSet);
756 return paths;
757 }
758
759 @Override
760 protected final void cancelled() {
761 cancelled.set(true);
762 }
763 });
764 } catch (InterruptedException | ExecutionException e) {
765 ErrorDialog
766 .open(getScene().getWindow(), Messages.getString("ERROR"), Messages.getString("OPERATION_FAILED"),
767 e);
768 LOG.log(Level.SEVERE, "Exception: ", e);
769 return;
770 }
771 if (cancelled.get()) {
772 return;
773 } else if (paths == null || paths.isEmpty()) {
774 MessageDialog.open(getWindow(), Messages.getString("WARNING"),
775 Messages.getString("NO_RESULTS_FOUND"));
776 return;
777 }
778
779 String selectedPath = PropertiesDialog.open(getWindow(), paths);
780 if (selectedPath != null) {
781 setSelectedPath(selectedPath);
782 }
783
784 findPropertiesButton.requestFocus();
785 }
786
787
788
789
790 private void setObjectFieldType(FieldType fieldType, String objectFieldText) {
791 objectField.setFieldType(fieldType);
792 objectField.setText(objectFieldText);
793 }
794
795
796
797
798
799
800
801 private void setSelectedPath(String selectedPath) {
802 Matcher m = FOUND_PATHS.matcher(selectedPath);
803 if (m.matches()) {
804 propertyField.setText(m.group(1));
805 String objectFieldText = m.group(2);
806 String firstCharOfObject = objectFieldText.substring(0, 1);
807 switch (firstCharOfObject) {
808 case Definitions.BLANK_NODE_PREFIX:
809 setObjectFieldType(FieldType.Variable, objectFieldText);
810 notifyVariableAdded(objectFieldText);
811 break;
812 case Definitions.QUOTATION_MARK:
813 m = OBJECT_LITERAL.matcher(objectFieldText);
814 if (m.matches()) {
815 setObjectFieldType(FieldType.Literal, m.group(1));
816 String notPlainStringMark = m.group(2);
817 String literalDescription = m.group(3);
818 if (notPlainStringMark != null && !notPlainStringMark.isEmpty()
819 && literalDescription != null && !literalDescription.isEmpty()) {
820 if (notPlainStringMark.equals(DATA_TYPE_PREFIX)) {
821 objectDataTypeComboBox.setValue(literalDescription);
822 setTypedLiteralType();
823 } else if (notPlainStringMark.equals(LANG_PREFIX)) {
824 langTextField.setText(literalDescription);
825 setLocalizedStringLiteralType();
826 }
827 } else {
828 setPlainStringLiteralType();
829 }
830 }
831 break;
832 default:
833 if (SparqlValidationUtils.isPrefixedNameValid(objectFieldText, true)) {
834 if (parentQueryFormPane.getQueryPrefixesStorage()
835 .getNsPrefixURI(objectFieldText.substring(0, objectFieldText
836 .indexOf(Definitions.PREFIXED_NAME_PREFIX_DELIMITER))) != null) {
837 setObjectFieldType(FieldType.PrefixedName, objectFieldText);
838 } else {
839 setObjectFieldType(FieldType.Literal, objectFieldText);
840 }
841 } else {
842 setObjectFieldType(FieldType.IRI,
843 parentQueryFormPane.getQueryPrefixesStorage().shortForm(objectFieldText));
844 }
845 break;
846 }
847 }
848 }
849
850
851
852
853
854
855
856
857
858 private List<RDFNode> getWantedGraphElement(SimpleBooleanProperty cancelled) {
859 final String subjectText = this.subjectField.getText();
860 final List<RDFNode> results = new ArrayList<>();
861 switch (this.subjectField.getFieldType()) {
862 case Variable:
863 case BlankNode:
864 String requiredVariable = Definitions.VARIABLE_PREFIX + this.subjectField.getText();
865 results.addAll(getVariableNode(createQuery(requiredVariable), requiredVariable, cancelled));
866 break;
867 case PrefixedName:
868 results.add(parentQueryFormPane.getDataAgent().getFullModel().getResource(
869 this.parentQueryFormPane.getQueryPrefixesStorage().expandPrefix(subjectText)));
870 break;
871 case IRI:
872 results.add(parentQueryFormPane.getDataAgent().getFullModel().getResource(subjectText));
873 break;
874 default:
875 LOG.info(this.getClass().getCanonicalName() + ": Unknown field type");
876 break;
877 }
878 return results;
879 }
880
881
882
883
884
885
886
887
888
889
890
891 private List<RDFNode> getVariableNode(String query, String requiredVariable,
892 final ObservableBooleanValue cancelled) {
893 final List<RDFNode> results = new ArrayList<>();
894 final CancellableConsumer<QuerySolution> consumer = new CancellableConsumer<QuerySolution>() {
895 @Override
896 public void accept(final QuerySolution qs) {
897 if (qs.contains(requiredVariable)) {
898 results.add(qs.get(requiredVariable));
899 }
900 }
901 };
902 final ChangeListener<Boolean> cancellationListener = (observable, oldValue, newValue) -> {
903 if (newValue) {
904 consumer.cancel();
905 }
906 };
907
908 cancelled.addListener(cancellationListener);
909 parentQueryFormPane.getDataAgent().select(query, consumer);
910 cancelled.removeListener(cancellationListener);
911 return results;
912 }
913
914
915
916
917
918
919
920
921 private String createQuery(final String requiredVariable) {
922 final String currentTriplePane = this.getQueryPart();
923 final String groupGraphPatternPanePart
924 = getGroupGraphPattPaneFromQuery(parentQueryFormPane.getQuery(), currentTriplePane);
925 int indexOfTriplePane = groupGraphPatternPanePart.indexOf(currentTriplePane);
926 String firstPartOfWhereClause = groupGraphPatternPanePart.substring(0, indexOfTriplePane).trim();
927 if (firstPartOfWhereClause.endsWith(";")) {
928 firstPartOfWhereClause
929 = firstPartOfWhereClause.substring(0, firstPartOfWhereClause.length() - 1) + ".";
930 }
931
932 final StringBuilder sb = new StringBuilder(" SELECT ");
933 sb.append(requiredVariable).append(" WHERE ").append(firstPartOfWhereClause)
934 .append(requiredVariable).
935 append(Definitions.SPACE).append(Definitions.VARIABLE_PREFIX)
936 .append(getRandomString(RANDOM_VARIABLE_LENGTH)).
937 append(" ?").append(getRandomString(RANDOM_VARIABLE_LENGTH)).
938 append(
939 groupGraphPatternPanePart.substring(indexOfTriplePane + currentTriplePane.length()));
940
941 sb.insert(0, getUsedQueryPrefixes(parentQueryFormPane.getQueryPrefixesStorage().getNsPrefixMap(), sb.toString()));
942 return sb.toString();
943 }
944
945
946
947
948
949
950
951
952
953
954
955
956
957 private List<String> getPaths(final Model model, final int depth, final Resource rootNode,
958 String selectedLanguage, final SimpleBooleanProperty cancelled) {
959
960 final List<String> results = new ArrayList<>();
961 final Map<Resource, String> predicates
962 = new HashMap<>();
963 final Queue<List<Resource>> queue = new LinkedList<>();
964 final List<Resource> rootNodePath = new LinkedList<>();
965 final List<RDFNode> visitedNodes = new LinkedList<>();
966 final int allowedPathDepth = depth - 1;
967
968 visitedNodes.add(rootNode);
969 predicates.put(rootNode, Definitions.EMPTY_STRING);
970 rootNodePath.add(rootNode);
971 queue.add(rootNodePath);
972
973 while (!queue.isEmpty() && !cancelled.get()) {
974 List<Resource> pathNodes = queue.poll();
975
976 if (pathNodes != null && pathNodes.size() < depth) {
977 Resource lastPathNode = pathNodes.get(pathNodes.size() - 1);
978 StmtIterator stmtIterator = model.listStatements(lastPathNode, null, (RDFNode) null);
979
980 while (stmtIterator.hasNext()) {
981 final Statement stmtValue = stmtIterator.next();
982 final RDFNode objectOfStmtValue = stmtValue.getObject();
983
984 if (!visitedNodes.contains(objectOfStmtValue)) {
985 visitedNodes.add(objectOfStmtValue);
986 final String prefixedNameOfChild
987 = parentQueryFormPane.getQueryPrefixesStorage()
988 .shortForm(stmtValue.getPredicate().getURI());
989 searchAndAddPath(results, allowedPathDepth, pathNodes, predicates, prefixedNameOfChild,
990 objectOfStmtValue, selectedLanguage);
991 if (objectOfStmtValue.isResource()) {
992 final Resource stmtObjectResource = objectOfStmtValue.asResource();
993 final List<Resource> foundNodePath = new ArrayList<>(pathNodes);
994 foundNodePath.add(stmtObjectResource);
995 queue.add(foundNodePath);
996 predicates.put(stmtObjectResource, prefixedNameOfChild);
997 }
998 }
999 }
1000 }
1001 }
1002 return results;
1003 }
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 private void searchAndAddPath(final List<String> recordsToView, final int allowedPathDepth,
1018 final List<Resource> pathNodes, final Map<Resource, String> predicates,
1019 final String lastPrefixedName, final RDFNode objectOfStmtValue,
1020 final String selectedLanguage) {
1021
1022 final StringBuilder sb = new StringBuilder();
1023 int slashCount = 0;
1024
1025 slashCount
1026 = pathNodes.stream().map(predicates::get).filter((edge) -> (edge.length() > 0))
1027 .map((edge) -> {
1028 sb.append(edge).append("/");
1029 return edge;
1030 }).map((_item) -> 1).reduce(slashCount, Integer::sum);
1031
1032 if (slashCount < allowedPathDepth) {
1033 sb.append(lastPrefixedName).append(" -- ");
1034 if (objectOfStmtValue.isLiteral()) {
1035 Literal literal = objectOfStmtValue.asLiteral();
1036 String literalType
1037 = getLiteralType(this.parentQueryFormPane.getQueryPrefixesStorage(), literal,
1038 selectedLanguage);
1039 if (literalType != null) {
1040 sb.append(Definitions.QUOTATION_MARK).append(literal.getString()).append(Definitions.QUOTATION_MARK)
1041 .append(literalType);
1042 } else {
1043 return;
1044 }
1045 } else if (objectOfStmtValue.isAnon()) {
1046 sb.append(Messages.getString("_BLANK")).append(getRandomString(BLANK_NODE_LENGTH));
1047 } else if (objectOfStmtValue.isURIResource()) {
1048 sb.append(parentQueryFormPane.getQueryPrefixesStorage().shortForm(objectOfStmtValue.toString()));
1049 }
1050 recordsToView.add(sb.toString());
1051 }
1052 }
1053
1054
1055
1056
1057 @FXML
1058 private void findPathButtonOnAction() {
1059
1060 String endPropertyIRI = null;
1061 if (propertyField.getFieldType() == FieldType.PrefixedName) {
1062 final String fieldContent = propertyField.getText();
1063 final Set<String> prefixes = propertyField.getPrefixesUsed(false);
1064 if (!prefixes.isEmpty()) {
1065 final String prefix = prefixes.iterator().next();
1066 endPropertyIRI = parentQueryFormPane.getQueryPrefixesStorage().getPrefixToIri().get(prefix);
1067 }
1068 if (endPropertyIRI == null) {
1069 ErrorDialog.open(getScene().getWindow(), Messages.getString("ERROR"),
1070 Messages.getString("PROPERTY_PREFIX_CANNOT_BE_RESOLVED"));
1071 propertyField.requestFocus();
1072 return;
1073 }
1074 final String localName
1075 = fieldContent.substring(fieldContent.indexOf(Definitions.PREFIXED_NAME_PREFIX_DELIMITER) + 1);
1076 endPropertyIRI += localName;
1077 }
1078
1079
1080
1081
1082
1083
1084
1085 final Set<Resource> startResources;
1086 try {
1087 startResources = ProgressDialog.performTask(getScene().getWindow(), new Task<Set<Resource>>() {
1088 @Override
1089 protected final Set<Resource> call() throws Exception {
1090
1091
1092 updateMessage(Messages.getString("RETRIEVING_PATH_START_ELEMENTS"));
1093 return identifyVariable(subjectField.getText().trim(), 0, 0, null, true);
1094 }
1095 });
1096 } catch (InterruptedException | ExecutionException e) {
1097 ErrorDialog
1098 .open(getScene().getWindow(), Messages.getString("ERROR"), Messages.getString("OPERATION_FAILED"),
1099 e);
1100 LOG.log(Level.SEVERE, "Exception: ", e);
1101 return;
1102 }
1103
1104
1105 if (startResources == null) {
1106 return;
1107 }
1108
1109 if (startResources.isEmpty()) {
1110 MessageDialog.open(getScene().getWindow(), Messages.getString("SORRY"),
1111 Messages.getString("NO_PATH_START_ELEMENTS_AVAILIBLE"));
1112 return;
1113 }
1114
1115
1116 final LinkedList<Resource> path = PathsDialog
1117 .open(getScene().getWindow(), parentQueryFormPane.getDataAgent(),
1118 parentQueryFormPane.getQueryPrefixesStorage(),
1119 startResources, ResourceFactory.createProperty(endPropertyIRI));
1120 if (path == null) {
1121 return;
1122 }
1123
1124 final FieldType objectFieldType = objectField.getFieldType();
1125 final String objectContent = objectField.getText();
1126
1127
1128 path.removeFirst();
1129
1130
1131 final Iterator<Resource> i = path.iterator();
1132 TriplePane currentTriple = this;
1133 while (i.hasNext()) {
1134 final Resource node = i.next();
1135 if (node instanceof Property) {
1136 if (node.isAnon()) {
1137 final String varName
1138 = parentQueryFormPane
1139 .generateNewVariableName(Messages.getString("_BLANK"), null);
1140 notifyVariableAdded(varName);
1141 currentTriple.propertyField.setFieldType(FieldType.Variable);
1142 currentTriple.propertyField.setText(varName);
1143 } else {
1144 final String nodeID = node.toString();
1145 final String prefixedName = parentQueryFormPane.getQueryPrefixesStorage().shortForm(nodeID);
1146 currentTriple.propertyField
1147 .setFieldType(nodeID.equals(prefixedName) ? FieldType.IRI : FieldType.PrefixedName);
1148 currentTriple.propertyField.setText(prefixedName);
1149 }
1150 continue;
1151 }
1152
1153 final String varName
1154 = parentQueryFormPane.generateNewVariableName(Messages.getString("_PATH"), null);
1155
1156
1157
1158
1159
1160
1161 notifyVariableAdded(varName);
1162
1163 currentTriple.objectField.setFieldType(FieldType.Variable);
1164 currentTriple.objectField.setText(varName);
1165
1166 currentTriple = parentGroupGraphPatternPane.addTriple(currentTriple, true);
1167 currentTriple.subjectField.setFieldType(FieldType.Variable);
1168 currentTriple.subjectField.setText(varName);
1169 }
1170
1171 currentTriple.objectField.setText(objectContent);
1172 currentTriple.objectField.setFieldType(objectFieldType);
1173
1174 findPathButton.requestFocus();
1175 }
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190 @SuppressWarnings("SameParameterValue")
1191 private Set<Resource> identifyVariable(final String variableName, final int limit, final int offset, String orderBy,
1192 final boolean identifyTypes) {
1193
1194
1195 GroupGraphPatternPane topParentPane = parentGroupGraphPatternPane;
1196 GroupGraphPatternPane _topParentPane;
1197 while ((_topParentPane = topParentPane.getParentGroupGraphPatternPane()) != null) {
1198 topParentPane = _topParentPane;
1199 }
1200
1201 final StringBuilder sb = new StringBuilder();
1202 final Set<String> prefixes = new HashSet<>();
1203 final Set<String> constraints = new HashSet<>();
1204 final Set<String> dependingVariables = new HashSet<>();
1205
1206
1207 topParentPane.fillInVariableConstraints(variableName, this, prefixes, constraints, dependingVariables);
1208
1209
1210 prefixes.stream().forEach((prefix) -> {
1211 final String iri = parentQueryFormPane.getQueryPrefixesStorage().getPrefixToIri().get(prefix);
1212 QueryFormPane.appendPrologue(sb, prefix, iri);
1213 });
1214
1215 sb.append("SELECT DISTINCT ");
1216 sb.append(Definitions.VARIABLE_PREFIX);
1217
1218 final String classOfVariableName = "classOf_" + variableName;
1219 final String subClassOfVariableName = "subClassOf_" + variableName;
1220
1221 if (identifyTypes) {
1222 sb.append(classOfVariableName);
1223 sb.append(" WHERE { ");
1224 constraints.stream().forEach(sb::append);
1225
1226
1227 sb.append(Definitions.VARIABLE_PREFIX);
1228 sb.append(variableName);
1229 sb.append(" a ");
1230 sb.append(Definitions.VARIABLE_PREFIX);
1231 sb.append(classOfVariableName);
1232 sb.append(" . OPTIONAL { ");
1233 sb.append(Definitions.VARIABLE_PREFIX);
1234 sb.append(variableName);
1235 sb.append(" a ");
1236 sb.append(Definitions.VARIABLE_PREFIX);
1237 sb.append(subClassOfVariableName);
1238 sb.append(" . ");
1239 sb.append(Definitions.VARIABLE_PREFIX);
1240 sb.append(subClassOfVariableName);
1241 sb.append(' ');
1242 sb.append(Definitions.IRI_PREFIX);
1243 sb.append(RDFS.subClassOf.getURI());
1244 sb.append(Definitions.IRI_SUFFIX);
1245 sb.append(' ');
1246 sb.append(Definitions.VARIABLE_PREFIX);
1247 sb.append(classOfVariableName);
1248 sb.append(" . FILTER(");
1249 sb.append(Definitions.VARIABLE_PREFIX);
1250 sb.append(subClassOfVariableName);
1251 sb.append(" != ");
1252 sb.append(Definitions.VARIABLE_PREFIX);
1253 sb.append(classOfVariableName);
1254 sb.append(") . } FILTER(!bound(");
1255 sb.append(Definitions.VARIABLE_PREFIX);
1256 sb.append(subClassOfVariableName);
1257 sb.append(")) .");
1258
1259 sb.append("} ");
1260
1261 System.out.println(sb.toString());
1262 } else {
1263 sb.append(variableName);
1264 sb.append(" WHERE ");
1265 constraints.stream().forEach(sb::append);
1266 }
1267
1268 if (limit > 0) {
1269 sb.append("LIMIT ");
1270 sb.append(limit);
1271 sb.append(' ');
1272 }
1273
1274 if (offset > 0) {
1275 sb.append("OFFSET ");
1276 sb.append(offset);
1277 sb.append(' ');
1278 }
1279
1280 if (orderBy != null) {
1281 orderBy = orderBy.trim();
1282 if (!orderBy.isEmpty()) {
1283 sb.append("ORDER BY ");
1284 sb.append(orderBy);
1285 }
1286 }
1287
1288 final Set<Resource> result = new HashSet<>();
1289 final Query query = DataAgent.createQuery(sb.toString());
1290
1291 if (identifyTypes) {
1292
1293 result.addAll(DataHelper.extractVariableTypes(query, variableName));
1294 }
1295
1296 final String resultVariableName = identifyTypes ? classOfVariableName : variableName;
1297
1298
1299 parentQueryFormPane.getDataAgent().select(query, new CancellableConsumer<QuerySolution>() {
1300 @Override
1301 public final void accept(final QuerySolution t) {
1302 final RDFNode node = t.get(resultVariableName);
1303 if ((node != null) && (node.isResource())) {
1304 result.add(node.asResource());
1305 }
1306 }
1307 });
1308
1309 return result;
1310 }
1311
1312
1313
1314
1315 @Override
1316 public final void fillInVariableConstraints(final String variableName,
1317 final VariableConstraintsGenerator nodeToSkip, final Set<String> prefixes,
1318 final Set<String> constraints, final Set<String> dependingVariables) {
1319
1320
1321 final Set<String> variables = getVariables();
1322 if ((this == nodeToSkip) || !variables.contains(variableName)) {
1323 return;
1324 }
1325
1326 variables.remove(variableName);
1327 dependingVariables.addAll(variables);
1328 prefixes.addAll(getPrefixesUsed(false));
1329 constraints.add(getQueryPart());
1330 }
1331
1332
1333
1334
1335 @Override
1336 public final void save(final Element root) {
1337 final Document doc = root.getOwnerDocument();
1338
1339 if (parentTriplePaneProperty.get() == null) {
1340 final ObservableList<Node> subTriples = container.getChildren();
1341 if (!subTriples.isEmpty()) {
1342 final Element subTriplesElement = doc.createElement(XML_SUBTRIPLES_ELEMENT_NAME);
1343 root.appendChild(subTriplesElement);
1344 Saveable.defaultSave(subTriplesElement, subTriples);
1345 }
1346
1347 root.appendChild(saveField(doc, XML_SUBJECT_ELEMENT_NAME, subjectField, null, null));
1348 }
1349
1350 root.appendChild(saveField(doc, XML_PREDICATE_ELEMENT_NAME, propertyField, null, null));
1351 root.appendChild(saveField(doc, XML_OBJECT_ELEMENT_NAME, objectField, langTextField, objectDataTypeComboBox));
1352 }
1353
1354
1355
1356
1357
1358
1359 private void saveFull(final Element root) {
1360 save(root);
1361 if (parentTriplePaneProperty.get() != null) {
1362 final Document doc = root.getOwnerDocument();
1363 root.appendChild(saveField(doc, XML_SUBJECT_ELEMENT_NAME, subjectField, null, null));
1364 }
1365 }
1366
1367
1368
1369
1370 private Element saveField(final Document doc, final String tagName, final TypedTextField field,
1371 final TextField langTextField,
1372 final ComboBox<String> dataTypeComboBox) {
1373 final Element e = doc.createElement(tagName);
1374
1375 final FieldType fieldType = field.getFieldType();
1376 e.setAttribute(XML_FIELD_TYPE, fieldType.name().toLowerCase());
1377
1378 switch (fieldType) {
1379 case Literal:
1380 switch (literalTypeProperty.get()) {
1381 case LocalizedString:
1382 e.setAttribute(XML_LITERAL_LANG, langTextField.getText().trim());
1383 break;
1384 case Typed:
1385 e.setAttribute(XML_LITERAL_DATA_TYPE, dataTypeComboBox.getValue().trim());
1386 break;
1387 default:
1388 break;
1389 }
1390 case IRI:
1391 case Variable:
1392 case PrefixedName:
1393 case BlankNode:
1394 case A:
1395 e.setAttribute(XML_FIELD_TEXT, field.getText().trim());
1396 break;
1397 default:
1398 break;
1399 }
1400 return e;
1401 }
1402
1403
1404
1405
1406 @Override
1407 public final void load(final Object e) throws LoadException {
1408
1409 if (e instanceof Element) {
1410 final NodeList childNodes = ((Element) e).getChildNodes();
1411 final int childNodesCount = childNodes.getLength();
1412 boolean gotSubject = parentTriplePaneProperty.get() != null;
1413 boolean gotPredicate = false;
1414 boolean gotObject = false;
1415 boolean gotSubTriples = false;
1416 for (int index = 0; index < childNodesCount; index++) {
1417 final org.w3c.dom.Node node = childNodes.item(index);
1418 if (!(node instanceof Element)) {
1419 continue;
1420 }
1421 final Element childElement = (Element) node;
1422 final String tagName = childElement.getTagName();
1423 if (!gotSubject && tagName.equals(XML_SUBJECT_ELEMENT_NAME)) {
1424 SubjectField.loadSubjectField(this, childElement);
1425 gotSubject = true;
1426 } else if (!gotPredicate && tagName.equals(XML_PREDICATE_ELEMENT_NAME)) {
1427 PropertyField.loadPredicateField(this, childElement);
1428 gotPredicate = true;
1429 } else if (!gotObject && tagName.equals(XML_OBJECT_ELEMENT_NAME)) {
1430 ObjectField.loadObjectField(this, childElement);
1431 gotObject = true;
1432 } else if (!gotSubTriples && tagName.equals(XML_SUBTRIPLES_ELEMENT_NAME)) {
1433 loadSubTriples(childElement);
1434 gotSubTriples = true;
1435 }
1436 if (gotSubject && gotPredicate && gotObject) {
1437 break;
1438 }
1439 }
1440
1441 if (!gotSubject) {
1442 throw new LoadException(XML_SUBJECT_ELEMENT_NAME);
1443 }
1444 if (!gotPredicate) {
1445 throw new LoadException(XML_PREDICATE_ELEMENT_NAME);
1446 }
1447 if (!gotObject) {
1448 throw new LoadException(XML_OBJECT_ELEMENT_NAME);
1449 }
1450 } else if (e instanceof SparqlParserTriple) {
1451 SparqlParserTriple eNode = (SparqlParserTriple) e;
1452 SubjectField.loadSubjectField(this, eNode);
1453 PropertyField.loadPredicateField(this, eNode);
1454 ObjectField.loadObjectField(this, eNode);
1455 }
1456 }
1457
1458
1459
1460
1461 static FieldType loadFieldType(final Object e, final FieldType fieldTypeEElement,
1462 final FieldType... allowedFieldTypes) throws LoadException {
1463 FieldType fieldType = null;
1464 if (e instanceof Element) {
1465 Element eNode = (Element) e;
1466 final String fieldTypeString = eNode.getAttribute(XML_FIELD_TYPE);
1467 fieldType = FieldType.valueOfIgnoreCase(fieldTypeString);
1468 if ((fieldType == null) || !fieldType.oneOf(allowedFieldTypes)) {
1469 throw new LoadException(eNode, XML_FIELD_TYPE);
1470 }
1471 } else if (e instanceof SparqlParserTriple) {
1472 fieldType = fieldTypeEElement;
1473 if ((fieldType == null) || !fieldType.oneOf(allowedFieldTypes)) {
1474 throw new LoadException(FIELD_TYPE);
1475 }
1476 }
1477 return fieldType;
1478 }
1479
1480
1481
1482
1483 static void loadSimpleField(Object e, final TypedTextField field) throws LoadException {
1484 if (e instanceof Element) {
1485 Element eNode = (Element) e;
1486 final FieldType fieldType = loadFieldType(eNode, null, field.getAllowedFieldTypes());
1487 field.setFieldType(fieldType);
1488 if (fieldType != FieldType.A) {
1489 field.setText(eNode.getAttribute(XML_FIELD_TEXT));
1490 }
1491 } else if (e instanceof SparqlParserTriple) {
1492 SparqlParserTriple eNode = (SparqlParserTriple) e;
1493 FieldProperties fieldProperties = new FieldProperties(eNode, field);
1494 FieldType type = loadFieldType(eNode, fieldProperties.getElemeFieldType(), field.getAllowedFieldTypes());
1495 field.setFieldType(type);
1496 if (type != FieldType.A) {
1497 field.setText(fieldProperties.getElementValue());
1498 }
1499 }
1500 }
1501
1502
1503
1504
1505 private void loadSubTriples(final Element e) throws LoadException {
1506 final NodeList childNodes = e.getElementsByTagName(XML_SUBTRIPLE_ELEMENT_NAME);
1507 final int childNodesCount = childNodes.getLength();
1508 for (int index = 0; index < childNodesCount; index++) {
1509 final org.w3c.dom.Node node = childNodes.item(index);
1510 if (node instanceof Element) {
1511 addSubTriple(false).load(node);
1512 }
1513 }
1514 }
1515
1516
1517
1518
1519 @Override
1520 public final String getXMLElementName() {
1521 return parentTriplePaneProperty.get() == null ? XML_ELEMENT_NAME : XML_SUBTRIPLE_ELEMENT_NAME;
1522 }
1523
1524 @Override
1525 public final Set<InvalidationListener> getObservers() {
1526 return observers;
1527 }
1528
1529
1530
1531
1532 private String toXML()
1533 throws TransformerException, TransformerFactoryConfigurationError,
1534 ParserConfigurationException {
1535 final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
1536 final Element root = doc.createElement(XML_ELEMENT_NAME);
1537 doc.appendChild(root);
1538 saveFull(root);
1539 final StringWriter buffer = new StringWriter();
1540 final StreamResult result = new StreamResult(buffer);
1541 TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), result);
1542 return buffer.toString();
1543 }
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554 public void fromXML(final String xml)
1555 throws TransformerException, TransformerFactoryConfigurationError,
1556 ParserConfigurationException, LoadException {
1557 final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
1558 final StreamSource source = new StreamSource(new StringReader(xml));
1559 TransformerFactory.newInstance().newTransformer().transform(source, new DOMResult(doc));
1560 final NodeList nodes = doc.getElementsByTagName(XML_ELEMENT_NAME);
1561 if (nodes.getLength() > 0) {
1562 load(nodes.item(0));
1563 }
1564 }
1565
1566 public TypedTextField getSubjectField() {
1567 return subjectField;
1568 }
1569
1570 public TypedTextField getPropertyField() {
1571 return propertyField;
1572 }
1573
1574 public TypedTextField getObjectField() {
1575 return objectField;
1576 }
1577
1578 public QueryFormPane<?> getParentQueryFormPane() {
1579 return parentQueryFormPane;
1580 }
1581
1582 public VBox getContainer() {
1583 return container;
1584 }
1585
1586 public ObservableList<Node> getSiblings() {
1587 return siblings;
1588 }
1589
1590 public TriplePaneShortcuts getShortcuts() {
1591 return shortcuts;
1592 }
1593
1594 public AutoCompleteListHandler getVariablesAutoCompleteListHandler() {
1595 return variablesAutoCompleteListHandler;
1596 }
1597
1598 public AutoCompleteListHandler getPropertiesAutoCompleteListHandler() {
1599 return propertiesAutoCompleteListHandler;
1600 }
1601
1602 public AutoCompleteListHandler getResourcesAutoCompleteListHandler() {
1603 return resourcesAutoCompleteListHandler;
1604 }
1605
1606 public HBox getSubjectFieldContainer() {
1607 return subjectFieldContainer;
1608 }
1609
1610 public HBox getPropertyFieldContainer() {
1611 return propertyFieldContainer;
1612 }
1613
1614 public HBox getObjectFieldContainer() {
1615 return objectFieldContainer;
1616 }
1617
1618 public ComboBox<String> getObjectDataTypeComboBox() {
1619 return objectDataTypeComboBox;
1620 }
1621
1622 public ObjectProperty<LiteralType> getLiteralTypeProperty() {
1623 return literalTypeProperty;
1624 }
1625
1626 public TextField getLangTextField() {
1627 return langTextField;
1628 }
1629
1630 public MenuButton getLiteralTypeMenuButton() {
1631 return literalTypeMenuButton;
1632 }
1633
1634 public ReferenceKeeper getObjectFieldTypePropertyRefKeeper() {
1635 return objectFieldTypePropertyRefKeeper;
1636 }
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678 }