Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: organize GuiUtils and FXUtils into Effects and Dialogs #586

Merged
merged 2 commits into from
Oct 7, 2020

Conversation

skaldarnar
Copy link
Member

These two utility classes have the same functionality, so there is no reason why they should be separated. I think all UI/JavaFX related code should live in a ui package, therefore, I'm merging GuiUtils into FXUtils.

@skaldarnar skaldarnar added Status: Actionable An issue or task that can immediately be worked on Type: Maintenance Maintenance or chores not adding new features or fixing bugs. labels Oct 5, 2020
Copy link
Member

@keturn keturn left a comment

Choose a reason for hiding this comment

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

Hmm, I'm not really opposed, but making a collection named "Utils" bigger isn't much of a win either.

I notice the things from GuiUtils are all dialogs, and calling those public methods immediately results in user-visible changes happening.

The lone method in FXUtils createScaleTransition, on the other hand, configures a type of animation and returns it without applying it to anything in particular.

They could be split in to things named "dialogs" and "animations" or "effects" or something like that?

@skaldarnar
Copy link
Member Author

They could be split in to things named "dialogs" and "animations" or "effects" or something like that?

Yep, that would also be an option. I was wondering whether all these dialog utils are strictly required or whether we could get rid of some of them... 🤔 What is the idiomatic JavaFX way of handling this?

Maybe the main utility aspect here is running something on the JavaFX event thread, rather than what exactly we are running ... let me check something...

@skaldarnar skaldarnar changed the title chore: merge util.GuiUtils into gui.javafx.FXUtils chore: organize util.GuiUtils and gui.javafx.FXUtils into Effects and Dialogs Oct 5, 2020
@skaldarnar skaldarnar requested a review from keturn October 5, 2020 20:40
@keturn
Copy link
Member

keturn commented Oct 5, 2020

Additional consideration: #571 used FXUtils as a place to put a FxTimer class, adopted from ReactFX. (It seemed like a reasonable idea to copy the single class, instead of depending on the entire library.)

It looks like that is a class, not a static method, so it could stand alone in its own .java file without needing to be put in one of these.

@keturn
Copy link
Member

keturn commented Oct 5, 2020

and yes, I also read those dialog methods and thought "are we missing something?"

It does feel like a use case that ought to be handled by some upstream interface already.

@keturn
Copy link
Member

keturn commented Oct 6, 2020

The renames here look good. I just want to look up a thing or two related to that runOnEventThread stuff before sending this on.

@skaldarnar
Copy link
Member Author

Sure, please feel free to push changes and merge if you feel save enough about it 😉

Copy link
Member

@keturn keturn left a comment

Choose a reason for hiding this comment

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

Long-term, there are usage patterns here that I think we should get away from. Specifically the blocking calls like future.get() or showAndWait in the application thread.

I guess we do want these to be modal dialogs, and maaaaaaybe that's the way you're supposed to do modal dialogs? but I am suspicious.

But that's not really in scope for now. This PR is a mostly-simple refactor, I just had to look at it a little closer because runOnEventThread is not quite a simple mechanical refactor, and when I started reading it I didn't realize that much of its logic is extracted straight out of chooseDirectoryDialog.

Refactoring approved.

private Dialogs() {
}

private static <T> T runOnEventThread(Supplier<T> producer) {
Copy link
Member

Choose a reason for hiding this comment

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

Ah, I have seen functions like this in the API before. But they're in TestFX: WaitForAsyncUtils, and it would seem weird to include TestFX as an implementation dependency instead of a test dependency.

Comment on lines +49 to +50
if (Platform.isFxApplicationThread()) {
result = producer.get();
Copy link
Member

Choose a reason for hiding this comment

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

I wondered: What would happen if this if clause weren't here? But I have a horrible suspicion about what the answer is: we'd ask it to "run later", and then move on to the blocking task.get(), and then "later" would never come because we're blocking the application thread.

ughhhhh.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was wondering about that, too. At some point, we've put this if construct in the main code, and I hope for some reason (maybe the one you described above) 🙈 I did not double-check that, though, and this is probably something we could unit test in the future, too.

return producer.get();
}
};
Platform.runLater(task);
Copy link
Member

Choose a reason for hiding this comment

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

and the main reason for this Platform.runLater is that we're using this with Dialog.showAndWait, which says

This method must be called on the JavaFX Application thread. Additionally, it must either be called from an input event handler or from the run method of a Runnable passed to Platform.runLater. It must not be called during animation or layout processing.

Copy link
Member

Choose a reason for hiding this comment

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

and while showMessageDialog has no return value, we're also using this method to remove the duplication in chooseDirectoryDialog. That is where the isFxApplicationThread switch comes from, and that's why we need a Task with a return value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, that's basically the train of thought here - including the part further above about the dialogs being modal. We had non-modal dialogs in the past, and they kept vanishing behind the launcher window and thus were often missed by users - so far that they kept working with the launcher which was trying to tell that it has crashed 🙈

Maybe we can move to a more modern notification area where these messages show up in a non-blocking way instead. And only use modal dialogs for hard crashes from which we cannot recover.

try {
result = task.get();
} catch (InterruptedException | ExecutionException e) {
logger.warn("Uh oh, something went wrong running this on the event thread.", e);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
logger.warn("Uh oh, something went wrong running this on the event thread.", e);
logger.error("Uh oh, something went wrong running this on the event thread.", e);

@skaldarnar skaldarnar changed the title chore: organize util.GuiUtils and gui.javafx.FXUtils into Effects and Dialogs chore: organize GuiUtils and FXUtils into Effects and Dialogs Oct 7, 2020
@skaldarnar skaldarnar merged commit 24252ec into master Oct 7, 2020
@skaldarnar skaldarnar deleted the chore/fx-utils branch October 7, 2020 06:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Actionable An issue or task that can immediately be worked on Type: Maintenance Maintenance or chores not adding new features or fixing bugs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants