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 }