diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..3a23aeb8d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: https://EditorConfig.org +root = true + +[*.java] +indent_style = space +indent_size = 4 + +[*.fxml] +indent_style = space +indent_size = 2 + +[*.yml] +indent_style = space +indent_size = 2 + +[pom.xml] +indent_style = space +indent_size = 4 + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c97f5deeb..455b5ff9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ on: pull_request: env: - JAVA_VERSION: '21' + JAVA_VERSION: '23' jobs: verify: @@ -14,10 +14,10 @@ jobs: os: [ macos-latest, windows-latest, ubuntu-latest ] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/bundles-kit.yml b/.github/workflows/bundles-kit.yml index f0e03dfe1..16f0cb9b4 100644 --- a/.github/workflows/bundles-kit.yml +++ b/.github/workflows/bundles-kit.yml @@ -7,7 +7,7 @@ on: required: true type: string java-version: - default: '21.0.1' + default: '23' required: false type: string @@ -15,16 +15,16 @@ jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ inputs.java-version }} - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -40,7 +40,7 @@ jobs: PROJECT_VERSION: ${{ inputs.project-version }} - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: artifacts + name: scenebuilder-kit-${{ inputs.project-version }}.jar path: kit/target/lib/*.jar diff --git a/.github/workflows/bundles-linux.yml b/.github/workflows/bundles-linux.yml index edf745e2b..2c2779f29 100644 --- a/.github/workflows/bundles-linux.yml +++ b/.github/workflows/bundles-linux.yml @@ -10,11 +10,11 @@ on: required: true type: string java-version: - default: '21.0.1' + default: '23' required: false type: string javafx-version: - default: '21.0.1' + default: '23' required: false type: string test: @@ -29,21 +29,24 @@ jobs: - name: Install packages run: sudo apt-get install xdg-utils - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ inputs.java-version }} - name: Setup JavaFX + id: javafx run: | - wget -P /tmp https://download2.gluonhq.com/openjfx/${{ inputs.javafx-version }}/openjfx-${{ inputs.javafx-version }}_linux-x64_bin-jmods.zip + JAVAFX_MAJOR_VERSION=$(echo ${{ inputs.javafx-version }} | cut -d- -f1) + echo JAVAFX_MAJOR_VERSION=$JAVAFX_MAJOR_VERSION >> $GITHUB_OUTPUT + wget -P /tmp https://download2.gluonhq.com/openjfx/$JAVAFX_MAJOR_VERSION/openjfx-${{ inputs.javafx-version }}_linux-x64_bin-jmods.zip unzip /tmp/openjfx-${{ inputs.javafx-version }}_linux-x64_bin-jmods.zip -d /tmp - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -89,16 +92,22 @@ jobs: ls ${{ env.INSTALL_DIR }} env: MAIN_CLASS: com.oracle.javafx.scenebuilder.app.SceneBuilderApp - JAVAFX_HOME: /tmp/javafx-jmods-${{ inputs.javafx-version }}/ + JAVAFX_HOME: /tmp/javafx-jmods-${{ steps.javafx.outputs.JAVAFX_MAJOR_VERSION }}/ JPACKAGE_HOME: ${{ env.JAVA_HOME }} PROJECT_VERSION: ${{ inputs.project-version }} APP_VERSION: ${{ inputs.app-version }} INSTALL_DIR: app/target/install - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: artifacts + name: SceneBuilder-${{ inputs.project-version }}.deb path: | app/target/install/*.deb + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: SceneBuilder-${{ inputs.project-version }}.rpm + path: | app/target/install/*.rpm diff --git a/.github/workflows/bundles-mac.yml b/.github/workflows/bundles-mac.yml index 7cf811a9f..61fed6407 100644 --- a/.github/workflows/bundles-mac.yml +++ b/.github/workflows/bundles-mac.yml @@ -10,11 +10,11 @@ on: required: true type: string java-version: - default: '21.0.1' + default: '23' required: false type: string javafx-version: - default: '21.0.1' + default: '23' required: false type: string test: @@ -36,12 +36,12 @@ on: required: true jobs: build: - runs-on: macos-latest + runs-on: macos-13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ inputs.java-version }} @@ -52,12 +52,15 @@ jobs: p12-password: ${{ secrets.CERTIFICATES_PASSWORD }} - name: Setup JavaFX + id: javafx run: | - wget -P /tmp https://download2.gluonhq.com/openjfx/${{ inputs.javafx-version }}/openjfx-${{ inputs.javafx-version }}_osx-x64_bin-jmods.zip + JAVAFX_MAJOR_VERSION=$(echo ${{ inputs.javafx-version }} | cut -d- -f1) + echo JAVAFX_MAJOR_VERSION=$JAVAFX_MAJOR_VERSION >> $GITHUB_OUTPUT + wget -P /tmp https://download2.gluonhq.com/openjfx/$JAVAFX_MAJOR_VERSION/openjfx-${{ inputs.javafx-version }}_osx-x64_bin-jmods.zip unzip /tmp/openjfx-${{ inputs.javafx-version }}_osx-x64_bin-jmods.zip -d /tmp - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -89,10 +92,10 @@ jobs: --mac-sign mv ${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.APP_VERSION }}.dmg ${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-amd64.dmg ls ${{ env.INSTALL_DIR }} - echo ::set-output name=path::${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-amd64.dmg + echo path=${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-amd64.dmg >> $GITHUB_OUTPUT env: MAIN_CLASS: com.oracle.javafx.scenebuilder.app.SceneBuilderApp - JAVAFX_HOME: /tmp/javafx-jmods-${{ inputs.javafx-version }}/ + JAVAFX_HOME: /tmp/javafx-jmods-${{ steps.javafx.outputs.JAVAFX_MAJOR_VERSION }}/ JPACKAGE_HOME: ${{ env.JAVA_HOME }} MACSIGN_PREFIX: ${{ secrets.MACSIGN_PREFIX }} MACSIGN_USER: ${{ secrets.MACSIGN_USER }} @@ -109,7 +112,7 @@ jobs: team-id: ${{ secrets.MACSIGN_PREFIX }} - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: artifacts + name: SceneBuilder-${{ inputs.project-version }}-amd64.dmg path: ${{ steps.outputfile.outputs.path }} diff --git a/.github/workflows/bundles-mac_aarch64.yml b/.github/workflows/bundles-mac_aarch64.yml index 631c85649..c59950aa1 100644 --- a/.github/workflows/bundles-mac_aarch64.yml +++ b/.github/workflows/bundles-mac_aarch64.yml @@ -10,11 +10,11 @@ on: required: true type: string java-version: - default: '21.0.1' + default: '23' required: false type: string javafx-version: - default: '21.0.1' + default: '23' required: false type: string test: @@ -37,32 +37,31 @@ on: jobs: build: name: macOS on M1 - runs-on: [macOS, ARM64] - env: - KEYCHAIN: job-${{ github.job }}-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }} + runs-on: macos-14 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ inputs.java-version }} - uses: Apple-Actions/import-codesign-certs@v1 with: - keychain: ${{ env.KEYCHAIN }} p12-file-base64: ${{ secrets.CERTIFICATES_FILE_BASE64 }} p12-password: ${{ secrets.CERTIFICATES_PASSWORD }} - name: Setup JavaFX + id: javafx run: | - rm -rf /tmp/javafx-jmods-${{ inputs.javafx-version }} - wget -P /tmp https://download2.gluonhq.com/openjfx/${{ inputs.javafx-version }}/openjfx-${{ inputs.javafx-version }}_osx-aarch64_bin-jmods.zip + JAVAFX_MAJOR_VERSION=$(echo ${{ inputs.javafx-version }} | cut -d- -f1) + echo JAVAFX_MAJOR_VERSION=$JAVAFX_MAJOR_VERSION >> $GITHUB_OUTPUT + wget -P /tmp https://download2.gluonhq.com/openjfx/$JAVAFX_MAJOR_VERSION/openjfx-${{ inputs.javafx-version }}_osx-aarch64_bin-jmods.zip unzip /tmp/openjfx-${{ inputs.javafx-version }}_osx-aarch64_bin-jmods.zip -d /tmp - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -94,10 +93,10 @@ jobs: --mac-sign mv ${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.APP_VERSION }}.dmg ${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-aarch64.dmg ls ${{ env.INSTALL_DIR }} - echo ::set-output name=path::${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-aarch64.dmg + echo path=${{ env.INSTALL_DIR }}/SceneBuilder-${{ env.PROJECT_VERSION }}-aarch64.dmg >> $GITHUB_OUTPUT env: MAIN_CLASS: com.oracle.javafx.scenebuilder.app.SceneBuilderApp - JAVAFX_HOME: /tmp/javafx-jmods-${{ inputs.javafx-version }}/ + JAVAFX_HOME: /tmp/javafx-jmods-${{ steps.javafx.outputs.JAVAFX_MAJOR_VERSION }}/ JPACKAGE_HOME: ${{ env.JAVA_HOME }} MACSIGN_PREFIX: ${{ secrets.MACSIGN_PREFIX }} MACSIGN_USER: ${{ secrets.MACSIGN_USER }} @@ -114,11 +113,7 @@ jobs: team-id: ${{ secrets.MACSIGN_PREFIX }} - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: artifacts + name: SceneBuilder-${{ inputs.project-version }}-aarch64.dmg path: ${{ steps.outputfile.outputs.path }} - - - name: Delete keychain - run: | - security delete-keychain "${{ env.KEYCHAIN }}".keychain diff --git a/.github/workflows/bundles-windows.yml b/.github/workflows/bundles-windows.yml index 36723f4e1..a4009f006 100644 --- a/.github/workflows/bundles-windows.yml +++ b/.github/workflows/bundles-windows.yml @@ -10,11 +10,11 @@ on: required: true type: string java-version: - default: '21.0.1' + default: '23' required: false type: string javafx-version: - default: '21.0.1' + default: '23' required: false type: string test: @@ -33,22 +33,25 @@ jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ inputs.java-version }} - name: Setup JavaFX + id: javafx shell: pwsh run: | - Invoke-WebRequest -Uri https://download2.gluonhq.com/openjfx/${{ inputs.javafx-version }}/openjfx-${{ inputs.javafx-version }}_windows-x64_bin-jmods.zip -OutFile D:\openjfx-${{ inputs.javafx-version }}_windows-x64_bin-jmods.zip + $JAVAFX_MAJOR_VERSION = '${{ inputs.javafx-version }}' -split '-' | Select-Object -Index 0 + echo "JAVAFX_MAJOR_VERSION=$JAVAFX_MAJOR_VERSION" >> $env:GITHUB_OUTPUT + Invoke-WebRequest -Uri https://download2.gluonhq.com/openjfx/$JAVAFX_MAJOR_VERSION/openjfx-${{ inputs.javafx-version }}_windows-x64_bin-jmods.zip -OutFile D:\openjfx-${{ inputs.javafx-version }}_windows-x64_bin-jmods.zip Expand-Archive -Force D:\openjfx-${{ inputs.javafx-version }}_windows-x64_bin-jmods.zip D:\ - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -75,7 +78,7 @@ jobs: call dir ${{ env.INSTALL_DIR }} env: MAIN_CLASS: com.oracle.javafx.scenebuilder.app.SceneBuilderApp - JAVAFX_HOME: D:\javafx-jmods-${{ inputs.javafx-version }} + JAVAFX_HOME: D:\javafx-jmods-${{ steps.javafx.outputs.JAVAFX_MAJOR_VERSION }} JPACKAGE_HOME: ${{ env.JAVA_HOME }} PROJECT_VERSION: ${{ inputs.project-version }} APP_VERSION: ${{ inputs.app-version }} @@ -91,7 +94,7 @@ jobs: folder: 'app/target/install' - name: Upload Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: artifacts + name: SceneBuilder-${{ inputs.project-version }}.msi path: app/target/install/*.msi diff --git a/.github/workflows/early-access.yml b/.github/workflows/early-access.yml index 7954621c8..ef2bcb60b 100644 --- a/.github/workflows/early-access.yml +++ b/.github/workflows/early-access.yml @@ -5,8 +5,8 @@ on: branches: [ master ] env: - JAVAFX_VERSION: '21.0.1' - JAVA_VERSION: '21' + JAVAFX_VERSION: '23' + JAVA_VERSION: '23' jobs: precheck: @@ -19,16 +19,16 @@ jobs: PROJECT_VERSION: ${{ steps.vars.outputs.PROJECT_VERSION }} steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ env.JAVA_VERSION }} - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -41,12 +41,12 @@ jobs: PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) APP_VERSION=$PROJECT_VERSION APP_VERSION=${APP_VERSION%-*} - echo ::set-output name=APP_VERSION::$APP_VERSION - echo ::set-output name=PROJECT_VERSION::$PROJECT_VERSION + echo APP_VERSION=$APP_VERSION >> $GITHUB_OUTPUT + echo PROJECT_VERSION=$PROJECT_VERSION >> $GITHUB_OUTPUT linux-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-linux.yml@master + uses: ./.github/workflows/bundles-linux.yml with: javafx-version: ${{ needs.precheck.outputs.JAVAFX_VERSION }} java-version: ${{ needs.precheck.outputs.JAVA_VERSION }} @@ -56,7 +56,7 @@ jobs: windows-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-windows.yml@master + uses: ./.github/workflows/bundles-windows.yml secrets: WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} WINDOWS_PASSWORD: ${{ secrets.WINDOWS_PASSWORD }} @@ -70,7 +70,7 @@ jobs: mac-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-mac.yml@master + uses: ./.github/workflows/bundles-mac.yml secrets: CERTIFICATES_FILE_BASE64: ${{ secrets.CERTIFICATES_FILE_BASE64 }} CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} @@ -87,7 +87,7 @@ jobs: mac_aarch64-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-mac_aarch64.yml@master + uses: ./.github/workflows/bundles-mac_aarch64.yml secrets: CERTIFICATES_FILE_BASE64: ${{ secrets.CERTIFICATES_FILE_BASE64 }} CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} @@ -104,7 +104,7 @@ jobs: kit-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-kit.yml@master + uses: ./.github/workflows/bundles-kit.yml with: java-version: ${{ needs.precheck.outputs.JAVA_VERSION }} project-version: ${{ needs.precheck.outputs.PROJECT_VERSION }} @@ -115,21 +115,24 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download all build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true - name: Set up Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ needs.precheck.outputs.JAVA_VERSION }} - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -143,7 +146,7 @@ jobs: - name: JReleaser output if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: jreleaser-logs path: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e0e0f9230..49b800eba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,8 +11,8 @@ on: - GA env: - JAVAFX_VERSION: '21.0.1' - JAVA_VERSION: '21' + JAVAFX_VERSION: '23' + JAVA_VERSION: '23' jobs: precheck: @@ -25,16 +25,16 @@ jobs: S3_PATH: ${{ steps.vars.outputs.S3_PATH }} steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ env.JAVA_VERSION }} - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} @@ -54,13 +54,13 @@ jobs: S3_PATH=RC/$PROJECT_VERSION fi echo "Releasing.. "$PROJECT_VERSION - echo ::set-output name=APP_VERSION::$APP_VERSION - echo ::set-output name=PROJECT_VERSION::$PROJECT_VERSION - echo ::set-output name=S3_PATH::$S3_PATH + echo APP_VERSION=$APP_VERSION >> $GITHUB_OUTPUT + echo PROJECT_VERSION=$PROJECT_VERSION >> $GITHUB_OUTPUT + echo S3_PATH=$S3_PATH >> $GITHUB_OUTPUT linux-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-linux.yml@master + uses: ./.github/workflows/bundles-linux.yml with: javafx-version: ${{ needs.precheck.outputs.JAVAFX_VERSION }} java-version: ${{ needs.precheck.outputs.JAVA_VERSION }} @@ -70,7 +70,7 @@ jobs: windows-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-windows.yml@master + uses: ./.github/workflows/bundles-windows.yml secrets: WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} WINDOWS_PASSWORD: ${{ secrets.WINDOWS_PASSWORD }} @@ -84,7 +84,7 @@ jobs: mac-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-mac.yml@master + uses: ./.github/workflows/bundles-mac.yml secrets: CERTIFICATES_FILE_BASE64: ${{ secrets.CERTIFICATES_FILE_BASE64 }} CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} @@ -101,7 +101,7 @@ jobs: mac_aarch64-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-mac_aarch64.yml@master + uses: ./.github/workflows/bundles-mac_aarch64.yml secrets: CERTIFICATES_FILE_BASE64: ${{ secrets.CERTIFICATES_FILE_BASE64 }} CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }} @@ -118,7 +118,7 @@ jobs: kit-bundles: needs: [precheck] - uses: gluonhq/scenebuilder/.github/workflows/bundles-kit.yml@master + uses: ./.github/workflows/bundles-kit.yml with: java-version: ${{ needs.precheck.outputs.JAVA_VERSION }} project-version: ${{ needs.precheck.outputs.PROJECT_VERSION }} @@ -128,25 +128,28 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Check out repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Java - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@v1.4.0 with: website: jdk.java.net release: ${{ needs.precheck.outputs.JAVA_VERSION }} - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Download all build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true - name: Set Release Version run: | @@ -170,7 +173,7 @@ jobs: - name: JReleaser output if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: jreleaser-logs path: | diff --git a/README.md b/README.md index 4d6a02f60..d59c37696 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,10 @@ See the [documentation](http://docs.gluonhq.com/scenebuilder/) about the new fea For community support, go to [StackOverflow](https://stackoverflow.com/questions/tagged/scenebuilder). +### Requirements on Linux ### + +On Linux systems, Scene Builder uses the `xdg-open` command to reveal files in the system's default file system browser or to open URLs in the default web browser. Most modern Linux Desktop Environments already provide the [xdg-utils](https://freedesktop.org/wiki/Software/xdg-utils/) package. If it is missing, it can be installed using the respective Linux package management tool such as `yum`, `apt-get`, `dnf` or `pacman`. The `xdg-utils` package is usually available on KDE based systems, some Arch based systems may require manual installations. + ## Issues and Contributions ## Issues can be reported to the [Issue tracker](https://github.com/gluonhq/scenebuilder/issues/) @@ -35,7 +39,7 @@ Gluon Scene Builder is frequently released, and this is only required in case yo These are the requisites: -* A recent version of [JDK 11 or later](https://www.oracle.com/technetwork/java/javase/downloads/index.html) for building 'master' branch +* A recent version of [JDK 21 or later](https://www.oracle.com/technetwork/java/javase/downloads/index.html) for building 'master' branch * A recent version of [JDK 8](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) for building '8u-dev' branch ### How to build Scene Builder ### @@ -110,3 +114,4 @@ There will be a report for each sub-project, one for `app` and one for `kit`. * Kit: `kit/target/site/checkstyle.html` * App: `app/target/site/checkstyle.html` +This project makes use of [EditorConfig](https://editorconfig.org/) which is [directly supported](https://editorconfig.org/#pre-installed) by IntelliJ IDEA. There are plugins for NetBeans, Eclipse and Visual Studio and [more](https://editorconfig.org/#download). EditorConfig ensures via configuration in `.editorconfig` file, that the proper indentation is used. diff --git a/app/pom.xml b/app/pom.xml index e4989ed9e..6659f97ec 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -7,11 +7,11 @@ com.gluonhq.scenebuilder parent - 21.0.2-SNAPSHOT + 24.0.0-SNAPSHOT - com.oracle.javafx.scenebuilder.app.SceneBuilderApp + com.gluonhq.scenebuilder.app/com.oracle.javafx.scenebuilder.app.SceneBuilderApp ${maven.build.timestamp} ${maven.build.timestamp.format} diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/AppPlatform.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/AppPlatform.java index 3d7e77235..98e183e19 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/AppPlatform.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/AppPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -56,7 +56,11 @@ public class AppPlatform { private static String messageBoxFolder; private static String logsFolder; private static MessageBox messageBox; - + + AppPlatform() { + // no-op + } + public static synchronized String getApplicationDataFolder() { if (applicationDataFolder == null) { diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java index 32fd42e5e..087679214 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/DocumentWindowController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -47,6 +47,7 @@ import com.oracle.javafx.scenebuilder.kit.editor.EditorController.ControlAction; import com.oracle.javafx.scenebuilder.kit.editor.EditorController.EditAction; import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; +import com.oracle.javafx.scenebuilder.kit.editor.FileBrowserRevealException; import com.oracle.javafx.scenebuilder.kit.editor.job.Job; import com.oracle.javafx.scenebuilder.kit.editor.panel.content.ContentPanelController; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.CssPanelController; @@ -94,6 +95,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; import javafx.beans.InvalidationListener; import javafx.beans.binding.Bindings; @@ -184,6 +187,8 @@ public enum ActionStatus { DONE } + private static final Logger LOGGER = Logger.getLogger(DocumentWindowController.class.getName()); + private final EditorController editorController = new EditorController(); private final MenuBarController menuBarController = new MenuBarController(this); private final ContentPanelController contentPanelController = new ContentPanelController(editorController); @@ -1035,6 +1040,10 @@ public boolean isUnused() { public static class TitleComparator implements Comparator { + public TitleComparator() { + // no-op + } + @Override public int compare(DocumentWindowController d1, DocumentWindowController d2) { final int result; @@ -1467,14 +1476,13 @@ void onLibraryImportSelection(ActionEvent event) { @FXML void onLibraryRevealCustomFolder(ActionEvent event) { String userLibraryPath = ((UserLibrary) getEditorController().getLibrary()).getPath(); + + // ensure that there is no mixup of forward and backward slashes. + File libraryPath = Paths.get(userLibraryPath).normalize().toFile(); try { - EditorPlatform.revealInFileBrowser(new File(userLibraryPath)); - } catch(IOException x) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.reveal.failure.message", getStage().getTitle())); - errorDialog.setDetails(I18N.getString("alert.reveal.failure.details")); - errorDialog.setDebugInfoWithThrowable(x); - errorDialog.showAndWait(); + EditorPlatform.revealInFileBrowser(libraryPath); + } catch (Exception revealError) { + handleRevealFolderException(revealError, String.valueOf(libraryPath)); } } @@ -2185,26 +2193,33 @@ ActionStatus performCloseAction() { return closeConfirmed ? ActionStatus.DONE : ActionStatus.CANCELLED; } - private void performRevealAction() { assert editorController.getFxomDocument() != null; assert editorController.getFxomDocument().getLocation() != null; - + final URL location = editorController.getFxomDocument().getLocation(); - + + File fxmlFile = null; + try { + /* + * Using Path.normalize().toAbsolutePath() ensures that forward and backward slashes are not mixed + * and the path matches the platform requirements. It also ensures, that the file:/ prefix is + * removed from paths and users can directly use the path in their attempt to investigate the error. + */ + fxmlFile = Path.of(location.toURI()).normalize().toAbsolutePath().toFile(); + } catch (URISyntaxException e) { + handleRevealResourceException(e, String.valueOf(location)); + } + try { - final File fxmlFile = new File(location.toURI()); EditorPlatform.revealInFileBrowser(fxmlFile); - } catch(IOException | URISyntaxException x) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.reveal.failure.message", getStage().getTitle())); - errorDialog.setDetails(I18N.getString("alert.reveal.failure.details")); - errorDialog.setDebugInfoWithThrowable(x); - errorDialog.showAndWait(); + } catch (FileBrowserRevealException re) { + handleRevealFileException(re, String.valueOf(fxmlFile)); + } catch (IOException x) { + handleRevealResourceException(x, String.valueOf(fxmlFile)); } } - private void updateLoadFileTime() { final URL fxmlURL = editorController.getFxmlLocation(); @@ -2275,17 +2290,64 @@ private void performHelp() { private void openURL(String url) { try { + LOGGER.log(Level.FINE, "Attempting to open URL: {0}", url); EditorPlatform.open(url); } catch (IOException ioe) { - handleErrorWhenOpeningURL(ioe, url); + LOGGER.log(Level.WARNING, "Error during attempt to open URL!", ioe); + handleRevealResourceException(ioe, url); } } - private void handleErrorWhenOpeningURL(IOException ioe, String url) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.help.failure.message", url)); - errorDialog.setDetails(I18N.getString("alert.messagebox.failure.details")); - errorDialog.setDebugInfoWithThrowable(ioe); + /** + * When an FXML file is to be revealed and an error occurs, the file and the error are displayed in this dialog. + * The error type and its details are displayed within the details window. The dialog itself only + * notifies that there was an error. + * + * @param fileRevealException {@link FileBrowserRevealException} + * @param locationToBeRevealed {@link String} + */ + private void handleRevealFileException(FileBrowserRevealException fileRevealException, String locationToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", locationToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(fileRevealException); + errorDialog.showAndWait(); + } + + /** + * + * Resources may be related to files included with Scene Builder or with arbitrary files (e.g. CSS sheets) + * co-located to a given FXML file. In case of an error opening a resource, a custom dialog is shown. + * + * @param revealException {@link Exception} + * @param locationToBeRevealed {@link String} + */ + private void handleRevealResourceException(Exception revealException, String locationToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.resource.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.resource.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.resource.reveal.details", locationToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.resource.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(revealException); + errorDialog.showAndWait(); + } + + /** + * + * In some cases the resource to be revealed or opened is a directory. Hence the UI dialog should reflect this. + * + * @param revealException {@link Exception} + * @param directoryToBeRevealed {@link String} + */ + private void handleRevealFolderException(Exception revealException, String directoryToBeRevealed) { + final ErrorDialog errorDialog = new ErrorDialog(this.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.directory.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.directory.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.directory.reveal.details", directoryToBeRevealed)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.directory.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(revealException); errorDialog.showAndWait(); } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java index ced064bbc..e63489cd6 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/ResourceController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -35,6 +35,7 @@ import com.oracle.javafx.scenebuilder.app.i18n.I18N; import com.oracle.javafx.scenebuilder.kit.editor.EditorController; import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; +import com.oracle.javafx.scenebuilder.kit.editor.FileBrowserRevealException; import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; import javafx.stage.FileChooser; @@ -46,7 +47,7 @@ /** * */ -class ResourceController { +public class ResourceController { private final DocumentWindowController documentWindowController; private File resourceFile; @@ -97,10 +98,11 @@ public void performRevealResource() { try { EditorPlatform.revealInFileBrowser(resourceFile); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.reveal.title")); - errorDialog.setMessage(I18N.getString("error.file.reveal.message")); - errorDialog.setDetails(I18N.getString("error.filesystem.details")); + final ErrorDialog errorDialog = new ErrorDialog(documentWindowController.getStage()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", resourceFile)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java index f9630b1ce..351a99732 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneBuilderApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -82,9 +82,16 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDate; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; @@ -94,6 +101,8 @@ */ public class SceneBuilderApp extends Application implements AppPlatform.AppNotificationHandler { + private static final Logger LOGGER = Logger.getLogger(SceneBuilderApp.class.getName()); + public enum ApplicationControlAction { ABOUT, CHECK_UPDATES, @@ -496,8 +505,25 @@ private void createEmptyDocumentWindow() { newWindow.updateWithDefaultContent(); } + /** + * By default all necessary actions to open a single file or a group of files take place in this method. + * If it is required to perform certain actions after successfully loading all files, please use {@code handleOpenFilesAction(List files, Runnable onSuccess)} instead. + * + * All error handling takes place here within, there is no way yet to access exceptional results and to work with them. + */ @Override public void handleOpenFilesAction(List files) { + handleOpenFilesAction(files, () -> { /* no operation in this case */ }); + } + + /** + * As file loading errors are handled within this method (all exceptions are handled within), it can be helpful to be able to run a certain action after successful file loading (e.g. closing a certain stage). + * For this case this method offers the argument {@code Runnable onSuccess} which will be executed after successful file open activity. The {@code Runnable onSuccess} is only ran once, despite how many files have been loaded. + * + * @param files List of Strings denoting file paths to be opened + * @param onSuccess {@link Runnable} to be executed after all files have been opened successfully + */ + public void handleOpenFilesAction(List files, Runnable onSuccess) { assert files != null; assert files.isEmpty() == false; @@ -507,24 +533,60 @@ public void handleOpenFilesAction(List files) { } EditorController.updateNextInitialDirectory(fileObjs.get(0)); - + + Consumer> onError = errors -> showFileOpenErrors(errors, + () -> WelcomeDialogWindowController.getInstance().getStage()); + // Fix for #45 if (userLibrary.isFirstExplorationCompleted()) { - performOpenFiles(fileObjs); + performOpenFiles(fileObjs, onError, onSuccess); } else { // open files only after the first exploration has finished userLibrary.firstExplorationCompletedProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable observable) { if (userLibrary.isFirstExplorationCompleted()) { - performOpenFiles(fileObjs); userLibrary.firstExplorationCompletedProperty().removeListener(this); + performOpenFiles(fileObjs, onError, onSuccess); } } }); } } + /** + * For each file open error (when opened through the welcome dialog), the file + * name and the related exception text are presented to the user to confirm. + * For an empty collection, no dialog is displayed. + * + * @param errors A {@link Map} with having the file to be opened as the key and + * the occurred {@link Exception} as value. exceptions. + * @param owner Owner Supplier function to obtain the owners {@link Stage} + */ + private void showFileOpenErrors(Map errors, Supplier owner) { + if (errors.isEmpty()) { + return; + } + + for (Entry error : errors.entrySet()) { + final File fxmlFile = error.getKey(); + final Exception x = error.getValue(); + final ErrorDialog errorDialog = new ErrorDialog(owner.get()); + errorDialog.setMessage(I18N.getString("alert.open.failure1.message", displayName(fxmlFile.getPath()))); + errorDialog.setDetails(I18N.getString("alert.open.failure1.details")); + errorDialog.setDebugInfoWithThrowable(x); + errorDialog.setTitle(I18N.getString("alert.open.failure.title")); + errorDialog.setDetailsTitle(I18N.getString("alert.open.failure.title") + ": " + fxmlFile.getName()); + errorDialog.showAndWait(); + } + } + + private Supplier getOwnerWindow() { + return () -> findFirstUnusedDocumentWindowController() + .map(DocumentWindowController::getStage) + .orElse(WelcomeDialogWindowController.getInstance().getStage()); + } + @Override public void handleMessageBoxFailure(Exception x) { final ErrorDialog errorDialog = new ErrorDialog(null); @@ -657,11 +719,18 @@ public DocumentWindowController getFrontDocumentWindow() { } private void performOpenFiles(List fxmlFiles) { + performOpenFiles(fxmlFiles, r -> showFileOpenErrors(r, getOwnerWindow()), () -> { /* no action here */ } ); + } + + private void performOpenFiles(List fxmlFiles, Consumer> onError, Runnable onSuccess) { assert fxmlFiles != null; assert fxmlFiles.isEmpty() == false; - final Map exceptions = new HashMap<>(); + LOGGER.log(Level.FINE, "Opening {0} files...", fxmlFiles.size()); + final Map exceptionsPerFile = new HashMap<>(); + final List openedFiles = new ArrayList<>(); for (File fxmlFile : fxmlFiles) { + LOGGER.log(Level.FINE, "Attempting to open file {0}", fxmlFile); try { final DocumentWindowController dwc = lookupDocumentWindowControllers(fxmlFile.toURI().toURL()); @@ -673,46 +742,27 @@ private void performOpenFiles(List fxmlFiles) { var hostWindow = findFirstUnusedDocumentWindowController().orElse(makeNewWindow()); hostWindow.loadFromFile(fxmlFile); hostWindow.openWindow(); + openedFiles.add(fxmlFile); + LOGGER.log(Level.INFO, "Successfully opened file {0}", fxmlFile); } } catch (Exception xx) { - exceptions.put(fxmlFile, xx); + LOGGER.log(Level.WARNING, "Failed to open file: %s".formatted(fxmlFile), xx); + exceptionsPerFile.put(fxmlFile, xx); } } + + // Update recent items with opened files + if (!openedFiles.isEmpty()) { + final PreferencesController pc = PreferencesController.getSingleton(); + pc.getRecordGlobal().addRecentItems(openedFiles); + } - switch (exceptions.size()) { - case 0: { // Good - // Update recent items with opened files - final PreferencesController pc = PreferencesController.getSingleton(); - pc.getRecordGlobal().addRecentItems(fxmlFiles); - break; - } - case 1: { - final File fxmlFile = exceptions.keySet().iterator().next(); - final Exception x = exceptions.get(fxmlFile); - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setMessage(I18N.getString("alert.open.failure1.message", displayName(fxmlFile.getPath()))); - errorDialog.setDetails(I18N.getString("alert.open.failure1.details")); - errorDialog.setDebugInfoWithThrowable(x); - errorDialog.setTitle(I18N.getString("alert.title.open")); - errorDialog.showAndWait(); - break; - } - default: { - final ErrorDialog errorDialog = new ErrorDialog(null); - if (exceptions.size() == fxmlFiles.size()) { - // Open operation has failed for all the files - errorDialog.setMessage(I18N.getString("alert.open.failureN.message")); - errorDialog.setDetails(I18N.getString("alert.open.failureN.details")); - } else { - // Open operation has failed for some files - errorDialog.setMessage(I18N.getString("alert.open.failureMofN.message", - exceptions.size(), fxmlFiles.size())); - errorDialog.setDetails(I18N.getString("alert.open.failureMofN.details")); - } - errorDialog.setTitle(I18N.getString("alert.title.open")); - errorDialog.showAndWait(); - break; - } + if (exceptionsPerFile.isEmpty()) { + LOGGER.log(Level.FINE, "Successfully opened all files."); + onSuccess.run(); + } else { + LOGGER.log(Level.WARNING, "Failed to open {0} of {1} files!", new Object[] {exceptionsPerFile.size(), fxmlFiles.size()}); + onError.accept(exceptionsPerFile); } } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java index e8c977fc6..d8dce99a9 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/SceneStyleSheetMenuController.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -102,10 +103,11 @@ public void performOpenSceneStyleSheet(File toOpen) { try { EditorPlatform.open(toOpen.getPath()); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); + final ErrorDialog errorDialog = new ErrorDialog(documentWindowController.getStage()); errorDialog.setTitle(I18N.getString("error.file.open.title")); - errorDialog.setMessage(I18N.getString("error.file.open.message")); + errorDialog.setMessage(I18N.getString("error.file.open.message", toOpen)); errorDialog.setDetails(I18N.getString("error.filesystem.details")); + errorDialog.setDetailsTitle(I18N.getString("error.file.open.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/i18n/I18N.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/i18n/I18N.java index bfa2c45eb..61f7b9c53 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/i18n/I18N.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/i18n/I18N.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -33,14 +34,11 @@ import java.text.MessageFormat; import java.util.ResourceBundle; -import com.oracle.javafx.scenebuilder.kit.i18n.I18NControl; public class I18N { private static ResourceBundle bundle; - private static ResourceBundle.Control utf8EncodingControl = new I18NControl(); - public static String getString(String key) { return getBundle().getString(key); } @@ -53,7 +51,7 @@ public static String getString(String key, Object... arguments) { public static synchronized ResourceBundle getBundle() { if (bundle == null) { final String packageName = I18N.class.getPackage().getName(); - bundle = ResourceBundle.getBundle(packageName + ".SceneBuilderApp",utf8EncodingControl); //NOI18N + bundle = ResourceBundle.getBundle(packageName + ".SceneBuilderApp"); //NOI18N } return bundle; diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogFilesDropHandler.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogFilesDropHandler.java new file mode 100644 index 000000000..06cea55af --- /dev/null +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogFilesDropHandler.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.javafx.scenebuilder.app.welcomedialog; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + +final class WelcomeDialogFilesDropHandler { + + private static final Logger LOGGER = Logger.getLogger(WelcomeDialogFilesDropHandler.class.getName()); + + private final List droppedFiles; + private final List toOpen; + private final List unsupportedItems; + private Consumer> openFiles; + private Consumer> handleUnsupported; + + WelcomeDialogFilesDropHandler(List droppedFiles) { + this.droppedFiles = Objects.requireNonNull(droppedFiles); + this.toOpen = new ArrayList<>(droppedFiles.size()); + this.unsupportedItems = new ArrayList<>(droppedFiles.size()); + } + + final WelcomeDialogFilesDropHandler withSupportedFiles(Consumer> handleOpen) { + this.openFiles = handleOpen; + return this; + } + + final WelcomeDialogFilesDropHandler withUnsupportedFiles(Consumer> unsupportedHandler) { + this.handleUnsupported = unsupportedHandler; + return this; + } + + final void run() { + analyzeDroppedItems(); + handleDropResult(); + } + + /** + * + * SceneBuilder will silently ignore unsupported files and empty directories as long + * as there is at least one FXML file to be opened. For individual FXML files, the actual + * error handling happens later. Here the files to be opened are not tested or validated. + * + * The idea is, that if a user picks one file intentionally, a concise feedback in case + * of the wrong file format or an empty directory can be helpful and is desired. + * + * But when selecting a whole directory or multiple files, it might be helpful to ignore + * unsupported files as long actual candidates to be opened exist. The unsupported ones + * can result from an imprecise selection. One example could be that the user knowingly + * picked a resources folder with FXMLs, which also includes other files such as properties + * or icons. In that case the user would get annoyed about an message. + * Another case is a quick selection e. g. in Gnome Nautilus or Windows Explorer where some + * other files are unintentionally (by accident) selected. In such case, an error message + * could be annoying as well. + * + * Supported files are passed into the openFiles handler. + * The error message for unsupported files is only shown when the list of files toOpen is + * empty. + * + * Nevertheless, the fact that unsupported files were dropped and the location of unsupported + * files are logged. + * + */ + final void handleDropResult() { + if (this.openFiles == null) { + throw new IllegalStateException("Please configure a dropped file handling action using the withSupportedFiles(...) method."); + } + if (this.handleUnsupported == null) { + throw new IllegalStateException("Please configure an action for handling of unsupported files using withUnsupportedFiles(...) method."); + } + + if (!toOpen.isEmpty()) { + LOGGER.log(Level.INFO, "Received drop event to open files..."); + openFiles.accept(toOpen); + } else { + LOGGER.log(Level.INFO, "Dropped object does not contain any loadable FXML files."); + handleUnsupported.accept(unsupportedItems); + } + + if (!unsupportedItems.isEmpty()) { + LOGGER.log(Level.WARNING, "{0} unsupported items dropped.", unsupportedItems.size()); + for (var unsupportedItem : unsupportedItems) { + LOGGER.log(Level.INFO, "Unsupported file or empty directory: {0}", unsupportedItem); + } + } + } + + final void analyzeDroppedItems() { + if (droppedFiles.isEmpty()) { + return; + } + + for (var file : droppedFiles) { + if (file.isDirectory()) { + File[] children = file.listFiles(); + List inDir = new ArrayList<>(children.length); + for (var child : children) { + if (isFxml(child)) { + inDir.add(child.getAbsolutePath()); + } + } + if (inDir.isEmpty()) { + unsupportedItems.add(file.getAbsolutePath()); + } else { + toOpen.addAll(inDir); + } + } else { + if (isFxml(file)) { + toOpen.add(file.getAbsolutePath()); + } else { + unsupportedItems.add(file.getAbsolutePath()); + } + } + } + } + + final boolean isFxml(File file) { + if (file.isDirectory()) { + return false; + } + return file.toString() + .toLowerCase() + .endsWith(".fxml"); + } +} diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogWindowController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogWindowController.java index aaac1d51f..1fc11e4bd 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogWindowController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeDialogWindowController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -32,12 +32,25 @@ package com.oracle.javafx.scenebuilder.app.welcomedialog; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + import com.oracle.javafx.scenebuilder.app.SceneBuilderApp; import com.oracle.javafx.scenebuilder.app.i18n.I18N; import com.oracle.javafx.scenebuilder.app.preferences.PreferencesController; import com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal; import com.oracle.javafx.scenebuilder.app.util.AppSettings; import com.oracle.javafx.scenebuilder.kit.editor.EditorController; +import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.AbstractModalDialog.ButtonID; +import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.AlertDialog; +import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; import com.oracle.javafx.scenebuilder.kit.template.Template; import com.oracle.javafx.scenebuilder.kit.template.TemplatesBaseWindowController; import javafx.application.Platform; @@ -48,19 +61,19 @@ import javafx.scene.control.Label; import javafx.scene.control.ProgressIndicator; import javafx.scene.control.Tooltip; +import javafx.scene.input.DragEvent; +import javafx.scene.input.TransferMode; import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Modality; +import javafx.stage.Stage; import javafx.stage.WindowEvent; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - public class WelcomeDialogWindowController extends TemplatesBaseWindowController { + private static final Logger LOGGER = Logger.getLogger(WelcomeDialogWindowController.class.getName()); + @FXML private BorderPane contentPane; @@ -80,7 +93,7 @@ public class WelcomeDialogWindowController extends TemplatesBaseWindowController private final SceneBuilderApp sceneBuilderApp; - private WelcomeDialogWindowController() { + WelcomeDialogWindowController() { super(WelcomeDialogWindowController.class.getResource("WelcomeWindow.fxml"), //NOI18N I18N.getBundle(), null); // We want it to be a top level window so we're setting the owner to null. @@ -105,6 +118,38 @@ protected void controllerDidCreateStage() { getStage().setTitle(I18N.getString("welcome.title")); getStage().initModality(Modality.APPLICATION_MODAL); } + + @FXML + void handleFileDraggedOver(DragEvent event) { + if (event.getDragboard().hasFiles()) { + event.acceptTransferModes(TransferMode.ANY); + } + } + + @FXML + void handleDroppedFiles(DragEvent event) { + if (event.getDragboard().hasFiles()) { + new WelcomeDialogFilesDropHandler(event.getDragboard().getFiles()) + .withSupportedFiles(fileNames->Platform.runLater(()->handleOpen(fileNames))) + .withUnsupportedFiles(unsupported->notifyUserWhenDroppedUnsupportedFiles(unsupported)) + .run(); + } + } + + private void notifyUserWhenDroppedUnsupportedFiles(List unsupported) { + ErrorDialog dialog = new ErrorDialog(getStage()); + dialog.setTitle(I18N.getString("welcome.loading.when.dropped.error.title")); + dialog.setMessage(I18N.getString("welcome.loading.when.dropped.error.message")); + dialog.setDetailsTitle(I18N.getString("welcome.loading.when.dropped.error.title")); + dialog.setDetails(I18N.getString("welcome.loading.when.dropped.error.detail.explanation")); + + String debugInfo = unsupported.stream() + .collect(Collectors.joining(System.lineSeparator())); + + dialog.setDebugInfo(debugInfo); + + Platform.runLater(()->dialog.showAndWait()); + } @Override protected void controllerDidLoadFxml() { @@ -168,7 +213,7 @@ private void loadAndPopulateRecentItemsInBackground() { } public static WelcomeDialogWindowController getInstance() { - if (instance == null){ + if (instance == null) { instance = new WelcomeDialogWindowController(); var stage = instance.getStage(); stage.setMinWidth(800); @@ -201,7 +246,6 @@ private void openDocument() { new FileChooser.ExtensionFilter(I18N.getString("file.filter.label.fxml"), "*.fxml") ); fileChooser.setInitialDirectory(EditorController.getNextInitialDirectory()); - List fxmlFiles = fileChooser.showOpenMultipleDialog(getStage()); // no file was selected, so nothing to do @@ -215,19 +259,103 @@ private void openDocument() { handleOpen(paths); } + + protected static AlertDialog questionMissingFilesCleanup(Stage stage, List missingFiles) { + String withPath = missingFiles.stream() + .collect(Collectors.joining(System.lineSeparator())); + + AlertDialog question = new AlertDialog(stage); + question.setDefaultButtonID(ButtonID.CANCEL); + question.setShowDefaultButton(true); + question.setOKButtonTitle(I18N.getString("alert.welcome.file.not.found.okay")); + question.setTitle(I18N.getString("alert.welcome.file.not.found.title")); + question.setMessage(I18N.getString("alert.welcome.file.not.found.question")); + question.setCancelButtonTitle(I18N.getString("alert.welcome.file.not.found.no")); + question.setDetails(I18N.getString("alert.welcome.file.not.found.message") + withPath); + return question; + } + + boolean filePathExists(String filePath) { + return Files.exists(Path.of(filePath)); + } + + /** + * Attempts to open files in filePaths. Scene Builder will only attempt to load + * files which exist. If a file does not exist, Scene Builder will ask the user + * to remove this file from recent files. + * + * @param filePaths List of file paths to project files to be opened by Scene + * Builder. + */ + private void handleOpen(List filePaths) { + handleOpen(filePaths, + this::askUserToRemoveMissingRecentFiles, + this::attemptOpenExistingFiles); + } - private void handleOpen(List paths) { + private void askUserToRemoveMissingRecentFiles(List missingFiles) { + if (!missingFiles.isEmpty()) { + var questionDialog = questionMissingFilesCleanup(getStage(), missingFiles); + if (questionDialog.showAndWait() == AlertDialog.ButtonID.OK) { + removeMissingFilesFromPrefs(missingFiles); + loadAndPopulateRecentItemsInBackground(); + } + } + } + + private void attemptOpenExistingFiles(List paths) { if (sceneBuilderApp.startupTasksFinishedBinding().get()) { - sceneBuilderApp.handleOpenFilesAction(paths); - getStage().hide(); + openFilesAndHideStage(paths); } else { - showMasker(() -> { - sceneBuilderApp.handleOpenFilesAction(paths); - getStage().hide(); - }); + showMasker(() -> openFilesAndHideStage(paths)); } } + private void openFilesAndHideStage(List files) { + sceneBuilderApp.handleOpenFilesAction(files, () -> getStage().hide()); + } + + /** + * Attempts to open files in filePaths. + * In case of files are missing, a special procedure is applied to handle missing files. + * + * @param filePaths List of file paths to project files to be opened by Scene Builder. + * @param missingFilesHandler Determines how missing files are handled. + * @param fileLoader Determines how files are loaded. + */ + void handleOpen(List filePaths, + Consumer> missingFilesHandler, + Consumer> fileLoader) { + LOGGER.log(Level.INFO, "Attempting to open files: {0}", filePaths); + if (filePaths.isEmpty()) { + return; + } + + List existingFiles = new ArrayList<>(); + List missingFiles = new ArrayList<>(); + filePaths.forEach(file -> { + if (filePathExists(file)) { + existingFiles.add(file); + } else { + missingFiles.add(file); + } + }); + + missingFilesHandler.accept(missingFiles); + + if (existingFiles.isEmpty()) { + return; + } + + fileLoader.accept(existingFiles); + } + + private void removeMissingFilesFromPrefs(List missingFiles) { + missingFiles.forEach(fxmlFileName -> LOGGER.log(Level.INFO, "Removing missing file from recent items: {0}", fxmlFileName)); + PreferencesRecordGlobal preferencesRecordGlobal = PreferencesController.getSingleton().getRecordGlobal(); + preferencesRecordGlobal.removeRecentItems(missingFiles); + } + private void showMasker(Runnable onEndAction) { contentPane.setDisable(true); masker.setVisible(true); @@ -239,7 +367,6 @@ private void showMasker(Runnable onEndAction) { if (isFinished) { Platform.runLater(() -> { onEndAction.run(); - // restore state in case welcome dialog is opened again contentPane.setDisable(false); masker.setVisible(false); diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java new file mode 100644 index 000000000..31f010d22 --- /dev/null +++ b/app/src/main/java/module-info.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module com.gluonhq.scenebuilder.app { + requires javafx.web; + requires javafx.fxml; + requires javafx.media; + requires javafx.swing; + requires transitive com.gluonhq.scenebuilder.kit; + requires java.logging; + requires java.prefs; + requires javax.json.api; + + opens com.oracle.javafx.scenebuilder.app to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.about to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.i18n to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.menubar to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.message to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.preferences to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.registration to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.report to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.tracking to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.app.welcomedialog; + + uses com.oracle.javafx.scenebuilder.kit.i18n.spi.I18NResourcesProvider; + + exports com.oracle.javafx.scenebuilder.app; + exports com.oracle.javafx.scenebuilder.app.menubar; + exports com.oracle.javafx.scenebuilder.app.preferences; +} \ No newline at end of file diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties index 98c136064..b3f4b97ac 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp.properties @@ -1,4 +1,4 @@ -# Copyright (c) 2016, 2023, Gluon and/or its affiliates. +# Copyright (c) 2016, 2024, Gluon and/or its affiliates. # Copyright (c) 2012, 2014, Oracle and/or its affiliates. # All rights reserved. Use is subject to license terms. # @@ -397,12 +397,9 @@ alert.title.copy = Copy alert.title.start = Startup alert.title.messagebox = External Open +alert.open.failure.title = File Open Error alert.open.failure1.message = Could not open ''{0}'' alert.open.failure1.details = Open operation has failed. Make sure that the chosen file is a valid FXML document. -alert.open.failureN.message = Could not open the specified files -alert.open.failureN.details = Open operation has failed. Make sure that those files are valid FXML documents. -alert.open.failureMofN.message = Could not open {0} files -alert.open.failureMofN.details = Open operation has failed for some files. Make sure that those files are valid FXML documents. alert.review.question.message = {0} of your documents contain unsaved changes. Do you want to review them before exiting ? alert.review.question.details = Your changes will be lost if you don't review them. alert.overwrite.message = The file ''{0}'' was modified externally. Do you want to overwrite it ? @@ -420,8 +417,6 @@ alert.messagebox.failure.message = Could not process open request alert.messagebox.failure.details = An unexpected failure happened during open operation. Please report this failure to support. alert.revert.question.message = Do you want to revert to the last saved version of ''{0}'' ? alert.revert.question.details = Your current changes will be lost. -alert.reveal.failure.message = Could not reveal ''{0}'' -alert.reveal.failure.details = Reveal operation has failed. Check logs of the operating system. alert.copy.failure.message = Could not copy ''{0}'' alert.help.failure.message = Could not access to ''{0}'' alert.delete.fxid1of1.message = This component has an fx:id. Do you really want to delete it ? @@ -436,7 +431,12 @@ alert.save.noextension.savewith = Save with '.fxml' alert.save.noextension.savewithout = Save without '.fxml' alert.open.failure.charset.not.found = The given charset could not be set. alert.open.failure.charset.not.found.details = It may be due to the encoding in your document. - +alert.welcome.file.not.found.question = One or more project files were not found. +alert.welcome.file.not.found.message = If those are located on a removable or network drive, please make sure the drive is connected.\n\n +alert.welcome.file.not.found.title = Project file(s) not found +alert.welcome.file.not.found.okay = Remove From List +alert.welcome.file.not.found.no = OK + # ----------------------------------------------------------------------------- # Log Messages # ----------------------------------------------------------------------------- @@ -468,11 +468,29 @@ file.filter.label.image = Image Document file.filter.label.media = Media Document file.filter.label.video = Video Document error.file.open.title = File opening failed +error.file.open.details.title = File opening failed - Details # {0} is a file path error.file.open.message = File {0} cannot be opened -error.filesystem.details = Please check your file system. -error.file.reveal.title = File locating failed -error.file.reveal.message = File {0} cannot be found +error.filesystem.details = File: {0} + +# File Reveal Error Dialog +alert.error.file.reveal.title = Failed to reveal file ... +alert.error.file.reveal.message = Cannot reveal file in file system viewer due to an error. +alert.error.file.reveal.details = ''{0}'' +alert.error.file.reveal.details.title = File Reveal Error Details + +# Directory Reveal Error Dialog +alert.error.directory.reveal.title = Failed to reveal folder ... +alert.error.directory.reveal.message = Cannot reveal folder in file system viewer due to an error. +alert.error.directory.reveal.details = ''{0}'' +alert.error.directory.reveal.details.title = Folder Reveal Error Details + +# Resource Reveal Error Dialog +alert.error.resource.reveal.title = Failed to reveal resource ... +alert.error.resource.reveal.message = Cannot reveal resource in file system viewer due to an error. +alert.error.resource.reveal.details = ''{0}'' +alert.error.resource.reveal.details.title = Resource Reveal Error Details + # log.start = JavaFX Scene Builder started log.stop = JavaFX Scene Builder stopped @@ -509,6 +527,10 @@ welcome.recent.items.loading = Loading recent projects... welcome.recent.items.no.recent.items = no recent projects welcome.open.project.label = Open Project welcome.loading.label = Loading Components... +welcome.loading.when.dropped.error.title=Unsupported files dropped +welcome.loading.when.dropped.error.message=Cannot open dropped files or directories. +welcome.loading.when.dropped.error.detail.explanation=Scene Builder only supports *.fxml files or directories which contain *.fxml files.\n\n + # -- Template (this keys are replicated from SceneBuilderKit.properties) template.new.project.label = New Project from Template template.title.header.desktop = Desktop diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties index 280754a22..4a6650813 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_ja.properties @@ -394,10 +394,6 @@ alert.title.messagebox = 外部プログラムで開く alert.open.failure1.message = ''{0}''を開けませんでした alert.open.failure1.details = 開くのに失敗しました。選択されたファイルが有効なFXMLドキュメントであることを確認してください。 -alert.open.failureN.message = 指定されたファイルを開けませんでした -alert.open.failureN.details = 開くのに失敗しました。それらのファイルが有効なFXMLドキュメントであることを確認してください。 -alert.open.failureMofN.message = {0}個のファイルを開けませんでした -alert.open.failureMofN.details = いくつかのファイルを開くのに失敗しました。それらのファイルが有効なFXMLドキュメントであることを確認してください。 alert.review.question.message = ドキュメントのうち{0}個に未保存の変更があります。終了する前にそれらをレビューしますか。 alert.review.question.details = レビューしないと、変更は失われます。 alert.overwrite.message = ファイル''{0}''は外部で変更されました。上書きしますか。 @@ -414,8 +410,6 @@ alert.messagebox.failure.message = 開く操作を処理できませんでした alert.messagebox.failure.details = 開く操作中に予期しない問題が起きました。この問題をサポートに報告してください。 alert.revert.question.message = 最後に保存した''{0}''に戻しますか。 alert.revert.question.details = 現在の変更は失われます。 -alert.reveal.failure.message = ''{0}''を表示できませんでした -alert.reveal.failure.details = 元に戻すのに失敗しました。オペレーティング・システムのログを確認してください。 alert.copy.failure.message = コピー alert.help.failure.message = ''{0}''にアクセスできませんでした alert.delete.fxid1of1.message = このコンポーネントにはfx:idがあります。このコンポーネントを削除しますか。 @@ -461,7 +455,7 @@ file.filter.label.fxml = FXMLドキュメント file.filter.label.image = イメージ・ドキュメント file.filter.label.media = メディア・ドキュメント file.filter.label.video = ビデオ・ドキュメント -error.file.open.title = ファイルを開くのに失敗しました + # {0} is a file path error.file.open.message = ファイル{0}を開けません error.filesystem.details = ファイル・システムを確認してください。 diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties index cd75db0b8..2fd97b692 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/i18n/SceneBuilderApp_zh_CN.properties @@ -1,3 +1,4 @@ +# Copyright (c) 2016, 2024, Gluon and/or its affiliates. # Copyright (c) 2012, 2014, Oracle and/or its affiliates. # All rights reserved. Use is subject to license terms. # @@ -28,9 +29,503 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ----------------------------------------------------------------------------- # Generic labels +# ----------------------------------------------------------------------------- +label.ok = 确定 +label.cancel = 取消 +label.close = 关闭 +label.delete = 删除 +label.copy = 复制 +label.save = 保存 +label.revert = 恢复 +label.do.not.save = 不保存 +label.overwrite = 覆盖 +label.review.changes = 查看更改 +label.discard.changes = 放弃更改 -label.ok = \u786e\u5b9a -label.cancel = \u53d6\u6d88 -label.close = \u5173\u95ed -label.copy = \u590d\u5236 + +# ----------------------------------------------------------------------------- +# Menu Bar +# ----------------------------------------------------------------------------- +menu.title.file = 文件 +menu.title.edit = 编辑 +menu.title.view = 视图 +menu.title.insert = 插入 +menu.title.insert.error = 插入失败。 +menu.title.modify = 修改 +menu.title.arrange = 安排 +menu.title.preview = 预览 +menu.title.window = 窗口 +menu.title.help = 帮助 +# File menu items +menu.title.new = 新建 +menu.title.new.template = 从模板中新建 +menu.title.new.basic.phone.app = 基本 +menu.title.open = 打开\u2026 +menu.title.open.recent = 打开最近 +menu.title.open.recent.clear = 清除菜单 +menu.title.save = 保存 +menu.title.save.as = 另存为\u2026 +menu.title.revert = 恢复为保存 +menu.title.close = 关闭窗口 +menu.title.reveal.mac = 在 Finder 中显示 +menu.title.reveal.win.mnemonic = 在资源管理器中显示 +menu.title.reveal.win = 在资源管理器中显示 +menu.title.reveal.linux = 在桌面上显示 +menu.title.import = 导入 +menu.title.import.fxml = FXML\u2026 +menu.title.import.media = 媒体\u2026 +menu.title.include = 包括 +menu.title.include.fxml = FXML\u2026 +menu.title.edit.included = 编辑 ''{0}'' +menu.title.edit.included.default = 编辑包含的文件 +menu.title.reveal.included.finder = 在 Finder 中显示 ''{0}'' +menu.title.reveal.included.explorer = 在资源管理器中显示 ''{0}'' +menu.title.reveal.included.default = 显示包含的文件 +menu.title.print = 打印\u2026 +menu.title.preferences = 偏好选项\u2026 +menu.title.quit = 退出 +# Edit menu items +menu.title.undo = 撤销 +menu.title.redo = 重做 +menu.title.cut = 剪切 +menu.title.copy = 复制 +menu.title.paste = 粘贴 +menu.title.paste.into = 粘贴到 +menu.title.duplicate = 重复 +menu.title.delete = 删除 +menu.title.select.all = 全选 +menu.title.select.none = 选择无 +menu.title.select.parent = 选择父项 +menu.title.select.next = 选择下一个 +menu.title.select.previous = 选择上一个 +menu.title.trim = 将文档修剪为所选内容 +# View menu items +menu.title.content = 内容 +menu.title.properties = 属性 +menu.title.layout = 布局 +menu.title.code = 代码 +menu.title.show.library.panel = 显示库 +menu.title.hide.library.panel = 隐藏库 +menu.title.show.document.panel = 显示文档 +menu.title.hide.document.panel = 隐藏文档 +menu.title.show.left.panel = 显示左侧面板 +menu.title.hide.left.panel = 隐藏左侧面板 +menu.title.show.right.panel = 显示右侧面板 +menu.title.hide.right.panel = 隐藏右侧面板 +menu.title.show.bottom.panel = 显示 CSS 分析器 +menu.title.hide.bottom.panel = 隐藏 CSS 分析器 +menu.title.show.outlines = 显示大纲 +menu.title.hide.outlines = 隐藏大纲 +menu.title.show.sample.data = 显示示例数据 +menu.title.hide.sample.data = 隐藏示例数据 +menu.title.disable.guides = 禁用对齐参考线 +menu.title.enable.guides = 启用对齐参考线 +menu.title.show.sample.controller.skeleton = 显示示例控制器骨架 +menu.title.zoom = 缩放 +menu.title.zoom.in = 缩小 +menu.title.zoom.out = 放大 +# Modify menu items +menu.title.fit = 适合父母 +menu.title.use.computed.sizes = 使用计算大小 +menu.title.grid = _GridPane +menu.title.add.effect = 设置效果 +menu.title.add.popup = 添加弹出控件 +menu.title.add.popup.context.menu = 上下文菜单 +menu.title.add.popup.tooltip = 工具提示 +# Modify -> GridPane menu items +menu.title.grid.select.next.row = 选择下一行 +menu.title.grid.select.next.column = 选择下一列 +menu.title.grid.move.row.above = 将行移到上方 +menu.title.grid.move.row.below = 将行移到下面 +menu.title.grid.move.column.before = 将列移到前面 +menu.title.grid.move.column.after = 将列移到之后 +menu.title.grid.add.row.above = 在上面添加行 +menu.title.grid.add.row.below = 在下面添加行 +menu.title.grid.add.column.before = 在之前添加列 +menu.title.grid.add.column.after = 在之后添加列 +menu.title.grid.increase.row.span = 增加行跨度 +menu.title.grid.decrease.row.span = 减小行跨度 +menu.title.grid.increase.column.span = 增加列跨度 +menu.title.grid.decrease.column.span = 减小列跨度 +# Modify -> Scene Size +menu.title.size.phone = 335 x 600 (Phone) +menu.title.size.tablet = 900 x 600 (Tablet) +menu.title.size.qvga = 320 x 240 (QVGA) +menu.title.size.vga = 640 x 480 (VGA) +menu.title.size.touch = 1280 x 800 +menu.title.size.hd = 1920 x 1080 +# Arrange menu items +menu.title.front = 带到前面 +menu.title.back = 发送回 +menu.title.forward = 向前推进 +menu.title.backward = 向后发送 +menu.title.wrap = 包裹 +menu.title.unwrap = 解开 +# Preview menu items +menu.title.show.preview.in.window = 在窗口中显示预览 +menu.title.show.preview.in.dialog = 在对话框中显示预览 +menu.title.hide.preview = 在窗口中隐藏预览 + +menu.title.theme = 主题 +menu.title.gluon.swatch = _Gluon Swatch + +menu.title.scene.stylesheets = 场景样式表 +menu.title.add.stylesheet = 添加样式表\u2026 +menu.title.remove.stylesheet = 删除样式表 +menu.title.open.stylesheet = 打开样式表 +menu.title.internationalization = 国际化 +menu.title.set.resource = 设置资源\u2026 +menu.title.remove.resource = 删除资源 +menu.title.remove.resource.with.file = 删除资源 "{0}" +menu.title.reveal.resource = 显示资源 +menu.title.reveal.resource.with.file = 显示资源 "{0}" +menu.title.resolve.unknown.types = 解决未知类型\u2026 +menu.title.preview.size = 预览大小 +menu.title.size = 场景大小 +menu.title.size.preferred = 首选大小 +menu.title.size.preferred.with.value = 首选大小 ({0} x {1}) +# Window menu items +menu.title.no.window = 无窗口 +# Help menu items +menu.title.scene.builder.help = Scene Builder 帮助 +menu.title.show.welcome = 显示欢迎页面 +menu.title.check.updates = 检查更新... +menu.title.about = 关于 Scene Builder +menu.title.register = 注册... +menu.title.help.javafx=JavaFX +menu.title.help.openjfx.getting.started=JavaFX 入门 +menu.title.help.openjfx.api.docs=JavaFX API 文档 +menu.title.help.openjfx.css.reference=JavaFX CSS 参考指南 +menu.title.help.openjfx.fxml.reference=FXML 简介 +menu.title.help.scenebuilder.contribute=为 Scene Builder 做贡献 +menu.title.help.scenebuilder.home=Gluon Scene Builder 主页 +menu.title.help.jfxcentral.homepage=JFX-Central +# ----------------------------------------------------------------------------- +# Document +# ----------------------------------------------------------------------------- +document = 文档 + +# ----------------------------------------------------------------------------- +# Hierarchy +# ----------------------------------------------------------------------------- +hierarchy = 层次结构 +hierarchy.displays = 层次结构显示 +hierarchy.show.info = 信息 +hierarchy.show.fxid = fx:id +hierarchy.show.nodeid = 节点 ID + +# ----------------------------------------------------------------------------- +# Controller +# ----------------------------------------------------------------------------- +controller = 控制器 + +# ----------------------------------------------------------------------------- +# Inspector +# ----------------------------------------------------------------------------- +inspector = 检查器 +inspector.show.all = 显示全部 +inspector.show.edited = 显示已编辑 +inspector.view.sections = 查看部分 +inspector.by.property.name = 按属性名称查看 +inspector.by.property.type = 按属性类型查看 + +# ----------------------------------------------------------------------------- +# Preferences Window +# ----------------------------------------------------------------------------- +prefs.title = 偏好选项 +prefs.alignment.guides = 对齐参考线颜色 : +prefs.doc.width = 默认根容器宽度 : +prefs.doc.height = 默认根容器高度 : +prefs.drop.ring = 水滴和父环颜色 : +prefs.tooltheme = Scene Builder 主题 : +prefs.library.displayoption = 库中显示的默认视图 : +prefs.hierarchy.displayoption = 层次结构中显示的默认信息 : +prefs.revert = 恢复为内置默认值 +prefs.background = 背景图片 : +prefs.cssanalyzer.columns.order = CSS 分析器列顺序 : +prefs.cssanalyzer.columns.defaults.first = "默认值" 列 第一 +prefs.cssanalyzer.columns.defaults.last = "默认值" 列 最后 +prefs.recent.items = 最近项目 : +prefs.animate.accordion = Animate Accordion : +prefs.wildcard.import = 使用通配符导入 : +prefs.tic.paste.alternate.behavior = 文本输入的替代粘贴行为 : +prefs.tic.paste.alternate.behavior.tooltip = 仅限 MacOS: 启用粘贴到文本输入控件中的变通办法。\n在粘贴文本无法按预期工作时禁用。 +prefs.reset.default = 重置为内置默认值 +prefs.document.theme = 默认主题 : +prefs.document.gluonswatch = 默认 Gluon Swatch : +prefs.document.gluontheme = 默认 Gluon Theme : + +# ----------------------------------------------------------------------------- +# Template Dialog +# ----------------------------------------------------------------------------- +template.label.name = 名称: +template.label.location = 位置: +template.button.choose = 选择... +template.details.title = 将创建以下文件: +template.title.new.project = 新建 {0} 项目 +template.location.does.not.exist = 位置 {0} 不存在 +template.name.already.exists = 目录 "{0}" 已存在 +template.cannot.create = "{0}" 无法创建 +template.cannot.save.file = 无法保存文件: {0} + +# ----------------------------------------------------------------------------- +# Library Menu within Library panel +# ----------------------------------------------------------------------------- +library = 库 +library.exploring = 探索图书馆.. +library.panel.menu.manage.jar.fxml = JAR/FXML 管理器 +library.panel.menu.import.selection = 导入选择 +# Messages below are temporarily unused +#library.panel.menu.category.view = View Library Category +#library.panel.menu.category.create = Create Library Category +#library.panel.menu.category.remove = Remove Library Category +#library.panel.menu.item.move = Move Custom Item to +#library.panel.menu.item.rename = Rename Custom Item +#library.panel.menu.item.remove = Remove Custom Item +library.panel.menu.view.list = 以列表形式查看 +library.panel.menu.view.sections = 以部分形式查看 +library.panel.menu.custom = 自定义库文件夹 +library.panel.menu.custom.report = 显示 JAR 分析报告 + +# ----------------------------------------------------------------------------- +# About Window +# ----------------------------------------------------------------------------- +about.title = 关于 JavaFX Scene Builder +about.build.information = 构建信息 +about.build.date = 日期: {0} +about.build.java.version = Java 版本: {0} +about.build.javafx.version = JavaFX 版本: {0} +about.copyright = Copyright \u00a9 2012, 2014, Oracle and/or its affiliates. All rights reserved.\n\nThis software and related documentation are provided under a license agreement containing restrictions on use and disclosure and are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation of this software, unless required by law for interoperability, is prohibited.\n\nThe information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.\n\nIf this software or related documentation is delivered to the U.S. Government or anyone licensing it on behalf of the U.S. Government, the following notice is applicable:\n\nU.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data delivered to U.S. Government customers are \"commercial computer software\" or \"commercial technical data\" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject to the restrictions and license terms set forth in the applicable Government contract, and, to the extent applicable by the terms of the Government contract, the additional rights set forth in FAR 52.227-19, Commercial Computer Software License (December 2007). Oracle USA, Inc., 500 Oracle Parkway, Redwood City, CA 94065.\n\nThis software is developed for general use in a variety of information management applications. It is not developed or intended for use in any inherently dangerous applications, including applications which may create a risk of personal injury. If you use this software in dangerous applications, then you shall be responsible to take all appropriate fail-safe, backup, redundancy, and other measures to ensure the safe use of this software. Oracle and its affiliates disclaim any liability for any damages caused by use of this software in dangerous applications.\n\nOracle is a registered trademark of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.\n\nThis software and documentation may provide access to or information on content, products, and services from third parties. Oracle and its affiliates are not responsible for and expressly disclaim all warranties of any kind with respect to third-party content, products, and services. Oracle and its affiliates will not be responsible for any loss, costs, or damages incurred due to your access to or use of third-party content, products, or services. +about.copyright.open = Copyright (c) 2016-{0}, Gluon.\nAll rights reserved. Use is subject to license terms.\n\nThis file is available and licensed under the following license:\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n - Neither the name of Gluon nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# Hardware acceleration is a boolean: its value depends on the FX toolkit and pipeline in use. +about.fx.hardware.acceleration = 硬件加速 +about.fx.hardware.acceleration.enabled = ENABLED +about.fx.hardware.acceleration.disabled = DISABLED +about.fx.pipeline = Pipeline +about.fx.toolkit = 工具箱 +about.logging.title = 日志 +about.logging.body.first = 默认配置将日志记录输出存储在名为 {0} 的文件中(可能后跟尾部 ''.'' 和数字)。 +about.logging.body.second = 默认文件路径为 {0} +about.operating.system = 操作系统 +about.product.version = 产品版本 + +about.app.data.directory = 应用程序数据文件夹: +about.app.user.library = 用户资源库文件夹: +about.app.program.directory = 应用程序文件夹: + +about.java.library.paths = Java 库路径(s): +about.java.library.paths.invalids = 缺少或无效的 Java 库路径(s): + +# ----------------------------------------------------------------------------- +# Themes +# ----------------------------------------------------------------------------- +# Document themes +title.theme.gluon_mobile_dark = Gluon Mobile Dark +title.theme.gluon_mobile_light = Gluon Mobile Light +title.theme.modena = Modena (FX8) +title.theme.modena_touch = Modena Touch (FX8) +title.theme.modena_high_contrast_black_on_white = Modena High Contrast - Black on White (FX8) +title.theme.modena_high_contrast_white_on_black = Modena High Contrast - White on Black (FX8) +title.theme.modena_high_contrast_yellow_on_black = Modena High Contrast - Yellow on Black (FX8) +title.theme.modena_touch_high_contrast_black_on_white = Modena Touch High Contrast - Black on White (FX8) +title.theme.modena_touch_high_contrast_white_on_black = Modena Touch High Contrast - White on Black (FX8) +title.theme.modena_touch_high_contrast_yellow_on_black = Modena Touch High Contrast - Yellow on Black (FX8) +title.theme.caspian = Caspian (FX2) +title.theme.caspian_embedded = Caspian Embedded (FX2) +title.theme.caspian_embedded_qvga = Caspian Embedded QVGA (FX2) +title.theme.caspian_high_contrast = Caspian High Contrast (FX2) +title.theme.caspian_embedded_high_contrast = Caspian Embedded High Contrast (FX2) +title.theme.caspian_embedded_qvga_high_contrast = Caspian Embedded QVGA High Contrast (FX2) +# Gluon Swatches +title.gluon.swatch.blue = Blue Swatch +title.gluon.swatch.cyan = Cyan Swatch +title.gluon.swatch.deep_orange = Deep Orange Swatch +title.gluon.swatch.deep_purple = Deep Purple Swatch +title.gluon.swatch.green = Green Swatch +title.gluon.swatch.indigo = Indigo Swatch +title.gluon.swatch.light_blue = Light Blue Swatch +title.gluon.swatch.pink = Pink Swatch +title.gluon.swatch.purple = Purple Swatch +title.gluon.swatch.red = Red Swatch +title.gluon.swatch.teal = Teal Swatch +title.gluon.swatch.light_green = Light Green Swatch +title.gluon.swatch.lime = Lime Swatch +title.gluon.swatch.yellow = Yellow Swatch +title.gluon.swatch.amber = Amber Swatch +title.gluon.swatch.orange = Orange Swatch +title.gluon.swatch.brown = Brown Swatch +title.gluon.swatch.grey = Grey Swatch +title.gluon.swatch.blue_grey = Blue Grey Swatch +# Gluon Themes +title.gluon.theme.light = 浅色主题 +title.gluon.theme.dark = 暗色主题 + +# ----------------------------------------------------------------------------- +# Registration Window +# ----------------------------------------------------------------------------- +registration.title = 在 Gluon 注册 +registration.info = 欢迎使用 JavaFX 场景生成器,这是快速构建 JavaFX 用户界面的最佳方式。我们很乐意与您保持联系,让您了解更新、新功能、技术提示等。如果您不想收到我们的来信,只需取消选中下面的复选框即可。 +registration.alert.invalid_email_address = 需要有效的电子邮件地址。 +registration.email_address = 电子邮件地址: +registration.opt_in = 保持最新状态 +registration.register = 注册 +registration.cancel = 取消 + +# ----------------------------------------------------------------------------- +# Message bar +# ----------------------------------------------------------------------------- +message.bar.file.dirty = 文件有未保存的更改 +message.bar.details = 单击以访问警告消息列表 + +# ----------------------------------------------------------------------------- +# Message panel +# ----------------------------------------------------------------------------- +message.panel.clear = 清楚 + +# ----------------------------------------------------------------------------- +# Menu Bar +# ----------------------------------------------------------------------------- +menubar.no.lib.item = 无库项目 + +# ----------------------------------------------------------------------------- +# Alert +# ----------------------------------------------------------------------------- +alert.title.open = 打开 +alert.title.copy = 复制 +alert.title.start = 启动 +alert.title.messagebox = 外部打开 + +alert.open.failure1.message = 无法打开 ''{0}'' +alert.open.failure1.details = 打开操作失败。确保所选文件是有效的 FXML 文档。 +alert.review.question.message = {0} 文档包含未保存的更改。您想在退出之前查看它们吗? +alert.review.question.details = 如果您不查看更改,则更改将丢失。 +alert.overwrite.message = 文件 ''{0}'' 已在外部修改。你想覆盖它吗? +alert.overwrite.details = 另一个应用程序修改了该文件。覆盖它将放弃此应用程序所做的更改。 +alert.save.question.title = Scene Builder +alert.save.question.message = 是否要保存在文件 ''{0}'' 中所做的更改? +alert.save.question.details = 如果您不保存更改,它们将丢失。 +alert.save.failure.message = 无法保存 ''{0}'' +alert.save.failure.details = 写入操作失败。检查文件系统和权限。 +alert.save.conflict.message = 文件 ''{0}'' 已打开 +alert.save.conflict.details = 先关闭它,然后重试。 +alert.start.failure.message = 无法启动 +alert.start.failure.details = 应用程序启动期间发生意外故障。请将此问题报告给支持人员。 +alert.messagebox.failure.message = 无法处理打开的请求 +alert.messagebox.failure.details = 打开操作期间发生意外故障。请向支持部门报告此故障。 +alert.revert.question.message = 是否要恢复到上次保存的 ''{0}'' 版本? +alert.revert.question.details = 您当前的更改将丢失。 +alert.copy.failure.message = 无法复制 ''{0}'' +alert.help.failure.message = 无法访问 ''{0}'' +alert.delete.fxid1of1.message = 此组件具有 fx:id,你真的要删除它吗? +alert.delete.fxid1ofN.message = 其中一个组件具有 fx:id,你真的要删除它们吗? +alert.delete.fxidNofN.message = 这些组件具有 fx:id,你真的要删除它们吗? +alert.delete.fxidKofN.message = 某些组件具有 fx:id,你真的要删除它们吗? +alert.delete.fxid.details = 具有 fx:id 的组件可能会从应用程序源代码中引用。如果删除它们,则必须更新源代码。 +alert.save.noextension.message = 你真的想保存没有 ''.fxml'' 扩展名的 ''{0}'' 吗? +alert.save.noextension.details = 建议添加 '.fxml' 扩展名:它允许场景生成器识别文件系统上可用的 FXML 文档。 +alert.save.noextension.details.overwrite = 注意:文件 ''{0}'' 已存在。替换它将覆盖其内容。 +alert.save.noextension.savewith = 使用 '.fxml' 保存 +alert.save.noextension.savewithout = 保存时不带 '.fxml' +alert.open.failure.charset.not.found = 无法设置给定的字符集。 +alert.open.failure.charset.not.found.details = 这可能是由于文档中的编码。 + +# ----------------------------------------------------------------------------- +# Log Messages +# ----------------------------------------------------------------------------- +log.info.save.confirmation = 保存为 ''{0}'' 的更改 +log.info.reload = 从 ''{0}'' 读取更改 +log.info.file.deleted= 文件 ''{0}'' 已删除 +log.user.exploration.0 = 探索用户库 (未找到 FXML 或 JAR 文件) +log.user.exploration.1 = 探索用户库 (加载 ''{0}'') +log.user.fxml.exploration.n = 探索用户库 (加载 {0} FXML 文件) +log.user.jar.exploration.n = 探索用户库 (加载 {0} JAR 文件) +log.user.fxml.jar.exploration.1.1 = 探索用户库 (加载 ''{0}'' 和 ''{1}'') +log.user.fxml.jar.exploration.n.1 = 探索用户库 (加载 {0} FXML 文件和 ''{1}'' ) +log.user.fxml.jar.exploration.1.n = 探索用户库 (加载 ''{0}'' 和 {1} JAR 文件) +log.user.fxml.jar.exploration.n.n = 探索用户库 (加载 {0} FXML 文件和 {1} JAR 文件) + +# ----------------------------------------------------------------------------- +# Preview Window +# ----------------------------------------------------------------------------- +resource.filechooser.filter.msg = 属性文件 +# Used as menu item label when no style sheet has been added +scenestylesheet.none = 无 + +# ----------------------------------------------------------------------------- +# Other +# ----------------------------------------------------------------------------- +file.filter.label.audio = 音频文档 +file.filter.label.fxml = FXML 文档 +file.filter.label.image = 图像文档 +file.filter.label.media = 媒体文件 +file.filter.label.video = 视频文档 +error.file.open.title = 文件打开失败 +# {0} is a file path +error.file.open.message = 无法打开 {0} 文件 +error.filesystem.details = 请检查您的文件系统。 +error.file.reveal.title = 文件定位失败 +error.file.reveal.message = 找不到 {0} 文件 +# +log.start = JavaFX Scene Builder 已启动 +log.stop = JavaFX Scene Builder 已停止 + +# ----------------------------------------------------------------------------- +# CSS Panel +# ----------------------------------------------------------------------------- +csspanel = CSS 分析器 +csspanel.copy.path = 复制可设置样式的路径 +csspanel.rules = 规则 +csspanel.show.default.values = 显示具有默认值的属性 +csspanel.hide.default.values = 隐藏具有默认值的属性 +csspanel.defaults.split = 拆分默认值 +csspanel.defaults.join = 联接默认值 +csspanel.table = 表格 +csspanel.text = 文本 +csspanel.view.as = 查看为 + +# ----------------------------------------------------------------------------- +# JAR Analysis Report dialog +# ----------------------------------------------------------------------------- +# The parameter is a time stamp +jar.analysis.report.timestamp = {0} 分析完成 +jar.analysis.report.title = JAR 分析报告 +jar.analysis.exception = 例外: +jar.analysis.not.node = 不是节点: + +# ----------------------------------------------------------------------------- +# Welcome Dialog +# ----------------------------------------------------------------------------- +welcome.title = Gluon Scene Builder +welcome.recent.items.header = 最近项目 +welcome.recent.items.loading = 加载最近的项目... +welcome.recent.items.no.recent.items = 没有最近的项目 +welcome.open.project.label = 打开项目 +welcome.loading.label = 正在加载组件... +# -- Template (this keys are replicated from SceneBuilderKit.properties) +template.new.project.label = 从模板新建项目 +template.title.header.desktop = 桌面 +template.title.header.phone = 移动 + + +# ----------------------------------------------------------------------------- +# Download latest version dialog +# ----------------------------------------------------------------------------- +download.scene.builder.title = 下载 Scene Builder +download.scene.builder.header.label = 您的 Scene Builder 版本不是最新版本。 +download.scene.builder.current.version.label = 目前版本: +download.scene.builder.last.version.number.label = 最新版本: +download.scene.builder.remind.later.label = 稍后提醒 +download.scene.builder.ignore.label = 忽略 +download.scene.builder.download.label = 下载 +download.scene.builder.learn.mode.label = 了解更多信息 + +# ----------------------------------------------------------------------------- +# Check for updates +# ----------------------------------------------------------------------------- +check_for_updates.alert.error.message = 无法通过服务器检查最新版本。 +check_for_updates.alert.error.title = Scene Builder +check_for_updates.alert.up_to_date.message = 您已经安装了最新版本的 Scene Builder。 +check_for_updates.alert.up_to_date.title = Scene Builder +check_for_updates.alert.headertext = 更新检查 diff --git a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeWindow.fxml b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeWindow.fxml index 76c629d24..d77276f79 100644 --- a/app/src/main/resources/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeWindow.fxml +++ b/app/src/main/resources/com/oracle/javafx/scenebuilder/app/welcomedialog/WelcomeWindow.fxml @@ -1,7 +1,7 @@ Controls under Library Panel

