Skip to content

Commit

Permalink
Implemented a process to conditionally import previous SceneBuilder v…
Browse files Browse the repository at this point in the history
…ersion Preferences.
  • Loading branch information
Oliver-Loeffler committed Jan 4, 2022
1 parent 023d86a commit 34bd44f
Show file tree
Hide file tree
Showing 18 changed files with 1,271 additions and 48 deletions.
7 changes: 7 additions & 0 deletions app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
<artifactId>kit</artifactId>
<version>17.0.0</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.oracle.javafx.scenebuilder.app.i18n.I18N;
import com.oracle.javafx.scenebuilder.app.menubar.MenuBarController;
import com.oracle.javafx.scenebuilder.app.preferences.PreferencesController;
import com.oracle.javafx.scenebuilder.app.preferences.PreferencesImporter;
import com.oracle.javafx.scenebuilder.app.preferences.PreferencesRecordGlobal;
import com.oracle.javafx.scenebuilder.app.preferences.PreferencesWindowController;
import com.oracle.javafx.scenebuilder.app.registration.RegistrationWindowController;
Expand Down Expand Up @@ -388,6 +389,9 @@ public void handleLaunch(List<String> files) {

setApplicationUncaughtExceptionHandler();

PreferencesImporter prefsImporter = PreferencesController.getSingleton().getImporter();
prefsImporter.askForActionAndRun();

MavenPreferences mavenPreferences = PreferencesController.getSingleton().getMavenPreferences();
// Creates the user library
userLibrary = new UserLibrary(AppPlatform.getUserLibraryFolder(),
Expand Down Expand Up @@ -792,9 +796,7 @@ private void performExit() {
}
}

private enum ACTION {START, STOP}

;
private enum ACTION {START, STOP};

private void logTimestamp(ACTION type) {
switch (type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* Copyright (c) 2022, 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.preferences;

import java.util.Comparator;
import java.util.Optional;

/**
* A record type to work with Scene Builder versions following the semantic
* versioning schema. Patch versions can be null and will be ignored then.
*
* Version numbers can be sorted, where major beats minor beats patch versions.
* Version numbers with patch versions will be considered as higher (or newer) than version numbers without patch numbers.
* This is regardless if there is no patch number or patch version is 0. Patch version 0 is higher than no patch version at all.
*/
public record AppVersion(int major, int minor, Integer patch) implements Comparable<AppVersion> {

/**
* @return {@link Comparator} sorting {@link AppVersion} instances in descending order.
*/
public static Comparator<AppVersion> descending() {
return (a,b)->b.compareTo(a);
}

public AppVersion(int major, int minor) {
this(major, minor, null);
}

@Override
public int compareTo(AppVersion o) {
int majorDiff = major - o.major;
int minorDiff = minor - o.minor;
int patchDiff = calcPatchDiff(o);
if (majorDiff == 0) {
if (minorDiff == 0) {
return patchDiff;
}
return minorDiff;
}
return majorDiff;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(major);
builder.append(".");
builder.append(minor);
if (patch != null) {
builder.append(".");
builder.append(patch);
}
return builder.toString();
}

/**
* Creates a version specific Scene Builder Preferences node name using the given prefix.
* @param prefix {@link String} used as prefix in Preferences node naming.
* @return
*/
public String nodeNameWithPrefix(String prefix) {
StringBuilder builder = new StringBuilder();
if (prefix != null && !prefix.isBlank()) {
builder.append(prefix);
}
builder.append(major);
builder.append(".");
builder.append(minor);
if (patch != null) {
builder.append(".");
builder.append(patch);
}
return builder.toString();
}

protected int calcPatchDiff(AppVersion o) {
if (patch == null && o.patch == null) {
return 0;
} else if (patch == null && o.patch != null) {
return -1;
} else if (patch != null && o.patch == null) {
return 1;
}
return patch - o.patch;
}


/**
* Parses an optional AppVersion from any given String.
* Snapshot versions are not considered as valid.
*
* @param validVersion String representing a Scene Builder version.
* @return Empty optional when the String does not represent a valid version. If valid, then an optional AppVersion is returned.
*/
public static Optional<AppVersion> fromString(String validVersion) {
String[] elements = validVersion.strip().split("[.]");
return switch (elements.length) {
case 2 -> parseMajorMinor(elements);
case 3 -> parseMajorMinorPatch(elements);
default -> Optional.empty();
};
}

private static Optional<AppVersion> parseMajorMinor(String[] elements) {
try {
int major = Integer.parseInt(elements[0]);
int minor = Integer.parseInt(elements[1]);
if (major < 0 || minor < 0) {
return Optional.empty();
}
return Optional.of(new AppVersion(major, minor));
} catch (NumberFormatException nfe) {
return Optional.empty();
}
}

private static Optional<AppVersion> parseMajorMinorPatch(String[] elements) {
try {
int major = Integer.parseInt(elements[0]);
int minor = Integer.parseInt(elements[1]);
int patch = Integer.parseInt(elements[2]);
if (major < 0 || minor < 0 || patch < 0) {
return Optional.empty();
}
return Optional.of(new AppVersion(major, minor, patch));
} catch (NumberFormatException nfe) {
return Optional.empty();
}
}
}
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, 2012 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 @@ -32,17 +32,20 @@
*/
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;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import com.oracle.javafx.scenebuilder.app.DocumentWindowController;
import com.oracle.javafx.scenebuilder.app.util.AppSettings;
import com.oracle.javafx.scenebuilder.kit.preferences.MavenPreferences;
import com.oracle.javafx.scenebuilder.kit.preferences.PreferencesControllerBase;
import com.oracle.javafx.scenebuilder.kit.preferences.RepositoryPreferences;

/**
* Defines preferences for Scene Builder App.
*/
Expand All @@ -55,7 +58,8 @@ public class PreferencesController extends PreferencesControllerBase{
**************************************************************************/

// PREFERENCES NODE NAME
static final String SB_RELEASE_NODE = "SB_"+AppSettings.getSceneBuilderVersion(); //NOI18N
static final String SB_RELEASE_NODE_PREFIX = "SB_";
static final String SB_RELEASE_NODE = SB_RELEASE_NODE_PREFIX+AppSettings.getSceneBuilderVersion(); //NOI18N

// GLOBAL PREFERENCES
static final String TOOL_THEME = "TOOL_THEME"; //NOI18N
Expand Down Expand Up @@ -103,8 +107,8 @@ public class PreferencesController extends PreferencesControllerBase{
* *
**************************************************************************/

private PreferencesController() {
super(SB_RELEASE_NODE, new PreferencesRecordGlobal());
private PreferencesController(Preferences rootNode) {
super(rootNode, SB_RELEASE_NODE, new PreferencesRecordGlobal());

// Cleanup document preferences at start time :
final String items = applicationRootPreferences.get(RECENT_ITEMS, null); //NOI18N
Expand Down Expand Up @@ -139,14 +143,31 @@ private PreferencesController() {
**************************************************************************/

public static synchronized PreferencesController getSingleton() {
return getSingleton(null);
}

/**
* This method allows to pass in a custom {@link Preferences} node, e.g. for testing.
* When configured with null, the Preferences node to be used will be defined internally.
* The custom node is only set with the first call, when the {@link PreferencesController} was initialized before, t
* the Preferences node to be used cannot be changed anymore.
*
* @param prefs {@link Preferences} node to be used, can be null.
* @return The one and only PreferencesController instance.
*/
protected static synchronized PreferencesController getSingleton(Preferences prefs) {
if (singleton == null) {
singleton = new PreferencesController();
singleton = new PreferencesController(prefs);
singleton.getRecordGlobal().readFromJavaPreferences();
} else {
if (prefs != null) {
Logger.getLogger(PreferencesController.class.getName())
.log(Level.INFO, "PreferencesController was already initialized. Ignoring the provided preferences node.");
}
}
return singleton;
}


public PreferencesRecordDocument getRecordDocument(final DocumentWindowController dwc) {
final PreferencesRecordDocument recordDocument;
if (recordDocuments.containsKey(dwc)) {
Expand Down Expand Up @@ -185,4 +206,39 @@ public PreferencesRecordGlobal getRecordGlobal() {
protected String getEffectiveUsedRootNode() {
return applicationRootPreferences.absolutePath();
}

/**
* If there were older versions of Scene Builder used,
* this will return the Preferences node matching the most recent previous version.
* @return Optional version number of
*/
protected Optional<VersionedPreferences> getPreviousVersionSettings() {
return new VersionedPreferencesFinder(SB_RELEASE_NODE_PREFIX, applicationPreferences)
.previousVersionPrefs();
}

/**
* This allows to re-initialize application settings after user has decided to
* import previous version settings. If not called after import, a restart of
* Scene Builder is needed to have all imported settings effective.
* <p>
* Reloads the contents of {@link PreferencesRecordGlobal} and initializes
* {@link MavenPreferences} and {@link RepositoryPreferences} afterwards.
*/
protected void reload() {
getRecordGlobal().readFromJavaPreferences();
initializeMavenPreferences();
initializeRepositoryPreferences();
}

/**
* @return A {@link PreferencesImporter} instance for this application which
* will help to import previous version application settings.
*/
public PreferencesImporter getImporter() {
Optional<VersionedPreferences> previousVersionSettings = getPreviousVersionSettings();
PreferencesImporter importer = new PreferencesImporter(applicationRootPreferences, previousVersionSettings);
importer.runAfterImport(this::reload);
return importer;
}
}
Loading

0 comments on commit 34bd44f

Please sign in to comment.