Saving settings in a file, added SettingsItem class

This commit is contained in:
Kai S. K. Engelbart 2019-12-23 14:25:46 +01:00
parent 7ec9e6b13a
commit 89e8fc62dc
5 changed files with 198 additions and 92 deletions

View File

@ -1,6 +1,7 @@
package envoy.client; package envoy.client;
import java.io.*; import java.io.File;
import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -11,6 +12,7 @@ import javax.xml.datatype.DatatypeFactory;
import envoy.client.event.EventBus; import envoy.client.event.EventBus;
import envoy.client.event.MessageCreationEvent; import envoy.client.event.MessageCreationEvent;
import envoy.client.util.EnvoyLog; import envoy.client.util.EnvoyLog;
import envoy.client.util.SerializationUtils;
import envoy.exception.EnvoyException; import envoy.exception.EnvoyException;
import envoy.schema.*; import envoy.schema.*;
import envoy.schema.Message.Metadata.MessageState; import envoy.schema.Message.Metadata.MessageState;
@ -38,7 +40,7 @@ public class LocalDB {
private Sync sync = objectFactory.createSync(); private Sync sync = objectFactory.createSync();
private Sync readMessages = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync();
private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName());
/** /**
* Constructs an empty local database. To serialize any chats to the file * Constructs an empty local database. To serialize any chats to the file
@ -83,10 +85,10 @@ public class LocalDB {
*/ */
public void save() throws IOException { public void save() throws IOException {
// Save users // Save users
write(usersFile, users); SerializationUtils.write(usersFile, users);
// Save chats // Save chats
write(localDBFile, chats); SerializationUtils.write(localDBFile, chats);
} }
/** /**
@ -95,8 +97,7 @@ public class LocalDB {
* @throws EnvoyException if the loading process failed * @throws EnvoyException if the loading process failed
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
@SuppressWarnings("unchecked") public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); }
public void loadUsers() throws EnvoyException { users = read(usersFile, HashMap.class); }
/** /**
* Loads all chats saved by Envoy for the client user. * Loads all chats saved by Envoy for the client user.
@ -104,31 +105,7 @@ public class LocalDB {
* @throws EnvoyException if the loading process failed * @throws EnvoyException if the loading process failed
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
@SuppressWarnings("unchecked") public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); }
public void loadChats() throws EnvoyException { chats = read(localDBFile, ArrayList.class); }
private <T> T read(File file, Class<T> serializedClass) throws EnvoyException {
if (file == null) throw new NullPointerException("File is null");
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
return serializedClass.cast(in.readObject());
} catch (ClassNotFoundException | IOException e) {
throw new EnvoyException("Could not load serialized object", e);
}
}
private <T> void write(File file, T obj) throws IOException {
if (file == null) throw new NullPointerException("File is null");
if (obj == null) throw new NullPointerException("Object to serialize is null");
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(obj);
} catch (IOException e) {
throw e;
}
}
/** /**
* Creates a {@link Message} object serializable to XML. * Creates a {@link Message} object serializable to XML.
@ -238,8 +215,7 @@ public class LocalDB {
// Updating UserStatus of all users in LocalDB // Updating UserStatus of all users in LocalDB
for (User user : returnSync.getUsers()) for (User user : returnSync.getUsers())
for (Chat chat : getChats()) for (Chat chat : getChats())
if (user.getID() == chat.getRecipient().getID()) if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus());
chat.getRecipient().setStatus(user.getStatus());
sync.getMessages().clear(); sync.getMessages().clear();
sync.getUsers().clear(); sync.getUsers().clear();
@ -301,7 +277,8 @@ public class LocalDB {
public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); }
/** /**
* @return a {@code Map<String, User>} of all users stored locally with their user names as keys * @return a {@code Map<String, User>} of all users stored locally with their
* user names as keys
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Map<String, User> getUsers() { return users; } public Map<String, User> getUsers() { return users; }

View File

@ -7,6 +7,8 @@ import java.util.prefs.Preferences;
import envoy.client.ui.Color; import envoy.client.ui.Color;
import envoy.client.ui.Theme; import envoy.client.ui.Theme;
import envoy.client.util.SerializationUtils;
import envoy.exception.EnvoyException;
/** /**
* Manages all application settings, which are different objects that can be * Manages all application settings, which are different objects that can be
@ -25,20 +27,18 @@ import envoy.client.ui.Theme;
public class Settings { public class Settings {
// Actual settings accessible by the rest of the application // Actual settings accessible by the rest of the application
private boolean enterToSend = true; private Map<String, SettingsItem<?>> items;
private Map<String, Theme> themes; private Map<String, Theme> themes;
private String currentTheme;
private boolean currentOnCloseMode;
/** /**
* Required to save the settings. * Settings are stored in this file.
*/ */
private Preferences prefs = Preferences.userNodeForPackage(Settings.class); private static final File settingsFile = new File(Config.getInstance().getHomeDirectory(), "settings.ser");
/** /**
* User-defined themes are stored inside this file. * User-defined themes are stored inside this file.
*/ */
private File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser"); private static final File themeFile = new File(Config.getInstance().getHomeDirectory(), "themes.ser");
/** /**
* Singleton instance of this class. * Singleton instance of this class.
@ -51,30 +51,21 @@ public class Settings {
* *
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
private Settings() { load(); } private Settings() {
// Load settings from settings file
/** try {
* This method is used to ensure that there is only one instance of Settings. items = SerializationUtils.read(settingsFile, HashMap.class);
* } catch (EnvoyException e) {
* @return the instance of Settings items = new HashMap<>();
* @since Envoy v0.2-alpha }
*/ supplementDefaults();
public static Settings getInstance() { return settings; }
@SuppressWarnings("unchecked")
private void load() {
setEnterToSend(prefs.getBoolean("enterToSend", true));
setCurrentTheme(prefs.get("theme", "dark"));
setCurrentOnCloseMode(prefs.getBoolean("onCloseMode", true));
// Load themes from theme file // Load themes from theme file
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { try {
Object obj = in.readObject(); themes = SerializationUtils.read(themeFile, HashMap.class);
if (obj instanceof HashMap) themes = (Map<String, Theme>) obj; } catch (EnvoyException e1) {
} catch (IOException | ClassNotFoundException e) { themes = new HashMap<>();
themes = new HashMap<>(); setCurrentTheme("dark");
currentTheme = "dark";
e.printStackTrace();
} }
// Load standard themes not defined in the themes file // Load standard themes not defined in the themes file
@ -86,6 +77,14 @@ public class Settings {
Color.black, Color.black)); Color.black, Color.black));
} }
/**
* This method is used to ensure that there is only one instance of Settings.
*
* @return the instance of Settings
* @since Envoy v0.2-alpha
*/
public static Settings getInstance() { return settings; }
/** /**
* Updates the preferences when the save button is clicked. * Updates the preferences when the save button is clicked.
* *
@ -94,15 +93,17 @@ public class Settings {
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void save() throws IOException { public void save() throws IOException {
prefs.put("theme", currentTheme); // Save settings to settings file
prefs.putBoolean("enterToSend", isEnterToSend()); SerializationUtils.write(settingsFile, items);
prefs.putBoolean("onCloseMode", currentOnCloseMode);
// Save themes to theme file // Save themes to theme file
themeFile.createNewFile(); SerializationUtils.write(themeFile, themes);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { }
out.writeObject(themes);
} private void supplementDefaults() {
items.putIfAbsent("enterToSend", new SettingsItem<>(true, "Enter to send", "Sends a message by pressing the enter key."));
items.putIfAbsent("onCloseMode", new SettingsItem<>(false, "Hide on close", "Hides the chat window when it is closed."));
items.putIfAbsent("currentTheme", new SettingsItem<>("dark", null));
} }
/** /**
@ -117,7 +118,7 @@ public class Settings {
* @return the name of the currently active {@link Theme} * @return the name of the currently active {@link Theme}
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public String getCurrentTheme() { return currentTheme; } public String getCurrentTheme() { return (String) items.get("currentTheme").get(); }
/** /**
* Sets the name of the current {@link Theme}. * Sets the name of the current {@link Theme}.
@ -125,7 +126,8 @@ public class Settings {
* @param themeName the name to set * @param themeName the name to set
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void setCurrentTheme(String themeName) { currentTheme = themeName; } @SuppressWarnings("unchecked")
public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); }
/** /**
* @return {@code true}, if pressing the {@code Enter} key suffices to send a * @return {@code true}, if pressing the {@code Enter} key suffices to send a
@ -133,7 +135,7 @@ public class Settings {
* {@code Control} key. * {@code Control} key.
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public boolean isEnterToSend() { return enterToSend; } public boolean isEnterToSend() { return (boolean) items.get("enterToSend").get(); }
/** /**
* Changes the keystrokes performed by the user to send a message. * Changes the keystrokes performed by the user to send a message.
@ -143,7 +145,23 @@ public class Settings {
* conjunction with the {@code Control} key. * conjunction with the {@code Control} key.
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } @SuppressWarnings("unchecked")
public void setEnterToSend(boolean enterToSend) { ((SettingsItem<Boolean>) items.get("enterToSend")).set(enterToSend); }
/**
* @return the current on close mode.
* @since Envoy v0.3-alpha
*/
public boolean getCurrentOnCloseMode() { return (boolean) items.get("onCloseMode").get(); }
/**
* Sets the current on close mode.
*
* @param currentOnCloseMode the on close mode that should be set.
* @since Envoy v0.3-alpha
*/
@SuppressWarnings("unchecked")
public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem<Boolean>) items.get("onCloseMode")).set(currentOnCloseMode); }
/** /**
* @return a {@code Map<String, Theme>} of all themes with their names as keys * @return a {@code Map<String, Theme>} of all themes with their names as keys
@ -158,18 +176,4 @@ public class Settings {
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void setThemes(Map<String, Theme> themes) { this.themes = themes; } public void setThemes(Map<String, Theme> themes) { this.themes = themes; }
/**
* @return the current on close mode.
* @since Envoy v0.3-alpha
*/
public boolean getCurrentOnCloseMode() { return currentOnCloseMode; }
/**
* Sets the current on close mode.
*
* @param currentOnCloseMode the on close mode that should be set.
* @since Envoy v0.3-alpha
*/
public void setCurrentOnCloseMode(boolean currentOnCloseMode) { this.currentOnCloseMode = currentOnCloseMode; }
} }

