diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 7db7200..b5e3971 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -1,6 +1,7 @@ package envoy.client; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.time.Instant; import java.util.*; import java.util.logging.Logger; @@ -11,6 +12,7 @@ import javax.xml.datatype.DatatypeFactory; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; +import envoy.client.util.SerializationUtils; import envoy.exception.EnvoyException; import envoy.schema.*; import envoy.schema.Message.Metadata.MessageState; @@ -38,7 +40,7 @@ public class LocalDB { private Sync sync = 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 @@ -83,10 +85,10 @@ public class LocalDB { */ public void save() throws IOException { // Save users - write(usersFile, users); + SerializationUtils.write(usersFile, users); // Save chats - write(localDBFile, chats); + SerializationUtils.write(localDBFile, chats); } /** @@ -95,8 +97,7 @@ public class LocalDB { * @throws EnvoyException if the loading process failed * @since Envoy v0.2-alpha */ - @SuppressWarnings("unchecked") - public void loadUsers() throws EnvoyException { users = read(usersFile, HashMap.class); } + public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. @@ -104,31 +105,7 @@ public class LocalDB { * @throws EnvoyException if the loading process failed * @since Envoy v0.1-alpha */ - @SuppressWarnings("unchecked") - public void loadChats() throws EnvoyException { chats = read(localDBFile, ArrayList.class); } - - private T read(File file, Class 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 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; - } - } + public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } /** * Creates a {@link Message} object serializable to XML. @@ -238,8 +215,7 @@ public class LocalDB { // Updating UserStatus of all users in LocalDB for (User user : returnSync.getUsers()) for (Chat chat : getChats()) - if (user.getID() == chat.getRecipient().getID()) - chat.getRecipient().setStatus(user.getStatus()); + if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus()); sync.getMessages().clear(); sync.getUsers().clear(); @@ -301,7 +277,8 @@ public class LocalDB { public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } /** - * @return a {@code Map} of all users stored locally with their user names as keys + * @return a {@code Map} of all users stored locally with their + * user names as keys * @since Envoy v0.2-alpha */ public Map getUsers() { return users; } diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index fc60877..199653d 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -7,6 +7,8 @@ import java.util.prefs.Preferences; import envoy.client.ui.Color; 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 @@ -25,20 +27,18 @@ import envoy.client.ui.Theme; public class Settings { // Actual settings accessible by the rest of the application - private boolean enterToSend = true; - private Map themes; - private String currentTheme; - private boolean currentOnCloseMode; + private Map> items; + private Map themes; /** - * 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. */ - 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. @@ -51,30 +51,21 @@ public class Settings { * * @since Envoy v0.2-alpha */ - private Settings() { load(); } - - /** - * 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; } - - @SuppressWarnings("unchecked") - private void load() { - setEnterToSend(prefs.getBoolean("enterToSend", true)); - setCurrentTheme(prefs.get("theme", "dark")); - setCurrentOnCloseMode(prefs.getBoolean("onCloseMode", true)); + private Settings() { + // Load settings from settings file + try { + items = SerializationUtils.read(settingsFile, HashMap.class); + } catch (EnvoyException e) { + items = new HashMap<>(); + } + supplementDefaults(); // Load themes from theme file - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(themeFile))) { - Object obj = in.readObject(); - if (obj instanceof HashMap) themes = (Map) obj; - } catch (IOException | ClassNotFoundException e) { - themes = new HashMap<>(); - currentTheme = "dark"; - e.printStackTrace(); + try { + themes = SerializationUtils.read(themeFile, HashMap.class); + } catch (EnvoyException e1) { + themes = new HashMap<>(); + setCurrentTheme("dark"); } // Load standard themes not defined in the themes file @@ -86,6 +77,14 @@ public class Settings { 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. * @@ -94,15 +93,17 @@ public class Settings { * @since Envoy v0.2-alpha */ public void save() throws IOException { - prefs.put("theme", currentTheme); - prefs.putBoolean("enterToSend", isEnterToSend()); - prefs.putBoolean("onCloseMode", currentOnCloseMode); + // Save settings to settings file + SerializationUtils.write(settingsFile, items); // Save themes to theme file - themeFile.createNewFile(); - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(themeFile))) { - out.writeObject(themes); - } + SerializationUtils.write(themeFile, 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<>(true, "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} * @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}. @@ -125,7 +126,8 @@ public class Settings { * @param themeName the name to set * @since Envoy v0.2-alpha */ - public void setCurrentTheme(String themeName) { currentTheme = themeName; } + @SuppressWarnings("unchecked") + public void setCurrentTheme(String themeName) { ((SettingsItem) items.get("currentTheme")).set(themeName); } /** * @return {@code true}, if pressing the {@code Enter} key suffices to send a @@ -133,7 +135,7 @@ public class Settings { * {@code Control} key. * @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. @@ -143,7 +145,33 @@ public class Settings { * conjunction with the {@code Control} key. * @since Envoy v0.2-alpha */ - public void setEnterToSend(boolean enterToSend) { this.enterToSend = enterToSend; } + @SuppressWarnings("unchecked") + public void setEnterToSend(boolean enterToSend) { ((SettingsItem) 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) items.get("onCloseMode")).set(currentOnCloseMode); } + + /** + * @return the items + */ + public Map> getItems() { return items; } + + /** + * @param items the items to set + */ + public void setItems(Map> items) { this.items = items; } /** * @return a {@code Map} of all themes with their names as keys @@ -158,18 +186,4 @@ public class Settings { * @since Envoy v0.2-alpha */ public void setThemes(Map 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; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/SettingsItem.java b/src/main/java/envoy/client/SettingsItem.java new file mode 100644 index 0000000..4de2a47 --- /dev/null +++ b/src/main/java/envoy/client/SettingsItem.java @@ -0,0 +1,148 @@ +package envoy.client; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import javax.swing.JComponent; + +import envoy.client.ui.PrimaryToggleSwitch; + +/** + * Encapsulates a persistent value that is directly or indirectly mutable by the + * user.
+ *
+ * Project: envoy-clientChess
+ * File: SettingsItem.java
+ * Created: 23.12.2019
+ * + * @param the type of this {@link SettingsItem}'s value + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class SettingsItem implements Serializable { + + private T value; + private Class componentClass; + private String userFriendlyName, description; + + transient private Consumer changeHandler; + + private static final Map, Class> componentClasses = new HashMap<>(); + + private static final long serialVersionUID = 2146837835556852218L; + + static { + componentClasses.put(Boolean.class, PrimaryToggleSwitch.class); + } + + /** + * Initializes a {@link SettingsItem}. The default value's class will be mapped + * to a {@link JComponent} that can be used to display this {@link SettingsItem} + * to the user. + * + * @param value the default value + * @param userFriendlyName the user friendly name (short) + * @param description the description (long) + * @since Envoy v0.3-alpha + */ + public SettingsItem(T value, String userFriendlyName, String description) { + this(value, componentClasses.get(value.getClass())); + this.userFriendlyName = userFriendlyName; + this.description = description; + } + + /** + * Initializes a {@link SettingsItem}. The default value's class will be mapped + * to a specific {@link JComponent}. The mapping can also be disables if this + * parameter is {@code null}. In that case a {@link NullPointerException} will + * be thrown if the method {@link SettingsItem#getComponent()} is called. + * + * @param value the default value + * @param componentClass the class of the {@link JComponent} to represent this {@link SettingsItem} with + * @since Envoy v0.3-alpha + */ + public SettingsItem(T value, Class componentClass) { + this.value = value; + this.componentClass = componentClass; + } + + /** + * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} + * @throws ReflectiveOperationException if the component initialization failed + * @throws SecurityException if the component initialization failed + * @since Envoy v0.3-alpha + */ + 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 + * @since Envoy v0.3-alpha + */ + public T get() { return value; } + + /** + * Changes the value of this {@link SettingsItem}. If a {@code ChangeHandler} if + * defined, it will be invoked with this value. + * + * @param value the value to set + * @since Envoy v0.3-alpha + */ + public void set(T value) { + if (changeHandler != null && value != this.value) changeHandler.accept(value); + this.value = value; + } + + /** + * @return the componentClass + * @since Envoy v0.3-alpha + */ + public Class getComponentClass() { return componentClass; } + + /** + * @param componentClass the componentClass to set + * @since Envoy v0.3-alpha + */ + public void setComponentClass(Class componentClass) { this.componentClass = componentClass; } + + /** + * @return the userFriendlyName + * @since Envoy v0.3-alpha + */ + public String getUserFriendlyName() { return userFriendlyName; } + + /** + * @param userFriendlyName the userFriendlyName to set + * @since Envoy v0.3-alpha + */ + public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } + + /** + * @return the description + * @since Envoy v0.3-alpha + */ + public String getDescription() { return description; } + + /** + * @param description the description to set + * @since Envoy v0.3-alpha + */ + public void setDescription(String description) { this.description = description; } + + /** + * Sets a {@code ChangeHandler} for this {@link SettingsItem}. It will be + * invoked with the current value once during the registration and every time + * when the value changes. + * + * @param changeHandler the changeHandler to set + * @since Envoy v0.3-alpha + */ + public void setChangeHandler(Consumer changeHandler) { + this.changeHandler = changeHandler; + changeHandler.accept(value); + } +} diff --git a/src/main/java/envoy/client/event/EnterToSendEvent.java b/src/main/java/envoy/client/event/EnterToSendEvent.java deleted file mode 100644 index 7b26e0a..0000000 --- a/src/main/java/envoy/client/event/EnterToSendEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -/** - * Encapsulates a change to the {@code enterToSend} setting.
- *
- * Project: envoy-client
- * File: EnterToSendEvent.java
- * Created: 22 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class EnterToSendEvent implements Event { - - private boolean mode; - - /** - * Initializes an {@link EnterToSendEvent}. - * - * @param mode the state of the {@code enterToSend} setting - * @since Envoy 0.3-alpha - */ - public EnterToSendEvent(boolean mode) { this.mode = mode; } - - @Override - public Boolean get() { return mode; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/event/OnCloseChangeEvent.java b/src/main/java/envoy/client/event/OnCloseChangeEvent.java deleted file mode 100644 index 2d86fb6..0000000 --- a/src/main/java/envoy/client/event/OnCloseChangeEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -/** - * Encapsulates a change to the {@code currentOnCloseMode} setting.
- *
- * Project: envoy-client
- * File: OnCloseChangeEvent.java
- * Created: 22 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class OnCloseChangeEvent implements Event { - - private boolean closeMode; - - /** - * Initializes an {@link OnCloseChangeEvent}. - * - * @param closeMode the state of the {@code currentOnCloseMode} setting - * @since Envoy 0.3-alpha - */ - public OnCloseChangeEvent(boolean closeMode) { this.closeMode = closeMode; } - - @Override - public Boolean get() { return closeMode; } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java index 15e8a83..2882a05 100644 --- a/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/PrimaryToggleSwitch.java @@ -1,114 +1,57 @@ package envoy.client.ui; -import java.awt.*; -import java.lang.reflect.Constructor; -import java.util.logging.Logger; +import java.awt.Dimension; +import java.awt.Graphics; import javax.swing.JButton; -import javax.swing.JPanel; import envoy.client.Settings; -import envoy.client.event.Event; -import envoy.client.event.EventBus; -import envoy.client.util.EnvoyLog; +import envoy.client.SettingsItem; /** - * This Component can be used to toggle between two options. e.g. on and - * off.
+ * This component can be used to toggle between two options. This will change + * the state of a {@code boolean} {@link SettingsItem}.
*
* Project: envoy-client
* File: PrimaryToggleSwitch.java
* Created: 21 Dec 2019
* * @author Maximilian Käfer + * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public class PrimaryToggleSwitch extends JPanel { +public class PrimaryToggleSwitch extends JButton { - private final JButton b = new JButton(""); + private boolean state; - private boolean currentState; - - private static final Logger logger = EnvoyLog.getLogger(PrimaryToggleSwitch.class.getSimpleName()); - private static final long serialVersionUID = -721155303106833184L; + private static final long serialVersionUID = -721155303106833184L; /** - * This is the constructor for the PrimaryToggleSwitch. + * Initializes a {@link PrimaryToggleSwitch}. * - * @param initialState The state the toggleSwitch is standardly set to.
- * true: off
- * false: on - * @param eventClass the class of the event dispatched by this toggleSwitch + * @param settingsItem the {@link SettingsItem} that is controlled by this + * {@link PrimaryToggleSwitch} * @since Envoy v0.3-alpha */ - public PrimaryToggleSwitch(boolean initialState, Class> eventClass) { - setEnabled(true); - setVisible(true); - + public PrimaryToggleSwitch(SettingsItem settingsItem) { setPreferredSize(new Dimension(50, 25)); setMinimumSize(new Dimension(50, 25)); setMaximumSize(new Dimension(50, 25)); - b.setPreferredSize(new Dimension(25, 25)); - b.setMinimumSize(new Dimension(25, 25)); - b.setMaximumSize(new Dimension(25, 25)); + setBorderPainted(false); + setFocusPainted(false); + setContentAreaFilled(false); - b.setBackground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); - - GridBagLayout gbl_toggleSwitch = new GridBagLayout(); - gbl_toggleSwitch.columnWidths = new int[] { 1, 1 }; - gbl_toggleSwitch.rowHeights = new int[] { 1 }; - gbl_toggleSwitch.columnWeights = new double[] { 1.0, 1.0 }; - gbl_toggleSwitch.rowWeights = new double[] { 1.0 }; - - setLayout(gbl_toggleSwitch); - - setState(initialState); - - b.addActionListener((evt) -> { - try { - // Dispatch event - Constructor> constructor = eventClass.getConstructor(boolean.class); - EventBus.getInstance().dispatch(constructor.newInstance(currentState)); - - setState(!currentState); - revalidate(); - repaint(); - } catch (ReflectiveOperationException | SecurityException e) { - logger.warning("An error occured while changing the setting: " + e); - } - }); - - repaint(); + state = settingsItem.get(); + addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); } @Override public void paintComponent(Graphics g) { - g.setColor(Color.LIGHT_GRAY); - g.fillRect(0, 0, 50, 25); - g.setColor(Color.GREEN); - g.fillRect(0, 0, 25, 25); + g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); + g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); + + g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); + g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); } - - /** - * This method sets the state of this {@link PrimaryToggleSwitch}. - * - * @param state {@code true} to enable the switch, {@code false} to disable it - * @since Envoy 0.3-alpha - */ - public void setState(boolean state) { - GridBagConstraints gbc_toggleButton = new GridBagConstraints(); - - if (state) { - gbc_toggleButton.anchor = GridBagConstraints.WEST; - gbc_toggleButton.gridx = 0; - } else { - gbc_toggleButton.anchor = GridBagConstraints.EAST; - gbc_toggleButton.gridx = 1; - } - gbc_toggleButton.gridy = 0; - add(b, gbc_toggleButton); - - currentState = state; - } -} +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 5e5bc92..8e57a08 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -143,8 +143,7 @@ public class Startup { new StatusTrayIcon(chatWindow).show(); // If the tray icon is supported and corresponding settings is set, hide the chat window on close - if (Settings.getInstance().getCurrentOnCloseMode()) - chatWindow.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + Settings.getInstance().getItems().get("onCloseMode").setChangeHandler((onCloseMode) -> chatWindow.setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } diff --git a/src/main/java/envoy/client/ui/settings/General.java b/src/main/java/envoy/client/ui/settings/General.java deleted file mode 100644 index b128454..0000000 --- a/src/main/java/envoy/client/ui/settings/General.java +++ /dev/null @@ -1,169 +0,0 @@ -package envoy.client.ui.settings; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; -import java.awt.event.ActionListener; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.swing.JOptionPane; -import javax.swing.JTextPane; - -import envoy.client.Settings; -import envoy.client.event.*; -import envoy.client.ui.PrimaryToggleSwitch; -import envoy.client.ui.Theme; -import envoy.client.util.EnvoyLog; - -/** - * Displays GUI components that allow general settings regarding the client.
- *
- * Project: envoy-client
- * File: General.java
- * Created: 21 Dec 2019
- * - * @author Maximilian Käfer - * @since Envoy v0.3-alpha - */ -public class General extends SettingsPanel { - - private Theme theme; - private boolean onCloseState; - private boolean enterToSend; - - private PrimaryToggleSwitch toggleSwitch; - private JTextPane onCloseModeTextPane = new JTextPane(); - private JTextPane onCloseModeStatePane = new JTextPane(); - - private PrimaryToggleSwitch toggleSwitchEnterToSend; - private JTextPane enterToSendTextPane = new JTextPane(); - private JTextPane enterToSendStatePane = new JTextPane(); - - private static final Logger logger = EnvoyLog.getLogger(General.class.getSimpleName()); - private static final long serialVersionUID = -7470848775130754239L; - - /** - * This is the constructor for the General class. Here the user can set general - * settings for the client. - * - * @since Envoy 0.3-alpha - */ - public General() { - theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - setBackground(theme.getCellColor()); - - GridBagLayout gbl_general = new GridBagLayout(); - gbl_general.columnWidths = new int[] { 1, 1 }; - gbl_general.rowHeights = new int[] { 1, 1, 1, 1, 1 }; - gbl_general.columnWeights = new double[] { 1.0, 0.1 }; - gbl_general.rowWeights = new double[] { 0.02, 0.0005, 0.02, 0.0005, 1.0 }; - - setLayout(gbl_general); - - createSettingElement(0, - OnCloseChangeEvent.class, - Settings.getInstance().getCurrentOnCloseMode(), - toggleSwitch, - onCloseModeStatePane, - onCloseModeTextPane, - "Client runs in the background, when window is closed"); - EventBus.getInstance().register(OnCloseChangeEvent.class, (evt) -> changeOnClose(((OnCloseChangeEvent) evt).get())); - - createSettingElement(2, - EnterToSendEvent.class, - Settings.getInstance().isEnterToSend(), - toggleSwitchEnterToSend, - enterToSendStatePane, - enterToSendTextPane, - "Press Enter to send messages"); - EventBus.getInstance().register(EnterToSendEvent.class, (evt) -> changeEnterToSend(((EnterToSendEvent) evt).get())); - } - - /** - * This method changes the on close mode of the client. - * - * @param state This is the integer that defines weather the toggleSwitch is on - * or off. - * @since Envoy v0.3-alpha - */ - public void changeOnClose(boolean state) { - this.onCloseState = state; - - onCloseModeStatePane.setText(state ? "ON" : "OFF"); - revalidate(); - repaint(); - } - - /** - * This method changes the enter to send a message setting. - * - * @param state This is the integer that defines weather the toggleSwitch is on - * or off. - * @since Envoy v0.3-alpha - */ - public void changeEnterToSend(boolean state) { - this.enterToSend = state; - - enterToSendStatePane.setText(state ? "ON" : "OFF"); - revalidate(); - repaint(); - } - - private void createSettingElement(int gridy, Class> eventClass, boolean state, PrimaryToggleSwitch toggleSwitch, - JTextPane stateText, JTextPane descriptionText, String text) { - toggleSwitch = new PrimaryToggleSwitch(state, eventClass); - - GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); - gbc_toggleSwitch.gridx = 1; - gbc_toggleSwitch.gridy = gridy; - - add(toggleSwitch, gbc_toggleSwitch); - - stateText.setText(state ? "ON" : "OFF"); - stateText.setBackground(theme.getCellColor()); - stateText.setForeground(theme.getUserNameColor()); - stateText.setEditable(false); - - GridBagConstraints gbc_stateText = new GridBagConstraints(); - gbc_stateText.anchor = GridBagConstraints.NORTH; - gbc_stateText.gridx = 1; - gbc_stateText.gridy = gridy + 1; - - add(stateText, gbc_stateText); - - descriptionText.setText(text); - descriptionText.setBackground(theme.getBackgroundColor().invert()); - descriptionText.setForeground(theme.getUserNameColor()); - descriptionText.setEditable(false); - - GridBagConstraints gbc_descriptionText = new GridBagConstraints(); - gbc_descriptionText.fill = GridBagConstraints.BOTH; - gbc_descriptionText.gridx = 0; - gbc_descriptionText.gridy = gridy; - gbc_descriptionText.gridheight = 2; - gbc_descriptionText.insets = new Insets(5, 5, 5, 5); - - add(descriptionText, gbc_descriptionText); - } - - @Override - public ActionListener getOkButtonAction() { - return (evt) -> { - if (onCloseState != Settings.getInstance().getCurrentOnCloseMode()) try { - Settings.getInstance().setCurrentOnCloseMode(onCloseState); - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.log(Level.WARNING, "Close mode could not be changed! ", e); - } - - if (enterToSend != Settings.getInstance().isEnterToSend()) try { - Settings.getInstance().setEnterToSend(enterToSend); - JOptionPane.showMessageDialog(null, "The changes will take effect the next time the program is started."); - } catch (Exception e) { - logger.log(Level.WARNING, "Enter to send mode could not be changed! ", e); - } - }; - } -} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java new file mode 100644 index 0000000..ee8f619 --- /dev/null +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -0,0 +1,90 @@ +package envoy.client.ui.settings; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionListener; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JComponent; +import javax.swing.JTextPane; + +import envoy.client.Settings; +import envoy.client.SettingsItem; +import envoy.client.ui.Theme; +import envoy.client.util.EnvoyLog; + +/** + * Displays GUI components that allow general settings regarding the client.
+ *
+ * Project: envoy-client
+ * File: GeneralSettingsPanel.java
+ * Created: 21 Dec 2019
+ * + * @author Maximilian Käfer + * @since Envoy v0.3-alpha + */ +public class GeneralSettingsPanel extends SettingsPanel { + + private Theme theme; + + private static final String[] items = { "onCloseMode", "enterToSend" }; + private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class.getSimpleName()); + private static final long serialVersionUID = -7470848775130754239L; + + /** + * This is the constructor for the General class. Here the user can set general + * settings for the client. + * + * @since Envoy 0.3-alpha + */ + public GeneralSettingsPanel() { + theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + + setBackground(theme.getCellColor()); + + GridBagLayout gbl_general = new GridBagLayout(); + gbl_general.columnWidths = new int[] { 1, 1 }; + gbl_general.rowHeights = new int[] { 1, 1, 1 }; + gbl_general.columnWeights = new double[] { 1.0, 0.1 }; + gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 }; + + setLayout(gbl_general); + + for (int i = 0; i < items.length; i++) + try { + createSettingElement(i, Settings.getInstance().getItems().get(items[i])); + } catch (SecurityException | ReflectiveOperationException e) { + logger.log(Level.WARNING, "Could not create settings item", e); + } + } + + private void createSettingElement(int gridy, SettingsItem settingsItem) throws SecurityException, ReflectiveOperationException { + JTextPane descriptionText = new JTextPane(); + + JComponent settingComponent = settingsItem.getComponent(); + + GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); + gbc_toggleSwitch.gridx = 1; + gbc_toggleSwitch.gridy = gridy; + + add(settingComponent, gbc_toggleSwitch); + + descriptionText.setText(settingsItem.getDescription()); + descriptionText.setBackground(theme.getBackgroundColor()); + descriptionText.setForeground(theme.getBackgroundColor().invert()); + descriptionText.setEditable(false); + + GridBagConstraints gbc_descriptionText = new GridBagConstraints(); + gbc_descriptionText.fill = GridBagConstraints.BOTH; + gbc_descriptionText.gridx = 0; + gbc_descriptionText.gridy = gridy; + gbc_descriptionText.insets = new Insets(5, 5, 5, 5); + + add(descriptionText, gbc_descriptionText); + } + + @Override + public ActionListener getOkButtonAction() { return (evt) -> {}; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index b971625..b37bf9a 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -57,7 +57,7 @@ public class SettingsScreen extends JDialog { public SettingsScreen() { // Initialize settings pages Map> panels = new HashMap<>(); - panels.put("General", General.class); + panels.put("General", GeneralSettingsPanel.class); panels.put("Color Themes", ThemeCustomizationPanel.class); setBounds(10, 10, 450, 650); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 8c3f9f4..c07bc56 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -194,7 +194,8 @@ public class ThemeCustomizationPanel extends SettingsPanel { button.addActionListener((evt) -> { try { - Color newColor = (Color) JColorChooser.showDialog(null, "Choose a color", color); + java.awt.Color c = JColorChooser.showDialog(null, "Choose a color", color); + Color newColor = new Color(c.getRGB()); if (newColor.getRGB() != color.getRGB()) { logger.log(Level.FINEST, "New Color: " + String.valueOf(color.getRGB())); // TODO: When Theme changed in same settings screen, color variable doesn't diff --git a/src/main/java/envoy/client/util/SerializationUtils.java b/src/main/java/envoy/client/util/SerializationUtils.java new file mode 100644 index 0000000..f0cc70f --- /dev/null +++ b/src/main/java/envoy/client/util/SerializationUtils.java @@ -0,0 +1,57 @@ +package envoy.client.util; + +import java.io.*; + +import envoy.exception.EnvoyException; + +/** + * Project: envoy-clientChess
+ * File: SerializationUtils.javaEvent.java
+ * Created: 23.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class SerializationUtils { + + private SerializationUtils() {} + + /** + * Deserializes an arbitrary {@link Serializable} object from a file. + * + * @param the type of the object to deserialize + * @param file the file deserialize from + * @param serializedClass the class of the object to deserialize + * @return the deserialized object + * @throws EnvoyException if an error occurred during deserialization + * @since Envoy v0.3-alpha + */ + public static T read(File file, Class 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); + } + } + + /** + * Serializes an arbitrary object to a file. + * + * @param file the file to serialize to + * @param obj the object to serialize + * @throws IOException if an error occurred during serialization + * @since Envoy v0.3-alpha + */ + 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); + } + } +} \ No newline at end of file