Skip to content

Conversation

@mstr2
Copy link
Collaborator

@mstr2 mstr2 commented Oct 21, 2025

Adds the DialogPane.headerBar property, which allows developers to specify a custom HeaderBar when the dialog uses the EXTENDED stage style.


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change requires CSR request JDK-8371872 to be approved
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issues

  • JDK-8370446: Support dialogs with StageStyle.EXTENDED (Preview) (Enhancement - P4)
  • JDK-8371872: Support dialogs with StageStyle.EXTENDED (Preview) (CSR)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1943/head:pull/1943
$ git checkout pull/1943

Update a local copy of the PR:
$ git checkout pull/1943
$ git pull https://git.openjdk.org/jfx.git pull/1943/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 1943

View PR using the GUI difftool:
$ git pr show -t 1943

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1943.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 21, 2025

👋 Welcome back mstrauss! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Oct 21, 2025

@mstr2 This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8370446: Support dialogs with StageStyle.EXTENDED (Preview)

Reviewed-by: angorya, kcr

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 3 new commits pushed to the master branch:

  • 8341264: 8371069: RichTextArea: caret with inline node
  • 7862ab8: 8370140: RichTextArea: line endings
  • 8892188: 8356770: TreeTableView not updated after removing a TreeItem with children and adding it to another parent

Please see this link for an up-to-date comparison between the source branch of this pull request and the master branch.
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@mstr2 mstr2 changed the title Support dialogs with StageStyle.EXTENDED 8370446: Support dialogs with StageStyle.EXTENDED Oct 22, 2025
@credmond
Copy link

credmond commented Oct 22, 2025

The nature of when and how DialogPane's "scene" is available seems to have changed.

For example, consider this (very old) code of mine:

public class BaseDialog<T> extends Dialog<T> implements CtDialog<T> {

