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.queryTypes.construct;
21  
22  import cz.zcu.mre.sparkle.Messages;
23  import cz.zcu.mre.sparkle.data.DataAgent;
24  import cz.zcu.mre.sparkle.data.Storage;
25  import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
26  import cz.zcu.mre.sparkle.gui.query.CustomTitledPane;
27  import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
28  import cz.zcu.mre.sparkle.gui.query.modifiers.LimitOffsetClausePane;
29  import cz.zcu.mre.sparkle.gui.query.modifiers.OrderByClausePane;
30  import cz.zcu.mre.sparkle.gui.query.modifiers.ValuesClausePane;
31  import cz.zcu.mre.sparkle.gui.query.modifiers.groupBy.GroupByClausePane;
32  import cz.zcu.mre.sparkle.gui.query.modifiers.having.HavingClausePane;
33  import cz.zcu.mre.sparkle.gui.query.queryMainParts.FromClausePane;
34  import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
35  import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
36  import cz.zcu.mre.sparkle.tools.Saveable;
37  import cz.zcu.mre.sparkle.tools.SparqlParser;
38  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserNode;
39  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserWhereClauseWalker;
40  import javafx.collections.FXCollections;
41  import javafx.collections.ObservableList;
42  import javafx.collections.ObservableSet;
43  import javafx.scene.Node;
44  import org.antlr.v4.runtime.tree.ParseTree;
45  import org.apache.jena.rdf.model.Model;
46  import org.w3c.dom.Element;
47  import java.util.*;
48  import static cz.zcu.mre.sparkle.gui.query.QueryFormPane.QUERY_PARTS.*;
49  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.getTreeChild;
50  
51  /**
52   * Kontroler panelu s dotazem typu CONSTRUCT.
53   *
54   * @author Jan Smucr
55   * @author Klara Hlavacova
56   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
57   */
58  public final class ConstructQueryFormPane
59          extends QueryFormPane<Model> {
60  
61      public static final String XML_QUERY_TYPE_VALUE = "construct"; //$NON-NLS-1$
62  
63      private List<Object> queryFormParts;
64  
65      private ObservableSet<String> constructClauseVariables;
66      private ObservableSet<String> whereClauseVariables;
67      private ObservableSet<String> orderByClauseVariables;
68      private ObservableSet<String> groupByClauseVariables;
69      private ObservableSet<String> valuesClauseVariables;
70  
71      public ConstructQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
72              String paneType) {
73          super(mainForm, dataAgent, localStorage, paneType);
74      }
75  
76      public ConstructQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
77              final Object root, String paneType)
78              throws LoadException {
79          super(mainForm, dataAgent, localStorage, root, paneType);
80      }
81  
82      @Override
83      public final void load(final Object root) throws LoadException {
84          constructClauseVariables = FXCollections.observableSet();
85          whereClauseVariables = FXCollections.observableSet();
86          orderByClauseVariables = FXCollections.observableSet();
87          groupByClauseVariables = FXCollections.observableSet();
88          valuesClauseVariables = FXCollections.observableSet();
89  
90          initializeQueryFormParts();
91          addVariablesCollectors();
92          addPartsTitles();
93  
94          loadForm(root);
95  
96          watch((((ConstructClausePane) getPane(FIRST_CLAUSE))));
97          addWatches();
98      }
99  
100     /**
101      * Nacte formular
102      *
103      * @param root rodicovsky element
104      *
105      * @throws LoadException
106      */
107     private void loadForm(Object root) throws LoadException {
108         if (root == null) {
109             // Výchozí nastavení nového dotazu
110             (((ConstructClausePane) getPane(FIRST_CLAUSE))).addTriple(null, true);
111             ((WhereClausePane) getPane(WHERE_CLAUSE)).addTriple(null, true);
112 
113         } else if (root instanceof Element) {
114             Element rootNode = (Element) root;
115             // Načtení uloženého dotazu
116             loadElement(rootNode, (((ConstructClausePane) getPane(FIRST_CLAUSE))));
117             loadQueryPartsElements((Element) root, queryFormParts);
118 
119         } else if (root instanceof ParseTree) {
120             setVariables((ParseTree) root);
121         }
122     }
123 
124     /**
125      * Inicializace pole casti
126      */
127     private void initializeQueryFormParts() {
128         queryFormParts = new ArrayList<>();
129 
130         queryFormParts.add(new ConstructClausePane(this));
131 
132         queryFormParts.add(new FromClausePane(this));
133         queryFormParts.add(new WhereClausePane(this));
134         queryFormParts.add(new OrderByClausePane(this));
135         queryFormParts.add(new GroupByClausePane(this));
136         queryFormParts.add(new HavingClausePane(this));
137         queryFormParts.add(new LimitOffsetClausePane());
138         queryFormParts.add(new ValuesClausePane(this));
139     }
140 
141     /**
142      * Nastavi kolektory promennych
143      */
144     private void addVariablesCollectors() {
145         ((ConstructClausePane) getPane(FIRST_CLAUSE)).addVariablesCollector(
146                 createCollector(constructClauseVariables, whereClauseVariables, groupByClauseVariables,
147                         orderByClauseVariables, valuesClauseVariables));
148 
149         ((WhereClausePane) getPane(WHERE_CLAUSE)).addVariablesCollector(
150                 createCollector(whereClauseVariables, groupByClauseVariables, orderByClauseVariables,
151                         valuesClauseVariables));
152 
153         ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).addVariablesCollector(
154                 createCollector(orderByClauseVariables, whereClauseVariables, groupByClauseVariables,
155                         valuesClauseVariables));
156 
157         ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).addVariablesCollector(
158                 createCollector(groupByClauseVariables, whereClauseVariables, orderByClauseVariables,
159                         valuesClauseVariables));
160 
161         ((ValuesClausePane) getPane(VALUES_CLAUSE)).addVariablesCollector(
162                 createCollector(valuesClauseVariables, whereClauseVariables, groupByClauseVariables,
163                         orderByClauseVariables));
164     }
165 
166     /**
167      * Vrati panel ze seznamu casti formulare
168      *
169      * @param paneType typ panelu
170      *
171      * @return panel ze seznamu casti formulare
172      */
173     private Object getPane(QUERY_PARTS paneType) {
174         return getPane(queryFormParts, paneType);
175     }
176 
177     /**
178      * Titulky panelu
179      */
180     private void addPartsTitles() {
181         final ObservableList<Node> children = getChildren();
182         addChild(children, "CONSTRUCT_QUERY_FRAGMENT", (ConstructClausePane) getPane(FIRST_CLAUSE));
183         addTitlesPanes(children);
184     }
185 
186     private void addTitlesPanes(ObservableList<Node> children) {
187         addChild(children, "FROM_QUERY_FRAGMENT", (FromClausePane) getPane(FROM_CLAUSE));
188         addChild(children, "WHERE_QUERY_FRAGMENT", (WhereClausePane) getPane(WHERE_CLAUSE));
189         addChild(children, "GROUP_BY_QUERY_FRAGMENT", (GroupByClausePane) getPane(GROUP_BY_CLAUSE));
190         addChild(children, "HAVING_QUERY_FRAGMENT", (HavingClausePane) getPane(HAVING_CLAUSE));
191         addChild(children, "ORDER_BY_QUERY_FRAGMENT", (OrderByClausePane) getPane(ORDER_BY_CLAUSE));
192         addChild(children, "MODIFIERS_QUERY_FRAGMENT", (LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE));
193         addChild(children, "VALUES_QUERY_FRAGMENT", (ValuesClausePane) getPane(VALUES_CLAUSE));
194     }
195 
196     /**
197      * Vlozi {@code CustomTitledPane} do seznamu uzlu
198      *
199      * @param children seznam uzlu
200      * @param title titulek
201      * @param content obsah (panel)
202      */
203     private void addChild(ObservableList<Node> children, final String title, final Node... content) {
204         children.add(new CustomTitledPane(Messages.getString(title), content));
205     }
206 
207     /**
208      * Nastavení hlídání změn
209      */
210     private void addWatches() {
211         watch((FromClausePane) getPane(FROM_CLAUSE));
212         watch((WhereClausePane) getPane(WHERE_CLAUSE));
213         watch(((OrderByClausePane) getPane(ORDER_BY_CLAUSE)));
214         watch(((GroupByClausePane) getPane(GROUP_BY_CLAUSE)));
215         watch(((HavingClausePane) getPane(HAVING_CLAUSE)));
216         watch(((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)));
217         watch(((ValuesClausePane) getPane(VALUES_CLAUSE)));
218     }
219 
220     @Override
221     protected void setVariables(ParseTree root) throws LoadException {
222         Stack<SparqlParserNode> nodeStack = new Stack<>(); //current path in parse tree
223         nodeStack.push(new SparqlParserNode(root));
224         while (!nodeStack.isEmpty()) {
225             SparqlParserNode currentNode = nodeStack.pop();
226 
227             ParseTree nodeData = currentNode.getNodeData();
228 
229             if (nodeData instanceof SparqlParser.ConstructTriplesContext) { //part with variables of query
230                 new SparqlParserWhereClauseWalker(nodeData, (((ConstructClausePane) getPane(FIRST_CLAUSE))))
231                         .processWhereClauseDFS();
232             } else if (nodeData instanceof SparqlParser.DatasetClauseContext) { //from clause
233                 ((FromClausePane) getPane(FROM_CLAUSE)).load(nodeData);
234 
235             } else if (nodeData instanceof SparqlParser.LimitClauseContext) { //limit clause
236                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).load(nodeData);
237 
238             } else if (nodeData instanceof SparqlParser.OffsetClauseContext) { //offset clause
239                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).load(nodeData);
240 
241             } else if (nodeData instanceof SparqlParser.OrderConditionContext) { //order clause
242                 ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).load(nodeData);
243 
244             } else if (nodeData instanceof SparqlParser.HavingConditionContext) { //having clause
245                 ((HavingClausePane) getPane(HAVING_CLAUSE)).load(nodeData);
246 
247             } else if (nodeData instanceof SparqlParser.WhereClauseContext) { //where clause
248                 new SparqlParserWhereClauseWalker(nodeData, ((WhereClausePane) getPane(WHERE_CLAUSE)))
249                         .processWhereClauseDFS();
250 
251             } else if (nodeData instanceof SparqlParser.GroupConditionContext) { //group by clause
252                 ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).load(nodeData);
253 
254             } else if (nodeData instanceof SparqlParser.ValuesClauseContext) { // Values clause
255                 ((ValuesClausePane) getPane(VALUES_CLAUSE)).load(nodeData);
256 
257             } else { //uninsteresting node -> get next node
258                 nodeStack.push(currentNode);
259                 getTreeChild(currentNode, nodeStack);
260             }
261         }
262     }
263 
264     @Override
265     public final String getQueryPart() {
266         return "CONSTRUCT " //$NON-NLS-1$
267                 + (((ConstructClausePane) getPane(FIRST_CLAUSE))).getQueryPart()
268                 + ((FromClausePane) getPane(FROM_CLAUSE)).getQueryPart() + "WHERE "//$NON-NLS-1$
269                 + ((WhereClausePane) getPane(WHERE_CLAUSE)).getQueryPart()
270                 + ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).getQueryPart()
271                 + ((HavingClausePane) getPane(HAVING_CLAUSE)).getQueryPart()
272                 + ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).getQueryPart()
273                 + ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).getQueryPart()
274                 + ((ValuesClausePane) getPane(VALUES_CLAUSE)).getQueryPart() + " ";
275     }
276 
277     @Override
278     public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
279         final Set<String> result
280                 = new HashSet<>((((ConstructClausePane) getPane(FIRST_CLAUSE))).getPrefixesUsed(appendDelimiter));
281         result.addAll(((WhereClausePane) getPane(WHERE_CLAUSE)).getPrefixesUsed(appendDelimiter));
282         result.addAll(((FromClausePane) getPane(FROM_CLAUSE)).getPrefixesUsed(appendDelimiter));
283         result.addAll(((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).getPrefixesUsed(appendDelimiter));
284         result.addAll(((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).getPrefixesUsed(appendDelimiter));
285         result.addAll(((HavingClausePane) getPane(HAVING_CLAUSE)).getPrefixesUsed(appendDelimiter));
286         result.addAll(((ValuesClausePane) getPane(VALUES_CLAUSE)).getPrefixesUsed(appendDelimiter));
287         return result;
288     }
289 
290     @Override
291     public final List<SubSelectPane> getSubSelectPanes() {
292         return ((WhereClausePane) getPane(WHERE_CLAUSE)).getSubSelectPanes();
293     }
294 
295     @Override
296     public final ObservableList<String> getSortedVariables() {
297         ObservableSet<String> variables = FXCollections.observableSet();
298         variables.addAll(this.getNetVariables());
299         ((WhereClausePane) getPane(WHERE_CLAUSE)).getSubSelectPanes().forEach((subSelectPane) -> variables.addAll(subSelectPane.getSubSelectQueryPane().getSelectedVariables()));
300         return FXCollections.observableArrayList(variables).sorted(String.CASE_INSENSITIVE_ORDER);
301     }
302 
303     @Override
304     public final void save(final Element root) {
305         Saveable.defaultSave(root, (((ConstructClausePane) getPane(FIRST_CLAUSE))),
306                 ((FromClausePane) getPane(FROM_CLAUSE)), ((WhereClausePane) getPane(WHERE_CLAUSE)),
307                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)),
308                 ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)),
309                 ((HavingClausePane) getPane(HAVING_CLAUSE)),
310                 ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)),
311                 ((ValuesClausePane) getPane(VALUES_CLAUSE)));
312     }
313 
314     @Override
315     protected final String getXMLQueryType() {
316         return XML_QUERY_TYPE_VALUE;
317     }
318 
319 }