From 06bd12743255b4c9450b35c042cf5c63e92557eb Mon Sep 17 00:00:00 2001 From: kske Date: Mon, 2 Dec 2019 21:44:18 +0100 Subject: [PATCH 01/13] Added a test call to the system tray displaying a message --- src/main/java/envoy/client/ui/ChatWindow.java | 24 ++++++++++++++---- src/main/resources/Envoy Logo.png | Bin 0 -> 8152 bytes 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/Envoy Logo.png diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 32b024b..0eeccc0 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,11 +1,17 @@ package envoy.client.ui; +import java.awt.AWTException; import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.Image; import java.awt.Insets; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -37,7 +43,7 @@ import envoy.schema.User; * Project: envoy-client
* File: ChatWindow.java
* Created: 28 Sep 2019
- * + * * @author Kai S. K. Engelbart * @author Maximilian Käfer * @author Leon Hofmeister @@ -122,13 +128,11 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } - } }); // Checks for changed Message @@ -287,7 +291,7 @@ public class ChatWindow extends JFrame { /** * Initializes the elements of the user list by downloading them from the * server. - * + * * @since Envoy v0.1-alpha */ private void loadUsersAndChats() { @@ -308,7 +312,7 @@ public class ChatWindow extends JFrame { /** * Updates the data model and the UI repeatedly after a certain amount of * time. - * + * * @param timeout the amount of time that passes between two requests sent to * the server * @since Envoy v0.1-alpha @@ -346,4 +350,14 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } + + private void displayNotification(String message) throws AWTException { + SystemTray tray = SystemTray.getSystemTray(); + Image image = Toolkit.getDefaultToolkit().createImage(getClass().getResource("Envoy Logo.png")); + TrayIcon trayIcon = new TrayIcon(image, "Envoy Client"); + trayIcon.setImageAutoSize(true); + trayIcon.setToolTip("You are notified if you have unread messages."); + tray.add(trayIcon); + trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); + } } diff --git a/src/main/resources/Envoy Logo.png b/src/main/resources/Envoy Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..35ef7d9fd78cc3b79454de104ae59fbb65c0b050 GIT binary patch literal 8152 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 Date: Tue, 3 Dec 2019 21:48:16 +0100 Subject: [PATCH 02/13] Moved system tray logic to StatusTrayIcon class --- src/main/java/envoy/client/ui/ChatWindow.java | 37 +++-------------- .../java/envoy/client/ui/StatusTrayIcon.java | 39 ++++++++++++++++++ .../{Envoy Logo.png => envoy_logo.png} | Bin 3 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 src/main/java/envoy/client/ui/StatusTrayIcon.java rename src/main/resources/{Envoy Logo.png => envoy_logo.png} (100%) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 0eeccc0..7a5c67c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -1,17 +1,11 @@ package envoy.client.ui; -import java.awt.AWTException; import java.awt.Color; import java.awt.ComponentOrientation; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.Image; import java.awt.Insets; -import java.awt.SystemTray; -import java.awt.Toolkit; -import java.awt.TrayIcon; -import java.awt.TrayIcon.MessageType; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; @@ -128,8 +122,8 @@ public class ChatWindow extends JFrame { @Override public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) - || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { + if (e.getKeyCode() == KeyEvent.VK_ENTER + && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { postMessage(messageList); } @@ -220,11 +214,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = localDB.getChats() - .stream() - .filter(chat -> chat.getRecipient().getID() == user.getID()) - .findFirst() - .get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -263,10 +253,7 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { - JOptionPane.showMessageDialog(this, - "Please select a recipient!", - "Cannot send message", - JOptionPane.INFORMATION_MESSAGE); + JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); } if (!messageEnterTextArea.getText().isEmpty()) try { @@ -322,8 +309,7 @@ public class ChatWindow extends JFrame { new Thread(() -> { // Synchronize - localDB.applySync( - client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); // Process unread messages localDB.addUnreadMessagesToLocalDB(); @@ -333,8 +319,7 @@ public class ChatWindow extends JFrame { readCurrentChat(); // Update UI - SwingUtilities - .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + SwingUtilities.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); }).start(); }).start(); } @@ -350,14 +335,4 @@ public class ChatWindow extends JFrame { * Marks messages in the current chat as {@code READ}. */ private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } - - private void displayNotification(String message) throws AWTException { - SystemTray tray = SystemTray.getSystemTray(); - Image image = Toolkit.getDefaultToolkit().createImage(getClass().getResource("Envoy Logo.png")); - TrayIcon trayIcon = new TrayIcon(image, "Envoy Client"); - trayIcon.setImageAutoSize(true); - trayIcon.setToolTip("You are notified if you have unread messages."); - tray.add(trayIcon); - trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); - } } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java new file mode 100644 index 0000000..54bc3a3 --- /dev/null +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -0,0 +1,39 @@ +package envoy.client.ui; + +import java.awt.AWTException; +import java.awt.Image; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; + +import envoy.exception.EnvoyException; + +/** + * Project: envoy-client
+ * File: StatusTrayIcon.java
+ * Created: 3 Dec 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha + */ +public class StatusTrayIcon { + + private TrayIcon trayIcon; + + public StatusTrayIcon() throws EnvoyException { + if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); + + Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + TrayIcon trayIcon = new TrayIcon(img, "Envoy Client"); + trayIcon.setImageAutoSize(true); + trayIcon.setToolTip("You are notified if you have unread messages."); + try { + SystemTray.getSystemTray().add(trayIcon); + } catch (AWTException e) { + throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); + } + } + + // TODO: Add event listener + // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); +} diff --git a/src/main/resources/Envoy Logo.png b/src/main/resources/envoy_logo.png similarity index 100% rename from src/main/resources/Envoy Logo.png rename to src/main/resources/envoy_logo.png From 378a83638a3ff2fc498a6cfd2fba5e7b0305b368 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 4 Dec 2019 07:50:59 +0100 Subject: [PATCH 03/13] Added a small popup menu to StatusTrayIcon and loading it in Startup --- src/main/java/envoy/client/ui/Startup.java | 1 + .../java/envoy/client/ui/StatusTrayIcon.java | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index c3a3baa..7b35158 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -64,6 +64,7 @@ public class Startup { EventQueue.invokeLater(() -> { try { ChatWindow frame = new ChatWindow(client, localDB); + new StatusTrayIcon().show(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 54bc3a3..7ef6877 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -2,6 +2,8 @@ package envoy.client.ui; import java.awt.AWTException; import java.awt.Image; +import java.awt.MenuItem; +import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; @@ -24,16 +26,31 @@ public class StatusTrayIcon { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); - TrayIcon trayIcon = new TrayIcon(img, "Envoy Client"); + trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); + + PopupMenu popup = new PopupMenu(); + + MenuItem exitMenuItem = new MenuItem("Exit"); + exitMenuItem.addActionListener((evt) -> System.exit(0)); + popup.add(exitMenuItem); + + trayIcon.setPopupMenu(popup); + } + + /** + * Makes this {@link StatusTrayIcon} appear in the system tray. + * @throws EnvoyException + */ + public void show() throws EnvoyException { try { SystemTray.getSystemTray().add(trayIcon); } catch (AWTException e) { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } - + // TODO: Add event listener // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); } From 3c7f95f86973a9ff22dc91e506e33b812cbdb563 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 4 Dec 2019 18:50:06 +0100 Subject: [PATCH 04/13] Added event system + Event interface for defining event objects + EventHandler interface for defining event handlers + EventBus singleton class for managing event handlers and dispatching events --- src/main/java/envoy/client/event/Event.java | 16 ++++++++++ .../java/envoy/client/event/EventBus.java | 32 +++++++++++++++++++ .../java/envoy/client/event/EventHandler.java | 25 +++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/java/envoy/client/event/Event.java create mode 100644 src/main/java/envoy/client/event/EventBus.java create mode 100644 src/main/java/envoy/client/event/EventHandler.java diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java new file mode 100644 index 0000000..5d2e8a3 --- /dev/null +++ b/src/main/java/envoy/client/event/Event.java @@ -0,0 +1,16 @@ +package envoy.client.event; + +/** + * Project: envoy-clientChess
+ * File: Event.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public interface Event { + + /** + * @return the data associated with this event + */ + T get(); +} diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java new file mode 100644 index 0000000..c97844b --- /dev/null +++ b/src/main/java/envoy/client/event/EventBus.java @@ -0,0 +1,32 @@ +package envoy.client.event; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Project: envoy-clientChess
+ * File: EventBus.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public class EventBus { + + private static EventBus eventBus; + + private List handlers = new ArrayList<>(); + + private EventBus() {} + + public EventBus getInstance() { + if (eventBus == null) eventBus = new EventBus(); + return eventBus; + } + + public void register(EventHandler... handlers) { this.handlers.addAll(Arrays.asList(handlers)); } + + public void dispatch(Event event) { handlers.stream().filter(h -> h.supports().contains(event.getClass())).forEach(h -> h.handle(event)); } + + public List getHandlers() { return handlers; } +} diff --git a/src/main/java/envoy/client/event/EventHandler.java b/src/main/java/envoy/client/event/EventHandler.java new file mode 100644 index 0000000..a6e5b81 --- /dev/null +++ b/src/main/java/envoy/client/event/EventHandler.java @@ -0,0 +1,25 @@ +package envoy.client.event; + +import java.util.Set; + +/** + * Project: envoy-clientChess
+ * File: EventHandler.javaEvent.java
+ * Created: 04.12.2019
+ * + * @author Kai S. K. Engelbart + */ +public interface EventHandler { + + /** + * Consumes an event dispatched by the event bus. + * + * @param event The event dispatched by the event bus, only of supported type + */ + void handle(Event event); + + /** + * @return A set of classes this class is supposed to handle in events + */ + Set>> supports(); +} From b5badae77308a14860e200aa856c2e688e60b353 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 4 Dec 2019 18:52:48 +0100 Subject: [PATCH 05/13] Added StatusTrayIcon#displayMessageNotification method Using this method, a message object can be displayed as a OS-specific notification, which can be useful in the future to alert the user about an incoming message while the application is not in focus. --- .../java/envoy/client/ui/StatusTrayIcon.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 7ef6877..869e678 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -7,8 +7,10 @@ import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; +import java.awt.TrayIcon.MessageType; import envoy.exception.EnvoyException; +import envoy.schema.Message; /** * Project: envoy-client
@@ -25,22 +27,23 @@ public class StatusTrayIcon { public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); - trayIcon = new TrayIcon(img, "Envoy Client"); + Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); - + PopupMenu popup = new PopupMenu(); - + MenuItem exitMenuItem = new MenuItem("Exit"); exitMenuItem.addActionListener((evt) -> System.exit(0)); popup.add(exitMenuItem); - + trayIcon.setPopupMenu(popup); } /** * Makes this {@link StatusTrayIcon} appear in the system tray. + * * @throws EnvoyException */ public void show() throws EnvoyException { @@ -50,7 +53,14 @@ public class StatusTrayIcon { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } - - // TODO: Add event listener - // trayIcon.displayMessage("Envoy Client", message, MessageType.INFO); + + /** + * Notifies the user of a message by displaying a popup. + * + * @param message the {@link Message} object to display in the popup + */ + public void displayMessageNotification(Message message) { + // TODO: Add event listener + trayIcon.displayMessage("New message received", message.getContent().get(0).getText(), MessageType.INFO); + } } From af7408142c55560945685c8ce0cbcf55fec89b2c Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 4 Dec 2019 22:26:24 +0100 Subject: [PATCH 06/13] Added message events, triggering message creation event + Abstract MessageEvent class with MessageCreationEvent and MessageModificationEvent subclasses + Made StatusTrayIcon an event handler - Fixed EventBus#getInstance not being static --- src/main/java/envoy/client/LocalDB.java | 15 ++++++---- .../java/envoy/client/event/EventBus.java | 4 +-- .../client/event/MessageCreationEvent.java | 18 ++++++++++++ .../java/envoy/client/event/MessageEvent.java | 20 +++++++++++++ .../event/MessageModificationEvent.java | 18 ++++++++++++ .../java/envoy/client/ui/StatusTrayIcon.java | 29 +++++++++++++------ 6 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 src/main/java/envoy/client/event/MessageCreationEvent.java create mode 100644 src/main/java/envoy/client/event/MessageEvent.java create mode 100644 src/main/java/envoy/client/event/MessageModificationEvent.java diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 3cc96a2..bf6f01a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -13,6 +13,8 @@ import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; +import envoy.client.event.EventBus; +import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; import envoy.schema.Message; import envoy.schema.Message.Metadata.MessageState; @@ -112,7 +114,7 @@ public class LocalDB { /** * Creates a {@link Message} object serializable to XML. - * + * * @param textContent The content (text) of the message * @return prepared {@link Message} object */ @@ -161,6 +163,9 @@ public class LocalDB { && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { // these are the unread Messages from the server unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + // Create and dispatch message creation event + EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); } if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 @@ -225,7 +230,7 @@ public class LocalDB { /** * Adds the unread messages returned from the server in the latest sync to the * right chats in the LocalDB. - * + * * @param localDB * @since Envoy v0.1-alpha */ @@ -243,7 +248,7 @@ public class LocalDB { * {@code READ}. *
* Adds these messages to the {@code readMessages} {@link Sync} object. - * + * * @param currentChat * @since Envoy v0.1-alpha */ @@ -259,7 +264,7 @@ public class LocalDB { /** * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the * {@link Sync} object. - * + * * @since Envoy v0.1-alpha */ private void addWaitingMessagesToSync() { @@ -273,7 +278,7 @@ public class LocalDB { /** * Clears the {@code unreadMessagesSync} {@link Sync} object. - * + * * @since Envoy v0.1-alpha */ public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java index c97844b..f1c40fc 100644 --- a/src/main/java/envoy/client/event/EventBus.java +++ b/src/main/java/envoy/client/event/EventBus.java @@ -8,7 +8,7 @@ import java.util.List; * Project: envoy-clientChess
* File: EventBus.javaEvent.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart */ public class EventBus { @@ -19,7 +19,7 @@ public class EventBus { private EventBus() {} - public EventBus getInstance() { + public static EventBus getInstance() { if (eventBus == null) eventBus = new EventBus(); return eventBus; } diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java new file mode 100644 index 0000000..28f1b58 --- /dev/null +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -0,0 +1,18 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageCreationEvent extends MessageEvent { + + /** + * @param message the {@link Message} that has been created + */ + public MessageCreationEvent(Message message) { super(message); } +} diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java new file mode 100644 index 0000000..014a7bb --- /dev/null +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -0,0 +1,20 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageCreationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageEvent implements Event { + + protected final Message message; + + public MessageEvent(Message message) { this.message = message; } + + @Override + public Message get() { return message; } +} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java new file mode 100644 index 0000000..0b83ef0 --- /dev/null +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -0,0 +1,18 @@ +package envoy.client.event; + +import envoy.schema.Message; + +/** + * Project: envoy-client
+ * File: MessageModificationEvent.java
+ * Created: 4 Dec 2019
+ * + * @author Kai S. K. Engelbart + */ +public class MessageModificationEvent extends MessageEvent { + + /** + * @param message the {@link Message} that has been modified + */ + public MessageModificationEvent(Message message) { super(message); } +} diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 869e678..ab668e1 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,9 +8,14 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.util.HashSet; +import java.util.Set; +import envoy.client.event.Event; +import envoy.client.event.EventBus; +import envoy.client.event.EventHandler; +import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; -import envoy.schema.Message; /** * Project: envoy-client
@@ -20,7 +25,7 @@ import envoy.schema.Message; * @author Kai S. K. Engelbart * @since Envoy v0.2-alpha */ -public class StatusTrayIcon { +public class StatusTrayIcon implements EventHandler { private TrayIcon trayIcon; @@ -39,11 +44,12 @@ public class StatusTrayIcon { popup.add(exitMenuItem); trayIcon.setPopupMenu(popup); + EventBus.getInstance().register(this); } /** * Makes this {@link StatusTrayIcon} appear in the system tray. - * + * * @throws EnvoyException */ public void show() throws EnvoyException { @@ -55,12 +61,17 @@ public class StatusTrayIcon { } /** - * Notifies the user of a message by displaying a popup. - * - * @param message the {@link Message} object to display in the popup + * Notifies the user of a message by displaying a pop-up. */ - public void displayMessageNotification(Message message) { - // TODO: Add event listener - trayIcon.displayMessage("New message received", message.getContent().get(0).getText(), MessageType.INFO); + @Override + public void handle(Event event) { + trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); + } + + @Override + public Set>> supports() { + Set>> supportedEvents = new HashSet<>(); + supportedEvents.add(MessageCreationEvent.class); + return supportedEvents; } } From dca65df9bdd8b995e404a1f0c8de9c867ac76e81 Mon Sep 17 00:00:00 2001 From: kske Date: Wed, 4 Dec 2019 23:27:17 +0100 Subject: [PATCH 07/13] Added Javadoc to event related classes and StatusTrayIcon --- src/main/java/envoy/client/LocalDB.java | 1 - src/main/java/envoy/client/event/Event.java | 1 + .../java/envoy/client/event/EventBus.java | 57 ++++++++++++++++--- .../java/envoy/client/ui/StatusTrayIcon.java | 28 ++++++++- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index bf6f01a..c080541 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -49,7 +49,6 @@ public class LocalDB { * @param client the user that is logged in with this client * @since Envoy v0.1-alpha */ - public LocalDB(User sender) { this.sender = sender; try { diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java index 5d2e8a3..9db2477 100644 --- a/src/main/java/envoy/client/event/Event.java +++ b/src/main/java/envoy/client/event/Event.java @@ -6,6 +6,7 @@ package envoy.client.event; * Created: 04.12.2019
* * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public interface Event { diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java index f1c40fc..f6da3f5 100644 --- a/src/main/java/envoy/client/event/EventBus.java +++ b/src/main/java/envoy/client/event/EventBus.java @@ -5,28 +5,67 @@ import java.util.Arrays; import java.util.List; /** - * Project: envoy-clientChess
- * File: EventBus.javaEvent.java
+ * This class handles events by allowing {@link EventHandler} object to register + * themselves and then be notified about certain events dispatched by the event + * bus.
+ *
+ * The event bus is a singleton and can be used across the entire application to + * guarantee the propagation of events. + * Project: envoy-client
+ * File: EventBus.java
* Created: 04.12.2019
- * + * * @author Kai S. K. Engelbart + * @since Envoy v0.2-alpha */ public class EventBus { - private static EventBus eventBus; - + /** + * Contains all {@link EventHandler} instances registered at this + * {@link EventBus}. + */ private List handlers = new ArrayList<>(); + /** + * The singleton instance of this {@link EventBus} that is used across the + * entire application. + */ + private static EventBus eventBus = new EventBus(); + + /** + * This constructor is not accessible from outside this class because a + * singleton instance of it is provided by the {@link EventBus#getInstance()} + * method. + */ private EventBus() {} - public static EventBus getInstance() { - if (eventBus == null) eventBus = new EventBus(); - return eventBus; - } + /** + * @return the singleton instance of the {@link EventBus} + * @since Envoy v0.2-alpha + */ + public static EventBus getInstance() { return eventBus; } + /** + * Registers a list of {@link EventHandler} objects to be notified when a + * {@link Event} is dispatched that they are subscribed to. + * + * @param handlers the {@link EventHandler} objects to register + * @since Envoy v0.2-alpha + */ public void register(EventHandler... handlers) { this.handlers.addAll(Arrays.asList(handlers)); } + /** + * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it. + * + * @param event the {@link Event} to dispatch + * @since Envoy v0.2-alpha + */ public void dispatch(Event event) { handlers.stream().filter(h -> h.supports().contains(event.getClass())).forEach(h -> h.handle(event)); } + /** + * @return a list of all {@link EventHandler} instances currently registered at + * this {@link EventBus} + * @since Envoy v0.2-alpha + */ public List getHandlers() { return handlers; } } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index ab668e1..951fbd4 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -27,8 +27,20 @@ import envoy.exception.EnvoyException; */ public class StatusTrayIcon implements EventHandler { + /** + * The {@link TrayIcon} provided by the System Tray API for controlling the + * system tray. This includes displaying the icon, but also creating + * notifications when new messages are received. + */ private TrayIcon trayIcon; + /** + * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up + * menu. + * + * @throws EnvoyException if the currently used OS does not support the System + * Tray API + */ public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); @@ -50,7 +62,9 @@ public class StatusTrayIcon implements EventHandler { /** * Makes this {@link StatusTrayIcon} appear in the system tray. * - * @throws EnvoyException + * @throws EnvoyException if the status icon could not be attaches to the system + * tray for system-internal reasons + * @since Envoy v0.2-alpha */ public void show() throws EnvoyException { try { @@ -61,13 +75,23 @@ public class StatusTrayIcon implements EventHandler { } /** - * Notifies the user of a message by displaying a pop-up. + * Notifies the user of a message by displaying a pop-up every time a new + * message is received. + * + * @since Envoy v0.2-alpha */ @Override public void handle(Event event) { trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); } + /** + * The {@link StatusTrayIcon} only reacts to {@link MessageCreationEvent} + * instances which signify newly received messages. + * + * @return A set with the single element {@code MessageCreationEvent.class} + * @since Envoy v0.2-alpha + */ @Override public Set>> supports() { Set>> supportedEvents = new HashSet<>(); From 50945a45a2f616274eae56901eaebd96cd0ee17e Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 5 Dec 2019 15:05:05 +0100 Subject: [PATCH 08/13] Simplified and optimized sync related code in LocalDB --- src/main/java/envoy/client/LocalDB.java | 141 ++++++++++++------------ 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index c080541..d15e62a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -147,80 +147,83 @@ public class LocalDB { public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { - // Update Local Messages with State WAITING (add Message ID and change State to - // SENT) - for (int j = 0; j < sync.getMessages().size(); j++) { - if (j == i) { - sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); - sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - } - } - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // these are the unread Messages from the server - unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - // Create and dispatch message creation event - EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); - } + // The message has an ID + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { - // Update Messages in localDB to state RECEIVED - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - // Update Message in LocalDB - getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState()); + // Messages are processes differently corresponding to their state + switch (returnSync.getMessages().get(i).getMetadata().getState()) { + case SENT: + // Update previously waiting and now sent messages that were assigned an ID by + // the server + sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); + sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + break; + case RECEIVED: + if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + // Create and dispatch message creation event + EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); + } else { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + // Update Message in LocalDB + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } } } - } - } - - } - - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 - && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { - // Update local Messages to state READ - System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - System.out.println( - "Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); - getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out - .println("Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + break; + case READ: + // Update local Messages to state READ + System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + System.out.println("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + + "was selected."); + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out.println( + "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + } + } } } - } + break; } } } // Updating UserStatus of all users in LocalDB - for (int j = 0; j < returnSync.getUsers().size(); j++) { - for (int k = 0; k < getChats().size(); k++) { - if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { - - getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); - System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + for (User user : returnSync.getUsers()) + for (Chat chat : getChats()) + if (user.getID() == chat.getRecipient().getID()) { + chat.getRecipient().setStatus(user.getStatus()); + System.out.println(chat.getRecipient().getStatus()); } - } - } sync.getMessages().clear(); sync.getUsers().clear(); @@ -234,11 +237,11 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { - Sync unreadMessages = unreadMessagesSync; - for (int i = 0; i < unreadMessages.getMessages().size(); i++) - for (int j = 0; j < getChats().size(); j++) - if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { - getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + for(Message message : unreadMessagesSync.getMessages()) + for(Chat chat : getChats()) + if(message.getMetadata().getSender() == chat.getRecipient().getID()) { + chat.appendMessage(message); + break; } } @@ -283,8 +286,8 @@ public class LocalDB { public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } /** - * @return all saves {@link Chat} objects that list the client user as the - * client + * @return all saved {@link Chat} objects that list the client user as the + * sender * @since Envoy v0.1-alpha **/ public List getChats() { return chats; } From 6dad4eda08b0a9cb08bd2418d2bd18917b66f019 Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 5 Dec 2019 15:13:19 +0100 Subject: [PATCH 09/13] Fixed Envoy logo loading for StatusTrayIcon --- src/main/java/envoy/client/ui/StatusTrayIcon.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 951fbd4..94d30d0 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -44,7 +44,8 @@ public class StatusTrayIcon implements EventHandler { public StatusTrayIcon() throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - Image img = Toolkit.getDefaultToolkit().createImage(getClass().getResource("envoy_logo.png")); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); From 2831b9a7a362c34125419bc0a09329ed49a73451 Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 5 Dec 2019 15:42:20 +0100 Subject: [PATCH 10/13] Creating message notifications only if ChatWindow has lost focus StatusTray injects a WindowFocusListener into ChatWindow in its constructor and does only react to received messages if ChatWindow has currently lost focus. --- src/main/java/envoy/client/ui/Startup.java | 6 ++-- .../java/envoy/client/ui/StatusTrayIcon.java | 35 ++++++++++++++++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 7b35158..6333a60 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -63,9 +63,9 @@ public class Startup { EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client, localDB); - new StatusTrayIcon().show(); - frame.setVisible(true); + ChatWindow chatWindow = new ChatWindow(client, localDB); + new StatusTrayIcon(chatWindow).show(); + chatWindow.setVisible(true); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 94d30d0..827296d 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,6 +8,8 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.HashSet; import java.util.Set; @@ -16,6 +18,7 @@ import envoy.client.event.EventBus; import envoy.client.event.EventHandler; import envoy.client.event.MessageCreationEvent; import envoy.exception.EnvoyException; +import envoy.schema.Message; /** * Project: envoy-client
@@ -34,6 +37,12 @@ public class StatusTrayIcon implements EventHandler { */ private TrayIcon trayIcon; + /** + * A received {@link Message} is only displayed as a system tray notification if + * this variable is set to {@code true}. + */ + private boolean displayMessages = false; + /** * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up * menu. @@ -41,11 +50,11 @@ public class StatusTrayIcon implements EventHandler { * @throws EnvoyException if the currently used OS does not support the System * Tray API */ - public StatusTrayIcon() throws EnvoyException { + public StatusTrayIcon(ChatWindow chatWindow) throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Image img = Toolkit.getDefaultToolkit().createImage(loader.getResource("envoy_logo.png")); trayIcon = new TrayIcon(img, "Envoy Client"); trayIcon.setImageAutoSize(true); trayIcon.setToolTip("You are notified if you have unread messages."); @@ -57,6 +66,22 @@ public class StatusTrayIcon implements EventHandler { popup.add(exitMenuItem); trayIcon.setPopupMenu(popup); + + // Only display messages if the chat window is not focused + chatWindow.addWindowFocusListener(new WindowAdapter() { + + @Override + public void windowGainedFocus(WindowEvent e) { + displayMessages = false; + } + + @Override + public void windowLostFocus(WindowEvent e) { + displayMessages = true; + } + }); + + // Start processing message events EventBus.getInstance().register(this); } @@ -83,7 +108,9 @@ public class StatusTrayIcon implements EventHandler { */ @Override public void handle(Event event) { - trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); + System.out.println("Message received. Displaying message: " + displayMessages); + if (displayMessages) + trayIcon.displayMessage("New message received", ((MessageCreationEvent) event).get().getContent().get(0).getText(), MessageType.INFO); } /** From 6cf8c462b9da60516051cc4cedc7049a7867f5e7 Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 5 Dec 2019 16:10:28 +0100 Subject: [PATCH 11/13] Re-added logging to LocalDB to resolve merge conflict --- src/main/java/envoy/client/LocalDB.java | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d15e62a..d3ed430 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -9,6 +9,7 @@ import java.io.ObjectOutputStream; import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; @@ -43,6 +44,8 @@ public class LocalDB { private Sync sync = objectFactory.createSync(); private Sync readMessages = objectFactory.createSync(); + private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName()); + /** * Constructs an empty local database. * @@ -85,13 +88,13 @@ public class LocalDB { localDB.createNewFile(); } catch (IOException e) { e.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { out.writeObject(chats); } catch (IOException ex) { ex.printStackTrace(); - System.err.println("unable to save the messages"); + logger.warning("unable to save the messages"); } } @@ -141,7 +144,7 @@ public class LocalDB { sync.getMessages().addAll(readMessages.getMessages()); readMessages.getMessages().clear(); - System.out.println(sync.getMessages().size()); + logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size())); return sync; } @@ -189,24 +192,24 @@ public class LocalDB { break; case READ: // Update local Messages to state READ - System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (int j = 0; j < getChats().size(); j++) { if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - System.out.println("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + logger.info("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + "was selected."); getChats().get(j) .getModel() .get(k) .getMetadata() .setState(returnSync.getMessages().get(i).getMetadata().getState()); - System.out.println( + logger.info( "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); } } @@ -222,7 +225,7 @@ public class LocalDB { for (Chat chat : getChats()) if (user.getID() == chat.getRecipient().getID()) { chat.getRecipient().setStatus(user.getStatus()); - System.out.println(chat.getRecipient().getStatus()); + logger.info(chat.getRecipient().getStatus().toString()); } sync.getMessages().clear(); @@ -273,7 +276,7 @@ public class LocalDB { for (Chat chat : getChats()) for (int i = 0; i < chat.getModel().size(); i++) if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { - System.out.println("Got Waiting Message"); + logger.info("Got Waiting Message"); sync.getMessages().add(chat.getModel().get(i)); } } From 8247e18fce4517bce46ea2a6e91e6fb5dcf3ca84 Mon Sep 17 00:00:00 2001 From: kske Date: Thu, 5 Dec 2019 16:17:33 +0100 Subject: [PATCH 12/13] Javadoc fixes and using superclass when injecting WindowFocusListener --- src/main/java/envoy/client/LocalDB.java | 4 +++- src/main/java/envoy/client/ui/StatusTrayIcon.java | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d3ed430..8caea75 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -49,7 +49,7 @@ public class LocalDB { /** * Constructs an empty local database. * - * @param client the user that is logged in with this client + * @param sender the user that is logged in with this client * @since Envoy v0.1-alpha */ public LocalDB(User sender) { @@ -118,7 +118,9 @@ public class LocalDB { * Creates a {@link Message} object serializable to XML. * * @param textContent The content (text) of the message + * @param recipient The recipient of the message * @return prepared {@link Message} object + * @since Envoy v0.1-alpha */ public Message createMessage(String textContent, User recipient) { Message.Metadata metaData = objectFactory.createMessageMetadata(); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 827296d..01cc8d7 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,6 +8,7 @@ import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.TrayIcon.MessageType; +import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashSet; @@ -46,11 +47,14 @@ public class StatusTrayIcon implements EventHandler { /** * Creates a {@link StatusTrayIcon} with the Envoy logo, a tool tip and a pop-up * menu. - * + * + * @param focusTarget the {@link Window} which focus determines if message + * notifications are displayed * @throws EnvoyException if the currently used OS does not support the System * Tray API + * @since Envoy v0.2-alpha */ - public StatusTrayIcon(ChatWindow chatWindow) throws EnvoyException { + public StatusTrayIcon(Window focusTarget) throws EnvoyException { if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); ClassLoader loader = Thread.currentThread().getContextClassLoader(); @@ -68,7 +72,7 @@ public class StatusTrayIcon implements EventHandler { trayIcon.setPopupMenu(popup); // Only display messages if the chat window is not focused - chatWindow.addWindowFocusListener(new WindowAdapter() { + focusTarget.addWindowFocusListener(new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent e) { @@ -103,7 +107,7 @@ public class StatusTrayIcon implements EventHandler { /** * Notifies the user of a message by displaying a pop-up every time a new * message is received. - * + * * @since Envoy v0.2-alpha */ @Override @@ -116,7 +120,7 @@ public class StatusTrayIcon implements EventHandler { /** * The {@link StatusTrayIcon} only reacts to {@link MessageCreationEvent} * instances which signify newly received messages. - * + * * @return A set with the single element {@code MessageCreationEvent.class} * @since Envoy v0.2-alpha */ From 8f7e115219f5713f2f277eab42739a76c849aaee Mon Sep 17 00:00:00 2001 From: kske Date: Sat, 7 Dec 2019 09:53:55 +0100 Subject: [PATCH 13/13] Implemented changes requested by @delvh --- .settings/org.eclipse.jdt.core.prefs | 99 +++++++++++++++++++ src/main/java/envoy/client/LocalDB.java | 67 ++++++------- src/main/java/envoy/client/ui/ChatWindow.java | 1 + 3 files changed, 131 insertions(+), 36 deletions(-) diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index cb635b1..262bd4f 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,107 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 1989f89..3929315 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -140,6 +140,13 @@ public class LocalDB { return message; } + /** + * Creates a {@link Sync} object filled with the changes that occurred to the + * local database since the last synchronization. + * + * @param userId the ID of the user that is synchronized by this client + * @return {@link Sync} object filled with the current changes + */ public Sync fillSync(long userId) { addWaitingMessagesToSync(); @@ -150,6 +157,11 @@ public class LocalDB { return sync; } + /** + * Applies the changes carried by a {@link Sync} object to the local database + * + * @param returnSync the {@link Sync} object to apply + */ public void applySync(Sync returnSync) { for (int i = 0; i < returnSync.getMessages().size(); i++) { @@ -173,50 +185,33 @@ public class LocalDB { EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); } else { // Update Messages in localDB to state RECEIVED - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - // Update Message in LocalDB - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(j).getMetadata().getState()); - } - } - } - } + for (Chat chat : getChats()) + if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) + for (int j = 0; j < chat.getModel().getSize(); j++) + if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() + .get(i) + .getMetadata() + .getMessageId()) + chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); } break; case READ: // Update local Messages to state READ logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); - for (int j = 0; j < getChats().size(); j++) { - if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); - for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { - if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() + for (Chat chat : getChats()) + if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + logger.info("Chat with: " + chat.getRecipient().getID() + "was selected."); + for (int k = 0; k < chat.getModel().getSize(); k++) + if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) .getMetadata() .getMessageId()) { - logger.info("Message with ID: " + getChats().get(j).getModel().get(k).getMetadata().getMessageId() - + "was selected."); - getChats().get(j) - .getModel() - .get(k) - .getMetadata() - .setState(returnSync.getMessages().get(i).getMetadata().getState()); - logger.info( - "Message State is now: " + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + logger.info("Message with ID: " + chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); + chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + logger.info("Message State is now: " + chat.getModel().get(k).getMetadata().getState()); } - } } - } break; } } @@ -242,9 +237,9 @@ public class LocalDB { * @since Envoy v0.1-alpha */ public void addUnreadMessagesToLocalDB() { - for(Message message : unreadMessagesSync.getMessages()) - for(Chat chat : getChats()) - if(message.getMetadata().getSender() == chat.getRecipient().getID()) { + for (Message message : unreadMessagesSync.getMessages()) + for (Chat chat : getChats()) + if (message.getMetadata().getSender() == chat.getRecipient().getID()) { chat.appendMessage(message); break; } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index cefe886..e6e6872 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -257,6 +257,7 @@ public class ChatWindow extends JFrame { private void postMessage(JList messageList) { if (!client.hasRecipient()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); + return; } if (!messageEnterTextArea.getText().isEmpty()) try {