+ +However, many projects use extra sets of controls, which will be called from now on _custom controls_, that is, JavaFX controls that are not in the built-in set of default controls. + +The Library Manager deals with custom controls in different ways, allowing the user not only to import local jar or FXML files, but also to import jars from a number of repositories, remote and local, public and even private ones. + +On top of the Library pane item, there is a small MenuButton control with a cog icon, press it to show the Library Manager dialog: + +

Library menuButton

+ +### View as List or Sections options + +The first two menu items are for selecting between using a flat list to list all the components in the Library (custom and built-in ones): + +

View as List

+ +or the default Accordion container with TiledPanes as Sections, as shown earlier above. + +### Import Selection option + +This is a quick way of creating a custom control out of an existing FXML in Scene Builder. + +

import selection

+ +Once you select part of it, clicking the menu item will create a custom control which in this case is a simple FXML file: + +

custom FXML

+ +This FXML code snippet can be reused now in other FXMLs. + +### Custom Library Folder option + +The last menu item refers to the Section for Custom Controls: + +

custom library folder

+ +There is a system folder where custom jars and files are cached, and this can be revealed in Finder. And for all existing custom controls, an analysis can be performed and the report will show possible errors. This is useful especially when importing a custom control doesn't behave as expected. + +### JAR/FXML Manager option + +The third menu item gives you access to the Library Manager dialog: + +

