449 */
450 public final Node getHeader() {
451 return header.get();
452 }
453
454 /**
455 * Assigns the dialog pane header. Any Node can be used.
456 *
457 * @param header The new header of the DialogPane.
458 */
459 public final void setHeader(Node header) {
460 this.header.setValue(header);
461 }
462
463 /**
464 * Property representing the header area of the dialog pane. Note that if this
465 * header is set to a non-null value, that it will take up the entire top
466 * area of the DialogPane. It will also result in the DialogPane switching its
467 * layout to the 'header' layout - as outlined in the {@link DialogPane} class
468 * javadoc.
469 */
470 public final ObjectProperty<Node> headerProperty() {
471 return header;
472 }
473
474
475
476 // --- header text
477 private final StringProperty headerText = new SimpleStringProperty(this, "headerText") {
478 @Override protected void invalidated() {
479 updateHeaderArea();
480 requestLayout();
481 }
482 };
483
484 /**
485 * Sets the string to show in the dialog header area. Note that the header text
486 * is lower precedence than the {@link #headerProperty() header node}, meaning
487 * that if both the header node and the headerText properties are set, the
488 * header text will not be displayed in a default DialogPane instance.
489 *
490 * <p>When headerText is set to a non-null value, this will result in the
491 * DialogPane switching its layout to the 'header' layout - as outlined in
492 * the {@link DialogPane} class javadoc.</p>
493 */
494 public final void setHeaderText(String headerText) {
495 this.headerText.set(headerText);
496 }
497
498 /**
499 * Returns the currently-set header text for this DialogPane.
500 */
501 public final String getHeaderText() {
502 return headerText.get();
503 }
504
505 /**
506 * A property representing the header text for the dialog pane. The header text
507 * is lower precedence than the {@link #headerProperty() header node}, meaning
508 * that if both the header node and the headerText properties are set, the
509 * header text will not be displayed in a default DialogPane instance.
510 *
511 * <p>When headerText is set to a non-null value, this will result in the
512 * DialogPane switching its layout to the 'header' layout - as outlined in
513 * the {@link DialogPane} class javadoc.</p>
514 */
515 public final StringProperty headerTextProperty() {
516 return headerText;
517 }
518
519
520 // --- content
521 private final ObjectProperty<Node> content = new SimpleObjectProperty<Node>(null) {
522 WeakReference<Node> contentRef = new WeakReference<>(null);
523 @Override protected void invalidated() {
524 Node oldContent = contentRef.get();
525 if (oldContent != null) {
526 getChildren().remove(oldContent);
527 }
528
529 Node newContent = getContent();
530 contentRef = new WeakReference<>(newContent);
531 updateContentArea();
532 }
533 };
538 * {@link Node} (most probably a {@link Label}).
539 *
540 * @return dialog's content
541 */
542 public final Node getContent() {
543 return content.get();
544 }
545
546 /**
547 * Assign dialog content. Any Node can be used
548 *
549 * @param content
550 * dialog's content
551 */
552 public final void setContent(Node content) {
553 this.content.setValue(content);
554 }
555
556 /**
557 * Property representing the content area of the dialog.
558 */
559 public final ObjectProperty<Node> contentProperty() {
560 return content;
561 }
562
563
564 // --- content text
565 private final StringProperty contentText = new SimpleStringProperty(this, "contentText") {
566 @Override protected void invalidated() {
567 updateContentArea();
568 requestLayout();
569 }
570 };
571
572 /**
573 * Sets the string to show in the dialog content area. Note that the content text
574 * is lower precedence than the {@link #contentProperty() content node}, meaning
575 * that if both the content node and the contentText properties are set, the
576 * content text will not be displayed in a default DialogPane instance.
577 */
578 public final void setContentText(String contentText) {
579 this.contentText.set(contentText);
580 }
581
582 /**
583 * Returns the currently-set content text for this DialogPane.
584 */
585 public final String getContentText() {
586 return contentText.get();
587 }
588
589 /**
590 * A property representing the content text for the dialog pane. The content text
591 * is lower precedence than the {@link #contentProperty() content node}, meaning
592 * that if both the content node and the contentText properties are set, the
593 * content text will not be displayed in a default DialogPane instance.
594 */
595 public final StringProperty contentTextProperty() {
596 return contentText;
597 }
598
599
600 // --- expandable content
601 private final ObjectProperty<Node> expandableContentProperty = new SimpleObjectProperty<Node>(null) {
602 WeakReference<Node> expandableContentRef = new WeakReference<>(null);
603 @Override protected void invalidated() {
604 Node oldExpandableContent = expandableContentRef.get();
605 if (oldExpandableContent != null) {
606 getChildren().remove(oldExpandableContent);
607 }
608
609 Node newExpandableContent = getExpandableContent();
610 expandableContentRef = new WeakReference<Node>(newExpandableContent);
611 if (newExpandableContent != null) {
612 newExpandableContent.setVisible(isExpanded());
613 newExpandableContent.setManaged(isExpanded());
614
615 if (!newExpandableContent.getStyleClass().contains("expandable-content")) { //$NON-NLS-1$
616 newExpandableContent.getStyleClass().add("expandable-content"); //$NON-NLS-1$
617 }
618
619 getChildren().add(newExpandableContent);
620 }
621 }
622 };
623
624 /**
625 * A property that represents the dialog expandable content area. Any Node
626 * can be placed in this area, but it will only be shown when the user
627 * clicks the 'Show Details' expandable button. This button will be added
628 * automatically when the expandable content property is non-null.
629 */
630 public final ObjectProperty<Node> expandableContentProperty() {
631 return expandableContentProperty;
632 }
633
634 /**
635 * Returns the dialog expandable content node, if one is set, or null
636 * otherwise.
637 */
638 public final Node getExpandableContent() {
639 return expandableContentProperty.get();
640 }
641
642 /**
643 * Sets the dialog expandable content node, or null if no expandable content
644 * needs to be shown.
645 */
646 public final void setExpandableContent(Node content) {
647 this.expandableContentProperty.set(content);
648 }
649
650
651 // --- expanded
652 private final BooleanProperty expandedProperty = new SimpleBooleanProperty(this, "expanded", false) {
653 protected void invalidated() {
654 final Node expandableContent = getExpandableContent();
655
656 if (expandableContent != null) {
657 expandableContent.setVisible(isExpanded());
658 }
659
660 requestLayout();
661 }
662 };
663
664 /**
665 * Represents whether the dialogPane is expanded.
666 */
667 public final BooleanProperty expandedProperty() {
668 return expandedProperty;
669 }
670
671 /**
672 * Returns whether or not the dialogPane is expanded.
673 *
674 * @return true if dialogPane is expanded.
675 */
676 public final boolean isExpanded() {
677 return expandedProperty().get();
678 }
679
680 /**
681 * Sets whether the dialogPane is expanded. This only makes sense when there
682 * is {@link #expandableContentProperty() expandable content} to show.
683 *
684 * @param value true if dialogPane should be expanded.
685 */
726 /**
727 * This method can be overridden by subclasses to provide the button bar.
728 * Note that by overriding this method, the developer must take on multiple
729 * responsibilities:
730 *
731 * <ol>
732 * <li>The developer must immediately iterate through all
733 * {@link #getButtonTypes() button types} and call
734 * {@link #createButton(ButtonType)} for each of them in turn.
735 * <li>The developer must add a listener to the
736 * {@link #getButtonTypes() button types} list, and when this list changes
737 * update the button bar as appropriate.
738 * <li>Similarly, the developer must watch for changes to the
739 * {@link #expandableContentProperty() expandable content} property,
740 * adding and removing the details button (created via
741 * {@link #createDetailsButton()} method).
742 * </ol>
743 *
744 * <p>The default implementation of this method creates and returns a new
745 * {@link ButtonBar} instance.
746 */
747 protected Node createButtonBar() {
748 ButtonBar buttonBar = new ButtonBar();
749 buttonBar.setMaxWidth(Double.MAX_VALUE);
750
751 updateButtons(buttonBar);
752 getButtonTypes().addListener((ListChangeListener<? super ButtonType>) c -> updateButtons(buttonBar));
753 expandableContentProperty().addListener(o -> updateButtons(buttonBar));
754
755 return buttonBar;
756 }
757
758 /**
759 * This method can be overridden by subclasses to create a custom button that
760 * will subsequently inserted into the DialogPane button area (created via
761 * the {@link #createButtonBar()} method, but mostly commonly it is an instance
762 * of {@link ButtonBar}.
763 *
764 * @param buttonType The {@link ButtonType} to create a button from.
765 * @return A JavaFX {@link Node} that represents the given {@link ButtonType},
777 dialog.setResultAndClose(buttonType, true);
778 }
779 });
780
781 return button;
782 }
783
784 /**
785 * This method can be overridden by subclasses to create a custom details button.
786 *
787 * <p>To override this method you must do two things:
788 * <ol>
789 * <li>The button will need to have its own code set to handle mouse / keyboard
790 * interaction and to toggle the state of the
791 * {@link #expandedProperty() expanded} property.
792 * <li>If your button changes its visuals based on whether the dialog pane
793 * is expanded or collapsed, you should add a listener to the
794 * {@link #expandedProperty() expanded} property, so that you may update
795 * the button visuals.
796 * </ol>
797 */
798 protected Node createDetailsButton() {
799 final Hyperlink detailsButton = new Hyperlink();
800 final String moreText = ControlResources.getString("Dialog.detail.button.more"); //$NON-NLS-1$
801 final String lessText = ControlResources.getString("Dialog.detail.button.less"); //$NON-NLS-1$
802
803 InvalidationListener expandedListener = o -> {
804 final boolean isExpanded = isExpanded();
805 detailsButton.setText(isExpanded ? lessText : moreText);
806 detailsButton.getStyleClass().setAll("details-button", (isExpanded ? "less" : "more")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
807 };
808
809 // we call the listener immediately to ensure the state is correct at start up
810 expandedListener.invalidated(null);
811 expandedProperty().addListener(expandedListener);
812
813 detailsButton.setOnAction(ae -> setExpanded(!isExpanded()));
814 return detailsButton;
815 }
816
|
449 */
450 public final Node getHeader() {
451 return header.get();
452 }
453
454 /**
455 * Assigns the dialog pane header. Any Node can be used.
456 *
457 * @param header The new header of the DialogPane.
458 */
459 public final void setHeader(Node header) {
460 this.header.setValue(header);
461 }
462
463 /**
464 * Property representing the header area of the dialog pane. Note that if this
465 * header is set to a non-null value, that it will take up the entire top
466 * area of the DialogPane. It will also result in the DialogPane switching its
467 * layout to the 'header' layout - as outlined in the {@link DialogPane} class
468 * javadoc.
469 * @return the property representing the header area of the dialog pane
470 */
471 public final ObjectProperty<Node> headerProperty() {
472 return header;
473 }
474
475
476
477 // --- header text
478 private final StringProperty headerText = new SimpleStringProperty(this, "headerText") {
479 @Override protected void invalidated() {
480 updateHeaderArea();
481 requestLayout();
482 }
483 };
484
485 /**
486 * Sets the string to show in the dialog header area. Note that the header text
487 * is lower precedence than the {@link #headerProperty() header node}, meaning
488 * that if both the header node and the headerText properties are set, the
489 * header text will not be displayed in a default DialogPane instance.
490 *
491 * <p>When headerText is set to a non-null value, this will result in the
492 * DialogPane switching its layout to the 'header' layout - as outlined in
493 * the {@link DialogPane} class javadoc.</p>
494 * @param headerText the string to show in the dialog header area
495 */
496 public final void setHeaderText(String headerText) {
497 this.headerText.set(headerText);
498 }
499
500 /**
501 * Returns the currently-set header text for this DialogPane.
502 * @return the currently-set header text for this DialogPane
503 */
504 public final String getHeaderText() {
505 return headerText.get();
506 }
507
508 /**
509 * A property representing the header text for the dialog pane. The header text
510 * is lower precedence than the {@link #headerProperty() header node}, meaning
511 * that if both the header node and the headerText properties are set, the
512 * header text will not be displayed in a default DialogPane instance.
513 *
514 * <p>When headerText is set to a non-null value, this will result in the
515 * DialogPane switching its layout to the 'header' layout - as outlined in
516 * the {@link DialogPane} class javadoc.</p>
517 * @return the property representing the header text for the dialog pane
518 */
519 public final StringProperty headerTextProperty() {
520 return headerText;
521 }
522
523
524 // --- content
525 private final ObjectProperty<Node> content = new SimpleObjectProperty<Node>(null) {
526 WeakReference<Node> contentRef = new WeakReference<>(null);
527 @Override protected void invalidated() {
528 Node oldContent = contentRef.get();
529 if (oldContent != null) {
530 getChildren().remove(oldContent);
531 }
532
533 Node newContent = getContent();
534 contentRef = new WeakReference<>(newContent);
535 updateContentArea();
536 }
537 };
542 * {@link Node} (most probably a {@link Label}).
543 *
544 * @return dialog's content
545 */
546 public final Node getContent() {
547 return content.get();
548 }
549
550 /**
551 * Assign dialog content. Any Node can be used
552 *
553 * @param content
554 * dialog's content
555 */
556 public final void setContent(Node content) {
557 this.content.setValue(content);
558 }
559
560 /**
561 * Property representing the content area of the dialog.
562 * @return the property representing the content area of the dialog
563 */
564 public final ObjectProperty<Node> contentProperty() {
565 return content;
566 }
567
568
569 // --- content text
570 private final StringProperty contentText = new SimpleStringProperty(this, "contentText") {
571 @Override protected void invalidated() {
572 updateContentArea();
573 requestLayout();
574 }
575 };
576
577 /**
578 * Sets the string to show in the dialog content area. Note that the content text
579 * is lower precedence than the {@link #contentProperty() content node}, meaning
580 * that if both the content node and the contentText properties are set, the
581 * content text will not be displayed in a default DialogPane instance.
582 * @param contentText the string to show in the dialog content area
583 */
584 public final void setContentText(String contentText) {
585 this.contentText.set(contentText);
586 }
587
588 /**
589 * Returns the currently-set content text for this DialogPane.
590 * @return the currently-set content text for this DialogPane
591 */
592 public final String getContentText() {
593 return contentText.get();
594 }
595
596 /**
597 * A property representing the content text for the dialog pane. The content text
598 * is lower precedence than the {@link #contentProperty() content node}, meaning
599 * that if both the content node and the contentText properties are set, the
600 * content text will not be displayed in a default DialogPane instance.
601 * @return the property representing the content text for the dialog pane
602 */
603 public final StringProperty contentTextProperty() {
604 return contentText;
605 }
606
607
608 // --- expandable content
609 private final ObjectProperty<Node> expandableContentProperty = new SimpleObjectProperty<Node>(null) {
610 WeakReference<Node> expandableContentRef = new WeakReference<>(null);
611 @Override protected void invalidated() {
612 Node oldExpandableContent = expandableContentRef.get();
613 if (oldExpandableContent != null) {
614 getChildren().remove(oldExpandableContent);
615 }
616
617 Node newExpandableContent = getExpandableContent();
618 expandableContentRef = new WeakReference<Node>(newExpandableContent);
619 if (newExpandableContent != null) {
620 newExpandableContent.setVisible(isExpanded());
621 newExpandableContent.setManaged(isExpanded());
622
623 if (!newExpandableContent.getStyleClass().contains("expandable-content")) { //$NON-NLS-1$
624 newExpandableContent.getStyleClass().add("expandable-content"); //$NON-NLS-1$
625 }
626
627 getChildren().add(newExpandableContent);
628 }
629 }
630 };
631
632 /**
633 * A property that represents the dialog expandable content area. Any Node
634 * can be placed in this area, but it will only be shown when the user
635 * clicks the 'Show Details' expandable button. This button will be added
636 * automatically when the expandable content property is non-null.
637 * @return the property that represents the dialog expandable content area
638 */
639 public final ObjectProperty<Node> expandableContentProperty() {
640 return expandableContentProperty;
641 }
642
643 /**
644 * Returns the dialog expandable content node, if one is set, or null
645 * otherwise.
646 * @return the dialog expandable content node
647 */
648 public final Node getExpandableContent() {
649 return expandableContentProperty.get();
650 }
651
652 /**
653 * Sets the dialog expandable content node, or null if no expandable content
654 * needs to be shown.
655 * @param content the dialog expandable content node
656 */
657 public final void setExpandableContent(Node content) {
658 this.expandableContentProperty.set(content);
659 }
660
661
662 // --- expanded
663 private final BooleanProperty expandedProperty = new SimpleBooleanProperty(this, "expanded", false) {
664 protected void invalidated() {
665 final Node expandableContent = getExpandableContent();
666
667 if (expandableContent != null) {
668 expandableContent.setVisible(isExpanded());
669 }
670
671 requestLayout();
672 }
673 };
674
675 /**
676 * Represents whether the dialogPane is expanded.
677 * @return the property representing whether the dialogPane is expanded
678 */
679 public final BooleanProperty expandedProperty() {
680 return expandedProperty;
681 }
682
683 /**
684 * Returns whether or not the dialogPane is expanded.
685 *
686 * @return true if dialogPane is expanded.
687 */
688 public final boolean isExpanded() {
689 return expandedProperty().get();
690 }
691
692 /**
693 * Sets whether the dialogPane is expanded. This only makes sense when there
694 * is {@link #expandableContentProperty() expandable content} to show.
695 *
696 * @param value true if dialogPane should be expanded.
697 */
738 /**
739 * This method can be overridden by subclasses to provide the button bar.
740 * Note that by overriding this method, the developer must take on multiple
741 * responsibilities:
742 *
743 * <ol>
744 * <li>The developer must immediately iterate through all
745 * {@link #getButtonTypes() button types} and call
746 * {@link #createButton(ButtonType)} for each of them in turn.
747 * <li>The developer must add a listener to the
748 * {@link #getButtonTypes() button types} list, and when this list changes
749 * update the button bar as appropriate.
750 * <li>Similarly, the developer must watch for changes to the
751 * {@link #expandableContentProperty() expandable content} property,
752 * adding and removing the details button (created via
753 * {@link #createDetailsButton()} method).
754 * </ol>
755 *
756 * <p>The default implementation of this method creates and returns a new
757 * {@link ButtonBar} instance.
758 * @return the created button bar
759 */
760 protected Node createButtonBar() {
761 ButtonBar buttonBar = new ButtonBar();
762 buttonBar.setMaxWidth(Double.MAX_VALUE);
763
764 updateButtons(buttonBar);
765 getButtonTypes().addListener((ListChangeListener<? super ButtonType>) c -> updateButtons(buttonBar));
766 expandableContentProperty().addListener(o -> updateButtons(buttonBar));
767
768 return buttonBar;
769 }
770
771 /**
772 * This method can be overridden by subclasses to create a custom button that
773 * will subsequently inserted into the DialogPane button area (created via
774 * the {@link #createButtonBar()} method, but mostly commonly it is an instance
775 * of {@link ButtonBar}.
776 *
777 * @param buttonType The {@link ButtonType} to create a button from.
778 * @return A JavaFX {@link Node} that represents the given {@link ButtonType},
790 dialog.setResultAndClose(buttonType, true);
791 }
792 });
793
794 return button;
795 }
796
797 /**
798 * This method can be overridden by subclasses to create a custom details button.
799 *
800 * <p>To override this method you must do two things:
801 * <ol>
802 * <li>The button will need to have its own code set to handle mouse / keyboard
803 * interaction and to toggle the state of the
804 * {@link #expandedProperty() expanded} property.
805 * <li>If your button changes its visuals based on whether the dialog pane
806 * is expanded or collapsed, you should add a listener to the
807 * {@link #expandedProperty() expanded} property, so that you may update
808 * the button visuals.
809 * </ol>
810 * @return the created details button
811 */
812 protected Node createDetailsButton() {
813 final Hyperlink detailsButton = new Hyperlink();
814 final String moreText = ControlResources.getString("Dialog.detail.button.more"); //$NON-NLS-1$
815 final String lessText = ControlResources.getString("Dialog.detail.button.less"); //$NON-NLS-1$
816
817 InvalidationListener expandedListener = o -> {
818 final boolean isExpanded = isExpanded();
819 detailsButton.setText(isExpanded ? lessText : moreText);
820 detailsButton.getStyleClass().setAll("details-button", (isExpanded ? "less" : "more")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
821 };
822
823 // we call the listener immediately to ensure the state is correct at start up
824 expandedListener.invalidated(null);
825 expandedProperty().addListener(expandedListener);
826
827 detailsButton.setOnAction(ae -> setExpanded(!isExpanded()));
828 return detailsButton;
829 }
830
|