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