How to show a blocking dialog on project load
Hi, I am working on a plugin in which, when a project is loaded, I occasionally need to show a dialog that asks the user to choose one of several options. For this I have a class implementing ProjectComponent and overriding the projectOpened method, like this:
public final class MyProjectComponent implements ProjectComponent {
// Some stuff...
@Override
public void projectOpened() {
methodWithDialog();
// This depends on the action taken by the user
// in the dialog shown by methodWithDialog
methodAfterDialog();
}
private void methodWithDialog() {
// Some code...
// This needs to block the execution
ApplicationManager.getApplication().invokeAndWait(() ->
// ListChooserDialog is just a subclass of JDialog that I wrote.
// Its display method calls setVisible(true).
new ListChooserDialog(
"Please choose one of the following options:",
optionList,
selectedOption -> { /* Store selection */ },
() -> { /* Cancelled */ },
ListSelectionModel.SINGLE_SELECTION
).display()
);
}
private void methodAfterDialog() {
// Some more code...
}
}
As I tried to explain in the code comments, I need the displayed dialog to block the execution until the user makes a selection from the dialog (or just cancels) as the execution of methodAfterDialog will depend on the user's selection, which is why I'm using invokeAndWait instead of invokeLater. This seems to work as expected only 50% of the time and for the other 50%, for some reason, the dialog does show up when the project is loaded but it is unresponsive to mouse clicks or key presses or anything, and of course so is the rest of the IDE because the dialog is displayed. It seems random, so when I load a project, it randomly either works or hangs indefinitely and I have to manually kill the process. Note that this only seems to happen when a project loads, so if I show the dialog using invokeAndWait at any point other than on project load, it will respond to input 100% of the time.
I know I could "solve" my problem by making the whole thing asynchronous, for example by having methodWithDialog take a runnable, just use invokeLater and execute the runnable inside the call to invokeLater, after displaying the dialog. That's however not an option for me as methodWithDialog is called from different places, in some cases in a series of method calls, which means that a big part of the plugin's internal API would need to be adapted to work asynchronously, and it just seems too unnecessary especially that it's currently working, but it's hanging half of the time for some reason.
So am I doing something wrong? What's the proper way to show a blocking dialog when a project is loaded? Thanks :)
Please sign in to leave a comment.
Please take a thread dump when it hangs, and post here
UPDATE: It might not be clear as this reply is very long but there are TWO thread dumps here.
Ok so here's a thread dump from a run where it hangs:
And I thought for comparison a dump from a run where it doesn't hang might be useful:
Thanks for the help :)
I see, thanks for the two dumps! The problem is, the IDE has its own modality tracking (which plays an important role here), but unfortunately it doesn't yet track pure swing JDialog (filed as https://youtrack.jetbrains.com/issue/IDEA-198631). Please try extending DialogWrapper, which should be handled correctly and is more in style with the other IDE components.
Yep, extending DialogWrapper solved it! Thanks :)