View File

@ -0,0 +1,87 @@
package envoy.client;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JComponent;
import envoy.client.ui.PrimaryToggleSwitch;
/**
* Project: <strong>envoy-clientChess</strong><br>
* File: <strong>SettingsItem.java</strong><br>
* Created: <strong>23.12.2019</strong><br>
*
* @author Kai S. K. Engelbart
*/
public class SettingsItem<T> implements Serializable {
private T value;
private Class<? extends JComponent> componentClass;
private String userFriendlyName, description;
private static final Map<Class<?>, Class<? extends JComponent>> componentClasses = new HashMap<>();
private static final long serialVersionUID = 2146837835556852218L;
static {
componentClasses.put(boolean.class, PrimaryToggleSwitch.class);
}
public SettingsItem(T value, String userFriendlyName, String description) {
this(value, componentClasses.get(value.getClass()));
this.userFriendlyName = userFriendlyName;
this.description = description;
}
public SettingsItem(T value, Class<? extends JComponent> componentClass) {
this.value = value;
this.componentClass = componentClass;
}
public JComponent getComponent() throws ReflectiveOperationException, SecurityException {
if (componentClass == null) throw new NullPointerException("Component class is null");
return componentClass.getConstructor(SettingsItem.class).newInstance(this);
}
/**
* @return the value
*/
public T get() { return value; }
/**
* @param value the value to set
*/
public void set(T value) { this.value = value; }
/**
* @return the componentClass
*/
public Class<? extends JComponent> getComponentClass() { return componentClass; }
/**
* @param componentClass the componentClass to set
*/
public void setComponentClass(Class<? extends JComponent> componentClass) { this.componentClass = componentClass; }
/**
* @return the userFriendlyName
*/
public String getUserFriendlyName() { return userFriendlyName; }
/**
* @param userFriendlyName the userFriendlyName to set
*/
public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; }
/**
* @return the description
*/
public String getDescription() { return description; }
/**
* @param description the description to set
*/
public void setDescription(String description) { this.description = description; }
}

