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 98e183e19..468f84415 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 @@ -32,17 +32,23 @@ */ package com.oracle.javafx.scenebuilder.app; -import com.oracle.javafx.scenebuilder.app.util.MessageBox; -import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; -import static com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.IS_LINUX; import static com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.IS_MAC; -import static com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.IS_WINDOWS; + import java.io.IOException; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Properties; + +import com.oracle.javafx.scenebuilder.app.util.AppSettings; +import com.oracle.javafx.scenebuilder.app.util.MessageBox; +import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform; +import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.OS; + import javafx.application.Application; import javafx.application.Platform; @@ -62,46 +68,80 @@ public class AppPlatform { } public static synchronized String getApplicationDataFolder() { - + return getApplicationDataFolder(OS.get()); + } + + static synchronized String getApplicationDataFolder(OS operatingSystem) { + return getApplicationDataFolder(System.getenv(), + System.getProperties(), + operatingSystem, + AppSettings.getSceneBuilderVersion()); + } + + static synchronized String getApplicationDataFolder(Map sysenv, Properties system, + OS operatingSystem, String version) { if (applicationDataFolder == null) { - final String appName = "Scene Builder"; //NOI18N - - if (IS_WINDOWS) { - applicationDataFolder - = System.getenv("APPDATA") + "\\" + appName; //NOI18N - } else if (IS_MAC) { - applicationDataFolder - = System.getProperty("user.home") //NOI18N - + "/Library/Application Support/" //NOI18N - + appName; - } else if (IS_LINUX) { - applicationDataFolder - = System.getProperty("user.home") + "/.scenebuilder"; //NOI18N + final String appName = "Scene Builder"; // NOI18N + switch (operatingSystem) { + case WINDOWS: + applicationDataFolder = sysenv.get("APPDATA") + "\\" + appName + "\\" + version; // NOI18N + break; + case MAC: + applicationDataFolder = system.getProperty("user.home") // NOI18N + + "/Library/Application Support/" // NOI18N + + appName + "/" + version; + break; + case LINUX: + applicationDataFolder = system.getProperty("user.home") + "/.scenebuilder/" + version; // NOI18N + break; } } - - assert applicationDataFolder != null; - + + assert applicationDataFolder != null; return applicationDataFolder; } + /** + * Clears application data folder, user library folder, message box folder and logs folder. + * Those locations will be determined on next occasion. + */ + protected static synchronized void clear() { + applicationDataFolder = null; + userLibraryFolder = null; + messageBoxFolder = null; + logsFolder = null; + } public static synchronized String getUserLibraryFolder() { - + return getUserLibraryFolder(OS.get()); + } + + static synchronized String getUserLibraryFolder(OS operatingSystem) { if (userLibraryFolder == null) { - userLibraryFolder = getApplicationDataFolder() + "/Library"; //NOI18N + if (OS.WINDOWS.equals(operatingSystem)) { + userLibraryFolder = getApplicationDataFolder(operatingSystem) + "\\" + "Library"; // NOI18N + } else { + userLibraryFolder = getApplicationDataFolder(operatingSystem) + "/" + "Library"; // NOI18N + } } - return userLibraryFolder; } - + /** * Returns the directory path for logs. Default path is "${user.home}/.scenebuilder/logs/". * @return Directory path for Scene Builder logs */ public static synchronized String getLogFolder() { + return getLogFolder(System.getProperties(), OS.get()); + } + + static synchronized String getLogFolder(Properties system, OS operatingSystem) { if (logsFolder == null) { - logsFolder = Paths.get(System.getProperty("user.home"), ".scenebuilder", "logs").toString(); //NOI18N + if (OS.WINDOWS.equals(operatingSystem)) { + logsFolder = system.getProperty("user.home") + "\\.scenebuilder\\logs"; //NOI18N + } else { + logsFolder = system.getProperty("user.home") + "/.scenebuilder/logs"; //NOI18N + } } return logsFolder; } @@ -125,7 +165,6 @@ public interface AppNotificationHandler { public void handleQuitAction(); } - /* * Private (requestStartGeneric) */ @@ -165,15 +204,21 @@ private static synchronized boolean requestStartGeneric( throw new IOException(x); } } - return result; } - private static String getMessageBoxFolder() { + protected static String getMessageBoxFolder() { + return getMessageBoxFolder(OS.get()); + } + + protected static String getMessageBoxFolder(OS operatingSystem) { if (messageBoxFolder == null) { - messageBoxFolder = getApplicationDataFolder() + "/MB"; //NOI18N + if (OS.WINDOWS.equals(operatingSystem)) { + messageBoxFolder = getApplicationDataFolder() + "\\MB"; //NOI18N + } else { + messageBoxFolder = getApplicationDataFolder() + "/MB"; //NOI18N + } } - return messageBoxFolder; } diff --git a/app/src/main/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java b/app/src/main/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java index 9925fa096..a1a5bf26b 100644 --- a/app/src/main/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java +++ b/app/src/main/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesController.java @@ -33,6 +33,7 @@ package com.oracle.javafx.scenebuilder.app.preferences; import com.oracle.javafx.scenebuilder.app.DocumentWindowController; +import com.oracle.javafx.scenebuilder.app.util.AppSettings; import com.oracle.javafx.scenebuilder.kit.preferences.PreferencesControllerBase; import java.util.HashMap; @@ -54,7 +55,7 @@ public class PreferencesController extends PreferencesControllerBase { **************************************************************************/ // PREFERENCES NODE NAME - static final String SB_RELEASE_NODE = "SB_2.0"; //NOI18N + static final String SB_RELEASE_NODE = "SB_"+AppSettings.getSceneBuilderVersion(); //NOI18N // GLOBAL PREFERENCES static final String TOOL_THEME = "TOOL_THEME"; //NOI18N diff --git a/app/src/test/java/com/oracle/javafx/scenebuilder/app/AppPlatformTest.java b/app/src/test/java/com/oracle/javafx/scenebuilder/app/AppPlatformTest.java new file mode 100644 index 000000000..497b9b25f --- /dev/null +++ b/app/src/test/java/com/oracle/javafx/scenebuilder/app/AppPlatformTest.java @@ -0,0 +1,132 @@ +/* + * 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. + * + * 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 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; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import com.oracle.javafx.scenebuilder.app.util.AppSettings; +import com.oracle.javafx.scenebuilder.kit.editor.EditorPlatform.OS; + +class AppPlatformTest { + + private final Map testEnvironment = new HashMap<>(); + + private final Properties testProperties = new Properties(); + + @BeforeEach + void prepare() { + AppPlatform.clear(); + + testEnvironment.clear(); + testEnvironment.put("APPDATA", "C:\\Users\\UserName\\AppData\\Roaming"); + + testProperties.clear(); + testProperties.put("user.home", "/home/user"); + } + + @ParameterizedTest + @CsvSource({ "WINDOWS, 18.0.0, C:\\Users\\UserName\\AppData\\Roaming\\Scene Builder\\18.0.0", + "LINUX, 19.1.2-SNAPSHOT, /home/user/.scenebuilder/19.1.2-SNAPSHOT", + "MAC, 17, /home/user/Library/Application Support/Scene Builder/17" }) + void that_applications_data_folder_matches_OS_requirements(OS operatingSystem, String version, + String expectedPath) { + String appDir = AppPlatform.getApplicationDataFolder(testEnvironment, testProperties, operatingSystem, version); + assertEquals(expectedPath, appDir); + } + + @Test + void that_library_path_is_subdir_of_appdata() { + Path appDir = Path.of(AppPlatform.getApplicationDataFolder()); + Path expectedLibDir = appDir.resolve("Library"); + Path generatedLibDir = Path.of(AppPlatform.getUserLibraryFolder()); + + assertEquals(expectedLibDir, generatedLibDir); + } + + @Test + void that_application_settings_directory_is_created_properly_on_windows() { + Path appDir = Path.of(AppPlatform.getApplicationDataFolder(OS.WINDOWS)); + Path expected = Path.of(System.getenv("APPDATA") + "\\Scene Builder\\" + AppSettings.getSceneBuilderVersion()); + assertEquals(expected, appDir); + } + + @Test + void that_application_settings_directory_is_created_properly_on_linux() { + Path appDir = Path.of(AppPlatform.getApplicationDataFolder(OS.LINUX)); + Path expected = Path + .of(System.getProperty("user.home") + "/.scenebuilder/" + AppSettings.getSceneBuilderVersion()); + assertEquals(expected, appDir); + } + + @Test + void that_application_settings_directory_is_created_properly_on_mac() { + Path appDir = Path.of(AppPlatform.getApplicationDataFolder(OS.MAC)); + Path expected = Path.of(System.getProperty("user.home") + "/Library/Application Support/Scene Builder/" + + AppSettings.getSceneBuilderVersion()); + assertEquals(expected, appDir); + } + + @Test + void that_user_library_folder_resides_in_applications_data_folder() { + // init app data folder first as this is the basis + AppPlatform.getApplicationDataFolder(testEnvironment, testProperties, OS.WINDOWS, "19.0.0-SNAPSHOT"); + String libraryDir = AppPlatform.getUserLibraryFolder(OS.WINDOWS); + assertEquals("C:\\Users\\UserName\\AppData\\Roaming\\Scene Builder\\19.0.0-SNAPSHOT\\Library", libraryDir); + } + + @Test + void that_messagebox_folder_resides_in_applications_data_folder() { + // init app data folder first as this is the basis + AppPlatform.getApplicationDataFolder(testEnvironment, testProperties, OS.WINDOWS, "19.0.0-SNAPSHOT"); + Path messageBoxDir = Path.of(AppPlatform.getMessageBoxFolder(OS.WINDOWS)); + Path expectedDir = Path.of("C:\\Users\\UserName\\AppData\\Roaming\\Scene Builder\\19.0.0-SNAPSHOT\\MB"); + assertEquals(expectedDir, messageBoxDir); + } + + @Test + void that_logfiles_are_stored_in_userhome_scenebuilder_logs() { + String expectedLogDir = Path.of(System.getProperty("user.home"), ".scenebuilder", "logs").toString(); + assertEquals(expectedLogDir, AppPlatform.getLogFolder()); + } +} diff --git a/app/src/test/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesControllerTest.java b/app/src/test/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesControllerTest.java new file mode 100644 index 000000000..24c1b0159 --- /dev/null +++ b/app/src/test/java/com/oracle/javafx/scenebuilder/app/preferences/PreferencesControllerTest.java @@ -0,0 +1,49 @@ +/* + * 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. + * + * 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 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.preferences; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import com.oracle.javafx.scenebuilder.app.util.AppSettings; + +class PreferencesControllerTest { + + @Test + void that_preferences_release_node_name_matches_app_version() { + assertEquals("SB_"+AppSettings.getSceneBuilderVersion(), + PreferencesController.SB_RELEASE_NODE); + } + +} diff --git a/app/src/test/java/com/oracle/javafx/scenebuilder/app/util/AppSettingsTest.java b/app/src/test/java/com/oracle/javafx/scenebuilder/app/util/AppSettingsTest.java new file mode 100644 index 000000000..fb303b777 --- /dev/null +++ b/app/src/test/java/com/oracle/javafx/scenebuilder/app/util/AppSettingsTest.java @@ -0,0 +1,78 @@ +/* + * 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: + * + * 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.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; + +import com.oracle.javafx.scenebuilder.app.about.AboutWindowController; + +class AppSettingsTest { + + @Test + void that_scene_builder_version_is_obtained_correctly() { + String expectedVersion = readSceneBuilderVersion(); + assertEquals(expectedVersion, AppSettings.getSceneBuilderVersion()); + } + + private String readSceneBuilderVersion() { + // about.properties is generated by Maven + URL resource = AboutWindowController.class.getResource("about.properties"); + if (null == resource) { + fail("The required file resource \"about.properties\" was not found!"); + } + Path file = new File(resource.getFile()).toPath(); + try { + List lines = Files.readAllLines(file); + for (String line : lines) { + if (line.startsWith("build.version=")) { + return line.split("=")[1]; + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + throw new AssertionFailedError("About.properties does not contain the required \"build.version\" entry."); + } + +} diff --git a/pom.xml b/pom.xml index f34de7467..77b02c753 100644 --- a/pom.xml +++ b/pom.xml @@ -136,7 +136,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M5 + 3.5.0 false 1