the library manager

+ +If there were already some custom controls (jars or FXML files) presented in the Custom section of the Library, then those would be listed in this dialog. + +For each library or file, the user can edit or delete it. Editing an FXML will open it in Scene Builder. Editing a jar file will open a dialog where the user can preview and select or unselect different components (if any) of that jar that will be added to the Custom panel. + +On the lower part of the dialog, there are different actions that the user can perform. + +### Search repositories option + +The user can type a name of a library: full name or part of its group id, or full name or part of it of the artifact id, following the usual naming convention. + +

Search Library in Repositories

+ +For instance, to download and install the latest release of ControlsFX, just by typing its maven group `org.controlsfx`, the existing artifacts (in the registered repositories) will show up: + +

ControlsFX results

+ +Then selecting one of the presented results will download the latest release of the artifact from one of the repositories, install it to the user's local .m2, find all possible custom controls found in the jar, and present them for a preview: + +

ControlsFX custom controls

+ +The user can browse over the list of custom controls, select anyone for a preview (not all have one), and select one or more custom controls to be imported. + +After pressing Import Components, the Import dialog will close and the Manager will show a new entry added: + +

ControlsFX successfully imported

+ +And while the full jar was imported, only the selected custom controls are added into the Custom section, ready to be used: + +

Using ControlsFX imported controls

