diff --git a/G-Earth/pom.xml b/G-Earth/pom.xml
index 3c4a4ff..e778d23 100644
--- a/G-Earth/pom.xml
+++ b/G-Earth/pom.xml
@@ -299,6 +299,12 @@
logback-classic
${logback.version}
+
+ com.dustinredmond.fxtrayicon
+ FXTrayIcon
+ 4.0.1
+
+
diff --git a/G-Earth/src/main/java/gearth/GEarth.java b/G-Earth/src/main/java/gearth/GEarth.java
index cc5fb52..2b6a696 100644
--- a/G-Earth/src/main/java/gearth/GEarth.java
+++ b/G-Earth/src/main/java/gearth/GEarth.java
@@ -1,41 +1,33 @@
package gearth;
import gearth.misc.AdminValidator;
-import gearth.misc.Cacher;
import gearth.misc.UpdateChecker;
-import gearth.misc.listenerpattern.ObservableObject;
import gearth.ui.GEarthController;
+import gearth.ui.GEarthProperties;
import gearth.ui.themes.Theme;
-import gearth.ui.themes.ThemeFactory;
import gearth.ui.titlebar.TitleBarConfig;
import gearth.ui.titlebar.TitleBarController;
import javafx.application.Application;
import javafx.application.Platform;
+import javafx.beans.binding.Bindings;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
-import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
+import java.io.IOException;
+
public class GEarth extends Application {
public static GEarth main;
public static String version = "1.5.3";
public static String gitApi = "https://api.github.com/repos/sirjonasxx/G-Earth/releases/latest";
- public static ObservableObject observableTheme;
private Stage stage;
private GEarthController controller;
- static {
- observableTheme = new ObservableObject<>(
- Cacher.getCacheContents().has("theme") ?
- ThemeFactory.themeForTitle(Cacher.getCacheContents().getString("theme")) :
- ThemeFactory.getDefaultTheme()
- );
- }
@Override
public void start(Stage primaryStage) throws Exception{
@@ -52,9 +44,28 @@ public class GEarth extends Application {
}
controller = loader.getController();
controller.setStage(primaryStage);
- stage.initStyle(StageStyle.TRANSPARENT);
+ primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(new Scene(root));
+ primaryStage.setAlwaysOnTop(GEarthProperties.isAlwaysOnTop());
+ GEarthProperties.alwaysOnTopProperty
+ .addListener((observable, oldValue, newValue) -> primaryStage.setAlwaysOnTop(newValue));
+
+ initTitleBar(primaryStage);
+ initTheme();
+
+ primaryStage.setResizable(false);
+ primaryStage.sizeToScene();
+
+ primaryStage.show();
+ primaryStage.setOnCloseRequest(event -> closeGEarth());
+
+ AdminValidator.validate();
+ UpdateChecker.checkForUpdates();
+
+ }
+
+ private void initTitleBar(Stage primaryStage) throws IOException {
TitleBarController.create(primaryStage, new TitleBarConfig() {
@Override
public boolean displayThemePicker() {
@@ -66,11 +77,6 @@ public class GEarth extends Application {
return true;
}
-// @Override
-// public boolean allowResizing() {
-// return false;
-// }
-
@Override
public void onCloseClicked() {
closeGEarth();
@@ -83,25 +89,20 @@ public class GEarth extends Application {
@Override
public void setTheme(Theme theme) {
- setGearthTheme(theme);
+ GEarthProperties.themeProperty.set(theme);
}
@Override
public Theme getCurrentTheme() {
- return observableTheme.getObject();
+ return GEarthProperties.getTheme();
}
});
- primaryStage.setResizable(false);
- primaryStage.sizeToScene();
-
- setGearthTheme(observableTheme.getObject());
-
- primaryStage.show();
- primaryStage.setOnCloseRequest(event -> closeGEarth());
-
- AdminValidator.validate();
- UpdateChecker.checkForUpdates();
+ }
+ private void initTheme() {
+ stage.titleProperty().bind(GEarthProperties.themeTitleBinding);
+ Bindings.bindContent(stage.getScene().getStylesheets(), GEarthProperties.styleSheets);
+ Bindings.bindContent(stage.getIcons(), GEarthProperties.icons);
}
private void closeGEarth() {
@@ -110,30 +111,6 @@ public class GEarth extends Application {
System.exit(0);
}
- private void setGearthTheme(Theme theme) {
- Cacher.put("theme", theme.title());
- observableTheme.setObject(theme);
- Theme defaultTheme = ThemeFactory.getDefaultTheme();
-
-// Platform.runLater(() -> {
- stage.getScene().getStylesheets().clear();
- stage.getScene().getStylesheets().add(GEarth.class.getResource(String.format("/gearth/ui/themes/%s/styling.css", theme.internalName())).toExternalForm());
-
- stage.getIcons().clear();
- stage.getIcons().add(new Image(GEarth.class.getResourceAsStream(String.format("/gearth/ui/themes/%s/logoSmall.png", theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName()))));
- stage.setTitle((theme.overridesTitle() ? theme.title() : defaultTheme.title()) + " " + GEarth.version);
-
- controller.infoController.img_logo.setImage(new Image(GEarth.class.getResourceAsStream(
- String.format(
- "/gearth/ui/themes/%s/logo.png",
- theme.overridesLogo() ? theme.internalName() : defaultTheme.internalName()
- )
- )));
- controller.infoController.version.setText(stage.getTitle());
-// });
-
- }
-
public static String[] args;
public static void main(String[] args) {
@@ -161,14 +138,6 @@ public class GEarth extends Application {
return null;
}
- public static ObservableObject getThemeObservable() {
- return observableTheme;
- }
-
- public static Theme getTheme() {
- return observableTheme.getObject();
- }
-
public static void setAlertOwner(Alert alert) {
alert.initOwner(main.stage);
}
diff --git a/G-Earth/src/main/java/gearth/extensions/ExtensionBase.java b/G-Earth/src/main/java/gearth/extensions/ExtensionBase.java
index d801aeb..b3feef8 100644
--- a/G-Earth/src/main/java/gearth/extensions/ExtensionBase.java
+++ b/G-Earth/src/main/java/gearth/extensions/ExtensionBase.java
@@ -2,19 +2,14 @@ package gearth.extensions;
import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
-import gearth.misc.listenerpattern.ObservableObject;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.services.packet_info.PacketInfo;
import gearth.services.packet_info.PacketInfoManager;
import javafx.beans.property.ObjectProperty;
-import org.reactfx.util.Lists;
+import javafx.beans.property.SimpleObjectProperty;
import java.util.*;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Stream;
public abstract class ExtensionBase extends IExtension {
@@ -33,10 +28,11 @@ public abstract class ExtensionBase extends IExtension {
volatile PacketInfoManager packetInfoManager = PacketInfoManager.EMPTY;
- ObservableObject observableHostInfo = new ObservableObject<>(null);
+
+ ObjectProperty hostInfoProperty = new SimpleObjectProperty<>();
void updateHostInfo(HostInfo hostInfo) {
- observableHostInfo.setObject(hostInfo);
+ hostInfoProperty.set(hostInfo);
}
/**
@@ -67,7 +63,7 @@ public abstract class ExtensionBase extends IExtension {
* @param messageListener the callback
*/
public void intercept(HMessage.Direction direction, String hashOrName, MessageListener messageListener) {
- Map> listeners =
+ final Map> listeners =
direction == HMessage.Direction.TOCLIENT ?
hashOrNameIncomingListeners :
hashOrNameOutgoingListeners;
@@ -197,6 +193,6 @@ public abstract class ExtensionBase extends IExtension {
}
public HostInfo getHostInfo() {
- return observableHostInfo.getObject();
+ return hostInfoProperty.get();
}
}
diff --git a/G-Earth/src/main/java/gearth/extensions/ExtensionForm.java b/G-Earth/src/main/java/gearth/extensions/ExtensionForm.java
index 6922c93..8ebe983 100644
--- a/G-Earth/src/main/java/gearth/extensions/ExtensionForm.java
+++ b/G-Earth/src/main/java/gearth/extensions/ExtensionForm.java
@@ -1,17 +1,17 @@
package gearth.extensions;
+import com.sun.org.apache.xpath.internal.operations.Bool;
import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
import gearth.services.packet_info.PacketInfoManager;
import javafx.application.HostServices;
import javafx.application.Platform;
-import javafx.beans.InvalidationListener;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
import javafx.stage.Stage;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
-import java.util.function.Consumer;
-
/**
* Created by Jonas on 22/09/18.
*/
@@ -99,8 +99,17 @@ public abstract class ExtensionForm extends ExtensionBase {
}
public HostInfo getHostInfo() {
- return extension.observableHostInfo.getObject();
+ return extension.hostInfoProperty.get();
+ }
+
+ private final BooleanProperty fieldsInitializedProperty = new SimpleBooleanProperty(false);
+
+ public void setFieldsInitialised(boolean value) {
+ fieldsInitializedProperty.set(value);
+ }
+
+ public BooleanProperty fieldsInitialisedProperty() {
+ return fieldsInitializedProperty;
}
- Observable fieldsInitialized = new Observable<>(Runnable::run);
}
diff --git a/G-Earth/src/main/java/gearth/extensions/ExtensionFormLauncher.java b/G-Earth/src/main/java/gearth/extensions/ExtensionFormLauncher.java
index 8f67369..1cde28a 100644
--- a/G-Earth/src/main/java/gearth/extensions/ExtensionFormLauncher.java
+++ b/G-Earth/src/main/java/gearth/extensions/ExtensionFormLauncher.java
@@ -60,7 +60,8 @@ public class ExtensionFormLauncher extends Application {
extensionForm.extension = extension;
extensionForm.primaryStage = primaryStage;
- extensionForm.fieldsInitialized.fireEvent();
+ extensionForm.setFieldsInitialised(true);
+
Thread t = new Thread(() -> {
extension.run();
//when the extension has ended, close this process
diff --git a/G-Earth/src/main/java/gearth/extensions/InternalExtensionFormLauncher.java b/G-Earth/src/main/java/gearth/extensions/InternalExtensionFormLauncher.java
index ecb8ff2..4fab268 100644
--- a/G-Earth/src/main/java/gearth/extensions/InternalExtensionFormLauncher.java
+++ b/G-Earth/src/main/java/gearth/extensions/InternalExtensionFormLauncher.java
@@ -55,7 +55,7 @@ public class InternalExtensionFormLauncher {
- primaryStage.getScene().getRoot().getStyleClass().add(defaultTheme.title().replace(" ", "-").toLowerCase());
- primaryStage.getScene().getRoot().getStyleClass().add(defaultTheme.isDark() ? "g-dark" : "g-light");
- });
+ Platform.runLater(() -> primaryStage.getScene().getRoot().getStyleClass().addAll(
+ defaultTheme.title().replace(" ", "-").toLowerCase(),
+ defaultTheme.isDark() ? "g-dark" : "g-light"
+ ));
- ExtensionForm extensionForm = loader.getController();
- extensionForm.fieldsInitialized.addListener(() -> extensionForm.extension.observableHostInfo.addListener(hostInfo -> {
- if (hostInfo.getAttributes().containsKey("theme")) {
- String themeTitle = hostInfo.getAttributes().get("theme");
- Theme theme = ThemeFactory.themeForTitle(themeTitle);
+ final ExtensionForm extensionForm = loader.getController();
+ extensionForm
+ .fieldsInitialisedProperty()
+ .addListener(observable -> listenForThemeChange(primaryStage, config, extensionForm));
+ return extensionForm;
+ }
+
+ private static void listenForThemeChange(Stage primaryStage, DefaultTitleBarConfig config, ExtensionForm extensionForm) {
+ extensionForm.extension.hostInfoProperty.addListener((observable, oldValue, newValue) -> {
+ final String themeTitle = newValue.getAttributes().get("theme");
+ if (themeTitle != null) {
+ final Theme theme = ThemeFactory.themeForTitle(themeTitle);
if (config.getCurrentTheme() != theme) {
- String styleClassOld = config.getCurrentTheme().title().replace(" ", "-").toLowerCase();
- String lightClassOld = config.getCurrentTheme().isDark() ? "g-dark" : "g-light";
- String styleClassNew = theme.title().replace(" ", "-").toLowerCase();
- String lightClassNew = theme.isDark() ? "g-dark" : "g-light";
+ final String styleClassOld = config.getCurrentTheme().title().replace(" ", "-").toLowerCase();
+ final String lightClassOld = config.getCurrentTheme().isDark() ? "g-dark" : "g-light";
+ final String styleClassNew = theme.title().replace(" ", "-").toLowerCase();
+ final String lightClassNew = theme.isDark() ? "g-dark" : "g-light";
config.setTheme(theme);
- Parent currentRoot = primaryStage.getScene().getRoot();
+ final Parent currentRoot = primaryStage.getScene().getRoot();
Platform.runLater(() -> {
currentRoot.getStyleClass().remove(styleClassOld);
currentRoot.getStyleClass().add(styleClassNew);
@@ -62,13 +69,11 @@ public abstract class ThemedExtensionFormCreator extends ExtensionFormCreator {
});
}
}
- }));
-
-
- return extensionForm;
+ });
}
protected abstract String getTitle();
+
protected abstract URL getFormResource();
// can be overridden for more settings
diff --git a/G-Earth/src/main/java/gearth/misc/BindingsUtil.java b/G-Earth/src/main/java/gearth/misc/BindingsUtil.java
new file mode 100644
index 0000000..e87f893
--- /dev/null
+++ b/G-Earth/src/main/java/gearth/misc/BindingsUtil.java
@@ -0,0 +1,62 @@
+package gearth.misc;
+
+import javafx.beans.binding.ObjectBinding;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.Property;
+import javafx.beans.property.StringProperty;
+import javafx.collections.ObservableList;
+import javafx.util.StringConverter;
+
+/**
+ * Provides utility methods for bindings.
+ *
+ * @author Dorving
+ */
+public final class BindingsUtil {
+
+ /**
+ * Ensures the list always contains the value of the binding.
+ */
+ public static void addAndBindContent(ObservableList list, ObjectBinding binding) {
+ binding.addListener((observable, oldValue, newValue) -> {
+ list.remove(oldValue);
+ list.add(newValue);
+ });
+ list.add(binding.get());
+ }
+
+ /**
+ * Sets the value of a property and binds it bidirectionally to another property.
+ */
+ public static void setAndBindBiDirectional(Property a, Property b) {
+ a.setValue(b.getValue());
+ a.bindBidirectional(b);
+ }
+
+ /**
+ * Sets the value of a string property and binds it bidirectionally to another property using a converter.
+ */
+ public static void setAndBindBiDirectional(StringProperty a, Property b, StringConverter converter) {
+ a.setValue(converter.toString(b.getValue()));
+ a.bindBidirectional(b, converter);
+ }
+
+ /**
+ * Sets the value of a string property and binds it bidirectionally to an integer property.
+ */
+ public static void setAndBindBiDirectional(StringProperty a, IntegerProperty b) {
+ setAndBindBiDirectional(a, b, STRING_INT_CONVERTER);
+ }
+
+ private static final StringConverter STRING_INT_CONVERTER = new StringConverter() {
+ @Override
+ public String toString(Number object) {
+ return Integer.toString(object.intValue());
+ }
+
+ @Override
+ public Number fromString(String string) {
+ return Integer.parseInt(string);
+ }
+ };
+}
diff --git a/G-Earth/src/main/java/gearth/misc/Cacher.java b/G-Earth/src/main/java/gearth/misc/Cacher.java
index 882c4ab..0b1f699 100644
--- a/G-Earth/src/main/java/gearth/misc/Cacher.java
+++ b/G-Earth/src/main/java/gearth/misc/Cacher.java
@@ -1,6 +1,10 @@
package gearth.misc;
import gearth.GEarth;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.Property;
+import javafx.beans.property.StringProperty;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -10,6 +14,8 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Created by Jonas on 28/09/18.
@@ -130,4 +136,36 @@ public class Cacher {
public static void clear() {
clear(DEFAULT_CACHE_FILENAME);
}
+
+ public static > void ifEnumPresent(String key, Class enumClass, Consumer consumer) {
+ if (getCacheContents().has(key)) {
+ final E value = getCacheContents().getEnum(enumClass, key);
+ consumer.accept(value);
+ }
+ }
+ public static > void bindEnum(String key, Class enumClass, ObjectProperty valueProperty) {
+ if (getCacheContents().has(key)) {
+ final E value = getCacheContents().getEnum(enumClass, key);
+ valueProperty.set(value);
+ }
+ valueProperty.addListener((observable, oldValue, newValue) -> put(key, newValue));
+ }
+
+ public static void bindString(String key, StringProperty valueProperty) {
+ bind(key, valueProperty, getCacheContents()::getString);
+ }
+ public static void bindNumber(String key, Property valueProperty) {
+ bind(key, valueProperty, getCacheContents()::getNumber);
+ }
+ public static void bindBoolean(String key, BooleanProperty valueProperty) {
+ bind(key, valueProperty, getCacheContents()::getBoolean);
+ }
+ public static void bindJSONObject(String key, ObjectProperty valueProperty) {
+ bind(key, valueProperty, getCacheContents()::getJSONObject);
+ }
+ private static void bind(String key, Property valueProperty, Function reader) {
+ if (getCacheContents().has(key))
+ valueProperty.setValue(reader.apply(key));
+ valueProperty.addListener((observable, oldValue, newValue) -> put(key, newValue));
+ }
}
diff --git a/G-Earth/src/main/java/gearth/misc/listenerpattern/ObservableObject.java b/G-Earth/src/main/java/gearth/misc/listenerpattern/ObservableObject.java
deleted file mode 100644
index 4fd62de..0000000
--- a/G-Earth/src/main/java/gearth/misc/listenerpattern/ObservableObject.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package gearth.misc.listenerpattern;
-
-import java.util.function.Consumer;
-
-public class ObservableObject extends Observable> {
-
- private T object;
-
- public ObservableObject(T object) {
- super();
- this.object = object;
- }
-
- public void setObject(T object) {
- this.object = object;
- fireEvent(c -> c.accept(object));
- }
-
- public T getObject() {
- return object;
- }
-}
diff --git a/G-Earth/src/main/java/gearth/protocol/HConnection.java b/G-Earth/src/main/java/gearth/protocol/HConnection.java
index 495481f..854800e 100644
--- a/G-Earth/src/main/java/gearth/protocol/HConnection.java
+++ b/G-Earth/src/main/java/gearth/protocol/HConnection.java
@@ -13,29 +13,29 @@ import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.flash.unix.LinuxRawIpFlashProxyProvider;
import gearth.protocol.connection.proxy.unity.UnityProxyProvider;
import gearth.services.extension_handler.ExtensionHandler;
+import gearth.ui.GEarthProperties;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
import java.io.IOException;
import java.util.function.Consumer;
public class HConnection {
- public static volatile boolean DECRYPTPACKETS = true;
- public static volatile boolean DEBUG = false;
-
private volatile ExtensionHandler extensionHandler = null;
private volatile Object[] trafficObservables = {new Observable(), new Observable(), new Observable()};
- private volatile Observable stateObservable = new Observable<>();
- private volatile Observable> developerModeChangeObservable = new Observable<>();
- private volatile HState state = HState.NOT_CONNECTED;
+ @Deprecated
+ private volatile Observable stateObservable = new Observable<>();
+
+ private final ObjectProperty stateProperty = new SimpleObjectProperty<>(HState.NOT_CONNECTED);
+
private volatile HProxy proxy = null;
private ProxyProviderFactory proxyProviderFactory;
private ProxyProvider proxyProvider = null;
- private volatile boolean developerMode = false;
-
public HConnection() {
HConnection selff = this;
proxyProviderFactory = new ProxyProviderFactory(
@@ -47,16 +47,16 @@ public class HConnection {
PacketSafetyManager.PACKET_SAFETY_MANAGER.initialize(this);
}
+ public ObjectProperty stateProperty() {
+ return stateProperty;
+ }
+
public HState getState() {
- return state;
+ return stateProperty.get();
}
private void setState(HState state) {
- if (state != this.state) {
- HState buffer = this.state;
- this.state = state;
- stateObservable.fireEvent(l -> l.stateChanged(buffer, state));
- }
+ stateProperty.set(state);
}
// autodetect mode
@@ -107,6 +107,7 @@ public class HConnection {
}
}
+ @Deprecated
public Observable getStateObservable() {
return stateObservable;
}
@@ -165,11 +166,12 @@ public class HConnection {
}
public boolean canSendPacket(HMessage.Direction direction, HPacket packet) {
- return isPacketSendingAllowed(direction, packet) && (developerMode || isPacketSendingSafe(direction, packet));
+ return isPacketSendingAllowed(direction, packet)
+ && (GEarthProperties.isDeveloperModeEnabled() || isPacketSendingSafe(direction, packet));
}
public boolean isPacketSendingAllowed(HMessage.Direction direction, HPacket packet) {
- if (state != HState.CONNECTED) return false;
+ if (getState() != HState.CONNECTED) return false;
HProxy proxy = this.proxy;
if (proxy == null) return false;
@@ -196,14 +198,6 @@ public class HConnection {
return packetsContainer.isPacketSafe(packet.headerId(), direction);
}
- public void setDeveloperMode(boolean developerMode) {
- this.developerMode = developerMode;
- developerModeChangeObservable.fireEvent(listener -> listener.accept(developerMode));
- }
-
- public void onDeveloperModeChange(Consumer onChange) {
- developerModeChangeObservable.addListener(onChange);
- }
public String getClientHost() {
if (proxy == null) {
diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java
index 6df5f7a..03e3af9 100644
--- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java
+++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/FlashProxyProvider.java
@@ -10,15 +10,14 @@ import gearth.protocol.memory.Rc4Obtainer;
import gearth.protocol.packethandler.flash.IncomingFlashPacketHandler;
import gearth.protocol.packethandler.flash.OutgoingFlashPacketHandler;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
+import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
-import javafx.scene.image.Image;
import javafx.scene.layout.Region;
-import javafx.stage.Stage;
import java.io.IOException;
import java.net.Socket;
@@ -47,7 +46,7 @@ public abstract class FlashProxyProvider implements ProxyProvider {
client.setSoTimeout(0);
server.setSoTimeout(0);
- if (HConnection.DEBUG) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println(server.getLocalAddress().getHostAddress() + ": " + server.getLocalPort());
Rc4Obtainer rc4Obtainer = new Rc4Obtainer(hConnection);
OutgoingFlashPacketHandler outgoingHandler = new OutgoingFlashPacketHandler(server.getOutputStream(), hConnection.getTrafficObservables(), hConnection.getExtensionHandler());
@@ -73,7 +72,7 @@ public abstract class FlashProxyProvider implements ProxyProvider {
try {
if (!server.isClosed()) server.close();
if (!client.isClosed()) client.close();
- if (HConnection.DEBUG) System.out.println("STOP");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("STOP");
if (datastream[0]) {
onConnectEnd();
};
diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/NormalFlashProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/NormalFlashProxyProvider.java
index 49b4c6e..b04b9f3 100644
--- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/NormalFlashProxyProvider.java
+++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/NormalFlashProxyProvider.java
@@ -1,6 +1,5 @@
package gearth.protocol.connection.proxy.flash;
-import gearth.GEarth;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.connection.*;
@@ -10,12 +9,11 @@ import gearth.protocol.hostreplacer.hostsfile.HostReplacer;
import gearth.protocol.hostreplacer.hostsfile.HostReplacerFactory;
import gearth.protocol.portchecker.PortChecker;
import gearth.protocol.portchecker.PortCheckerFactory;
+import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
-import javafx.scene.image.Image;
-import javafx.stage.Stage;
import java.io.IOException;
import java.net.*;
@@ -128,7 +126,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
Socket client = proxy_server.accept();
proxy = potentialProxy;
closeAllProxies(proxy);
- if (HConnection.DEBUG) System.out.println("accepted a proxy");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("accepted a proxy");
new Thread(() -> {
try {
@@ -173,7 +171,7 @@ public class NormalFlashProxyProvider extends FlashProxyProvider {
}
- if (HConnection.DEBUG) System.out.println("done waiting for clients with: " + hConnection.getState() );
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("done waiting for clients with: " + hConnection.getState() );
}
diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/unix/LinuxRawIpFlashProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/unix/LinuxRawIpFlashProxyProvider.java
index 3b31f78..4d1df09 100644
--- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/unix/LinuxRawIpFlashProxyProvider.java
+++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/flash/unix/LinuxRawIpFlashProxyProvider.java
@@ -7,6 +7,7 @@ import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.protocol.hostreplacer.ipmapping.IpMapper;
import gearth.protocol.hostreplacer.ipmapping.IpMapperFactory;
+import gearth.ui.GEarthProperties;
import java.io.IOException;
import java.net.*;
@@ -54,7 +55,7 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
maybeAddMapping();
- if (HConnection.DEBUG) System.out.println("Added mapping for raw IP");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("Added mapping for raw IP");
ServerSocket proxy_server = new ServerSocket(proxy.getIntercept_port(), 10, InetAddress.getByName(proxy.getIntercept_host()));
proxy.initProxy(proxy_server);
@@ -62,10 +63,10 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
stateSetter.setState(HState.WAITING_FOR_CLIENT);
while ((hConnection.getState() == HState.WAITING_FOR_CLIENT) && !proxy_server.isClosed()) {
try {
- if (HConnection.DEBUG) System.out.println("try accept proxy");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("try accept proxy");
Socket client = proxy_server.accept();
- if (HConnection.DEBUG) System.out.println("accepted a proxy");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("accepted a proxy");
new Thread(() -> {
try {
@@ -151,7 +152,7 @@ public class LinuxRawIpFlashProxyProvider extends FlashProxyProvider {
createSocksProxyThread(client);
}
else if (preConnectedServerConnections.isEmpty()) {
- if (HConnection.DEBUG) System.out.println("pre-made server connections ran out of stock");
+ if (GEarthProperties.isDebugModeEnabled()) System.out.println("pre-made server connections ran out of stock");
}
else {
startProxyThread(client, preConnectedServerConnections.poll(), proxy);
diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/nitro/NitroProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/nitro/NitroProxyProvider.java
index b86a4fc..50b7d8d 100644
--- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/nitro/NitroProxyProvider.java
+++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/nitro/NitroProxyProvider.java
@@ -9,6 +9,8 @@ import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.protocol.connection.proxy.nitro.http.NitroHttpProxy;
import gearth.protocol.connection.proxy.nitro.http.NitroHttpProxyServerCallback;
import gearth.protocol.connection.proxy.nitro.websocket.NitroWebsocketProxy;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -16,7 +18,7 @@ import java.io.IOException;
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicBoolean;
-public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCallback, StateChangeListener {
+public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCallback, ChangeListener {
private static final Logger logger = LoggerFactory.getLogger(NitroProxyProvider.class);
@@ -53,7 +55,7 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
originalWebsocketUrl = null;
originalCookies = null;
- connection.getStateObservable().addListener(this);
+ connection.stateProperty().addListener(this);
logger.info("Starting http proxy");
@@ -112,7 +114,7 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
stateSetter.setState(HState.NOT_CONNECTED);
- connection.getStateObservable().removeListener(this);
+ connection.stateProperty().removeListener(this);
logger.info("Nitro proxy stopped");
}).start();
@@ -131,16 +133,15 @@ public class NitroProxyProvider implements ProxyProvider, NitroHttpProxyServerCa
}
@Override
- public void stateChanged(HState oldState, HState newState) {
- if (oldState == HState.WAITING_FOR_CLIENT && newState == HState.CONNECTED) {
+ public void changed(ObservableValue extends HState> observable, HState oldValue, HState newValue) {
+ if (oldValue == HState.WAITING_FOR_CLIENT && newValue == HState.CONNECTED) {
// Unregister but do not stop http proxy.
// We are not stopping the http proxy because some requests might still require it to be running.
nitroHttpProxy.pause();
}
// Catch setState ABORTING inside NitroWebsocketClient.
- if (newState == HState.ABORTING) {
+ if (newValue == HState.ABORTING)
abort();
- }
}
}
diff --git a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java
index 58308db..29ecd40 100644
--- a/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java
+++ b/G-Earth/src/main/java/gearth/protocol/connection/proxy/unity/UnityProxyProvider.java
@@ -1,18 +1,21 @@
package gearth.protocol.connection.proxy.unity;
import gearth.protocol.HConnection;
-import gearth.protocol.StateChangeListener;
import gearth.protocol.connection.HProxySetter;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.HStateSetter;
import gearth.protocol.connection.proxy.ProxyProvider;
import gearth.services.unity_tools.GUnityFileServer;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
@@ -22,6 +25,9 @@ import static gearth.services.unity_tools.GUnityFileServer.FILESERVER_PORT;
public class UnityProxyProvider implements ProxyProvider {
+ private final static Logger LOGGER = LoggerFactory.getLogger(UnityProxyProvider.class);
+
+ public static final int PORT_REQUESTER_SERVER_PORT = 9039;
private final HProxySetter proxySetter;
private final HStateSetter stateSetter;
private final HConnection hConnection;
@@ -34,7 +40,6 @@ public class UnityProxyProvider implements ProxyProvider {
this.hConnection = hConnection;
}
-
@Override
public void start() throws IOException {
// https://happyhyppo.ro/2016/03/21/minimal-websockets-communication-with-javajetty-and-angularjs/
@@ -45,13 +50,13 @@ public class UnityProxyProvider implements ProxyProvider {
while (fail && port < 9100) {
try {
packetHandlerServer = new Server(port);
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
- HandlerList handlers = new HandlerList();
+ final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
- ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
+ final ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(UnityCommunicator.class, "/packethandler") // the endpoint url
.configurator(new UnityCommunicatorConfig(proxySetter, stateSetter, hConnection, this))
@@ -65,10 +70,8 @@ public class UnityProxyProvider implements ProxyProvider {
}
}
- if (fail) {
+ if (fail)
throw new Exception();
- }
-
startPortRequestServer(port);
startUnityFileServer();
@@ -79,17 +82,16 @@ public class UnityProxyProvider implements ProxyProvider {
try {
packetHandlerServer.stop();
} catch (Exception ex) {
- ex.printStackTrace();
+ LOGGER.error("Failed to close packet handler server", ex);
}
- e.printStackTrace();
+ LOGGER.error("Failed to connect to unity proxy", e);
}
}
@Override
public synchronized void abort() {
- if (packetHandlerServer == null) {
+ if (packetHandlerServer == null)
return;
- }
final Server abortThis = packetHandlerServer;
stateSetter.setState(HState.ABORTING);
@@ -97,7 +99,7 @@ public class UnityProxyProvider implements ProxyProvider {
try {
abortThis.stop();
} catch (Exception e) {
- e.printStackTrace();
+ LOGGER.error("Failed to abort", e);
} finally {
stateSetter.setState(HState.NOT_CONNECTED);
}
@@ -106,43 +108,30 @@ public class UnityProxyProvider implements ProxyProvider {
}
private void startUnityFileServer() throws Exception {
- Server server = new Server(FILESERVER_PORT);
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ final Server server = new Server(FILESERVER_PORT);
+ final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
-
context.addServlet(new ServletHolder(new GUnityFileServer()), "/*");
- HandlerList handlers = new HandlerList();
+ final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
server.setHandler(handlers);
server.start();
- StateChangeListener fileServerCloser = new StateChangeListener() {
- @Override
- public void stateChanged(HState oldState, HState newState) {
- if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
- hConnection.getStateObservable().removeListener(this);
- try {
- server.stop();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- };
- hConnection.getStateObservable().addListener(fileServerCloser);
+
+ stopServerOnDisconnect(server);
}
private void startPortRequestServer(int packetHandlerPort) throws Exception {
- Server portRequestServer = new Server(9039);
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ final Server portRequestServer = new Server(PORT_REQUESTER_SERVER_PORT);
+ final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/ws");
- HandlerList handlers = new HandlerList();
+ final HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context });
portRequestServer.setHandler(handlers);
- ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
+ final ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder
.create(PortRequester.class, "/portrequest") // the endpoint url
.configurator(new PortRequesterConfig(packetHandlerPort))
@@ -150,19 +139,22 @@ public class UnityProxyProvider implements ProxyProvider {
portRequestServer.start();
- StateChangeListener portRequesterCloser = new StateChangeListener() {
+ stopServerOnDisconnect(portRequestServer);
+ }
+
+ private void stopServerOnDisconnect(Server server) {
+ hConnection.stateProperty().addListener(new ChangeListener() {
@Override
- public void stateChanged(HState oldState, HState newState) {
- if (oldState == HState.WAITING_FOR_CLIENT || newState == HState.NOT_CONNECTED) {
- hConnection.getStateObservable().removeListener(this);
+ public void changed(ObservableValue extends HState> observable, HState oldValue, HState newValue) {
+ if (oldValue == HState.WAITING_FOR_CLIENT || newValue == HState.NOT_CONNECTED) {
+ hConnection.stateProperty().removeListener(this);
try {
- portRequestServer.stop();
+ server.stop();
} catch (Exception e) {
- e.printStackTrace();
+ LOGGER.error("Failed to stop server {}", server, e);
}
}
}
- };
- hConnection.getStateObservable().addListener(portRequesterCloser);
+ });
}
}
diff --git a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java
index 616354c..86689de 100644
--- a/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java
+++ b/G-Earth/src/main/java/gearth/protocol/memory/Rc4Obtainer.java
@@ -7,11 +7,13 @@ import gearth.protocol.crypto.RC4;
import gearth.protocol.memory.habboclient.HabboClient;
import gearth.protocol.memory.habboclient.HabboClientFactory;
import gearth.protocol.packethandler.PayloadBuffer;
-import gearth.protocol.packethandler.flash.BufferChangeListener;
import gearth.protocol.packethandler.flash.FlashPacketHandler;
+import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import javafx.application.Platform;
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
@@ -37,21 +39,22 @@ public class Rc4Obtainer {
public void setFlashPacketHandlers(FlashPacketHandler... flashPacketHandlers) {
this.flashPacketHandlers = Arrays.asList(flashPacketHandlers);
for (FlashPacketHandler handler : flashPacketHandlers) {
- BufferChangeListener bufferChangeListener = new BufferChangeListener() {
+ final InvalidationListener bufferChangeListener = new InvalidationListener() {
@Override
- public void act() {
+ public void invalidated(Observable observable) {
if (handler.isEncryptedStream()) {
- onSendFirstEncryptedMessage(handler);
- handler.getBufferChangeObservable().removeListener(this);
+ Rc4Obtainer.this.onSendFirstEncryptedMessage(handler);
+ handler.incomingBufferProperty().removeListener(this);
}
}
};
- handler.getBufferChangeObservable().addListener(bufferChangeListener);
+ handler.incomingBufferProperty().addListener(bufferChangeListener);
}
}
private void onSendFirstEncryptedMessage(FlashPacketHandler flashPacketHandler) {
- if (!HConnection.DECRYPTPACKETS) return;
+ if (GEarthProperties.isPacketDecryptionDisabled())
+ return;
flashPacketHandlers.forEach(FlashPacketHandler::block);
diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java
deleted file mode 100644
index e39d6e7..0000000
--- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/BufferChangeListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package gearth.protocol.packethandler.flash;
-
-
-public interface BufferChangeListener {
-
- void act();
-
-}
diff --git a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java
index 98b7ffe..921d54c 100644
--- a/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java
+++ b/G-Earth/src/main/java/gearth/protocol/packethandler/flash/FlashPacketHandler.java
@@ -1,13 +1,14 @@
package gearth.protocol.packethandler.flash;
-import gearth.misc.listenerpattern.Observable;
-import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
import gearth.protocol.crypto.RC4;
import gearth.protocol.packethandler.PacketHandler;
import gearth.protocol.packethandler.PayloadBuffer;
import gearth.services.extension_handler.ExtensionHandler;
+import gearth.ui.GEarthProperties;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
import java.io.IOException;
import java.io.OutputStream;
@@ -18,7 +19,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
protected static final boolean DEBUG = false;
- private volatile OutputStream out;
+ private final OutputStream out;
private volatile boolean isTempBlocked = false;
volatile boolean isDataStream = false;
@@ -36,7 +37,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
FlashPacketHandler(OutputStream outputStream, Object[] trafficObservables, ExtensionHandler extensionHandler) {
super(extensionHandler, trafficObservables);
out = outputStream;
- this.payloadBuffer = new PayloadBuffer();
+ payloadBuffer = new PayloadBuffer();
}
public boolean isDataStream() {return isDataStream;}
@@ -49,6 +50,7 @@ public abstract class FlashPacketHandler extends PacketHandler {
}
public void act(byte[] buffer) throws IOException {
+
if (!isDataStream) {
synchronized (sendLock) {
out.write(buffer);
@@ -56,20 +58,19 @@ public abstract class FlashPacketHandler extends PacketHandler {
return;
}
- bufferChangeObservable.fireEvent();
+ incomingBufferProperty.set(buffer);
if (!isEncryptedStream) {
payloadBuffer.push(buffer);
}
- else if (!HConnection.DECRYPTPACKETS) {
+ else if (GEarthProperties.isPacketDecryptionDisabled()) {
synchronized (sendLock) {
out.write(buffer);
}
}
else if (decryptcipher == null) {
- for (int i = 0; i < buffer.length; i++) {
- tempEncryptedBuffer.add(buffer[i]);
- }
+ for (byte b : buffer)
+ tempEncryptedBuffer.add(b);
}
else {
byte[] tm = decryptcipher.rc4(buffer);
@@ -162,9 +163,10 @@ public abstract class FlashPacketHandler extends PacketHandler {
protected abstract void printForDebugging(byte[] bytes);
- private Observable bufferChangeObservable = new Observable<>(BufferChangeListener::act);
- public Observable getBufferChangeObservable() {
- return bufferChangeObservable;
+ private final ObjectProperty incomingBufferProperty = new SimpleObjectProperty<>();
+
+ public ObjectProperty incomingBufferProperty() {
+ return incomingBufferProperty;
}
public int getCurrentIndex() {
diff --git a/G-Earth/src/main/java/gearth/services/extension_handler/ExtensionHandler.java b/G-Earth/src/main/java/gearth/services/extension_handler/ExtensionHandler.java
index 87a57d8..1df5eda 100644
--- a/G-Earth/src/main/java/gearth/services/extension_handler/ExtensionHandler.java
+++ b/G-Earth/src/main/java/gearth/services/extension_handler/ExtensionHandler.java
@@ -1,7 +1,6 @@
package gearth.services.extension_handler;
import gearth.GEarth;
-import gearth.misc.HostInfo;
import gearth.misc.listenerpattern.Observable;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
@@ -12,14 +11,15 @@ import gearth.services.extension_handler.extensions.GEarthExtension;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducer;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerFactory;
import gearth.services.extension_handler.extensions.extensionproducers.ExtensionProducerObserver;
-import gearth.ui.themes.Theme;
+import gearth.ui.GEarthProperties;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
import javafx.util.Pair;
import java.io.IOException;
import java.util.*;
-import java.util.function.Consumer;
-public class ExtensionHandler {
+public class ExtensionHandler implements ChangeListener {
private final List gEarthExtensions = new ArrayList<>();
private final HConnection hConnection;
@@ -47,38 +47,13 @@ public class ExtensionHandler {
}
private void initialize() {
- GEarth.getThemeObservable().addListener(theme -> {
+ GEarthProperties.hostInfoBinding.addListener(((observable1, oldValue, newValue) -> {
synchronized (gEarthExtensions) {
- for (GEarthExtension extension : gEarthExtensions) {
- extension.updateHostInfo(getHostInfo());
- }
+ gEarthExtensions.forEach(extension -> extension.updateHostInfo(newValue));
}
- });
-
- hConnection.getStateObservable().addListener((oldState, newState) -> {
- if (newState == HState.CONNECTED) {
- synchronized (gEarthExtensions) {
- for (GEarthExtension extension : gEarthExtensions) {
- extension.connectionStart(
- hConnection.getDomain(),
- hConnection.getServerPort(),
- hConnection.getHotelVersion(),
- hConnection.getClientIdentifier(),
- hConnection.getClientType(),
- hConnection.getPacketInfoManager()
- );
- }
- }
- }
- if (oldState == HState.CONNECTED) {
- synchronized (gEarthExtensions) {
- for (GEarthExtension extension : gEarthExtensions) {
- extension.connectionEnd();
- }
- }
- }
- });
+ }));
+ hConnection.stateProperty().addListener(this);
extensionProducers = ExtensionProducerFactory.getAll();
extensionProducers.forEach(extensionProducer -> extensionProducer.startProducing(createExtensionProducerObserver()));
}
@@ -259,7 +234,7 @@ public class ExtensionHandler {
extension.getClickedObservable().addListener(extension::doubleclick);
observable.fireEvent(l -> l.onExtensionConnect(extension));
- extension.init(hConnection.getState() == HState.CONNECTED, getHostInfo());
+ extension.init(hConnection.getState() == HState.CONNECTED, GEarthProperties.getHostInfo());
if (hConnection.getState() == HState.CONNECTED) {
extension.connectionStart(
hConnection.getDomain(),
@@ -274,16 +249,6 @@ public class ExtensionHandler {
};
}
- private HostInfo getHostInfo() {
- HashMap attributes = new HashMap<>();
- attributes.put("theme", GEarth.getTheme().title());
- return new HostInfo(
- "G-Earth",
- GEarth.version,
- attributes
- );
- }
-
public List getExtensionProducers() {
return extensionProducers;
}
@@ -296,5 +261,26 @@ public class ExtensionHandler {
extensionProducers.add(producer);
}
-
+ @Override
+ public void changed(ObservableValue extends HState> observable, HState oldValue, HState newValue) {
+ if (newValue == HState.CONNECTED) {
+ synchronized (gEarthExtensions) {
+ for (GEarthExtension extension : gEarthExtensions) {
+ extension.connectionStart(
+ hConnection.getDomain(),
+ hConnection.getServerPort(),
+ hConnection.getHotelVersion(),
+ hConnection.getClientIdentifier(),
+ hConnection.getClientType(),
+ hConnection.getPacketInfoManager()
+ );
+ }
+ }
+ }
+ if (oldValue == HState.CONNECTED) {
+ synchronized (gEarthExtensions) {
+ gEarthExtensions.forEach(GEarthExtension::connectionEnd);
+ }
+ }
+ }
}
diff --git a/G-Earth/src/main/java/gearth/ui/GEarthProperties.java b/G-Earth/src/main/java/gearth/ui/GEarthProperties.java
new file mode 100644
index 0000000..4a5637d
--- /dev/null
+++ b/G-Earth/src/main/java/gearth/ui/GEarthProperties.java
@@ -0,0 +1,228 @@
+package gearth.ui;
+
+import gearth.GEarth;
+import gearth.misc.BindingsUtil;
+import gearth.misc.Cacher;
+import gearth.misc.HostInfo;
+import gearth.protocol.connection.HClient;
+import gearth.ui.themes.Theme;
+import gearth.ui.themes.ThemeFactory;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.ObjectBinding;
+import javafx.beans.binding.StringBinding;
+import javafx.beans.property.*;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.scene.image.Image;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * Handles G-Earth's observable properties.
+ *
+ * @author Dorving
+ */
+public final class GEarthProperties {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GEarthProperties.class);
+
+ public static final ObjectProperty themeProperty = new SimpleObjectProperty<>();
+
+ public static final StringBinding themeTitleBinding;
+
+ public static final ObjectBinding hostInfoBinding;
+
+ public static final ObjectBinding logoImageBinding;
+ public static final ObjectBinding logoSmallImageBinding;
+ public static final ObservableList icons = FXCollections.observableArrayList();
+
+ public static final ObjectBinding styleSheetBinding;
+ public static final ObservableList styleSheets = FXCollections.observableArrayList();
+
+ public static final ObjectProperty clientTypeProperty = new SimpleObjectProperty<>();
+
+ public static final BooleanProperty autoDetectProperty = new SimpleBooleanProperty(false);
+ public static final StringProperty hostProperty = new SimpleStringProperty();
+ public static final IntegerProperty portProperty = new SimpleIntegerProperty();
+
+ public static final BooleanProperty alwaysOnTopProperty = new SimpleBooleanProperty(false);
+ public static final BooleanProperty enableDeveloperModeProperty = new SimpleBooleanProperty(false);
+ public static final BooleanProperty enableDebugProperty = new SimpleBooleanProperty(false);
+ public static final BooleanProperty disablePacketDecryptionProperty = new SimpleBooleanProperty(false);
+ public static final BooleanProperty enableSocksProperty = new SimpleBooleanProperty(false);
+ public static final StringProperty socksHostProperty = new SimpleStringProperty();
+ public static final IntegerProperty socksPortProperty = new SimpleIntegerProperty();
+ public static final BooleanProperty enableGPythonProperty = new SimpleBooleanProperty(false);
+ public static final BooleanProperty alwaysAdminProperty = new SimpleBooleanProperty(false);
+ public static final StringProperty notesProperty = new SimpleStringProperty();
+
+ static {
+ themeProperty.addListener((observable, oldValue, newValue) -> Cacher.put("theme", newValue.title()));
+ final Theme value = Cacher.getCacheContents().has("theme") ?
+ ThemeFactory.themeForTitle(Cacher.getCacheContents().getString("theme")) :
+ ThemeFactory.getDefaultTheme();
+
+ LOGGER.debug("Loading theme {}", value);
+
+ themeProperty.set(Objects.requireNonNull(value, "Unable to load theme"));
+
+ styleSheetBinding = createThemeStylesheetBinding();
+ logoSmallImageBinding = createThemeImageBinding("logoSmall.png");
+ logoImageBinding = createThemeImageBinding("logo.png");
+ hostInfoBinding = createThemeHostInfoBinding();
+ themeTitleBinding = createThemeTitleBinding();
+
+ BindingsUtil.addAndBindContent(icons, logoSmallImageBinding);
+ BindingsUtil.addAndBindContent(styleSheets, styleSheetBinding);
+
+ Cacher.bindEnum("last_client_mode", HClient.class, clientTypeProperty);
+ Cacher.bindBoolean("auto_detect", autoDetectProperty);
+ Cacher.bindString("host", hostProperty);
+ Cacher.bindNumber("port", portProperty);
+ convertOldConnectionSettingsIfPresent();
+
+ Cacher.bindBoolean("always_on_top", alwaysOnTopProperty);
+ Cacher.bindBoolean("always_admin", alwaysAdminProperty);
+ Cacher.bindBoolean("develop_mode", enableDeveloperModeProperty);
+ Cacher.bindBoolean("debug_mode_enabled", enableDebugProperty);
+ Cacher.bindBoolean("packet_decryption_disabled", disablePacketDecryptionProperty);
+ Cacher.bindBoolean("socks_enabled", enableSocksProperty);
+ Cacher.bindString("socks_host", socksHostProperty);
+ Cacher.bindNumber("socks_port", socksPortProperty);
+ Cacher.bindBoolean("use_gpython", enableGPythonProperty);
+ Cacher.bindString("notepad_text", notesProperty);
+ }
+
+ public static Theme getTheme() {
+ return themeProperty.get();
+ }
+
+ public static String getThemeTitle() {
+ return themeTitleBinding.get();
+ }
+
+ public static HostInfo getHostInfo() {
+ return hostInfoBinding.get();
+ }
+
+ public static Image getLogoImage() {
+ return logoImageBinding.get();
+ }
+
+ public static Image getLogoSmallImage() {
+ return logoSmallImageBinding.get();
+ }
+
+ public static String getStyleSheet() {
+ return styleSheetBinding.get();
+ }
+
+ public static HClient getClientType() {
+ return clientTypeProperty.get();
+ }
+
+ public static boolean isPacketDecryptionDisabled() {
+ return disablePacketDecryptionProperty.get();
+ }
+
+ public static boolean isDebugModeEnabled() {
+ return enableDebugProperty.get();
+ }
+
+ public static boolean isDeveloperModeEnabled() {
+ return enableDeveloperModeProperty.get();
+ }
+
+ public static boolean isAlwaysOnTop() {
+ return alwaysOnTopProperty.get();
+ }
+
+ public static String getSocksHost() {
+ return socksHostProperty.get();
+ }
+
+ public static int getSocksPort() {
+ return socksPortProperty.get();
+ }
+
+ private static StringBinding createThemeTitleBinding() {
+ return Bindings.createStringBinding(() -> {
+ final Theme theme = getTheme();
+ return theme.overridesTitle() ? theme.title() : ThemeFactory.getDefaultTheme().title();
+ }, themeProperty);
+ }
+
+ private static ObjectBinding createThemeHostInfoBinding() {
+ return Bindings.createObjectBinding(() -> new HostInfo(
+ "G-Earth",
+ GEarth.version,
+ new HashMap<>(Collections.singletonMap("theme", getTheme().title()))
+ ), themeProperty);
+ }
+
+ private static ObjectBinding createThemeStylesheetBinding() {
+ return Bindings.createObjectBinding(() -> {
+ final String pathToStyleSheet = getThemeRelativePath("styling.css");
+ final URL styleSheetInput = GEarth.class.getResource(pathToStyleSheet);
+ if (styleSheetInput == null) {
+ LOGGER.error("Could not load style sheet `{}`, input-stream is null for {}", "styling.css", pathToStyleSheet);
+ return null;
+ }
+ return styleSheetInput.toExternalForm();
+ }, themeProperty);
+ }
+
+ private static ObjectBinding createThemeImageBinding(String imageName) {
+ return Bindings.createObjectBinding(() -> {
+ final Theme theme = getTheme();
+ final String pathToLogo = getThemeRelativePath(theme.overridesLogo()
+ ? theme
+ : ThemeFactory.getDefaultTheme(), imageName);
+ try (final InputStream imageInput = GEarth.class.getResourceAsStream(pathToLogo)) {
+ if (imageInput == null) {
+ LOGGER.error("Could not load image `{}`, input-stream is null for {}", imageName, pathToLogo);
+ return null;
+ }
+ return new Image(imageInput);
+ } catch (Exception e) {
+ LOGGER.error("Failed to load image `{}", imageName, e);
+ return null;
+ }
+ }, themeProperty);
+ }
+
+ private static String getThemeRelativePath(String fileName) {
+ return getThemeRelativePath(getTheme(), fileName);
+ }
+
+ private static String getThemeRelativePath(Theme theme, String fileName) {
+ return String.format("/gearth/ui/themes/%s/" + fileName, theme.internalName());
+ }
+
+ private static final String KEY_LAST_CONNECTION_SETTINGS = "last_connection_settings";
+ private static final String KEY_AUTODETECT = "auto_detect";
+ private static final String KEY_HOST = "host";
+ private static final String KEY_PORT = "port";
+
+ private static void convertOldConnectionSettingsIfPresent() {
+ /*
+ BACKWARDS COMPATABILITY
+ */
+ if (Cacher.getCacheContents().has(KEY_LAST_CONNECTION_SETTINGS)) {
+ final JSONObject jsonObject = Cacher.getCacheContents().getJSONObject(KEY_LAST_CONNECTION_SETTINGS);
+ if (jsonObject != null) {
+ autoDetectProperty.set(jsonObject.getBoolean(KEY_AUTODETECT));
+ hostProperty.set(jsonObject.getString(KEY_HOST));
+ portProperty.set(jsonObject.getInt(KEY_PORT));
+ Cacher.getCacheContents().remove(KEY_LAST_CONNECTION_SETTINGS);
+ }
+ }
+ }
+}
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java b/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java
index 1a38967..fe6e093 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/connection/ConnectionController.java
@@ -1,19 +1,19 @@
package gearth.ui.subforms.connection;
import gearth.GEarth;
-import gearth.misc.Cacher;
+import gearth.misc.BindingsUtil;
+import gearth.protocol.HConnection;
import gearth.protocol.connection.HClient;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.services.Constants;
+import gearth.ui.GEarthProperties;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
-import gearth.protocol.HConnection;
import gearth.ui.SubForm;
import javafx.scene.layout.GridPane;
-import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
@@ -22,11 +22,6 @@ import java.util.Set;
public class ConnectionController extends SubForm {
- private final String CONNECTION_INFO_CACHE_KEY = "last_connection_settings";
- private final String AUTODETECT_CACHE = "auto_detect";
- private final String HOST_CACHE = "host";
- private final String PORT_CACHE = "port";
-
public ComboBox inpPort;
public ComboBox inpHost;
public Button btnConnect;
@@ -40,7 +35,6 @@ public class ConnectionController extends SubForm {
private volatile int fullyInitialized = 0;
- public static final String CLIENT_CACHE_KEY = "last_client_mode";
public ToggleGroup tgl_clientMode;
public RadioButton rd_unity;
public RadioButton rd_flash;
@@ -59,38 +53,16 @@ public class ConnectionController extends SubForm {
Constants.UNITY_PACKETS = rd_unity.isSelected();
});
- if (Cacher.getCacheContents().has(CLIENT_CACHE_KEY)) {
- switch (Cacher.getCacheContents().getEnum(HClient.class, CLIENT_CACHE_KEY)) {
- case FLASH:
- rd_flash.setSelected(true);
- break;
- case UNITY:
- rd_unity.setSelected(true);
- break;
- case NITRO:
- rd_nitro.setSelected(true);
- break;
- }
- }
+ GEarthProperties.clientTypeProperty
+ .addListener((observable, oldValue, newValue) -> selectClientType(newValue));
+ selectClientType(GEarthProperties.clientTypeProperty.getValue());
+ cbx_autodetect.selectedProperty().addListener(observable -> updateInputUI());
+ inpPort.getEditor().textProperty().addListener(observable -> updateInputUI());
- Object object;
- String hostRemember = null;
- String portRemember = null;
- if ((object = Cacher.get(CONNECTION_INFO_CACHE_KEY)) != null) {
- JSONObject connectionSettings = (JSONObject) object;
- boolean autoDetect = connectionSettings.getBoolean(AUTODETECT_CACHE);
- hostRemember = connectionSettings.getString(HOST_CACHE);
- portRemember = connectionSettings.getInt(PORT_CACHE) + "";
- cbx_autodetect.setSelected(autoDetect);
- }
-
- inpPort.getEditor().textProperty().addListener(observable -> {
- updateInputUI();
- });
- cbx_autodetect.selectedProperty().addListener(observable -> {
- updateInputUI();
- });
+ BindingsUtil.setAndBindBiDirectional(cbx_autodetect.selectedProperty(), GEarthProperties.autoDetectProperty);
+ BindingsUtil.setAndBindBiDirectional(outHost.textProperty(), GEarthProperties.hostProperty);
+ BindingsUtil.setAndBindBiDirectional(outPort.textProperty(), GEarthProperties.portProperty);
List knownHosts = ProxyProviderFactory.autoDetectHosts;
Set hosts = new HashSet<>();
@@ -110,6 +82,8 @@ public class ConnectionController extends SubForm {
int hostSelectIndex = 0;
int portSelectIndex = 0;
+ final String hostRemember = GEarthProperties.hostProperty.get();
+ final String portRemember = Integer.toString(GEarthProperties.portProperty.get());
if (hostRemember != null) {
hostSelectIndex = hostsSorted.indexOf(hostRemember);
portSelectIndex = portsSorted.indexOf(portRemember);
@@ -138,15 +112,31 @@ public class ConnectionController extends SubForm {
initLanguageBinding();
}
+ private void selectClientType(HClient newValue) {
+ switch (newValue) {
+ case FLASH:
+ rd_flash.setSelected(true);
+ break;
+ case UNITY:
+ rd_unity.setSelected(true);
+ break;
+ case NITRO:
+ rd_nitro.setSelected(true);
+ break;
+ }
+ }
private void updateInputUI() {
if (parentController == null) return;
- grd_clientSelection.setDisable(getHConnection().getState() != HState.NOT_CONNECTED);
- txtfield_hotelversion.setText(getHConnection().getHotelVersion());
+ final HConnection hConnection = getHConnection();
+ final HState hConnectionState = hConnection.getState();
- btnConnect.setDisable(getHConnection().getState() == HState.PREPARING || getHConnection().getState() == HState.ABORTING);
+ grd_clientSelection.setDisable(hConnectionState != HState.NOT_CONNECTED);
+ txtfield_hotelversion.setText(hConnection.getHotelVersion());
+
+ btnConnect.setDisable(hConnectionState == HState.PREPARING || hConnectionState == HState.ABORTING);
if (!cbx_autodetect.isSelected() && !btnConnect.isDisable() && useFlash()) {
@@ -159,15 +149,15 @@ public class ConnectionController extends SubForm {
}
}
- inpHost.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
- inpPort.setDisable(getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
+ inpHost.setDisable(hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
+ inpPort.setDisable(hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
cbx_autodetect.setDisable(!useFlash());
outHost.setDisable(!useFlash());
outPort.setDisable(!useFlash());
- inpHost.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
- inpPort.setDisable(!useFlash() || getHConnection().getState() != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
+ inpHost.setDisable(!useFlash() || hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
+ inpPort.setDisable(!useFlash() || hConnectionState != HState.NOT_CONNECTED || cbx_autodetect.isSelected());
}
public void onParentSet(){
@@ -178,37 +168,28 @@ public class ConnectionController extends SubForm {
}
}
- getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(() -> {
+ getHConnection().stateProperty().addListener((observable, oldValue, newValue) -> Platform.runLater(() -> {
updateInputUI();
- if (newState == HState.NOT_CONNECTED) {
+ if (newValue == HState.NOT_CONNECTED) {
state.setKey(0, "tab.connection.state.notconnected");
connect.setKey(0, "tab.connection.button.connect");
outHost.setText("");
outPort.setText("");
}
- else if (oldState == HState.NOT_CONNECTED) {
+ else if (oldValue == HState.NOT_CONNECTED)
connect.setKey(0, "tab.connection.button.abort");
- }
-
- if (newState == HState.CONNECTED) {
+ if (newValue == HState.CONNECTED)
state.setKey(0, "tab.connection.state.connected");
- }
- if (newState == HState.WAITING_FOR_CLIENT) {
+ if (newValue == HState.WAITING_FOR_CLIENT)
state.setKey(0, "tab.connection.state.waiting");
+ if (newValue == HState.CONNECTED && useFlash()) {
+ final String host = getHConnection().getDomain();
+ final int port = getHConnection().getServerPort();
+ outHost.setText(host);
+ outPort.setText(Integer.toString(port));
+ GEarthProperties.hostProperty.set(host);
+ GEarthProperties.portProperty.set(port);
}
-
- if (newState == HState.CONNECTED && useFlash()) {
- outHost.setText(getHConnection().getDomain());
- outPort.setText(getHConnection().getServerPort()+"");
-
- JSONObject connectionSettings = new JSONObject();
- connectionSettings.put(AUTODETECT_CACHE, cbx_autodetect.isSelected());
- connectionSettings.put(HOST_CACHE, inpHost.getEditor().getText());
- connectionSettings.put(PORT_CACHE, Integer.parseInt(inpPort.getEditor().getText()));
-
- Cacher.put(CONNECTION_INFO_CACHE_KEY, connectionSettings);
- }
-
}));
Platform.runLater(this::updateInputUI);
@@ -234,9 +215,11 @@ public class ConnectionController extends SubForm {
String port = GEarth.getArgument("--port");
if (host != null && port != null) {
Platform.runLater(() -> {
- if (!inpHost.getItems().contains(host)) inpHost.getItems().add(host);
+ if (!inpHost.getItems().contains(host))
+ inpHost.getItems().add(host);
inpHost.getSelectionModel().select(host);
- if (!inpPort.getItems().contains(port)) inpPort.getItems().add(port);
+ if (!inpPort.getItems().contains(port))
+ inpPort.getItems().add(port);
inpPort.getSelectionModel().select(port);
cbx_autodetect.setSelected(false);
});
@@ -275,12 +258,9 @@ public class ConnectionController extends SubForm {
} else if (isClientMode(HClient.NITRO)) {
getHConnection().startNitro();
}
-
-
- if (HConnection.DEBUG) System.out.println("connecting");
+ if (GEarthProperties.isDebugModeEnabled())
+ System.out.println("connecting");
}).start();
-
-
}
else {
getHConnection().abort();
@@ -289,13 +269,10 @@ public class ConnectionController extends SubForm {
@Override
protected void onExit() {
- if (rd_flash.isSelected()) {
- Cacher.put(CLIENT_CACHE_KEY, HClient.FLASH);
- } else if (rd_unity.isSelected()) {
- Cacher.put(CLIENT_CACHE_KEY, HClient.UNITY);
- } else if (rd_nitro.isSelected()) {
- Cacher.put(CLIENT_CACHE_KEY, HClient.NITRO);
- }
+ GEarthProperties.clientTypeProperty.set(
+ rd_flash.isSelected() ? HClient.FLASH
+ : rd_unity.isSelected() ? HClient.UNITY
+ : HClient.NITRO);
getHConnection().abort();
}
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java b/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java
index 69b6546..a3774fc 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/extensions/ExtensionsController.java
@@ -8,6 +8,7 @@ import gearth.services.extension_handler.extensions.implementations.network.exec
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunner;
import gearth.services.extension_handler.extensions.implementations.network.executer.ExtensionRunnerFactory;
import gearth.services.g_python.GPythonShell;
+import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.subforms.extensions.logger.ExtensionLogger;
import gearth.ui.translations.LanguageBundle;
@@ -48,6 +49,8 @@ public class ExtensionsController extends SubForm {
scroller.widthProperty().addListener(observable -> header_ext.setPrefWidth(scroller.getWidth()));
extensionLogger = new ExtensionLogger();
+ btn_install.disableProperty().bind(GEarthProperties.enableDeveloperModeProperty.not());
+
initLanguageBinding();
}
@@ -79,8 +82,6 @@ public class ExtensionsController extends SubForm {
extensionLogger.log(text);
}
}));
-
- getHConnection().onDeveloperModeChange(this::setLocalInstallingEnabled);
}
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java b/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java
index 409a36a..1c3d170 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/extra/ExtraController.java
@@ -1,25 +1,25 @@
package gearth.ui.subforms.extra;
import gearth.GEarth;
-import gearth.misc.Cacher;
-import gearth.protocol.HConnection;
+import gearth.misc.BindingsUtil;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.services.always_admin.AdminService;
import gearth.services.g_python.GPythonVersionUtils;
+import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.subforms.info.InfoController;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
+import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
-import org.json.JSONObject;
import java.io.IOException;
import java.util.Optional;
@@ -31,16 +31,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
public static final String INFO_URL_GPYTHON = "https://github.com/sirjonasxx/G-Earth/wiki/G-Python-qtConsole";
- public static final String NOTEPAD_CACHE_KEY = "notepad_text";
- public static final String DEVELOP_CACHE_KEY = "develop_mode";
- public static final String ALWAYS_ADMIN_KEY = "always_admin";
- public static final String SOCKS_CACHE_KEY = "socks_config";
- public static final String GPYTHON_CACHE_KEY = "use_gpython";
-
- public static final String SOCKS_IP = "ip";
- public static final String SOCKS_PORT = "port";
-// public static final String IGNORE_ONCE = "ignore_once";
-
public TextArea txtarea_notepad;
@@ -69,32 +59,23 @@ public class ExtraController extends SubForm implements SocksConfiguration {
url_troubleshooting.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth/wiki/Troubleshooting"));
InfoController.activateHyperlink(url_troubleshooting);
- String notepadInitValue = (String)Cacher.get(NOTEPAD_CACHE_KEY);
- if (notepadInitValue != null) {
- txtarea_notepad.setText(notepadInitValue);
- }
+ BindingsUtil.setAndBindBiDirectional(txtarea_notepad.textProperty(), GEarthProperties.notesProperty);
- if (Cacher.getCacheContents().has(SOCKS_CACHE_KEY)) {
- JSONObject socksInitValue = Cacher.getCacheContents().getJSONObject(SOCKS_CACHE_KEY);
- txt_socksIp.setText(socksInitValue.getString(SOCKS_IP) + ":" + socksInitValue.getInt(SOCKS_PORT));
-// cbx_socksUseIfNeeded.setSelected(socksInitValue.getBoolean(IGNORE_ONCE));
- }
-
- if (Cacher.getCacheContents().has(GPYTHON_CACHE_KEY)) {
- cbx_gpython.setSelected(Cacher.getCacheContents().getBoolean(GPYTHON_CACHE_KEY));
- }
-
- if (Cacher.getCacheContents().has(ALWAYS_ADMIN_KEY)) {
- cbx_admin.setSelected(Cacher.getCacheContents().getBoolean(ALWAYS_ADMIN_KEY));
- }
-
- cbx_debug.selectedProperty().addListener(observable -> HConnection.DEBUG = cbx_debug.isSelected());
- cbx_disableDecryption.selectedProperty().addListener(observable -> HConnection.DECRYPTPACKETS = !cbx_disableDecryption.isSelected());
-
- cbx_useSocks.selectedProperty().addListener(observable -> grd_socksInfo.setDisable(!cbx_useSocks.isSelected()));
+ txt_socksIp.textProperty().set(GEarthProperties.getSocksHost()+":"+GEarthProperties.getSocksPort());
+ GEarthProperties.socksHostProperty.bind(Bindings.createStringBinding(this::getSocksHost, txt_socksIp.textProperty()));
+ GEarthProperties.socksPortProperty.bind(Bindings.createIntegerBinding(this::getSocksPort, txt_socksIp.textProperty()));
+ grd_socksInfo.disableProperty().bind(GEarthProperties.enableSocksProperty.not());
+ BindingsUtil.setAndBindBiDirectional(cbx_useSocks.selectedProperty(), GEarthProperties.enableSocksProperty);
ProxyProviderFactory.setSocksConfig(this);
+ BindingsUtil.setAndBindBiDirectional(cbx_debug.selectedProperty(), GEarthProperties.enableDebugProperty);
+ BindingsUtil.setAndBindBiDirectional(cbx_disableDecryption.selectedProperty(), GEarthProperties.disablePacketDecryptionProperty);
+ BindingsUtil.setAndBindBiDirectional(cbx_alwaysOnTop.selectedProperty(), GEarthProperties.alwaysOnTopProperty);
+ BindingsUtil.setAndBindBiDirectional(cbx_develop.selectedProperty(), GEarthProperties.enableDeveloperModeProperty);
+ BindingsUtil.setAndBindBiDirectional(cbx_admin.selectedProperty(), GEarthProperties.alwaysAdminProperty);
+ BindingsUtil.setAndBindBiDirectional(cbx_gpython.selectedProperty(), GEarthProperties.enableGPythonProperty);
+
initLanguageBinding();
}
@@ -102,47 +83,16 @@ public class ExtraController extends SubForm implements SocksConfiguration {
protected void onParentSet() {
adminService = new AdminService(cbx_admin.isSelected(), getHConnection());
getHConnection().addTrafficListener(1, message -> adminService.onMessage(message));
- getHConnection().getStateObservable().addListener((oldState, newState) -> {if (newState == HState.CONNECTED) adminService.onConnect();});
-
- parentController.getStage().setAlwaysOnTop(cbx_alwaysOnTop.isSelected());
- cbx_alwaysOnTop.selectedProperty().addListener(observable -> parentController.getStage().setAlwaysOnTop(cbx_alwaysOnTop.isSelected()));
-
- cbx_advanced.selectedProperty().addListener(observable -> updateAdvancedUI());
- getHConnection().getStateObservable().addListener((oldState, newState) -> {
- if (oldState == HState.NOT_CONNECTED || newState == HState.NOT_CONNECTED) {
+ getHConnection().stateProperty().addListener((observable, oldValue, newValue) -> {
+ if (newValue == HState.CONNECTED)
+ adminService.onConnect();
+ if (oldValue == HState.NOT_CONNECTED || newValue == HState.NOT_CONNECTED)
updateAdvancedUI();
- }
});
-
- if (Cacher.getCacheContents().has(DEVELOP_CACHE_KEY)) {
- boolean inDevelopMode = Cacher.getCacheContents().getBoolean(DEVELOP_CACHE_KEY);
- setDevelopMode(inDevelopMode);
- }
-
+ cbx_advanced.selectedProperty().addListener(observable -> updateAdvancedUI());
updateAdvancedUI();
}
- @Override
- protected void onExit() {
- Cacher.put(NOTEPAD_CACHE_KEY, txtarea_notepad.getText());
- Cacher.put(GPYTHON_CACHE_KEY, cbx_gpython.isSelected());
- Cacher.put(ALWAYS_ADMIN_KEY, cbx_admin.isSelected());
- Cacher.put(DEVELOP_CACHE_KEY, cbx_develop.isSelected());
- saveSocksConfig();
- }
-
- private void saveSocksConfig() {
- if (txt_socksIp.getText().contains(":")) {
- JSONObject jsonObject = new JSONObject();
- jsonObject.put(SOCKS_IP, getSocksHost());
- jsonObject.put(SOCKS_PORT, getSocksPort());
- Cacher.put(SOCKS_CACHE_KEY, jsonObject);
- }
- else {
- Cacher.remove(SOCKS_CACHE_KEY);
- }
- }
-
private void updateAdvancedUI() {
if (!cbx_advanced.isSelected()) {
cbx_debug.setSelected(false);
@@ -158,7 +108,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
@Override
public boolean useSocks() {
- saveSocksConfig();
return cbx_useSocks.isSelected();
}
@@ -265,7 +214,6 @@ public class ExtraController extends SubForm implements SocksConfiguration {
private void setDevelopMode(boolean enabled) {
cbx_develop.setSelected(enabled);
- getHConnection().setDeveloperMode(enabled);
}
public void adminCbxClick(ActionEvent actionEvent) {
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/info/InfoController.java b/G-Earth/src/main/java/gearth/ui/subforms/info/InfoController.java
index 8187826..6c478db 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/info/InfoController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/info/InfoController.java
@@ -1,23 +1,26 @@
package gearth.ui.subforms.info;
import gearth.GEarth;
+import gearth.ui.GEarthProperties;
import gearth.ui.titlebar.TitleBarController;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.event.ActionEvent;
+import javafx.fxml.Initializable;
import javafx.scene.control.*;
import gearth.ui.SubForm;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
-import javafx.scene.web.WebView;
import java.io.IOException;
+import java.net.URL;
+import java.util.ResourceBundle;
/**
* Created by Jonas on 06/04/18.
*/
-public class InfoController extends SubForm {
+public class InfoController extends SubForm implements Initializable {
public ImageView img_logo;
public Hyperlink link_darkbox;
public Hyperlink link_g_gearth;
@@ -38,7 +41,12 @@ public class InfoController extends SubForm {
});
}
- public void initialize() {
+ @Override
+ public void initialize(URL location, ResourceBundle resources) {
+
+ img_logo.imageProperty().bind(GEarthProperties.logoImageBinding);
+ version.textProperty().bind(GEarthProperties.themeTitleBinding);
+
link_darkbox.setTooltip(new Tooltip("https://darkbox.nl"));
link_d_gearth.setTooltip(new Tooltip("https://discord.gg/AVkcF8y"));
link_g_gearth.setTooltip(new Tooltip("https://github.com/sirjonasxx/G-Earth"));
@@ -87,4 +95,5 @@ public class InfoController extends SubForm {
btn_donate.textProperty().bind(new TranslatableString("%s", "tab.info.donate"));
}
+
}
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java b/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java
index aca0358..fcc377b 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/injection/InjectionController.java
@@ -4,10 +4,14 @@ import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.HMessage;
import gearth.protocol.HPacket;
+import gearth.ui.GEarthProperties;
import gearth.ui.SubForm;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.input.MouseButton;
@@ -38,10 +42,10 @@ public class InjectionController extends SubForm {
private TranslatableString corruption, pcktInfo;
protected void onParentSet() {
- getHConnection().onDeveloperModeChange(developMode -> updateUI());
- getHConnection().getStateObservable().addListener((oldState, newState) -> Platform.runLater(this::updateUI));
-
- inputPacket.textProperty().addListener(event -> Platform.runLater(this::updateUI));
+ final InvalidationListener updateUI = observable -> Platform.runLater(this::updateUI);
+ GEarthProperties.enableDeveloperModeProperty.addListener(updateUI);
+ getHConnection().stateProperty().addListener(updateUI);
+ inputPacket.textProperty().addListener(updateUI);
}
public void initialize() {
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/scheduler/InteractableScheduleItem.java b/G-Earth/src/main/java/gearth/ui/subforms/scheduler/InteractableScheduleItem.java
index 7651cd6..d131eda 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/scheduler/InteractableScheduleItem.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/scheduler/InteractableScheduleItem.java
@@ -9,6 +9,15 @@ import gearth.services.scheduler.listeners.OnBeingUpdatedListener;
import gearth.services.scheduler.listeners.OnDeleteListener;
import gearth.services.scheduler.listeners.OnEditListener;
import gearth.services.scheduler.listeners.OnUpdatedListener;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ObjectPropertyBase;
+import javafx.event.ActionEvent;
+import javafx.event.Event;
+import javafx.event.EventHandler;
+import javafx.event.EventType;
+import javafx.scene.control.ButtonBase;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeView;
public class InteractableScheduleItem extends ScheduleItem implements StringifyAble {
diff --git a/G-Earth/src/main/java/gearth/ui/subforms/scheduler/SchedulerController.java b/G-Earth/src/main/java/gearth/ui/subforms/scheduler/SchedulerController.java
index b2a95c5..4c9d341 100644
--- a/G-Earth/src/main/java/gearth/ui/subforms/scheduler/SchedulerController.java
+++ b/G-Earth/src/main/java/gearth/ui/subforms/scheduler/SchedulerController.java
@@ -7,9 +7,12 @@ import gearth.protocol.StateChangeListener;
import gearth.protocol.connection.HState;
import gearth.services.scheduler.Interval;
import gearth.services.scheduler.Scheduler;
+import gearth.ui.GEarthProperties;
import gearth.ui.translations.LanguageBundle;
import gearth.ui.translations.TranslatableString;
import javafx.application.Platform;
+import javafx.beans.InvalidationListener;
+import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
@@ -88,8 +91,9 @@ public class SchedulerController extends SubForm {
@Override
protected void onParentSet() {
scheduler = new Scheduler<>(getHConnection());
- getHConnection().onDeveloperModeChange(developMode -> updateUI());
- getHConnection().getStateObservable().addListener((oldState, newState) -> updateUI());
+ final InvalidationListener updateUI = observable -> Platform.runLater(this::updateUI);
+ GEarthProperties.enableDeveloperModeProperty.addListener(updateUI);
+ getHConnection().stateProperty().addListener(updateUI);
updateUI();
}
diff --git a/G-Earth/src/main/java/gearth/ui/titlebar/GEarthThemedTitleBarConfig.java b/G-Earth/src/main/java/gearth/ui/titlebar/GEarthThemedTitleBarConfig.java
index 83495a0..4166e68 100644
--- a/G-Earth/src/main/java/gearth/ui/titlebar/GEarthThemedTitleBarConfig.java
+++ b/G-Earth/src/main/java/gearth/ui/titlebar/GEarthThemedTitleBarConfig.java
@@ -1,16 +1,13 @@
package gearth.ui.titlebar;
-import gearth.GEarth;
-import gearth.ui.themes.Theme;
+import gearth.ui.GEarthProperties;
import javafx.stage.Stage;
-import java.util.function.Consumer;
-
public class GEarthThemedTitleBarConfig extends DefaultTitleBarConfig {
public GEarthThemedTitleBarConfig(Stage stage) {
- super(stage, GEarth.getTheme());
- GEarth.getThemeObservable().addListener(this::setTheme);
+ super(stage, GEarthProperties.getTheme());
+ GEarthProperties.themeProperty.addListener((observable, oldValue, newValue) -> setTheme(newValue));
}
@Override