View File

@ -29,8 +29,8 @@ import envoy.client.util.EnvoyLog;
public class General extends SettingsPanel { public class General extends SettingsPanel {
private Theme theme; private Theme theme;
private boolean onCloseState; private boolean onCloseState = Settings.getInstance().getCurrentOnCloseMode();
private boolean enterToSend; private boolean enterToSend = Settings.getInstance().isEnterToSend();
private PrimaryToggleSwitch toggleSwitch; private PrimaryToggleSwitch toggleSwitch;
private JTextPane onCloseModeTextPane = new JTextPane(); private JTextPane onCloseModeTextPane = new JTextPane();
@ -134,8 +134,8 @@ public class General extends SettingsPanel {
add(stateText, gbc_stateText); add(stateText, gbc_stateText);
descriptionText.setText(text); descriptionText.setText(text);
descriptionText.setBackground(theme.getBackgroundColor().invert()); descriptionText.setBackground(theme.getBackgroundColor());
descriptionText.setForeground(theme.getUserNameColor()); descriptionText.setForeground(theme.getBackgroundColor().invert());
descriptionText.setEditable(false); descriptionText.setEditable(false);
GridBagConstraints gbc_descriptionText = new GridBagConstraints(); GridBagConstraints gbc_descriptionText = new GridBagConstraints();

View File

@ -0,0 +1,38 @@
package envoy.client.util;
import java.io.*;
import envoy.exception.EnvoyException;
/**
* Project: <strong>envoy-clientChess</strong><br>
* File: <strong>SerializationUtils.javaEvent.java</strong><br>
* Created: <strong>23.12.2019</strong><br>
*
* @author Kai S. K. Engelbart
*/
public class SerializationUtils {
private SerializationUtils() {}
public static <T extends Serializable> T read(File file, Class<T> serializedClass) throws EnvoyException {
if (file == null) throw new NullPointerException("File is null");
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) {
return serializedClass.cast(in.readObject());
} catch (ClassNotFoundException | IOException e) {
throw new EnvoyException("Could not load serialized object", e);
}
}
public static void write(File file, Object obj) throws IOException {
if (file == null) throw new NullPointerException("File is null");
if (obj == null) throw new NullPointerException("Object to serialize is null");
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(obj);
}
}
}