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

fix: enable Scene Builder to load FXML with unresolved imports (#120, #281, #733) #576

Open
wants to merge 48 commits into
base: master
Choose a base branch
from

Conversation

Oliver-Loeffler
Copy link
Collaborator

@Oliver-Loeffler Oliver-Loeffler commented Oct 3, 2022

This fix allows Scene Builder to load FXML files with unresolved imports.
There is also a new option (keep unresolved imports) which also allows to keep the imports in saved FXML files. This can be toggled in Scene Builder preferences dialog.

If disabled, Scene Builder will effectively omit those unresolved imports and remove them from the updated FXML to be written.
If enabled, Scene Builder will keep track of unresolved imports and write them (unmodified) into the updated FXML. The import remains as it was declared in the original FXML file. Optimization is not applied to unresolved imports.

Of course, one cannot make use of unresolved imports and edit these controls. But, one can at least open an FXML file, edit and rework it in parts. Also, Scene Builder will inform the user that there is something wrong with the imports - it will not silently ignore the issue. This is quite helpful with foreign projects where users only want to look into the files and get a feeling of how the UI would look like.

This PR also increments Maven-Surefire version from 3.0.0-M5 to 3.5.0 in order to mitigate module system related errors during test.

Issue

Fixes #120
Fixes #281
Fixes #733 (added on 2024-09-29)

Progress

unresolved imports.

There is also a new option (preserve unresolved imports) which also
allows to keep the imports in saved FXML files.
…of FXML with unresolved imports' as it exactly does the 2nd.
@Oliver-Loeffler Oliver-Loeffler changed the title fix: enable Scene Builder to keep unresolved imports in FXML fix: enable Scene Builder to load FXML with unresolved imports (which are the preserved) Oct 3, 2022
@abhinayagarwal abhinayagarwal added this to the 22 milestone Sep 25, 2023
@Oliver-Loeffler Oliver-Loeffler changed the title fix: enable Scene Builder to load FXML with unresolved imports (which are the preserved) fix: enable Scene Builder to load FXML with unresolved imports (which are still preserved) Mar 27, 2024
@Oliver-Loeffler
Copy link
Collaborator Author

This one no longer works as it used to. I'll review and rework accordingly. Loading FXML files with unresolvable imports works. Saving does not work anymore. I'll also add example FXMLs and tests for the FXOM.

@Oliver-Loeffler
Copy link
Collaborator Author

Oliver-Loeffler commented Apr 4, 2024

@abhinayagarwal or @AlmasB Could you please review this one?
This one addresses the issue, that some FXMLs have import statements which cannot be resolved by Scene Builder (e.g. JARs not availabl etc,). This one solves #120.

The idea is:

  • SceneBuilder offers a preferences setting to ignore (and preserve) unresolvable imports.
  • If it is permitted to load FXMLs with unknown types:
    • The resulting FXOMDocument will keep track of the unknown types.
    • FXOMSaver and FXOMRefresher will ignore those imports (e.g. will also remove them conditionally from any intermediate created FXML text).

Interesting would be your opinion to see if this approach is helpful and maintainable.

Thanks!

@Oliver-Loeffler Oliver-Loeffler self-assigned this Apr 4, 2024
@Oliver-Loeffler Oliver-Loeffler removed this from the 22 milestone Apr 4, 2024
@abhinayagarwal
Copy link
Collaborator

I tested this PR, here are my observations:

  1. When SB is unable to find import for a Parent, it will load the FXML with with a yellow sign
  2. When SB is unable to find import for a Control, it will fail to load the FXML and show "File Open Error" dialog

I wonder what value 1 brings to the table because any components/children in the parent will be lost if edited in SB 🤔

@Oliver-Loeffler
Copy link
Collaborator Author

Oliver-Loeffler commented Apr 11, 2024

Please checkout the preferences dialog. There is a new setting. This is disabled by default stick with current Scene Builder behavior by default.

grafik

Also SceneBuilder will now also notify the user that there are unresolvable imports and that an FXML file with such cannot be properly edited. However, one can at least open it and work with it. Especially since there are cases where the imports are sometimes only needed to get some userData. The dialog will show the first 10 imports. If there are more, the details window will show. Well, instead of this dialog we could show a notification, like in ControlsFX.

grafik

However, default behavior is to not allow loading of FXMLs with unknown or broken imports.

Interestingly, the FXOMDocument knows that there are unknown imports. One could even notify the user upon save action that the resulting FXML might break.

This is IMHO bettern than either not opening an FXML or silently breaking it.

@Oliver-Loeffler
Copy link
Collaborator Author

Hi @abhinayagarwal, do you have any chance to review this one again?

@Oliver-Loeffler Oliver-Loeffler modified the milestones: 23, 24 Sep 27, 2024
@Oliver-Loeffler Oliver-Loeffler changed the title fix: enable Scene Builder to load FXML with unresolved imports (which are still preserved) fix: enable Scene Builder to load FXML with unresolved imports (#120, #281, #733) Sep 29, 2024
@Oliver-Loeffler Oliver-Loeffler added the bug Something isn't working label Sep 29, 2024
Copy link
Collaborator

@jperedadnr jperedadnr left a comment

Choose a reason for hiding this comment

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

Looks really good! Great contribution.
I've left a few comments.

Note also that you might need to disable the Preview option if there are unresolved imports, otherwise it fails with a RTE:

java.lang.RuntimeException: Bug in PreviewWindowController::requestUpdate
        at [email protected]/com.oracle.javafx.scenebuilder.kit.preview.PreviewWindowController$1.lambda$run$1(PreviewWindowController.java:269)

public static FXOMDocumentSwitch[] combined(FXOMDocumentSwitch[] existingSwitches,
FXOMDocumentSwitch newSwitch) {
Set<FXOMDocumentSwitch> options = EnumSet.of(FXOMDocumentSwitch.NORMALIZED);
options.addAll(Set.of(existingSwitches));
Copy link
Collaborator

Choose a reason for hiding this comment

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

or else, newSwitch is unused, and you are missing options.add(newSwitch);?

if (toggle) {
return new FXOMDocumentSwitch[] {this};
} else {
return new FXOMDocumentSwitch[0];
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe use new FXOMDocumentSwitch[] {}?

*/
public static FXOMDocumentSwitch[] combined(FXOMDocumentSwitch[] existingSwitches,
FXOMDocumentSwitch newSwitch) {
Set<FXOMDocumentSwitch> options = EnumSet.of(FXOMDocumentSwitch.NORMALIZED);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you include NORMALIZED here?

In EditorController you call: FXOMDocumentSwitch.combined(switches, FXOMDocumentSwitch.NORMALIZED);

Do you mean Set<FXOMDocumentSwitch> options = EnumSet.of(newSwitch);?


private boolean hasControlsFromExternalPlugin;

private List<Class<?>> initialDeclaredClasses;

Copy link
Collaborator

Choose a reason for hiding this comment

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

Unneeded extra line

this.glue = new GlueDocument(fxmlText);
this.location = location;
this.classLoader = classLoader;
this.resources = resources;
initialDeclaredClasses = new ArrayList<>();
this.initialDeclaredClasses = new ArrayList<>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unneeded use of this here

for (Entry<String,Pattern> entry : typesToRemove.entrySet()) {
var pattern = entry.getValue().matcher(lineToTest);
if (pattern.matches()) {
LOGGER.log(Level.INFO, "Import to ignore: {0}", lineToTest);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Lower to Level.FINE?

if (Platform.isFxApplicationThread()) {
return callable.call();
} else {
Platform.runLater(()->task.run());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Platform.runLater(task);

@@ -281,14 +282,61 @@ public void that_missing_imports_during_defines_resolution_cause_exception() thr
assertEquals(IllegalStateException.class, t.getClass());
assertTrue(t.getMessage().contains("Bug in FXOMRefresher"));
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

unneeded extra line

()->waitFor(()->new FXOMDocument(fxmlText, location, classLoader, resources, switches)));

if (t.getCause() != null) {
t = t.getCause();
Copy link
Collaborator

Choose a reason for hiding this comment

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

unused, missing an assertion?

errorDialog.setDebugInfo(I18N.getString("alert.open.failure.unresolved.imports.advice",
allMissing, missingTypes.size()));
errorDialog.setTitle(I18N.getString("alert.title.open") + ": " + fxmlFile.getName());
errorDialog.showAndWait();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion: add a button to the dialog with an Open FXML/JAR Manager option, so the user can add the missing dependency.

@Oliver-Loeffler
Copy link
Collaborator Author

Thank you for the feedback @jperedadnr, I'll look into and rework accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
3 participants