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.mainForm;
21  
22  import cz.zcu.mre.sparkle.data.*;
23  import cz.zcu.mre.sparkle.data.resourceStorage.ResourcesStorage;
24  import cz.zcu.mre.sparkle.gui.mainForm.mainMenu.MainMenuAction;
25  import cz.zcu.mre.sparkle.gui.mainForm.mainMenu.MainMenuBar;
26  import cz.zcu.mre.sparkle.gui.mainForm.mainMenu.MainToolBar;
27  import cz.zcu.mre.sparkle.gui.mainForm.mainMenu.menuItems.MenuItemsQuery;
28  import cz.zcu.mre.sparkle.gui.mainForm.mainTabPane.MainTabPane;
29  import cz.zcu.mre.sparkle.gui.mainForm.mainTabPane.MainTabPaneListener;
30  import cz.zcu.mre.sparkle.gui.mainForm.mainTabPane.TabContextMenu;
31  import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
32  import cz.zcu.mre.sparkle.gui.query.QueryTab;
33  import cz.zcu.mre.sparkle.gui.tools.AbstractFormController;
34  import cz.zcu.mre.sparkle.tools.Changeable;
35  import javafx.beans.InvalidationListener;
36  import javafx.beans.property.IntegerProperty;
37  import javafx.beans.property.ReadOnlyStringWrapper;
38  import javafx.beans.property.SimpleIntegerProperty;
39  import javafx.beans.value.ChangeListener;
40  import javafx.fxml.FXML;
41  import javafx.scene.control.Tab;
42  import javafx.scene.control.TabPane;
43  import javafx.scene.layout.GridPane;
44  import javafx.scene.layout.StackPane;
45  import java.io.IOException;
46  import java.sql.SQLException;
47  import java.util.HashSet;
48  import java.util.Properties;
49  import java.util.Set;
50  import java.util.logging.Logger;
51  
52  /**
53   * Kontroler hlavního okna aplikace.
54   *
55   * @author Jan Smucr
56   * @author Klara Hlavacova
57   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
58   */
59  public final class MainForm
60          extends AbstractFormController
61          implements Changeable {
62  
63      private final Set<InvalidationListener> observers = new HashSet<>();
64      private static final Logger LOG = Logger.getLogger(MainForm.class.getName());
65  
66      private static final String DEFAULT_TITLE = "Sparkle"; //$NON-NLS-1$
67  
68      // Názvy souborů, kam se serializují lokální seznamy
69      static final String PREFIXES = "prefixes"; //$NON-NLS-1$
70      static final String FUNCTIONS = "functions"; //$NON-NLS-1$
71      static final String DATATYPES = "datatypes"; //$NON-NLS-1$
72      static final String RESOURCES = "resources"; //$NON-NLS-1$
73      public static final String SPARQL_ENDPOINTS = "sparql_endpoints"; //$NON-NLS-1$
74  
75      /**
76       * Uchovává počet záložek s neuloženými změnami. Pokud je 0, lze zablokovat
77       * tlačítko Save all.
78       */
79      private final IntegerProperty unsavedTabsProperty = new SimpleIntegerProperty(0);
80  
81      /**
82       * Posluchač pro každou záložku hlídající, zda jsou v ní neuložené změny.
83       */
84      private final ChangeListener<? super Boolean> tabHasChangesListener
85              = (observable, oldValue, newValue) -> {
86                  final int n = newValue ? 1 : -1;
87                  unsavedTabsProperty.set(unsavedTabsProperty.get() + n);
88              };
89  
90      /**
91       * Umožňuje nastavit titulek okna podle aktuálně vybrané záložky.
92       */
93      private final InvalidationListener currentTabTextListener = observable -> updateTitle();
94  
95      @FXML
96      private TabPane mainTabPane;
97  
98      @FXML
99      private MainMenuBar mainMenuBar;
100 
101     @FXML
102     private MainToolBar mainToolBar;
103 
104     @FXML
105     private GridPane welcomePane;
106     @FXML
107     private StackPane stackPane;
108 
109     private DataAgent dataAgent = null;
110 
111     private PrefixesStorage appPrefixesStorage;
112     private ResourcesStorage appResourcesStorage;
113     private DataTypesStorage appDataTypesStorage;
114     private FunctionsStorage appFunctionsStorage;
115 
116     private String defaultTitle;
117     private int depth = 3;
118     private boolean loading = false;
119 
120     private final ReadOnlyStringWrapper titleProperty = new ReadOnlyStringWrapper();
121 
122     /**
123      * Zablokuje tlačítko Save, pokud nejsou v aktuální záložce neuložené změny.
124      */
125     private final ChangeListener<? super Boolean> currentTabHasChangesListener
126             = (observable, oldValue, newValue)
127             -> mainMenuBar.getMenuItemsQuery().get(MenuItemsQuery.getSaveOrdinal()).setDisable(oldValue);
128 
129     @Override
130     protected final void setup(final Object... args) {
131         dataAgent = (DataAgent) args[0];
132         watch(dataAgent);
133         titleProperty.addListener((observable) -> setTitle());
134         titleProperty.set(dataAgent.getStorageName());
135 
136         mainToolBar.initialize(this);
137         mainMenuBar.initialize(this);
138 
139         MainTabPaneListener.setupListeners(this);
140         MainTabPaneListener.onCurrentTabChanged(null, null, this);
141 
142         LocalStorageAction.loadStorages(this);
143         MainFormSetting.loadFormSettings(this);
144 
145     }
146 
147     /**
148      * Nastavi titulek okna na jmeno (adresu) uloziste
149      */
150     private void setTitle() {
151         defaultTitle = DEFAULT_TITLE + " (" + titleProperty.get() + ")"; //$NON-NLS-1$
152         updateTitle();
153     }
154 
155     /**
156      * It stores window size, maximization state and selected language into
157      * {@link Properties}. If the window is maximized size value is not stored.
158      */
159     public void saveFormSettings() {
160         MainFormSetting.saveFormSettings(this);
161     }
162 
163     /**
164      * The method creates context menu for the tab in parameter.
165      *
166      * @param ownerTab Owner tab of created context menu.
167      */
168     public void getContextMenu(Tab ownerTab) {
169         new TabContextMenu().getContextMenu(ownerTab, this);
170     }
171 
172     /**
173      * Serializuje seznamy do výchozího umístění.
174      *
175      * @throws IOException IO Exception.
176      */
177     public void storeObjects() throws IOException {
178         LocalStorageAction.storeObjects(this);
179     }
180 
181     /**
182      * Akce pri uzavreni aplikace
183      *
184      * @return false - chyba, true - ok
185      */
186     @Override
187     protected final boolean onCloseRequest() {
188         return ((MainTabPane) getMainTabPane()).onCloseRequest(this);
189     }
190 
191     /**
192      * Složí titulek okna ze standardní části {@link #defaultTitle} a titulku
193      * aktuálně vybrané záložky.
194      */
195     public void updateTitle() {
196         final Tab currentTab = ((MainTabPane) mainTabPane).getCurrentTab();
197         if (currentTab == null) {
198             setTitle(defaultTitle);
199             return;
200         }
201         setTitle(currentTab.getText() + " - " + defaultTitle); //$NON-NLS-1$
202     }
203 
204     /**
205      * Provede odpojení. Voláno paralelně z {@link #onCloseRequest()}.
206      *
207      * @throws SQLException SQL Exception.
208      */
209     public void disconnect() throws SQLException {
210         dataAgent.close();
211     }
212 
213     @FXML
214     private void open() {
215         MainMenuAction.open(this);
216     }
217 
218     /**
219      * Nastavi stav nacitani dotazu
220      *
221      * @param value true x false
222      */
223     public void setLoading(boolean value) {
224         this.loading = value;
225     }
226 
227     /**
228      * It returns relevant {@link QueryTab} due to parameter
229      * ({@link QueryFormPane}).
230      *
231      * @param queryFormPane {@link QueryFormPane} of wanted {@link QueryTab}.
232      *
233      * @return Relevant {@link QueryTab}.
234      */
235     public QueryTab getQueryTab(QueryFormPane queryFormPane) {
236         return ((MainTabPane) getMainTabPane()).getQueryTab(queryFormPane);
237     }
238 
239     /**
240      * It makes new SUBSELECT.
241      *
242      * @return New SUBSELECT.
243      */
244     public Tab createNewSubSelectQuery() {
245         return ((MainTabPane) getMainTabPane()).createQueryTab(MainTabPane.QueryType.SUBSELECT, this);
246     }
247 
248     @FXML
249     private void createNewSelectQuery() {
250         mainMenuBar.createNewSelectQueryOnAction();
251     }
252 
253     @FXML
254     private void createNewAskQuery() {
255         mainMenuBar.createNewAskQueryOnAction();
256     }
257 
258     @FXML
259     private void createNewConstructQuery() {
260         mainMenuBar.createNewConstructQueryOnAction();
261     }
262 
263     @FXML
264     private void createNewDescribeQuery() {
265         mainMenuBar.createNewDescribeQueryOnAction();
266     }
267 
268     @FXML
269     private void createNewDeleteInsertQuery() {
270         mainMenuBar.createNewDeleteInsertQueryOnAction();
271     }
272 
273     @FXML
274     private void createNewInsertQuery() {
275         mainMenuBar.createNewInsertQueryOnAction();
276     }
277 
278     @FXML
279     private void createNewDeleteQuery() {
280         mainMenuBar.createNewDeleteQueryOnAction();
281     }
282 
283     /**
284      * @return Aktivní {@link QueryTab} nebo <code>null</code>.
285      */
286     public QueryTab<?> getCurrentQueryTab() {
287         return ((MainTabPane) getMainTabPane()).getCurrentQueryTab();
288     }
289 
290     public void setDepth(int depth) {
291         this.depth = depth;
292     }
293 
294     public int getDepth() {
295         return this.depth;
296     }
297 
298     public TabPane getMainTabPane() {
299         return this.mainTabPane;
300     }
301 
302     public DataAgent getDataAgent() {
303         return dataAgent;
304     }
305 
306     public PrefixesStorage getAppPrefixesStorage() {
307         return appPrefixesStorage;
308     }
309 
310     public ResourcesStorage getAppResourcesStorage() {
311         return appResourcesStorage;
312     }
313 
314     public DataTypesStorage getAppDataTypesStorage() {
315         return appDataTypesStorage;
316     }
317 
318     public FunctionsStorage getAppFunctionsStorage() {
319         return appFunctionsStorage;
320     }
321 
322     public int getUnsavedTabsProperty() {
323         return unsavedTabsProperty.get();
324     }
325 
326     public IntegerProperty unsavedTabsPropertyProperty() {
327         return unsavedTabsProperty;
328     }
329 
330     public ChangeListener<? super Boolean> getTabHasChangesListener() {
331         return tabHasChangesListener;
332     }
333 
334     public InvalidationListener getCurrentTabTextListener() {
335         return currentTabTextListener;
336     }
337 
338     public GridPane getWelcomePane() {
339         return welcomePane;
340     }
341 
342     public StackPane getStackPane() {
343         return stackPane;
344     }
345 
346     public boolean isLoading() {
347         return loading;
348     }
349 
350     public ChangeListener<? super Boolean> getCurrentTabHasChangesListener() {
351         return currentTabHasChangesListener;
352     }
353 
354     void setAppPrefixesStorage(PrefixesStorage appPrefixesStorage) {
355         this.appPrefixesStorage = appPrefixesStorage;
356     }
357 
358     void setAppResourcesStorage(ResourcesStorage appResourcesStorage) {
359         this.appResourcesStorage = appResourcesStorage;
360     }
361 
362     void setAppDataTypesStorage(DataTypesStorage appDataTypesStorage) {
363         this.appDataTypesStorage = appDataTypesStorage;
364     }
365 
366     void setAppFunctionsStorage(FunctionsStorage appFunctionsStorage) {
367         this.appFunctionsStorage = appFunctionsStorage;
368     }
369 
370     public MainMenuBar getMainMenuBar() {
371         return mainMenuBar;
372     }
373 
374     public MainToolBar getMainToolBar() {
375         return mainToolBar;
376     }
377 
378     public void setDataAgent(DataAgent dataAgent) {
379         this.dataAgent = dataAgent;
380         titleProperty.set(dataAgent.getStorageName());
381         MainMenuAction.reInitBinding(this);
382 
383     }
384 
385     @Override
386     public Set<InvalidationListener> getObservers() {
387         return observers;
388     }
389 
390 }