+ +If other controls are needed from this jar, the user can open the Library Manager again, and edit the related entry, to select again from the Import dialog. + +Also note that if an artifact is removed from the list, it will just be removed from Scene Builder, but the artifact won’t be removed from the local .m2 repository. + +### Manually add Library from repository option + +The user can type the exact names of groupID and artifactID coordinates of an artifact to get all existing versions of an artifact in all registered repositories: + +

Add library from repository dialog

+ +For instance, for `org.controlsfx` group and `controlsfx` artifact, a list is found in the registered repositories (Maven Central releases, Sonatype snapshots, Local .m2, Nexus, …): + +

Different ControlsFX artifacts found

+ +Then any given version can be selected to extract its custom controls, as it was shown earlier. + +### Add Library/FXML from file system option + +This option opens a file chooser that lets the user find a jar or an FXML file in the local file system. + +

Finding custom controls in the file system

+ +After locating and selecting a jar with one or more custom controls, it will extract them, in the same way: + +

Custom controls from local jar

+ +### Add root folder with *.class files option + +This is an alternative to adding the jar with the packaged classed: when building the control, the output folder that contains the list of classes is enough to find and import the custom control. The result is the same as with the jar, but this option removes the extra step of packaging, especially while developing the early versions of the control. + +

Custom controls from build folder

