View Javadoc
1   /*
2    * Copyright 2013-2023 Medical Information Systems Research Group (https://medical.zcu.cz),
3    * Department of Computer Science and Engineering, University of West Bohemia.
4    * Address: Univerzitni 8, 306 14 Plzen, Czech Republic.
5    *
6    * This file is part of Sparkle project.
7    *
8    * Sparkle is free software: you can redistribute it and/or modify
9    * it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License.
11   *
12   * Sparkle is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with Sparkle. If not, see <http://www.gnu.org/licenses/>.
19   */
20  package cz.zcu.mre.sparkle.gui.query;
21  
22  import cz.zcu.mre.sparkle.Messages;
23  import cz.zcu.mre.sparkle.data.*;
24  import cz.zcu.mre.sparkle.data.AbstractTermsStorage.StorageChangeListener;
25  import cz.zcu.mre.sparkle.data.resourceStorage.ResourcesStorage;
26  import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
27  import static cz.zcu.mre.sparkle.gui.query.QueryFormPane.QUERY_PARTS.*;
28  import cz.zcu.mre.sparkle.gui.query.autoComplete.AutoCompleteListHandler;
29  import cz.zcu.mre.sparkle.gui.query.autoComplete.ExpressionAutoCompleteListHandler;
30  import cz.zcu.mre.sparkle.gui.query.autoComplete.VariablesAutoCompleteListHandler;
31  import cz.zcu.mre.sparkle.gui.query.helpers.*;
32  import cz.zcu.mre.sparkle.gui.query.modifiers.GroupGraphPatternPane;
33  import cz.zcu.mre.sparkle.gui.query.modifiers.LimitOffsetClausePane;
34  import cz.zcu.mre.sparkle.gui.query.modifiers.OrderByClausePane;
35  import cz.zcu.mre.sparkle.gui.query.modifiers.ValuesClausePane;
36  import cz.zcu.mre.sparkle.gui.query.modifiers.groupBy.GroupByClausePane;
37  import cz.zcu.mre.sparkle.gui.query.modifiers.having.HavingClausePane;
38  import cz.zcu.mre.sparkle.gui.query.queryMainParts.FromClausePane;
39  import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
40  import cz.zcu.mre.sparkle.gui.query.queryTypes.ask.AskQueryFormPane;
41  import cz.zcu.mre.sparkle.gui.query.queryTypes.construct.ConstructQueryFormPane;
42  import cz.zcu.mre.sparkle.gui.query.queryTypes.describe.DescribeQueryFormPane;
43  import cz.zcu.mre.sparkle.gui.query.queryTypes.select.SelectQueryFormPane;
44  import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
45  import cz.zcu.mre.sparkle.gui.tools.Components;
46  import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
47  import cz.zcu.mre.sparkle.tools.*;
48  import java.io.File;
49  import java.io.IOException;
50  import java.io.Serializable;
51  import java.util.HashSet;
52  import java.util.List;
53  import java.util.Set;
54  import java.util.logging.Level;
55  import java.util.logging.Logger;
56  import javafx.beans.InvalidationListener;
57  import javafx.beans.property.BooleanProperty;
58  import javafx.beans.property.SimpleBooleanProperty;
59  import javafx.collections.FXCollections;
60  import javafx.collections.MapChangeListener.Change;
61  import javafx.collections.ObservableList;
62  import javafx.scene.control.ScrollPane;
63  import javafx.scene.layout.VBox;
64  import javafx.scene.paint.Color;
65  import javax.xml.parsers.ParserConfigurationException;
66  import javax.xml.transform.TransformerException;
67  import org.antlr.v4.runtime.ParserRuleContext;
68  import org.antlr.v4.runtime.misc.ParseCancellationException;
69  import org.antlr.v4.runtime.tree.ParseTree;
70  import org.antlr.v4.runtime.tree.ParseTreeWalker;
71  import org.w3c.dom.Element;
72  import org.w3c.dom.NodeList;
73  
74  /**
75   * Abstraktní třída sloužící jako základ pro kontrolery komponent
76   * představujících jednotlivé dotazy
77   * ({@link AskQueryFormPane}, {@link ConstructQueryFormPane}, {@link DescribeQueryFormPane}
78   * a {@link SelectQueryFormPane}).
79   *
80   * @param <QueryResultType> Typ výsledku dotazu.
81   *
82   * @author Jan Smucr
83   * @author Klara Hlavacova
84   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
85   */
86  public abstract class QueryFormPane<QueryResultType>
87          extends VBox
88          implements PartialQueryGenerator, PrefixesUser, VariablesGenerator, Changeable, Saveable {
89  
90      private final Set<InvalidationListener> observers = new HashSet<>();
91  
92      public static final String XML_ELEMENT_NAME = "Sparkle"; //$NON-NLS-1$
93      public static final String XML_QUERY_TYPE = "type"; //$NON-NLS-1$
94      public static final String XML_TAB_COLOR = "tabColor"; //$NON-NLS-1$
95  
96      public enum QUERY_PARTS {
97          FIRST_CLAUSE, FROM_CLAUSE, WHERE_CLAUSE, ORDER_BY_CLAUSE, GROUP_BY_CLAUSE, HAVING_CLAUSE,
98          LIMIT_OFFSET_CLAUSE, VALUES_CLAUSE
99          //FIRST_CLAUSE - ASK, SELECT, CONSTRUCT, DESCRIBE
100     }
101 
102     private final Storage localStorage;
103     private final String paneType;
104 
105     private PrefixesStorage queryPrefixesStorage;
106     private FunctionsStorage queryFunctionsStorage;
107     private DataTypesStorage queryDataTypesStorage;
108     private ResourcesStorage queryResourcesStorage;
109 
110     private final ObservableList<String> variables = FXCollections.observableArrayList();
111     private final ObservableList<String> sortedVariables = variables.sorted(String.CASE_INSENSITIVE_ORDER);
112     private final Set<VariablesCollector> variablesCollectors = new HashSet<>();
113 
114     private final ReferenceKeeper keeper = new ReferenceKeeper();
115     private final Set<String> addedLocalPrefixes = new HashSet<>();
116 
117     private DataAgent dataAgent;
118 
119     private MainForm mainForm;
120     private final BooleanProperty deleteProperty = new SimpleBooleanProperty(false);
121     private static Color obtainedColor = null;
122 
123     private ScrollPane scrollPane;
124 
125     /**
126      * Výchozí handler pro seznam návrhů k poli pro zadávání výrazu.
127      */
128     public final AutoCompleteListHandler DEFAULT_EXPRESSION_AUTOCOMPLETE_LIST_HANDLER
129             = new ExpressionAutoCompleteListHandler(this);
130     /**
131      * Výchozí handler pro seznam návrhů k poli pro zadávání názvu proměnné.
132      */
133     public final AutoCompleteListHandler DEFAULT_VARIABLES_AUTOCOMPLETE_LIST_HANDLER
134             = new VariablesAutoCompleteListHandler(this);
135 
136     /**
137      * @param mainForm hlavni formular
138      * @param dataAgent rozhrani mezi ulozistem a aplikaci
139      * @param localStorage prepravka pro lokalni mapovani prefixu; seznam
140      * ostatních pojmu;
141      * @param paneType typ dotazu
142      */
143     public QueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
144             String paneType) {
145         this.localStorage = localStorage;
146         this.paneType = paneType;
147 
148         init(mainForm, dataAgent, localStorage);
149         try {
150             // Vytvoření nového dotazu
151             load(null);
152         } catch (final LoadException e) {
153             // Toto se nemůže stát
154         }
155         setupWatches();
156     }
157 
158     /**
159      * @param mainForm hlavni formular
160      * @param dataAgent rozhrani mezi ulozistem a aplikaci
161      * @param localStorage prepravka pro lokalni mapovani prefixu; seznam
162      * ostatních pojmu; seznam datovych typu; seznam funkci
163      * @param root rodicovksky uzel (element)
164      *
165      * @param paneType typ dotazu
166      * @throws LoadException
167      */
168     protected QueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
169             final Object root, String paneType)
170             throws LoadException {
171 
172         this.localStorage = localStorage;
173         this.paneType = paneType;
174         init(mainForm, dataAgent, localStorage);
175 
176         if (root instanceof Element) {
177             // Načtení uloženého dotazu
178             Element rootNode = (Element) root;
179             loadStorages(rootNode);
180             load(rootNode);
181 
182         } else if (root instanceof ParserRuleContext) {
183             ParserRuleContext prContext = (ParserRuleContext) root;
184             loadPrefixes(prContext);
185             load(prContext);
186         }
187         setupWatches();
188     }
189 
190     /**
191      * Inicializace panelu
192      *
193      * @param mainForm hlavni formular
194      * @param dataAgent rozhrani mezi ulozistem a aplikaci
195      * @param localStorage prepravka pro lokalni mapovani prefixu; seznam
196      * ostatních pojmu; seznam datovych typu; seznam funkci
197      */
198     private void init(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage) {
199 
200         Components.load(this);
201         this.mainForm = mainForm;
202         this.dataAgent = dataAgent;
203 
204         queryPrefixesStorage = new PrefixesStorage();
205         setupPrefixesStorage(localStorage.getPrefixesStorage());
206 
207         queryResourcesStorage = new ResourcesStorage(dataAgent, queryPrefixesStorage);
208         setupTermsStorage(localStorage.getResourcesStorage(), queryResourcesStorage);
209 
210         queryDataTypesStorage = new DataTypesStorage(dataAgent, queryPrefixesStorage);
211         setupTermsStorage(localStorage.getDataTypesStorage(), queryDataTypesStorage);
212 
213         queryFunctionsStorage = new FunctionsStorage(dataAgent, queryPrefixesStorage);
214         setupTermsStorage(localStorage.getFunctionsStorage(), queryFunctionsStorage);
215 
216         addVariablesCollector(new VariablesCollector() {
217             @Override
218             public final void onVariableRemoved(final String variableName) {
219                 variables.remove(variableName);
220             }
221 
222             @Override
223             public final void onVariableChanged(final String oldVariableName, final String newVariableName) {
224                 variables.set(variables.indexOf(oldVariableName), newVariableName);
225             }
226 
227             @Override
228             public final void onVariableAdded(final String variableName) {
229                 variables.add(variableName);
230             }
231         });
232 
233         scrollPane = new ScrollPane(this);
234         scrollPane.setFitToWidth(true);
235         scrollPane.setPannable(true);
236 
237     }
238 
239     /**
240      * Nastaví synchronizaci mezi lokálním seznamem pojmů a seznamem pojmů
241      * vázaným na dotaz.
242      *
243      * @param localStorage Místní seznam pojmů (platný pro app)
244      * @param queryStorage Seznam pojmů vázaný na dotaz.
245      */
246     private <StorageEntryType extends Serializable> void setupTermsStorage(
247             final AbstractTermsStorage<StorageEntryType> localStorage,
248             final AbstractTermsStorage<StorageEntryType> queryStorage) {
249 
250         final Set<StorageEntryType> termsToAdd = localStorage.getAllTerms();
251         termsToAdd.removeAll(queryStorage.getAllTerms());
252 
253         queryStorage.addFrom(localStorage);
254         //TODO: pridani noveho termu, pokud jiz existuje
255 
256         localStorage.addListener(keeper.toWeak(new StorageChangeListener<StorageEntryType>() {
257             private final Set<StorageEntryType> addedLocalTerms = new HashSet<>(termsToAdd);
258 
259             @Override
260             public final void changed(final StorageEntryType term, final boolean added) {
261                 if (added && addedLocalTerms.add(term)) {
262                     queryStorage.addTerm(term);
263                     return;
264                 }
265                 if (!added && addedLocalTerms.remove(term)) {
266                     queryStorage.removeTerm(term);
267                 }
268             }
269         }));
270     }
271 
272     /**
273      * Nastaví synchronizaci mezi lokálním mapováním prefixů a mapováním vázaným
274      * na dotaz.
275      *
276      * @param localPrefixesStorage Místní mapování.
277      */
278     private void setupPrefixesStorage(final PrefixesStorage localPrefixesStorage) {
279         final Set<String> prefixesToAdd = localPrefixesStorage.getPrefixesUsed(false);
280         prefixesToAdd.removeAll(queryPrefixesStorage.getPrefixesUsed(false));
281         addedLocalPrefixes.addAll(prefixesToAdd);
282 
283         queryPrefixesStorage.add(localPrefixesStorage);
284 
285         localPrefixesStorage
286                 .getPrefixToIri()
287                 .addListener(keeper.toWeak((final Change<? extends String, ? extends String> change) -> {
288 
289                     final boolean changed = change.wasRemoved() && change.wasAdded();
290                     final boolean canChange = addedLocalPrefixes.contains(change.getKey());
291 
292                     if (change.wasRemoved() && addedLocalPrefixes.remove(change.getKey())
293                             && !getPrefixesUsed(false).contains(change.getKey())) {
294 
295                         queryPrefixesStorage.removeNsPrefix(change.getKey());
296                     }
297                     if (!changed || canChange) {
298                         if (!canChange && queryPrefixesStorage.getPrefixToIri().containsKey(change.getKey())) {
299                             return;
300                         }
301                         if (change.wasAdded() && addedLocalPrefixes.add(change.getKey())) {
302                             String altIri = localPrefixesStorage.getIriToAlternativeIri().get(change.getValueAdded());
303                             queryPrefixesStorage.setNsPrefix(change.getKey(), change.getValueAdded(), altIri);
304                         }
305                     }
306                 }));
307 
308         queryPrefixesStorage.getPrefixToIri()
309                 .addListener(keeper.toWeak((final Change<? extends String, ? extends String> change) -> {
310 
311                     if (change.wasRemoved()) {
312                         addedLocalPrefixes.remove(change.getKey());
313                     }
314                 }));
315     }
316 
317     /**
318      * Sledování změn v seznamech. Změna v seznamu = změna dotazu.
319      */
320     private void setupWatches() {
321         watch(queryResourcesStorage);
322         watch(queryDataTypesStorage);
323         watch(queryFunctionsStorage);
324         watch(queryPrefixesStorage);
325         watch(dataAgent);
326     }
327 
328     /**
329      * Tento magicky vypadající kus kódu ve skutečnosti pouze vytváří
330      * posluchače, který reaguje na upozornění o manipulaci s proměnnými.
331      * Udržuje jednu sadu proměnných a porovnává ji s ostatními. Typickým
332      * případem využití je situace, kdy klauzule SELECT ohlásí odstranění
333      * proměnné. Posluchač se pak podívá, zda proměnná existuje ještě někde
334      * jinde (např. ve WHERE a v ORDER BY) a globálně ohlásí odstranění proměnné
335      * až pokud zjistí, že šlo o její poslední výskyt.
336      *
337      * @param relatedVariablesSet Sada proměnných, ke které se posluchač
338      * vztahuje.
339      * @param otherVariablesSets Sady proměnných, které je třeba kontrolovat.
340      *
341      * @return Posluchač.
342      */
343     @SafeVarargs
344     protected final VariablesCollector createCollector(final Set<String> relatedVariablesSet,
345             final Set<String>... otherVariablesSets) {
346         return new VariablesCollector() {
347             @Override
348             public void onVariableRemoved(final String variableName) {
349                 if (relatedVariablesSet.remove(variableName) && !someSetContains(variableName, otherVariablesSets)) {
350                     notifyVariableRemoved(variableName);
351                 }
352             }
353 
354             @Override
355             public void onVariableChanged(final String oldVariableName, final String newVariableName) {
356                 relatedVariablesSet.remove(oldVariableName);
357                 final boolean added = relatedVariablesSet.add(newVariableName);
358 
359                 if (someSetContains(oldVariableName, otherVariablesSets)) {
360                     if (added && !someSetContains(newVariableName, otherVariablesSets)) {
361                         notifyVariableAdded(newVariableName);
362                     }
363                 } else if (added && !someSetContains(newVariableName, otherVariablesSets)) {
364                     notifyVariableChanged(oldVariableName, newVariableName);
365                 } else {
366                     notifyVariableRemoved(oldVariableName);
367                 }
368             }
369 
370             @Override
371             public void onVariableAdded(final String variableName) {
372                 if (relatedVariablesSet.add(variableName) && !someSetContains(variableName, otherVariablesSets)) {
373                     notifyVariableAdded(variableName);
374                 }
375             }
376         };
377     }
378 
379     /**
380      * Hledá výskyt objektu v nějaké z uvedených množin.
381      *
382      * @param item Objekt.
383      * @param sets Množiny.
384      *
385      * @return <code>true</code>, pokud byl nalezen.
386      */
387     @SafeVarargs
388     private static <E> boolean someSetContains(final E item, final Set<E>... sets) {
389         for (final Set<E> set : sets) {
390             if (set.contains(item)) {
391                 return true;
392             }
393         }
394         return false;
395     }
396 
397     @Override
398     public final Set<String> getVariables() {
399         final Set<String> vars = new HashSet<>();
400         getChildren().stream().filter((node) -> (node instanceof SimpleVariablesGenerator)).forEach((node) -> vars.addAll(((SimpleVariablesGenerator) node).getVariables()));
401 
402         return vars;
403     }
404 
405     @Override
406     public final void addVariablesCollector(final VariablesCollector collector) {
407         variablesCollectors.add(collector);
408     }
409 
410     @Override
411     public final void removeVariablesCollector(final VariablesCollector collector) {
412         variablesCollectors.remove(collector);
413     }
414 
415     @Override
416     public final void notifyVariableAdded(final String variableName) {
417         variablesCollectors.stream().forEach((collector) -> collector.onVariableAdded(variableName));
418     }
419 
420     @Override
421     public final void notifyVariableRemoved(final String variableName) {
422         variablesCollectors.stream().forEach((collector) -> collector.onVariableRemoved(variableName));
423     }
424 
425     @Override
426     public final void notifyVariableChanged(final String oldVariableName, final String newVariableName) {
427         variablesCollectors.stream().forEach((collector) -> collector.onVariableChanged(oldVariableName, newVariableName));
428     }
429 
430     /**
431      * Vygeneruje proměnnou, která se v dotazu ještě nevyskytuje.
432      *
433      * @param prefix Prefix.
434      * @param suffix Suffix.
435      *
436      * @return Unikátní název proměnné.
437      */
438     public final String generateNewVariableName(String prefix, String suffix) {
439         String varName;
440         if ((prefix == null) || prefix.trim().isEmpty()) {
441             prefix = Messages.getString("AUTO_VARIABLE_PREFIX"); //$NON-NLS-1$
442         }
443         if ((suffix == null) || suffix.trim().isEmpty()) {
444             suffix = ""; //$NON-NLS-1$
445         }
446 
447         int num = 0;
448         do {
449             num++;
450             varName = prefix + num + suffix;
451         } while (variables.contains(varName));
452 
453         return varName;
454     }
455 
456     /**
457      * @return Sestavený dotaz v podobě řetězce.
458      */
459     public final String getQuery() {
460         final StringBuilder queryBuilder = new StringBuilder();
461 
462         getPrefixesUsed(false).stream().forEach((prefix) -> {
463             final String iri = queryPrefixesStorage.getPrefixToIri().get(prefix);
464             appendPrologue(queryBuilder, prefix, iri);
465         });
466 
467         queryBuilder.append(getQueryPart());
468         return queryBuilder.toString();
469     }
470 
471     /**
472      * Pripoji k dotazu prologue
473      *
474      * @param queryBuilder StringBuilder
475      * @param prefix prefix
476      * @param iri iri
477      */
478     public static void appendPrologue(StringBuilder queryBuilder, String prefix, String iri) {
479         if (iri != null) {
480             queryBuilder.append("PREFIX "); //$NON-NLS-1$
481             queryBuilder.append(prefix);
482             queryBuilder.append(Definitions.PREFIXED_NAME_PREFIX_DELIMITER);
483             queryBuilder.append(' ');
484             queryBuilder.append(Definitions.IRI_PREFIX);
485             queryBuilder.append(iri);
486             queryBuilder.append(Definitions.IRI_SUFFIX);
487             queryBuilder.append('\n');
488         }
489     }
490 
491     /**
492      * Uloží dotaz do XML souboru.
493      *
494      * @param file Výstupní souboru.
495      *
496      * @throws ParserConfigurationException from DocumentBuilderFactory
497      * @throws TransformerException from TransfomerFactory
498      */
499     public final void save(final File file) throws ParserConfigurationException, TransformerException {
500         QueryFormPaneSave.save(file, this);
501     }
502 
503     /**
504      * Načte dotaz ze souboru.
505      *
506      * @param mainForm MainForm of Sparkle instance.
507      * @param dataAgent Připojení k úložišti.
508      * @param localStorage Lokální mapování prefixů; Lokální seznam ostatních
509      * pojmů; Lokální seznam datových typů; Lokální seznam funkcí.
510      * @param file Vstupní soubor.
511      *
512      * @return Instance {@link QueryFormPane}.
513      *
514      * @throws ParserConfigurationException from DocumentBuilderFactory
515      * @throws TransformerException from TransformerFactory
516      * @throws Saveable.LoadException on loading
517      * @throws java.io.IOException on loading
518      */
519     public static QueryFormPane<?> load(
520             final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
521             final File file)
522             throws ParserConfigurationException, TransformerException, Saveable.LoadException,
523             ParseCancellationException, IOException {
524 
525         return QueryFormPaneLoad.load(mainForm, dataAgent, localStorage, file);
526     }
527 
528     /**
529      * Načte dotaz dany retezcem
530      *
531      * @param mainForm MainForm of Sparkle instance.
532      * @param dataAgent Připojení k úložišti.
533      * @param localStorage Lokální mapování prefixů; Lokální seznam ostatních
534      * pojmů; Lokální seznam datových typů; Lokální seznam funkcí.
535      * @param queryString Retezec s dotazem
536      *
537      * @return Instance {@link QueryFormPane}.
538      *
539      * @throws ParserConfigurationException from DocumentBuilderFactory
540      * @throws TransformerException from TransformerFactory
541      * @throws Saveable.LoadException on loading
542      */
543     public static QueryFormPane<?> load(
544             final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
545             final String queryString)
546             throws ParserConfigurationException, TransformerException, Saveable.LoadException,
547             ParseCancellationException {
548 
549         return QueryFormPaneLoad.load(mainForm, dataAgent, localStorage, queryString);
550     }
551 
552     /**
553      * Obnoví stav libovolného {@link Saveable} z předaného XML elementu.
554      *
555      * @param root Kořenový element.
556      * @param element Obnovovaný objekt.
557      *
558      * @throws LoadException Chyba při načítání dat z XML souboru.
559      */
560     protected static void loadElement(final Element root, final Saveable element) throws LoadException {
561         final String tagName = element.getXMLElementName();
562 
563         /*final NodeList nodeList = root.getElementsByTagName(tagName);
564         if (nodeList.getLength() > 0) {
565             element.load((Element) nodeList.item(0));
566         } else {
567             throw new LoadException(tagName);
568         }*/
569         final NodeList nodeList = root.getChildNodes();
570         int nodesCount = nodeList.getLength();
571         if (nodesCount > 0) {
572             for (int nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) {
573 
574                 final org.w3c.dom.Node childNode = nodeList.item(nodeIndex);
575                 if (childNode instanceof Element) {
576                     Element child = (Element) childNode;
577                     if (child.getTagName().equalsIgnoreCase(tagName)) {
578                         element.load(child);
579                     }
580                 }
581             }
582         } else {
583             throw new LoadException(tagName);
584         }
585     }
586 
587     /**
588      * Nahraje casti formulare
589      *
590      * @param root rodicovsky element
591      * @param queryFormParts pole s panely
592      *
593      * @throws LoadException
594      */
595     protected void loadQueryPartsElements(Element root, List<Object> queryFormParts) throws LoadException {
596         loadElement(root, (FromClausePane) getPane(queryFormParts, FROM_CLAUSE));
597         loadElement(root, (WhereClausePane) getPane(queryFormParts, WHERE_CLAUSE));
598         loadElement(root, ((OrderByClausePane) getPane(queryFormParts, ORDER_BY_CLAUSE)));
599         loadElement(root, ((GroupByClausePane) getPane(queryFormParts, GROUP_BY_CLAUSE)));
600         loadElement(root, ((HavingClausePane) getPane(queryFormParts, HAVING_CLAUSE)));
601         loadElement(root, ((LimitOffsetClausePane) getPane(queryFormParts, LIMIT_OFFSET_CLAUSE)));
602         loadElement(root, ((ValuesClausePane) getPane(queryFormParts, VALUES_CLAUSE)));
603     }
604 
605     void saveStorages(final Element root) {
606         Saveable.defaultSave(root, queryPrefixesStorage, queryFunctionsStorage, queryDataTypesStorage, queryResourcesStorage);
607     }
608 
609     private void loadStorages(final Element root) throws LoadException {
610         loadElement(root, queryPrefixesStorage);
611         loadElement(root, queryFunctionsStorage);
612         loadElement(root, queryDataTypesStorage);
613         loadElement(root, queryResourcesStorage);
614     }
615 
616     public void loadPrefixes(final ParserRuleContext prContext) {
617         ParseTreeWalker.DEFAULT.walk(new SparqlParserBaseListener() {
618             @Override
619             public void enterPrefixDecl(SparqlParser.PrefixDeclContext ctx) {
620                 try {
621                     queryPrefixesStorage.load(ctx);
622                 } catch (LoadException ex) {
623                     Logger.getLogger(QueryFormPane.class.getName()).log(Level.SEVERE, null, ex);
624                 }
625             }
626         }, prContext);
627     }
628 
629     /**
630      * Vrati panel ze seznamu casti formulare
631      *
632      * @param queryFormParts seznam casti formulare
633      * @param paneType typ panelu
634      *
635      * @return panel ze seznamu casti formulare
636      */
637     protected Object getPane(List<Object> queryFormParts, QUERY_PARTS paneType) {
638         return queryFormParts.get(paneType.ordinal());
639     }
640 
641     /**
642      * It returns query variables.
643      *
644      * @return List of variables.
645      */
646     public ObservableList<String> getNetVariables() {
647         return this.sortedVariables;
648     }
649 
650     public BooleanProperty getDeleteProperty() {
651         return this.deleteProperty;
652     }
653 
654     public void setDeleteProperty() {
655         this.deleteProperty.set(true);
656     }
657 
658     public MainForm getMainForm() {
659         return this.mainForm;
660     }
661 
662     public static void setObtainedColor(String colorText) {
663         try {
664             obtainedColor = Color.web(colorText);
665         } catch (Exception e) {
666             obtainedColor = null;
667         }
668     }
669 
670     public Color getObtainedColor() {
671         return obtainedColor;
672     }
673 
674     public final DataAgent getDataAgent() {
675         return dataAgent;
676     }
677 
678     public final ResourcesStorage getQueryResourcesStorage() {
679         return queryResourcesStorage;
680     }
681 
682     public final DataTypesStorage getQueryDataTypesStorage() {
683         return queryDataTypesStorage;
684     }
685 
686     public final FunctionsStorage getQueryFunctionsStorage() {
687         return queryFunctionsStorage;
688     }
689 
690     public final PrefixesStorage getQueryPrefixesStorage() {
691         return queryPrefixesStorage;
692     }
693 
694     public final void setQueryPrefixesStorage(PrefixesStorage queryPrefixesStorage) {
695         this.queryPrefixesStorage = queryPrefixesStorage;
696     }
697 
698     /**
699      * It returns a relevant list of variables from whole query.
700      *
701      * @return Variable list.
702      */
703     public ObservableList<String> getSortedVariables() {
704         return this.getNetVariables();
705     }
706 
707     @Override
708     public String getXMLElementName() {
709         return XML_ELEMENT_NAME;
710     }
711 
712     protected abstract String getXMLQueryType();
713 
714     /**
715      * Method obtains all {@link SubSelectPane} in query.
716      *
717      * @return All {@link SubSelectPane} in {@link GroupGraphPatternPane}.
718      */
719     public abstract List<SubSelectPane> getSubSelectPanes();
720 
721     /**
722      * It loads all query variables to pane by DFS.
723      *
724      * @param root root node (enter node) of query.
725      *
726      * @throws cz.zcu.mre.sparkle.tools.Saveable.LoadException Error during
727      * query loading from file.
728      */
729     protected abstract void setVariables(ParseTree root) throws LoadException;
730 
731     public Storage getLocalStorage() {
732         return localStorage;
733     }
734 
735     public ScrollPane getScrollPane() {
736         return scrollPane;
737     }
738 
739     @Override
740     public final Set<InvalidationListener> getObservers() {
741         return observers;
742     }
743 
744     public String getPaneType() {
745         return paneType;
746     }
747 }