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.modifiers;
21  
22  import cz.zcu.mre.sparkle.gui.query.helpers.PartialQueryGenerator;
23  import cz.zcu.mre.sparkle.gui.tools.Components;
24  import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
25  import cz.zcu.mre.sparkle.tools.Changeable;
26  import cz.zcu.mre.sparkle.tools.Saveable;
27  import cz.zcu.mre.sparkle.tools.SparqlParser;
28  import javafx.beans.InvalidationListener;
29  import javafx.fxml.FXML;
30  import javafx.scene.control.CheckBox;
31  import javafx.scene.control.TextField;
32  import javafx.scene.layout.FlowPane;
33  import org.w3c.dom.Element;
34  import java.util.HashSet;
35  import java.util.Set;
36  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.LIMIT_VALUE;
37  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.OFFSET_VALUE;
38  
39  /**
40   * Kontroler komponenty reprezentující klauzule LIMIT a OFFSET.
41   *
42   * @author Jan Smucr
43   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
44   */
45  public final class LimitOffsetClausePane
46          extends FlowPane
47          implements PartialQueryGenerator, Saveable, Changeable {
48  
49      private static final String XML_OFFSET = "offset"; //$NON-NLS-1$
50      private static final String XML_LIMIT = "limit"; //$NON-NLS-1$
51      private static final String XML_ELEMENT_NAME = "LimitOffset"; //$NON-NLS-1$
52      @FXML
53      private CheckBox limitCheckBox, offsetCheckBox;
54      @FXML
55      private TextField limitTextField, offsetTextField;
56  
57      private final ReferenceKeeper keeper = new ReferenceKeeper();
58      private final Set<InvalidationListener> observers = new HashSet<>();
59  
60      public LimitOffsetClausePane() {
61          Components.load(this);
62  
63          limitTextField.disableProperty().bind(limitCheckBox.selectedProperty().not());
64          offsetTextField.disableProperty().bind(offsetCheckBox.selectedProperty().not());
65  
66          limitTextField.setText("0"); //$NON-NLS-1$
67          offsetTextField.setText("0"); //$NON-NLS-1$
68  
69          createFieldTextListeners(limitTextField);
70          createFieldTextListeners(offsetTextField);
71  
72          // Sledování změn
73          watch(limitCheckBox.selectedProperty());
74          watch(limitTextField.textProperty());
75          watch(offsetCheckBox.selectedProperty());
76          watch(offsetTextField.textProperty());
77      }
78  
79      private static boolean isValidValue(final String value) {
80          try {
81              final int intValue = Integer.parseInt(value);
82              return intValue >= 0;
83          } catch (final NumberFormatException e) {
84              return false;
85          }
86      }
87  
88      private void createFieldTextListeners(final TextField field) {
89          field.focusedProperty().addListener(keeper.toWeak((observable, oldValue, newValue)
90                  -> {
91              if (newValue) {
92                  return;
93              }
94              if (!isValidValue(field.getText())) {
95                  field.setText("0"); //$NON-NLS-1$
96              }
97          }));
98  
99          field.textProperty().addListener(keeper.toWeak((observable, oldValue, newValue)
100                 -> {
101             if (!oldValue.isEmpty()) {
102                 if (!isValidValue(oldValue)) {
103                     oldValue = "0"; //$NON-NLS-1$
104                 }
105             }
106             if (newValue.isEmpty()) {
107                 return;
108             }
109             if (!isValidValue(newValue)) {
110                 field.setText(oldValue);
111             }
112         }));
113     }
114 
115     @Override
116     public final String getQueryPart() {
117         return (limitCheckBox.isSelected() ? "LIMIT " //$NON-NLS-1$
118                 + limitTextField.getText() + " " //$NON-NLS-2$
119                 : "")//$NON-NLS-3$
120                 + (offsetCheckBox.isSelected() ? "OFFSET " //$NON-NLS-1$
121                 + offsetTextField.getText() + " " //$NON-NLS-2$
122                 : "");  //$NON-NLS-3$
123     }
124 
125     @Override
126     public final void save(final Element e) {
127         if (limitCheckBox.isSelected()) {
128             e.setAttribute(XML_LIMIT, limitTextField.getText().trim());
129         }
130         if (offsetCheckBox.isSelected()) {
131             e.setAttribute(XML_OFFSET, offsetTextField.getText().trim());
132         }
133     }
134 
135     @Override
136     public final void load(final Object e) throws LoadException {
137         String limitString = null;
138         String offsetString = null;
139         if (e instanceof Element) {
140             Element eNode = (Element) e;
141             if (eNode.hasAttribute(XML_LIMIT)) {
142                 limitString = eNode.getAttribute(XML_LIMIT);
143                 if (!isValidValue(limitString)) {
144                     throw new LoadException(eNode, XML_LIMIT);
145                 }
146             }
147             if (eNode.hasAttribute(XML_OFFSET)) {
148                 offsetString = eNode.getAttribute(XML_OFFSET);
149                 if (!isValidValue(offsetString)) {
150                     throw new LoadException(eNode, XML_OFFSET);
151                 }
152             }
153             if (limitString == null) {
154                 limitCheckBox.setSelected(false);
155             } else {
156                 limitCheckBox.setSelected(true);
157                 limitTextField.setText(limitString);
158             }
159             if (offsetString == null) {
160                 offsetCheckBox.setSelected(false);
161             } else {
162                 offsetCheckBox.setSelected(true);
163                 offsetTextField.setText(offsetString);
164             }
165         } else if (e instanceof SparqlParser.LimitClauseContext) {
166             SparqlParser.LimitClauseContext eNode = (SparqlParser.LimitClauseContext) e;
167             String limitValue = eNode.INTEGER().getText();
168             if (limitValue != null) {
169                 limitCheckBox.setSelected(true);
170                 limitTextField.setText(limitValue);
171             } else {
172                 throw new LoadException(eNode, LIMIT_VALUE);
173             }
174         } else if (e instanceof SparqlParser.OffsetClauseContext) {
175             SparqlParser.OffsetClauseContext eNode = (SparqlParser.OffsetClauseContext) e;
176             String offsetValue = eNode.INTEGER().getText();
177             if (offsetValue != null) {
178                 offsetCheckBox.setSelected(true);
179                 offsetTextField.setText(offsetValue);
180             } else {
181                 throw new LoadException(eNode, OFFSET_VALUE);
182             }
183         }
184     }
185 
186     @Override
187     public final String getXMLElementName() {
188         return XML_ELEMENT_NAME;
189     }
190 
191     @Override
192     public final Set<InvalidationListener> getObservers() {
193         return observers;
194     }
195 }