View Javadoc
1   /*
2    * *************************************************************************************************************************************************************
3    *
4    * SteelBlue: DCI User Interfaces
5    * http://tidalwave.it/projects/steelblue
6    *
7    * Copyright (C) 2015 - 2024 by Tidalwave s.a.s. (http://tidalwave.it)
8    *
9    * *************************************************************************************************************************************************************
10   *
11   * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12   * You may obtain a copy of the License at
13   *
14   *     http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17   * CONDITIONS OF ANY KIND, either express or implied.  See the License for the specific language governing permissions and limitations under the License.
18   *
19   * *************************************************************************************************************************************************************
20   *
21   * git clone https://bitbucket.org/tidalwave/steelblue-src
22   * git clone https://github.com/tidalwave-it/steelblue-src
23   *
24   * *************************************************************************************************************************************************************
25   */
26  package it.tidalwave.role.ui.javafx;
27  
28  import javax.annotation.Nonnull;
29  import java.util.Collection;
30  import java.util.Optional;
31  import java.nio.file.Path;
32  import javafx.beans.property.Property;
33  import javafx.scene.Node;
34  import javafx.scene.control.ButtonBase;
35  import javafx.scene.control.ComboBox;
36  import javafx.scene.control.ListView;
37  import javafx.scene.control.MenuItem;
38  import javafx.scene.control.TableView;
39  import javafx.scene.control.TextField;
40  import javafx.scene.control.ToggleButton;
41  import javafx.scene.control.TreeTableView;
42  import javafx.scene.control.TreeView;
43  import javafx.scene.layout.GridPane;
44  import javafx.scene.layout.Pane;
45  import javafx.stage.Window;
46  import it.tidalwave.util.ui.UserNotification;
47  import it.tidalwave.util.ui.UserNotificationWithFeedback;
48  import it.tidalwave.role.ui.BoundProperty;
49  import it.tidalwave.role.ui.PresentationModel;
50  import it.tidalwave.role.ui.UserAction;
51  
52  /***************************************************************************************************************************************************************
53   *
54   * @author  Fabrizio Giudici
55   *
56   **************************************************************************************************************************************************************/
57  public interface JavaFXBinder
58    {
59      /***********************************************************************************************************************************************************
60       * Sets the main window. This operation must be performed before any other method is called. This operation is
61       * automatically performed by the SteelBlue runtime.
62       *
63       * @param   window      the main window
64       **********************************************************************************************************************************************************/
65      public void setMainWindow (@Nonnull Window window);
66  
67      /***********************************************************************************************************************************************************
68       * Binds a button to a {@link UserAction}. The following roles o the action are used:
69       *
70       * <ul>
71       * <li>Displayable: to set the label of the button</li>
72       * </ul>
73       *
74       * The action is used as a callback when the button is pressed; invoked in a thread provided by the binder executor.
75       * The {@code enabled} property of the {@code UserAction} is bound, negated, to the {@code disabled} property of the
76       * button.
77       *
78       * @param   button      the button
79       * @param   action      the action
80       **********************************************************************************************************************************************************/
81      public void bind (@Nonnull ButtonBase button, @Nonnull UserAction action);
82  
83      /***********************************************************************************************************************************************************
84       * Binds a menu item to a {@link UserAction}. The following roles o the action are used:
85       *
86       * <ul>
87       * <li>Displayable: to set the label of the menu item</li>
88       * </ul>
89       *
90       * The action is used as a callback when the button is pressed; invoked in a thread provided by the binder executor.
91       * The {@code enabled} property of the {@code UserAction} is bound, negated, to the {@code disabled} property of the
92       * menu item.
93       *
94       * @param   menuItem    the menu item
95       * @param   action      the action
96       **********************************************************************************************************************************************************/
97      public void bind (@Nonnull MenuItem menuItem, @Nonnull UserAction action);
98  
99      /***********************************************************************************************************************************************************
100      * Binds a {@link TableView} to a {@link PresentationModel} and an optional callback.
101      *
102      * The {@code PresentationModel} is used to populate the table. The following roles are used:
103      *
104      * <ul>
105      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
106      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
107      *     each column.</li>
108      * <li>A {@link it.tidalwave.role.ui.Displayable} (optional) is used to provide the text to render for each item.</li>
109      * <li>A {@link it.tidalwave.ui.role.javafx.CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
110      * <li>A {@link it.tidalwave.role.ui.Styleable} (optional) is used to provide the rendering style for each item.</li>
111      * <li>A {@link it.tidalwave.role.ui.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
112      *     the default action is also bound to the double click or SPACE gesture.</li>
113      * </ul>
114      *
115      * The process of populating data is performed in background threads, so this method quickly returns also in case
116      * of large amount of data.
117      * The initialization callback is called in the JavaFX thread when data population has been completed.
118      *
119      * @since   1.0-ALPHA-13
120      * @param   tableView       the {@code TablewView}
121      * @param   pm              the {@code PresentationModel}
122      * @param   initCallback    the callback
123      **********************************************************************************************************************************************************/
124     public void bind (@Nonnull TableView<PresentationModel> tableView,
125                       @Nonnull PresentationModel pm,
126                       @Nonnull Optional<Runnable> initCallback);
127 
128     /***********************************************************************************************************************************************************
129      * Binds a {@link TableView} to a {@link PresentationModel} and a callback.
130      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
131      *
132      * The process of populating data is performed in background threads, so this method quickly returns also in case
133      * of large amount of data.
134      * The initialization callback is called in the JavaFX thread when data population has been completed.
135      *
136      * @param   tableView       the {@code TablewView}
137      * @param   pm              the {@code PresentationModel}
138      * @param   initCallback    the callback
139      **********************************************************************************************************************************************************/
140     public default void bind (@Nonnull final TableView<PresentationModel> tableView,
141                               @Nonnull final PresentationModel pm,
142                               @Nonnull final Runnable initCallback)
143       {
144         bind(tableView, pm, Optional.of(initCallback));
145       }
146 
147     /***********************************************************************************************************************************************************
148      * Binds a {@link TableView} to a {@link PresentationModel}.
149      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
150      *
151      * @since   1.0-ALPHA-13
152      * @param   tableView       the {@code TablewView}
153      * @param   pm              the {@code PresentationModel}
154      **********************************************************************************************************************************************************/
155     public default void bind (@Nonnull final TableView<PresentationModel> tableView,
156                               @Nonnull final PresentationModel pm)
157       {
158         bind(tableView, pm, Optional.empty());
159       }
160 
161     /***********************************************************************************************************************************************************
162      * Binds a {@link TreeView} to a {@link PresentationModel} and a callback.
163      *
164      * The {@code PresentationModel} is used to populate the table. The following roles are used:
165      *
166      * <ul>
167      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
168      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
169      *     each column.</li>
170      * <li>A {@link it.tidalwave.role.ui.Displayable} (optional) is used to provide the text to render for each item.</li>
171      * <li>A {@link it.tidalwave.ui.role.javafx.CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
172      * <li>A {@link it.tidalwave.role.ui.Styleable} (optional) is used to provide the rendering style for each item.</li>
173      * <li>A {@link it.tidalwave.role.ui.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
174      *     the default action is also bound to the double click or SPACE gesture.</li>
175      * <li>A {@link it.tidalwave.role.ui.Visible} (optional) is used to decide whether the root node should be visible or not.</li>
176      * </ul>
177      *
178      * The process of populating data is performed in background threads, so this method quickly returns also in case
179      * of large amount of data.
180      * The initialization callback is called in the JavaFX thread when data population has been completed.
181      *
182      * @param   treeView        the {@code TreeView}
183      * @param   pm              the {@code PresentationModel}
184      * @param   initCallback    the callback
185      **********************************************************************************************************************************************************/
186     public void bind (@Nonnull TreeView<PresentationModel> treeView,
187                       @Nonnull PresentationModel pm,
188                       @Nonnull Optional<Runnable> initCallback);
189 
190     /***********************************************************************************************************************************************************
191      * Binds a {@link TableView} to a {@link PresentationModel} and a callback.
192      * See {@link #bind(javafx.scene.control.TreeView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
193      *
194      * @since   1.0-ALPHA-13
195      * @param   treeView        the {@code TreeView}
196      * @param   pm              the {@code PresentationModel}
197      * @param   initCallback    the callback
198      **********************************************************************************************************************************************************/
199     public default void bind (@Nonnull final TreeView<PresentationModel> treeView,
200                               @Nonnull final PresentationModel pm,
201                               @Nonnull final Runnable initCallback)
202       {
203         bind(treeView, pm, Optional.of(initCallback));
204       }
205 
206     /***********************************************************************************************************************************************************
207      * Binds a {@link TableView} to a {@link PresentationModel}.
208      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}
209      *
210      * @since   1.0-ALPHA-13
211      * @param   treeView        the {@code TreeView}
212      * @param   pm              the {@code PresentationModel}
213      **********************************************************************************************************************************************************/
214     public default void bind (@Nonnull final TreeView<PresentationModel> treeView,
215                               @Nonnull final PresentationModel pm)
216       {
217         bind(treeView, pm, Optional.empty());
218       }
219 
220     /***********************************************************************************************************************************************************
221      * Binds a {@link TreeTableView} to a {@link PresentationModel} and a callback.
222      *
223      * The {@code PresentationModel} is used to populate the table. The following roles are used:
224      *
225      * <ul>
226      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
227      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
228      *     each column.</li>
229      * <li>A {@link it.tidalwave.role.ui.Displayable} (optional) is used to provide the text to render for each item.</li>
230      * <li>A {@link it.tidalwave.ui.role.javafx.CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
231      * <li>A {@link it.tidalwave.role.ui.Styleable} (optional) is used to provide the rendering style for each item.</li>
232      * <li>A {@link it.tidalwave.role.ui.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
233      *     the default action is also bound to the double click or SPACE gesture.</li>
234      * <li>A {@link it.tidalwave.role.ui.Visible} (optional) is used to decide whether the root node should be visible or not.</li>
235      * </ul>
236      *
237      * The process of populating data is performed in background threads, so this method quickly returns also in case
238      * of large amount of data.
239      * The initialization callback is called in the JavaFX thread when data population has been completed.
240      *
241      * @param   treeTableView   the {@code TreeTableView}
242      * @param   pm              the {@code PresentationModel}
243      * @param   initCallback    the callback
244      **********************************************************************************************************************************************************/
245     public void bind (@Nonnull TreeTableView<PresentationModel> treeTableView,
246                       @Nonnull PresentationModel pm,
247                       @Nonnull Optional<Runnable> initCallback);
248 
249     /***********************************************************************************************************************************************************
250      * Binds a {@link TreeTableView} to a {@link PresentationModel} and a callback.
251      * See {@link #bind(javafx.scene.control.TreeTableView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
252      *
253      * @since   1.0-ALPHA-13
254      * @param   treeTableView   the {@code TreeTableView}
255      * @param   pm              the {@code PresentationModel}
256      * @param   initCallback    the callback
257      **********************************************************************************************************************************************************/
258     public default void bind (@Nonnull final TreeTableView<PresentationModel> treeTableView,
259                               @Nonnull final PresentationModel pm,
260                               @Nonnull final Runnable initCallback)
261       {
262         bind(treeTableView, pm, Optional.of(initCallback));
263       }
264 
265     /***********************************************************************************************************************************************************
266      * Binds a {@link TreeTableView} to a {@link PresentationModel}.
267      * See {@link #bind(javafx.scene.control.TreeTableView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
268      *
269      * @since   1.0-ALPHA-13
270      * @param   treeTableView   the {@code TreeTableView}
271      * @param   pm              the {@code PresentationModel}
272      **********************************************************************************************************************************************************/
273     public default void bind (@Nonnull final TreeTableView<PresentationModel> treeTableView,
274                               @Nonnull final PresentationModel pm)
275       {
276         bind(treeTableView, pm, Optional.empty());
277       }
278 
279     /***********************************************************************************************************************************************************
280      * Binds a {@link ListView} to a {@link PresentationModel} and an optional callback.
281      *
282      * The {@code PresentationModel} is used to populate the table. The following roles are used:
283      *
284      * <ul>
285      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
286      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
287      *     each column.</li>
288      * <li>A {@link it.tidalwave.role.ui.Displayable} (optional) is used to provide the text to render for each item.</li>
289      * <li>A {@link it.tidalwave.ui.role.javafx.CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
290      * <li>A {@link it.tidalwave.role.ui.Styleable} (optional) is used to provide the rendering style for each item.</li>
291      * <li>A {@link it.tidalwave.role.ui.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
292      *     the default action is also bound to the double click or SPACE gesture.</li>
293      * </ul>
294      *
295      * The process of populating data is performed in background threads, so this method quickly returns also in case
296      * of large amount of data.
297      * The initialization callback is called in the JavaFX thread when data population has been completed.
298      *
299      * @param   listView        the {@code ListView}
300      * @param   pm              the {@code PresentationModel}
301      * @param   initCallback    the callback
302      **********************************************************************************************************************************************************/
303     public void bind (@Nonnull ListView<PresentationModel> listView,
304                       @Nonnull PresentationModel pm,
305                       @Nonnull Optional<Runnable> initCallback);
306 
307     /***********************************************************************************************************************************************************
308      * Binds a {@link ListView} to a {@link PresentationModel} and a callback.
309      * See {@link #bind(javafx.scene.control.ListView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
310      *
311      * @since   1.0-ALPHA-13
312      * @param   listView        the {@code ListView}
313      * @param   pm              the {@code PresentationModel}
314      * @param   initCallback    the callback
315      **********************************************************************************************************************************************************/
316     public default void bind (@Nonnull final ListView<PresentationModel> listView,
317                               @Nonnull final PresentationModel pm,
318                               @Nonnull final Runnable initCallback)
319       {
320         bind(listView, pm, Optional.of(initCallback));
321       }
322 
323     /***********************************************************************************************************************************************************
324      * Binds a {@link ComboBox} to a {@link PresentationModel}.
325      * See {@link #bind(javafx.scene.control.ListView, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
326      *
327      * @since   1.0-ALPHA-13
328      * @param   listView        the {@code ListView}
329      * @param   pm              the {@code PresentationModel}
330      **********************************************************************************************************************************************************/
331     public default void bind (@Nonnull final ListView<PresentationModel> listView,
332                               @Nonnull final PresentationModel pm)
333       {
334         bind(listView, pm, Optional.empty());
335       }
336 
337     /***********************************************************************************************************************************************************
338      * Binds a {@link ComboBox} to a {@link PresentationModel} and an optional callback.
339      *
340      * The {@code PresentationModel} is used to populate the table. The following roles are used:
341      *
342      * <ul>
343      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
344      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
345      *     each column.</li>
346      * <li>A {@link it.tidalwave.role.ui.Displayable} (optional) is used to provide the text to render for each item.</li>
347      * <li>A {@link it.tidalwave.ui.role.javafx.CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
348      * <li>A {@link it.tidalwave.role.ui.Styleable} (optional) is used to provide the rendering style for each item.</li>
349      * <li>A {@link it.tidalwave.role.ui.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
350      *     the default action is also bound to the double click or SPACE gesture.</li>
351      * </ul>
352      *
353      * The process of populating data is performed in background threads, so this method quickly returns also in case
354      * of large amount of data.
355      * The initialization callback is called in the JavaFX thread when data population has been completed.
356      *
357      * @param   comboBox        the {@code ComboBox}
358      * @param   pm              the {@code PresentationModel}
359      * @param   initCallback    the callback
360      **********************************************************************************************************************************************************/
361     public void bind (@Nonnull ComboBox<PresentationModel> comboBox,
362                       @Nonnull PresentationModel pm,
363                       @Nonnull Optional<Runnable> initCallback);
364 
365     /***********************************************************************************************************************************************************
366      * Binds a {@link ComboBox} to a {@link PresentationModel} and a callback.
367      * See {@link #bind(javafx.scene.control.ComboBox, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
368      *
369      * @since   1.0-ALPHA-13
370      * @param   comboBox        the {@code ComboBox}
371      * @param   pm              the {@code PresentationModel}
372      * @param   initCallback    the callback
373      **********************************************************************************************************************************************************/
374     public default void bind (@Nonnull final ComboBox<PresentationModel> comboBox,
375                               @Nonnull final PresentationModel pm,
376                               @Nonnull final Runnable initCallback)
377       {
378         bind(comboBox, pm, Optional.of(initCallback));
379       }
380 
381     /***********************************************************************************************************************************************************
382      * Binds a {@link ComboBox} to a {@link PresentationModel}.
383      * See {@link #bind(javafx.scene.control.ComboBox, it.tidalwave.role.ui.PresentationModel, java.util.Optional)}.
384      *
385      * @since   1.0-ALPHA-13
386      * @param   comboBox        the {@code ComboBox}
387      * @param   pm              the {@code PresentationModel}
388      **********************************************************************************************************************************************************/
389     public default void bind (@Nonnull final ComboBox<PresentationModel> comboBox,
390                               @Nonnull final PresentationModel pm)
391       {
392         bind(comboBox, pm, Optional.empty());
393       }
394 
395     /***********************************************************************************************************************************************************
396      * Given a {@link PresentationModel} that contains a {@link it.tidalwave.role.Composite}, populate the pane with
397      * {@link ToggleButton}s associated to the elements of the {@link it.tidalwave.role.Composite}. Each element is searched for the
398      * following roles:
399      *
400      * <ul>
401      * <li>{@link it.tidalwave.role.ui.UserActionProvider} (mandatory) to provide a callback for the button</li>
402      * <li>{@link it.tidalwave.role.ui.Displayable} to provide a text for the button</li>
403      * <li>{@link it.tidalwave.role.ui.Styleable} to provide a CSS style for the button</li>
404      * </ul>
405      *
406      * The pane must be pre-populated with at least one button, which will be queried for the CSS style.
407      *
408      * @param   pane        the {@code Pane}
409      * @param   pm          the {@code PresentationModel}
410      **********************************************************************************************************************************************************/
411     public void bindToggleButtons (@Nonnull Pane pane, @Nonnull PresentationModel pm);
412 
413     /***********************************************************************************************************************************************************
414      * Deprecated. Merge to bindToggleButtons, passing some arguments for choosing toggle or normal buttons.
415      *
416      * @deprecated
417      **********************************************************************************************************************************************************/
418     @Deprecated
419     public void bindButtonsInPane (@Nonnull GridPane gridPane, @Nonnull Collection<UserAction> actions);
420 
421     /***********************************************************************************************************************************************************
422      * Bidirectionally binds two properties.
423      *
424      * @param   <T>         the property type
425      * @param   property1   the former property
426      * @param   property2   the latter property
427      **********************************************************************************************************************************************************/
428     public <T> void bindBidirectionally (@Nonnull Property<T> property1, @Nonnull BoundProperty<T> property2);
429 
430     /***********************************************************************************************************************************************************
431      *
432      **********************************************************************************************************************************************************/
433     public <T> void bindBidirectionally (@Nonnull TextField textField,
434                                          @Nonnull BoundProperty<String> textProperty,
435                                          @Nonnull BoundProperty<Boolean> validProperty);
436 
437     /***********************************************************************************************************************************************************
438      * Shows a modal dialog with the given content and provides feedback by means of the given notification.
439      *
440      * @param   notification  the object notifying whether the operation is confirmed or cancelled
441      * @since   1.1-ALPHA-6
442      **********************************************************************************************************************************************************/
443     public default void showInModalDialog (@Nonnull final UserNotification notification)
444       {
445         showInModalDialog(UserNotificationWithFeedback.notificationWithFeedback()
446                                                       .withCaption(notification.getCaption())
447                                                       .withText(notification.getText()));
448       }
449 
450     /***********************************************************************************************************************************************************
451      * Shows a modal dialog with the given content and provides feedback by means of the given notification.
452      *
453      * @param  node          the dialog content
454      * @param  notification  the object notifying whether the operation is confirmed or cancelled
455      **********************************************************************************************************************************************************/
456     public void showInModalDialog (@Nonnull UserNotificationWithFeedback notification,
457                                    @Nonnull Optional<Node> node);
458 
459     // FIXME: use a Builder, merge with the above
460     public default void showInModalDialog (@Nonnull final Node node,
461                                            @Nonnull final UserNotificationWithFeedback notification,
462                                            @Nonnull final BoundProperty<Boolean> valid)
463       {
464         showInModalDialog(notification, Optional.of(node));
465       }
466 
467     @Deprecated
468     public default void showInModalDialog (@Nonnull final Node node,
469                                            @Nonnull final UserNotificationWithFeedback notification)
470       {
471         showInModalDialog(notification, Optional.of(node));
472       }
473 
474     public default void showInModalDialog (@Nonnull final UserNotificationWithFeedback notification)
475       {
476         showInModalDialog(notification, Optional.empty());
477       }
478 
479     /***********************************************************************************************************************************************************
480      * Opens the FileChooser for selecting a file. The outcome of the operation (confirmed or cancelled) will be
481      * notified to the given notification object. The selected file will be set to the given bound property, which can
482      * be also used to set the default value rendered on the FileChooser.
483      *
484      * @param  notification  the object notifying whether the operation is confirmed or cancelled
485      * @param  selectedFile  the property containing the selected file
486      **********************************************************************************************************************************************************/
487     public void openFileChooserFor (@Nonnull UserNotificationWithFeedback notification,
488                                     @Nonnull BoundProperty<Path> selectedFile);
489 
490     /***********************************************************************************************************************************************************
491      * Opens the FileChooser for selecting a folder. The outcome of the operation (confirmed or cancelled) will be
492      * notified to the given notification object. The selected folder will be set to the given bound property, which can
493      * be also used to set the default value rendered on the FileChooser.
494      *
495      * @param  notification    the object notifying whether the operation is confirmed or cancelled
496      * @param  selectedFolder  the property containing the selected folder
497      **********************************************************************************************************************************************************/
498     public void openDirectoryChooserFor (@Nonnull UserNotificationWithFeedback notification,
499                                          @Nonnull BoundProperty<Path> selectedFolder);
500   }