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