+ +### Manage repositories option + +Finally, the user can manage the repositories where artifacts are resolved from. + +

Manage repositories dialog

+ +Initially, the preset list of remote repositories is listed. These are not editable and can’t be removed. + +By clicking on Add Repository, the user can add new repositories to the list, both public or private. + +A new repository requires a name and a valid URL. If it is private, the credentials are required as well. The test button will perform a connection to the given URL to check if it is valid or not, and if private, if the credentials are valid as well. + +

Add custom repository dialog

+ +Note that in case of private repositories, the credentials will be stored locally in the user preferences. They will be used only when installing libraries from the private repository. + +## The Custom section + +All the components imported once from either local or remote repositories or from the local file system, will be listed in the Custom panel, ready to be used. These will remain available upon further restarts of Scene Builder, and will only be removed, if user does so from the Library Manager. + +## Custom controls + +To extract valid custom controls from the added jars or files, Scene Builder has to check every class or FXML file in the added jars/files and determine if those classes are valid custom controls or not. + +To determine if a *.class file is a possible custom control candidate, the following rules are applied: + +- First, it checks that the class name is not null, and the package name doesn't start with: + ``` + {"java.”, "javax.", "javafx.", "com.oracle.javafx.scenebuilder.", "com.javafx.", "module-info", “com.gluonhq.charm.glisten”)} + ``` + +- For valid class names, the classLoader tries to load the class +- The class should be public or protected and not abstract or package-private +- Finally, for the valid classes, FXMLLoader tries to load a simple FXML file that contains a reference to the given class. For instance, for the Popup custom control: + ``` + + + + ``` +- If the process succeeds, the class is considered a custom control. + +After the control is imported, there could be still some errors (related to its properties, for instance), and for that the Jar Analyzer report can offer valuable insight. + +### The Popup Custom Control + +This is just an example of a very simple custom control. + +The following classes define the Popup custom control that could be used as a simple bubble message node for chat applications. + +
+Popup.java + +```java +package popup; + +import javafx.beans.NamedArg; +import javafx.css.converter.PaintConverter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javafx.beans.DefaultProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.value.WritableValue; +import javafx.css.CssMetaData; +import javafx.css.FontCssMetaData; +import javafx.css.StyleOrigin; +import javafx.css.Styleable; +import javafx.css.StyleableObjectProperty; +import javafx.css.StyleableProperty; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; + +@DefaultProperty("content") +public class Popup extends Control { + + public Popup(@NamedArg("message") String message) { + getStyleClass().setAll("popup"); + + setContent(message); + } + + private final StringProperty content = new SimpleStringProperty(this, "content", "Default Message"); + public final String getContent() { return content.get(); } + public final void setContent(String value) { content.set(value); } + public final StringProperty contentProperty() { return content; } + + @Override + protected Skin createDefaultSkin() { + return new PopupSkin(this); + } + + @Override + public String getUserAgentStylesheet() { + return Popup.class.getResource("popup.css").toExternalForm(); + } + + private ObjectProperty bubbleFill; + private ObjectProperty textFill; + private ObjectProperty textFont; + + public final Paint getTextFill() { + return null == textFill ? Color.BLACK : textFill.get(); + } + public final void setTextFill(Paint value) { + textFillProperty().set(value); + } + public final ObjectProperty textFillProperty() { + if (null == textFill) { + textFill = new StyleableObjectProperty<>(Color.BLACK) { + + @Override public CssMetaData getCssMetaData() { return StyleableProperties.TEXT_FILL; } + + @Override public Object getBean() { return Popup.this; } + + @Override public String getName() { return "textFill"; } + }; + } + return textFill; + } + + public final Paint getBubbleFill() { + return null == bubbleFill ? Color.BLACK : bubbleFill.get(); + } + + public final void setBubbleFill(Paint value) { + bubbleFillProperty().set(value); + } + + public final ObjectProperty bubbleFillProperty() { + if (null == bubbleFill) { + bubbleFill = new StyleableObjectProperty<>(Color.BLACK) { + + @Override public CssMetaData getCssMetaData() { return StyleableProperties.BUBBLE_FILL; } + + @Override public Object getBean() { return Popup.this; } + + @Override public String getName() { return "bubbleFill"; } + }; + } + return bubbleFill; + } + + public final Font getTextFont(){ + return null == textFont ? Font.getDefault() : textFont.get(); + } + + public final void setTextFont(Font value) { + textFontProperty().set(value); + } + + public final ObjectProperty textFontProperty() { + if (null == textFont) { + textFont = new StyleableObjectProperty<>(Font.getDefault()) { + private boolean fontSetByCss = false; + @Override public void applyStyle(StyleOrigin newOrigin, Font value) { + try { + fontSetByCss = true; + super.applyStyle(newOrigin, value); + } catch(Exception e) { + throw e; + } finally { + fontSetByCss = false; + } + } + @Override public void set(Font value) { + final Font oldValue = get(); + if (value != null ? !value.equals(oldValue) : oldValue != null) { + super.set(value); + } + } + @Override protected void invalidated() { + if (!fontSetByCss) { + Popup.this.layout(); + Popup.this.applyCss(); + Popup.this.requestLayout(); + } + } + @Override public CssMetaData getCssMetaData() { return StyleableProperties.TEXT_FONT; } + @Override public Object getBean() { return Popup.this; } + @Override public String getName() { return "textFont"; } + }; + } + return textFont; + } + + private static class StyleableProperties { + + private static final CssMetaData BUBBLE_FILL = + new CssMetaData<>("-bubble-fill", PaintConverter.getInstance()) { + + @Override public boolean isSettable(Popup bubble) { + return null == bubble.bubbleFill || !bubble.bubbleFill.isBound(); + } + + @Override public StyleableProperty getStyleableProperty(Popup popup) { + return (StyleableProperty)(WritableValue) popup.bubbleFillProperty(); + } + }; + + private static final CssMetaData TEXT_FILL = + new CssMetaData("-text-fill", PaintConverter.getInstance(), Color.BLACK) { + + @Override public boolean isSettable(Popup bubble) { + return null == bubble.textFill || !bubble.textFill.isBound(); + } + + @Override public StyleableProperty getStyleableProperty(Popup popup) { + return (StyleableProperty)(WritableValue) popup.textFillProperty(); + } + }; + + private static final FontCssMetaData TEXT_FONT = + new FontCssMetaData("-text-font", Font.getDefault()) { + + @Override public boolean isSettable(Popup bubble) { + return null == bubble.textFont || !bubble.textFont.isBound(); + } + + @Override public StyleableProperty getStyleableProperty(Popup bubble) { + return (StyleableProperty)(WritableValue)bubble.textFontProperty(); + } + }; + + private static final List> STYLEABLES; + static { + final List> styleables = + new ArrayList<>(Control.getClassCssMetaData()); + styleables.add(BUBBLE_FILL); + styleables.add(TEXT_FILL); + styleables.add(TEXT_FONT); + + STYLEABLES = Collections.unmodifiableList(styleables); + } + + } + + public static List> getClassCssMetaData() { + return StyleableProperties.STYLEABLES; + } + + @Override + public List> getControlCssMetaData() { + return getClassCssMetaData(); + } + +} +``` +
+ +
+PopupSkin.java + +```java +package popup; + +import javafx.beans.binding.Bindings; +import javafx.geometry.Insets; +import javafx.scene.control.SkinBase; +import javafx.scene.layout.Background; +import javafx.scene.layout.BackgroundFill; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Region; +import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; + +public class PopupSkin extends SkinBase { + + private final Pane pane = new Pane(); + private final Region region = new Region(); + private final Text text = new Text(); + + private final Popup control; + + public PopupSkin(Popup control) { + super(control); + this.control = control; + + initialize(); + } + + private void initialize() { + pane.getStyleClass().add("popup-pane"); + region.getStyleClass().add("popup-region"); + text.getStyleClass().add("popup-text"); + + region.backgroundProperty().bind(Bindings.createObjectBinding(()-> + new Background(new BackgroundFill(getSkinnable().getBubbleFill(), CornerRadii.EMPTY, Insets.EMPTY)), + getSkinnable().bubbleFillProperty())); + + text.setTextAlignment(TextAlignment.CENTER); + + text.textProperty().bind(control.contentProperty()); + + text.fillProperty().bind(control.textFillProperty()); + text.fontProperty().bind(getSkinnable().textFontProperty()); + + pane.setPrefSize(50, 50); + pane.getChildren().addAll(region, text); + getChildren().add(pane); + } + + @Override + protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) { + super.layoutChildren(contentX, contentY, contentWidth, contentHeight); + + pane.resize(contentWidth, contentHeight); + + region.setPrefSize(0.8 * contentWidth, 0.8 * contentHeight); + region.relocate(0.1 * contentWidth, 0.1 * contentHeight); + + text.setWrappingWidth(contentWidth / 2d); + + text.relocate(pane.getWidth() / 2d - text.getBoundsInLocal().getWidth() / 2d, + pane.getHeight() / 2d - text.getBoundsInLocal().getHeight() / 2d); + } +} +``` +
+ + +
+popup.css + +```css +.popup { + +} + +.popup > .popup-pane > .popup-region { + /* https://commons.wikimedia.org/wiki/File:Speech_bubble.svg */ + -fx-shape: "M 45.673,0 C 67.781,0 85.703,12.475 85.703,27.862 C 85.703,43.249 67.781,55.724 45.673,55.724 C 38.742,55.724 32.224,54.497 26.539,52.34 C 15.319,56.564 0,64.542 0,64.542 C 0,64.542 9.989,58.887 14.107,52.021 C 15.159,50.266 15.775,48.426 16.128,46.659 C 9.618,41.704 5.643,35.106 5.643,27.862 C 5.643,12.475 23.565,0 45.673,0 M 45.673,2.22 C 24.824,2.22 7.862,13.723 7.862,27.863 C 7.862,34.129 11.275,40.177 17.472,44.893 L 18.576,45.734 L 18.305,47.094 C 17.86,49.324 17.088,51.366 16.011,53.163 C 15.67,53.73 15.294,54.29 14.891,54.837 C 18.516,53.191 22.312,51.561 25.757,50.264 L 26.542,49.968 L 27.327,50.266 C 32.911,52.385 39.255,53.505 45.673,53.505 C 66.522,53.505 83.484,42.002 83.484,27.862 C 83.484,13.722 66.522,2.22 45.673,2.22 L 45.673,2.22 z "; + -fx-background-color: red; +} + +``` +
+ +As it can be seen in the source code, the control is a regular JavaFX control with some JavaFX properties and a custom skin. + +There are some specific optional annotations intended for FXML: + +- `@DefaultProperty`: Specifies a property to which child elements will be added or set when an explicit property is not given. +- `@NamedArg`: allows an FXMLLoader to instantiate a class that does not have a zero-argument constructor. + +When the control is added to Scene Builder, the control’s properties are visible in the Inspector area (to the right), and the user can interact with them: + +

The popup custom control in action

+ +```xml + + + + + + + + + + + + + + + +``` + +## Troubleshooting + +After importing a jar with one or more possible custom controls, it is possible that not all the expected controls show up. + +The Jar Analysis Report can provide insightful information about the reasons for this. As mentioned earlier, when exploring the jar, the FXMLLoader is instantiated with the possible custom control classes, and if something fails, the result is one or more exceptions that are captured by the Jar Analysis and the report just shows them: + +

The Jar Analysis report

