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.autoComplete;
21  
22  import cz.zcu.mre.sparkle.data.PrefixesStorage;
23  import cz.zcu.mre.sparkle.data.StorageEntry;
24  import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
25  import cz.zcu.mre.sparkle.gui.query.other.TypedTextField;
26  import cz.zcu.mre.sparkle.tools.Definitions;
27  import cz.zcu.mre.sparkle.tools.Utils;
28  import cz.zcu.mre.sparkle.tools.sparqlValidation.SparqlValidationUtils;
29  import javafx.collections.FXCollections;
30  import javafx.collections.ObservableList;
31  import javafx.scene.control.TextField;
32  import java.util.List;
33  import java.util.Set;
34  import java.util.stream.Collectors;
35  
36  /**
37   * Handler pro seznam návrhů využitelný s {@link TypedTextField} nastaveným pro
38   * zápis výrazu.
39   *
40   * @author Jan Smucr
41   * @author Klara Hlavacova
42   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
43   */
44  public class ExpressionAutoCompleteListHandler
45          implements AutoCompleteListHandler {
46  
47      private final QueryFormPane<?> queryFormPane;
48  
49      public ExpressionAutoCompleteListHandler(final QueryFormPane<?> queryFormPane) {
50          this.queryFormPane = queryFormPane;
51      }
52  
53      @Override
54      public PrefixesStorage getPrefixesStorage() {
55          return queryFormPane.getQueryPrefixesStorage();
56      }
57  
58      @Override
59      public ObservableList<Object> getAutoCompleteList(final TextField textField) {
60  
61          final String text = textField.getText().substring(0, textField.getCaretPosition());
62          final int lastVariableStartIndex = text.lastIndexOf(Definitions.VARIABLE_PREFIX);
63          final int lastPrefixDelimiterIndex = text.lastIndexOf(Definitions.PREFIXED_NAME_PREFIX_DELIMITER);
64  
65          // Hledání toho, jaký seznam vlastně zobrazit
66          if (lastVariableStartIndex > lastPrefixDelimiterIndex) {
67              ObservableList<Object> variablesList = getVariablesList(text, lastVariableStartIndex);
68              if (variablesList != null) {
69                  return variablesList;
70              }
71          }
72  
73          if ((lastPrefixDelimiterIndex > lastVariableStartIndex)) {
74              // Seznam všeho možného k zadanému prefixu
75              return getFunctionsWithPrefixAndResources(text, lastPrefixDelimiterIndex);
76          }
77  
78          // Seznam prefixů a funkcí bez prefixu
79          final ObservableList<Object> functionsList = getFunctionsAndResourcesWithoutPrefix();
80  
81          int pos = text.length() - 1;
82          String part = null;
83  
84          while (pos >= 0) {
85              final String tempPart = text.substring(pos);
86              if (SparqlValidationUtils.isPrefixOrLocalNameValid(tempPart)) {
87                  part = tempPart;
88              } else {
89                  break;
90              }
91              pos--;
92          }
93  
94          if (part == null) {
95              return functionsList;
96          }
97  
98          final String constPart = part;
99  
100         //seznam funkci/zdroju bez prefixu, ktere zacinaji danym textem z pole
101         return functionsList.filtered((t) -> Utils
102                 .stringStartsWithIgnoreCase(AutoCompleteWrapper.getIRI(t, getPrefixesStorage()), constPart));
103     }
104 
105     /**
106      * Vrati seznam funkci a zdroju bez prefixu.
107      *
108      * @return seznam funkci a zdroju bez prefixu
109      */
110     private ObservableList<Object> getFunctionsAndResourcesWithoutPrefix() {
111         final Set<String> prefixesSet = queryFormPane.getQueryPrefixesStorage().getPrefixesUsed(true);
112         List<StorageEntry> storageEntryStream = prefixesSet.stream().map(p -> new StorageEntry(null, p, "")).collect(
113                 Collectors.toList());
114 
115         final ObservableList<Object> prefixesList = FXCollections.observableArrayList(storageEntryStream);
116         // prefixesList.sort(Utils::compareResourceEntryByIri);
117 
118         final ObservableList<Object> functionsList = queryFormPane.getQueryFunctionsStorage().getUnprefixedFunctionNames();
119         //  functionsList.sort(Utils::compareResourceEntryByIri);
120 
121         functionsList.addAll(functionsList.size(), prefixesList);
122         return functionsList;
123     }
124 
125     /**
126      * Vrati seznam promennych nebo null.
127      *
128      * @param text text od zacatku pole po pozici kurzoru
129      * @param lastVariableStartIndex pozice prefixu promenne
130      *
131      * @return seznam promennych nebo null
132      */
133     private ObservableList<Object> getVariablesList(final String text, final int lastVariableStartIndex) {
134         // Seznam proměnných
135         final String variablePart = text.substring(lastVariableStartIndex + 1);
136         if (variablePart.isEmpty()) {
137             return Utils.getObjectList(queryFormPane.getSortedVariables());
138         }
139 
140         if (SparqlValidationUtils.isVariableNameValid(variablePart)) {
141             return Utils.getObjectList(queryFormPane
142                     .getSortedVariables()
143                     .filtered((t) -> Utils.stringStartsWithIgnoreCase(t, variablePart)));
144         }
145 
146         return null;
147     }
148 
149     /**
150      * Vrati seznam funkci s prefixy a zdroju.
151      *
152      * @param text text od zacatku pole po pozici kurzoru
153      * @param lastPrefixDelimiterIndex pozice prefixu zdroje
154      *
155      * @return seznam funkci a zdroju
156      */
157     private ObservableList<Object> getFunctionsWithPrefixAndResources(final String text,
158             final int lastPrefixDelimiterIndex) {
159 
160         int prefixPartPos = lastPrefixDelimiterIndex;
161         String prefixPart = null;
162         while (--prefixPartPos > -1) {
163             final String _prefixPart = text.substring(prefixPartPos, lastPrefixDelimiterIndex);
164             if (!SparqlValidationUtils.isPrefixNameValid(_prefixPart)) {
165                 break;
166             }
167             prefixPart = _prefixPart;
168         }
169 
170         if (prefixPart == null) {
171             return FXCollections.emptyObservableList();
172         }
173 
174         final ObservableList<String> functions
175                 = queryFormPane.getQueryFunctionsStorage().getFunctionsNamesByPrefix(prefixPart, false);
176         // functions.sort(String.CASE_INSENSITIVE_ORDER);
177 
178         final ObservableList<String> resources
179                 = queryFormPane.getQueryResourcesStorage().getResourcesNamesByPrefix(prefixPart, false);
180         //resources.sort(String.CASE_INSENSITIVE_ORDER);
181 
182         functions.addAll(resources);
183 
184         if (((lastPrefixDelimiterIndex + 1) == text.length()) || functions.isEmpty()) {
185             return Utils.getObjectList(functions);
186         }
187         final String termPart = text.substring(lastPrefixDelimiterIndex + 1);
188 
189         //seznam funkci/zdroju s prefixem, ktere zacinaji danym textem z pole
190         return Utils.getObjectList(functions.filtered((t) -> Utils.stringStartsWithIgnoreCase(t, termPart)));
191     }
192 
193 }