Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: app data, prefs and library are stored in version specific location (#346, #369) #579

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4fd9107
fix: Application data, application preferences, messagebox and user l…
Oliver-Loeffler Oct 4, 2022
2b93977
Added Javadoc and reduced visibility of overloaded methods which were
Oliver-Loeffler Oct 4, 2022
47839cd
Imports cleaned.
Oliver-Loeffler Oct 4, 2022
1b7e1d0
Added more detailed error message in AppSettingsTest for case when re…
Oliver-Loeffler Oct 4, 2022
2a87ddf
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Nov 1, 2022
f0b1ec7
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Nov 2, 2022
051e665
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Mar 18, 2024
60bd738
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Aug 26, 2024
1aee392
OS is now passed consequently as param. Now also the path separators …
Oliver-Loeffler Aug 26, 2024
8250d42
Merge branch 'master' into issue-369
Oliver-Loeffler Sep 30, 2024
647ac20
Update PreferencesController.java
Oliver-Loeffler Sep 30, 2024
e5e46c0
Update PreferencesControllerTest.java
Oliver-Loeffler Sep 30, 2024
fe34536
Update AppSettingsTest.java
Oliver-Loeffler Sep 30, 2024
f0e54e2
Updated surefire version in reactor POM to make tests work with modul…
Oliver-Loeffler Sep 30, 2024
dd34480
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Oct 1, 2024
a5a490a
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Oct 2, 2024
3fe6c86
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Oct 2, 2024
91da6b8
Merge branch 'gluonhq:master' into issue-369
Oliver-Loeffler Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 76 additions & 31 deletions app/src/main/java/com/oracle/javafx/scenebuilder/app/AppPlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<String, String> 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;
}
Expand All @@ -125,7 +165,6 @@ public interface AppNotificationHandler {
public void handleQuitAction();
}


/*
* Private (requestStartGeneric)
*/
Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017 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.
*
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, String> 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());
}
}
Original file line number Diff line number Diff line change
@@ -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);
}

}
Loading