+ +By checking the exceptions, developers can go back and fix the issues in the source code. diff --git a/kit/pom.xml b/kit/pom.xml index 3875ea491..ec0a7fe43 100644 --- a/kit/pom.xml +++ b/kit/pom.xml @@ -7,7 +7,7 @@ com.gluonhq.scenebuilder parent - 21.0.2-SNAPSHOT + 24.0.0-SNAPSHOT @@ -71,7 +71,6 @@ display ${gluon.attach.version} desktop - runtime @@ -91,14 +90,6 @@ 1.0.4 runtime - - - - org.assertj - assertj-core - 3.19.0 - test - @@ -117,15 +108,6 @@ - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M5 - - false - 1 - - diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/ResourceUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/ResourceUtils.java index 03b32a4fd..3f3992bd6 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/ResourceUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/ResourceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -50,6 +50,10 @@ public class ResourceUtils { private static List videoExtensions; private static List mediaExtensions; + ResourceUtils() { + // no-op + } + public static String getToolStylesheet(ToolTheme theme) { switch(theme) { case DARK: diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java new file mode 100644 index 000000000..2712a60b2 --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/Cmd.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Cmd allows the execution of a given command line in a defined working directory. The execution is + * aborted after the timeout. + */ +final class Cmd { + + /** + * Executes a given command line using the working directory and timeout. + * + * @param cmd The command line to be executed defined as a {@link List} of {@link String} + * @param wDir The working directory, where the process shall be executed within. + * @param timeoutSec Duration in in seconds after which the execution should be stopped. + * @return exit code of the command line as an Integer + * + * @throws IOException - if the command was not found or the program execution exceeds the given timeout duration. + * @throws InterruptedException - if the current thread is interrupted while waiting + */ + public final Integer exec(List cmd, File wDir, long timeoutSec) throws IOException, + InterruptedException { + ProcessBuilder builder = new ProcessBuilder(cmd); + builder = builder.directory(wDir); + Process proc = builder.start(); + boolean completed = proc.waitFor(timeoutSec, TimeUnit.SECONDS); + if (completed) { + return proc.exitValue(); + } + throw new IOException("Process timed out after %s seconds!".formatted(timeoutSec)); + } + +} diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java index 41073419a..0bb065252 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -2331,12 +2331,13 @@ private void performEditIncludedFile() { assert includedFile != null; // Because of (1) try { EditorPlatform.open(includedFile.getAbsolutePath()); - } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.open.title")); - errorDialog.setMessage(I18N.getString("error.file.open.message", - includedFile.getAbsolutePath())); - errorDialog.setDebugInfoWithThrowable(ioe); + } catch (IOException re) { + final ErrorDialog errorDialog = new ErrorDialog(this.ownerWindow); + errorDialog.setTitle(I18N.getString("alert.error.file.open.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.open.edit.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", includedFile.getAbsolutePath())); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.open.edit.details.title")); + errorDialog.setDebugInfoWithThrowable(re); errorDialog.showAndWait(); } } @@ -2348,11 +2349,11 @@ private void performRevealIncludedFile() { try { EditorPlatform.revealInFileBrowser(includedFile); } catch (IOException ioe) { - final ErrorDialog errorDialog = new ErrorDialog(null); - errorDialog.setTitle(I18N.getString("error.file.reveal.title")); - errorDialog.setMessage(I18N.getString("error.file.reveal.message", - includedFile.getAbsolutePath())); - errorDialog.setDetails(I18N.getString("error.write.details")); + final ErrorDialog errorDialog = new ErrorDialog(this.ownerWindow); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", includedFile.getAbsolutePath())); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); errorDialog.setDebugInfoWithThrowable(ioe); errorDialog.showAndWait(); } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java index e2a4e2ac2..40cf39e6d 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/EditorPlatform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -39,11 +39,13 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import com.oracle.javafx.scenebuilder.kit.i18n.I18N; import javafx.scene.Node; @@ -58,6 +60,8 @@ */ public class EditorPlatform { + private static final Logger LOGGER = Logger.getLogger(EditorPlatform.class.getName()); + public enum OS { LINUX, MAC, WINDOWS; @@ -68,6 +72,10 @@ public static OS get() { private static final String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); //NOI18N + static { + LOGGER.log(Level.FINE, "Detected Operating System: {0}", osName); + } + /** * True if current platform is running Linux. */ @@ -210,7 +218,7 @@ public Color getColor() { } } } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to get color from stylesheet: ", e); + LOGGER.log(Level.WARNING, "Failed to get color from stylesheet: ", e); } } return color; @@ -242,7 +250,11 @@ public String getStylesheetURL() { return GlistenStyleClasses.impl_loadResource("theme_" + name().toLowerCase(Locale.ROOT) + ".css"); } } - + + EditorPlatform() { + // no-op + } + public static String getPlatformThemeStylesheetURL() { // Return USER_AGENT css, which is Modena for fx 8.0 return Theme.MODENA.getStylesheetURL(); @@ -302,9 +314,10 @@ public static boolean isGluonMobileDark(Theme theme) { * 'xdg-open'. On Mac, it runs 'open'. On Windows, it runs 'cmd /c start'. * * @param path path for the file to be opened - * @throws IOException if an error occurs + * @throws IOException in case the application called failed to open due to an error. + * @throws FileBrowserRevealException in case the application opened indicates an error (unexpected return code). */ - public static void open(String path) throws IOException { + public static void open(String path) throws IOException, FileBrowserRevealException { List args = new ArrayList<>(); if (EditorPlatform.IS_MAC) { args.add("open"); //NOI18N @@ -327,21 +340,22 @@ public static void open(String path) throws IOException { } if (!args.isEmpty()) { - executeDaemon(args, null); + executeDaemon(args, null, 0); } } - + /** - * Requests the underlying platform to "reveal" the specified folder. On - * Linux, it runs 'nautilus'. On Mac, it runs 'open'. On Windows, it runs - * 'explorer /select'. + * Requests the underlying platform to open the specified folder in its default file system viewer. This will reveal any file therein. + * On Linux, it runs {@code 'xdg-open'}. On Mac, it runs {@code 'open'} and on Windows it runs {@code 'explorer /select'}. * * @param filePath path for the folder to be revealed - * @throws IOException if an error occurs + * @throws FileBrowserRevealException This exception allows to catch exits codes != 0 from the called process. + * @throws IOException General IOExceptions are thrown by Java System Call Processes in case of an error. */ - public static void revealInFileBrowser(File filePath) throws IOException { + public static void revealInFileBrowser(File filePath) throws IOException, FileBrowserRevealException { List args = new ArrayList<>(); - String path = filePath.toURI().toURL().toExternalForm(); + String path = Paths.get(filePath.toURI()).normalize().toAbsolutePath().toString(); + int exitCodeOk = 0; if (EditorPlatform.IS_MAC) { args.add("open"); //NOI18N args.add("-R"); //NOI18N @@ -349,32 +363,21 @@ public static void revealInFileBrowser(File filePath) throws IOException { } else if (EditorPlatform.IS_WINDOWS) { args.add("explorer"); //NOI18N args.add("/select," + path); //NOI18N - } else if (EditorPlatform.IS_LINUX) { - // nautilus does fine on Ubuntu, which is a Debian. - // I've no idea how it does with other Linux flavors. - args.add("nautilus"); //NOI18N - // The nautilus that comes with Ubuntu up to 11.04 included doesn't - // take a file path as parameter (you get an error popup), you must - // provide a dir path. - // Starting with Ubuntu 11.10 (the first based on kernel 3.x) a - // file path is well managed. - int osVersionNumerical = Integer.parseInt(System.getProperty("os.version").substring(0, 1)); //NOI18N - if (osVersionNumerical < 3) { - // Case Ubuntu 10.04 to 11.04: What you provide to nautilus is - // the name of the directory containing the file you want to see - // listed. See DTL-5384. - path = filePath.getAbsoluteFile().getParent(); - if (path == null) { - path = "."; //NOI18N - } + exitCodeOk = 1; + } else if (EditorPlatform.IS_LINUX) { + args.add("xdg-open"); //NOI18N + path = filePath.getAbsoluteFile().getParent(); + if (path == null) { + path = "."; //NOI18N } args.add(path); } else { // Not Supported + LOGGER.log(Level.SEVERE, "Unsupported operating system! Cannot reveal location {0} in file browser.", path); } if (!args.isEmpty()) { - executeDaemon(args, null); + executeDaemon(args, null, exitCodeOk); } } @@ -406,18 +409,49 @@ public static boolean isNonContinousSelectKeyDown(MouseEvent e) { public static boolean isAssertionEnabled() { return EditorPlatform.class.desiredAssertionStatus(); } - - /* - * Private + + /** + * Executes a system process using the given cmd list as command line definition within the provided + * working directory. + * + * @param cmd Command line definition as {@link List} of {@link String} + * @param wDir Working Directory as {@link File} + * @param exitCodeOk Certain applications (e.g. Windows Explorer) do report exit code 1 in case + * everything is okay. Hence one can configure the expected exit code here. + * @throws IOException Any given runtime exception is collected and re-thrown as + * IOException. + * + * @throws FileBrowserRevealException This exception is only thrown if the exit code of the command + * line call is not 0. This allows to specifically react e.g. to + * invalid command line calls or to unsuccessful calls. Not every + * cmd call which ends with an error code != 0 is creating an + * exception. */ - private static void executeDaemon(List cmd, File wDir) throws IOException { + private static void executeDaemon(List cmd, File wDir, int exitCodeOk) + throws IOException, FileBrowserRevealException { + var cmdLine = cmd.stream().collect(Collectors.joining(" ")); + long timeoutSec = 5; try { - ProcessBuilder builder = new ProcessBuilder(cmd); - builder = builder.directory(wDir); - builder.start(); + int exitValue = new Cmd().exec(cmd, wDir, timeoutSec); + if (exitCodeOk != exitValue) { + LOGGER.log(Level.SEVERE, "Error during attempt to run: {0} in {1}", new Object[] { cmdLine, wDir }); + throw new FileBrowserRevealException( + "The command to reval the file exited with an error (exitValue=%s).\nCommand: %s\nWorking Dir: %s" + .formatted(Integer.toString(exitValue), cmdLine, wDir)); + } else { + LOGGER.log(Level.FINE, "Successfully executed command: {0} in {1}", new Object[] { cmdLine, wDir }); + } } catch (RuntimeException ex) { + LOGGER.log(Level.SEVERE, "Unknown error during attempt to run: {0} in {1}", new Object[] { cmdLine, wDir }); throw new IOException(ex); + } catch (InterruptedException e) { + LOGGER.log(Level.SEVERE, "Process timeout after {0}s: {1} in {2}", + new Object[] { timeoutSec, cmdLine, wDir }); + Thread.currentThread().interrupt(); + String msg = "The command to reval the file exited with an error after timeout.\nCommand: %s\nWorking Dir: %s\nTimeout (s):%s" + .formatted(cmdLine, wDir, timeoutSec); + String detailMsg = msg + "\n" + e.getMessage(); + throw new IOException(detailMsg); } } - } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java new file mode 100644 index 000000000..a4a3e78ab --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/FileBrowserRevealException.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import java.io.IOException; + +public class FileBrowserRevealException extends IOException { + + private static final long serialVersionUID = -1682452255824949867L; + + public FileBrowserRevealException(String message) { + super(message); + } + +} diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/AbstractDropTarget.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/AbstractDropTarget.java index d73f0f4ad..1087cc179 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/AbstractDropTarget.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/AbstractDropTarget.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -40,7 +41,11 @@ * */ public abstract class AbstractDropTarget { - + + AbstractDropTarget() { + // no-op + } + public abstract FXOMObject getTargetObject(); public abstract boolean acceptDragSource(AbstractDragSource dragSource); public abstract Job makeDropJob(AbstractDragSource dragSource, EditorController editorController); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/RootDropTarget.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/RootDropTarget.java index abbf56aea..bdd009185 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/RootDropTarget.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/drag/target/RootDropTarget.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -43,6 +44,10 @@ */ public class RootDropTarget extends AbstractDropTarget { + public RootDropTarget() { + // no-op + } + /* * AbstractDropTarget */ diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/images/ImageUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/images/ImageUtils.java index ec409e915..016727d5c 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/images/ImageUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/images/ImageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -66,6 +66,10 @@ public abstract class ImageUtils { private static ImageCursor css_cursor; private static final WeakHashMap> imageCache = new WeakHashMap<>(); + ImageUtils() { + // no-op + } + public static Image getImage(URL resource) { // No resource found for the specified name if (resource == null) { diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/JobUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/JobUtils.java index 81c909888..4de72d0d3 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/JobUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/JobUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -50,6 +51,10 @@ */ public class JobUtils { + private JobUtils() { + // no-op + } + public static void addColumnConstraints( final FXOMDocument fxomDocument, final FXOMInstance gridPane, diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/gridpane/GridPaneJobUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/gridpane/GridPaneJobUtils.java index 8e5e0bfaf..65e0da6dd 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/gridpane/GridPaneJobUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/gridpane/GridPaneJobUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -55,6 +56,10 @@ public enum Position { ABOVE, BELOW, BEFORE, AFTER } + GridPaneJobUtils() { + // no-op + } + /** * Returns the list of target GridPane objects. * diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/FXOMObjectCourseComparator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/FXOMObjectCourseComparator.java index 89c0415ed..a5790318c 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/FXOMObjectCourseComparator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/FXOMObjectCourseComparator.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -118,6 +119,10 @@ public int index() { } } + FXOMObjectCourseComparator() { + // no-op + } + /** ************************************************************************* * * * Comparator on row axis AND column axis * diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/WrapJobUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/WrapJobUtils.java index defa4f4ea..b40222d34 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/WrapJobUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/job/wrap/WrapJobUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,6 +53,10 @@ */ public class WrapJobUtils { + WrapJobUtils() { + // no-op + } + /** * Returns the property name of the specified container to be used for wrapping jobs. * May be either the children or the content property name diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java index 91aab1609..ea127c372 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/messagelog/MessageLog.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -46,7 +47,11 @@ * */ public class MessageLog { - + + public MessageLog() { + // no-op + } + private final List entries = new ArrayList<>(); private final SimpleIntegerProperty revision = new SimpleIntegerProperty(); private final SimpleIntegerProperty numOfWarningMessages = new SimpleIntegerProperty(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java index 0def5bb29..4a9e161dd 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/ContentPanelController.java @@ -65,6 +65,7 @@ import javafx.scene.control.TreeTableView; import javafx.scene.image.Image; import javafx.scene.input.InputEvent; +import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundImage; @@ -911,6 +912,20 @@ protected void controllerDidLoadFxml() { = getEditorController().getContextMenuController(); scrollPane.setContextMenu(contextMenuController.getContextMenu()); + scrollPane.setOnKeyPressed(e -> { + + if (e.getCode() == KeyCode.ESCAPE) { + // on ESC we select the parent of current selected item + Selection selection = getEditorController().getSelection(); + FXOMObject parent = selection.getAncestor(); + + if (parent != null) { + selection.clear(); + selection.select(parent); + } + } + }); + // Setup default workspace background setWorkspaceBackground(ImageUtils.getImage(getDefaultWorkspaceBackgroundURL())); } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/SplitPaneDesignInfoX.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/SplitPaneDesignInfoX.java index 191b157bc..f4f7ce2a2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/SplitPaneDesignInfoX.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/SplitPaneDesignInfoX.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -44,6 +45,9 @@ */ public class SplitPaneDesignInfoX { + public SplitPaneDesignInfoX() { + // no-op + } /** * Convert from local coordinates to divider position coordinates (0-1). diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TabPaneDesignInfoX.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TabPaneDesignInfoX.java index b28d78c2d..93b019345 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TabPaneDesignInfoX.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TabPaneDesignInfoX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024 Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,6 +52,9 @@ */ public class TabPaneDesignInfoX /* extends TabDesignInfo */ { + public TabPaneDesignInfoX() { + // no-op + } /** * Returns the node representing the tab header in the TabPane skin. diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TableViewDesignInfoX.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TableViewDesignInfoX.java index 47ea3e39f..c32bcdcab 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TableViewDesignInfoX.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TableViewDesignInfoX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -55,6 +55,9 @@ */ public class TableViewDesignInfoX /* extends TableViewDesignInfo */ { + public TableViewDesignInfoX() { + // no-op + } public Bounds getColumnBounds(TableColumn tableColumn) { final TableView tv = tableColumn.getTableView(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TreeTableViewDesignInfoX.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TreeTableViewDesignInfoX.java index 2923f9054..0d9792562 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TreeTableViewDesignInfoX.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/driver/TreeTableViewDesignInfoX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -55,6 +55,9 @@ */ public class TreeTableViewDesignInfoX { + public TreeTableViewDesignInfoX() { + // no-op + } public Bounds getColumnBounds(TreeTableColumn treeTableColumn) { final TreeTableView tv = treeTableColumn.getTreeTableView(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/AbstractSegment.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/AbstractSegment.java index 62a6cea12..7db9a69e8 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/AbstractSegment.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/AbstractSegment.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -36,7 +37,11 @@ * */ public abstract class AbstractSegment implements Comparable { - + + AbstractSegment() { + // no-op + } + public abstract double getX1(); public abstract double getY1(); public abstract double getX2(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/SegmentIndex.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/SegmentIndex.java index 2183b3234..b2f60b011 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/SegmentIndex.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/guides/SegmentIndex.java @@ -45,6 +45,9 @@ public class SegmentIndex { private final List segments = new ArrayList<>(); private boolean sorted; + public SegmentIndex() { + // no-op + } public void addSegment(AbstractSegment s) { segments.add(s); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUnion.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUnion.java index d42bbd812..9059afdd0 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUnion.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUnion.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -42,7 +43,11 @@ public class BoundsUnion { private Bounds result; - + + public BoundsUnion() { + // no-op + } + public void add(Bounds b) { if (result == null) { result = b; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUtils.java index 5e6a029cd..afb3ac001 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/BoundsUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -42,7 +43,11 @@ * */ public class BoundsUtils { - + + BoundsUtils() { + // no-op + } + public static Bounds makeBounds(Point2D p1, Point2D p2) { return new BoundingBox( Math.min(p1.getX(), p2.getX()), diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/DistanceUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/DistanceUtils.java index 3c26bd12e..e24a20e98 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/DistanceUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/DistanceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Gluon and/or its affiliates. + * Copyright (c) 2018, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -37,6 +37,10 @@ public class DistanceUtils { + DistanceUtils() { + // no-op + } + /** * Calculates distance from point to line * diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java index bbe9f0f06..c9a655cc4 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/content/util/Picker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Gluon and/or its affiliates. + * Copyright (c) 2018, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -56,7 +56,11 @@ public class Picker { private final Set excludes = new HashSet<>(); private final List matches = new ArrayList<>(); - + + public Picker() { + // no-op + } + /** * Returns the list of nodes below (sceneX, sceneY). * Topmost node is at index 0. diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java index 301bb095e..757bc2ffc 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/CssPanelController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -46,6 +46,7 @@ import com.oracle.javafx.scenebuilder.kit.editor.panel.css.NodeCssState.CssProperty; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Item; import com.oracle.javafx.scenebuilder.kit.editor.panel.util.AbstractFxmlPanelController; +import com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog.ErrorDialog; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject; import com.oracle.javafx.scenebuilder.kit.editor.panel.css.SelectionPath.Path; @@ -107,6 +108,8 @@ * */ public class CssPanelController extends AbstractFxmlPanelController { + + private static final Logger LOGGER = Logger.getLogger(CssPanelController.class.getName()); @FXML private StackPane cssPanelHost; @@ -185,6 +188,10 @@ public enum View { */ public static abstract class Delegate { + public Delegate() { + // no-op + } + public abstract void revealInspectorEditor(ValuePropertyMetadata propMeta); } @@ -1445,7 +1452,14 @@ private void navigate(CssProperty item, PropertyState state, CssStyle style, Sty EditorPlatform.revealInFileBrowser(f); } } catch (URISyntaxException | IOException ex) { - System.out.println(ex.getMessage() + ": " + ex); + LOGGER.log(Level.SEVERE, "An unexpected error occured!", ex); + final ErrorDialog errorDialog = new ErrorDialog(editorController.getOwnerWindow()); + errorDialog.setTitle(I18N.getString("alert.error.file.reveal.title")); + errorDialog.setMessage(I18N.getString("alert.error.file.reveal.message")); + errorDialog.setDetails(I18N.getString("alert.error.file.reveal.details", path)); + errorDialog.setDetailsTitle(I18N.getString("alert.error.file.reveal.details.title")); + errorDialog.setDebugInfoWithThrowable(ex); + errorDialog.showAndWait(); } } } else { diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/NodeCssState.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/NodeCssState.java index 28c8fd6f4..124a3b49b 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/NodeCssState.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/css/NodeCssState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -427,6 +427,10 @@ public final Collection getUserAgentStyles() { */ public static class RuleComparator implements Comparator { + RuleComparator() { + // no-op + } + @Override public int compare(MatchingRule t, MatchingRule t1) { int originComparaison = compareOrigin( diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyAnimationScheduler.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyAnimationScheduler.java index 90da16f8d..5b543b7b4 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyAnimationScheduler.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/HierarchyAnimationScheduler.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,6 +53,10 @@ public class HierarchyAnimationScheduler { // The bigger it is, the slower the animation will be. private final double rate = 4.0; + public HierarchyAnimationScheduler() { + // no-op + } + public void playDecrementAnimation(final ScrollBar scrollBar) { assert scrollBar != null; final double minValue = scrollBar.getMin(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewController.java index dce380884..dec62e927 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewController.java @@ -1,4 +1,5 @@ /* + * 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. * @@ -46,11 +47,14 @@ import javafx.scene.Node; import javafx.scene.control.Cell; import javafx.scene.control.Control; +import javafx.scene.control.MultipleSelectionModel; import javafx.scene.control.ScrollBar; import javafx.scene.control.SelectionMode; import javafx.scene.control.TreeCell; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; +import javafx.scene.control.TableView.TableViewSelectionModel; +import javafx.scene.input.KeyCode; /** * Hierarchy panel controller based on the TreeView control. @@ -85,6 +89,22 @@ protected void initializePanel() { // We do not use the platform editing feature because // editing is started on selection + simple click instead of double click treeView.setEditable(false); + + treeView.setOnKeyPressed(event -> { + + if (event.getCode() == KeyCode.ESCAPE) { + // on ESC we select the parent of current selected item + MultipleSelectionModel> selectionModel = treeView.getSelectionModel(); + TreeItem item = selectionModel.getSelectedItem(); + if (item != null) { + TreeItem parent = item.getParent(); + if (parent != null) { + selectionModel.clearSelection(); + selectionModel.select(parent); + } + } + } + }); } @Override diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewUtils.java index 899d64529..1921183b8 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/hierarchy/treeview/HierarchyTreeViewUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -46,6 +47,10 @@ */ public abstract class HierarchyTreeViewUtils { + HierarchyTreeViewUtils() { + // no-op + } + /** * Returns the TreeCells for the specified TreeView. * diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/Editor.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/Editor.java index 5d2070309..cd380994e 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/Editor.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/Editor.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -57,6 +58,10 @@ public abstract class Editor { public static final String INDETERMINATE_STR = "-"; //NOI18N + Editor() { + // no-op + } + public abstract Node getValueEditor(); public abstract MenuButton getMenu(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java index 3eee5f2e3..72866b45b 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/inspector/editors/EditorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -80,6 +80,10 @@ public class EditorUtils { static final String[] FXML_RESERVED_KEYWORDS = {"null"}; //NOI18N private static final String FXINCLUDE_JAVADOC_URL = "https://openjfx.io/javadoc/11/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html#include_elements"; + EditorUtils() { + // no-op + } + public static void makeWidthStretchable(final Node node) { Parent p = node.getParent(); if (p == null) { diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/LibraryUtil.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/LibraryUtil.java index b6d1842e4..c5013b5f2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/LibraryUtil.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/LibraryUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019 Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -45,6 +45,10 @@ public class LibraryUtil { public static final String FOLDERS_LIBRARY_FILENAME = "library.folders"; //NOI18N + LibraryUtil() { + // no-op + } + public static boolean isJarPath(Path path) { final String pathString = path.toString().toLowerCase(Locale.ROOT); return pathString.endsWith(".jar"); //NOI18N diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/maven/preset/MavenPresets.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/maven/preset/MavenPresets.java index b36a9dbe3..87a76df43 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/maven/preset/MavenPresets.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/library/maven/preset/MavenPresets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -41,7 +41,11 @@ public class MavenPresets { public static final String SONATYPE = "Sonatype"; public static final String GLUON_NEXUS = "Gluon Nexus"; public static final String LOCAL = "Local"; - + + MavenPresets() { + // no-op + } + private static final List REPOSITORIES = Arrays.asList( new Repository(MAVEN, "default", "https://repo1.maven.org/maven2/"), new Repository(SONATYPE + " (snapshots)", "default", "https://oss.sonatype.org/content/repositories/snapshots"), diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/AbstractPopupController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/AbstractPopupController.java index 9a786d541..bfec1d9ce 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/AbstractPopupController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/AbstractPopupController.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,7 +53,11 @@ public abstract class AbstractPopupController { private Popup popup; private Node anchor; private Window anchorWindow; - + + public AbstractPopupController() { + // no-op + } + /** * Returns the root FX object of this popup. * When called the first time, this method invokes {@link #makeRoot()} diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/ErrorDialog.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/ErrorDialog.java index 2696e8518..8ee7f5080 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/ErrorDialog.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/ErrorDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -43,6 +43,7 @@ public class ErrorDialog extends AlertDialog { private String debugInfo; + private String detailsTitle; public ErrorDialog(Window owner) { super(owner); @@ -80,7 +81,10 @@ public void setDebugInfoWithThrowable(Throwable t) { setDebugInfo(info); } - + public void setDetailsTitle(String detailsTitle) { + this.detailsTitle = detailsTitle; + } + /* * Private */ @@ -90,8 +94,11 @@ private void updateActionButtonVisibility() { } private void showDetailsDialog() { - final TextViewDialog detailDialog = new TextViewDialog(null); + final TextViewDialog detailDialog = new TextViewDialog(this.getStage()); detailDialog.setText(debugInfo); + if (detailsTitle != null) { + detailDialog.setTitle(detailsTitle); + } detailDialog.showAndWait(); } } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/report/ErrorReport.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/report/ErrorReport.java index 047e56f01..f4dcd511a 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/report/ErrorReport.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/report/ErrorReport.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -56,7 +57,11 @@ * */ public class ErrorReport { - + + public ErrorReport() { + // no-op + } + private final Map> entries = new HashMap<>(); private final Map cssParsingReports = new HashMap<>(); private FXOMDocument fxomDocument; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/AbstractSelectionGroup.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/AbstractSelectionGroup.java index 1bc483e95..5cef398ed 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/AbstractSelectionGroup.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/AbstractSelectionGroup.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -42,7 +43,11 @@ public abstract class AbstractSelectionGroup implements Cloneable { public abstract FXOMObject getAncestor(); public abstract boolean isValid(FXOMDocument fxomDocument); - + + AbstractSelectionGroup() { + // no-op + } + @Override public AbstractSelectionGroup clone() throws CloneNotSupportedException { diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java index 1688bb5ba..252f838d0 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/editor/selection/Selection.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,7 +53,11 @@ * */ public class Selection { - + + public Selection() { + // no-op + } + private AbstractSelectionGroup group; private final SimpleIntegerProperty revision = new SimpleIntegerProperty(); private boolean lock; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/FXOMNodes.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/FXOMNodes.java index 96d87766e..b201ba55d 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/FXOMNodes.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/FXOMNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Gluon and/or its affiliates. + * Copyright (c) 2022, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -70,7 +70,10 @@ */ public class FXOMNodes { - + FXOMNodes() { + // no-op + } + /** * Sorts the specified set of objects according their location in * the fxom document. Objets are sorted according depth first order. diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueNode.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueNode.java index 7cc6385a4..8c2ec8338 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueNode.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/glue/GlueNode.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -36,5 +37,8 @@ * */ public abstract class GlueNode { - + + GlueNode() { + // no-op + } } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/sampledata/SampleDataGenerator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/sampledata/SampleDataGenerator.java index 9b9a61225..f45b9d16e 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/sampledata/SampleDataGenerator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/fxom/sampledata/SampleDataGenerator.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -55,7 +56,11 @@ public class SampleDataGenerator { private final Map sampleDataMap = new HashMap<>(); - + + public SampleDataGenerator() { + // no-op + } + public void assignSampleData(FXOMObject startObject) { assert startObject != null; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/glossary/Glossary.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/glossary/Glossary.java index 377667c12..576b0821b 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/glossary/Glossary.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/glossary/Glossary.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -43,7 +44,11 @@ public abstract class Glossary { private final SimpleIntegerProperty revision = new SimpleIntegerProperty(); - + + Glossary() { + // no-op + } + /** * Returns candidate controller classes tracked by this glossary. * If fxmlLocation is not null, this glossary may use it to filter the diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18N.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18N.java index 0b643dd64..93425e20a 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18N.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18N.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -41,8 +42,10 @@ public class I18N { private static ResourceBundle bundle; - private static ResourceBundle.Control utf8EncodingControl = new I18NControl(); - + I18N() { + // no-op + } + public static String getString(String key) { return getBundle().getString(key); } @@ -55,7 +58,7 @@ public static String getString(String key, Object... arguments) { public static synchronized ResourceBundle getBundle() { if (bundle == null) { final String packageName = I18N.class.getPackage().getName(); - bundle = ResourceBundle.getBundle(packageName + ".SceneBuilderKit",utf8EncodingControl); //NOI18N + bundle = ResourceBundle.getBundle(packageName + ".SceneBuilderKit"); //NOI18N } return bundle; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProvider.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProvider.java new file mode 100644 index 000000000..d92a61e70 --- /dev/null +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.javafx.scenebuilder.kit.i18n.spi; + +import java.util.spi.ResourceBundleProvider; + +public interface I18NResourcesProvider extends ResourceBundleProvider { } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18NControl.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProviderImpl.java similarity index 68% rename from kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18NControl.java rename to kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProviderImpl.java index 6b1a2b99a..5f66c50c9 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/I18NControl.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/i18n/spi/I18NResourcesProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Gluon and/or its affiliates. + * Copyright (c) 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -13,7 +13,7 @@ * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. - * - Neither the name of Oracle Corporation nor the names of its + * - Neither the name of Oracle Corporation and Gluon nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,30 +29,40 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -package com.oracle.javafx.scenebuilder.kit.i18n; +package com.oracle.javafx.scenebuilder.kit.i18n.spi; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Locale; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.spi.AbstractResourceBundleProvider; + +public class I18NResourcesProviderImpl extends AbstractResourceBundleProvider implements I18NResourcesProvider { + + public I18NResourcesProviderImpl() { + // no-op + } -public class I18NControl extends ResourceBundle.Control { @Override - public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) { + public ResourceBundle getBundle(String baseName, Locale locale) { String bundleName = toBundleName(baseName, locale); - String resourceName = toResourceName(bundleName, "properties"); - try (InputStream is = loader.getResourceAsStream(resourceName); - InputStreamReader isr = new InputStreamReader(is, "UTF-8"); + String resourceName = ResourceBundle.Control + .getControl(ResourceBundle.Control.FORMAT_DEFAULT) + .toResourceName(bundleName, "properties"); + try (InputStream is = Files.newInputStream(Path.of(resourceName)); + InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr)) { return new PropertyResourceBundle(reader); } catch (IOException e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to create ResourceBundle: ", e); + Logger.getLogger(getClass().getName()).log(Level.WARNING, "Failed to create ResourceBundle for bundleName: " + bundleName + " and resourceName: " + resourceName, e); return null; } } diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/BuiltinSectionComparator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/BuiltinSectionComparator.java index d20cd6480..b91b2a57d 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/BuiltinSectionComparator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/BuiltinSectionComparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Gluon and/or its affiliates. + * Copyright (c) 2016, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -55,7 +55,10 @@ public class BuiltinSectionComparator implements Comparator { orderedSections.add(BuiltinLibrary.TAG_3D); } - + public BuiltinSectionComparator() { + // no-op + } + /* * Comparator */ diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/Library.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/Library.java index 9c270327f..7566b68f8 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/Library.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/Library.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Gluon and/or its affiliates. + * Copyright (c) 2022, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -43,7 +43,11 @@ * A collection of [LibraryItem]. */ public abstract class Library { - + + public Library() { + // no-op + } + private final ObservableList itemsProperty = FXCollections.observableArrayList(); private final ObjectProperty classLoaderProperty = new SimpleObjectProperty<>(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/LibraryItemNameComparator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/LibraryItemNameComparator.java index bda3a28e4..814921319 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/LibraryItemNameComparator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/LibraryItemNameComparator.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -39,7 +40,11 @@ * */ public class LibraryItemNameComparator implements Comparator { - + + public LibraryItemNameComparator() { + // no-op + } + /** * The comparison done here is performed on the name property of the * LibraryItem, and it is done ignoring the case. diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/util/ExplorerBase.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/util/ExplorerBase.java index 6b711d4a4..1ddf56ebd 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/util/ExplorerBase.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/library/util/ExplorerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Gluon and/or its affiliates. + * Copyright (c) 2020, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -102,8 +102,10 @@ JarReportEntry exploreEntry(String entryName, ClassLoader classLoader, String cl // http://stackoverflow.com/questions/8100376/class-forname-vs-classloader-loadclass-which-to-use-for-dynamic-loading entryClass = classLoader.loadClass(className); // Note: static intializers of entryClass are not run, this doesn't seem to be an issue - if (Modifier.isAbstract(entryClass.getModifiers()) - || !Node.class.isAssignableFrom(entryClass)) { + final int modifiers = entryClass.getModifiers(); + if (Modifier.isAbstract(modifiers) + || !Node.class.isAssignableFrom(entryClass) + || !(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers))) { status = JarReportEntry.Status.IGNORED; entryClass = null; entryException = null; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ColorEncoder.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ColorEncoder.java index 5de9bf66a..360373e52 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ColorEncoder.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ColorEncoder.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -44,7 +45,11 @@ public class ColorEncoder { private static Map standardColors; private static Map standardColorNames; - + + ColorEncoder() { + // no-op + } + public static String encodeColor(Color color) { final String colorName = getStandardColorNames().get(color); final String result; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataClassComparator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataClassComparator.java index a1c978620..abc4f3bbb 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataClassComparator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataClassComparator.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -39,6 +40,10 @@ */ public class ValuePropertyMetadataClassComparator implements Comparator { + public ValuePropertyMetadataClassComparator() { + // no-op + } + @Override public int compare(ValuePropertyMetadata propMeta1, ValuePropertyMetadata propMeta2) { String className1; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataNameComparator.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataNameComparator.java index 084842d33..329e66247 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataNameComparator.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/metadata/util/ValuePropertyMetadataNameComparator.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -39,6 +40,10 @@ */ public class ValuePropertyMetadataNameComparator implements Comparator { + public ValuePropertyMetadataNameComparator() { + // no-op + } + @Override public int compare(ValuePropertyMetadata propMeta1, ValuePropertyMetadata propMeta2) { String name1 = propMeta1.getName().getName(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonContext.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonContext.java index f5b4c5232..f12560e64 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonContext.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Gluon and/or its affiliates. + * Copyright (c) 2021, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -47,7 +47,7 @@ import java.util.TreeMap; import java.util.TreeSet; -class SkeletonContext { +public class SkeletonContext { private final String fxController; private final String documentName; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJRuby.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJRuby.java index 866b21a8d..00da8ffd7 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJRuby.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJRuby.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Gluon and/or its affiliates. + * Copyright (c) 2023, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -45,6 +45,10 @@ public class SkeletonCreatorJRuby implements SkeletonConverter { static final String NL = System.lineSeparator(); static final String INDENT = " "; //NOI18N + SkeletonCreatorJRuby() { + // no-op + } + public String createFrom(SkeletonContext context) { final StringBuilder sb = new StringBuilder(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJava.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJava.java index fa205c012..cc1b09bc2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJava.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorJava.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Gluon and/or its affiliates. + * Copyright (c) 2021, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -33,6 +33,10 @@ public class SkeletonCreatorJava extends AbstractSkeletonCreator { + SkeletonCreatorJava() { + // no-op + } + @Override void appendPackage(SkeletonContext context, StringBuilder sb) { String controller = context.getFxController(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorKotlin.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorKotlin.java index ed9c68e70..587cfc11f 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorKotlin.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/skeleton/SkeletonCreatorKotlin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Gluon and/or its affiliates. + * Copyright (c) 2021, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -33,6 +33,10 @@ public class SkeletonCreatorKotlin extends AbstractSkeletonCreator { + SkeletonCreatorKotlin() { + // no-op + } + @Override void appendPackage(SkeletonContext context, StringBuilder sb) { String controller = context.getFxController(); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/CssInternal.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/CssInternal.java index e2c6e51f0..a00b0361c 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/CssInternal.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/CssInternal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Gluon and/or its affiliates. + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -59,22 +59,24 @@ import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.Theme; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance; import com.oracle.javafx.scenebuilder.kit.metadata.property.ValuePropertyMetadata; -import javafx.css.CompoundSelector; import javafx.css.Rule; import javafx.css.Selector; -import javafx.css.SimpleSelector; import javafx.css.Style; import javafx.css.Stylesheet; import javafx.css.CssParser; /** * - * Utility classes using css internal classes (from com.sun package). Note that - * the CSS Analyzer is also using extensively com.sun classes. + * Utility classes to extract CSS information. + * Note: Requires JavaFX 23+ * */ public class CssInternal { + CssInternal() { + // no-op + } + private final static String[] themeUrls = { Theme.CASPIAN_EMBEDDED_HIGH_CONTRAST.getStylesheetURL(), Theme.CASPIAN_EMBEDDED_QVGA_HIGH_CONTRAST.getStylesheetURL(), @@ -243,25 +245,12 @@ private static Set getStyleClasses(final URL url) { return styleClasses; } if (s == null) { - // The parsed CSS file was empty. No parsing occured. + // The parsed CSS file was empty. No parsing occurred. return styleClasses; } for (Rule r : s.getRules()) { for (Selector ss : r.getSelectors()) { - if (ss instanceof SimpleSelector) { - SimpleSelector simple = (SimpleSelector) ss; - styleClasses.addAll(simple.getStyleClasses()); - } else { - if (ss instanceof CompoundSelector) { - CompoundSelector cs = (CompoundSelector) ss; - for (Selector selector : cs.getSelectors()) { - if (selector instanceof SimpleSelector) { - SimpleSelector simple = (SimpleSelector) selector; - styleClasses.addAll(simple.getStyleClasses()); - } - } - } - } + styleClasses.addAll(ss.getStyleClassNames()); } } return styleClasses; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/JavaLanguage.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/JavaLanguage.java index 32d87ad7d..2de9a6a3b 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/JavaLanguage.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/JavaLanguage.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -39,7 +40,11 @@ * */ public class JavaLanguage { - + + JavaLanguage() { + // no-op + } + /** * Returns true if value is a valid identifier (as specified * in Java Language Specification, section 3.8). diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/MathUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/MathUtils.java index bafa6297d..88d664313 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/MathUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/MathUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -35,7 +36,11 @@ * */ public class MathUtils { - + + MathUtils() { + // no-op + } + /** * Returns true if the two specified double values are approximately equals. * @param v1 first double to check diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/PaintConvertUtil.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/PaintConvertUtil.java index bc7be4781..e5700e458 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/PaintConvertUtil.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/PaintConvertUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Gluon and/or its affiliates. + * Copyright (c) 2022, 2024, Gluon and/or its affiliates. * All rights reserved. Use is subject to license terms. * * This file is available and licensed under the following license: @@ -47,6 +47,10 @@ public class PaintConvertUtil { private static final int ROUNDING_FACTOR = 10000;//Use for round to 4 decimal places + PaintConvertUtil() { + // no-op + } + public static String convertPaintToCss(Paint fxPaint) { if (fxPaint instanceof LinearGradient) { LinearGradient paint = (LinearGradient) fxPaint; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/URLUtils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/URLUtils.java index 777507edd..166155c94 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/URLUtils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/URLUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -42,7 +43,11 @@ * */ public class URLUtils { - + + URLUtils() { + // no-op + } + public static boolean equals(URL url1, URL url2) { boolean result; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/Utils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/Utils.java index 1f594b9e2..d41268f3e 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/Utils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/Utils.java @@ -1,3 +1,34 @@ +/* + * Copyright (c) 2017, 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.oracle.javafx.scenebuilder.kit.util; import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument; @@ -7,6 +38,11 @@ import java.net.URISyntaxException; public class Utils { + + Utils() { + // no-op + } + public static final String makeTitle(FXOMDocument fxomDocument) { final String title; diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/Utils.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/Utils.java index 359e12577..5ea247424 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/Utils.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/effectpicker/Utils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -52,6 +53,10 @@ public abstract class Utils { + Utils() { + // no-op + } + public static final Effect newInstance(Class clazz) { assert clazz != null; return newInstance(clazz.getSimpleName()); diff --git a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java index 514a01591..a4f17f6d2 100644 --- a/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java +++ b/kit/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/PaintPickerController.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Gluon and/or its affiliates. * Copyright (c) 2012, 2014, Oracle and/or its affiliates. * All rights reserved. Use is subject to license terms. * @@ -79,6 +80,10 @@ public class PaintPickerController { public final static RadialGradient DEFAULT_RADIAL = new RadialGradient(0.0, 0.0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE); + public PaintPickerController() { + // no-op + } + public final ObjectProperty paintProperty() { return paint; } diff --git a/kit/src/main/java/module-info.java b/kit/src/main/java/module-info.java new file mode 100644 index 000000000..3031a0f18 --- /dev/null +++ b/kit/src/main/java/module-info.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module com.gluonhq.scenebuilder.kit { + requires transitive javafx.graphics; + requires transitive javafx.controls; + requires transitive javafx.fxml; + requires javafx.swing; + requires javafx.media; + requires transitive javafx.web; + + requires com.gluonhq.charm.glisten; + requires com.gluonhq.attach.display; + requires static javax.json.api; + requires transitive static java.prefs; + + requires transitive static aether.api; + requires static aether.connector.basic; + requires static aether.impl; + requires static aether.spi; + requires static aether.transport.file; + requires static aether.transport.http; + requires static aether.util; + requires static org.apache.commons.codec; + requires static org.apache.httpcomponents.httpclient; + requires static org.apache.httpcomponents.httpcore; + requires static commons.lang3; + requires static maven.aether.provider; + requires static plexus.utils; + + opens com.oracle.javafx.scenebuilder.kit to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.alert to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.css; + opens com.oracle.javafx.scenebuilder.kit.editor; + opens com.oracle.javafx.scenebuilder.kit.editor.drag to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.drag.source to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.drag.target to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.images to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.atomic to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.gridpane to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.gridpane.v2 to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.reference to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.togglegroup to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.job.wrap to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.messagelog to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.curve to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.gridpane to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.handles to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.outline to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.pring to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.relocater to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.resizer to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.rudder to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.tring to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.key to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.mouse to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.guides to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.mode to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.content.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.css to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.info to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.inspector to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.popupeditors to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.manager to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.preset to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.repository to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.repository.dialog to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.search to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.report to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.search to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.selection to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.editor.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.fxom to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.fxom.glue to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.fxom.sampledata to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.glossary to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.i18n to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.i18n.spi to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.library to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.library.user to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.library.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.metadata to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.metadata.klass to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.metadata.property to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.metadata.property.value to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.metadata.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.preferences to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.preview to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.selectionbar to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.skeleton to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.template; + opens com.oracle.javafx.scenebuilder.kit.util to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.effectpicker to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.paintpicker to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.colorpicker to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.gradientpicker to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.rotator to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.slider to javafx.fxml; + opens com.oracle.javafx.scenebuilder.kit.util.eventnames to javafx.fxml; + + provides com.oracle.javafx.scenebuilder.kit.i18n.spi.I18NResourcesProvider with com.oracle.javafx.scenebuilder.kit.i18n.spi.I18NResourcesProviderImpl; + + exports com.oracle.javafx.scenebuilder.kit; + exports com.oracle.javafx.scenebuilder.kit.alert; + exports com.oracle.javafx.scenebuilder.kit.editor; + exports com.oracle.javafx.scenebuilder.kit.editor.drag; + exports com.oracle.javafx.scenebuilder.kit.editor.drag.source; + exports com.oracle.javafx.scenebuilder.kit.editor.drag.target; + exports com.oracle.javafx.scenebuilder.kit.editor.images; + exports com.oracle.javafx.scenebuilder.kit.editor.job; + exports com.oracle.javafx.scenebuilder.kit.editor.job.atomic; + exports com.oracle.javafx.scenebuilder.kit.editor.job.gridpane; + exports com.oracle.javafx.scenebuilder.kit.editor.job.gridpane.v2; + exports com.oracle.javafx.scenebuilder.kit.editor.job.reference; + exports com.oracle.javafx.scenebuilder.kit.editor.job.togglegroup; + exports com.oracle.javafx.scenebuilder.kit.editor.job.wrap; + exports com.oracle.javafx.scenebuilder.kit.editor.messagelog; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.curve; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.gridpane; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.handles; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.outline; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.pring; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.relocater; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.resizer; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.rudder; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.driver.tring; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.key; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.gesture.mouse; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.guides; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.mode; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.content.util; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.css; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.hierarchy.treeview; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.info; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.inspector; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.editors.util; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.inspector.popupeditors; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.manager; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.preset; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.repository; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.repository.dialog; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.library.maven.search; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.util; + exports com.oracle.javafx.scenebuilder.kit.editor.panel.util.dialog; + exports com.oracle.javafx.scenebuilder.kit.editor.report; + exports com.oracle.javafx.scenebuilder.kit.editor.search; + exports com.oracle.javafx.scenebuilder.kit.editor.selection; + exports com.oracle.javafx.scenebuilder.kit.editor.util; + exports com.oracle.javafx.scenebuilder.kit.fxom; + exports com.oracle.javafx.scenebuilder.kit.fxom.glue; + exports com.oracle.javafx.scenebuilder.kit.fxom.sampledata; + exports com.oracle.javafx.scenebuilder.kit.glossary; + exports com.oracle.javafx.scenebuilder.kit.i18n; + exports com.oracle.javafx.scenebuilder.kit.i18n.spi; + exports com.oracle.javafx.scenebuilder.kit.library; + exports com.oracle.javafx.scenebuilder.kit.library.user; + exports com.oracle.javafx.scenebuilder.kit.library.util; + exports com.oracle.javafx.scenebuilder.kit.metadata; + exports com.oracle.javafx.scenebuilder.kit.metadata.klass; + exports com.oracle.javafx.scenebuilder.kit.metadata.property; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value.list; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value.effect; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value.effect.light; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value.paint; + exports com.oracle.javafx.scenebuilder.kit.metadata.property.value.keycombination; + exports com.oracle.javafx.scenebuilder.kit.metadata.util; + exports com.oracle.javafx.scenebuilder.kit.preferences; + exports com.oracle.javafx.scenebuilder.kit.preview; + exports com.oracle.javafx.scenebuilder.kit.selectionbar; + exports com.oracle.javafx.scenebuilder.kit.skeleton; + exports com.oracle.javafx.scenebuilder.kit.template; + exports com.oracle.javafx.scenebuilder.kit.util; + exports com.oracle.javafx.scenebuilder.kit.util.control.effectpicker; + exports com.oracle.javafx.scenebuilder.kit.util.control.effectpicker.editors; + exports com.oracle.javafx.scenebuilder.kit.util.control.paintpicker; + exports com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.colorpicker; + exports com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.gradientpicker; + exports com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.rotator; + exports com.oracle.javafx.scenebuilder.kit.util.control.paintpicker.slider; + exports com.oracle.javafx.scenebuilder.kit.util.eventnames; +} \ No newline at end of file diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/AbstractModalDialogW.fxml b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/AbstractModalDialogW.fxml index c847ccc9f..84284225a 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/AbstractModalDialogW.fxml +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/editor/panel/util/dialog/AbstractModalDialogW.fxml @@ -1,4 +1,5 @@ + - + + @@ -55,7 +57,7 @@ - + diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties index decb59e0e..55de7bffa 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit.properties @@ -20,7 +20,7 @@ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NOlabel.action.edit.paste EVENT SHALL THE COPYRIGHT +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, @@ -430,10 +430,19 @@ error.file.create.title = File creation failed # {0} is a file path error.file.create.message = File {0} cannot be created error.file.open.message = File {0} cannot be opened -error.file.open.title = File opening failed error.write.details = Please check your file system. -error.file.reveal.title = File locating failed -error.file.reveal.message = File {0} cannot be found + +# Alert file open error +alert.error.file.open.title = File opening failed +alert.error.file.open.edit.message = Cannot open file for editing! +alert.error.file.open.edit.details = ''{0}'' +alert.error.file.open.edit.details.title = Details - File opening failed + +# Alert Dialog in case of revealing a file +alert.error.file.reveal.title = Failed to reveal file ... +alert.error.file.reveal.message = Cannot reveal file in file system viewer due to an error. +alert.error.file.reveal.details.title = File Reveal Error Details +alert.error.file.reveal.details = {0} #maven log.user.maven.installed = {0} installed in local repository diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties index 3b62233f7..e6c5eba6a 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_ja.properties @@ -406,8 +406,6 @@ error.file.create.message = ファイル{0}を作成できません error.file.open.message = ファイル{0}を開けません error.file.open.title = ファイルを開くのに失敗しました error.write.details = ファイル・システムを確認してください。 -error.file.reveal.title = ファイルを見つけるのに失敗しました -error.file.reveal.message = ファイル{0}が見つかりません #maven log.user.maven.installed = {0}はローカル・レポジトリにインストールされています diff --git a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties index c4df18a52..3e6b52b2a 100644 --- a/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties +++ b/kit/src/main/resources/com/oracle/javafx/scenebuilder/kit/i18n/SceneBuilderKit_zh_CN.properties @@ -76,12 +76,12 @@ log.info.explore.jar.results = 探索 JAR {0} 的结果 log.info.explore.folder.results = 探索文件夹 {0} 的结果 log.info.explore.no.results = 未找到自定义控件 log.warning.inline.edit.internationalized.strings = 无法内联编辑国际化字符串 -log.warning.color.creation.error.hexadecimal = 无法为十六进制值 “{0}” 创建颜色 -log.warning.image.location.does.not.exist = 图像 “{0}” 不存在 -log.warning.invalid.fxid = Id “{0}” 不是有效的 Java 标识符 -log.warning.no.injectable.fxid = 在 FXML 控制器类中找不到 id “{0}” 的可注入字段 -log.warning.duplicate.fxid = Id 为 “{0}” 的元素已注入 FXML 控制器 -log.warning.layout.failed = 布局失败 (“{0}”) +log.warning.color.creation.error.hexadecimal = 无法为十六进制值 ''{0}'' 创建颜色 +log.warning.image.location.does.not.exist = 图像 ''{0}'' 不存在 +log.warning.invalid.fxid = Id ''{0}'' 不是有效的 Java 标识符 +log.warning.no.injectable.fxid = 在 FXML 控制器类中找不到 id ''{0}'' 的可注入字段 +log.warning.duplicate.fxid = Id 为 ''{0}'' 的元素已注入 FXML 控制器 +log.warning.layout.failed = 布局失败 (''{0}'') # ----------------------------------------------------------------------------- # Library Panel @@ -99,7 +99,7 @@ hierarchy.column.header.classname = 类名 hierarchy.column.header.info = 信息 hierarchy.displayoption.info = 信息 hierarchy.displayoption.fxid = fx:id -hierarchy.displayoption.nodeid = 节点 Id +hierarchy.displayoption.nodeid = 节点 ID hierarchy.unresolved.class = 未解析的类 hierarchy.unresolved.location = 未解析的位置 hierarchy.unresolved.resource = 未解析的资源 @@ -176,8 +176,8 @@ inspector.rectangle2D.not.defined = 未定义 inspector.select.css.filter = 样式表文件 inspector.select.css.title = 添加样式表 inspector.select.image = 图像文件 -inspector.style.parsingerror = CSS 解析内联样式时出错:“{0}” -inspector.style.valuetypeerror = CSS 值类型错误:“{0}” +inspector.style.parsingerror = CSS 解析内联样式时出错:''{0}'' +inspector.style.valuetypeerror = CSS 值类型错误:''{0}'' inspector.stylesheet.alreadyexist = 已添加样式表 {0} inspector.stylesheet.cannotopen = 无法打开 {0} inspector.stylesheet.cannotreveal = 无法显示 {0} @@ -235,13 +235,13 @@ import.error.title = 导入失败 import.error.message = 无法完成导入 import.error.details = 请检查您尝试导入的内容,然后重试。 # File -> Import -> FXML / Media -import.from.file = 从 “{0}” 导入 -import.from.file.failed = 无法导入 “{0}” -import.from.file.failed.target = 无法在 “{1}” 下导入 “{0}” +import.from.file = 从 ''{0}'' 导入 +import.from.file.failed = 无法导入 ''{0}'' +import.from.file.failed.target = 无法在 ''{1}'' 下导入 ''{0}'' # File -> Include -> FXML -include.file = 包括 “{0}” -include.file.failed = 未能包括 “{0}” -include.file.failed.target = 未能在 “{1}” 下包括 “{0}” +include.file = 包括 ''{0}'' +include.file.failed = 未能包括 ''{0}'' +include.file.failed.target = 未能在 ''{1}'' 下包括 ''{0}'' # ----------------------------------------------------------------------------- # Library Dialog @@ -344,7 +344,7 @@ menu.title.duplicate = 重复 menu.title.delete = 删除 menu.title.select.parent = 选择父项 # Modify menu items -menu.title.fit = Fit to Parent +menu.title.fit = 适合父母 menu.title.use.computed.sizes = 使用计算大小 menu.title.grid = GridPane menu.title.edit.included.default = 编辑包含的文件 @@ -363,12 +363,12 @@ menu.title.grid.decrease.row.span = 减小行跨度 menu.title.grid.increase.column.span = 增加列跨度 menu.title.grid.decrease.column.span = 减小列跨度 # Arrange menu items -menu.title.front = Bring to Front -menu.title.back = Send to Back -menu.title.forward = Bring Forward -menu.title.backward = Send Backward -menu.title.wrap = Wrap in -menu.title.unwrap = Unwrap +menu.title.front = 带到前面 +menu.title.back = 发送回 +menu.title.forward = 向前推进 +menu.title.backward = 向后发送 +menu.title.wrap = 包裹 +menu.title.unwrap = 解开 # ----------------------------------------------------------------------------- # Preview Window @@ -432,8 +432,6 @@ error.file.create.message = 无法创建文件 {0} error.file.open.message = 无法打开文件 {0} error.file.open.title = 文件打开失败 error.write.details = 请检查您的文件系统。 -error.file.reveal.title = 文件定位失败 -error.file.reveal.message = 未找到 {0} 文件 #maven log.user.maven.installed = {0} 安装在本地存储库中 @@ -449,8 +447,8 @@ log.user.repository.updated = {0} 已更新 csspanel.col.api.defaults = API 默认值 csspanel.col.defaults = 默认值 csspanel.col.inline = 内联样式 -csspanel.col.inspector = Inspector -csspanel.col.properties = Properties +csspanel.col.inspector = 检查器 +csspanel.col.properties = 属性 csspanel.col.stylesheets = 样式表 csspanel.col.theme.defaults = FX 主题默认值 csspanel.hide.default.values = 隐藏具有默认值的属性 @@ -468,8 +466,8 @@ csspanel.fxtheme.origin = FX 主题样式表 csspanel.copy = 复制 csspanel.inherited = 继承 csspanel.no.matching.rule = 无匹配规则 -csspanel.node.property = property -csspanel.reveal.inspector = 在 Inspector 中显示... +csspanel.node.property = 属性 +csspanel.reveal.inspector = 在检查器中显示... csspanel.reveal.finder = 在 Finder 中显示 {0} csspanel.reveal.explorer = 在资源管理器中显示 {0} csspanel.open.stylesheet = 打开 {0} @@ -483,8 +481,8 @@ job.increase.row.span = 增加行跨度 job.set.size = 使用预定义大小 {0} x {1} job.set.toggle.group = 设置切换组 job.toggle.fx.root = 切换 fx:root -job.set.fxid = 设置 fx:id 到 “{0}” -job.remove.fxid = 移除 fx:id “{0}” +job.set.fxid = 设置 fx:id 到 ''{0}'' +job.remove.fxid = 移除 fx:id ''{0}'' ################ Alert when Gluon Mobile theme is not set alert.theme.gluon.mobile.title = Scene Builder @@ -500,15 +498,15 @@ alert.importing.gluon.contenttext = 不会导入这些控件,因为此版本 alert.importing.gluon.ok.button = 确定 ################ Scene Builder theme -prefs.tool.theme.default = Default Theme -prefs.tool.theme.dark = Dark Theme +prefs.tool.theme.default = 默认主题 +prefs.tool.theme.dark = 暗色主题 ################ Skeleton window -skeleton.add.comments = Comments +skeleton.add.comments = 注释 skeleton.empty = 不能从空文档构造任何骨架 skeleton.format.full = 完全 # Parameter is a fxml file name -skeleton.window.title = 示例 “{0}” 控制器类的骨架 +skeleton.window.title = 示例 ''{0}'' 控制器类的骨架 ################ Alert for saving Skeletons to file alert.skeleton.title = 控制器骨架 @@ -578,5 +576,5 @@ title.gluon.swatch.brown = Brown Swatch title.gluon.swatch.grey = Grey Swatch title.gluon.swatch.blue_grey = Blue Grey Swatch # Gluon Themes -title.gluon.theme.light = Light Theme -title.gluon.theme.dark = Dark Theme +title.gluon.theme.light = 浅色主题 +title.gluon.theme.dark = 暗色主题 diff --git a/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java new file mode 100644 index 000000000..32f25cadb --- /dev/null +++ b/kit/src/test/java/com/oracle/javafx/scenebuilder/kit/editor/CmdTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Gluon and/or its affiliates. + * All rights reserved. Use is subject to license terms. + * + * This file is available and licensed under the following license: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * - Neither the name of Oracle Corporation and Gluon nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.javafx.scenebuilder.kit.editor; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +public class CmdTest { + + private Cmd classUnderTest = new Cmd(); + + private final long timeoutSeconds = 2L; + + private Path workingDir = Path.of("./src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/") + .normalize() + .toAbsolutePath(); + + @Test + void that_exception_is_created_with_not_existing_command() { + var cmdLine = List.of("this", "command", "should", "not", "exist"); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertTrue(t.getMessage().startsWith("Cannot run program \"this\"")); + } + + @EnabledOnOs(value = {OS.WINDOWS}) + @Test + void that_exit_code_from_program_is_collected_on_Windows() { + var cmdLine = List.of(workingDir.resolve("exit-error.cmd").toString()); + + Integer result = assertDoesNotThrow(() -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(1, result, "Exit code must be 1"); + } + + @EnabledOnOs(value = {OS.LINUX, OS.MAC}) + @Test + void that_exit_code_is_collected_on_Linux_and_Mac() { + var cmdLine = List.of("/bin/sh", workingDir.resolve("exit-error.sh").toString()); + + Integer result = assertDoesNotThrow(() -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(1, result, "Exit code must be 1"); + } + + @EnabledOnOs(value = {OS.WINDOWS}) + @Test + void that_process_does_not_run_indefinitevely_on_Windows() { + var cmdLine = List.of(workingDir.resolve("timeout.cmd").toString()); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(t.getMessage(), "Process timed out after 2 seconds!"); + } + + @EnabledOnOs(value = {OS.LINUX, OS.MAC}) + @Test + void that_process_does_not_run_indefinitevely_on_Linux_and_Mac() { + var cmdLine = List.of("/bin/sh", workingDir.resolve("timeout.sh").toString()); + + Throwable t = assertThrows(IOException.class, + () -> classUnderTest.exec(cmdLine, workingDir.toFile(), timeoutSeconds)); + + assertEquals(t.getMessage(), "Process timed out after 2 seconds!"); + } + +} diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd new file mode 100644 index 000000000..9e24ca57f --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.cmd @@ -0,0 +1,2 @@ +ECHO Programm Error! +EXIT 1 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh new file mode 100644 index 000000000..23817e8c9 --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/exit-error.sh @@ -0,0 +1,2 @@ +echo Program exited with error. +exit 1 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd new file mode 100644 index 000000000..4f03ca5ca --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.cmd @@ -0,0 +1,3 @@ +ECHO Waiting for 5sec +TIMEOUT /T 5 +EXIT 0 diff --git a/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh new file mode 100644 index 000000000..9b5b3b78e --- /dev/null +++ b/kit/src/test/resources/com/oracle/javafx/scenebuilder/kit/editor/timeout.sh @@ -0,0 +1,3 @@ +echo Waiting for 5sec +sleep 5 +exit 0 diff --git a/pom.xml b/pom.xml index 9688d967c..8d6cfc4f2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.gluonhq.scenebuilder parent pom - 21.0.2-SNAPSHOT + 24.0.0-SNAPSHOT Scene Builder Scene Builder is a visual, drag n drop, layout tool for designing JavaFX application user interfaces 2012 @@ -16,14 +16,14 @@ - 21.0.1 - 21 - 21 - 21 - 21.0.1 + 21 + ${java.version} + ${java.version} + ${java.version} + 23 1.1.0 - 6.2.2 - 4.0.19 + 6.2.3 + 4.0.21 5.10.0 UTF-8 gluonhq/scenebuilder @@ -70,6 +70,12 @@ junit-jupiter-engine test + + org.assertj + assertj-core + 3.19.0 + test + @@ -82,7 +88,8 @@ ${main.class.name} - + + @@ -134,6 +141,18 @@ maven-resources-plugin 3.2.0 + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + false + 1 + --add-opens=javafx.fxml/javafx.fxml=com.gluonhq.scenebuilder.kit + +