    protected BaseDialog() {
        getDialogPane().getScene().setOnKeyPressed(event -> {
            <...SNIP....>

Now I get an NPE because getScene() is null even after a dialog pane is set, presumably because of the changes to HeavyweightDialog.setDialogPane().

It might be incorrect to assume a scene is assigned at this point (...?), but it is and has been for a long time...

E.g., simply instantiating a Dialog would have created a scene immediately via setDialogPane() previously:

    public Dialog() {
        this.setDialogPane(new DialogPane());
        this.initModality(Modality.APPLICATION_MODAL);
    }

... which is now not the case. Would you consider this a breaking change?

@mstr2
Copy link
Collaborator Author

mstr2 commented Oct 22, 2025

...
... which is now not the case. Would you consider this a breaking change?

Yes, and it's probably not useful to introduce a breaking change at this point. I've updated the PR to match the old behavior.

@credmond
Copy link

...
... which is now not the case. Would you consider this a breaking change?

Yes, and it's probably not useful to introduce a breaking change at this point. I've updated the PR to match the old behavior.

Great, thanks. It now appears to be working as desired with these tweaks...

Comment on lines 592 to 594
* @since 26
*/
private ObjectProperty<HeaderBar> headerBar;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a preview feature, it needs to be documented and handled as such.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. This requires documenting all property methods individually, instead of relying on the javadoc tool to do it automatically (as the @deprecated annotation is not carried over). I'll revert this to a property field doc once this feature is finalized.

@mstr2 mstr2 marked this pull request as ready for review October 23, 2025 16:21
@mstr2
Copy link
Collaborator Author

mstr2 commented Oct 23, 2025

/reviewers 2
/csr

@openjdk openjdk bot added the rfr Ready for review label Oct 23, 2025
@openjdk
Copy link

openjdk bot commented Oct 23, 2025

@mstr2
The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 1 Reviewer, 1 Author).

@openjdk openjdk bot added the csr Need approved CSR to integrate pull request label Oct 23, 2025
@openjdk
Copy link

openjdk bot commented Oct 23, 2025

@mstr2 has indicated that a compatibility and specification (CSR) request is needed for this pull request.

@mstr2 please create a CSR request for issue JDK-8370446 with the correct fix version. This pull request cannot be integrated until the CSR request is approved.

@mlbridge
Copy link

mlbridge bot commented Oct 23, 2025

Webrevs

@credmond
Copy link

credmond commented Oct 23, 2025

I've found a layout issue when using HeaderBar in Dialogs. This only occurs when:

  • you use a HeaderBar
  • a preferred width is set on the DialogPane

When using HeaderBar (clipped):
image

When not using HeaderBar:
image

Code to reproduce:

public class DialogBugDemo extends Application {

    @Override
    public void start(Stage stage) {
        Button infoBtn = new Button("Show Two Alerts");
        infoBtn.setOnAction(e -> {
            showInfo(true); // With HeaderBar - content clipping issue
            showInfo(false); // Without HeaderBar - works fine
        });
        stage.setScene(new Scene(new VBox(10, infoBtn), 400, 300));
        stage.show();
    }

    private void showInfo(boolean withHeaderBar) {
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setHeaderText(null);

        // Set preferred width causing the issue to manifest, no issue without it
        alert.getDialogPane().setPrefWidth(400); // Comment out and bug goes away

        alert.getDialogPane().setContent(createVbox());

        // Display issues only occur when HeaderBar is set
        if (withHeaderBar) {
            alert.setHeaderBar(new HeaderBar());
            alert.initStyle(StageStyle.EXTENDED);
        }

        alert.show();
    }

    private  VBox createVbox() {
        TextFlow tf = new TextFlow(
                new Text("1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; end of first TextFlow.")
        );

        TextFlow tf2 = new TextFlow(
                new Text("1 2 3 4 5 6 7 8 9 0 1 sdf 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; end of second TextFlow.")
        );

        return new VBox(tf, new VBox(tf2));
    }

    public static void main(String[] args) {
        launch(args);
    }
}

@credmond
Copy link

More strange behaviour, this time using Labels and setting a min height, leads to different behaviours...

image
public class DialogBugDemoTwo extends Application {

    @Override
    public void start(Stage stage) {
        Button infoBtn = new Button("Show Two Alerts");
        infoBtn.setOnAction(e -> {
            showInfo(true, false, "with header, NO min height");
            showInfo(false, true, "NO header, with min height");
            showInfo(true, true, "with header, with min height");
            showInfo(false, false, "NO header, NO min height");
        });
        stage.setScene(new Scene(new VBox(10, infoBtn), 400, 300));
        stage.show();
    }

    private void showInfo(boolean withHeaderBar, boolean setMinHeight, String desc) {
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setHeaderText(null);
        alert.initModality(Modality.NONE);

        // Set preferred width causing the issue to manifest, no issue without it
        alert.getDialogPane().setPrefWidth(600); // Comment out and bug goes away

        alert.getDialogPane().setContent(createVbox(desc));

        if (setMinHeight) {
            alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
        }
        // Display issues only occur when HeaderBar is set
        if (withHeaderBar) {
            alert.setHeaderBar(new HeaderBar());
            alert.initStyle(StageStyle.EXTENDED);
        }

        alert.show();
    }

    private VBox createVbox(String desc) {
        final Label lbl1 = new Label(desc + ".... 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; end of first Label.");
        lbl1.setWrapText(true);

        final Label lbl2 = new Label("1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0; end of second Label.");
        lbl2.setWrapText(true);

        return new VBox(lbl1, new VBox(lbl2));
    }

    public static void main(String[] args) {
        launch(args);
    }
}

@credmond
Copy link

credmond commented Oct 24, 2025

Hi. Another bug, a slightly more serious one this time.

Dialogs cannot be re-used. E.g., sequentially calling showAndWait() twice on the same instance, does not work:

bug

This works fine on older JFXs:

nobug

Steps to reproduce:

public class DialogBugDemoThree extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        final Dialog<String> dialog = new Dialog<>();
        dialog.getDialogPane().setContent(new Label("Label"));
        ButtonType okButton = new ButtonType("OK", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(okButton, ButtonType.CANCEL);

        // Show once
        dialog.showAndWait();

        // Show twice
        // This will NOT work (it shows a tiny window frame with no content)
        dialog.showAndWait();
    }
}

@credmond
Copy link

Hi. Another bug, a slightly more serious one this time.

Dialogs cannot be re-used. E.g., sequentially calling showAndWait() twice on the same instance, does not work:
...

Hi @mstr2: any thoughts on this one (in particular)? Seems like a bug...

@mstr2
Copy link
Collaborator Author

mstr2 commented Oct 31, 2025

I've moved the new API from Dialog (which roughly corresponds to a Stage) to DialogPane, which contains the scene graph of a dialog. All bugs you've found should also be fixed.

@credmond
Copy link

credmond commented Nov 1, 2025

@mstr2: Thanks. I've been using this build a lot yesterday and today, and haven't noticed any issues re: alerts/dialogs + HeaderBar usage. Great to have HeaderBar support for dialogs now.

@andy-goryachev-oracle
Copy link
Contributor

This might be a silly question: is there a need for split HeaderBars?

* or StageStyle.UNIFIED.
* Specifies the style for this dialog. This must be done prior to making the dialog visible.
* <p>
* Note that a dialog with the {@link StageStyle#EXTENDED} style must also specify a {@link HeaderBar} with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must or should? meaning, is it a requirement, or just a warning?
if the latter, it might be better to say something like "the dialog will not be draggable if the header bar is not set"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's more like a warning. I've changed it to "should".


/** {@inheritDoc} */
@Override protected double computeMinWidth(double height) {
double headerBarMinWidth = getHeaderBar() instanceof HeaderBar hb ? hb.minWidth(height) : 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clever! :-)

@andy-goryachev-oracle
Copy link
Contributor

For testing: added the header bar options to the Stage and Dialog pages:
https://github.com/andy-goryachev-oracle/MonkeyTest/tree/dialog.header.bar

@andy-goryachev-oracle
Copy link
Contributor

Looks nice!

Screenshot 2025-11-06 at 15 56 35

@mstr2
Copy link
Collaborator Author

mstr2 commented Nov 7, 2025

This might be a silly question: is there a need for split HeaderBars?

I don't think that this is very useful for DialogPane. A dialog is a pretty opinionated control; if users want this level of customization, it's probably better to use use a normal Stage.

Copy link
Contributor

@andy-goryachev-oracle andy-goryachev-oracle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, thanks!

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API changes look good. The code change look good, although I left an inline question about one of the changes (since it would impact all stage styles, not just EXTENDED).

You can create the CSR now.

Comment on lines 220 to 221
headerTextPanel.setVisible(false);
headerTextPanel.setManaged(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this change needed? At first glance it seems unrelated to supporting an (optional) header bar.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was left over from a previous bug-fixing attempt. I've removed the added code.

Comment on lines 227 to 228
contentLabel.setVisible(false);
contentLabel.setManaged(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here.

@mstr2
Copy link
Collaborator Author

mstr2 commented Nov 13, 2025

I discovered a bug where HeaderBar would sometimes not report its correct height in situations when a DialogPane is re-used (similar to this). The root cause for this bug was that HeaderButtonOverlay.metricsProperty() was updated in HeaderButtonOverlay.layoutChildren(), i.e. during the layout phase. However, the metrics property itself is used as an input for the layout of HeaderBar, so its value should be known in advance of layout, and not be determined during the layout phase. The solution here is to disentangle the computation of header button metrics from the layout computation of HeaderButtonOverlay. I've refactored the code a bit, and now the metrics property is always updated after CSS processing (which is when we have enough information to know the size and placement of the header buttons), and therefore before a layout pass.

@kevinrushforth kevinrushforth self-requested a review November 14, 2025 18:55
@openjdk
Copy link

openjdk bot commented Nov 15, 2025

@mstr2 this pull request can not be integrated into master due to one or more merge conflicts. To resolve these merge conflicts and update this pull request you can run the following commands in the local repository for your personal fork:

git checkout feature/extended-dialog
git fetch https://git.openjdk.org/jfx.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push

@openjdk openjdk bot added the merge-conflict Pull request has merge conflict with target branch label Nov 15, 2025
@openjdk openjdk bot changed the title 8370446: Support dialogs with StageStyle.EXTENDED 8370446: Support dialogs with StageStyle.EXTENDED (Preview) Nov 15, 2025
# Conflicts:
#	modules/javafx.controls/src/test/java/test/javafx/scene/control/DialogPaneTest.java
@openjdk openjdk bot removed the merge-conflict Pull request has merge conflict with target branch label Nov 15, 2025
Copy link
Contributor

@andy-goryachev-oracle andy-goryachev-oracle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm.
added more options to the monkey tester Dialog page
https://github.com/andy-goryachev-oracle/MonkeyTest

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API and docs looks good.

The code changes look reasonable, but I haven't tested them and also want to take another pass, since these have the potential to impact DialogPane even when not using StageStyle.EXTENDED + HeaderBar.

@openjdk openjdk bot removed the csr Need approved CSR to integrate pull request label Nov 17, 2025
Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running a simple Dialog test that doesn't try to use HeaderBar or StageStyle.EXTENDED gets a RuntimeException without enabling preview features.

To reproduce, run HelloAlert from apps/toys/Hello or use the MonkeyTester without setting javafx.enablePreview and bring up an alert dialog:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: HeaderBar is a preview feature of JavaFX 26-internal.
Preview features may be removed in a future release, or upgraded to permanent features of JavaFX.
Programs can only use preview features when the following system property is set: -Djavafx.enablePreview=true

	at javafx.base@26-internal/com.sun.javafx.PreviewFeature.checkEnabled(PreviewFeature.java:71)
	at javafx.controls@26-internal/javafx.scene.control.DialogPane.getHeaderBar(DialogPane.java:487)
	at javafx.controls@26-internal/javafx.scene.control.DialogPane.computePrefWidth(DialogPane.java:1077)
	...

@mstr2
Copy link
Collaborator Author

mstr2 commented Nov 18, 2025

Running a simple Dialog test that doesn't try to use HeaderBar or StageStyle.EXTENDED gets a RuntimeException without enabling preview features.

I've updated the code to skip the preview feature check internally. It's still active for the public API.

Copy link
Member

@kevinrushforth kevinrushforth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

}
}

// This method skips the preview feature check for internal use and can be removed when HeaderBar is finalized.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if a comment should be added to the JBS ticket listing the things that need to be undone, lest we forget.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this specific case it's quite hard to miss, since it's right next to the preview API. But go ahead if you want to add the comment.

@openjdk openjdk bot added the ready Ready to be integrated label Nov 18, 2025
@mstr2
Copy link
Collaborator Author

mstr2 commented Nov 18, 2025

/integrate

@openjdk
Copy link

openjdk bot commented Nov 18, 2025

Going to push as commit f87448e.
Since your change was applied there have been 3 commits pushed to the master branch:

  • 8341264: 8371069: RichTextArea: caret with inline node
  • 7862ab8: 8370140: RichTextArea: line endings
  • 8892188: 8356770: TreeTableView not updated after removing a TreeItem with children and adding it to another parent

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Nov 18, 2025
@openjdk openjdk bot closed this Nov 18, 2025
@openjdk openjdk bot removed ready Ready to be integrated rfr Ready for review labels Nov 18, 2025
@openjdk
Copy link

openjdk bot commented Nov 18, 2025

@mstr2 Pushed as commit f87448e.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

@mstr2 mstr2 deleted the feature/extended-dialog branch November 18, 2025 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integrated Pull request has been integrated

Development

Successfully merging this pull request may close these issues.

4 participants