View Javadoc
1   /*
2    * *************************************************************************************************************************************************************
3    *
4    * SteelBlue: DCI User Interfaces
5    * http://tidalwave.it/projects/steelblue
6    *
7    * Copyright (C) 2015 - 2025 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.ui.javafx;
27  
28  import jakarta.annotation.Nonnull;
29  import java.util.Collection;
30  import java.util.Optional;
31  import java.util.function.Function;
32  import java.nio.file.Path;
33  import javafx.beans.property.BooleanProperty;
34  import javafx.beans.property.DoubleProperty;
35  import javafx.beans.property.IntegerProperty;
36  import javafx.beans.property.LongProperty;
37  import javafx.beans.property.Property;
38  import javafx.scene.Node;
39  import javafx.scene.control.ButtonBase;
40  import javafx.scene.control.ComboBox;
41  import javafx.scene.control.ListView;
42  import javafx.scene.control.MenuItem;
43  import javafx.scene.control.TableView;
44  import javafx.scene.control.TextField;
45  import javafx.scene.control.ToggleButton;
46  import javafx.scene.control.TreeTableView;
47  import javafx.scene.control.TreeView;
48  import javafx.scene.layout.GridPane;
49  import javafx.scene.layout.Pane;
50  import javafx.stage.Window;
51  import it.tidalwave.ui.core.role.Visibility;
52  import it.tidalwave.ui.javafx.role.CustomGraphicProvider;
53  import it.tidalwave.util.ui.UserNotification;
54  import it.tidalwave.util.ui.UserNotificationWithFeedback;
55  import it.tidalwave.ui.core.BoundProperty;
56  import it.tidalwave.ui.core.role.PresentationModel;
57  import it.tidalwave.ui.core.role.UserAction;
58  
59  /***************************************************************************************************************************************************************
60   *
61   * @author  Fabrizio Giudici
62   *
63   **************************************************************************************************************************************************************/
64  public interface JavaFXBinder
65    {
66      /***********************************************************************************************************************************************************
67       * Sets the main window. This operation must be performed before any other method is called. This operation is
68       * automatically performed by the SteelBlue runtime.
69       *
70       * @param   window      the main window
71       **********************************************************************************************************************************************************/
72      public void setMainWindow (@Nonnull Window window);
73  
74      /***********************************************************************************************************************************************************
75       * Binds a button to a {@link UserAction}. The following roles o the action are used:
76       *
77       * <ul>
78       * <li>Displayable: to set the label of the button</li>
79       * </ul>
80       *
81       * The action is used as a callback when the button is pressed; invoked in a thread provided by the binder executor.
82       * The {@code enabled} property of the {@code UserAction} is bound, negated, to the {@code disabled} property of the
83       * button.
84       *
85       * @param   button      the button
86       * @param   action      the action
87       **********************************************************************************************************************************************************/
88      public void bind (@Nonnull ButtonBase button, @Nonnull UserAction action);
89  
90      /***********************************************************************************************************************************************************
91       * Binds a menu item to a {@link UserAction}. The following roles o the action are used:
92       *
93       * <ul>
94       * <li>Displayable: to set the label of the menu item</li>
95       * </ul>
96       *
97       * The action is used as a callback when the button is pressed; invoked in a thread provided by the binder executor.
98       * The {@code enabled} property of the {@code UserAction} is bound, negated, to the {@code disabled} property of the
99       * menu item.
100      *
101      * @param   menuItem    the menu item
102      * @param   action      the action
103      **********************************************************************************************************************************************************/
104     public void bind (@Nonnull MenuItem menuItem, @Nonnull UserAction action);
105 
106     /***********************************************************************************************************************************************************
107      * Binds a {@link TableView} to a {@link PresentationModel} and an optional callback.
108      *
109      * The {@code PresentationModel} is used to populate the table. The following roles are used:
110      *
111      * <ul>
112      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
113      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
114      *     each column.</li>
115      * <li>A {@link it.tidalwave.ui.core.role.Displayable} (optional) is used to provide the text to render for each item.</li>
116      * <li>A {@link CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
117      * <li>A {@link it.tidalwave.ui.core.role.Styleable} (optional) is used to provide the rendering style for each item.</li>
118      * <li>A {@link it.tidalwave.ui.core.role.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
119      *     the default action is also bound to the double click or SPACE gesture.</li>
120      * </ul>
121      *
122      * The process of populating data is performed in background threads, so this method quickly returns also in case
123      * of large amount of data.
124      * The initialization callback is called in the JavaFX thread when data population has been completed.
125      *
126      * @since   1.0-ALPHA-13
127      * @param   tableView       the {@code TablewView}
128      * @param   pm              the {@code PresentationModel}
129      * @param   initCallback    the callback
130      **********************************************************************************************************************************************************/
131     public void bind (@Nonnull TableView<PresentationModel> tableView,
132                       @Nonnull PresentationModel pm,
133                       @Nonnull Optional<Runnable> initCallback);
134 
135     /***********************************************************************************************************************************************************
136      * Binds a {@link TableView} to a {@link PresentationModel} and a callback.
137      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
138      *
139      * The process of populating data is performed in background threads, so this method quickly returns also in case
140      * of large amount of data.
141      * The initialization callback is called in the JavaFX thread when data population has been completed.
142      *
143      * @param   tableView       the {@code TablewView}
144      * @param   pm              the {@code PresentationModel}
145      * @param   initCallback    the callback
146      **********************************************************************************************************************************************************/
147     public default void bind (@Nonnull final TableView<PresentationModel> tableView,
148                               @Nonnull final PresentationModel pm,
149                               @Nonnull final Runnable initCallback)
150       {
151         bind(tableView, pm, Optional.of(initCallback));
152       }
153 
154     /***********************************************************************************************************************************************************
155      * Binds a {@link TableView} to a {@link PresentationModel}.
156      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
157      *
158      * @since   1.0-ALPHA-13
159      * @param   tableView       the {@code TablewView}
160      * @param   pm              the {@code PresentationModel}
161      **********************************************************************************************************************************************************/
162     public default void bind (@Nonnull final TableView<PresentationModel> tableView,
163                               @Nonnull final PresentationModel pm)
164       {
165         bind(tableView, pm, Optional.empty());
166       }
167 
168     /***********************************************************************************************************************************************************
169      * Binds a {@link TreeView} to a {@link PresentationModel} and a callback.
170      *
171      * The {@code PresentationModel} is used to populate the table. The following roles are used:
172      *
173      * <ul>
174      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
175      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
176      *     each column.</li>
177      * <li>A {@link it.tidalwave.ui.core.role.Displayable} (optional) is used to provide the text to render for each item.</li>
178      * <li>A {@link CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
179      * <li>A {@link it.tidalwave.ui.core.role.Styleable} (optional) is used to provide the rendering style for each item.</li>
180      * <li>A {@link it.tidalwave.ui.core.role.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
181      *     the default action is also bound to the double click or SPACE gesture.</li>
182      * <li>A {@link Visibility} (optional) is used to decide whether the root node should be visible or not.</li>
183      * </ul>
184      *
185      * The process of populating data is performed in background threads, so this method quickly returns also in case
186      * of large amount of data.
187      * The initialization callback is called in the JavaFX thread when data population has been completed.
188      *
189      * @param   treeView        the {@code TreeView}
190      * @param   pm              the {@code PresentationModel}
191      * @param   initCallback    the callback
192      **********************************************************************************************************************************************************/
193     public void bind (@Nonnull TreeView<PresentationModel> treeView,
194                       @Nonnull PresentationModel pm,
195                       @Nonnull Optional<Runnable> initCallback);
196 
197     /***********************************************************************************************************************************************************
198      * Binds a {@link TableView} to a {@link PresentationModel} and a callback.
199      * See {@link #bind(javafx.scene.control.TreeView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
200      *
201      * @since   1.0-ALPHA-13
202      * @param   treeView        the {@code TreeView}
203      * @param   pm              the {@code PresentationModel}
204      * @param   initCallback    the callback
205      **********************************************************************************************************************************************************/
206     public default void bind (@Nonnull final TreeView<PresentationModel> treeView,
207                               @Nonnull final PresentationModel pm,
208                               @Nonnull final Runnable initCallback)
209       {
210         bind(treeView, pm, Optional.of(initCallback));
211       }
212 
213     /***********************************************************************************************************************************************************
214      * Binds a {@link TableView} to a {@link PresentationModel}.
215      * See {@link #bind(javafx.scene.control.TableView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}
216      *
217      * @since   1.0-ALPHA-13
218      * @param   treeView        the {@code TreeView}
219      * @param   pm              the {@code PresentationModel}
220      **********************************************************************************************************************************************************/
221     public default void bind (@Nonnull final TreeView<PresentationModel> treeView,
222                               @Nonnull final PresentationModel pm)
223       {
224         bind(treeView, pm, Optional.empty());
225       }
226 
227     /***********************************************************************************************************************************************************
228      * Binds a {@link TreeTableView} to a {@link PresentationModel} and a callback.
229      *
230      * The {@code PresentationModel} is used to populate the table. The following roles are used:
231      *
232      * <ul>
233      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
234      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
235      *     each column.</li>
236      * <li>A {@link it.tidalwave.ui.core.role.Displayable} (optional) is used to provide the text to render for each item.</li>
237      * <li>A {@link CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
238      * <li>A {@link it.tidalwave.ui.core.role.Styleable} (optional) is used to provide the rendering style for each item.</li>
239      * <li>A {@link it.tidalwave.ui.core.role.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
240      *     the default action is also bound to the double click or SPACE gesture.</li>
241      * <li>A {@link Visibility} (optional) is used to decide whether the root node should be visible or not.</li>
242      * </ul>
243      *
244      * The process of populating data is performed in background threads, so this method quickly returns also in case
245      * of large amount of data.
246      * The initialization callback is called in the JavaFX thread when data population has been completed.
247      *
248      * @param   treeTableView   the {@code TreeTableView}
249      * @param   pm              the {@code PresentationModel}
250      * @param   initCallback    the callback
251      **********************************************************************************************************************************************************/
252     public void bind (@Nonnull TreeTableView<PresentationModel> treeTableView,
253                       @Nonnull PresentationModel pm,
254                       @Nonnull Optional<Runnable> initCallback);
255 
256     /***********************************************************************************************************************************************************
257      * Binds a {@link TreeTableView} to a {@link PresentationModel} and a callback.
258      * See {@link #bind(javafx.scene.control.TreeTableView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
259      *
260      * @since   1.0-ALPHA-13
261      * @param   treeTableView   the {@code TreeTableView}
262      * @param   pm              the {@code PresentationModel}
263      * @param   initCallback    the callback
264      **********************************************************************************************************************************************************/
265     public default void bind (@Nonnull final TreeTableView<PresentationModel> treeTableView,
266                               @Nonnull final PresentationModel pm,
267                               @Nonnull final Runnable initCallback)
268       {
269         bind(treeTableView, pm, Optional.of(initCallback));
270       }
271 
272     /***********************************************************************************************************************************************************
273      * Binds a {@link TreeTableView} to a {@link PresentationModel}.
274      * See {@link #bind(javafx.scene.control.TreeTableView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
275      *
276      * @since   1.0-ALPHA-13
277      * @param   treeTableView   the {@code TreeTableView}
278      * @param   pm              the {@code PresentationModel}
279      **********************************************************************************************************************************************************/
280     public default void bind (@Nonnull final TreeTableView<PresentationModel> treeTableView,
281                               @Nonnull final PresentationModel pm)
282       {
283         bind(treeTableView, pm, Optional.empty());
284       }
285 
286     /***********************************************************************************************************************************************************
287      * Binds a {@link ListView} to a {@link PresentationModel} and an optional callback.
288      *
289      * The {@code PresentationModel} is used to populate the table. The following roles are used:
290      *
291      * <ul>
292      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
293      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
294      *     each column.</li>
295      * <li>A {@link it.tidalwave.ui.core.role.Displayable} (optional) is used to provide the text to render for each item.</li>
296      * <li>A {@link CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
297      * <li>A {@link it.tidalwave.ui.core.role.Styleable} (optional) is used to provide the rendering style for each item.</li>
298      * <li>A {@link it.tidalwave.ui.core.role.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
299      *     the default action is also bound to the double click or SPACE gesture.</li>
300      * </ul>
301      *
302      * The process of populating data is performed in background threads, so this method quickly returns also in case
303      * of large amount of data.
304      * The initialization callback is called in the JavaFX thread when data population has been completed.
305      *
306      * @param   listView        the {@code ListView}
307      * @param   pm              the {@code PresentationModel}
308      * @param   initCallback    the callback
309      **********************************************************************************************************************************************************/
310     public void bind (@Nonnull ListView<PresentationModel> listView,
311                       @Nonnull PresentationModel pm,
312                       @Nonnull Optional<Runnable> initCallback);
313 
314     /***********************************************************************************************************************************************************
315      * Binds a {@link ListView} to a {@link PresentationModel} and a callback.
316      * See {@link #bind(javafx.scene.control.ListView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
317      *
318      * @since   1.0-ALPHA-13
319      * @param   listView        the {@code ListView}
320      * @param   pm              the {@code PresentationModel}
321      * @param   initCallback    the callback
322      **********************************************************************************************************************************************************/
323     public default void bind (@Nonnull final ListView<PresentationModel> listView,
324                               @Nonnull final PresentationModel pm,
325                               @Nonnull final Runnable initCallback)
326       {
327         bind(listView, pm, Optional.of(initCallback));
328       }
329 
330     /***********************************************************************************************************************************************************
331      * Binds a {@link ComboBox} to a {@link PresentationModel}.
332      * See {@link #bind(javafx.scene.control.ListView, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
333      *
334      * @since   1.0-ALPHA-13
335      * @param   listView        the {@code ListView}
336      * @param   pm              the {@code PresentationModel}
337      **********************************************************************************************************************************************************/
338     public default void bind (@Nonnull final ListView<PresentationModel> listView,
339                               @Nonnull final PresentationModel pm)
340       {
341         bind(listView, pm, Optional.empty());
342       }
343 
344     /***********************************************************************************************************************************************************
345      * Binds a {@link ComboBox} to a {@link PresentationModel} and an optional callback.
346      *
347      * The {@code PresentationModel} is used to populate the table. The following roles are used:
348      *
349      * <ul>
350      * <li>A {@link it.tidalwave.role.SimpleComposite} provides children {@code PresentationModel}s for each row.</li>
351      * <li>In each row, an {@link it.tidalwave.role.Aggregate<PresentationModel>} is used to provide the {@code PresentationModel}s for
352      *     each column.</li>
353      * <li>A {@link it.tidalwave.ui.core.role.Displayable} (optional) is used to provide the text to render for each item.</li>
354      * <li>A {@link CustomGraphicProvider} (optional) is used to provide the graphics to render for each item.</li>
355      * <li>A {@link it.tidalwave.ui.core.role.Styleable} (optional) is used to provide the rendering style for each item.</li>
356      * <li>A {@link it.tidalwave.ui.core.role.UserActionProvider} (optional) is used to provide the actions for creating a context menu;
357      *     the default action is also bound to the double click or SPACE gesture.</li>
358      * </ul>
359      *
360      * The process of populating data is performed in background threads, so this method quickly returns also in case
361      * of large amount of data.
362      * The initialization callback is called in the JavaFX thread when data population has been completed.
363      *
364      * @param   comboBox        the {@code ComboBox}
365      * @param   pm              the {@code PresentationModel}
366      * @param   initCallback    the callback
367      **********************************************************************************************************************************************************/
368     public void bind (@Nonnull ComboBox<PresentationModel> comboBox,
369                       @Nonnull PresentationModel pm,
370                       @Nonnull Optional<Runnable> initCallback);
371 
372     /***********************************************************************************************************************************************************
373      * Binds a {@link ComboBox} to a {@link PresentationModel} and a callback.
374      * See {@link #bind(javafx.scene.control.ComboBox, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
375      *
376      * @since   1.0-ALPHA-13
377      * @param   comboBox        the {@code ComboBox}
378      * @param   pm              the {@code PresentationModel}
379      * @param   initCallback    the callback
380      **********************************************************************************************************************************************************/
381     public default void bind (@Nonnull final ComboBox<PresentationModel> comboBox,
382                               @Nonnull final PresentationModel pm,
383                               @Nonnull final Runnable initCallback)
384       {
385         bind(comboBox, pm, Optional.of(initCallback));
386       }
387 
388     /***********************************************************************************************************************************************************
389      * Binds a {@link ComboBox} to a {@link PresentationModel}.
390      * See {@link #bind(javafx.scene.control.ComboBox, it.tidalwave.ui.core.role.PresentationModel, java.util.Optional)}.
391      *
392      * @since   1.0-ALPHA-13
393      * @param   comboBox        the {@code ComboBox}
394      * @param   pm              the {@code PresentationModel}
395      **********************************************************************************************************************************************************/
396     public default void bind (@Nonnull final ComboBox<PresentationModel> comboBox,
397                               @Nonnull final PresentationModel pm)
398       {
399         bind(comboBox, pm, Optional.empty());
400       }
401 
402     /***********************************************************************************************************************************************************
403      * Given a {@link PresentationModel} that contains a {@link it.tidalwave.role.Composite}, populate the pane with
404      * {@link ToggleButton}s associated to the elements of the {@link it.tidalwave.role.Composite}. Each element is searched for the
405      * following roles:
406      *
407      * <ul>
408      * <li>{@link it.tidalwave.ui.core.role.UserActionProvider} (mandatory) to provide a callback for the button</li>
409      * <li>{@link it.tidalwave.ui.core.role.Displayable} to provide a text for the button</li>
410      * <li>{@link it.tidalwave.ui.core.role.Styleable} to provide a CSS style for the button</li>
411      * </ul>
412      *
413      * The pane must be pre-populated with at least one button, which will be queried for the CSS style.
414      *
415      * @param   pane        the {@code Pane}
416      * @param   pm          the {@code PresentationModel}
417      **********************************************************************************************************************************************************/
418     public void bindToggleButtons (@Nonnull Pane pane, @Nonnull PresentationModel pm);
419 
420     /***********************************************************************************************************************************************************
421      * Deprecated. Merge to bindToggleButtons, passing some arguments for choosing toggle or normal buttons.
422      *
423      * @deprecated
424      **********************************************************************************************************************************************************/
425     @Deprecated
426     public void bindButtonsInPane (@Nonnull GridPane gridPane, @Nonnull Collection<UserAction> actions);
427 
428     /***********************************************************************************************************************************************************
429      * Binds two properties of different types.
430      * @param   <T>             the target property type
431      * @param   <S>             the source property type
432      * @param   target          the target property
433      * @param   source          the source property
434      * @param   adapter         an adapter from one source to the target
435      * @since   2.0-ALPHA-1
436      **********************************************************************************************************************************************************/
437     public <T, S> void bind (@Nonnull final BoundProperty<? super T> target,
438                              @Nonnull final Property<? extends S> source,
439                              @Nonnull final Function<S, T> adapter);
440 
441     /***********************************************************************************************************************************************************
442      * Binds two properties of the same type.
443      * @param   <T>             the property type
444      * @param   target          the target property
445      * @param   source          the source property
446      * @since   2.0-ALPHA-1
447      **********************************************************************************************************************************************************/
448     public default <T> void bind (@Nonnull final BoundProperty<? super T> target, @Nonnull final Property<T> source)
449       {
450         bind(target, source, Function.identity());
451       }
452 
453     /***********************************************************************************************************************************************************
454      * Bidirectionally binds two properties of different types.
455      * @param   <T>             the former property type
456      * @param   <S>             the latter property type
457      * @param   property1       the former property
458      * @param   property2       the latter property
459      * @param   adapter         an adapter from one type to the other
460      * @param   reverseAdapter  the reverse adapter
461      * @since   2.0-ALPHA-1
462      **********************************************************************************************************************************************************/
463     public <T, S> void bindBidirectionally (@Nonnull final BoundProperty<? super T> property1,
464                                             @Nonnull final Property<S> property2,
465                                             @Nonnull final Function<? super S, T> adapter,
466                                             @Nonnull final Function<? super T, ? extends S> reverseAdapter);
467 
468     /***********************************************************************************************************************************************************
469      * {@inheritDoc}
470      **********************************************************************************************************************************************************/
471     public default <T> void bindBidirectionally (@Nonnull final BoundProperty<? super T> property1, @Nonnull final Property<T> property2)
472       {
473         bindBidirectionally(property1, property2, Function.identity(), Function.identity());
474       }
475 
476     /***********************************************************************************************************************************************************
477      * Bidirectionally binds two properties.
478      * @param   property1   the former property
479      * @param   property2   the latter property
480      **********************************************************************************************************************************************************/
481     public default void bindBidirectionally (@Nonnull final BoundProperty<? super Boolean> property1, @Nonnull final BooleanProperty property2)
482       {
483         bindBidirectionally(property1, property2, a -> a, a -> a);
484       }
485 
486     /***********************************************************************************************************************************************************
487      * Bidirectionally binds two properties.
488      * @param   property1   the former property
489      * @param   property2   the latter property
490      **********************************************************************************************************************************************************/
491     public default void bindBidirectionally (@Nonnull final BoundProperty<? super Integer> property1, @Nonnull final IntegerProperty property2)
492       {
493         bindBidirectionally(property1, property2, Number::intValue, a -> a);
494       }
495 
496     /***********************************************************************************************************************************************************
497      * Bidirectionally binds two properties.
498      * @param   property1   the former property
499      * @param   property2   the latter property
500      **********************************************************************************************************************************************************/
501     public default void bindBidirectionally (@Nonnull final BoundProperty<? super Long> property1, @Nonnull final LongProperty property2)
502       {
503         bindBidirectionally(property1, property2, Number::longValue, a -> a);
504       }
505 
506     /***********************************************************************************************************************************************************
507      * Bidirectionally binds two properties.
508      * @param   property1   the former property
509      * @param   property2   the latter property
510      **********************************************************************************************************************************************************/
511     public default void bindBidirectionally (@Nonnull final BoundProperty<? super Double> property1, @Nonnull final DoubleProperty property2)
512       {
513         bindBidirectionally(property1, property2, Number::doubleValue, a -> a);
514       }
515 
516     /***********************************************************************************************************************************************************
517      *
518      **********************************************************************************************************************************************************/
519     public void bindBidirectionally (@Nonnull TextField textField,
520                                      @Nonnull BoundProperty<String> textProperty,
521                                      @Nonnull BoundProperty<Boolean> validProperty);
522 
523     /***********************************************************************************************************************************************************
524      * Shows a modal dialog with the given content and provides feedback by means of the given notification.
525      *
526      * @param   notification  the object notifying whether the operation is confirmed or cancelled
527      * @since   1.1-ALPHA-6
528      **********************************************************************************************************************************************************/
529     public default void showInModalDialog (@Nonnull final UserNotification notification)
530       {
531         showInModalDialog(UserNotificationWithFeedback.notificationWithFeedback()
532                                                       .withCaption(notification.getCaption())
533                                                       .withText(notification.getText()));
534       }
535 
536     /***********************************************************************************************************************************************************
537      * Shows a modal dialog with the given content and provides feedback by means of the given notification.
538      *
539      * @param  node          the dialog content
540      * @param  notification  the object notifying whether the operation is confirmed or cancelled
541      **********************************************************************************************************************************************************/
542     public void showInModalDialog (@Nonnull UserNotificationWithFeedback notification,
543                                    @Nonnull Optional<Node> node);
544 
545     // FIXME: use a Builder, merge with the above
546     public default void showInModalDialog (@Nonnull final Node node,
547                                            @Nonnull final UserNotificationWithFeedback notification,
548                                            @Nonnull final BoundProperty<Boolean> valid)
549       {
550         showInModalDialog(notification, Optional.of(node));
551       }
552 
553     @Deprecated
554     public default void showInModalDialog (@Nonnull final Node node,
555                                            @Nonnull final UserNotificationWithFeedback notification)
556       {
557         showInModalDialog(notification, Optional.of(node));
558       }
559 
560     public default void showInModalDialog (@Nonnull final UserNotificationWithFeedback notification)
561       {
562         showInModalDialog(notification, Optional.empty());
563       }
564 
565     /***********************************************************************************************************************************************************
566      * Opens the FileChooser for selecting a file. The outcome of the operation (confirmed or cancelled) will be
567      * notified to the given notification object. The selected file will be set to the given bound property, which can
568      * be also used to set the default value rendered on the FileChooser.
569      *
570      * @param  notification  the object notifying whether the operation is confirmed or cancelled
571      * @param  selectedFile  the property containing the selected file
572      **********************************************************************************************************************************************************/
573     public void openFileChooserFor (@Nonnull UserNotificationWithFeedback notification,
574                                     @Nonnull BoundProperty<Path> selectedFile);
575 
576     /***********************************************************************************************************************************************************
577      * Opens the FileChooser for selecting a folder. The outcome of the operation (confirmed or cancelled) will be
578      * notified to the given notification object. The selected folder will be set to the given bound property, which can
579      * be also used to set the default value rendered on the FileChooser.
580      *
581      * @param  notification    the object notifying whether the operation is confirmed or cancelled
582      * @param  selectedFolder  the property containing the selected folder
583      **********************************************************************************************************************************************************/
584     public void openDirectoryChooserFor (@Nonnull UserNotificationWithFeedback notification,
585                                          @Nonnull BoundProperty<Path> selectedFolder);
586   }