1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package cz.zcu.mre.sparkle.gui.query;
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.dialogs.other.ConfirmationDialog;
26 import cz.zcu.mre.sparkle.gui.dialogs.other.ErrorDialog;
27 import cz.zcu.mre.sparkle.gui.dialogs.other.ProgressDialog;
28 import cz.zcu.mre.sparkle.gui.dialogs.other.YesNoCancelDialog;
29 import cz.zcu.mre.sparkle.gui.dialogs.other.YesNoCancelDialog.Result;
30 import cz.zcu.mre.sparkle.gui.evaluation.EvaluationTab;
31 import cz.zcu.mre.sparkle.gui.evaluation.EvaluatorTab;
32 import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
33 import cz.zcu.mre.sparkle.gui.query.queryTypes.insert.InsertQueryFormPane;
34 import cz.zcu.mre.sparkle.gui.query.queryTypes.insert.InsertQueryTab;
35 import cz.zcu.mre.sparkle.gui.query.other.CloseableTab;
36 import cz.zcu.mre.sparkle.gui.query.other.ExporterTab;
37 import cz.zcu.mre.sparkle.gui.query.other.SaverTab;
38 import cz.zcu.mre.sparkle.gui.query.queryTypes.ask.AskQueryFormPane;
39 import cz.zcu.mre.sparkle.gui.query.queryTypes.ask.AskQueryTab;
40 import cz.zcu.mre.sparkle.gui.query.queryTypes.construct.ConstructQueryFormPane;
41 import cz.zcu.mre.sparkle.gui.query.queryTypes.construct.ConstructQueryTab;
42 import cz.zcu.mre.sparkle.gui.query.queryTypes.delete.DeleteInsertQueryFormPane;
43 import cz.zcu.mre.sparkle.gui.query.queryTypes.delete.DeleteInsertQueryTab;
44 import cz.zcu.mre.sparkle.gui.query.queryTypes.delete.DeleteQueryFormPane;
45 import cz.zcu.mre.sparkle.gui.query.queryTypes.delete.DeleteQueryTab;
46 import cz.zcu.mre.sparkle.gui.query.queryTypes.describe.DescribeQueryFormPane;
47 import cz.zcu.mre.sparkle.gui.query.queryTypes.describe.DescribeQueryTab;
48 import cz.zcu.mre.sparkle.gui.query.queryTypes.select.SelectQueryFormPane;
49 import cz.zcu.mre.sparkle.gui.query.queryTypes.select.SelectQueryTab;
50 import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
51 import cz.zcu.mre.sparkle.gui.text_editor.TextEditor;
52 import cz.zcu.mre.sparkle.gui.tools.ReferenceKeeper;
53 import cz.zcu.mre.sparkle.tools.IO;
54 import cz.zcu.mre.sparkle.tools.Utils;
55 import javafx.beans.Observable;
56 import javafx.beans.property.*;
57 import javafx.beans.value.ObservableValue;
58 import javafx.concurrent.Task;
59 import javafx.event.Event;
60 import javafx.scene.control.ColorPicker;
61 import javafx.scene.control.Tab;
62 import javafx.scene.paint.Color;
63 import javafx.stage.Window;
64 import org.apache.jena.query.Query;
65 import java.io.File;
66 import java.util.concurrent.ExecutionException;
67 import static cz.zcu.mre.sparkle.tools.Definitions.QUERY_FILE_EXTENSION_DELIMITER;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71
72
73
74
75
76
77
78
79
80
81 public abstract class QueryTab<QueryResultType>
82 extends Tab
83 implements EvaluatorTab, SaverTab, CloseableTab, ExporterTab {
84
85 private static final Logger LOG = LoggerFactory.getLogger(QueryTab.class);
86
87 private static final String FORM_TAB_NAME = Messages.getString("FORM");
88 private static final String EDITOR_TAB_NAME = Messages.getString("EDITOR");
89
90 private final String defaultFileName = getDefaultFileName();
91
92 private QueryFormPane<QueryResultType> queryFormPane;
93 private final QueryTabPane<QueryResultType> queryTabPane;
94
95 private final ReadOnlyObjectWrapper<File> fileProperty = new ReadOnlyObjectWrapper<>();
96 private final ReadOnlyStringWrapper titleProperty = new ReadOnlyStringWrapper();
97
98 private final ReadOnlyBooleanWrapper formChangedProperty = new ReadOnlyBooleanWrapper(false);
99 private final ReferenceKeeper keeperForm = new ReferenceKeeper();
100
101 private final ReadOnlyBooleanWrapper editorChangedProperty = new ReadOnlyBooleanWrapper(false);
102 private final ReferenceKeeper keeperEditor = new ReferenceKeeper();
103
104 private final ColorPicker colorPicker = new ColorPicker(Utils.DEFAULT_COLOR);
105
106 private final ReadOnlyBooleanWrapper queryValidProperty = new ReadOnlyBooleanWrapper(true);
107
108 protected QueryTab(final QueryFormPane<QueryResultType> queryFormPane) {
109 this.queryFormPane = queryFormPane;
110
111
112 queryTabPane = new QueryTabPane<>(this.queryFormPane);
113
114 setContent(queryTabPane);
115
116 titleProperty.addListener((observable) -> updateText());
117 fileProperty.addListener((observable) -> updateTitle());
118
119
120 setFormChangeListener();
121 setEditorChangeListener();
122 colorPicker.valueProperty().addListener((observable, oldValue, newValue) -> formChangedProperty.set(true));
123
124 updateTitle();
125 setOnCloseRequest(this::onCloseRequest);
126
127 initializeEditor();
128 }
129
130
131
132
133 private void initializeEditor() {
134 Window window = queryFormPane.getMainForm().getMainTabPane().getScene().getWindow();
135 queryTabPane.initStorage(this, window);
136 }
137
138
139
140
141 private void setEditorChangeListener() {
142 editorChangedProperty.addListener((observable) -> updateText());
143
144 ((TextEditor) queryTabPane.getQueryTextArea())
145 .textProperty()
146 .addListener(keeperEditor.toWeak((obs, oldText, newText) -> {
147 validateQuery(newText);
148 editorChangedProperty.set(true);
149
150 }));
151 }
152
153
154
155
156 private void setFormChangeListener() {
157 formChangedProperty.addListener((observable) -> updateText());
158
159 this.queryFormPane.addListener(
160 keeperForm.toWeak((final Observable observable) -> {
161 formChangedProperty.set(true);
162 validateQuery(queryFormPane.getQuery());
163 }));
164
165 }
166
167
168
169
170 private void updateText() {
171 setText(formChangedProperty.get() ? "*" + titleProperty.get() : titleProperty.get());
172 queryTabPane.getFormTab()
173 .setText(formChangedProperty.get() ? "*" + FORM_TAB_NAME : FORM_TAB_NAME);
174 queryTabPane.getEditorTab()
175 .setText(editorChangedProperty.get() ? "*" + EDITOR_TAB_NAME : EDITOR_TAB_NAME);
176
177 formChangedProperty.set(formChangedProperty.get() || editorChangedProperty.get());
178 }
179
180
181
182
183
184
185 private void validateQuery(String queryInEditor) {
186 try {
187 if (queryTabPane.getEditorTab().isSelected()) {
188 queryTabPane.getQuery(queryInEditor);
189 } else {
190 queryTabPane.getQuery(queryFormPane.getQuery());
191 }
192
193 queryValidProperty.set(true);
194 } catch (Exception e) {
195
196 queryValidProperty.set(false);
197 }
198 }
199
200
201
202
203
204
205
206
207
208 public void setSubSelectName(QueryTab mainQuery, SubSelectPane subSelectQueryPane, String loadedQueryTabName) {
209
210 formChangedProperty.set(false);
211 if (loadedQueryTabName != null && !loadedQueryTabName.isEmpty()) {
212 this.titleProperty.set(loadedQueryTabName);
213 } else {
214 this.titleProperty.set(mainQuery.titleProperty().get() + this.titleProperty.get()
215 + subSelectQueryPane.getSubSelectOrder());
216 }
217 setText(titleProperty.get());
218
219
220 mainQuery.titleProperty()
221 .addListener((ObservableValue<? extends String> ov, String oldString, String newString) -> {
222 String suffix = titleProperty.get().substring(titleProperty.get().indexOf(
223 Messages.getString("SUBSELECT_QUERY_DEFAULT_FILE_NAME")));
224 if (newString.contains(QUERY_FILE_EXTENSION_DELIMITER)) {
225 titleProperty
226 .set(newString.subSequence(0, newString.lastIndexOf(QUERY_FILE_EXTENSION_DELIMITER))
227 + suffix);
228 } else {
229 titleProperty.set(newString + suffix);
230 }
231 });
232 }
233
234
235
236
237
238
239 public ReadOnlyBooleanWrapper getFormChangedProperty() {
240 return this.formChangedProperty;
241 }
242
243
244
245
246
247
248
249 public void setCheckingSubSelect(ReadOnlyBooleanWrapper changedPropertySelect) {
250 changedPropertySelect
251 .addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
252 if (newValue) {
253 this.formChangedProperty.set(true);
254 }
255 });
256 }
257
258
259
260
261
262
263
264
265 public void setCheckingMainQueryPart(ReadOnlyBooleanWrapper changedPropertySelect) {
266 changedPropertySelect
267 .addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
268 if (!newValue) {
269 this.formChangedProperty.set(newValue);
270 }
271 });
272 }
273
274
275
276
277
278
279 @Override
280 public final void evaluate(DataAgent dataAgent) {
281
282 if (queryTabPane.getEditorTab().isSelected()) {
283 queryTabPane.getSelectionModel().select(queryTabPane.getFormTab());
284 queryTabPane.getSelectionModel().select(queryTabPane.getEditorTab());
285
286 queryTabPane.getEvaluationTab()
287 .evaluate(queryTabPane.getQueryTextArea().getText(), dataAgent);
288 } else {
289 queryTabPane.getEvaluationTab()
290 .evaluate(queryFormPane.getQuery(), dataAgent);
291 }
292 }
293
294
295
296
297 @Override
298 public void stopEvaluating() {
299 if (queryTabPane.getEvaluationTab() != null) {
300 queryTabPane.getEvaluationTab().stopEvaluating();
301 }
302 }
303
304
305
306
307
308
309 @Override
310 public ReadOnlyBooleanProperty evaluatingProperty() {
311 return queryTabPane.getEvaluatingProperty().getReadOnlyProperty();
312 }
313
314
315
316
317 @Override
318 public void export() {
319 QueryTabPane.updateFormAndReturnToTab(this);
320
321 String query = "";
322 try {
323
324 final Query q;
325 q = DataAgent.createQuery(query = queryFormPane.getQuery());
326 query = q.serialize();
327 } catch (final Exception e) {
328 if (!ConfirmationDialog.open(getWindow(), Messages.getString("EXPORT"), Messages.getString(
329 "QUERY_CONTAINS_ERRORS_EXPORT_ANYWAY"))) {
330 return;
331 }
332
333
334 }
335
336 assert (!query.isEmpty());
337
338 final File file = IO.saveExportedQueryFile(getWindow(), Messages.getString("EXPORT"),
339 getFileNameWithoutExtension());
340 if (file == null) {
341 return;
342 }
343
344 final String finalQuery = query;
345 try {
346 ProgressDialog.performTask(getWindow(), new Task<Void>() {
347 @Override
348 protected Void call() throws Exception {
349 updateMessage(Messages.getString("SAVING_IN_PROGRESS"));
350 IO.saveString(file, finalQuery);
351 return null;
352 }
353 }, false);
354 } catch (final InterruptedException | ExecutionException excp) {
355 LOG.error("Exception: ", excp);
356 ErrorDialog.open(getWindow(), Messages.getString("ERROR"),
357 Messages.getString("FILE_COULD_NOT_BE_SAVED"),
358 excp);
359 }
360 }
361
362
363
364
365 private String getFileNameWithoutExtension() {
366 final File file = fileProperty.get();
367 String name;
368 if (file == null) {
369 name = defaultFileName;
370 } else {
371 name = file.getName();
372 }
373 final int lastDotIndex = name.lastIndexOf('.');
374 if (lastDotIndex == -1) {
375 return name;
376 }
377 return name.substring(0, lastDotIndex);
378 }
379
380
381
382
383
384
385 @Override
386 public final boolean save() {
387 final File f = fileProperty.get();
388 if (f == null || f.getName().contains(".txt")) {
389 return saveAs();
390 }
391 return saveAs(f);
392 }
393
394
395
396
397 private Window getWindow() {
398 return getTabPane().getScene().getWindow();
399 }
400
401
402
403
404
405
406 @Override
407 public final boolean saveAs() {
408 QueryTabPane.updateFormAndReturnToTab(this);
409
410 final File oldFile = fileProperty.get();
411 final File f = IO.saveQueryFile(getWindow(), Messages.getString("SAVE_QUERY_AS"),
412 oldFile == null ? new File(defaultFileName) : oldFile);
413 return f != null && saveAs(f);
414 }
415
416
417
418
419
420
421
422
423
424 private boolean saveAs(final File file) {
425 try {
426 ProgressDialog.performTask(getWindow(), new Task<Void>() {
427 @Override
428 protected Void call() throws Exception {
429 updateMessage(Messages.getString("SAVING_IN_PROGRESS"));
430 queryFormPane.save(file);
431 return null;
432 }
433 }, false);
434
435 fileProperty.set(file);
436 formChangedProperty.set(false);
437 editorChangedProperty.set(false);
438
439 return true;
440 } catch (final InterruptedException | ExecutionException excp) {
441 LOG.error("Exception: ", excp);
442 ErrorDialog.open(getWindow(), Messages.getString("ERROR"),
443 Messages.getString("FILE_COULD_NOT_BE_SAVED"),
444 excp);
445 }
446 return false;
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460
461 public final static QueryTab<?> open(final MainForm mainForm, final File file, final Window ownerWindow,
462 final DataAgent dataAgent, final Storage localStorage) {
463
464 mainForm.setLoading(true);
465
466 try {
467 return ProgressDialog.performTask(ownerWindow, new Task<QueryTab<?>>() {
468 @Override
469 protected QueryTab<?> call() throws Exception {
470 updateMessage(Messages.getString("OPENING_IN_PROGRESS"));
471
472 final QueryFormPane<?> pane = Utils.runAndWait(() -> QueryFormPane
473 .load(mainForm, dataAgent, localStorage, file));
474
475 QueryTab<?> tab;
476 if (pane instanceof SelectQueryFormPane) {
477 tab = new SelectQueryTab((SelectQueryFormPane) pane);
478 } else if (pane instanceof AskQueryFormPane) {
479 tab = new AskQueryTab((AskQueryFormPane) pane);
480 } else if (pane instanceof ConstructQueryFormPane) {
481 tab = new ConstructQueryTab((ConstructQueryFormPane) pane);
482 } else if (pane instanceof DescribeQueryFormPane) {
483 tab = new DescribeQueryTab((DescribeQueryFormPane) pane);
484 } else if (pane instanceof DeleteQueryFormPane) {
485 tab = new DeleteQueryTab((DeleteQueryFormPane) pane);
486 } else if (pane instanceof InsertQueryFormPane) {
487 tab = new InsertQueryTab((InsertQueryFormPane) pane);
488 } else if (pane instanceof DeleteInsertQueryFormPane) {
489 tab = new DeleteInsertQueryTab((DeleteInsertQueryFormPane) pane);
490 } else {
491 return null;
492 }
493 tab.fileProperty.set(file);
494
495 return tab;
496 }
497 });
498 } catch (InterruptedException | ExecutionException e) {
499
500
501 ErrorDialog.open(ownerWindow, Messages.getString("ERROR"),
502 Messages.getString("FILE_COULD_NOT_BE_OPENED"),
503 e);
504
505 mainForm.setLoading(false);
506 return null;
507 }
508 }
509
510 public final QueryFormPane<QueryResultType> getQueryFormPane() {
511 return queryFormPane;
512 }
513
514 public void setBackgroundColor(Color color) {
515 this.colorPicker.setValue(color);
516 }
517
518 public Color getBackgroundColor() {
519 return this.colorPicker.getValue();
520 }
521
522 public ColorPicker getColorPicker() {
523 return this.colorPicker;
524 }
525
526 public final String getTitle() {
527 return titleProperty.get();
528 }
529
530 public final ReadOnlyStringProperty titleProperty() {
531 return titleProperty.getReadOnlyProperty();
532 }
533
534
535
536
537
538 private void updateTitle() {
539 final File file = fileProperty.get();
540 titleProperty.set(file == null ? defaultFileName : file.getName());
541 }
542
543
544
545
546
547
548 private void onCloseRequest(final Event event) {
549 if (!requestClose()) {
550
551 event.consume();
552 }
553 }
554
555
556
557
558
559
560 @Override
561 public final boolean requestClose() {
562 if (!formChangedProperty.get()) {
563 return true;
564 }
565 boolean closed = ((QueryTabPane) getQueryTabPane()).setClosed();
566 LOG.debug("Closed QueryTabPane {}, closed={}", ((QueryTabPane) getQueryTabPane()), closed);
567
568
569 getTabPane().requestFocus();
570
571 final Result result
572 = YesNoCancelDialog.open(getWindow(),
573 Messages.getString("CONFIRMATION"),
574 String.format(Messages.getString("FILE_X_MODIFIED_SAVE"),
575 titleProperty.get()));
576 switch (result) {
577 case Cancel:
578 return false;
579 case Yes:
580 return save();
581 case No:
582 return true;
583 }
584
585 return true;
586 }
587
588
589
590
591
592
593 @Override
594 public final ReadOnlyBooleanProperty hasChangesProperty() {
595 return formChangedProperty.getReadOnlyProperty();
596 }
597
598
599
600
601
602
603 @Override
604 public ReadOnlyObjectProperty<File> fileProperty() {
605 return fileProperty.getReadOnlyProperty();
606 }
607
608
609
610
611
612
613
614 protected abstract EvaluationTab<QueryResultType> createEvaluationTab(final DataAgent dataAgent);
615
616
617
618
619 protected abstract String getDefaultFileName();
620
621 public QueryTabPane<QueryResultType> getQueryTabPane() {
622 return queryTabPane;
623 }
624
625 public boolean isEditorChangedProperty() {
626 return editorChangedProperty.get();
627 }
628
629 public ReadOnlyBooleanWrapper getEditorChangedPropertyProperty() {
630 return editorChangedProperty;
631 }
632
633 public void setQueryFormPane(QueryFormPane<QueryResultType> queryFormPane) {
634 this.queryFormPane = queryFormPane;
635 }
636
637 public boolean isQueryValidProperty() {
638 return queryValidProperty.get();
639 }
640
641 public ReadOnlyBooleanWrapper queryValidPropertyProperty() {
642 return queryValidProperty;
643 }
644
645 public void setQueryValidProperty(boolean queryValidProperty) {
646 this.queryValidProperty.set(queryValidProperty);
647 }
648
649 }