Skip to content

Commit

Permalink
fix: Allows Scene Builder conditionally to load FXML files with
Browse files Browse the repository at this point in the history
unresolved imports.

There is also a new option (preserve unresolved imports) which also
allows to keep the imports in saved FXML files.
  • Loading branch information
Oliver-Loeffler committed Oct 3, 2022
1 parent 7711a71 commit 8f48abb
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.oracle.javafx.scenebuilder.kit.editor.selection.AbstractSelectionGroup;
import com.oracle.javafx.scenebuilder.kit.editor.selection.ObjectSelectionGroup;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.FXOMDocumentSwitch;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMNodes;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
import com.oracle.javafx.scenebuilder.kit.library.Library;
Expand Down Expand Up @@ -395,7 +396,13 @@ public SplitController getDocumentSplitController() {
public void loadFromFile(File fxmlFile) throws IOException {
final URL fxmlURL = fxmlFile.toURI().toURL();
final String fxmlText = FXOMDocument.readContentFromURL(fxmlURL);
editorController.setFxmlTextAndLocation(fxmlText, fxmlURL, false);

FXOMDocumentSwitch[] options = PreferencesController.getSingleton().getRecordGlobal()
.isPreserveUnresolvedImports()
? new FXOMDocumentSwitch[] {FXOMDocumentSwitch.PRESERVE_UNRESOLVED_IMPORTS}
: new FXOMDocumentSwitch[0];

editorController.setFxmlTextAndLocation(fxmlText, fxmlURL, false, options);
updateLoadFileTime();
updateStageTitle(); // No-op if fxml has not been loaded yet
updateFromDocumentPreferences(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Gluon and/or its affiliates.
* Copyright (c) 2016, 2022, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
Expand Down Expand Up @@ -98,6 +98,7 @@ public String toString() {
static final int DEFAULT_RECENT_ITEMS_SIZE = 15;
static final boolean DEFAULT_ACCORDION_ANIMATION = true;
static final boolean DEFAULT_WILDCARD_IMPORTS = false;
static final boolean DEFAULT_PRESERVE_UNRESOLVED_IMPORTS = true;

/***************************************************************************
* *
Expand All @@ -113,6 +114,7 @@ public String toString() {
private int recentItemsSize = DEFAULT_RECENT_ITEMS_SIZE;
private boolean accordionAnimation = DEFAULT_ACCORDION_ANIMATION;
private boolean wildcardImports = DEFAULT_WILDCARD_IMPORTS;
private boolean preserveUnresolvedImports = DEFAULT_PRESERVE_UNRESOLVED_IMPORTS;
private final List<String> recentItems = new ArrayList<>();

private LocalDate showUpdateDialogDate = null;
Expand Down Expand Up @@ -382,6 +384,14 @@ public void setWildcardImports(boolean wildcardImports) {
this.wildcardImports = wildcardImports;
}

public boolean isPreserveUnresolvedImports() {
return this.preserveUnresolvedImports;
}

public void setPreserveUnresolvedImports(boolean preserveUnresolvedImports) {
this.preserveUnresolvedImports = preserveUnresolvedImports;
}

/**
* Read data from the java preferences DB and initialize properties.
*/
Expand Down Expand Up @@ -468,7 +478,7 @@ public void readFromJavaPreferences() {

// Wildcard imports
setWildcardImports(applicationRootPreferences.getBoolean(WILDCARD_IMPORT, DEFAULT_WILDCARD_IMPORTS));

setPreserveUnresolvedImports(applicationRootPreferences.getBoolean(PRESERVE_UNRESOLVED_IMPORTS, DEFAULT_PRESERVE_UNRESOLVED_IMPORTS));
}

public void writeToJavaPreferences(String key) {
Expand Down Expand Up @@ -535,6 +545,9 @@ public void writeToJavaPreferences(String key) {
case WILDCARD_IMPORT:
applicationRootPreferences.putBoolean(WILDCARD_IMPORT, isWildcardImports());
break;
case PRESERVE_UNRESOLVED_IMPORTS:
applicationRootPreferences.putBoolean(PRESERVE_UNRESOLVED_IMPORTS, isPreserveUnresolvedImports());
break;
default:
super.writeToJavaPreferences(key);
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Gluon and/or its affiliates.
* Copyright (c) 2016, 2022, Gluon and/or its affiliates.
* Copyright (c) 2012, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
Expand Down Expand Up @@ -53,6 +53,7 @@
import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.RECENT_ITEMS_SIZE;
import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.TOOL_THEME;
import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.WILDCARD_IMPORT;
import static com.oracle.javafx.scenebuilder.app.preferences.PreferencesController.PRESERVE_UNRESOLVED_IMPORTS;

import static com.oracle.javafx.scenebuilder.kit.preferences.PreferencesRecordGlobalBase.DEFAULT_ALIGNMENT_GUIDES_COLOR;
import static com.oracle.javafx.scenebuilder.kit.preferences.PreferencesRecordGlobalBase.DEFAULT_BACKGROUND_IMAGE;
Expand Down Expand Up @@ -139,6 +140,8 @@ public class PreferencesWindowController extends AbstractFxmlWindowController {
private CheckBox animateAccordion;
@FXML
private CheckBox wildcardImports;
@FXML
private CheckBox preserveUnresolvedImports;

private PaintPicker alignmentColorPicker;
private PaintPicker parentRingColorPicker;
Expand Down Expand Up @@ -259,6 +262,9 @@ protected void controllerDidLoadFxml() {
// Wildcard Imports
wildcardImports.setSelected(recordGlobal.isWildcardImports());
wildcardImports.selectedProperty().addListener(new WildcardImportListener());

preserveUnresolvedImports.setSelected(recordGlobal.isPreserveUnresolvedImports());
preserveUnresolvedImports.selectedProperty().addListener(new PreserveUnresolvedImportListener());
}

/*
Expand Down Expand Up @@ -576,4 +582,14 @@ public void changed(ObservableValue<? extends Boolean> observable, Boolean oldVa
recordGlobal.writeToJavaPreferences(WILDCARD_IMPORT);
}
}

private static class PreserveUnresolvedImportListener implements ChangeListener<Boolean> {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
final PreferencesController preferencesController = PreferencesController.getSingleton();
final PreferencesRecordGlobal recordGlobal = preferencesController.getRecordGlobal();
recordGlobal.setPreserveUnresolvedImports(newValue);
recordGlobal.writeToJavaPreferences(PRESERVE_UNRESOLVED_IMPORTS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ prefs.cssanalyzer.columns.defaults.last = "Defaults" Column Last
prefs.recent.items = Recent items :
prefs.animate.accordion = Animate Accordion :
prefs.wildcard.import = Use Wildcard Imports :
prefs.preserve.unresolved.import = Keep unresolved imports :
prefs.reset.default = Reset to Builtin Default Values
prefs.document.theme = Default Theme :
prefs.document.gluonswatch = Default Gluon Swatch :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@
<?import java.lang.String?>
<?import javafx.collections.FXCollections?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.CustomMenuItem?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.shape.Rectangle?>

<GridPane hgap="6.0" maxWidth="1.7976931348623157E308" styleClass="theme-presets" vgap="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<GridPane hgap="6.0" maxWidth="1.7976931348623157E308" styleClass="theme-presets" vgap="10.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="%prefs.doc.width" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<DoubleField fx:id="rootContainerWidth" prefWidth="200.0" text="" GridPane.columnIndex="1" GridPane.rowIndex="0" />
Expand Down Expand Up @@ -121,14 +121,16 @@
<Separator prefWidth="-1.0" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="16" />

<Label text="%prefs.animate.accordion" GridPane.columnIndex="0" GridPane.rowIndex="17" />
<CheckBox fx:id="animateAccordion" selected="true" GridPane.columnIndex="1" GridPane.rowIndex="17"/>
<CheckBox fx:id="animateAccordion" selected="true" GridPane.columnIndex="1" GridPane.rowIndex="17" />

<Label text="%prefs.wildcard.import" GridPane.columnIndex="0" GridPane.rowIndex="18" />
<CheckBox fx:id="wildcardImports" selected="true" GridPane.columnIndex="1" GridPane.rowIndex="18"/>
<CheckBox fx:id="wildcardImports" selected="true" GridPane.columnIndex="1" GridPane.rowIndex="18" />

<Separator prefWidth="-1.0" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="19" />
<Separator prefWidth="-1.0" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="20" />

<Button onAction="#resetToDefaultAction" prefWidth="-1.0" text="%prefs.reset.default" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.rowIndex="20" />
<Button onAction="#resetToDefaultAction" prefWidth="-1.0" text="%prefs.reset.default" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.rowIndex="21" />
<Label text="%prefs.preserve.unresolved.import" GridPane.rowIndex="19" />
<CheckBox fx:id="preserveUnresolvedImports" selected="true" GridPane.columnIndex="1" GridPane.rowIndex="19" />
</children>
<columnConstraints>
<ColumnConstraints halignment="RIGHT" hgrow="SOMETIMES" maxWidth="-Infinity" minWidth="-Infinity" />
Expand All @@ -138,20 +140,27 @@
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="-1.0" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" vgrow="NEVER" />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
</GridPane>
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.ResourceBundle;
Expand Down Expand Up @@ -758,10 +759,11 @@ public void setFxmlTextAndLocation(String fxmlText, URL fxmlLocation) throws IOE
* @param fxmlLocation null or the location of the fxml text being edited
* @param checkTheme if set to true a check will be made if the fxml contains
* Gluon controls and if so, the correct theme is set
* @param switches Optional switches to configure FXOM and FXML processes
* @throws IOException if fxml text cannot be parsed and loaded correctly.
*/
public void setFxmlTextAndLocation(String fxmlText, URL fxmlLocation, boolean checkTheme) throws IOException {
updateFxomDocument(fxmlText, fxmlLocation, getResources(), checkTheme);
public void setFxmlTextAndLocation(String fxmlText, URL fxmlLocation, boolean checkTheme, FXOMDocumentSwitch ... switches) throws IOException {
updateFxomDocument(fxmlText, fxmlLocation, getResources(), checkTheme, switches);
this.fxmlLocationProperty.setValue(fxmlLocation);
}

Expand Down Expand Up @@ -2554,11 +2556,13 @@ private boolean isSelectionControl() {
return true;
}

private void updateFxomDocument(String fxmlText, URL fxmlLocation, ResourceBundle resources, boolean checkTheme) throws IOException {
private void updateFxomDocument(String fxmlText, URL fxmlLocation, ResourceBundle resources, boolean checkTheme, FXOMDocumentSwitch ... switches) throws IOException {
final FXOMDocument newFxomDocument;

if (fxmlText != null) {
newFxomDocument = new FXOMDocument(fxmlText, fxmlLocation, getLibrary().getClassLoader(), resources, FXOMDocumentSwitch.NORMALIZED);
Set<FXOMDocumentSwitch> options = EnumSet.of(FXOMDocumentSwitch.NORMALIZED);
options.addAll(Set.of(switches));
newFxomDocument = new FXOMDocument(fxmlText, fxmlLocation, getLibrary().getClassLoader(), resources, options.toArray(new FXOMDocumentSwitch[0]));
} else {
newFxomDocument = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;

import com.oracle.javafx.scenebuilder.kit.fxom.glue.GlueDocument;
Expand Down Expand Up @@ -77,6 +78,7 @@ public class FXOMDocument {
private final SimpleIntegerProperty cssRevision = new SimpleIntegerProperty();
private SceneGraphHolder sceneGraphHolder;
private int updateDepth;
private List<String> missingClasses = new ArrayList<>();

private boolean hasGluonControls;

Expand Down Expand Up @@ -112,7 +114,7 @@ public FXOMDocument(String fxmlText, URL location, ClassLoader classLoader, Reso
fxmlTextToLoad = fxmlPropertiesDisabler.disableProperties(fxmlText);
}
final FXOMLoader loader = new FXOMLoader(this);
loader.load(fxmlTextToLoad);
loader.load(fxmlTextToLoad, switches);
if (availableSwitches.contains(FXOMDocumentSwitch.NORMALIZED)) {
final FXOMNormalizer normalizer = new FXOMNormalizer(this);
normalizer.normalize();
Expand All @@ -126,6 +128,24 @@ public FXOMDocument(String fxmlText, URL location, ClassLoader classLoader, Reso

hasGluonControls = fxmlText.contains(EditorPlatform.GLUON_PACKAGE);
}

/**
* Adds the name of a class or a name space which could not be resolved by FXMLLoader.
*
* @param missingClassName Either a class namr from an import or a name space from a wild card import.
*/
public void addMissingClass(String missingClassName) {
this.missingClasses.add(missingClassName);
}

/**
* If there were unresolved FXML import statements, affected class names and package name spaces are provided here.
*
* @return list of unresolved FXML import class names or name spaces.
*/
public List<String> getMissingClasses() {
return this.missingClasses;
}

public FXOMDocument() {
this.glue = new GlueDocument();
Expand Down Expand Up @@ -159,7 +179,7 @@ public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
endUpdate();
}

public List<Class<?>> getInitialDeclaredClasses() {
return initialDeclaredClasses;
}
Expand Down Expand Up @@ -201,8 +221,8 @@ public void setSampleDataEnabled(boolean sampleDataEnabled) {
sampleDataGenerator.assignSampleData(fxomRoot);
}
}
}
}

public FXOMObject getFxomRoot() {
return fxomRoot;
}
Expand Down Expand Up @@ -480,6 +500,12 @@ public enum FXOMDocumentSwitch {
* configuration. One possible example here is the option to use the MacOS
* system menu bar.
*/
FOR_PREVIEW;
FOR_PREVIEW,

/**
* This flag ensures that the {@link FXOMLoader} preserves imports which were not resolvable by {@link FXMLLoader}.
* This behavior is controlled using Preferences-API.
*/
PRESERVE_UNRESOLVED_IMPORTS;
}
}
Loading

0 comments on commit 8f48abb

Please sign in to comment.