Merge branch 'develop' into f/password_in_login_credentials
This commit is contained in:
		
							
								
								
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ | |||||||
| 		<dependency> | 		<dependency> | ||||||
| 			<groupId>com.github.informatik-ag-ngl</groupId> | 			<groupId>com.github.informatik-ag-ngl</groupId> | ||||||
| 			<artifactId>envoy-common</artifactId> | 			<artifactId>envoy-common</artifactId> | ||||||
| 			<version>f~password_in_login_credentials-SNAPSHOT</version> | 			<version>develop-SNAPSHOT</version> | ||||||
| 		</dependency> | 		</dependency> | ||||||
| 		<dependency> | 		<dependency> | ||||||
| 			<groupId>org.openjfx</groupId> | 			<groupId>org.openjfx</groupId> | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy Client v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class Cache<T> implements Consumer<T>, Serializable { | public final class Cache<T> implements Consumer<T>, Serializable { | ||||||
|  |  | ||||||
| 	private final Queue<T>			elements	= new LinkedList<>(); | 	private final Queue<T>			elements	= new LinkedList<>(); | ||||||
| 	private transient Consumer<T>	processor; | 	private transient Consumer<T>	processor; | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								src/main/java/envoy/client/data/CacheMap.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/main/java/envoy/client/data/CacheMap.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | package envoy.client.data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Stores a heterogeneous map of {@link Cache} objects with different type | ||||||
|  |  * parameters. | ||||||
|  |  * <p> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>CacheMap.java</strong><br> | ||||||
|  |  * Created: <strong>09.07.2020</strong><br> | ||||||
|  |  *  | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public final class CacheMap implements Serializable { | ||||||
|  |  | ||||||
|  | 	private final Map<Class<?>, Cache<?>> map = new HashMap<>(); | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = 1L; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Adds a cache to the map. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param <T>   the type accepted by the cache | ||||||
|  | 	 * @param key   the class that maps to the cache | ||||||
|  | 	 * @param cache the cache to store | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public <T> void put(Class<T> key, Cache<T> cache) { map.put(key, cache); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Returns a cache mapped by a class. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param <T> the type accepted by the cache | ||||||
|  | 	 * @param key the class that maps to the cache | ||||||
|  | 	 * @return the cache | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public <T> Cache<T> get(Class<T> key) { return (Cache<T>) map.get(key); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Returns a cache mapped by a class or any of its subclasses. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param <T> the type accepted by the cache | ||||||
|  | 	 * @param key the class that maps to the cache | ||||||
|  | 	 * @return the cache | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public <T> Cache<? super T> getApplicable(Class<T> key) { | ||||||
|  | 		Cache<? super T> cache = get(key); | ||||||
|  | 		if (cache == null) | ||||||
|  | 			for (var e : map.entrySet()) | ||||||
|  | 				if (e.getKey().isAssignableFrom(key)) | ||||||
|  | 					cache = (Cache<? super T>) e.getValue(); | ||||||
|  | 		return cache; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the map in which the caches are stored | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<Class<?>, Cache<?>> getMap() { return map; } | ||||||
|  | } | ||||||
| @@ -20,12 +20,16 @@ import envoy.event.NameChange; | |||||||
|  */ |  */ | ||||||
| public abstract class LocalDB { | public abstract class LocalDB { | ||||||
|  |  | ||||||
| 	protected User							user; | 	protected User					user; | ||||||
| 	protected Map<String, Contact>			users			= new HashMap<>(); | 	protected Map<String, Contact>	users		= new HashMap<>(); | ||||||
| 	protected List<Chat>					chats			= new ArrayList<>(); | 	protected List<Chat>			chats		= new ArrayList<>(); | ||||||
| 	protected IDGenerator					idGenerator; | 	protected IDGenerator			idGenerator; | ||||||
| 	protected Cache<Message>				messageCache	= new Cache<>(); | 	protected CacheMap				cacheMap	= new CacheMap(); | ||||||
| 	protected Cache<MessageStatusChange>	statusCache		= new Cache<>(); |  | ||||||
|  | 	{ | ||||||
|  | 		cacheMap.put(Message.class, new Cache<>()); | ||||||
|  | 		cacheMap.put(MessageStatusChange.class, new Cache<>()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Initializes a storage space for a user-specific list of chats. | 	 * Initializes a storage space for a user-specific list of chats. | ||||||
| @@ -139,28 +143,10 @@ public abstract class LocalDB { | |||||||
| 	public boolean hasIDGenerator() { return idGenerator != null; } | 	public boolean hasIDGenerator() { return idGenerator != null; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the offline message cache | 	 * @return the cache map for messages and message status changes | ||||||
| 	 * @since Envoy Client v0.3-alpha | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public Cache<Message> getMessageCache() { return messageCache; } | 	public CacheMap getCacheMap() { return cacheMap; } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @param messageCache the offline message cache to set |  | ||||||
| 	 * @since Envoy Client v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public void setMessageCache(Cache<Message> messageCache) { this.messageCache = messageCache; } |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @return the offline status cache |  | ||||||
| 	 * @since Envoy Client v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public Cache<MessageStatusChange> getStatusCache() { return statusCache; } |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @param statusCache the offline status cache to set |  | ||||||
| 	 * @since Envoy Client v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public void setStatusCache(Cache<MessageStatusChange> statusCache) { this.statusCache = statusCache; } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Searches for a message by ID. | 	 * Searches for a message by ID. | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ import java.util.ArrayList; | |||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  |  | ||||||
| import envoy.data.IDGenerator; | import envoy.data.IDGenerator; | ||||||
| import envoy.data.Message; |  | ||||||
| import envoy.event.MessageStatusChange; |  | ||||||
| import envoy.util.SerializationUtils; | import envoy.util.SerializationUtils; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -64,7 +62,7 @@ public final class PersistentLocalDB extends LocalDB { | |||||||
| 		SerializationUtils.write(usersFile, users); | 		SerializationUtils.write(usersFile, users); | ||||||
|  |  | ||||||
| 		// Save user data | 		// Save user data | ||||||
| 		if (user != null) SerializationUtils.write(userFile, chats, messageCache, statusCache); | 		if (user != null) SerializationUtils.write(userFile, chats, cacheMap); | ||||||
|  |  | ||||||
| 		// Save id generator | 		// Save id generator | ||||||
| 		if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); | 		if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); | ||||||
| @@ -76,9 +74,8 @@ public final class PersistentLocalDB extends LocalDB { | |||||||
| 	@Override | 	@Override | ||||||
| 	public void loadUserData() throws ClassNotFoundException, IOException { | 	public void loadUserData() throws ClassNotFoundException, IOException { | ||||||
| 		try (var in = new ObjectInputStream(new FileInputStream(userFile))) { | 		try (var in = new ObjectInputStream(new FileInputStream(userFile))) { | ||||||
| 			chats = (ArrayList<Chat>) in.readObject(); | 			chats		= (ArrayList<Chat>) in.readObject(); | ||||||
| 			messageCache	= (Cache<Message>) in.readObject(); | 			cacheMap	= (CacheMap) in.readObject(); | ||||||
| 			statusCache		= (Cache<MessageStatusChange>) in.readObject(); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ import java.util.concurrent.TimeoutException; | |||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
|  |  | ||||||
| import envoy.client.data.Cache; | import envoy.client.data.*; | ||||||
| import envoy.client.data.ClientConfig; |  | ||||||
| import envoy.client.data.LocalDB; |  | ||||||
| import envoy.client.event.SendEvent; | import envoy.client.event.SendEvent; | ||||||
| import envoy.data.*; | import envoy.data.*; | ||||||
| import envoy.event.*; | import envoy.event.*; | ||||||
| @@ -53,34 +51,14 @@ public class Client implements Closeable { | |||||||
| 	 * will block for up to 5 seconds. If the handshake does exceed this time limit, | 	 * will block for up to 5 seconds. If the handshake does exceed this time limit, | ||||||
| 	 * an exception is thrown. | 	 * an exception is thrown. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param credentials                           the login credentials of the | 	 * @param credentials the login credentials of the user | ||||||
| 	 *                                              user | 	 * @param cacheMap    the map of all caches needed | ||||||
| 	 * @param receivedMessageCache                  a message cache containing all |  | ||||||
| 	 *                                              unread messages from the server |  | ||||||
| 	 *                                              that can be relayed after |  | ||||||
| 	 *                                              initialization |  | ||||||
| 	 * @param receivedGroupMessageCache             a groupMessage cache containing |  | ||||||
| 	 *                                              all unread groupMessages from |  | ||||||
| 	 *                                              the server that can be relayed |  | ||||||
| 	 *                                              after initialization |  | ||||||
| 	 * @param receivedMessageStatusChangeCache      an event cache containing all |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              messageStatusChangeEvents from |  | ||||||
| 	 *                                              the server that can be relayed |  | ||||||
| 	 *                                              after initialization |  | ||||||
| 	 * @param receivedGroupMessageStatusChangeCache an event cache containing all |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              groupMessageStatusChangeEvents |  | ||||||
| 	 *                                              from the server that can be |  | ||||||
| 	 *                                              relayed after initialization |  | ||||||
| 	 * @throws TimeoutException     if the server could not be reached | 	 * @throws TimeoutException     if the server could not be reached | ||||||
| 	 * @throws IOException          if the login credentials could not be written | 	 * @throws IOException          if the login credentials could not be written | ||||||
| 	 * @throws InterruptedException if the current thread is interrupted while | 	 * @throws InterruptedException if the current thread is interrupted while | ||||||
| 	 *                              waiting for the handshake response | 	 *                              waiting for the handshake response | ||||||
| 	 */ | 	 */ | ||||||
| 	public void performHandshake(LoginCredentials credentials, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache, | 	public void performHandshake(LoginCredentials credentials, CacheMap cacheMap) throws TimeoutException, IOException, InterruptedException { | ||||||
| 			Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache) |  | ||||||
| 			throws TimeoutException, IOException, InterruptedException { |  | ||||||
| 		if (online) throw new IllegalStateException("Handshake has already been performed successfully"); | 		if (online) throw new IllegalStateException("Handshake has already been performed successfully"); | ||||||
|  |  | ||||||
| 		// Establish TCP connection | 		// Establish TCP connection | ||||||
| @@ -93,10 +71,7 @@ public class Client implements Closeable { | |||||||
|  |  | ||||||
| 		// Register user creation processor, contact list processor and message cache | 		// Register user creation processor, contact list processor and message cache | ||||||
| 		receiver.registerProcessor(User.class, sender -> this.sender = sender); | 		receiver.registerProcessor(User.class, sender -> this.sender = sender); | ||||||
| 		receiver.registerProcessor(Message.class, receivedMessageCache); | 		receiver.registerProcessors(cacheMap.getMap()); | ||||||
| 		receiver.registerProcessor(GroupMessage.class, receivedGroupMessageCache); |  | ||||||
| 		receiver.registerProcessor(MessageStatusChange.class, receivedMessageStatusChangeCache); |  | ||||||
| 		receiver.registerProcessor(GroupMessageStatusChange.class, receivedGroupMessageStatusChangeCache); |  | ||||||
| 		receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); }); | 		receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); }); | ||||||
|  |  | ||||||
| 		rejected = false; | 		rejected = false; | ||||||
| @@ -125,9 +100,6 @@ public class Client implements Closeable { | |||||||
|  |  | ||||||
| 		online = true; | 		online = true; | ||||||
|  |  | ||||||
| 		// Remove all processors as they are only used during the handshake |  | ||||||
| 		receiver.removeAllProcessors(); |  | ||||||
|  |  | ||||||
| 		logger.log(Level.INFO, "Handshake completed."); | 		logger.log(Level.INFO, "Handshake completed."); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -135,65 +107,35 @@ public class Client implements Closeable { | |||||||
| 	 * Initializes the {@link Receiver} used to process data sent from the server to | 	 * Initializes the {@link Receiver} used to process data sent from the server to | ||||||
| 	 * this client. | 	 * this client. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param localDB                               the local database used to | 	 * @param localDB  the local database used to persist the current | ||||||
| 	 *                                              persist | 	 *                 {@link IDGenerator} | ||||||
| 	 *                                              the current | 	 * @param cacheMap the map of all caches needed | ||||||
| 	 *                                              {@link IDGenerator} |  | ||||||
| 	 * @param receivedMessageCache                  a message cache containing all |  | ||||||
| 	 *                                              unread |  | ||||||
| 	 *                                              messages |  | ||||||
| 	 *                                              from the server that can be |  | ||||||
| 	 *                                              relayed |  | ||||||
| 	 *                                              after |  | ||||||
| 	 *                                              initialization |  | ||||||
| 	 * @param receivedGroupMessageCache             a groupMessage cache containing |  | ||||||
| 	 *                                              all |  | ||||||
| 	 *                                              unread |  | ||||||
| 	 *                                              groupMessages |  | ||||||
| 	 *                                              from the server that can be |  | ||||||
| 	 *                                              relayed |  | ||||||
| 	 *                                              after |  | ||||||
| 	 *                                              initialization |  | ||||||
| 	 * @param receivedMessageStatusChangeCache      an event cache containing all |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              messageStatusChangeEvents |  | ||||||
| 	 *                                              from the server that can be |  | ||||||
| 	 *                                              relayed |  | ||||||
| 	 *                                              after initialization |  | ||||||
| 	 * @param receivedGroupMessageStatusChangeCache an event cache containing all |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              groupMessageStatusChangeEvents |  | ||||||
| 	 *                                              from the server that can be |  | ||||||
| 	 *                                              relayed after initialization |  | ||||||
| 	 * @throws IOException if no {@link IDGenerator} is present and none could be | 	 * @throws IOException if no {@link IDGenerator} is present and none could be | ||||||
| 	 *                     requested from the server | 	 *                     requested from the server | ||||||
| 	 * @since Envoy Client v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void initReceiver(LocalDB localDB, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache, | 	public void initReceiver(LocalDB localDB, CacheMap cacheMap) throws IOException { | ||||||
| 			Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache) |  | ||||||
| 			throws IOException { |  | ||||||
| 		checkOnline(); | 		checkOnline(); | ||||||
|  |  | ||||||
|  | 		// Remove all processors as they are only used during the handshake | ||||||
|  | 		receiver.removeAllProcessors(); | ||||||
|  |  | ||||||
| 		// Process incoming messages | 		// Process incoming messages | ||||||
| 		final ReceivedMessageProcessor			receivedMessageProcessor			= new ReceivedMessageProcessor(); | 		final var	receivedMessageProcessor			= new ReceivedMessageProcessor(); | ||||||
| 		final ReceivedGroupMessageProcessor		receivedGroupMessageProcessor		= new ReceivedGroupMessageProcessor(); | 		final var	receivedGroupMessageProcessor		= new ReceivedGroupMessageProcessor(); | ||||||
| 		final MessageStatusChangeProcessor		messageStatusChangeProcessor		= new MessageStatusChangeProcessor(); | 		final var	messageStatusChangeProcessor		= new MessageStatusChangeProcessor(); | ||||||
| 		final GroupMessageStatusChangeProcessor	groupMessageStatusChangeProcessor	= new GroupMessageStatusChangeProcessor(); | 		final var	groupMessageStatusChangeProcessor	= new GroupMessageStatusChangeProcessor(); | ||||||
|  |  | ||||||
| 		receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor); | 		receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor); | ||||||
|  |  | ||||||
| 		receiver.registerProcessor(Message.class, receivedMessageProcessor); | 		receiver.registerProcessor(Message.class, receivedMessageProcessor); | ||||||
|  |  | ||||||
| 		receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor); | 		receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor); | ||||||
|  |  | ||||||
| 		receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor); | 		receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor); | ||||||
| 		// Relay cached unread messages and unread groupMessages |  | ||||||
| 		receivedMessageCache.setProcessor(receivedMessageProcessor); |  | ||||||
| 		receivedGroupMessageCache.setProcessor(receivedGroupMessageProcessor); |  | ||||||
|  |  | ||||||
| 		// Process message status changes | 		// Relay cached messages and message status changes | ||||||
| 		receivedMessageStatusChangeCache.setProcessor(messageStatusChangeProcessor); | 		cacheMap.get(Message.class).setProcessor(receivedMessageProcessor); | ||||||
| 		receivedGroupMessageStatusChangeCache.setProcessor(groupMessageStatusChangeProcessor); | 		cacheMap.get(GroupMessage.class).setProcessor(receivedGroupMessageProcessor); | ||||||
|  | 		cacheMap.get(MessageStatusChange.class).setProcessor(messageStatusChangeProcessor); | ||||||
|  | 		cacheMap.get(GroupMessageStatusChange.class).setProcessor(groupMessageStatusChangeProcessor); | ||||||
|  |  | ||||||
| 		// Process user status changes | 		// Process user status changes | ||||||
| 		receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch); | 		receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch); | ||||||
| @@ -224,18 +166,10 @@ public class Client implements Closeable { | |||||||
|  |  | ||||||
| 		// Request a generator if none is present or the existing one is consumed | 		// Request a generator if none is present or the existing one is consumed | ||||||
| 		if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext()) requestIdGenerator(); | 		if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext()) requestIdGenerator(); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** | 		// Relay caches | ||||||
| 	 * Creates a new write proxy that uses this client to communicate with the | 		cacheMap.getMap().values().forEach(Cache::relay); | ||||||
| 	 * server. | 	} | ||||||
| 	 * |  | ||||||
| 	 * @param localDB the local database that the write proxy will use to access |  | ||||||
| 	 *                caches |  | ||||||
| 	 * @return a new write proxy |  | ||||||
| 	 * @since Envoy Client v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public WriteProxy createWriteProxy(LocalDB localDB) { return new WriteProxy(this, localDB); } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Sends a message to the server. The message's status will be incremented once | 	 * Sends a message to the server. The message's status will be incremented once | ||||||
|   | |||||||
| @@ -79,9 +79,7 @@ public class Receiver extends Thread { | |||||||
| 					@SuppressWarnings("rawtypes") | 					@SuppressWarnings("rawtypes") | ||||||
| 					final Consumer processor = processors.get(obj.getClass()); | 					final Consumer processor = processors.get(obj.getClass()); | ||||||
| 					if (processor == null) | 					if (processor == null) | ||||||
| 						logger.log(Level.WARNING, String.format( | 						logger.log(Level.WARNING, String.format("The received object has the %s for which no processor is defined.", obj.getClass())); | ||||||
| 										"The received object has the %s for which no processor is defined.", |  | ||||||
| 										obj.getClass())); |  | ||||||
| 					else processor.accept(obj); | 					else processor.accept(obj); | ||||||
| 				} | 				} | ||||||
| 			} catch (final SocketException e) { | 			} catch (final SocketException e) { | ||||||
| @@ -103,6 +101,14 @@ public class Receiver extends Thread { | |||||||
| 	 */ | 	 */ | ||||||
| 	public <T> void registerProcessor(Class<T> processorClass, Consumer<T> processor) { processors.put(processorClass, processor); } | 	public <T> void registerProcessor(Class<T> processorClass, Consumer<T> processor) { processors.put(processorClass, processor); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Adds a map of object processors to this {@link Receiver}. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param processors the processors to add the processors to add | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void registerProcessors(Map<Class<?>, ? extends Consumer<?>> processors) { this.processors.putAll(processors); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Removes all object processors registered at this {@link Receiver}. | 	 * Removes all object processors registered at this {@link Receiver}. | ||||||
| 	 * | 	 * | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import java.io.IOException; | |||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
|  |  | ||||||
|  | import envoy.client.data.Cache; | ||||||
| import envoy.client.data.LocalDB; | import envoy.client.data.LocalDB; | ||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
| import envoy.event.MessageStatusChange; | import envoy.event.MessageStatusChange; | ||||||
| @@ -43,7 +44,7 @@ public class WriteProxy { | |||||||
| 		this.localDB	= localDB; | 		this.localDB	= localDB; | ||||||
|  |  | ||||||
| 		// Initialize cache processors for messages and message status change events | 		// Initialize cache processors for messages and message status change events | ||||||
| 		localDB.getMessageCache().setProcessor(msg -> { | 		localDB.getCacheMap().get(Message.class).setProcessor(msg -> { | ||||||
| 			try { | 			try { | ||||||
| 				logger.log(Level.FINER, "Sending cached " + msg); | 				logger.log(Level.FINER, "Sending cached " + msg); | ||||||
| 				client.sendMessage(msg); | 				client.sendMessage(msg); | ||||||
| @@ -51,7 +52,7 @@ public class WriteProxy { | |||||||
| 				logger.log(Level.SEVERE, "Could not send cached message: ", e); | 				logger.log(Level.SEVERE, "Could not send cached message: ", e); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		localDB.getStatusCache().setProcessor(evt -> { | 		localDB.getCacheMap().get(MessageStatusChange.class).setProcessor(evt -> { | ||||||
| 			logger.log(Level.FINER, "Sending cached " + evt); | 			logger.log(Level.FINER, "Sending cached " + evt); | ||||||
| 			try { | 			try { | ||||||
| 				client.sendEvent(evt); | 				client.sendEvent(evt); | ||||||
| @@ -68,11 +69,7 @@ public class WriteProxy { | |||||||
| 	 * @since Envoy Client v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void flushCache() { | 	public void flushCache() { | ||||||
| 		// Send messages | 		localDB.getCacheMap().getMap().values().forEach(Cache::relay); | ||||||
| 		localDB.getMessageCache().relay(); |  | ||||||
|  |  | ||||||
| 		// Send message status change events |  | ||||||
| 		localDB.getStatusCache().relay(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -85,7 +82,7 @@ public class WriteProxy { | |||||||
| 	 */ | 	 */ | ||||||
| 	public void writeMessage(Message message) throws IOException { | 	public void writeMessage(Message message) throws IOException { | ||||||
| 		if (client.isOnline()) client.sendMessage(message); | 		if (client.isOnline()) client.sendMessage(message); | ||||||
| 		else localDB.getMessageCache().accept(message); | 		else localDB.getCacheMap().getApplicable(Message.class).accept(message); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -98,6 +95,6 @@ public class WriteProxy { | |||||||
| 	 */ | 	 */ | ||||||
| 	public void writeMessageStatusChange(MessageStatusChange evt) throws IOException { | 	public void writeMessageStatusChange(MessageStatusChange evt) throws IOException { | ||||||
| 		if (client.isOnline()) client.sendEvent(evt); | 		if (client.isOnline()) client.sendEvent(evt); | ||||||
| 		else localDB.getStatusCache().accept(evt); | 		else localDB.getCacheMap().getApplicable(MessageStatusChange.class).accept(evt); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -42,12 +42,8 @@ public final class Startup extends Application { | |||||||
| 	 */ | 	 */ | ||||||
| 	public static final String VERSION = "0.1-beta"; | 	public static final String VERSION = "0.1-beta"; | ||||||
|  |  | ||||||
| 	private LocalDB						localDB; | 	private LocalDB	localDB; | ||||||
| 	private Client						client; | 	private Client	client; | ||||||
| 	private Cache<Message>				messageCache; |  | ||||||
| 	private Cache<GroupMessage>			groupMessageCache; |  | ||||||
| 	private Cache<MessageStatusChange>	messageStatusCache; |  | ||||||
| 	private Cache<GroupMessageStatusChange>	groupMessageStatusCache; |  | ||||||
|  |  | ||||||
| 	private static final ClientConfig	config	= ClientConfig.getInstance(); | 	private static final ClientConfig	config	= ClientConfig.getInstance(); | ||||||
| 	private static final Logger			logger	= EnvoyLog.getLogger(Startup.class); | 	private static final Logger			logger	= EnvoyLog.getLogger(Startup.class); | ||||||
| @@ -101,19 +97,20 @@ public final class Startup extends Application { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Initialize client and unread message cache | 		// Initialize client and unread message cache | ||||||
| 		client				= new Client(); | 		client = new Client(); | ||||||
| 		messageCache		= new Cache<>(); |  | ||||||
| 		groupMessageCache	= new Cache<>(); | 		final var cacheMap = new CacheMap(); | ||||||
| 		messageStatusCache	= new Cache<>(); | 		cacheMap.put(Message.class, new Cache<Message>()); | ||||||
| 		groupMessageStatusCache	= new Cache<>(); | 		cacheMap.put(GroupMessage.class, new Cache<GroupMessage>()); | ||||||
|  | 		cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>()); | ||||||
|  | 		cacheMap.put(GroupMessageStatusChange.class, new Cache<GroupMessageStatusChange>()); | ||||||
|  |  | ||||||
| 		stage.setTitle("Envoy"); | 		stage.setTitle("Envoy"); | ||||||
| 		stage.getIcons().add(IconUtil.loadIcon("envoy_logo")); | 		stage.getIcons().add(IconUtil.loadIcon("envoy_logo")); | ||||||
|  |  | ||||||
| 		final var sceneContext = new SceneContext(stage); | 		final var sceneContext = new SceneContext(stage); | ||||||
| 		sceneContext.load(SceneInfo.LOGIN_SCENE); | 		sceneContext.load(SceneInfo.LOGIN_SCENE); | ||||||
| 		sceneContext.<LoginScene>getController() | 		sceneContext.<LoginScene>getController().initializeData(client, localDB, cacheMap, sceneContext); | ||||||
| 			.initializeData(client, localDB, messageCache, groupMessageCache, messageStatusCache, groupMessageStatusCache, sceneContext); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -430,24 +430,6 @@ public final class ChatScene implements Restorable { | |||||||
|  |  | ||||||
| 	// Context menu actions | 	// Context menu actions | ||||||
| 	 | 	 | ||||||
| 	@FXML |  | ||||||
| 	private void copyMessage() { |  | ||||||
| 		try { |  | ||||||
| 			Toolkit.getDefaultToolkit() |  | ||||||
| 				.getSystemClipboard() |  | ||||||
| 				.setContents(new StringSelection(messageList.getSelectionModel().getSelectedItem().getText()), null); |  | ||||||
| 		} catch (final NullPointerException e) {} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@FXML |  | ||||||
| 	private void deleteMessage() { try {} catch (final NullPointerException e) {} } |  | ||||||
|  |  | ||||||
| 	@FXML |  | ||||||
| 	private void forwardMessage() { try {} catch (final NullPointerException e) {} } |  | ||||||
|  |  | ||||||
| 	@FXML |  | ||||||
| 	private void quoteMessage() { try {} catch (final NullPointerException e) {} } |  | ||||||
|  |  | ||||||
| 	@FXML | 	@FXML | ||||||
| 	private void deleteContact() { try {} catch (final NullPointerException e) {} } | 	private void deleteContact() { try {} catch (final NullPointerException e) {} } | ||||||
|  |  | ||||||
| @@ -460,7 +442,4 @@ public final class ChatScene implements Restorable { | |||||||
| 		updateRemainingCharsLabel(); | 		updateRemainingCharsLabel(); | ||||||
| 		postButton.setDisable(messageText.isBlank()); | 		postButton.setDisable(messageText.isBlank()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@FXML |  | ||||||
| 	private void loadMessageInfoScene() { try {} catch (final NullPointerException e) {} } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,12 +13,15 @@ import javafx.scene.control.Alert.AlertType; | |||||||
|  |  | ||||||
| import envoy.client.data.*; | import envoy.client.data.*; | ||||||
| import envoy.client.net.Client; | import envoy.client.net.Client; | ||||||
|  | import envoy.client.net.WriteProxy; | ||||||
| import envoy.client.ui.ClearableTextField; | import envoy.client.ui.ClearableTextField; | ||||||
| import envoy.client.ui.SceneContext; | import envoy.client.ui.SceneContext; | ||||||
| import envoy.client.ui.Startup; | import envoy.client.ui.Startup; | ||||||
| import envoy.data.*; | import envoy.data.LoginCredentials; | ||||||
|  | import envoy.data.User; | ||||||
| import envoy.data.User.UserStatus; | import envoy.data.User.UserStatus; | ||||||
| import envoy.event.*; | import envoy.event.EventBus; | ||||||
|  | import envoy.event.HandshakeRejection; | ||||||
| import envoy.exception.EnvoyException; | import envoy.exception.EnvoyException; | ||||||
| import envoy.util.Bounds; | import envoy.util.Bounds; | ||||||
| import envoy.util.EnvoyLog; | import envoy.util.EnvoyLog; | ||||||
| @@ -52,13 +55,10 @@ public final class LoginScene { | |||||||
| 	@FXML | 	@FXML | ||||||
| 	private Label connectionLabel; | 	private Label connectionLabel; | ||||||
|  |  | ||||||
| 	private Client							client; | 	private Client			client; | ||||||
| 	private LocalDB							localDB; | 	private LocalDB			localDB; | ||||||
| 	private Cache<Message>					receivedMessageCache; | 	private CacheMap		cacheMap; | ||||||
| 	private Cache<GroupMessage>				receivedGroupMessageCache; | 	private SceneContext	sceneContext; | ||||||
| 	private Cache<MessageStatusChange>		receivedMessageStatusChangeCache; |  | ||||||
| 	private Cache<GroupMessageStatusChange>	receivedGroupMessageStatusChangeCache; |  | ||||||
| 	private SceneContext					sceneContext; |  | ||||||
|  |  | ||||||
| 	private static final Logger			logger		= EnvoyLog.getLogger(LoginScene.class); | 	private static final Logger			logger		= EnvoyLog.getLogger(LoginScene.class); | ||||||
| 	private static final EventBus		eventBus	= EventBus.getInstance(); | 	private static final EventBus		eventBus	= EventBus.getInstance(); | ||||||
| @@ -75,41 +75,17 @@ public final class LoginScene { | |||||||
| 	/** | 	/** | ||||||
| 	 * Loads the login dialog using the FXML file {@code LoginDialog.fxml}. | 	 * Loads the login dialog using the FXML file {@code LoginDialog.fxml}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param client                                the client used to perform the | 	 * @param client       the client used to perform the handshake | ||||||
| 	 *                                              handshake | 	 * @param localDB      the local database used for offline login | ||||||
| 	 * @param localDB                               the local database used for | 	 * @param cacheMap     the map of all caches needed | ||||||
| 	 *                                              offline | 	 * @param sceneContext the scene context used to initialize the chat scene | ||||||
| 	 *                                              login |  | ||||||
| 	 * @param receivedMessageCache                  the cache storing messages |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              during |  | ||||||
| 	 *                                              the handshake |  | ||||||
| 	 * @param receivedGroupMessageCache             the cache storing groupMessages |  | ||||||
| 	 *                                              received during the handshake |  | ||||||
| 	 * @param receivedMessageStatusChangeCache      the cache storing |  | ||||||
| 	 *                                              messageStatusChangeEvents |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              during handshake |  | ||||||
| 	 * @param receivedGroupMessageStatusChangeCache the cache storing |  | ||||||
| 	 *                                              groupMessageStatusChangeEvents |  | ||||||
| 	 *                                              received |  | ||||||
| 	 *                                              during handshake |  | ||||||
| 	 * @param sceneContext                          the scene context used to |  | ||||||
| 	 *                                              initialize |  | ||||||
| 	 *                                              the chat |  | ||||||
| 	 *                                              scene |  | ||||||
| 	 * @since Envoy Client v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public void initializeData(Client client, LocalDB localDB, Cache<Message> receivedMessageCache, Cache<GroupMessage> receivedGroupMessageCache, | 	public void initializeData(Client client, LocalDB localDB, CacheMap cacheMap, SceneContext sceneContext) { | ||||||
| 			Cache<MessageStatusChange> receivedMessageStatusChangeCache, Cache<GroupMessageStatusChange> receivedGroupMessageStatusChangeCache, | 		this.client			= client; | ||||||
| 			SceneContext sceneContext) { | 		this.localDB		= localDB; | ||||||
| 		this.client									= client; | 		this.cacheMap		= cacheMap; | ||||||
| 		this.localDB								= localDB; | 		this.sceneContext	= sceneContext; | ||||||
| 		this.receivedMessageCache					= receivedMessageCache; |  | ||||||
| 		this.receivedGroupMessageCache				= receivedGroupMessageCache; |  | ||||||
| 		this.receivedMessageStatusChangeCache		= receivedMessageStatusChangeCache; |  | ||||||
| 		this.receivedGroupMessageStatusChangeCache	= receivedGroupMessageStatusChangeCache; |  | ||||||
| 		this.sceneContext							= sceneContext; |  | ||||||
|  |  | ||||||
| 		// Prepare handshake | 		// Prepare handshake | ||||||
| 		localDB.loadIDGenerator(); | 		localDB.loadIDGenerator(); | ||||||
| @@ -156,18 +132,10 @@ public final class LoginScene { | |||||||
|  |  | ||||||
| 	private void performHandshake(LoginCredentials credentials) { | 	private void performHandshake(LoginCredentials credentials) { | ||||||
| 		try { | 		try { | ||||||
| 			client.performHandshake(credentials, | 			client.performHandshake(credentials, cacheMap); | ||||||
| 					receivedMessageCache, |  | ||||||
| 					receivedGroupMessageCache, |  | ||||||
| 					receivedMessageStatusChangeCache, |  | ||||||
| 					receivedGroupMessageStatusChangeCache); |  | ||||||
| 			if (client.isOnline()) { | 			if (client.isOnline()) { | ||||||
| 				client.initReceiver(localDB, |  | ||||||
| 						receivedMessageCache, |  | ||||||
| 						receivedGroupMessageCache, |  | ||||||
| 						receivedMessageStatusChangeCache, |  | ||||||
| 						receivedGroupMessageStatusChangeCache); |  | ||||||
| 				loadChatScene(); | 				loadChatScene(); | ||||||
|  | 				client.initReceiver(localDB, cacheMap); | ||||||
| 			} | 			} | ||||||
| 		} catch (IOException | InterruptedException | TimeoutException e) { | 		} catch (IOException | InterruptedException | TimeoutException e) { | ||||||
| 			logger.log(Level.INFO, "Could not connect to server. Entering offline mode..."); | 			logger.log(Level.INFO, "Could not connect to server. Entering offline mode..."); | ||||||
| @@ -207,7 +175,7 @@ public final class LoginScene { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Initialize write proxy | 		// Initialize write proxy | ||||||
| 		final var writeProxy = client.createWriteProxy(localDB); | 		final var writeProxy = new WriteProxy(client, localDB); | ||||||
|  |  | ||||||
| 		localDB.synchronize(); | 		localDB.synchronize(); | ||||||
|  |  | ||||||
| @@ -227,11 +195,5 @@ public final class LoginScene { | |||||||
| 		sceneContext.getStage().setMinWidth(350); | 		sceneContext.getStage().setMinWidth(350); | ||||||
| 		sceneContext.load(SceneContext.SceneInfo.CHAT_SCENE); | 		sceneContext.load(SceneContext.SceneInfo.CHAT_SCENE); | ||||||
| 		sceneContext.<ChatScene>getController().initializeData(sceneContext, localDB, client, writeProxy); | 		sceneContext.<ChatScene>getController().initializeData(sceneContext, localDB, client, writeProxy); | ||||||
|  |  | ||||||
| 		// Relay unread messages from cache |  | ||||||
| 		if (receivedMessageCache != null && client.isOnline()) receivedMessageCache.relay(); |  | ||||||
| 		if (receivedGroupMessageCache != null && client.isOnline()) receivedGroupMessageCache.relay(); |  | ||||||
| 		if (receivedMessageStatusChangeCache != null && client.isOnline()) receivedMessageStatusChangeCache.relay(); |  | ||||||
| 		if (receivedGroupMessageStatusChangeCache != null && client.isOnline()) receivedGroupMessageStatusChangeCache.relay(); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,16 @@ | |||||||
| package envoy.client.ui.listcell; | package envoy.client.ui.listcell; | ||||||
|  |  | ||||||
|  | import java.awt.Toolkit; | ||||||
|  | import java.awt.datatransfer.StringSelection; | ||||||
| import java.time.format.DateTimeFormatter; | import java.time.format.DateTimeFormatter; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  | import java.util.logging.Level; | ||||||
|  | import java.util.logging.Logger; | ||||||
|  |  | ||||||
| import javafx.geometry.Insets; | import javafx.geometry.Insets; | ||||||
|  | import javafx.scene.control.ContextMenu; | ||||||
| import javafx.scene.control.Label; | import javafx.scene.control.Label; | ||||||
|  | import javafx.scene.control.MenuItem; | ||||||
| import javafx.scene.image.Image; | import javafx.scene.image.Image; | ||||||
| import javafx.scene.image.ImageView; | import javafx.scene.image.ImageView; | ||||||
| import javafx.scene.layout.VBox; | import javafx.scene.layout.VBox; | ||||||
| @@ -14,6 +20,7 @@ import envoy.client.ui.IconUtil; | |||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
| import envoy.data.Message.MessageStatus; | import envoy.data.Message.MessageStatus; | ||||||
| import envoy.data.User; | import envoy.data.User; | ||||||
|  | import envoy.util.EnvoyLog; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This class formats a single {@link Message} into a UI component. |  * This class formats a single {@link Message} into a UI component. | ||||||
| @@ -25,50 +32,89 @@ import envoy.data.User; | |||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy Client v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| public class MessageControl extends VBox { | public class MessageControl extends Label { | ||||||
|  |  | ||||||
| 	private static User								client; | 	private static User								client; | ||||||
| 	private static final DateTimeFormatter			dateFormat		= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"); | 	private static final DateTimeFormatter			dateFormat		= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"); | ||||||
| 	private static final Map<MessageStatus, Image>	statusImages	= IconUtil.loadByEnum(MessageStatus.class, 16); | 	private static final Map<MessageStatus, Image>	statusImages	= IconUtil.loadByEnum(MessageStatus.class, 16); | ||||||
|  |  | ||||||
|  | 	private static final Logger logger = EnvoyLog.getLogger(MessageControl.class); | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * | 	 * | ||||||
| 	 * @param message the message that should be formatted | 	 * @param message the message that should be formatted | ||||||
| 	 * @since Envoy Client v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public MessageControl(Message message) { | 	public MessageControl(Message message) { | ||||||
| 		// Creating the underlying VBox, the dateLabel and the textLabel | 		// Creating the underlying VBox and the dateLabel | ||||||
| 		super(new Label(dateFormat.format(message.getCreationDate()))); | 		final var vbox = new VBox(new Label(dateFormat.format(message.getCreationDate()))); | ||||||
|  |  | ||||||
|  | 		// Creating the actions for the MenuItems | ||||||
|  | 		final ContextMenu	contextMenu		= new ContextMenu(); | ||||||
|  | 		final MenuItem		copyMenuItem	= new MenuItem("Copy"); | ||||||
|  | 		final MenuItem		deleteMenuItem	= new MenuItem("Delete"); | ||||||
|  | 		final MenuItem		forwardMenuItem	= new MenuItem("Forward"); | ||||||
|  | 		final MenuItem		quoteMenuItem	= new MenuItem("Quote"); | ||||||
|  | 		final MenuItem		infoMenuItem	= new MenuItem("Info"); | ||||||
|  | 		copyMenuItem.setOnAction(e -> copyMessage(message)); | ||||||
|  | 		deleteMenuItem.setOnAction(e -> deleteMessage(message)); | ||||||
|  | 		forwardMenuItem.setOnAction(e -> forwardMessage(message)); | ||||||
|  | 		quoteMenuItem.setOnAction(e -> quoteMessage(message)); | ||||||
|  | 		infoMenuItem.setOnAction(e -> loadMessageInfoScene(message)); | ||||||
|  | 		contextMenu.getItems().addAll(copyMenuItem, deleteMenuItem, forwardMenuItem, quoteMenuItem, infoMenuItem); | ||||||
|  |  | ||||||
| 		// Handling message attachment display | 		// Handling message attachment display | ||||||
| 		if (message.hasAttachment()) switch (message.getAttachment().getType()) { | 		if (message.hasAttachment()) { | ||||||
| 			case PICTURE: | 			switch (message.getAttachment().getType()) { | ||||||
| 				break; | 				case PICTURE: | ||||||
| 			case VIDEO: | 					break; | ||||||
| 				break; | 				case VIDEO: | ||||||
| 			case VOICE: | 					break; | ||||||
| 				getChildren().add(new AudioControl(message.getAttachment().getData())); | 				case VOICE: | ||||||
| 				break; | 					vbox.getChildren().add(new AudioControl(message.getAttachment().getData())); | ||||||
| 			case DOCUMENT: | 					break; | ||||||
| 				break; | 				case DOCUMENT: | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			final var saveAttachment = new MenuItem("Save attachment"); | ||||||
|  | 			saveAttachment.setOnAction(e -> saveAttachment(message)); | ||||||
|  | 			contextMenu.getItems().add(saveAttachment); | ||||||
| 		} | 		} | ||||||
|  | 		// Creating the textLabel | ||||||
| 		final var textLabel = new Label(message.getText()); | 		final var textLabel = new Label(message.getText()); | ||||||
| 		textLabel.setWrapText(true); | 		textLabel.setWrapText(true); | ||||||
| 		getChildren().add(textLabel); | 		vbox.getChildren().add(textLabel); | ||||||
| 		// Setting the message status icon and background color | 		// Setting the message status icon and background color | ||||||
| 		if (message.getSenderID() == client.getID()) { | 		if (message.getSenderID() == client.getID()) { | ||||||
| 			final var statusIcon = new ImageView(statusImages.get(message.getStatus())); | 			final var statusIcon = new ImageView(statusImages.get(message.getStatus())); | ||||||
| 			statusIcon.setPreserveRatio(true); | 			statusIcon.setPreserveRatio(true); | ||||||
| 			getChildren().add(statusIcon); | 			vbox.getChildren().add(statusIcon); | ||||||
| 			getStyleClass().add("own-message"); | 			getStyleClass().add("own-message"); | ||||||
| 		} else { | 		} else { | ||||||
| 			getStyleClass().add("received-message"); | 			getStyleClass().add("received-message"); | ||||||
| 		} | 		} | ||||||
| 		// Adjusting height and weight of the cell to the corresponding ListView | 		// Adjusting height and weight of the cell to the corresponding ListView | ||||||
| 		paddingProperty().setValue(new Insets(5, 20, 5, 20)); | 		paddingProperty().setValue(new Insets(5, 20, 5, 20)); | ||||||
|  | 		setContextMenu(contextMenu); | ||||||
|  | 		setGraphic(vbox); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// Context Menu actions | ||||||
|  |  | ||||||
|  | 	private void copyMessage(Message message) { | ||||||
|  | 		Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(message.getText()), null); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void deleteMessage(Message message) { logger.log(Level.FINEST, "message deletion was requested for " + message); } | ||||||
|  |  | ||||||
|  | 	private void forwardMessage(Message message) { logger.log(Level.FINEST, "message forwarding was requested for " + message); } | ||||||
|  |  | ||||||
|  | 	private void quoteMessage(Message message) { logger.log(Level.FINEST, "message quotation was requested for " + message); } | ||||||
|  |  | ||||||
|  | 	private void loadMessageInfoScene(Message message) { logger.log(Level.FINEST, "message info scene was requested for " + message); } | ||||||
|  |  | ||||||
|  | 	private void saveAttachment(Message message) { logger.log(Level.FINEST, "attachment saving was requested for " + message); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param client the user who has logged in | 	 * @param client the user who has logged in | ||||||
| 	 * @since Envoy Client v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
|   | |||||||
| @@ -92,22 +92,6 @@ | |||||||
| 			<padding> | 			<padding> | ||||||
| 				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> | 				<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> | ||||||
| 			</padding> | 			</padding> | ||||||
| 			<contextMenu> |  | ||||||
| 				<ContextMenu anchorLocation="CONTENT_TOP_LEFT"> |  | ||||||
| 					<items> |  | ||||||
| 						<MenuItem mnemonicParsing="false" onAction="#copyMessage" |  | ||||||
| 							text="Copy" /> |  | ||||||
| 						<MenuItem mnemonicParsing="false" |  | ||||||
| 							onAction="#deleteMessage" text="Delete" /> |  | ||||||
| 						<MenuItem mnemonicParsing="false" |  | ||||||
| 							onAction="#forwardMessage" text="Forward" /> |  | ||||||
| 						<MenuItem mnemonicParsing="false" |  | ||||||
| 							onAction="#quoteMessage" text="Quote" /> |  | ||||||
| 						<MenuItem mnemonicParsing="false" |  | ||||||
| 							onAction="#loadMessageInfoScene" text="Info" /> |  | ||||||
| 					</items> |  | ||||||
| 				</ContextMenu> |  | ||||||
| 			</contextMenu> |  | ||||||
| 		</ListView> | 		</ListView> | ||||||
| 		<ButtonBar prefWidth="436.0" GridPane.columnIndex="1" | 		<ButtonBar prefWidth="436.0" GridPane.columnIndex="1" | ||||||
| 			GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" | 			GridPane.columnSpan="2147483647" GridPane.halignment="CENTER" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user