Merge pull request #123 from informatik-ag-ngl/f/forward_messages
Added message forwarding capability
This commit is contained in:
		| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui; | package envoy.client; | ||||||
| 
 | 
 | ||||||
| import java.awt.EventQueue; | import java.awt.EventQueue; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| @@ -15,6 +15,9 @@ import javax.swing.SwingUtilities; | |||||||
| 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.net.WriteProxy; | ||||||
|  | import envoy.client.ui.StatusTrayIcon; | ||||||
|  | import envoy.client.ui.container.ChatWindow; | ||||||
|  | import envoy.client.ui.container.LoginDialog; | ||||||
| import envoy.data.Config; | import envoy.data.Config; | ||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
| import envoy.data.User.UserStatus; | import envoy.data.User.UserStatus; | ||||||
| @@ -31,7 +34,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class Startup { | public class Startup { | ||||||
| 
 | 
 | ||||||
| @@ -48,7 +51,7 @@ public class Startup { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param args the command line arguments may contain configuration parameters | 	 * @param args the command line arguments may contain configuration parameters | ||||||
| 	 *             and are parsed by the {@link Config} class | 	 *             and are parsed by the {@link Config} class | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public static void main(String[] args) { | 	public static void main(String[] args) { | ||||||
| 		ClientConfig config = ClientConfig.getInstance(); | 		ClientConfig config = ClientConfig.getInstance(); | ||||||
| @@ -127,11 +130,9 @@ public class Startup { | |||||||
| 			// Save all users to the local database and flush cache | 			// Save all users to the local database and flush cache | ||||||
| 			localDb.setUsers(client.getUsers()); | 			localDb.setUsers(client.getUsers()); | ||||||
| 			writeProxy.flushCache(); | 			writeProxy.flushCache(); | ||||||
| 		} else { | 		} else | ||||||
| 
 |  | ||||||
| 			// Set all contacts to offline mode | 			// Set all contacts to offline mode | ||||||
| 			localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE)); | 			localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE)); | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// Display ChatWindow and StatusTrayIcon | 		// Display ChatWindow and StatusTrayIcon | ||||||
| 		EventQueue.invokeLater(() -> { | 		EventQueue.invokeLater(() -> { | ||||||
| @@ -173,4 +174,4 @@ public class Startup { | |||||||
| 			} | 			} | ||||||
| 		})); | 		})); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -17,7 +17,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * |  * | ||||||
|  * @param <T> the type of cached elements |  * @param <T> the type of cached elements | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class Cache<T> implements Consumer<T>, Serializable { | public class Cache<T> implements Consumer<T>, Serializable { | ||||||
|  |  | ||||||
| @@ -31,7 +31,7 @@ public class Cache<T> implements Consumer<T>, Serializable { | |||||||
| 	 * Adds an element to the cache. | 	 * Adds an element to the cache. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param element the element to add | 	 * @param element the element to add | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	public void accept(T element) { | 	public void accept(T element) { | ||||||
| @@ -43,7 +43,7 @@ public class Cache<T> implements Consumer<T>, Serializable { | |||||||
| 	 * Sets the processor to which cached elements are relayed. | 	 * Sets the processor to which cached elements are relayed. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param processor the processor to set | 	 * @param processor the processor to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setProcessor(Consumer<T> processor) { this.processor = processor; } | 	public void setProcessor(Consumer<T> processor) { this.processor = processor; } | ||||||
|  |  | ||||||
| @@ -51,7 +51,7 @@ public class Cache<T> implements Consumer<T>, Serializable { | |||||||
| 	 * Relays all cached elements to the processor. | 	 * Relays all cached elements to the processor. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws IllegalStateException if the processor is not initialized | 	 * @throws IllegalStateException if the processor is not initialized | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void relay() { | 	public void relay() { | ||||||
| 		if (processor == null) throw new IllegalStateException("Processor is not defined"); | 		if (processor == null) throw new IllegalStateException("Processor is not defined"); | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import java.io.IOException; | |||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
|  |  | ||||||
| import envoy.client.net.WriteProxy; | import envoy.client.net.WriteProxy; | ||||||
| import envoy.client.ui.list.ComponentListModel; | import envoy.client.ui.list.Model; | ||||||
| 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; | ||||||
| @@ -21,21 +21,21 @@ import envoy.event.MessageStatusChangeEvent; | |||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class Chat implements Serializable { | public class Chat implements Serializable { | ||||||
|  |  | ||||||
| 	private static final long serialVersionUID = -7751248474547242056L; | 	private static final long serialVersionUID = -7751248474547242056L; | ||||||
|  |  | ||||||
| 	private final User							recipient; | 	private final User							recipient; | ||||||
| 	private final ComponentListModel<Message>	model	= new ComponentListModel<>(); | 	private final Model<Message>	model	= new Model<>(); | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Provides the list of messages that the recipient receives.<br> | 	 * Provides the list of messages that the recipient receives.<br> | ||||||
| 	 * Saves the Messages in the corresponding chat at that Point. | 	 * Saves the Messages in the corresponding chat at that Point. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param recipient the user who receives the messages | 	 * @param recipient the user who receives the messages | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Chat(User recipient) { this.recipient = recipient; } | 	public Chat(User recipient) { this.recipient = recipient; } | ||||||
|  |  | ||||||
| @@ -43,7 +43,7 @@ public class Chat implements Serializable { | |||||||
| 	 * Appends a message to the bottom of this chat | 	 * Appends a message to the bottom of this chat | ||||||
| 	 * | 	 * | ||||||
| 	 * @param message the message to append | 	 * @param message the message to append | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void appendMessage(Message message) { model.add(message); } | 	public void appendMessage(Message message) { model.add(message); } | ||||||
|  |  | ||||||
| @@ -56,17 +56,15 @@ public class Chat implements Serializable { | |||||||
| 	 *                   the message status changes | 	 *                   the message status changes | ||||||
| 	 * @throws IOException if a {@link MessageStatusChangeEvent} could not be | 	 * @throws IOException if a {@link MessageStatusChangeEvent} could not be | ||||||
| 	 *                     delivered to the server | 	 *                     delivered to the server | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void read(WriteProxy writeProxy) throws IOException { | 	public void read(WriteProxy writeProxy) throws IOException { | ||||||
| 		for (int i = model.size() - 1; i >= 0; --i) { | 		for (int i = model.size() - 1; i >= 0; --i) { | ||||||
| 			final Message m = model.get(i); | 			final Message m = model.get(i); | ||||||
| 			if (m.getSenderId() == recipient.getId()) { | 			if (m.getSenderId() == recipient.getId()) if (m.getStatus() == MessageStatus.READ) break; | ||||||
| 				if (m.getStatus() == MessageStatus.READ) break; | 			else { | ||||||
| 				else { | 				m.setStatus(MessageStatus.READ); | ||||||
| 					m.setStatus(MessageStatus.READ); | 				writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m)); | ||||||
| 					writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m)); |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -74,19 +72,19 @@ public class Chat implements Serializable { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return {@code true} if the newest message received in the chat doesn't have | 	 * @return {@code true} if the newest message received in the chat doesn't have | ||||||
| 	 *         the status {@code READ} | 	 *         the status {@code READ} | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean isUnread() { return !model.isEmpty() && model.get(model.size() - 1).getStatus() != MessageStatus.READ; } | 	public boolean isUnread() { return !model.isEmpty() && model.get(model.size() - 1).getStatus() != MessageStatus.READ; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return all messages in the current chat | 	 * @return all messages in the current chat | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public ComponentListModel<Message> getModel() { return model; } | 	public Model<Message> getModel() { return model; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the recipient of a message | 	 * @return the recipient of a message | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public User getRecipient() { return recipient; } | 	public User getRecipient() { return recipient; } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import envoy.data.LoginCredentials; | |||||||
|  * Created: <strong>01.03.2020</strong><br> |  * Created: <strong>01.03.2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| public class ClientConfig extends Config { | public class ClientConfig extends Config { | ||||||
|  |  | ||||||
| @@ -26,7 +26,7 @@ public class ClientConfig extends Config { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the singleton instance of the client config | 	 * @return the singleton instance of the client config | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public static ClientConfig getInstance() { | 	public static ClientConfig getInstance() { | ||||||
| 		if (config == null) config = new ClientConfig(); | 		if (config == null) config = new ClientConfig(); | ||||||
| @@ -47,68 +47,68 @@ public class ClientConfig extends Config { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the host name of the Envoy server | 	 * @return the host name of the Envoy server | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getServer() { return (String) items.get("server").get(); } | 	public String getServer() { return (String) items.get("server").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the port at which the Envoy server is located on the host | 	 * @return the port at which the Envoy server is located on the host | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Integer getPort() { return (Integer) items.get("port").get(); } | 	public Integer getPort() { return (Integer) items.get("port").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the local database specific to the client user | 	 * @return the local database specific to the client user | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public File getLocalDB() { return (File) items.get("localDB").get(); } | 	public File getLocalDB() { return (File) items.get("localDB").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return {@code true} if the local database is to be ignored | 	 * @return {@code true} if the local database is to be ignored | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); } | 	public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the directory in which all local files are saves | 	 * @return the directory in which all local files are saves | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } | 	public File getHomeDirectory() { return (File) items.get("homeDirectory").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the minimal {@link Level} to log inside the log file | 	 * @return the minimal {@link Level} to log inside the log file | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } | 	public Level getFileLevelBarrier() { return (Level) items.get("fileLevelBarrier").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the minimal {@link Level} to log inside the console | 	 * @return the minimal {@link Level} to log inside the console | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } | 	public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the user name | 	 * @return the user name | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getUser() { return (String) items.get("user").get(); } | 	public String getUser() { return (String) items.get("user").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the password | 	 * @return the password | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public char[] getPassword() { return (char[]) items.get("password").get(); } | 	public char[] getPassword() { return (char[]) items.get("password").get(); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return {@code true} if user name and password are set | 	 * @return {@code true} if user name and password are set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; } | 	public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return login credentials for the specified user name and password, without | 	 * @return login credentials for the specified user name and password, without | ||||||
| 	 *         the registration option | 	 *         the registration option | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public LoginCredentials getLoginCredentials() { | 	public LoginCredentials getLoginCredentials() { | ||||||
| 		try { | 		try { | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ import envoy.event.MessageStatusChangeEvent; | |||||||
|  * Created: <strong>3 Feb 2020</strong><br> |  * Created: <strong>3 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public abstract class LocalDb { | public abstract class LocalDb { | ||||||
|  |  | ||||||
| @@ -30,7 +30,7 @@ public abstract class LocalDb { | |||||||
| 	/** | 	/** | ||||||
| 	 * Initializes a storage space for a user-specific list of chats. | 	 * Initializes a storage space for a user-specific list of chats. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void initializeUserStorage() {} | 	public void initializeUserStorage() {} | ||||||
|  |  | ||||||
| @@ -39,7 +39,7 @@ public abstract class LocalDb { | |||||||
| 	 * as well. The message id generator will also be saved if present. | 	 * as well. The message id generator will also be saved if present. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws Exception if the saving process failed | 	 * @throws Exception if the saving process failed | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void save() throws Exception {} | 	public void save() throws Exception {} | ||||||
|  |  | ||||||
| @@ -47,7 +47,7 @@ public abstract class LocalDb { | |||||||
| 	 * Loads all user data. | 	 * Loads all user data. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws Exception if the loading process failed | 	 * @throws Exception if the loading process failed | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void loadUsers() throws Exception {} | 	public void loadUsers() throws Exception {} | ||||||
|  |  | ||||||
| @@ -55,21 +55,21 @@ public abstract class LocalDb { | |||||||
| 	 * Loads all data of the client user. | 	 * Loads all data of the client user. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws Exception if the loading process failed | 	 * @throws Exception if the loading process failed | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void loadUserData() throws Exception {} | 	public void loadUserData() throws Exception {} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Loads the ID generator. Any exception thrown during this process is ignored. | 	 * Loads the ID generator. Any exception thrown during this process is ignored. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void loadIdGenerator() {} | 	public void loadIdGenerator() {} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return a {@code Map<String, User>} of all users stored locally with their | 	 * @return a {@code Map<String, User>} of all users stored locally with their | ||||||
| 	 *         user names as keys | 	 *         user names as keys | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Map<String, User> getUsers() { return users; } | 	public Map<String, User> getUsers() { return users; } | ||||||
|  |  | ||||||
| @@ -81,7 +81,7 @@ public abstract class LocalDb { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return all saved {@link Chat} objects that list the client user as the | 	 * @return all saved {@link Chat} objects that list the client user as the | ||||||
| 	 *         sender | 	 *         sender | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 **/ | 	 **/ | ||||||
| 	public List<Chat> getChats() { return chats; } | 	public List<Chat> getChats() { return chats; } | ||||||
|  |  | ||||||
| @@ -92,55 +92,55 @@ public abstract class LocalDb { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the {@link User} who initialized the local database | 	 * @return the {@link User} who initialized the local database | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public User getUser() { return user; } | 	public User getUser() { return user; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param user the user to set | 	 * @param user the user to set | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setUser(User user) { this.user = user; } | 	public void setUser(User user) { this.user = user; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the message ID generator | 	 * @return the message ID generator | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public IdGenerator getIdGenerator() { return idGenerator; } | 	public IdGenerator getIdGenerator() { return idGenerator; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param idGenerator the message ID generator to set | 	 * @param idGenerator the message ID generator to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } | 	public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return {@code true} if an {@link IdGenerator} is present | 	 * @return {@code true} if an {@link IdGenerator} is present | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean hasIdGenerator() { return idGenerator != null; } | 	public boolean hasIdGenerator() { return idGenerator != null; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the offline message cache | 	 * @return the offline message cache | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Cache<Message> getMessageCache() { return messageCache; } | 	public Cache<Message> getMessageCache() { return messageCache; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param messageCache the offline message cache to set | 	 * @param messageCache the offline message cache to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setMessageCache(Cache<Message> messageCache) { this.messageCache = messageCache; } | 	public void setMessageCache(Cache<Message> messageCache) { this.messageCache = messageCache; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the offline status cache | 	 * @return the offline status cache | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Cache<MessageStatusChangeEvent> getStatusCache() { return statusCache; } | 	public Cache<MessageStatusChangeEvent> getStatusCache() { return statusCache; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param statusCache the offline status cache to set | 	 * @param statusCache the offline status cache to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setStatusCache(Cache<MessageStatusChangeEvent> statusCache) { this.statusCache = statusCache; } | 	public void setStatusCache(Cache<MessageStatusChangeEvent> statusCache) { this.statusCache = statusCache; } | ||||||
|  |  | ||||||
| @@ -150,7 +150,7 @@ public abstract class LocalDb { | |||||||
| 	 * @param id the ID of the message to search for | 	 * @param id the ID of the message to search for | ||||||
| 	 * @return the message with the corresponding ID, or {@code null} if no message | 	 * @return the message with the corresponding ID, or {@code null} if no message | ||||||
| 	 *         has been found | 	 *         has been found | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public Message getMessage(long id) { | 	public Message getMessage(long id) { | ||||||
| 		for (Chat c : chats) | 		for (Chat c : chats) | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import envoy.util.SerializationUtils; | |||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class PersistentLocalDb extends LocalDb { | public class PersistentLocalDb extends LocalDb { | ||||||
|  |  | ||||||
| @@ -32,7 +32,7 @@ public class PersistentLocalDb extends LocalDb { | |||||||
| 	 * This constructor shall be used in conjunction with the {@code ignoreLocalDB} | 	 * This constructor shall be used in conjunction with the {@code ignoreLocalDB} | ||||||
| 	 * {@link ConfigItem}. | 	 * {@link ConfigItem}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public PersistentLocalDb() {} | 	public PersistentLocalDb() {} | ||||||
|  |  | ||||||
| @@ -42,7 +42,7 @@ public class PersistentLocalDb extends LocalDb { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param localDbDir the directory in which to store users and chats | 	 * @param localDbDir the directory in which to store users and chats | ||||||
| 	 * @throws IOException if the PersistentLocalDb could not be initialized | 	 * @throws IOException if the PersistentLocalDb could not be initialized | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public PersistentLocalDb(File localDbDir) throws IOException { | 	public PersistentLocalDb(File localDbDir) throws IOException { | ||||||
| 		localDBDir = localDbDir; | 		localDBDir = localDbDir; | ||||||
| @@ -58,7 +58,7 @@ public class PersistentLocalDb extends LocalDb { | |||||||
| 	 * Creates a database file for a user-specific list of chats. | 	 * Creates a database file for a user-specific list of chats. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws NullPointerException if the client user is not yet specified | 	 * @throws NullPointerException if the client user is not yet specified | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	public void initializeUserStorage() { | 	public void initializeUserStorage() { | ||||||
| @@ -100,4 +100,4 @@ public class PersistentLocalDb extends LocalDb { | |||||||
| 			idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); | 			idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); | ||||||
| 		} catch (ClassNotFoundException | IOException e) {} | 		} catch (ClassNotFoundException | IOException e) {} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ import envoy.util.SerializationUtils; | |||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class Settings { | public class Settings { | ||||||
|  |  | ||||||
| @@ -49,7 +49,7 @@ public class Settings { | |||||||
| 	 * The way to instantiate the settings. | 	 * The way to instantiate the settings. | ||||||
| 	 * Is set to private to deny other instances of that object. | 	 * Is set to private to deny other instances of that object. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	private Settings() { | 	private Settings() { | ||||||
| 		// Load settings from settings file | 		// Load settings from settings file | ||||||
| @@ -81,7 +81,7 @@ public class Settings { | |||||||
| 	 * This method is used to ensure that there is only one instance of Settings. | 	 * This method is used to ensure that there is only one instance of Settings. | ||||||
| 	 * | 	 * | ||||||
| 	 * @return the instance of Settings | 	 * @return the instance of Settings | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public static Settings getInstance() { return settings; } | 	public static Settings getInstance() { return settings; } | ||||||
|  |  | ||||||
| @@ -90,7 +90,7 @@ public class Settings { | |||||||
| 	 * | 	 * | ||||||
| 	 * @throws IOException if an error occurs while saving the themes to the theme | 	 * @throws IOException if an error occurs while saving the themes to the theme | ||||||
| 	 *                     file | 	 *                     file | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void save() throws IOException { | 	public void save() throws IOException { | ||||||
| 		// Save settings to settings file | 		// Save settings to settings file | ||||||
| @@ -110,21 +110,27 @@ public class Settings { | |||||||
| 	 * Adds new theme to the theme map. | 	 * Adds new theme to the theme map. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param theme the {@link Theme} to add | 	 * @param theme the {@link Theme} to add | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void addNewThemeToMap(Theme theme) { settings.getThemes().put(theme.getThemeName(), theme); } | 	public void addNewThemeToMap(Theme theme) { getThemes().put(theme.getThemeName(), theme); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the name of the currently active {@link Theme} | 	 * @return the name of the currently active {@link Theme} | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getCurrentTheme() { return (String) items.get("currentTheme").get(); } | 	public String getCurrentThemeName() { return (String) items.get("currentTheme").get(); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the currently active {@link Theme} | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Theme getCurrentTheme() { return getTheme(getCurrentThemeName()); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Sets the name of the current {@link Theme}. | 	 * Sets the name of the current {@link Theme}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param themeName the name to set | 	 * @param themeName the name to set | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); } | 	public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); } | ||||||
|  |  | ||||||
| @@ -132,7 +138,7 @@ public class Settings { | |||||||
| 	 * @return {@code true}, if pressing the {@code Enter} key suffices to send a | 	 * @return {@code true}, if pressing the {@code Enter} key suffices to send a | ||||||
| 	 *         message. Otherwise it has to be pressed in conjunction with the | 	 *         message. Otherwise it has to be pressed in conjunction with the | ||||||
| 	 *         {@code Control} key. | 	 *         {@code Control} key. | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Boolean isEnterToSend() { return (Boolean) items.get("enterToSend").get(); } | 	public Boolean isEnterToSend() { return (Boolean) items.get("enterToSend").get(); } | ||||||
|  |  | ||||||
| @@ -142,13 +148,13 @@ public class Settings { | |||||||
| 	 * @param enterToSend If set to {@code true} a message can be sent by pressing | 	 * @param enterToSend If set to {@code true} a message can be sent by pressing | ||||||
| 	 *                    the {@code Enter} key. Otherwise it has to be pressed in | 	 *                    the {@code Enter} key. Otherwise it has to be pressed in | ||||||
| 	 *                    conjunction with the {@code Control} key. | 	 *                    conjunction with the {@code Control} key. | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setEnterToSend(boolean enterToSend) { ((SettingsItem<Boolean>) items.get("enterToSend")).set(enterToSend); } | 	public void setEnterToSend(boolean enterToSend) { ((SettingsItem<Boolean>) items.get("enterToSend")).set(enterToSend); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the current on close mode. | 	 * @return the current on close mode. | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Boolean getCurrentOnCloseMode() { return (Boolean) items.get("onCloseMode").get(); } | 	public Boolean getCurrentOnCloseMode() { return (Boolean) items.get("onCloseMode").get(); } | ||||||
|  |  | ||||||
| @@ -156,7 +162,7 @@ public class Settings { | |||||||
| 	 * Sets the current on close mode. | 	 * Sets the current on close mode. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param currentOnCloseMode the on close mode that should be set. | 	 * @param currentOnCloseMode the on close mode that should be set. | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem<Boolean>) items.get("onCloseMode")).set(currentOnCloseMode); } | 	public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem<Boolean>) items.get("onCloseMode")).set(currentOnCloseMode); } | ||||||
|  |  | ||||||
| @@ -172,7 +178,7 @@ public class Settings { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return a {@code Map<String, Theme>} of all themes with their names as keys | 	 * @return a {@code Map<String, Theme>} of all themes with their names as keys | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Map<String, Theme> getThemes() { return themes; } | 	public Map<String, Theme> getThemes() { return themes; } | ||||||
|  |  | ||||||
| @@ -180,14 +186,14 @@ public class Settings { | |||||||
| 	 * Sets the {@code Map<String, Theme>} of all themes with their names as keys | 	 * Sets the {@code Map<String, Theme>} of all themes with their names as keys | ||||||
| 	 * | 	 * | ||||||
| 	 * @param themes the theme map to set | 	 * @param themes the theme map to set | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setThemes(Map<String, Theme> themes) { this.themes = themes; } | 	public void setThemes(Map<String, Theme> themes) { this.themes = themes; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param themeName the name of the {@link Theme} to get | 	 * @param themeName the name of the {@link Theme} to get | ||||||
| 	 * @return the {@link Theme} with the specified name | 	 * @return the {@link Theme} with the specified name | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Theme getTheme(String themeName) { return themes.get(themeName); } | 	public Theme getTheme(String themeName) { return themes.get(themeName); } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ import java.util.function.Consumer; | |||||||
|  |  | ||||||
| import javax.swing.JComponent; | import javax.swing.JComponent; | ||||||
|  |  | ||||||
| import envoy.client.ui.PrimaryToggleSwitch; | import envoy.client.ui.primary.PrimaryToggleSwitch; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Encapsulates a persistent value that is directly or indirectly mutable by the |  * Encapsulates a persistent value that is directly or indirectly mutable by the | ||||||
| @@ -19,7 +19,7 @@ import envoy.client.ui.PrimaryToggleSwitch; | |||||||
|  *  |  *  | ||||||
|  * @param <T> the type of this {@link SettingsItem}'s value |  * @param <T> the type of this {@link SettingsItem}'s value | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class SettingsItem<T> implements Serializable { | public class SettingsItem<T> implements Serializable { | ||||||
|  |  | ||||||
| @@ -45,7 +45,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
| 	 * @param value            the default value | 	 * @param value            the default value | ||||||
| 	 * @param userFriendlyName the user friendly name (short) | 	 * @param userFriendlyName the user friendly name (short) | ||||||
| 	 * @param description      the description (long) | 	 * @param description      the description (long) | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public SettingsItem(T value, String userFriendlyName, String description) { | 	public SettingsItem(T value, String userFriendlyName, String description) { | ||||||
| 		this(value, componentClasses.get(value.getClass())); | 		this(value, componentClasses.get(value.getClass())); | ||||||
| @@ -61,7 +61,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
| 	 *  | 	 *  | ||||||
| 	 * @param value the default value | 	 * @param value the default value | ||||||
| 	 * @param componentClass the class of the {@link JComponent} to represent this {@link SettingsItem} with | 	 * @param componentClass the class of the {@link JComponent} to represent this {@link SettingsItem} with | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public SettingsItem(T value, Class<? extends JComponent> componentClass) { | 	public SettingsItem(T value, Class<? extends JComponent> componentClass) { | ||||||
| 		this.value			= value; | 		this.value			= value; | ||||||
| @@ -72,7 +72,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
| 	 * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} | 	 * @return an instance of the {@link JComponent} that represents this {@link SettingsItem} | ||||||
| 	 * @throws ReflectiveOperationException if the component initialization failed | 	 * @throws ReflectiveOperationException if the component initialization failed | ||||||
| 	 * @throws SecurityException if the component initialization failed | 	 * @throws SecurityException if the component initialization failed | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public JComponent getComponent() throws ReflectiveOperationException, SecurityException { | 	public JComponent getComponent() throws ReflectiveOperationException, SecurityException { | ||||||
| 		if (componentClass == null) throw new NullPointerException("Component class is null"); | 		if (componentClass == null) throw new NullPointerException("Component class is null"); | ||||||
| @@ -81,7 +81,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the value | 	 * @return the value | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public T get() { return value; } | 	public T get() { return value; } | ||||||
|  |  | ||||||
| @@ -90,7 +90,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
| 	 * defined, it will be invoked with this value. | 	 * defined, it will be invoked with this value. | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param value the value to set | 	 * @param value the value to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void set(T value) { | 	public void set(T value) { | ||||||
| 		if (changeHandler != null && value != this.value) changeHandler.accept(value); | 		if (changeHandler != null && value != this.value) changeHandler.accept(value); | ||||||
| @@ -99,37 +99,37 @@ public class SettingsItem<T> implements Serializable { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the componentClass | 	 * @return the componentClass | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Class<? extends JComponent> getComponentClass() { return componentClass; } | 	public Class<? extends JComponent> getComponentClass() { return componentClass; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param componentClass the componentClass to set | 	 * @param componentClass the componentClass to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setComponentClass(Class<? extends JComponent> componentClass) { this.componentClass = componentClass; } | 	public void setComponentClass(Class<? extends JComponent> componentClass) { this.componentClass = componentClass; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the userFriendlyName | 	 * @return the userFriendlyName | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getUserFriendlyName() { return userFriendlyName; } | 	public String getUserFriendlyName() { return userFriendlyName; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param userFriendlyName the userFriendlyName to set | 	 * @param userFriendlyName the userFriendlyName to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } | 	public void setUserFriendlyName(String userFriendlyName) { this.userFriendlyName = userFriendlyName; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the description | 	 * @return the description | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getDescription() { return description; } | 	public String getDescription() { return description; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param description the description to set | 	 * @param description the description to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setDescription(String description) { this.description = description; } | 	public void setDescription(String description) { this.description = description; } | ||||||
|  |  | ||||||
| @@ -139,7 +139,7 @@ public class SettingsItem<T> implements Serializable { | |||||||
| 	 * when the value changes. | 	 * when the value changes. | ||||||
| 	 *  | 	 *  | ||||||
| 	 * @param changeHandler the changeHandler to set | 	 * @param changeHandler the changeHandler to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setChangeHandler(Consumer<T> changeHandler) { | 	public void setChangeHandler(Consumer<T> changeHandler) { | ||||||
| 		this.changeHandler = changeHandler; | 		this.changeHandler = changeHandler; | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ package envoy.client.data; | |||||||
|  * Created: <strong>3 Feb 2020</strong><br> |  * Created: <strong>3 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class TransientLocalDb extends LocalDb { | public class TransientLocalDb extends LocalDb { | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| package envoy.client.data; | package envoy.client.data; | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ import envoy.event.Event; | |||||||
|  * Created: <strong>8 Feb 2020</strong><br> |  * Created: <strong>8 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class HandshakeSuccessfulEvent extends Event.Valueless { | public class HandshakeSuccessfulEvent extends Event.Valueless { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import envoy.event.Event; | |||||||
|  * Created: <strong>4 Dec 2019</strong><br> |  * Created: <strong>4 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class MessageCreationEvent extends Event<Message> { | public class MessageCreationEvent extends Event<Message> { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import envoy.event.Event; | |||||||
|  * Created: <strong>4 Dec 2019</strong><br> |  * Created: <strong>4 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class MessageModificationEvent extends Event<Message> { | public class MessageModificationEvent extends Event<Message> { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import envoy.event.Event; | |||||||
|  *  |  *  | ||||||
|  * @author: Maximilian Käfer |  * @author: Maximilian Käfer | ||||||
|  *  |  *  | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class SendEvent extends Event<Event<?>> { | public class SendEvent extends Event<Event<?>> { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import envoy.event.Event; | |||||||
|  * Created: <strong>15 Dec 2019</strong><br> |  * Created: <strong>15 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class ThemeChangeEvent extends Event<Theme> { | public class ThemeChangeEvent extends Event<Theme> { | ||||||
|  |  | ||||||
| @@ -20,7 +20,7 @@ public class ThemeChangeEvent extends Event<Theme> { | |||||||
| 	 * of the {@link Theme} currently in use | 	 * of the {@link Theme} currently in use | ||||||
| 	 * | 	 * | ||||||
| 	 * @param theme the new currently used {@link Theme} object | 	 * @param theme the new currently used {@link Theme} object | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public ThemeChangeEvent(Theme theme) { super(theme); } | 	public ThemeChangeEvent(Theme theme) { super(theme); } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| package envoy.client.event; | package envoy.client.event; | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ import envoy.util.SerializationUtils; | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class Client implements Closeable { | public class Client implements Closeable { | ||||||
|  |  | ||||||
| @@ -124,7 +124,7 @@ public class Client implements Closeable { | |||||||
| 	 *                             initialization | 	 *                             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 v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void initReceiver(LocalDb localDb, Cache<Message> receivedMessageCache) throws IOException { | 	public void initReceiver(LocalDb localDb, Cache<Message> receivedMessageCache) throws IOException { | ||||||
| 		checkOnline(); | 		checkOnline(); | ||||||
| @@ -181,7 +181,7 @@ public class Client implements Closeable { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param message the message to send | 	 * @param message the message to send | ||||||
| 	 * @throws IOException if the message does not reach the server | 	 * @throws IOException if the message does not reach the server | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void sendMessage(Message message) throws IOException { | 	public void sendMessage(Message message) throws IOException { | ||||||
| 		writeObject(message); | 		writeObject(message); | ||||||
| @@ -200,7 +200,7 @@ public class Client implements Closeable { | |||||||
| 	 * Requests a new {@link IdGenerator} from the server. | 	 * Requests a new {@link IdGenerator} from the server. | ||||||
| 	 * | 	 * | ||||||
| 	 * @throws IOException if the request does not reach the server | 	 * @throws IOException if the request does not reach the server | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void requestIdGenerator() throws IOException { | 	public void requestIdGenerator() throws IOException { | ||||||
| 		logger.info("Requesting new id generator..."); | 		logger.info("Requesting new id generator..."); | ||||||
| @@ -210,7 +210,7 @@ public class Client implements Closeable { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return a {@code Map<String, User>} of all users on the server with their | 	 * @return a {@code Map<String, User>} of all users on the server with their | ||||||
| 	 *         user names as keys | 	 *         user names as keys | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Map<String, User> getUsers() { | 	public Map<String, User> getUsers() { | ||||||
| 		checkOnline(); | 		checkOnline(); | ||||||
| @@ -232,7 +232,7 @@ public class Client implements Closeable { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the sender object that represents this client. | 	 * @return the sender object that represents this client. | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public User getSender() { return sender; } | 	public User getSender() { return sender; } | ||||||
|  |  | ||||||
| @@ -240,7 +240,7 @@ public class Client implements Closeable { | |||||||
| 	 * Sets the client user which is used to send messages. | 	 * Sets the client user which is used to send messages. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param sender the client user to set | 	 * @param sender the client user to set | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setSender(User sender) { this.sender = sender; } | 	public void setSender(User sender) { this.sender = sender; } | ||||||
|  |  | ||||||
| @@ -251,19 +251,19 @@ public class Client implements Closeable { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return {@code true} if a connection to the server could be established | 	 * @return {@code true} if a connection to the server could be established | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean isOnline() { return online; } | 	public boolean isOnline() { return online; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the contacts of this {@link Client} | 	 * @return the contacts of this {@link Client} | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Contacts getContacts() { return contacts; } | 	public Contacts getContacts() { return contacts; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param contacts the contacts to set | 	 * @param contacts the contacts to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setContacts(Contacts contacts) { this.contacts = contacts; } | 	public void setContacts(Contacts contacts) { this.contacts = contacts; } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * Created: <strong>4 Feb 2020</strong><br> |  * Created: <strong>4 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class MessageStatusChangeEventProcessor implements Consumer<MessageStatusChangeEvent> { | public class MessageStatusChangeEventProcessor implements Consumer<MessageStatusChangeEvent> { | ||||||
|  |  | ||||||
| @@ -25,7 +25,7 @@ public class MessageStatusChangeEventProcessor implements Consumer<MessageStatus | |||||||
| 	 * {@code RECEIVED} or {@code READ}. | 	 * {@code RECEIVED} or {@code READ}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param evt the status change event | 	 * @param evt the status change event | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	public void accept(MessageStatusChangeEvent evt) { | 	public void accept(MessageStatusChangeEvent evt) { | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * Created: <strong>31.12.2019</strong><br> |  * Created: <strong>31.12.2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class ReceivedMessageProcessor implements Consumer<Message> { | public class ReceivedMessageProcessor implements Consumer<Message> { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import envoy.util.SerializationUtils; | |||||||
|  * Created: <strong>30.12.2019</strong><br> |  * Created: <strong>30.12.2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class Receiver extends Thread { | public class Receiver extends Thread { | ||||||
|  |  | ||||||
| @@ -85,4 +85,4 @@ public class Receiver extends Thread { | |||||||
| 	 * Removes all object processors registered at this {@link Receiver}. | 	 * Removes all object processors registered at this {@link Receiver}. | ||||||
| 	 */ | 	 */ | ||||||
| 	public void removeAllProcessors() { processors.clear(); } | 	public void removeAllProcessors() { processors.clear(); } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ import envoy.event.UserStatusChangeEvent; | |||||||
|  * Created: <strong>2 Feb 2020</strong><br> |  * Created: <strong>2 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class UserStatusChangeProcessor implements Consumer<UserStatusChangeEvent> { | public class UserStatusChangeProcessor implements Consumer<UserStatusChangeEvent> { | ||||||
|  |  | ||||||
| @@ -20,7 +20,7 @@ public class UserStatusChangeProcessor implements Consumer<UserStatusChangeEvent | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param localDb the local database in which status updates will by applied | 	 * @param localDb the local database in which status updates will by applied | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public UserStatusChangeProcessor(LocalDb localDb) { this.localDb = localDb; } | 	public UserStatusChangeProcessor(LocalDb localDb) { this.localDb = localDb; } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * Created: <strong>6 Feb 2020</strong><br> |  * Created: <strong>6 Feb 2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class WriteProxy { | public class WriteProxy { | ||||||
|  |  | ||||||
| @@ -36,7 +36,7 @@ public class WriteProxy { | |||||||
| 	 *                events | 	 *                events | ||||||
| 	 * @param localDb the local database used to cache messages and message status | 	 * @param localDb the local database used to cache messages and message status | ||||||
| 	 *                change events | 	 *                change events | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public WriteProxy(Client client, LocalDb localDb) { | 	public WriteProxy(Client client, LocalDb localDb) { | ||||||
| 		this.client		= client; | 		this.client		= client; | ||||||
| @@ -68,7 +68,7 @@ public class WriteProxy { | |||||||
| 	 * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the | 	 * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the | ||||||
| 	 * server. | 	 * server. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void flushCache() { | 	public void flushCache() { | ||||||
| 		// Send messages | 		// Send messages | ||||||
| @@ -84,7 +84,7 @@ public class WriteProxy { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param message the message to send | 	 * @param message the message to send | ||||||
| 	 * @throws IOException if the message could not be sent | 	 * @throws IOException if the message could not be sent | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	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); | ||||||
| @@ -97,7 +97,7 @@ public class WriteProxy { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param evt the event to send | 	 * @param evt the event to send | ||||||
| 	 * @throws IOException if the event could not be sent | 	 * @throws IOException if the event could not be sent | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void writeMessageStatusChangeEvent(MessageStatusChangeEvent evt) throws IOException { | 	public void writeMessageStatusChangeEvent(MessageStatusChangeEvent evt) throws IOException { | ||||||
| 		if (client.isOnline()) client.sendEvent(evt); | 		if (client.isOnline()) client.sendEvent(evt); | ||||||
|   | |||||||
| @@ -4,6 +4,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| package envoy.client.net; | package envoy.client.net; | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import java.awt.color.ColorSpace; | |||||||
|  * Created: <strong>23.12.2019</strong><br> |  * Created: <strong>23.12.2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| @SuppressWarnings("javadoc") | @SuppressWarnings("javadoc") | ||||||
| public class Color extends java.awt.Color { | public class Color extends java.awt.Color { | ||||||
| @@ -102,13 +102,13 @@ public class Color extends java.awt.Color { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return the inversion of this {@link Color} by replacing the red, green and | 	 * @return the inversion of this {@link Color} by replacing the red, green and | ||||||
| 	 *         blue values by subtracting them form 255 | 	 *         blue values by subtracting them form 255 | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } | 	public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the hex value of this {@link Color} | 	 * @return the hex value of this {@link Color} | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } | 	public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										200
									
								
								src/main/java/envoy/client/ui/ContextMenu.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								src/main/java/envoy/client/ui/ContextMenu.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | |||||||
|  | package envoy.client.ui; | ||||||
|  |  | ||||||
|  | import java.awt.Component; | ||||||
|  | import java.awt.event.ActionListener; | ||||||
|  | import java.awt.event.MouseAdapter; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | import javax.swing.*; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This class defines a menu that will be automatically called if | ||||||
|  |  * {@link MouseEvent#isPopupTrigger()} returns true for the parent component. | ||||||
|  |  * The user has the possibility to directly add actions to be performed when | ||||||
|  |  * clicking on the element with the selected String. Additionally, for each | ||||||
|  |  * element an {@link Icon} can be added, but it must not be. | ||||||
|  |  * If the key(text) of an element starts with one of the predefined values, a | ||||||
|  |  * special component will be called: either a {@link JRadioButtonMenuItem}, a | ||||||
|  |  * {@link JCheckBoxMenuItem} or a {@link JMenu} will be created.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>ContextMenu.java</strong><br> | ||||||
|  |  * Created: <strong>17 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class ContextMenu extends JPopupMenu { | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = 2177146471226992104L; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JCheckBoxMenuItem} will be created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	checkboxMenuItem	= "ChBoMI"; | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JRadioButtonMenuItem} will be | ||||||
|  | 	 * created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	radioButtonMenuItem	= "RaBuMI"; | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JMenu} will be created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	subMenuItem			= "SubMI"; | ||||||
|  |  | ||||||
|  | 	private Map<String, ActionListener>	items		= new HashMap<>(); | ||||||
|  | 	private Map<String, Icon>			icons		= new HashMap<>(); | ||||||
|  | 	private Map<String, Integer>		mnemonics	= new HashMap<>(); | ||||||
|  |  | ||||||
|  | 	private ButtonGroup	radioButtonGroup	= new ButtonGroup(); | ||||||
|  | 	private boolean		built				= false; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param parent the component which will call this | ||||||
|  | 	 *               {@link ContextMenu} | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(Component parent) { setInvoker(parent); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param label            the string that a UI may use to display as a title | ||||||
|  | 	 *                         for the pop-up menu | ||||||
|  | 	 * @param parent           the component which will call this | ||||||
|  | 	 *                         {@link ContextMenu} | ||||||
|  | 	 * @param itemsWithActions a map of all strings to be displayed with according | ||||||
|  | 	 *                         actions | ||||||
|  | 	 * @param itemIcons        the icons to be displayed before a name, if wanted. | ||||||
|  | 	 *                         Only keys in here will have an Icon displayed. More | ||||||
|  | 	 *                         precisely, all keys here not included in the first | ||||||
|  | 	 *                         map will be thrown out. | ||||||
|  | 	 * @param itemMnemonics    the keyboard shortcuts that need to be pressed to | ||||||
|  | 	 *                         automatically execute the {@link JMenuItem} with the | ||||||
|  | 	 *                         given text | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(String label, Component parent, Map<String, ActionListener> itemsWithActions, Map<String, Icon> itemIcons, | ||||||
|  | 			Map<String, Integer> itemMnemonics) { | ||||||
|  | 		super(label); | ||||||
|  | 		setInvoker(parent); | ||||||
|  | 		this.items		= (itemsWithActions != null) ? itemsWithActions : items; | ||||||
|  | 		this.icons		= (itemIcons != null) ? itemIcons : icons; | ||||||
|  | 		this.mnemonics	= (itemMnemonics != null) ? itemMnemonics : mnemonics; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Prepares the PopupMenu to be displayed. Should only be used once all map | ||||||
|  | 	 * values have been set. | ||||||
|  | 	 * | ||||||
|  | 	 * @return this instance of {@link ContextMenu} to allow chaining behind the | ||||||
|  | 	 *         constructor | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu build() { | ||||||
|  | 		items.forEach((text, action) -> { | ||||||
|  | 			// case radio button wanted | ||||||
|  | 			AbstractButton item; | ||||||
|  | 			if (text.startsWith(radioButtonMenuItem)) { | ||||||
|  | 				item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 				radioButtonGroup.add(item); | ||||||
|  | 				// case check box wanted | ||||||
|  | 			} else if (text.startsWith(checkboxMenuItem)) | ||||||
|  | 				item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 			// case sub-menu wanted | ||||||
|  | 			else if (text.startsWith(subMenuItem)) item = new JMenu(text.substring(subMenuItem.length())); | ||||||
|  | 			else // normal JMenuItem wanted | ||||||
|  | 				item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 			item.addActionListener(action); | ||||||
|  | 			if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); | ||||||
|  | 			add(item); | ||||||
|  | 		}); | ||||||
|  | 		if (getInvoker() != null) { | ||||||
|  | 			getInvoker().addMouseListener(getShowingListener()); | ||||||
|  | 			built = true; | ||||||
|  | 		} | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param label the string that a UI may use to display as a title for the | ||||||
|  | 	 *              pop-up menu. | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(String label) { super(label); } | ||||||
|  |  | ||||||
|  | 	private MouseAdapter getShowingListener() { | ||||||
|  | 		return new MouseAdapter() { | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mouseClicked(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mousePressed(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mouseReleased(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			private void action(MouseEvent e) { | ||||||
|  | 				if (!built) build(); | ||||||
|  | 				if (e.isPopupTrigger()) { | ||||||
|  | 					// hides the menu if already visible | ||||||
|  | 					if (!isVisible()) show(e.getComponent(), e.getX(), e.getY()); | ||||||
|  | 					else setVisible(false); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Removes all subcomponents of this menu. | ||||||
|  | 	 * | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void clear() { | ||||||
|  | 		removeAll(); | ||||||
|  | 		items		= new HashMap<>(); | ||||||
|  | 		icons		= new HashMap<>(); | ||||||
|  | 		mnemonics	= new HashMap<>(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the items | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, ActionListener> getItems() { return items; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param items the items with the displayed text and the according action to | ||||||
|  | 	 *              take once called | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setItems(Map<String, ActionListener> items) { this.items = items; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the icons | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, Icon> getIcons() { return icons; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param icons the icons to set | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setIcons(Map<String, Icon> icons) { this.icons = icons; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the mnemonics (the keyboard shortcuts that automatically execute the | ||||||
|  | 	 *         command for a {@link JMenuItem} with corresponding text) | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, Integer> getMnemonics() { return mnemonics; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param mnemonics the keyboard shortcuts that need to be pressed to | ||||||
|  | 	 *                  automatically execute the {@link JMenuItem} with the given | ||||||
|  | 	 *                  text | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setMnemonics(Map<String, Integer> mnemonics) { this.mnemonics = mnemonics; } | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								src/main/java/envoy/client/ui/IconUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/main/java/envoy/client/ui/IconUtil.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | package envoy.client.ui; | ||||||
|  |  | ||||||
|  | import java.awt.Image; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.EnumMap; | ||||||
|  | import java.util.EnumSet; | ||||||
|  |  | ||||||
|  | import javax.imageio.ImageIO; | ||||||
|  | import javax.swing.ImageIcon; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Provides static utility methods for loading icons from the resource | ||||||
|  |  * folder.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong> | ||||||
|  |  * File: <strong>IconUtil.java</strong> | ||||||
|  |  * Created: <strong>16.03.2020</strong> | ||||||
|  |  * | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class IconUtil { | ||||||
|  |  | ||||||
|  | 	private IconUtil() {} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Loads an icon from resource folder and scales it to a given size. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param path the path to the icon inside the resource folder | ||||||
|  | 	 * @param size the size to scale the icon to | ||||||
|  | 	 * @return the scaled icon | ||||||
|  | 	 * @throws IOException if the loading process failed | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public static ImageIcon load(String path, int size) throws IOException { | ||||||
|  | 		return new ImageIcon(ImageIO.read(IconUtil.class.getResourceAsStream(path)).getScaledInstance(size, size, Image.SCALE_SMOOTH)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 *  | ||||||
|  | 	 * Loads icons specified by an enum. The images have to be named like the | ||||||
|  | 	 * lowercase enum constants with {@code .png} extension and be located inside a | ||||||
|  | 	 * folder with the lowercase name of the enum, which must be contained inside | ||||||
|  | 	 * the {@code /icons} folder. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param <T>       the enum that specifies the icons to load | ||||||
|  | 	 * @param enumClass the class of the enum | ||||||
|  | 	 * @param size      the size to scale the icons to | ||||||
|  | 	 * @return a map containing the loaded icons with the corresponding enum | ||||||
|  | 	 *         constants as keys | ||||||
|  | 	 * @throws IOException if the loading process failed | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public static <T extends Enum<T>> EnumMap<T, ImageIcon> loadByEnum(Class<T> enumClass, int size) throws IOException { | ||||||
|  | 		var	icons	= new EnumMap<T, ImageIcon>(enumClass); | ||||||
|  | 		var	path	= "/icons/" + enumClass.getSimpleName().toLowerCase() + "/"; | ||||||
|  | 		for (var e : EnumSet.allOf(enumClass)) | ||||||
|  | 			icons.put(e, load(path + e.toString().toLowerCase() + ".png", size)); | ||||||
|  | 		return icons; | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -1,93 +0,0 @@ | |||||||
| package envoy.client.ui; |  | ||||||
|  |  | ||||||
| import java.awt.BorderLayout; |  | ||||||
| import java.awt.Font; |  | ||||||
| import java.text.SimpleDateFormat; |  | ||||||
|  |  | ||||||
| import javax.swing.*; |  | ||||||
|  |  | ||||||
| import envoy.client.data.Settings; |  | ||||||
| import envoy.client.ui.list.ComponentList; |  | ||||||
| import envoy.client.ui.list.ComponentListCellRenderer; |  | ||||||
| import envoy.data.Message; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Defines how a message is displayed.<br> |  | ||||||
|  * <br> |  | ||||||
|  * Project: <strong>envoy-client</strong><br> |  | ||||||
|  * File: <strong>MessageListRenderer.java</strong><br> |  | ||||||
|  * Created: <strong>19 Oct 2019</strong><br> |  | ||||||
|  * |  | ||||||
|  * @author Kai S. K. Engelbart |  | ||||||
|  * @author Maximilian Käfer |  | ||||||
|  * @author Leon Hofmeister |  | ||||||
|  * @since Envoy v0.1-alpha |  | ||||||
|  */ |  | ||||||
| public class MessageListRenderer implements ComponentListCellRenderer<Message> { |  | ||||||
|  |  | ||||||
| 	private JTextArea messageTextArea; |  | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public JPanel getListCellComponent(ComponentList<? extends Message> list, Message value, boolean isSelected) { |  | ||||||
| 		final JPanel panel = new JPanel(); |  | ||||||
| 		panel.setLayout(new BorderLayout()); |  | ||||||
| 		final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); |  | ||||||
|  |  | ||||||
| 		// Panel background |  | ||||||
| 		panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); |  | ||||||
|  |  | ||||||
| 		// TODO: Handle message attachments |  | ||||||
|  |  | ||||||
| 		final String	state	= value.getStatus().toString(); |  | ||||||
| 		final String	date	= new SimpleDateFormat("dd.MM.yyyy HH:mm").format(value.getCreationDate()); |  | ||||||
| 		final String	text	= value.getText(); |  | ||||||
|  |  | ||||||
| 		// The Label that displays the creation date of a message |  | ||||||
| 		JLabel dateLabel = new JLabel(date); |  | ||||||
| 		// Set the date color to be the value of DateColorChat |  | ||||||
| 		dateLabel.setForeground(theme.getDateColor()); |  | ||||||
|  |  | ||||||
| 		panel.add(dateLabel, BorderLayout.NORTH); |  | ||||||
|  |  | ||||||
| 		// The JTextArea that displays the text content of a message and its status |  | ||||||
| 		messageTextArea = new JTextArea(text + System.getProperty("line.separator")); |  | ||||||
| 		messageTextArea.setLineWrap(true); |  | ||||||
| 		messageTextArea.setWrapStyleWord(true); |  | ||||||
| 		messageTextArea.setAlignmentX(0.5f); |  | ||||||
| 		messageTextArea.setForeground(theme.getMessageTextColor()); |  | ||||||
| 		messageTextArea.setBackground(panel.getBackground()); |  | ||||||
| 		messageTextArea.setEditable(false); |  | ||||||
|  |  | ||||||
| 		panel.add(messageTextArea, BorderLayout.CENTER); |  | ||||||
|  |  | ||||||
| 		JLabel statusLabel = new JLabel(state); |  | ||||||
| 		statusLabel.setFont(new Font("Arial", Font.BOLD, 14)); |  | ||||||
| 		Color statusColor; |  | ||||||
| 		switch (value.getStatus()) { |  | ||||||
| 			case WAITING: |  | ||||||
| 				statusColor = Color.gray; |  | ||||||
| 				break; |  | ||||||
| 			case SENT: |  | ||||||
| 				statusColor = Color.blue; |  | ||||||
| 				break; |  | ||||||
| 			case RECEIVED: |  | ||||||
| 				statusColor = Color.yellow; |  | ||||||
| 				break; |  | ||||||
| 			case READ: |  | ||||||
| 				statusColor = Color.green; |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				statusColor = theme.getMessageTextColor(); |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 		statusLabel.setForeground(statusColor); |  | ||||||
| 		statusLabel.setBackground(panel.getBackground()); |  | ||||||
|  |  | ||||||
| 		panel.add(statusLabel, BorderLayout.SOUTH); |  | ||||||
|  |  | ||||||
| 		// Define some space to the messages below |  | ||||||
| 		panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); |  | ||||||
|  |  | ||||||
| 		return panel; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -16,7 +16,7 @@ import envoy.exception.EnvoyException; | |||||||
|  * Created: <strong>3 Dec 2019</strong><br> |  * Created: <strong>3 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class StatusTrayIcon { | public class StatusTrayIcon { | ||||||
|  |  | ||||||
| @@ -41,7 +41,7 @@ public class StatusTrayIcon { | |||||||
| 	 *                    notifications are displayed | 	 *                    notifications are displayed | ||||||
| 	 * @throws EnvoyException if the currently used OS does not support the System | 	 * @throws EnvoyException if the currently used OS does not support the System | ||||||
| 	 *                        Tray API | 	 *                        Tray API | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public StatusTrayIcon(Window focusTarget) throws EnvoyException { | 	public StatusTrayIcon(Window focusTarget) throws EnvoyException { | ||||||
| 		if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); | 		if (!SystemTray.isSupported()) throw new EnvoyException("The Envoy tray icon is not supported."); | ||||||
| @@ -85,7 +85,7 @@ public class StatusTrayIcon { | |||||||
| 	 * | 	 * | ||||||
| 	 * @throws EnvoyException if the status icon could not be attaches to the system | 	 * @throws EnvoyException if the status icon could not be attaches to the system | ||||||
| 	 *                        tray for system-internal reasons | 	 *                        tray for system-internal reasons | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void show() throws EnvoyException { | 	public void show() throws EnvoyException { | ||||||
| 		try { | 		try { | ||||||
| @@ -94,4 +94,4 @@ public class StatusTrayIcon { | |||||||
| 			throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); | 			throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								src/main/java/envoy/client/ui/Theme.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										37
									
								
								src/main/java/envoy/client/ui/Theme.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -10,7 +10,7 @@ import java.util.Map; | |||||||
|  * Created: <strong>23 Nov 2019</strong><br> |  * Created: <strong>23 Nov 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class Theme implements Serializable { | public class Theme implements Serializable { | ||||||
|  |  | ||||||
| @@ -29,15 +29,16 @@ public class Theme implements Serializable { | |||||||
| 	 *                                    elements | 	 *                                    elements | ||||||
| 	 * @param interactableBackgroundColor the color of interactable background UI | 	 * @param interactableBackgroundColor the color of interactable background UI | ||||||
| 	 *                                    elements | 	 *                                    elements | ||||||
| 	 * @param messageColorChat            the color of chat messages | 	 * @param textColor                   the color normal text should be displayed | ||||||
|  | 	 *                                    in | ||||||
| 	 * @param dateColorChat               the color of chat message metadata | 	 * @param dateColorChat               the color of chat message metadata | ||||||
| 	 * @param selectionColor              the section color | 	 * @param selectionColor              the section color | ||||||
| 	 * @param typingMessageColor          the color of currently typed messages | 	 * @param typingMessageColor          the color of currently typed messages | ||||||
| 	 * @param userNameColor               the color of user names | 	 * @param userNameColor               the color of user names | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, | 	public Theme(String themeName, Color backgroundColor, Color cellColor, Color interactableForegroundColor, Color interactableBackgroundColor, | ||||||
| 			Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { | 			Color textColor, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) { | ||||||
|  |  | ||||||
| 		this.themeName = themeName; | 		this.themeName = themeName; | ||||||
|  |  | ||||||
| @@ -45,7 +46,7 @@ public class Theme implements Serializable { | |||||||
| 		colors.put("cellColor", cellColor); | 		colors.put("cellColor", cellColor); | ||||||
| 		colors.put("interactableForegroundColor", interactableForegroundColor); | 		colors.put("interactableForegroundColor", interactableForegroundColor); | ||||||
| 		colors.put("interactableBackgroundColor", interactableBackgroundColor); | 		colors.put("interactableBackgroundColor", interactableBackgroundColor); | ||||||
| 		colors.put("messageColorChat", messageColorChat); | 		colors.put("textColor", textColor); | ||||||
| 		colors.put("dateColorChat", dateColorChat); | 		colors.put("dateColorChat", dateColorChat); | ||||||
| 		colors.put("selectionColor", selectionColor); | 		colors.put("selectionColor", selectionColor); | ||||||
| 		colors.put("typingMessageColor", typingMessageColor); | 		colors.put("typingMessageColor", typingMessageColor); | ||||||
| @@ -58,7 +59,7 @@ public class Theme implements Serializable { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param name  the name of the {@link Theme} | 	 * @param name  the name of the {@link Theme} | ||||||
| 	 * @param other the {@link Theme} to copy | 	 * @param other the {@link Theme} to copy | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Theme(String name, Theme other) { | 	public Theme(String name, Theme other) { | ||||||
| 		themeName = name; | 		themeName = name; | ||||||
| @@ -68,69 +69,69 @@ public class Theme implements Serializable { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return a {@code Map<String, Color>} of all colors defined for this theme | 	 * @return a {@code Map<String, Color>} of all colors defined for this theme | ||||||
| 	 *         with their names as keys | 	 *         with their names as keys | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Map<String, Color> getColors() { return colors; } | 	public Map<String, Color> getColors() { return colors; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return name of the theme | 	 * @return name of the theme | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getThemeName() { return themeName; } | 	public String getThemeName() { return themeName; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return interactableForegroundColor | 	 * @return interactableForegroundColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } | 	public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the {@link Color} in which the text content of a message should be | 	 * @return the {@link Color} in which the text content of a message should be | ||||||
| 	 *         displayed | 	 *         displayed | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getMessageTextColor() { return colors.get("messageColorChat"); } | 	public Color getTextColor() { return colors.get("textColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the {@link Color} in which the creation date of a message should be | 	 * @return the {@link Color} in which the creation date of a message should be | ||||||
| 	 *         displayed | 	 *         displayed | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getDateColor() { return colors.get("dateColorChat"); } | 	public Color getDateColor() { return colors.get("dateColorChat"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return selectionColor | 	 * @return selectionColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getSelectionColor() { return colors.get("selectionColor"); } | 	public Color getSelectionColor() { return colors.get("selectionColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return typingMessageColor | 	 * @return typingMessageColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getTypingMessageColor() { return colors.get("typingMessageColor"); } | 	public Color getTypingMessageColor() { return colors.get("typingMessageColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return backgroundColor | 	 * @return backgroundColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getBackgroundColor() { return colors.get("backgroundColor"); } | 	public Color getBackgroundColor() { return colors.get("backgroundColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return cellColor | 	 * @return cellColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getCellColor() { return colors.get("cellColor"); } | 	public Color getCellColor() { return colors.get("cellColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return interactableBackgroundColor | 	 * @return interactableBackgroundColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); } | 	public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return userNameColor | 	 * @return userNameColor | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public Color getUserNameColor() { return colors.get("userNameColor"); } | 	public Color getUserNameColor() { return colors.get("userNameColor"); } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,13 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.container; | ||||||
| 
 | 
 | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
|  | import java.awt.datatransfer.StringSelection; | ||||||
| import java.awt.event.*; | import java.awt.event.*; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
| 
 | 
 | ||||||
| @@ -18,8 +23,16 @@ import envoy.client.event.MessageCreationEvent; | |||||||
| import envoy.client.event.ThemeChangeEvent; | import envoy.client.event.ThemeChangeEvent; | ||||||
| import envoy.client.net.Client; | import envoy.client.net.Client; | ||||||
| import envoy.client.net.WriteProxy; | import envoy.client.net.WriteProxy; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
| import envoy.client.ui.list.ComponentList; | import envoy.client.ui.list.ComponentList; | ||||||
| import envoy.client.ui.list.ComponentListModel; | import envoy.client.ui.list.ComponentList.SelectionMode; | ||||||
|  | import envoy.client.ui.list.Model; | ||||||
|  | import envoy.client.ui.list_component.ContactSearchComponent; | ||||||
|  | import envoy.client.ui.list_component.MessageComponent; | ||||||
|  | import envoy.client.ui.primary.PrimaryButton; | ||||||
|  | import envoy.client.ui.primary.PrimaryScrollPane; | ||||||
|  | import envoy.client.ui.primary.PrimaryTextArea; | ||||||
|  | import envoy.client.ui.renderer.UserListRenderer; | ||||||
| import envoy.client.ui.settings.SettingsScreen; | import envoy.client.ui.settings.SettingsScreen; | ||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
| import envoy.data.Message.MessageStatus; | import envoy.data.Message.MessageStatus; | ||||||
| @@ -36,13 +49,12 @@ import envoy.util.EnvoyLog; | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class ChatWindow extends JFrame { | public class ChatWindow extends JFrame { | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * This int defines the maximum amount of chars allowed per message. Currently | 	 * This integer defines the maximum amount of chars allowed per message. | ||||||
| 	 * set at 200. |  | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy 0.1-beta | 	 * @since Envoy 0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| @@ -59,11 +71,12 @@ public class ChatWindow extends JFrame { | |||||||
| 	private PrimaryTextArea			messageEnterTextArea	= new PrimaryTextArea(space); | 	private PrimaryTextArea			messageEnterTextArea	= new PrimaryTextArea(space); | ||||||
| 	private JList<User>				userList				= new JList<>(); | 	private JList<User>				userList				= new JList<>(); | ||||||
| 	private DefaultListModel<User>	userListModel			= new DefaultListModel<>(); | 	private DefaultListModel<User>	userListModel			= new DefaultListModel<>(); | ||||||
| 	private ComponentList<Message>	messageList				= new ComponentList<>(new MessageListRenderer()); | 	private ComponentList<Message>	messageList				= new ComponentList<>(); | ||||||
| 	private PrimaryScrollPane		scrollPane				= new PrimaryScrollPane(); | 	private PrimaryScrollPane		scrollPane				= new PrimaryScrollPane(); | ||||||
| 	private JTextPane				textPane				= new JTextPane(); | 	private JTextPane				textPane				= new JTextPane(); | ||||||
| 	private PrimaryButton			postButton				= new PrimaryButton("Post"); | 	private PrimaryButton			postButton				= new PrimaryButton("Post"); | ||||||
| 	private PrimaryButton			settingsButton			= new PrimaryButton("Settings"); | 	private PrimaryButton			settingsButton			= new PrimaryButton("Settings"); | ||||||
|  | 	private JPopupMenu				contextMenu; | ||||||
| 
 | 
 | ||||||
| 	// Contacts Header | 	// Contacts Header | ||||||
| 	private JPanel			contactsHeader	= new JPanel(); | 	private JPanel			contactsHeader	= new JPanel(); | ||||||
| @@ -71,13 +84,12 @@ public class ChatWindow extends JFrame { | |||||||
| 	private PrimaryButton	addContact		= new PrimaryButton("+"); | 	private PrimaryButton	addContact		= new PrimaryButton("+"); | ||||||
| 
 | 
 | ||||||
| 	// Search Contacts | 	// Search Contacts | ||||||
| 	private final JPanel					searchPane					= new JPanel(); | 	private final JPanel				searchPane					= new JPanel(); | ||||||
| 	private final PrimaryButton				cancelButton				= new PrimaryButton("x"); | 	private final PrimaryButton			cancelButton				= new PrimaryButton("x"); | ||||||
| 	private final PrimaryTextArea			searchField					= new PrimaryTextArea(space); | 	private final PrimaryTextArea		searchField					= new PrimaryTextArea(space); | ||||||
| 	private final PrimaryScrollPane			scrollForPossibleContacts	= new PrimaryScrollPane(); | 	private final PrimaryScrollPane		scrollForPossibleContacts	= new PrimaryScrollPane(); | ||||||
| 	private final ContactsSearchRenderer	contactRenderer				= new ContactsSearchRenderer(); | 	private final Model<User>			contactsModel				= new Model<>(); | ||||||
| 	private final ComponentListModel<User>	contactsModel				= new ComponentListModel<>(); | 	private final ComponentList<User>	contactList					= new ComponentList<User>().setRenderer(ContactSearchComponent::new); | ||||||
| 	private final ComponentList<User>		contactList					= new ComponentList<>(contactRenderer); |  | ||||||
| 
 | 
 | ||||||
| 	private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); | 	private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); | ||||||
| 
 | 
 | ||||||
| @@ -91,11 +103,12 @@ public class ChatWindow extends JFrame { | |||||||
| 	 * Initializes a {@link JFrame} with UI elements used to send and read messages | 	 * Initializes a {@link JFrame} with UI elements used to send and read messages | ||||||
| 	 * to different users. | 	 * to different users. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public ChatWindow() { | 	public ChatWindow() { | ||||||
| 		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | 		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | ||||||
| 		setBounds(100, 100, 600, 800); | 		setBounds(100, 100, 600, 800); | ||||||
|  | 		setMinimumSize(new Dimension(400, 300)); | ||||||
| 		setTitle("Envoy"); | 		setTitle("Envoy"); | ||||||
| 		setLocationRelativeTo(null); | 		setLocationRelativeTo(null); | ||||||
| 		setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); | 		setIconImage(Toolkit.getDefaultToolkit().createImage(getClass().getClassLoader().getResource("envoy_logo.png"))); | ||||||
| @@ -106,19 +119,46 @@ public class ChatWindow extends JFrame { | |||||||
| 		gbl_contentPane.columnWidths	= new int[] { 1, 1, 1 }; | 		gbl_contentPane.columnWidths	= new int[] { 1, 1, 1 }; | ||||||
| 		gbl_contentPane.rowHeights		= new int[] { 1, 1, 1, 1 }; | 		gbl_contentPane.rowHeights		= new int[] { 1, 1, 1, 1 }; | ||||||
| 		gbl_contentPane.columnWeights	= new double[] { 0.03, 1.0, 0.1 }; | 		gbl_contentPane.columnWeights	= new double[] { 0.03, 1.0, 0.1 }; | ||||||
| 		gbl_contentPane.rowWeights		= new double[] { 0.03, 0.001, 1.0, 0.005 }; | 		gbl_contentPane.rowWeights		= new double[] { 0.03, 0.001, 1.0, 0.001 }; | ||||||
| 		contentPane.setLayout(gbl_contentPane); | 		contentPane.setLayout(gbl_contentPane); | ||||||
| 
 | 
 | ||||||
| 		messageList.setBorder(new EmptyBorder(space, space, space, space)); | 		messageList.setBorder(new EmptyBorder(space, space, space, space)); | ||||||
|  | 		messageList.setSelectionMode(SelectionMode.SINGLE); | ||||||
|  | 		messageList.setSelectionHandler((message, comp, isSelected) -> { | ||||||
|  | 			final var theme = Settings.getInstance().getCurrentTheme(); | ||||||
|  | 			comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); | ||||||
|  | 
 | ||||||
|  | 			// ContextMenu | ||||||
|  | 			Map<String, ActionListener> commands = Map.of("forward selected message", evt -> { | ||||||
|  | 				final Message	selectedMessage	= messageList.getSingleSelectedElement(); | ||||||
|  | 				List<User>		chosenContacts	= ContactsChooserDialog | ||||||
|  | 					.showForwardingDialog("Forward selected message to", null, selectedMessage, localDb.getUsers().values()); | ||||||
|  | 				if (chosenContacts != null && chosenContacts.size() > 0) forwardMessage(selectedMessage, chosenContacts.toArray(new User[0])); | ||||||
|  | 			}, "copy", evt -> { | ||||||
|  | 				// TODO should be enhanced to allow also copying of message attachments, | ||||||
|  | 				// especially pictures | ||||||
|  | 				StringSelection copy = new StringSelection(messageList.getSingleSelectedElement().getText()); | ||||||
|  | 				Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); | ||||||
|  | 				// TODO insert implementation to edit and delete messages | ||||||
|  | 			}, "delete", evt -> {}, "edit", evt -> {}, "quote", evt -> {}); | ||||||
|  | 
 | ||||||
|  | 			if (isSelected) { | ||||||
|  | 				contextMenu = new ContextMenu(null, comp, commands, null, null).build(); | ||||||
|  | 				contextMenu.show(comp, 0, 0); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
| 
 | 
 | ||||||
| 		scrollPane.setViewportView(messageList); | 		scrollPane.setViewportView(messageList); | ||||||
|  | 		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); | ||||||
| 		scrollPane.addComponentListener(new ComponentAdapter() { | 		scrollPane.addComponentListener(new ComponentAdapter() { | ||||||
| 
 | 
 | ||||||
| 			// updates list elements when list is resized | 			// Update list elements when scroll pane (and thus list) is resized | ||||||
| 			@Override | 			@Override | ||||||
| 			public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } | 			public void componentResized(ComponentEvent e) { | ||||||
|  | 				messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); | ||||||
|  | 				messageList.synchronizeModel(); | ||||||
|  | 			} | ||||||
| 		}); | 		}); | ||||||
| 		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); |  | ||||||
| 
 | 
 | ||||||
| 		GridBagConstraints gbc_scrollPane = new GridBagConstraints(); | 		GridBagConstraints gbc_scrollPane = new GridBagConstraints(); | ||||||
| 		gbc_scrollPane.fill			= GridBagConstraints.BOTH; | 		gbc_scrollPane.fill			= GridBagConstraints.BOTH; | ||||||
| @@ -135,7 +175,10 @@ public class ChatWindow extends JFrame { | |||||||
| 		messageEnterTextArea.addInputMethodListener(new InputMethodListener() { | 		messageEnterTextArea.addInputMethodListener(new InputMethodListener() { | ||||||
| 
 | 
 | ||||||
| 			@Override | 			@Override | ||||||
| 			public void inputMethodTextChanged(InputMethodEvent event) { checkMessageTextLength(); } | 			public void inputMethodTextChanged(InputMethodEvent event) { | ||||||
|  | 				checkMessageTextLength(); | ||||||
|  | 				checkPostButton(messageEnterTextArea.getText()); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			@Override | 			@Override | ||||||
| 			public void caretPositionChanged(InputMethodEvent event) {} | 			public void caretPositionChanged(InputMethodEvent event) {} | ||||||
| @@ -146,32 +189,30 @@ public class ChatWindow extends JFrame { | |||||||
| 			@Override | 			@Override | ||||||
| 			public void keyReleased(KeyEvent e) { | 			public void keyReleased(KeyEvent e) { | ||||||
| 				if (e.getKeyCode() == KeyEvent.VK_ENTER | 				if (e.getKeyCode() == KeyEvent.VK_ENTER | ||||||
| 						&& (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)) | 						&& (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK) | ||||||
|  | 						&& postButton.isEnabled()) | ||||||
| 					postMessage(); | 					postMessage(); | ||||||
| 				// Checking if text is too long | 				// Checking if text is too long | ||||||
| 				checkMessageTextLength(); | 				checkMessageTextLength(); | ||||||
|  | 				checkPostButton(messageEnterTextArea.getText()); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		GridBagConstraints gbc_scrollPaneForTextInput = new GridBagConstraints(); | 		GridBagConstraints gbc_messageEnterTextArea = new GridBagConstraints(); | ||||||
| 		gbc_scrollPaneForTextInput.fill		= GridBagConstraints.BOTH; | 		gbc_messageEnterTextArea.fill	= GridBagConstraints.BOTH; | ||||||
| 		gbc_scrollPaneForTextInput.gridx	= 1; | 		gbc_messageEnterTextArea.gridx	= 1; | ||||||
| 		gbc_scrollPaneForTextInput.gridy	= 3; | 		gbc_messageEnterTextArea.gridy	= 3; | ||||||
| 
 | 		gbc_messageEnterTextArea.insets	= insets; | ||||||
| 		gbc_scrollPaneForTextInput.insets = insets; | 		contentPane.add(messageEnterTextArea, gbc_messageEnterTextArea); | ||||||
| 
 |  | ||||||
| 		contentPane.add(messageEnterTextArea, gbc_scrollPaneForTextInput); |  | ||||||
| 
 | 
 | ||||||
| 		// Post Button | 		// Post Button | ||||||
| 		GridBagConstraints gbc_postButton = new GridBagConstraints(); | 		GridBagConstraints gbc_postButton = new GridBagConstraints(); | ||||||
| 
 |  | ||||||
| 		gbc_postButton.fill		= GridBagConstraints.BOTH; | 		gbc_postButton.fill		= GridBagConstraints.BOTH; | ||||||
| 		gbc_postButton.gridx	= 2; | 		gbc_postButton.gridx	= 2; | ||||||
| 		gbc_postButton.gridy	= 3; | 		gbc_postButton.gridy	= 3; | ||||||
| 
 | 		gbc_postButton.insets	= insets; | ||||||
| 		gbc_postButton.insets = insets; |  | ||||||
| 
 |  | ||||||
| 		postButton.addActionListener((evt) -> { postMessage(); }); | 		postButton.addActionListener((evt) -> { postMessage(); }); | ||||||
|  | 		postButton.setEnabled(false); | ||||||
| 		contentPane.add(postButton, gbc_postButton); | 		contentPane.add(postButton, gbc_postButton); | ||||||
| 
 | 
 | ||||||
| 		// Settings Button | 		// Settings Button | ||||||
| @@ -353,11 +394,11 @@ public class ChatWindow extends JFrame { | |||||||
| 		gbc_addContact.gridy	= 0; | 		gbc_addContact.gridy	= 0; | ||||||
| 		gbc_addContact.insets	= insets; | 		gbc_addContact.insets	= insets; | ||||||
| 
 | 
 | ||||||
| 		addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); }); | 		addContact.addActionListener(evt -> drawContactSearch(gbc_searchPane)); | ||||||
| 
 | 
 | ||||||
| 		contactsHeader.add(addContact, gbc_addContact); | 		contactsHeader.add(addContact, gbc_addContact); | ||||||
| 
 | 
 | ||||||
| 		applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); | 		applyTheme(Settings.getInstance().getCurrentTheme()); | ||||||
| 
 | 
 | ||||||
| 		contentPane.add(contactsHeader, gbc_contactsHeader); | 		contentPane.add(contactsHeader, gbc_contactsHeader); | ||||||
| 		contentPane.revalidate(); | 		contentPane.revalidate(); | ||||||
| @@ -440,15 +481,16 @@ public class ChatWindow extends JFrame { | |||||||
| 	 * Used to immediately reload the {@link ChatWindow} when settings were changed. | 	 * Used to immediately reload the {@link ChatWindow} when settings were changed. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param theme the theme to change colors into | 	 * @param theme the theme to change colors into | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	private void applyTheme(Theme theme) { | 	private void applyTheme(Theme theme) { | ||||||
| 		// contentPane | 		// contentPane | ||||||
| 		contentPane.setBackground(theme.getBackgroundColor()); | 		contentPane.setBackground(theme.getBackgroundColor()); | ||||||
| 		contentPane.setForeground(theme.getUserNameColor()); | 		contentPane.setForeground(theme.getUserNameColor()); | ||||||
| 		// messageList | 		// messageList | ||||||
| 		messageList.setForeground(theme.getMessageTextColor()); | 		messageList.setForeground(theme.getTextColor()); | ||||||
| 		messageList.setBackground(theme.getCellColor()); | 		messageList.setBackground(theme.getCellColor()); | ||||||
|  | 		messageList.synchronizeModel(); | ||||||
| 		// scrollPane | 		// scrollPane | ||||||
| 		scrollPane.applyTheme(theme); | 		scrollPane.applyTheme(theme); | ||||||
| 		scrollPane.autoscroll(); | 		scrollPane.autoscroll(); | ||||||
| @@ -482,33 +524,68 @@ public class ChatWindow extends JFrame { | |||||||
| 		searchField.setForeground(theme.getUserNameColor()); | 		searchField.setForeground(theme.getUserNameColor()); | ||||||
| 		cancelButton.setBackground(theme.getInteractableBackgroundColor()); | 		cancelButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		cancelButton.setForeground(theme.getInteractableForegroundColor()); | 		cancelButton.setForeground(theme.getInteractableForegroundColor()); | ||||||
| 		contactList.setForeground(theme.getMessageTextColor()); | 		contactList.setForeground(theme.getTextColor()); | ||||||
| 		contactList.setBackground(theme.getCellColor()); | 		contactList.setBackground(theme.getCellColor()); | ||||||
| 		scrollForPossibleContacts.applyTheme(theme); | 		scrollForPossibleContacts.applyTheme(theme); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sends a new message to the server based on the text entered in the textArea. | ||||||
|  | 	 * | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
| 	private void postMessage() { | 	private void postMessage() { | ||||||
| 		if (userList.isSelectionEmpty()) { | 		if (userList.isSelectionEmpty()) { | ||||||
| 			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); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  | 		String text = messageEnterTextArea.getText().trim(); | ||||||
|  | 		if (!text.isEmpty()) checkMessageTextLength(); | ||||||
| 
 | 
 | ||||||
| 		if (!messageEnterTextArea.getText().isEmpty()) try { | 		// Create message | ||||||
| 			checkMessageTextLength(); | 		final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) | ||||||
| 			// Create message | 			.setText(text) | ||||||
| 			final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) | 			.build(); | ||||||
| 				.setText(messageEnterTextArea.getText()) | 		sendMessage(message); | ||||||
| 				.build(); | 		// Clear text field | ||||||
|  | 		messageEnterTextArea.setText(""); | ||||||
|  | 		postButton.setEnabled(false); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Forwards a message. | ||||||
|  | 	 * | ||||||
|  | 	 * @param message   the message to forward | ||||||
|  | 	 * @param recipient the new recipient of the message | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	private void forwardMessage(Message message, User... recipients) { | ||||||
|  | 		Arrays.stream(recipients).forEach(recipient -> { | ||||||
|  | 			if (message != null && recipients != null) sendMessage(new MessageBuilder(message, recipient.getId(), localDb.getIdGenerator()).build()); | ||||||
|  | 			else throw new NullPointerException("No recipient or no message selected"); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@SuppressWarnings("unused") | ||||||
|  | 	private void forwardMessages(Collection<Message> messages, User... recipients) { | ||||||
|  | 		messages.forEach(message -> { forwardMessage(message, recipients); }); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Sends a {@link Message} to the server. | ||||||
|  | 	 * | ||||||
|  | 	 * @param message the message to send | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	private void sendMessage(final Message message) { | ||||||
|  | 		try { | ||||||
| 			// Send message | 			// Send message | ||||||
| 			writeProxy.writeMessage(message); | 			writeProxy.writeMessage(message); | ||||||
| 
 | 
 | ||||||
| 			// Add message to PersistentLocalDb and update UI | 			// Add message to PersistentLocalDb and update UI | ||||||
| 			currentChat.appendMessage(message); | 			currentChat.appendMessage(message); | ||||||
| 
 | 
 | ||||||
| 			// Clear text field |  | ||||||
| 			messageEnterTextArea.setText(""); |  | ||||||
| 
 |  | ||||||
| 			// Update UI | 			// Update UI | ||||||
| 			revalidate(); | 			revalidate(); | ||||||
| 			repaint(); | 			repaint(); | ||||||
| @@ -525,7 +602,7 @@ public class ChatWindow extends JFrame { | |||||||
| 	private void readCurrentChat() { | 	private void readCurrentChat() { | ||||||
| 		try { | 		try { | ||||||
| 			currentChat.read(writeProxy); | 			currentChat.read(writeProxy); | ||||||
| 			messageList.synchronizeModel(); | 			if (messageList.getRenderer() != null) messageList.synchronizeModel(); | ||||||
| 		} catch (IOException e) { | 		} catch (IOException e) { | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 			logger.log(Level.WARNING, "Couldn't notify server about message status change", e); | 			logger.log(Level.WARNING, "Couldn't notify server about message status change", e); | ||||||
| @@ -562,13 +639,15 @@ public class ChatWindow extends JFrame { | |||||||
| 	 * @param writeProxy the write proxy used to send messages and status change | 	 * @param writeProxy the write proxy used to send messages and status change | ||||||
| 	 *                   events to the server or cache them inside the local | 	 *                   events to the server or cache them inside the local | ||||||
| 	 *                   database | 	 *                   database | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) { | 	public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) { | ||||||
| 		this.client		= client; | 		this.client		= client; | ||||||
| 		this.localDb	= localDb; | 		this.localDb	= localDb; | ||||||
| 		this.writeProxy	= writeProxy; | 		this.writeProxy	= writeProxy; | ||||||
| 
 | 
 | ||||||
|  | 		messageList.setRenderer((list, message) -> new MessageComponent(list, message, client.getSender().getId())); | ||||||
|  | 
 | ||||||
| 		// Load users and chats | 		// Load users and chats | ||||||
| 		new Thread(() -> { | 		new Thread(() -> { | ||||||
| 			localDb.getUsers().values().forEach(user -> { | 			localDb.getUsers().values().forEach(user -> { | ||||||
| @@ -589,7 +668,7 @@ public class ChatWindow extends JFrame { | |||||||
| 	 * {@link ChatWindow#MAX_MESSAGE_LENGTH} | 	 * {@link ChatWindow#MAX_MESSAGE_LENGTH} | ||||||
| 	 * and splits the text into the allowed part, if that is the case. | 	 * and splits the text into the allowed part, if that is the case. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void checkMessageTextLength() { | 	private void checkMessageTextLength() { | ||||||
| 		String input = messageEnterTextArea.getText(); | 		String input = messageEnterTextArea.getText(); | ||||||
| @@ -603,4 +682,6 @@ public class ChatWindow extends JFrame { | |||||||
| 					JOptionPane.WARNING_MESSAGE); | 					JOptionPane.WARNING_MESSAGE); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	private void checkPostButton(String text) { postButton.setEnabled(!text.trim().isBlank()); } | ||||||
| } | } | ||||||
							
								
								
									
										148
									
								
								src/main/java/envoy/client/ui/container/ContactsChooserDialog.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										148
									
								
								src/main/java/envoy/client/ui/container/ContactsChooserDialog.java
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,148 @@ | |||||||
|  | package envoy.client.ui.container; | ||||||
|  |  | ||||||
|  | import java.awt.BorderLayout; | ||||||
|  | import java.awt.Component; | ||||||
|  | import java.awt.event.ActionListener; | ||||||
|  | import java.awt.event.KeyEvent; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import javax.swing.JButton; | ||||||
|  | import javax.swing.JDialog; | ||||||
|  | import javax.swing.JPanel; | ||||||
|  | import javax.swing.border.EmptyBorder; | ||||||
|  |  | ||||||
|  | import envoy.client.data.Settings; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
|  | import envoy.client.ui.list.ComponentList; | ||||||
|  | import envoy.client.ui.list.ComponentList.SelectionMode; | ||||||
|  | import envoy.client.ui.list.Model; | ||||||
|  | import envoy.client.ui.list_component.UserComponent; | ||||||
|  | import envoy.data.Message; | ||||||
|  | import envoy.data.User; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This class defines a dialog to choose contacts from.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>ContactsChooserDialog.java</strong><br> | ||||||
|  |  * Created: <strong>15 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class ContactsChooserDialog extends JDialog { | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = -5774558118579032256L; | ||||||
|  |  | ||||||
|  | 	private ComponentList<User>	contactList		= new ComponentList<User>().setModel(new Model<User>()) | ||||||
|  | 		.setRenderer((list, user) -> new UserComponent(user)); | ||||||
|  | 	private JButton				okButton		= new JButton("Ok"); | ||||||
|  | 	private JButton				cancelButton	= new JButton("Cancel"); | ||||||
|  |  | ||||||
|  | 	private final Theme theme = Settings.getInstance().getCurrentTheme(); | ||||||
|  |  | ||||||
|  | 	private final JPanel contentPanel = new JPanel(); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Shows a modal contacts-chooser dialog and blocks until the | ||||||
|  | 	 * dialog is hidden. If the user presses the "OK" button, then | ||||||
|  | 	 * this method hides/disposes the dialog and returns the selected element (has | ||||||
|  | 	 * yet | ||||||
|  | 	 * to be casted back to its original type due to the limitations of Generics in | ||||||
|  | 	 * Java). | ||||||
|  | 	 * If the user presses the "Cancel" button or closes the dialog without | ||||||
|  | 	 * pressing "OK", then this method disposes the dialog and returns an empty | ||||||
|  | 	 * <code>ArrayList</code>. | ||||||
|  | 	 * | ||||||
|  | 	 * @param title   the title of the dialog | ||||||
|  | 	 * @param parent  this @{@link Component} will be parsed to | ||||||
|  | 	 *                {@link java.awt.Window#setLocationRelativeTo(Component)} in | ||||||
|  | 	 *                order to change the location of the dialog | ||||||
|  | 	 * @param message the {@link Message} to display on top of the Dialog | ||||||
|  | 	 * @param users   the users that should be displayed | ||||||
|  | 	 * @return the selected Element (yet has to be casted to the wanted type due to | ||||||
|  | 	 *         the Generics limitations in Java) | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public static List<User> showForwardingDialog(String title, Component parent, Message message, Collection<User> users) { | ||||||
|  | 		ContactsChooserDialog dialog = new ContactsChooserDialog(parent); | ||||||
|  | 		dialog.setTitle(title); | ||||||
|  | 		dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); | ||||||
|  | 		dialog.addCancelButtonActionListener(e -> dialog.dispose()); | ||||||
|  |  | ||||||
|  | 		List<User> results = new ArrayList<>(); | ||||||
|  | 		dialog.addOkButtonActionListener(e -> {  | ||||||
|  | 			results.addAll(dialog.getContactList().getSelectedElements()); | ||||||
|  | 			dialog.dispose(); | ||||||
|  | 		}); | ||||||
|  | 		Model<User> contactListModel = dialog.getContactList().getModel(); | ||||||
|  | 		users.forEach(contactListModel::add); | ||||||
|  |  | ||||||
|  | 		dialog.setModalityType(ModalityType.APPLICATION_MODAL); | ||||||
|  | 		dialog.setVisible(true); | ||||||
|  |  | ||||||
|  | 		return results; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param parent this @{@link Component} will be parsed to | ||||||
|  | 	 *               {@link java.awt.Window#setLocationRelativeTo(Component)} | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	private ContactsChooserDialog(Component parent) { | ||||||
|  | 		contactList.setSelectionMode(SelectionMode.MULTIPLE); | ||||||
|  | 		contactList.setSelectionHandler((user, comp, isSelected) -> { | ||||||
|  | 			final var theme = Settings.getInstance().getCurrentTheme(); | ||||||
|  | 			comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); | ||||||
|  | 		}); | ||||||
|  | 		setLocationRelativeTo(parent); | ||||||
|  | 		getContentPane().setLayout(new BorderLayout()); | ||||||
|  | 		setBackground(theme.getBackgroundColor()); | ||||||
|  | 		setForeground(theme.getTextColor()); | ||||||
|  | 		setSize(400, 400); | ||||||
|  | 		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); | ||||||
|  | 		getContentPane().add(contentPanel, BorderLayout.CENTER); | ||||||
|  | 		contentPanel.setLayout(new BorderLayout(0, 0)); | ||||||
|  | 		contentPanel.add(contactList, BorderLayout.CENTER); | ||||||
|  | 		{ | ||||||
|  | 			JPanel buttonPane = new JPanel(); | ||||||
|  | 			getContentPane().add(buttonPane, BorderLayout.SOUTH); | ||||||
|  | 			{ | ||||||
|  | 				okButton = new JButton("OK"); | ||||||
|  | 				okButton.setMnemonic(KeyEvent.VK_ENTER); | ||||||
|  | 				okButton.setActionCommand("OK"); | ||||||
|  | 				buttonPane.setLayout(new BorderLayout(0, 0)); | ||||||
|  | 				buttonPane.add(okButton, BorderLayout.EAST); | ||||||
|  | 				getRootPane().setDefaultButton(okButton); | ||||||
|  | 			} | ||||||
|  | 			{ | ||||||
|  | 				cancelButton = new JButton("Cancel"); | ||||||
|  | 				cancelButton.setActionCommand("Cancel"); | ||||||
|  | 				buttonPane.add(cancelButton, BorderLayout.WEST); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		applyTheme(Settings.getInstance().getCurrentTheme()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private void applyTheme(Theme theme) { | ||||||
|  | 		contentPanel.setBackground(theme.getBackgroundColor()); | ||||||
|  | 		contentPanel.setForeground(theme.getTextColor()); | ||||||
|  | 		contactList.setBackground(theme.getCellColor()); | ||||||
|  | 		okButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
|  | 		okButton.setForeground(theme.getTextColor()); | ||||||
|  | 		cancelButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
|  | 		cancelButton.setForeground(theme.getTextColor()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the underlying {@link ComponentList} | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	private ComponentList<User> getContactList() { return contactList; } | ||||||
|  |  | ||||||
|  | 	private void addOkButtonActionListener(ActionListener l) { okButton.addActionListener(l); } | ||||||
|  |  | ||||||
|  | 	private void addCancelButtonActionListener(ActionListener l) { cancelButton.addActionListener(l); } | ||||||
|  | } | ||||||
							
								
								
									
										255
									
								
								src/main/java/envoy/client/ui/container/ContextMenu.java
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										255
									
								
								src/main/java/envoy/client/ui/container/ContextMenu.java
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,255 @@ | |||||||
|  | package envoy.client.ui.container; | ||||||
|  |  | ||||||
|  | import java.awt.Color; | ||||||
|  | import java.awt.Component; | ||||||
|  | import java.awt.event.ActionListener; | ||||||
|  | import java.awt.event.MouseAdapter; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | import javax.swing.*; | ||||||
|  |  | ||||||
|  | import envoy.client.data.Settings; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This class defines a menu that will be automatically called if | ||||||
|  |  * {@link MouseEvent#isPopupTrigger()} returns true for the parent component. | ||||||
|  |  * The user has the possibility to directly add actions to be performed when | ||||||
|  |  * clicking on the element with the selected String. Additionally, for each | ||||||
|  |  * element an {@link Icon} can be added, but it must not be. | ||||||
|  |  * If the key(text) of an element starts with one of the predefined values, a | ||||||
|  |  * special component will be called: either a {@link JRadioButtonMenuItem}, a | ||||||
|  |  * {@link JCheckBoxMenuItem} or a {@link JMenu} will be created.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>ContextMenu.java</strong><br> | ||||||
|  |  * Created: <strong>17 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class ContextMenu extends JPopupMenu { | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = 2177146471226992104L; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JCheckBoxMenuItem} will be created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	checkboxMenuItem	= "ChBoMI"; | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JRadioButtonMenuItem} will be | ||||||
|  | 	 * created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	radioButtonMenuItem	= "RaBuMI"; | ||||||
|  | 	/** | ||||||
|  | 	 * If a key starts with this String, a {@link JMenu} will be created | ||||||
|  | 	 */ | ||||||
|  | 	public static final String	subMenuItem			= "SubMI"; | ||||||
|  |  | ||||||
|  | 	private Map<String, ActionListener>	items		= new HashMap<>(); | ||||||
|  | 	private Map<String, Icon>			icons		= new HashMap<>(); | ||||||
|  | 	private Map<String, Integer>		mnemonics	= new HashMap<>(); | ||||||
|  |  | ||||||
|  | 	private ButtonGroup	radioButtonGroup	= new ButtonGroup(); | ||||||
|  | 	private boolean		built				= false; | ||||||
|  | 	private boolean		visible				= false; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param parent the component which will call this | ||||||
|  | 	 *               {@link ContextMenu} | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(Component parent) { | ||||||
|  | 		setInvoker(parent); | ||||||
|  | 		setOpaque(true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param label            the string that a UI may use to display as a title | ||||||
|  | 	 *                         for the pop-up menu | ||||||
|  | 	 * @param parent           the component which will call this | ||||||
|  | 	 *                         {@link ContextMenu} | ||||||
|  | 	 * @param itemsWithActions a map of all strings to be displayed with according | ||||||
|  | 	 *                         actions | ||||||
|  | 	 * @param itemIcons        the icons to be displayed before a name, if wanted. | ||||||
|  | 	 *                         Only keys in here will have an Icon displayed. More | ||||||
|  | 	 *                         precisely, all keys here not included in the first | ||||||
|  | 	 *                         map will be thrown out. | ||||||
|  | 	 * @param itemMnemonics    the keyboard shortcuts that need to be pressed to | ||||||
|  | 	 *                         automatically execute the {@link JMenuItem} with the | ||||||
|  | 	 *                         given text | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(String label, Component parent, Map<String, ActionListener> itemsWithActions, Map<String, Icon> itemIcons, | ||||||
|  | 			Map<String, Integer> itemMnemonics) { | ||||||
|  | 		this(label); | ||||||
|  | 		setInvoker(parent); | ||||||
|  | 		this.items		= (itemsWithActions != null) ? itemsWithActions : items; | ||||||
|  | 		this.icons		= (itemIcons != null) ? itemIcons : icons; | ||||||
|  | 		this.mnemonics	= (itemMnemonics != null) ? itemMnemonics : mnemonics; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param label the string that a UI may use to display as a title for the | ||||||
|  | 	 *              pop-up menu. | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu(String label) { | ||||||
|  | 		super(label); | ||||||
|  | 		setOpaque(true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Prepares the PopupMenu to be displayed. Should only be used once all map | ||||||
|  | 	 * values have been set. | ||||||
|  | 	 * | ||||||
|  | 	 * @return this instance of {@link ContextMenu} to allow chaining behind the | ||||||
|  | 	 *         constructor | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ContextMenu build() { | ||||||
|  | 		items.forEach((text, action) -> { | ||||||
|  | 			// case radio button wanted | ||||||
|  | 			AbstractButton item; | ||||||
|  | 			if (text.startsWith(radioButtonMenuItem)) { | ||||||
|  | 				item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 				radioButtonGroup.add(item); | ||||||
|  | 				// case check box wanted | ||||||
|  | 			} else if (text.startsWith(checkboxMenuItem)) | ||||||
|  | 				item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 			// case sub-menu wanted | ||||||
|  | 			else if (text.startsWith(subMenuItem)) item = new JMenu(text.substring(subMenuItem.length())); | ||||||
|  | 			else // normal JMenuItem wanted | ||||||
|  | 				item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); | ||||||
|  | 			item.addActionListener(action); | ||||||
|  | 			item.setOpaque(true); | ||||||
|  | 			if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); | ||||||
|  | 			add(item); | ||||||
|  | 		}); | ||||||
|  | 		getInvoker().addMouseListener(getShowingListener()); | ||||||
|  | 		applyTheme(Settings.getInstance().getCurrentTheme()); | ||||||
|  | 		built = true; | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private MouseAdapter getShowingListener() { | ||||||
|  | 		return new MouseAdapter() { | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mouseClicked(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mousePressed(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mouseReleased(MouseEvent e) { action(e); } | ||||||
|  |  | ||||||
|  | 			private void action(MouseEvent e) { | ||||||
|  | 				if (!built) build(); | ||||||
|  | 				if (e.isPopupTrigger()) { | ||||||
|  | 					// hides the menu if already visible | ||||||
|  | 					visible = !visible; | ||||||
|  | 					if (visible) show(e.getComponent(), e.getX(), e.getY()); | ||||||
|  | 					else setVisible(false); | ||||||
|  |  | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Removes all subcomponents of this menu. | ||||||
|  | 	 * | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void clear() { | ||||||
|  | 		removeAll(); | ||||||
|  | 		items		= new HashMap<>(); | ||||||
|  | 		icons		= new HashMap<>(); | ||||||
|  | 		mnemonics	= new HashMap<>(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the items | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, ActionListener> getItems() { return items; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param items the items with the displayed text and the according action to | ||||||
|  | 	 *              take once called | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setItems(Map<String, ActionListener> items) { this.items = items; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the icons | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, Icon> getIcons() { return icons; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param icons the icons to set | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setIcons(Map<String, Icon> icons) { this.icons = icons; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the mnemonics (the keyboard shortcuts that automatically execute the | ||||||
|  | 	 *         command for a {@link JMenuItem} with corresponding text) | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Map<String, Integer> getMnemonics() { return mnemonics; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param mnemonics the keyboard shortcuts that need to be pressed to | ||||||
|  | 	 *                  automatically execute the {@link JMenuItem} with the given | ||||||
|  | 	 *                  text | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setMnemonics(Map<String, Integer> mnemonics) { this.mnemonics = mnemonics; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * {@inheritDoc}<br> | ||||||
|  | 	 * Additionally sets the foreground of all subcomponents of this | ||||||
|  | 	 * {@link ContextMenu}. | ||||||
|  | 	 * | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	@Override | ||||||
|  | 	public void setForeground(Color color) { | ||||||
|  | 		super.setForeground(color); | ||||||
|  | 		for (MenuElement element : getSubElements()) | ||||||
|  | 			((Component) element).setForeground(color); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * {@inheritDoc}<br> | ||||||
|  | 	 * Additionally sets the background of all subcomponents of this | ||||||
|  | 	 * {@link ContextMenu}. | ||||||
|  | 	 * | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	@Override | ||||||
|  | 	public void setBackground(Color color) { | ||||||
|  | 		super.setBackground(color); | ||||||
|  | 		for (MenuElement element : getSubElements()) | ||||||
|  | 			((Component) element).setBackground(color); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the fore- and background of all elements contained in this | ||||||
|  | 	 * {@link ContextMenu} | ||||||
|  | 	 * This method is to be only used by Envoy as {@link Theme} is an | ||||||
|  | 	 * Envoy-exclusive object. | ||||||
|  | 	 * | ||||||
|  | 	 * @param theme the theme to use | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	protected void applyTheme(Theme theme) { | ||||||
|  | 		setBackground(theme.getCellColor()); | ||||||
|  | 		setForeground(theme.getTextColor()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.container; | ||||||
| 
 | 
 | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
| import java.awt.event.ItemEvent; | import java.awt.event.ItemEvent; | ||||||
| @@ -16,6 +16,8 @@ import javax.swing.border.EmptyBorder; | |||||||
| import envoy.client.data.*; | import envoy.client.data.*; | ||||||
| import envoy.client.event.HandshakeSuccessfulEvent; | import envoy.client.event.HandshakeSuccessfulEvent; | ||||||
| import envoy.client.net.Client; | import envoy.client.net.Client; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
|  | import envoy.client.ui.primary.PrimaryButton; | ||||||
| import envoy.data.LoginCredentials; | import envoy.data.LoginCredentials; | ||||||
| import envoy.data.Message; | import envoy.data.Message; | ||||||
| import envoy.data.User; | import envoy.data.User; | ||||||
| @@ -31,7 +33,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class LoginDialog extends JDialog { | public class LoginDialog extends JDialog { | ||||||
| 
 | 
 | ||||||
| @@ -72,7 +74,7 @@ public class LoginDialog extends JDialog { | |||||||
| 	 * @param localDb              the local database in which data is persisted | 	 * @param localDb              the local database in which data is persisted | ||||||
| 	 * @param receivedMessageCache the cache that stored messages received during | 	 * @param receivedMessageCache the cache that stored messages received during | ||||||
| 	 *                             the handshake | 	 *                             the handshake | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public LoginDialog(Client client, LocalDb localDb, Cache<Message> receivedMessageCache) { | 	public LoginDialog(Client client, LocalDb localDb, Cache<Message> receivedMessageCache) { | ||||||
| 		this.client					= client; | 		this.client					= client; | ||||||
| @@ -281,7 +283,7 @@ public class LoginDialog extends JDialog { | |||||||
| 	/** | 	/** | ||||||
| 	 * Resets the text stored in the password fields. | 	 * Resets the text stored in the password fields. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	private void clearPasswordFields() { | 	private void clearPasswordFields() { | ||||||
| 		passwordField.setText(null); | 		passwordField.setText(null); | ||||||
| @@ -289,7 +291,7 @@ public class LoginDialog extends JDialog { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void setTheme() { | 	private void setTheme() { | ||||||
| 		Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); | 		Theme theme = Settings.getInstance().getCurrentTheme(); | ||||||
| 
 | 
 | ||||||
| 		// Panels | 		// Panels | ||||||
| 		contentPanel.setBackground(theme.getBackgroundColor()); | 		contentPanel.setBackground(theme.getBackgroundColor()); | ||||||
| @@ -335,7 +337,7 @@ public class LoginDialog extends JDialog { | |||||||
| 	/** | 	/** | ||||||
| 	 * Shuts the system down properly if the login was aborted. | 	 * Shuts the system down properly if the login was aborted. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void abortLogin() { | 	private void abortLogin() { | ||||||
| 		logger.info("The login process has been cancelled. Exiting..."); | 		logger.info("The login process has been cancelled. Exiting..."); | ||||||
							
								
								
									
										13
									
								
								src/main/java/envoy/client/ui/container/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/main/java/envoy/client/ui/container/package-info.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | /** | ||||||
|  |  * This package contains all graphical Containers, like Dialogs and Frames.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>package-info.java</strong><br> | ||||||
|  |  * Created: <strong>16 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @author Maximilian Käfer | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | package envoy.client.ui.container; | ||||||
| @@ -3,12 +3,14 @@ package envoy.client.ui.list; | |||||||
| import java.awt.event.MouseAdapter; | import java.awt.event.MouseAdapter; | ||||||
| import java.awt.event.MouseEvent; | import java.awt.event.MouseEvent; | ||||||
| import java.awt.event.MouseListener; | import java.awt.event.MouseListener; | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.Set; | ||||||
|  |  | ||||||
| import javax.swing.*; | import javax.swing.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Provides a vertical list layout of components provided in a |  * Provides a vertical list layout of components provided in a | ||||||
|  * {@link ComponentListModel}. Similar to {@link javax.swing.JList} but capable |  * {@link Model}. Similar to {@link javax.swing.JList} but capable | ||||||
|  * of rendering {@link JPanel}s.<br> |  * of rendering {@link JPanel}s.<br> | ||||||
|  * <br> |  * <br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
| @@ -17,141 +19,90 @@ import javax.swing.*; | |||||||
|  * |  * | ||||||
|  * @param <E> the type of object displayed in this list |  * @param <E> the type of object displayed in this list | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class ComponentList<E> extends JPanel { | public class ComponentList<E> extends JPanel { | ||||||
|  |  | ||||||
| 	private ComponentListModel<E>			model; | 	private Model<E>			model; | ||||||
| 	private ComponentListCellRenderer<E>	renderer; | 	private Renderer<E>			renderer; | ||||||
|  | 	private SelectionHandler<E>	selectionHandler; | ||||||
| 	private int currentSelection = -1; | 	private SelectionMode		selectionMode	= SelectionMode.NONE; | ||||||
|  | 	private Set<Integer>		selection		= new HashSet<>(); | ||||||
|  |  | ||||||
| 	private static final long serialVersionUID = 1759644503942876737L; | 	private static final long serialVersionUID = 1759644503942876737L; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates an instance of {@link ComponentList}. | 	 * Defines the possible modes of selection that can be performed by the user | ||||||
| 	 * | 	 * | ||||||
| 	 * @param renderer the list cell renderer used to display elements provided by | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 *                 the {@link ComponentListModel} |  | ||||||
| 	 * @since Envoy v0.3-alpha |  | ||||||
| 	 */ | 	 */ | ||||||
| 	public ComponentList(ComponentListCellRenderer<E> renderer) { | 	public static enum SelectionMode { | ||||||
| 		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); | 		/** | ||||||
| 		this.renderer = renderer; | 		 * Selection is completely ignored. | ||||||
|  | 		 */ | ||||||
|  | 		NONE, | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * Only a single element can be selected. | ||||||
|  | 		 */ | ||||||
|  | 		SINGLE, | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * Multiple elements can be selected regardless of their position. | ||||||
|  | 		 */ | ||||||
|  | 		MULTIPLE | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates an instance of {@link ComponentList}. | 	 * Creates an instance of {@link ComponentList}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param model    the list model providing the list elements to render | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 * @param renderer the list cell renderer used to display elements provided by |  | ||||||
| 	 *                 the {@link ComponentListModel} |  | ||||||
| 	 * @since Envoy v0.3-alpha |  | ||||||
| 	 */ | 	 */ | ||||||
| 	public ComponentList(ComponentListModel<E> model, ComponentListCellRenderer<E> renderer) { | 	public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } | ||||||
| 		this(renderer); |  | ||||||
| 		this.model = model; |  | ||||||
| 		setModel(model); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Sets the list model providing the list elements to render. The rendered |  | ||||||
| 	 * components will be synchronized with the contents of the new model or removed |  | ||||||
| 	 * if the new model is {@code null}. |  | ||||||
| 	 * |  | ||||||
| 	 * @param model the list model to set |  | ||||||
| 	 * @since Envoy v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public void setModel(ComponentListModel<E> model) { |  | ||||||
|  |  | ||||||
| 		// Remove old model |  | ||||||
| 		if (this.model != null) this.model.setComponentList(null); |  | ||||||
|  |  | ||||||
| 		// Synchronize with new model |  | ||||||
| 		this.model = model; |  | ||||||
| 		if (model != null) this.model.setComponentList(this); |  | ||||||
| 		synchronizeModel(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Removes all child components and then adds all components representing the | 	 * Removes all child components and then adds all components representing the | ||||||
| 	 * elements of the {@link ComponentListModel}. | 	 * elements of the {@link Model}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void synchronizeModel() { | 	public void synchronizeModel() { | ||||||
| 		removeAll(); | 		if (model != null) { | ||||||
| 		if (model != null) model.forEach(this::add); | 			removeAll(); | ||||||
| 		revalidate(); | 			model.forEach(this::addElement); | ||||||
|  | 			revalidate(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Adds an object to the list by rendering it with the current | 	 * Selects a list element by index. If the element is already selected, it is | ||||||
| 	 * {@link ComponentListCellRenderer}. | 	 * removed from the selection. | ||||||
| 	 * |  | ||||||
| 	 * @param elem the element to add |  | ||||||
| 	 * @since Envoy v0.3-alpha |  | ||||||
| 	 */ |  | ||||||
| 	void add(E elem) { add(elem, getComponentCount(), false); } |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Adds an object to the list by rendering it with the current |  | ||||||
| 	 * {@link ComponentListRenderer}. |  | ||||||
| 	 * |  | ||||||
| 	 * @param elem       the element to add |  | ||||||
| 	 * @param index      the index at which to add the element |  | ||||||
| 	 * @param isSelected the selection state of the element |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	private void add(E elem, int index, boolean isSelected) { |  | ||||||
| 		final JComponent component = renderer.getListCellComponent(this, elem, isSelected); |  | ||||||
| 		component.addMouseListener(getSelectionListener(index)); |  | ||||||
| 		add(component, index); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @param componentIndex the index of the list component to which the mouse |  | ||||||
| 	 *                       listener will be added |  | ||||||
| 	 * @return a mouse listener calling the |  | ||||||
| 	 *         {@link ComponentList#componentSelected(int)} method with the |  | ||||||
| 	 *         component's index when a left click is performed by the user |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	private MouseListener getSelectionListener(int componentIndex) { |  | ||||||
| 		return new MouseAdapter() { |  | ||||||
|  |  | ||||||
| 			@Override |  | ||||||
| 			public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); } |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Gets called when a list component has been clicked on by the user. Any |  | ||||||
| 	 * previous selections are then removed and the selected component gets |  | ||||||
| 	 * redrawn.<br> |  | ||||||
| 	 * <br> |  | ||||||
| 	 * If the currently selected component gets selected again, the selection is |  | ||||||
| 	 * removed. |  | ||||||
| 	 * | 	 * | ||||||
| 	 * @param index the index of the selected component | 	 * @param index the index of the selected component | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void componentSelected(int index) { | 	public void selectElement(int index) { | ||||||
| 		if (index == currentSelection) { | 		final JComponent element = getComponent(index); | ||||||
|  | 		if (selection.contains(index)) { | ||||||
|  |  | ||||||
|  | 			// Deselect if clicked again | ||||||
|  | 			if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); | ||||||
|  | 			selection.remove(index); | ||||||
|  |  | ||||||
| 			// Clear selection |  | ||||||
| 			update(currentSelection, false); |  | ||||||
| 			currentSelection = -1; |  | ||||||
| 		} else { | 		} else { | ||||||
|  |  | ||||||
| 			// Remove old selection | 			// Remove old selection if single selection is enabled | ||||||
| 			if (currentSelection >= 0) update(currentSelection, false); | 			if (selectionMode == SelectionMode.SINGLE) clearSelection(); | ||||||
|  |  | ||||||
| 			// Assign new selection | 			// Select item | ||||||
| 			currentSelection = index; | 			if (selectionMode != SelectionMode.NONE) { | ||||||
|  |  | ||||||
| 			// Update current selection | 				// Assign new selection | ||||||
| 			update(currentSelection, true); | 				selection.add(index); | ||||||
|  |  | ||||||
|  | 				// Update element | ||||||
|  | 				if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		revalidate(); | 		revalidate(); | ||||||
| @@ -159,14 +110,152 @@ public class ComponentList<E> extends JPanel { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Replaces a list element with a newly rendered instance of its contents. | 	 * Removes the current selection. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param index      the index of the element to update | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 * @param isSelected the selection state passed to the {@link ListCellRenderer} |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ | 	 */ | ||||||
| 	private void update(int index, boolean isSelected) { | 	public void clearSelection() { | ||||||
| 		remove(index); | 		if (selectionHandler != null) selection.forEach(i -> selectionHandler.selectionChanged(model.get(i), getComponent(i), false)); | ||||||
| 		add(model.get(index), index, isSelected); | 		selection.clear(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Adds an object to the list by rendering it with the current | ||||||
|  | 	 * {@link Renderer}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param elem the element to add | ||||||
|  | 	 * @since Envoy Client v0.3-alpha | ||||||
|  | 	 */ | ||||||
|  | 	void addElement(E elem) { | ||||||
|  | 		if (renderer != null) { | ||||||
|  | 			final JComponent component = renderer.getListCellComponent(this, elem); | ||||||
|  | 			component.addMouseListener(getSelectionListener(getComponentCount())); | ||||||
|  | 			add(component, getComponentCount()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param componentIndex the index of the list component to which the mouse | ||||||
|  | 	 *                       listener will be added | ||||||
|  | 	 * @return a mouse listener calling the | ||||||
|  | 	 *         {@link ComponentList#selectElement(int)} method with the | ||||||
|  | 	 *         component's index when a left click is performed by the user | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	private MouseListener getSelectionListener(int componentIndex) { | ||||||
|  | 		return new MouseAdapter() { | ||||||
|  |  | ||||||
|  | 			@Override | ||||||
|  | 			public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) selectElement(componentIndex); } | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public JComponent getComponent(int n) { return (JComponent) super.getComponent(n); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return a set of all selected indices | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Set<Integer> getSelection() { return selection; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return a set of all selected elements | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Set<E> getSelectedElements() { | ||||||
|  | 		var selectedElements = new HashSet<E>(); | ||||||
|  | 		selection.forEach(i -> selectedElements.add(model.get(i))); | ||||||
|  | 		return selectedElements; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the index of an arbitrary selected element | ||||||
|  | 	 * @throws java.util.NoSuchElementException if no selection is present | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public int getSingleSelection() { return selection.stream().findAny().get(); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return an arbitrary selected element | ||||||
|  | 	 * @throws java.util.NoSuchElementException if no selection is present | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public E getSingleSelectedElement() { return model.get(getSingleSelection()); } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the model | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Model<E> getModel() { return model; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Sets the list model providing the list elements to render. The rendered | ||||||
|  | 	 * components will be synchronized with the contents of the new model or removed | ||||||
|  | 	 * if the new model is {@code null}. | ||||||
|  | 	 * | ||||||
|  | 	 * @param model the list model to set | ||||||
|  | 	 * @return this component list | ||||||
|  | 	 * @since Envoy Client v0.3-alpha | ||||||
|  | 	 */ | ||||||
|  | 	public ComponentList<E> setModel(Model<E> model) { | ||||||
|  |  | ||||||
|  | 		// Remove old model | ||||||
|  | 		if (this.model != null) this.model.setComponentList(null); | ||||||
|  |  | ||||||
|  | 		// Synchronize with new model | ||||||
|  | 		this.model = model; | ||||||
|  | 		if (model != null) model.setComponentList(this); | ||||||
|  | 		synchronizeModel(); | ||||||
|  |  | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the renderer | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Renderer<E> getRenderer() { return renderer; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param renderer the renderer to set | ||||||
|  | 	 * @return this component list | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ComponentList<E> setRenderer(Renderer<E> renderer) { | ||||||
|  | 		this.renderer = renderer; | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the selection mode | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public SelectionMode getSelectionMode() { return selectionMode; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Sets a new selection mode. The current selection will be cleared during this | ||||||
|  | 	 * action. | ||||||
|  | 	 * | ||||||
|  | 	 * @param selectionMode the selection mode to set | ||||||
|  | 	 * @return this component list | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public ComponentList<E> setSelectionMode(SelectionMode selectionMode) { | ||||||
|  | 		this.selectionMode = selectionMode; | ||||||
|  | 		clearSelection(); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return the selection handler | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public SelectionHandler<E> getSelectionHandler() { return selectionHandler; } | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param selectionHandler the selection handler to set | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void setSelectionHandler(SelectionHandler<E> selectionHandler) { this.selectionHandler = selectionHandler; } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,19 +9,19 @@ import java.util.List; | |||||||
|  * Stores objects that will be displayed in a {@link ComponentList}.<br> |  * Stores objects that will be displayed in a {@link ComponentList}.<br> | ||||||
|  * <br> |  * <br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * File: <strong>ComponentListModel.java</strong><br> |  * File: <strong>Model.java</strong><br> | ||||||
|  * Created: <strong>25.01.2020</strong><br> |  * Created: <strong>25.01.2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @param <E> the type of object displayed in this list |  * @param <E> the type of object displayed in this list | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public final class ComponentListModel<E> implements Iterable<E>, Serializable { | public final class Model<E> implements Iterable<E>, Serializable { | ||||||
| 
 | 
 | ||||||
| 	private List<E>						elements	= new ArrayList<>(); | 	private List<E>						elements	= new ArrayList<>(); | ||||||
| 	transient private ComponentList<E>	componentList; | 	transient private ComponentList<E>	componentList; | ||||||
| 
 | 
 | ||||||
| 	private static final long serialVersionUID = 4815005915255497331L; | 	private static final long serialVersionUID = 0L; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Adds an element to this model and notifies the associated | 	 * Adds an element to this model and notifies the associated | ||||||
| @@ -30,11 +30,11 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 * @param e the element to add | 	 * @param e the element to add | ||||||
| 	 * @return {@code true} | 	 * @return {@code true} | ||||||
| 	 * @see java.util.List#add(java.lang.Object) | 	 * @see java.util.List#add(java.lang.Object) | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean add(E e) { | 	public boolean add(E e) { | ||||||
| 		if (componentList != null) { | 		if (componentList != null) { | ||||||
| 			componentList.add(e); | 			componentList.addElement(e); | ||||||
| 			componentList.revalidate(); | 			componentList.revalidate(); | ||||||
| 		} | 		} | ||||||
| 		return elements.add(e); | 		return elements.add(e); | ||||||
| @@ -45,7 +45,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 * {@link ComponentList}. | 	 * {@link ComponentList}. | ||||||
| 	 * | 	 * | ||||||
| 	 * @see java.util.List#clear() | 	 * @see java.util.List#clear() | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void clear() { | 	public void clear() { | ||||||
| 		elements.clear(); | 		elements.clear(); | ||||||
| @@ -56,7 +56,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 * @param index the index to retrieve the element from | 	 * @param index the index to retrieve the element from | ||||||
| 	 * @return the element located at the index | 	 * @return the element located at the index | ||||||
| 	 * @see java.util.List#get(int) | 	 * @see java.util.List#get(int) | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public E get(int index) { return elements.get(index); } | 	public E get(int index) { return elements.get(index); } | ||||||
| 
 | 
 | ||||||
| @@ -67,7 +67,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 * @param index the index of the element to remove | 	 * @param index the index of the element to remove | ||||||
| 	 * @return the removed element | 	 * @return the removed element | ||||||
| 	 * @see java.util.List#remove(int) | 	 * @see java.util.List#remove(int) | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public E remove(int index) { | 	public E remove(int index) { | ||||||
| 		if (componentList != null) componentList.remove(index); | 		if (componentList != null) componentList.remove(index); | ||||||
| @@ -77,7 +77,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return the amount of elements in this list model | 	 * @return the amount of elements in this list model | ||||||
| 	 * @see java.util.List#size() | 	 * @see java.util.List#size() | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public int size() { return elements.size(); } | 	public int size() { return elements.size(); } | ||||||
| 
 | 
 | ||||||
| @@ -90,7 +90,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	/** | 	/** | ||||||
| 	 * @return an iterator over the elements of this list model | 	 * @return an iterator over the elements of this list model | ||||||
| 	 * @see java.util.List#iterator() | 	 * @see java.util.List#iterator() | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	@Override | 	@Override | ||||||
| 	public Iterator<E> iterator() { | 	public Iterator<E> iterator() { | ||||||
| @@ -111,10 +111,10 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 * synchronization. | 	 * synchronization. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param componentList the component list to set | 	 * @param componentList the component list to set | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	void setComponentList(ComponentList<E> componentList) { | 	void setComponentList(ComponentList<E> componentList) { | ||||||
| 		this.componentList = componentList; | 		this.componentList = componentList; | ||||||
| 		if (componentList != null) componentList.synchronizeModel(); | 		if (componentList != null && componentList.getRenderer() != null) componentList.synchronizeModel(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -7,14 +7,15 @@ import javax.swing.JComponent; | |||||||
|  * that can be rendered.<br> |  * that can be rendered.<br> | ||||||
|  * <br> |  * <br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * File: <strong>ComponentListCellRenderer.java</strong><br> |  * File: <strong>Renderer.java</strong><br> | ||||||
|  * Created: <strong>25.01.2020</strong><br> |  * Created: <strong>25.01.2020</strong><br> | ||||||
|  * |  * | ||||||
|  * @param <E> the type of object displayed in this list |  * @param <E> the type of object displayed in this list | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public interface ComponentListCellRenderer<E> { | @FunctionalInterface | ||||||
|  | public interface Renderer<E> { | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Provides a Swing component representing a list element. | 	 * Provides a Swing component representing a list element. | ||||||
| @@ -24,7 +25,7 @@ public interface ComponentListCellRenderer<E> { | |||||||
| 	 * @param isSelected {@code true} if the user has selected the list cell in | 	 * @param isSelected {@code true} if the user has selected the list cell in | ||||||
| 	 *                   which the list element is rendered | 	 *                   which the list element is rendered | ||||||
| 	 * @return the component representing the list element | 	 * @return the component representing the list element | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	JComponent getListCellComponent(ComponentList<? extends E> list, E value, boolean isSelected); | 	JComponent getListCellComponent(ComponentList<? extends E> list, E value); | ||||||
| } | } | ||||||
							
								
								
									
										28
									
								
								src/main/java/envoy/client/ui/list/SelectionHandler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/main/java/envoy/client/ui/list/SelectionHandler.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | package envoy.client.ui.list; | ||||||
|  |  | ||||||
|  | import javax.swing.JComponent; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Handles the selection of elements in a {@link ComponentList}.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong> | ||||||
|  |  * File: <strong>SelectionHandler.java</strong> | ||||||
|  |  * Created: <strong>21.03.2020</strong> | ||||||
|  |  * | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @param <E> the type of the underlying {@link ComponentList} | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | @FunctionalInterface | ||||||
|  | public interface SelectionHandler<E> { | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Notifies the handler about a selection. | ||||||
|  | 	 * | ||||||
|  | 	 * @param element    the selected element | ||||||
|  | 	 * @param component  the selected component | ||||||
|  | 	 * @param isSelected contains the selection state | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	void selectionChanged(E element, JComponent component, boolean isSelected); | ||||||
|  | } | ||||||
| @@ -5,6 +5,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| package envoy.client.ui.list; | package envoy.client.ui.list; | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.list_component; | ||||||
| 
 | 
 | ||||||
| import java.awt.Component; | import java.awt.Component; | ||||||
| import java.awt.Dimension; | import java.awt.Dimension; | ||||||
| @@ -9,42 +9,40 @@ import javax.swing.*; | |||||||
| import envoy.client.data.Settings; | import envoy.client.data.Settings; | ||||||
| import envoy.client.event.SendEvent; | import envoy.client.event.SendEvent; | ||||||
| import envoy.client.ui.list.ComponentList; | import envoy.client.ui.list.ComponentList; | ||||||
| import envoy.client.ui.list.ComponentListCellRenderer; | import envoy.client.ui.primary.PrimaryButton; | ||||||
| import envoy.data.User; | import envoy.data.User; | ||||||
| import envoy.event.ContactOperationEvent; | import envoy.event.ContactOperationEvent; | ||||||
| import envoy.event.EventBus; | import envoy.event.EventBus; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Defines how a contact is displayed.<br> |  * Project: <strong>envoy-client</strong> | ||||||
|  * <br> |  * File: <strong>ContactSearchComponent.java</strong> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Created: <strong>21.03.2020</strong> | ||||||
|  * File: <strong>ContactsSearchRenderer.java</strong><br> |  | ||||||
|  * Created: <strong>08.02.2020</strong><br> |  | ||||||
|  * |  * | ||||||
|  * @author Maximilian Käfer |  | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| public class ContactsSearchRenderer implements ComponentListCellRenderer<User> { | public class ContactSearchComponent extends JComponent { | ||||||
| 
 | 
 | ||||||
| 	@Override | 	private static final long serialVersionUID = 3166795412575239455L; | ||||||
| 	public JComponent getListCellComponent(ComponentList<? extends User> list, User user, boolean isSelected) { | 
 | ||||||
| 		final JPanel panel = new JPanel(); | 	/** | ||||||
| 		panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); | 	 * @param list the {@link ComponentList} that is used to display search results | ||||||
| 		if (isSelected) { | 	 * @param user the {@link User} that appears as a search result | ||||||
| 			panel.setBackground(Color.DARK_GRAY); | 	 * @since Envoy Client v0.1-beta | ||||||
| 			panel.setForeground(Color.RED); | 	 */ | ||||||
| 		} else { | 	public ContactSearchComponent(ComponentList<? extends User> list, User user) { | ||||||
| 			panel.setBackground(list.getBackground()); | 		setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); | ||||||
| 			panel.setForeground(list.getForeground()); | 
 | ||||||
| 		} | 		setBackground(list.getBackground()); | ||||||
|  | 		setForeground(list.getForeground()); | ||||||
| 
 | 
 | ||||||
| 		JLabel display = new JLabel(user.getName()); | 		JLabel display = new JLabel(user.getName()); | ||||||
| 		display.setForeground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageTextColor()); | 		display.setForeground(Settings.getInstance().getCurrentTheme().getTextColor()); | ||||||
| 		display.setAlignmentX(Component.LEFT_ALIGNMENT); | 		display.setAlignmentX(Component.LEFT_ALIGNMENT); | ||||||
| 		display.setAlignmentY(Component.CENTER_ALIGNMENT); | 		display.setAlignmentY(Component.CENTER_ALIGNMENT); | ||||||
| 		display.setFont(new Font("Arial", Font.PLAIN, 16)); | 		display.setFont(new Font("Arial", Font.PLAIN, 16)); | ||||||
| 		panel.add(display); | 		add(display); | ||||||
| 
 | 
 | ||||||
| 		PrimaryButton add = new PrimaryButton("+"); | 		PrimaryButton add = new PrimaryButton("+"); | ||||||
| 		add.setFont(new Font("Arial", Font.PLAIN, 19)); | 		add.setFont(new Font("Arial", Font.PLAIN, 19)); | ||||||
| @@ -61,17 +59,15 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer<User> { | |||||||
| 			EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); | 			EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		panel.add(add); | 		add(add); | ||||||
| 
 | 
 | ||||||
| 		// Define some space to the messages below | 		// Define some space to the messages below | ||||||
| 		panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); | 		setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); | ||||||
| 
 | 
 | ||||||
| 		// Define a maximum height of 50px | 		// Define a maximum height of 50px | ||||||
| 		Dimension size = new Dimension(435, 50); | 		Dimension size = new Dimension(435, 50); | ||||||
| 		panel.setMaximumSize(size); | 		setMaximumSize(size); | ||||||
| 		panel.setMinimumSize(size); | 		setMinimumSize(size); | ||||||
| 		panel.setPreferredSize(size); | 		setPreferredSize(size); | ||||||
| 
 |  | ||||||
| 		return panel; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -0,0 +1,127 @@ | |||||||
|  | package envoy.client.ui.list_component; | ||||||
|  |  | ||||||
|  | import java.awt.*; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.text.SimpleDateFormat; | ||||||
|  | import java.util.EnumMap; | ||||||
|  |  | ||||||
|  | import javax.swing.*; | ||||||
|  |  | ||||||
|  | import envoy.client.data.Chat; | ||||||
|  | import envoy.client.data.Settings; | ||||||
|  | import envoy.client.ui.Color; | ||||||
|  | import envoy.client.ui.IconUtil; | ||||||
|  | import envoy.client.ui.list.ComponentList; | ||||||
|  | import envoy.data.Message; | ||||||
|  | import envoy.data.Message.MessageStatus; | ||||||
|  | import envoy.data.User; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Project: <strong>envoy-client</strong> | ||||||
|  |  * File: <strong>MessageComponent.java</strong> | ||||||
|  |  * Created: <strong>21.03.2020</strong> | ||||||
|  |  * | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class MessageComponent extends JPanel { | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = 103920706139926996L; | ||||||
|  |  | ||||||
|  | 	private static EnumMap<MessageStatus, ImageIcon>	statusIcons; | ||||||
|  | 	private static ImageIcon							forwardIcon; | ||||||
|  |  | ||||||
|  | 	static { | ||||||
|  | 		try { | ||||||
|  | 			statusIcons	= IconUtil.loadByEnum(MessageStatus.class, 16); | ||||||
|  | 			forwardIcon	= IconUtil.load("/icons/forward.png", 16); | ||||||
|  | 		} catch (IOException e) { | ||||||
|  | 			e.printStackTrace(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param list     the {@link ComponentList} that displays this {@link Chat} | ||||||
|  | 	 * @param message  the {@link Message} to display | ||||||
|  | 	 * @param senderId the id of the {@link User} who sends messages from this | ||||||
|  | 	 *                 account | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public MessageComponent(ComponentList<? extends Message> list, Message message, long senderId) { | ||||||
|  | 		var			width	= list.getMaximumSize().width; | ||||||
|  | 		final var	theme	= Settings.getInstance().getCurrentTheme(); | ||||||
|  | 		final int	padding	= (int) (width * 0.35); | ||||||
|  |  | ||||||
|  | 		GridBagLayout gbl_panel = new GridBagLayout(); | ||||||
|  | 		gbl_panel.columnWidths	= new int[] { 1, 1 }; | ||||||
|  | 		gbl_panel.rowHeights	= new int[] { 1, 1 }; | ||||||
|  | 		gbl_panel.columnWeights	= new double[] { 1, 1 }; | ||||||
|  | 		gbl_panel.rowWeights	= new double[] { 1, 1 }; | ||||||
|  |  | ||||||
|  | 		setLayout(gbl_panel); | ||||||
|  | 		setBackground(theme.getCellColor()); | ||||||
|  |  | ||||||
|  | 		// Date Label - The Label that displays the creation date of a message | ||||||
|  | 		var dateLabel = new JLabel(new SimpleDateFormat("dd.MM.yyyy HH:mm").format(message.getCreationDate())); | ||||||
|  | 		dateLabel.setForeground(theme.getDateColor()); | ||||||
|  | 		dateLabel.setAlignmentX(1f); | ||||||
|  | 		dateLabel.setFont(new Font("Arial", Font.PLAIN, 12)); | ||||||
|  | 		dateLabel.setPreferredSize(dateLabel.getPreferredSize()); | ||||||
|  |  | ||||||
|  | 		var gbc_dateLabel = new GridBagConstraints(); | ||||||
|  | 		gbc_dateLabel.fill	= GridBagConstraints.BOTH; | ||||||
|  | 		gbc_dateLabel.gridx	= 0; | ||||||
|  | 		gbc_dateLabel.gridy	= 0; | ||||||
|  | 		add(dateLabel, gbc_dateLabel); | ||||||
|  |  | ||||||
|  | 		// Message area - The JTextArea that displays the text content of a message. | ||||||
|  | 		var messageTextArea = new JTextArea(message.getText()); | ||||||
|  | 		messageTextArea.setLineWrap(true); | ||||||
|  | 		messageTextArea.setWrapStyleWord(true); | ||||||
|  | 		messageTextArea.setForeground(theme.getTextColor()); | ||||||
|  | 		messageTextArea.setAlignmentX(0.5f); | ||||||
|  | 		messageTextArea.setBackground(theme.getCellColor()); | ||||||
|  | 		messageTextArea.setEditable(false); | ||||||
|  | 		var font = new Font("Arial", Font.PLAIN, 14); | ||||||
|  | 		messageTextArea.setFont(font); | ||||||
|  | 		messageTextArea.setSize(width - padding - 16, 10); | ||||||
|  |  | ||||||
|  | 		var gbc_messageTextArea = new GridBagConstraints(); | ||||||
|  | 		gbc_messageTextArea.fill	= GridBagConstraints.HORIZONTAL; | ||||||
|  | 		gbc_messageTextArea.gridx	= 0; | ||||||
|  | 		gbc_messageTextArea.gridy	= 1; | ||||||
|  | 		add(messageTextArea, gbc_messageTextArea); | ||||||
|  |  | ||||||
|  | 		// Status Label - displays the status of the message | ||||||
|  | 		var statusLabel = new JLabel(statusIcons.get(message.getStatus())); | ||||||
|  |  | ||||||
|  | 		var gbc_statusLabel = new GridBagConstraints(); | ||||||
|  | 		gbc_statusLabel.gridx	= 1; | ||||||
|  | 		gbc_statusLabel.gridy	= 1; | ||||||
|  | 		add(statusLabel, gbc_statusLabel); | ||||||
|  |  | ||||||
|  | 		// Forwarding | ||||||
|  | 		if (message.isForwarded()) { | ||||||
|  | 			var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER); | ||||||
|  | 			forwardLabel.setBackground(getBackground()); | ||||||
|  | 			forwardLabel.setForeground(Color.lightGray); | ||||||
|  |  | ||||||
|  | 			var gbc_forwardLabel = new GridBagConstraints(); | ||||||
|  | 			gbc_forwardLabel.fill	= GridBagConstraints.BOTH; | ||||||
|  | 			gbc_forwardLabel.gridx	= 1; | ||||||
|  | 			gbc_forwardLabel.gridy	= 0; | ||||||
|  | 			add(forwardLabel, gbc_forwardLabel); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Define an etched border and some space to the messages below | ||||||
|  | 		var ours = senderId == message.getSenderId(); | ||||||
|  | 		setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 10, 10, ours ? 0 : padding), | ||||||
|  | 				BorderFactory.createEtchedBorder())); | ||||||
|  |  | ||||||
|  | 		var size = new Dimension(width - 50, getPreferredSize().height); | ||||||
|  |  | ||||||
|  | 		setPreferredSize(size); | ||||||
|  | 		setMinimumSize(size); | ||||||
|  | 		setMaximumSize(size); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,69 @@ | |||||||
|  | package envoy.client.ui.list_component; | ||||||
|  |  | ||||||
|  | import java.awt.BorderLayout; | ||||||
|  | import java.awt.Dimension; | ||||||
|  |  | ||||||
|  | import javax.swing.JLabel; | ||||||
|  | import javax.swing.JPanel; | ||||||
|  |  | ||||||
|  | import envoy.client.data.Settings; | ||||||
|  | import envoy.client.ui.Color; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
|  | import envoy.data.User; | ||||||
|  | import envoy.data.User.UserStatus; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Displays a {@link User}.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong> | ||||||
|  |  * File: <strong>UserComponent.java</strong> | ||||||
|  |  * Created: <strong>21.03.2020</strong> | ||||||
|  |  * | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | public class UserComponent extends JPanel { | ||||||
|  |  | ||||||
|  | 	private static final long serialVersionUID = 8450602172939729585L; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @param user the {@link User} whose information is displayed | ||||||
|  | 	 * @since Envoy Client v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public UserComponent(User user) { | ||||||
|  | 		final Theme theme = Settings.getInstance().getCurrentTheme(); | ||||||
|  |  | ||||||
|  | 		setLayout(new BorderLayout()); | ||||||
|  |  | ||||||
|  | 		// Panel background | ||||||
|  | 		setBackground(theme.getCellColor()); | ||||||
|  | 		setOpaque(true); | ||||||
|  | 		setPreferredSize(new Dimension(100, 35)); | ||||||
|  |  | ||||||
|  | 		// TODO add profile picture support in BorderLayout.West | ||||||
|  |  | ||||||
|  | 		JLabel username = new JLabel(user.getName()); | ||||||
|  | 		username.setForeground(theme.getUserNameColor()); | ||||||
|  | 		add(username, BorderLayout.CENTER); | ||||||
|  |  | ||||||
|  | 		final UserStatus	status		= user.getStatus(); | ||||||
|  | 		JLabel				statusLabel	= new JLabel(status.toString()); | ||||||
|  | 		Color				foreground; | ||||||
|  | 		switch (status) { | ||||||
|  | 			case AWAY: | ||||||
|  | 				foreground = Color.yellow; | ||||||
|  | 				break; | ||||||
|  | 			case BUSY: | ||||||
|  | 				foreground = Color.blue; | ||||||
|  | 				break; | ||||||
|  | 			case ONLINE: | ||||||
|  | 				foreground = Color.green; | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				foreground = Color.lightGray; | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 		statusLabel.setForeground(foreground); | ||||||
|  | 		add(statusLabel, BorderLayout.NORTH); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | /** | ||||||
|  |  * This package contains swing components that can be displayed by | ||||||
|  |  * {@link envoy.client.ui.list.ComponentList}.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>package-info.java</strong><br> | ||||||
|  |  * Created: <strong>21 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @author Maximilian Käfer | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | package envoy.client.ui.list_component; | ||||||
| @@ -4,6 +4,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| package envoy.client.ui; | package envoy.client.ui; | ||||||
|   | |||||||
| @@ -1,63 +1,63 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.primary; | ||||||
| 
 | 
 | ||||||
| import java.awt.Graphics; | import java.awt.Graphics; | ||||||
| 
 | 
 | ||||||
| import javax.swing.JButton; | import javax.swing.JButton; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * File: <strong>PrimaryButton.javaEvent.java</strong><br> |  * File: <strong>PrimaryButton.javaEvent.java</strong><br> | ||||||
|  * Created: <strong>07.12.2019</strong><br> |  * Created: <strong>07.12.2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class PrimaryButton extends JButton { | public class PrimaryButton extends JButton { | ||||||
| 
 | 
 | ||||||
| 	private static final long serialVersionUID = 3662266120667728364L; | 	private static final long serialVersionUID = 3662266120667728364L; | ||||||
| 
 | 
 | ||||||
| 	private int arcSize; | 	private int arcSize; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a primary button | 	 * Creates a primary button | ||||||
| 	 * | 	 * | ||||||
| 	 * @param title the title of the button | 	 * @param title the title of the button | ||||||
| 	 * @since Envoy 0.2-alpha | 	 * @since Envoy 0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public PrimaryButton(String title) { this(title, 6); } | 	public PrimaryButton(String title) { this(title, 6); } | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a primary button | 	 * Creates a primary button | ||||||
| 	 * | 	 * | ||||||
| 	 * @param title   the title of the button | 	 * @param title   the title of the button | ||||||
| 	 * @param arcSize the size of the arc used to draw the round button edges | 	 * @param arcSize the size of the arc used to draw the round button edges | ||||||
| 	 * @since Envoy 0.2-alpha | 	 * @since Envoy 0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public PrimaryButton(String title, int arcSize) { | 	public PrimaryButton(String title, int arcSize) { | ||||||
| 		super(title); | 		super(title); | ||||||
| 		setBorderPainted(false); | 		setBorderPainted(false); | ||||||
| 		setFocusPainted(false); | 		setFocusPainted(false); | ||||||
| 		setContentAreaFilled(false); | 		setContentAreaFilled(false); | ||||||
| 		this.arcSize = arcSize; | 		this.arcSize = arcSize; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected void paintComponent(Graphics g) { | 	protected void paintComponent(Graphics g) { | ||||||
| 		g.setColor(getBackground()); | 		g.setColor(getBackground()); | ||||||
| 		g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); | 		g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize); | ||||||
| 		super.paintComponent(g); | 		super.paintComponent(g); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the arcSize | 	 * @return the arcSize | ||||||
| 	 * @since Envoy 0.2-alpha | 	 * @since Envoy 0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public int getArcSize() { return arcSize; } | 	public int getArcSize() { return arcSize; } | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * @param arcSize the arcSize to set | 	 * @param arcSize the arcSize to set | ||||||
| 	 * @since Envoy 0.2-alpha | 	 * @since Envoy 0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setArcSize(int arcSize) { this.arcSize = arcSize; } | 	public void setArcSize(int arcSize) { this.arcSize = arcSize; } | ||||||
| } | } | ||||||
| @@ -1,11 +1,6 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.primary; | ||||||
| 
 | 
 | ||||||
| import java.awt.Color; | import java.awt.*; | ||||||
| import java.awt.Dimension; |  | ||||||
| import java.awt.Graphics; |  | ||||||
| import java.awt.Graphics2D; |  | ||||||
| import java.awt.Rectangle; |  | ||||||
| import java.awt.RenderingHints; |  | ||||||
| 
 | 
 | ||||||
| import javax.swing.JButton; | import javax.swing.JButton; | ||||||
| import javax.swing.JComponent; | import javax.swing.JComponent; | ||||||
| @@ -13,6 +8,7 @@ import javax.swing.JScrollBar; | |||||||
| import javax.swing.plaf.basic.BasicScrollBarUI; | import javax.swing.plaf.basic.BasicScrollBarUI; | ||||||
| 
 | 
 | ||||||
| import envoy.client.data.Settings; | import envoy.client.data.Settings; | ||||||
|  | import envoy.client.ui.Theme; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
| @@ -20,7 +16,7 @@ import envoy.client.data.Settings; | |||||||
|  * Created: <strong>14.12.2019</strong><br> |  * Created: <strong>14.12.2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class PrimaryScrollBar extends BasicScrollBarUI { | public class PrimaryScrollBar extends BasicScrollBarUI { | ||||||
| 
 | 
 | ||||||
| @@ -97,11 +93,11 @@ public class PrimaryScrollBar extends BasicScrollBarUI { | |||||||
| 		g2.setPaint(color); | 		g2.setPaint(color); | ||||||
| 		if (isVertical) { | 		if (isVertical) { | ||||||
| 			g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); | 			g2.fillRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); | ||||||
| 			g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); | 			g2.setPaint(Settings.getInstance().getCurrentTheme().getCellColor()); | ||||||
| 			g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); | 			g2.drawRoundRect(r.x - 9, r.y, r.width, r.height, arcSize, arcSize); | ||||||
| 		} else { | 		} else { | ||||||
| 			g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); | 			g2.fillRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); | ||||||
| 			g2.setPaint(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getCellColor()); | 			g2.setPaint(Settings.getInstance().getCurrentTheme().getCellColor()); | ||||||
| 			g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); | 			g2.drawRoundRect(r.x, r.y + 9, r.width, r.height - 10, arcSize, arcSize); | ||||||
| 		} | 		} | ||||||
| 		g2.dispose(); | 		g2.dispose(); | ||||||
| @@ -1,7 +1,9 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.primary; | ||||||
| 
 | 
 | ||||||
| import javax.swing.JScrollPane; | import javax.swing.JScrollPane; | ||||||
| 
 | 
 | ||||||
|  | import envoy.client.ui.Theme; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * File: <strong>PrimaryScrollPane.java</strong><br> |  * File: <strong>PrimaryScrollPane.java</strong><br> | ||||||
| @@ -20,7 +22,7 @@ public class PrimaryScrollPane extends JScrollPane { | |||||||
| 	/** | 	/** | ||||||
| 	 * Initializes a {@link JScrollPane} with the primary Envoy design scheme | 	 * Initializes a {@link JScrollPane} with the primary Envoy design scheme | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public PrimaryScrollPane() { setBorder(null); } | 	public PrimaryScrollPane() { setBorder(null); } | ||||||
| 
 | 
 | ||||||
| @@ -28,7 +30,7 @@ public class PrimaryScrollPane extends JScrollPane { | |||||||
| 	 * Styles the vertical and horizontal scroll bars. | 	 * Styles the vertical and horizontal scroll bars. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param theme the color set used to color the component | 	 * @param theme the color set used to color the component | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void applyTheme(Theme theme) { | 	public void applyTheme(Theme theme) { | ||||||
| 		setForeground(theme.getBackgroundColor()); | 		setForeground(theme.getBackgroundColor()); | ||||||
| @@ -52,7 +54,7 @@ public class PrimaryScrollPane extends JScrollPane { | |||||||
| 	 * When rereading messages, the chat doesn't scroll down if new messages </br> | 	 * When rereading messages, the chat doesn't scroll down if new messages </br> | ||||||
| 	 * are added. (Besides see first point) | 	 * are added. (Besides see first point) | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void autoscroll() { | 	public void autoscroll() { | ||||||
| 		// Automatic scrolling to the bottom | 		// Automatic scrolling to the bottom | ||||||
| @@ -77,7 +79,7 @@ public class PrimaryScrollPane extends JScrollPane { | |||||||
| 	 * triggering it to automatically scroll down. | 	 * triggering it to automatically scroll down. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param chatOpened indicates the chat opening status | 	 * @param chatOpened indicates the chat opening status | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setChatOpened(boolean chatOpened) { this.chatOpened = chatOpened; } | 	public void setChatOpened(boolean chatOpened) { this.chatOpened = chatOpened; } | ||||||
| } | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.primary; | ||||||
| 
 | 
 | ||||||
| import java.awt.Font; | import java.awt.Font; | ||||||
| import java.awt.Graphics; | import java.awt.Graphics; | ||||||
| @@ -12,7 +12,7 @@ import javax.swing.border.EmptyBorder; | |||||||
|  * Created: <strong>07.12.2019</strong><br> |  * Created: <strong>07.12.2019</strong><br> | ||||||
|  *  |  *  | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class PrimaryTextArea extends JTextArea { | public class PrimaryTextArea extends JTextArea { | ||||||
| 
 | 
 | ||||||
| @@ -1,57 +1,58 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.primary; | ||||||
| 
 | 
 | ||||||
| import java.awt.Dimension; | import java.awt.Dimension; | ||||||
| import java.awt.Graphics; | import java.awt.Graphics; | ||||||
| 
 | 
 | ||||||
| import javax.swing.JButton; | import javax.swing.JButton; | ||||||
| 
 | 
 | ||||||
| import envoy.client.data.Settings; | import envoy.client.data.Settings; | ||||||
| import envoy.client.data.SettingsItem; | import envoy.client.data.SettingsItem; | ||||||
| 
 | import envoy.client.ui.Color; | ||||||
| /** | 
 | ||||||
|  * This component can be used to toggle between two options. This will change | /** | ||||||
|  * the state of a {@code boolean} {@link SettingsItem}.<br> |  * This component can be used to toggle between two options. This will change | ||||||
|  * <br> |  * the state of a {@code boolean} {@link SettingsItem}.<br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * <br> | ||||||
|  * File: <strong>PrimaryToggleSwitch.java</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * Created: <strong>21 Dec 2019</strong><br> |  * File: <strong>PrimaryToggleSwitch.java</strong><br> | ||||||
|  *  |  * Created: <strong>21 Dec 2019</strong><br> | ||||||
|  * @author Maximilian Käfer |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.3-alpha |  * @author Kai S. K. Engelbart | ||||||
|  */ |  * @since Envoy Client v0.3-alpha | ||||||
| public class PrimaryToggleSwitch extends JButton { |  */ | ||||||
| 
 | public class PrimaryToggleSwitch extends JButton { | ||||||
| 	private boolean state; | 
 | ||||||
| 
 | 	private boolean state; | ||||||
| 	private static final long serialVersionUID = -721155303106833184L; | 
 | ||||||
| 
 | 	private static final long serialVersionUID = -721155303106833184L; | ||||||
| 	/** | 
 | ||||||
| 	 * Initializes a {@link PrimaryToggleSwitch}. | 	/** | ||||||
| 	 *  | 	 * Initializes a {@link PrimaryToggleSwitch}. | ||||||
| 	 * @param settingsItem the {@link SettingsItem} that is controlled by this | 	 * | ||||||
| 	 *                     {@link PrimaryToggleSwitch} | 	 * @param settingsItem the {@link SettingsItem} that is controlled by this | ||||||
| 	 * @since Envoy v0.3-alpha | 	 *                     {@link PrimaryToggleSwitch} | ||||||
| 	 */ | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) { | 	 */ | ||||||
| 		setPreferredSize(new Dimension(50, 25)); | 	public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) { | ||||||
| 		setMinimumSize(new Dimension(50, 25)); | 		setPreferredSize(new Dimension(50, 25)); | ||||||
| 		setMaximumSize(new Dimension(50, 25)); | 		setMinimumSize(new Dimension(50, 25)); | ||||||
| 
 | 		setMaximumSize(new Dimension(50, 25)); | ||||||
| 		setBorderPainted(false); | 
 | ||||||
| 		setFocusPainted(false); | 		setBorderPainted(false); | ||||||
| 		setContentAreaFilled(false); | 		setFocusPainted(false); | ||||||
| 
 | 		setContentAreaFilled(false); | ||||||
| 		state = settingsItem.get(); | 
 | ||||||
| 		addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); | 		state = settingsItem.get(); | ||||||
| 	} | 		addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); }); | ||||||
| 
 | 	} | ||||||
| 	@Override | 
 | ||||||
| 	public void paintComponent(Graphics g) { | 	@Override | ||||||
| 		g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); | 	public void paintComponent(Graphics g) { | ||||||
| 		g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); | 		g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY); | ||||||
| 
 | 		g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25); | ||||||
| 		g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor()); | 
 | ||||||
| 		g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); | 		g.setColor(Settings.getInstance().getCurrentTheme().getInteractableBackgroundColor()); | ||||||
| 	} | 		g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); | ||||||
| } | 	} | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/main/java/envoy/client/ui/primary/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/main/java/envoy/client/ui/primary/package-info.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | /** | ||||||
|  |  * This package defines all "primary" components that were defined specifically | ||||||
|  |  * for the visual improvement of Envoy. However, they can still be used in | ||||||
|  |  * general for other projects.<br> | ||||||
|  |  * Primary elements are supposed to provide the main functionality of a UI | ||||||
|  |  * component.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>package-info.java</strong><br> | ||||||
|  |  * Created: <strong>14 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @author Maximilian Käfer | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | package envoy.client.ui.primary; | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui; | package envoy.client.ui.renderer; | ||||||
| 
 | 
 | ||||||
| import java.awt.Component; | import java.awt.Component; | ||||||
| import java.awt.Dimension; | import java.awt.Dimension; | ||||||
| @@ -20,7 +20,7 @@ import envoy.data.User.UserStatus; | |||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-alpha |  * @since Envoy Client v0.1-alpha | ||||||
|  */ |  */ | ||||||
| public class UserListRenderer extends JLabel implements ListCellRenderer<User> { | public class UserListRenderer extends JLabel implements ListCellRenderer<User> { | ||||||
| 
 | 
 | ||||||
| @@ -46,7 +46,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer<User> { | |||||||
| 
 | 
 | ||||||
| 		// Getting the UserNameColor of the current theme | 		// Getting the UserNameColor of the current theme | ||||||
| 		String textColor = null; | 		String textColor = null; | ||||||
| 		textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex(); | 		textColor = Settings.getInstance().getCurrentTheme().getUserNameColor().toHex(); | ||||||
| 		switch (status) { | 		switch (status) { | ||||||
| 			case ONLINE: | 			case ONLINE: | ||||||
| 				setText(String | 				setText(String | ||||||
| @@ -59,4 +59,4 @@ public class UserListRenderer extends JLabel implements ListCellRenderer<User> { | |||||||
| 		} | 		} | ||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
							
								
								
									
										14
									
								
								src/main/java/envoy/client/ui/renderer/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/main/java/envoy/client/ui/renderer/package-info.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | /** | ||||||
|  |  * This package contains all Envoy-specific renderers for lists that store an | ||||||
|  |  * arbitrary number of JComponents.<br> | ||||||
|  |  * <br> | ||||||
|  |  * Project: <strong>envoy-client</strong><br> | ||||||
|  |  * File: <strong>package-info.java</strong><br> | ||||||
|  |  * Created: <strong>14 Mar 2020</strong><br> | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @author Kai S. K. Engelbart | ||||||
|  |  * @author Maximilian Käfer | ||||||
|  |  * @since Envoy Client v0.1-beta | ||||||
|  |  */ | ||||||
|  | package envoy.client.ui.renderer; | ||||||
| @@ -1,93 +1,89 @@ | |||||||
| package envoy.client.ui.settings; | package envoy.client.ui.settings; | ||||||
|  |  | ||||||
| import java.awt.GridBagConstraints; | import java.awt.GridBagConstraints; | ||||||
| import java.awt.GridBagLayout; | import java.awt.GridBagLayout; | ||||||
| import java.awt.Insets; | import java.awt.Insets; | ||||||
| import java.awt.event.ActionListener; | import java.util.logging.Level; | ||||||
| import java.util.logging.Level; | import java.util.logging.Logger; | ||||||
| import java.util.logging.Logger; |  | ||||||
|  | import javax.swing.JComponent; | ||||||
| import javax.swing.JComponent; | import javax.swing.JTextPane; | ||||||
| import javax.swing.JTextPane; |  | ||||||
|  | import envoy.client.data.Settings; | ||||||
| import envoy.client.data.Settings; | import envoy.client.data.SettingsItem; | ||||||
| import envoy.client.data.SettingsItem; | import envoy.client.ui.Theme; | ||||||
| import envoy.client.ui.Theme; | import envoy.util.EnvoyLog; | ||||||
| import envoy.util.EnvoyLog; |  | ||||||
|  | /** | ||||||
| /** |  * Displays GUI components that allow general settings regarding the client.<br> | ||||||
|  * Displays GUI components that allow general settings regarding the client.<br> |  * <br> | ||||||
|  * <br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * File: <strong>GeneralSettingsPanel.java</strong><br> | ||||||
|  * File: <strong>GeneralSettingsPanel.java</strong><br> |  * Created: <strong>21 Dec 2019</strong><br> | ||||||
|  * Created: <strong>21 Dec 2019</strong><br> |  * | ||||||
|  * |  * @author Maximilian Käfer | ||||||
|  * @author Maximilian Käfer |  * @since Envoy Client v0.3-alpha | ||||||
|  * @since Envoy v0.3-alpha |  */ | ||||||
|  */ | public class GeneralSettingsPanel extends SettingsPanel { | ||||||
| public class GeneralSettingsPanel extends SettingsPanel { |  | ||||||
|  | 	private Theme theme; | ||||||
| 	private Theme theme; |  | ||||||
|  | 	private static final String[]	items				= { "onCloseMode", "enterToSend" }; | ||||||
| 	private static final String[]	items				= { "onCloseMode", "enterToSend" }; | 	private static final Logger		logger				= EnvoyLog.getLogger(GeneralSettingsPanel.class); | ||||||
| 	private static final Logger		logger				= EnvoyLog.getLogger(GeneralSettingsPanel.class); | 	private static final long		serialVersionUID	= -7470848775130754239L; | ||||||
| 	private static final long		serialVersionUID	= -7470848775130754239L; |  | ||||||
|  | 	/** | ||||||
| 	/** | 	 * This is the constructor for the General class. Here the user can set general | ||||||
| 	 * This is the constructor for the General class. Here the user can set general | 	 * settings for the client. | ||||||
| 	 * settings for the client. | 	 * | ||||||
| 	 * | 	 * @param parent the {@link SettingsScreen} as a part of which this | ||||||
| 	 * @param parent the {@link SettingsScreen} as a part of which this | 	 *               {@link SettingsPanel} is displayed | ||||||
| 	 *               {@link SettingsPanel} is displayed | 	 * @since Envoy Client v0.3-alpha | ||||||
| 	 * @since Envoy v0.3-alpha | 	 */ | ||||||
| 	 */ | 	public GeneralSettingsPanel(SettingsScreen parent) { | ||||||
| 	public GeneralSettingsPanel(SettingsScreen parent) { | 		super(parent); | ||||||
| 		super(parent); | 		theme = Settings.getInstance().getCurrentTheme(); | ||||||
| 		theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); |  | ||||||
|  | 		setBackground(theme.getCellColor()); | ||||||
| 		setBackground(theme.getCellColor()); |  | ||||||
|  | 		GridBagLayout gbl_general = new GridBagLayout(); | ||||||
| 		GridBagLayout gbl_general = new GridBagLayout(); | 		gbl_general.columnWidths	= new int[] { 1, 1 }; | ||||||
| 		gbl_general.columnWidths	= new int[] { 1, 1 }; | 		gbl_general.rowHeights		= new int[] { 1, 1, 1 }; | ||||||
| 		gbl_general.rowHeights		= new int[] { 1, 1, 1 }; | 		gbl_general.columnWeights	= new double[] { 1.0, 0.1 }; | ||||||
| 		gbl_general.columnWeights	= new double[] { 1.0, 0.1 }; | 		gbl_general.rowWeights		= new double[] { 0.02, 0.02, 1.0 }; | ||||||
| 		gbl_general.rowWeights		= new double[] { 0.02, 0.02, 1.0 }; |  | ||||||
|  | 		setLayout(gbl_general); | ||||||
| 		setLayout(gbl_general); |  | ||||||
|  | 		for (int i = 0; i < items.length; i++) | ||||||
| 		for (int i = 0; i < items.length; i++) | 			try { | ||||||
| 			try { | 				createSettingElement(i, Settings.getInstance().getItems().get(items[i])); | ||||||
| 				createSettingElement(i, Settings.getInstance().getItems().get(items[i])); | 			} catch (SecurityException | ReflectiveOperationException e) { | ||||||
| 			} catch (SecurityException | ReflectiveOperationException e) { | 				logger.log(Level.WARNING, "Could not create settings item", e); | ||||||
| 				logger.log(Level.WARNING, "Could not create settings item", e); | 			} | ||||||
| 			} | 	} | ||||||
| 	} |  | ||||||
|  | 	private void createSettingElement(int gridy, SettingsItem<?> settingsItem) throws SecurityException, ReflectiveOperationException { | ||||||
| 	private void createSettingElement(int gridy, SettingsItem<?> settingsItem) throws SecurityException, ReflectiveOperationException { | 		JTextPane descriptionText = new JTextPane(); | ||||||
| 		JTextPane descriptionText = new JTextPane(); |  | ||||||
|  | 		JComponent settingComponent = settingsItem.getComponent(); | ||||||
| 		JComponent settingComponent = settingsItem.getComponent(); |  | ||||||
|  | 		GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); | ||||||
| 		GridBagConstraints gbc_toggleSwitch = new GridBagConstraints(); | 		gbc_toggleSwitch.gridx	= 1; | ||||||
| 		gbc_toggleSwitch.gridx	= 1; | 		gbc_toggleSwitch.gridy	= gridy; | ||||||
| 		gbc_toggleSwitch.gridy	= gridy; |  | ||||||
|  | 		add(settingComponent, gbc_toggleSwitch); | ||||||
| 		add(settingComponent, gbc_toggleSwitch); |  | ||||||
|  | 		descriptionText.setText(settingsItem.getDescription()); | ||||||
| 		descriptionText.setText(settingsItem.getDescription()); | 		descriptionText.setBackground(theme.getBackgroundColor()); | ||||||
| 		descriptionText.setBackground(theme.getBackgroundColor()); | 		descriptionText.setForeground(theme.getBackgroundColor().invert()); | ||||||
| 		descriptionText.setForeground(theme.getBackgroundColor().invert()); | 		descriptionText.setEditable(false); | ||||||
| 		descriptionText.setEditable(false); |  | ||||||
|  | 		GridBagConstraints gbc_descriptionText = new GridBagConstraints(); | ||||||
| 		GridBagConstraints gbc_descriptionText = new GridBagConstraints(); | 		gbc_descriptionText.fill	= GridBagConstraints.BOTH; | ||||||
| 		gbc_descriptionText.fill	= GridBagConstraints.BOTH; | 		gbc_descriptionText.gridx	= 0; | ||||||
| 		gbc_descriptionText.gridx	= 0; | 		gbc_descriptionText.gridy	= gridy; | ||||||
| 		gbc_descriptionText.gridy	= gridy; | 		gbc_descriptionText.insets	= new Insets(5, 5, 5, 5); | ||||||
| 		gbc_descriptionText.insets	= new Insets(5, 5, 5, 5); |  | ||||||
|  | 		add(descriptionText, gbc_descriptionText); | ||||||
| 		add(descriptionText, gbc_descriptionText); | 	} | ||||||
| 	} | } | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public ActionListener getOkButtonAction() { return evt -> {}; } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,226 +1,228 @@ | |||||||
| package envoy.client.ui.settings; | package envoy.client.ui.settings; | ||||||
|  |  | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
|  |  | ||||||
| import javax.swing.JDialog; | import javax.swing.JDialog; | ||||||
| import javax.swing.JPanel; | import javax.swing.JPanel; | ||||||
| import javax.swing.JTextPane; | import javax.swing.JTextPane; | ||||||
|  |  | ||||||
| import envoy.client.data.Settings; | import envoy.client.data.Settings; | ||||||
| import envoy.client.ui.PrimaryButton; | import envoy.client.ui.Theme; | ||||||
| import envoy.client.ui.PrimaryTextArea; | import envoy.client.ui.primary.PrimaryButton; | ||||||
| import envoy.client.ui.Theme; | import envoy.client.ui.primary.PrimaryTextArea; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Displays window where you can choose a name for the new {@link Theme}. |  * Displays window where you can choose a name for the new {@link Theme}. | ||||||
|  * <br> |  * <br> | ||||||
|  * Project: <strong>envoy-client</strong><br> |  * Project: <strong>envoy-client</strong><br> | ||||||
|  * File: <strong>NewThemeScreen.java</strong><br> |  * File: <strong>NewThemeScreen.java</strong><br> | ||||||
|  * Created: <strong>26 Dec 2019</strong><br> |  * Created: <strong>26 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.3-alpha |  * @since Envoy Client v0.3-alpha | ||||||
|  */ |  */ | ||||||
| public class NewThemeScreen extends JDialog { | public class NewThemeScreen extends JDialog { | ||||||
|  |  | ||||||
| 	private final JPanel	standardPanel		= new JPanel(); | 	private final JPanel	standardPanel		= new JPanel(); | ||||||
| 	private final JPanel	secondaryPanel		= new JPanel(); | 	private final JPanel	secondaryPanel		= new JPanel(); | ||||||
| 	private JTextPane		text				= new JTextPane(); | 	private JTextPane		text				= new JTextPane(); | ||||||
| 	private PrimaryTextArea	nameEnterTextArea	= new PrimaryTextArea(4); | 	private PrimaryTextArea	nameEnterTextArea	= new PrimaryTextArea(4); | ||||||
| 	private PrimaryButton	confirmButton		= new PrimaryButton("Confirm"); | 	private PrimaryButton	confirmButton		= new PrimaryButton("Confirm"); | ||||||
|  |  | ||||||
| 	private JTextPane		errorText	= new JTextPane(); | 	private JTextPane		errorText	= new JTextPane(); | ||||||
| 	private PrimaryButton	otherName	= new PrimaryButton("Other Name"); | 	private PrimaryButton	otherName	= new PrimaryButton("Other Name"); | ||||||
| 	private PrimaryButton	overwrite	= new PrimaryButton("Overwrite"); | 	private PrimaryButton	overwrite	= new PrimaryButton("Overwrite"); | ||||||
|  |  | ||||||
| 	private final Consumer<String> newThemeAction, modifyThemeAction; | 	private final Consumer<String> newThemeAction, modifyThemeAction; | ||||||
|  |  | ||||||
| 	private static final long serialVersionUID = 2369985550946300976L; | 	private static final long serialVersionUID = 2369985550946300976L; | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a window, where you can choose a name for a new {@link Theme}. <br> | 	 * Creates a window, where you can choose a name for a new {@link Theme}. <br> | ||||||
| 	 * There are two versions of this Window. The first one is responsible for | 	 * There are two versions of this Window. The first one is responsible for | ||||||
| 	 * choosing the name, the second one appears, if the name already exists. | 	 * choosing the name, the second one appears, if the name already exists. | ||||||
| 	 *  | 	 * | ||||||
| 	 * @param parent the dialog is launched with its location relative to this {@link SettingsScreen} | 	 * @param parent            the dialog is launched with its location relative to | ||||||
| 	 * @param newThemeAction is executed when a new theme name is entered | 	 *                          this {@link SettingsScreen} | ||||||
| 	 * @param modifyThemeAction is executed when an existing theme name is entered and confirmed | 	 * @param newThemeAction    is executed when a new theme name is entered | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @param modifyThemeAction is executed when an existing theme name is entered | ||||||
| 	 */ | 	 *                          and confirmed | ||||||
| 	public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) { | 	 * @since Envoy Client v0.3-alpha | ||||||
| 		this.newThemeAction		= newThemeAction; | 	 */ | ||||||
| 		this.modifyThemeAction	= modifyThemeAction; | 	public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) { | ||||||
|  | 		this.newThemeAction		= newThemeAction; | ||||||
| 		setLocationRelativeTo(parent); | 		this.modifyThemeAction	= modifyThemeAction; | ||||||
| 		setTitle("New Theme"); |  | ||||||
| 		setModal(true); | 		setLocationRelativeTo(parent); | ||||||
|  | 		setTitle("New Theme"); | ||||||
| 		setDimensions(true); | 		setModal(true); | ||||||
| 		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); |  | ||||||
|  | 		setDimensions(true); | ||||||
| 		Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); | 		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); | ||||||
|  |  | ||||||
| 		getContentPane().setLayout(new BorderLayout()); | 		Theme theme = Settings.getInstance().getCurrentTheme(); | ||||||
| 		standardPanel.setBackground(theme.getBackgroundColor()); |  | ||||||
| 		secondaryPanel.setBackground(theme.getBackgroundColor()); | 		getContentPane().setLayout(new BorderLayout()); | ||||||
| 		loadStandardContent(theme); | 		standardPanel.setBackground(theme.getBackgroundColor()); | ||||||
| 	} | 		secondaryPanel.setBackground(theme.getBackgroundColor()); | ||||||
|  | 		loadStandardContent(theme); | ||||||
| 	private void setDimensions(boolean isStandard) { | 	} | ||||||
| 		Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225); |  | ||||||
| 		setPreferredSize(size); | 	private void setDimensions(boolean isStandard) { | ||||||
| 		setMinimumSize(size); | 		Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225); | ||||||
| 		setMaximumSize(size); | 		setPreferredSize(size); | ||||||
| 	} | 		setMinimumSize(size); | ||||||
|  | 		setMaximumSize(size); | ||||||
| 	private void loadStandardContent(Theme theme) { | 	} | ||||||
| 		getContentPane().removeAll(); |  | ||||||
|  | 	private void loadStandardContent(Theme theme) { | ||||||
| 		// ContentPane | 		getContentPane().removeAll(); | ||||||
| 		GridBagLayout gbl_contentPanel = new GridBagLayout(); |  | ||||||
|  | 		// ContentPane | ||||||
| 		gbl_contentPanel.columnWidths	= new int[] { 1, 1 }; | 		GridBagLayout gbl_contentPanel = new GridBagLayout(); | ||||||
| 		gbl_contentPanel.rowHeights		= new int[] { 1, 1, 1 }; |  | ||||||
| 		gbl_contentPanel.columnWeights	= new double[] { 1, 1 }; | 		gbl_contentPanel.columnWidths	= new int[] { 1, 1 }; | ||||||
| 		gbl_contentPanel.rowWeights		= new double[] { 1, 1, 1 }; | 		gbl_contentPanel.rowHeights		= new int[] { 1, 1, 1 }; | ||||||
|  | 		gbl_contentPanel.columnWeights	= new double[] { 1, 1 }; | ||||||
| 		getContentPane().add(standardPanel, BorderLayout.CENTER); | 		gbl_contentPanel.rowWeights		= new double[] { 1, 1, 1 }; | ||||||
| 		standardPanel.setLayout(gbl_contentPanel); |  | ||||||
|  | 		getContentPane().add(standardPanel, BorderLayout.CENTER); | ||||||
| 		// text.setFont(new Font()); | 		standardPanel.setLayout(gbl_contentPanel); | ||||||
| 		text.setText("Please enter a name for the new Theme"); |  | ||||||
| 		text.setAlignmentX(CENTER_ALIGNMENT); | 		// text.setFont(new Font()); | ||||||
| 		text.setBackground(theme.getCellColor()); | 		text.setText("Please enter a name for the new Theme"); | ||||||
| 		text.setForeground(theme.getUserNameColor()); | 		text.setAlignmentX(CENTER_ALIGNMENT); | ||||||
| 		text.setEditable(false); | 		text.setBackground(theme.getCellColor()); | ||||||
|  | 		text.setForeground(theme.getUserNameColor()); | ||||||
| 		GridBagConstraints gbc_text = new GridBagConstraints(); | 		text.setEditable(false); | ||||||
| 		gbc_text.fill		= GridBagConstraints.HORIZONTAL; |  | ||||||
| 		gbc_text.gridx		= 0; | 		GridBagConstraints gbc_text = new GridBagConstraints(); | ||||||
| 		gbc_text.gridy		= 0; | 		gbc_text.fill		= GridBagConstraints.HORIZONTAL; | ||||||
| 		gbc_text.gridwidth	= 2; | 		gbc_text.gridx		= 0; | ||||||
| 		gbc_text.insets		= new Insets(5, 5, 5, 5); | 		gbc_text.gridy		= 0; | ||||||
|  | 		gbc_text.gridwidth	= 2; | ||||||
| 		standardPanel.add(text, gbc_text); | 		gbc_text.insets		= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		nameEnterTextArea.setBackground(theme.getCellColor()); | 		standardPanel.add(text, gbc_text); | ||||||
| 		nameEnterTextArea.setForeground(theme.getTypingMessageColor()); |  | ||||||
| 		nameEnterTextArea.setText(""); | 		nameEnterTextArea.setBackground(theme.getCellColor()); | ||||||
| 		nameEnterTextArea.setEditable(true); | 		nameEnterTextArea.setForeground(theme.getTypingMessageColor()); | ||||||
|  | 		nameEnterTextArea.setText(""); | ||||||
| 		GridBagConstraints gbc_input = new GridBagConstraints(); | 		nameEnterTextArea.setEditable(true); | ||||||
| 		gbc_input.fill		= GridBagConstraints.HORIZONTAL; |  | ||||||
| 		gbc_input.gridx		= 0; | 		GridBagConstraints gbc_input = new GridBagConstraints(); | ||||||
| 		gbc_input.gridy		= 1; | 		gbc_input.fill		= GridBagConstraints.HORIZONTAL; | ||||||
| 		gbc_input.gridwidth	= 2; | 		gbc_input.gridx		= 0; | ||||||
| 		gbc_input.insets	= new Insets(5, 5, 5, 5); | 		gbc_input.gridy		= 1; | ||||||
|  | 		gbc_input.gridwidth	= 2; | ||||||
| 		standardPanel.add(nameEnterTextArea, gbc_input); | 		gbc_input.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		confirmButton.setBackground(theme.getInteractableBackgroundColor()); | 		standardPanel.add(nameEnterTextArea, gbc_input); | ||||||
| 		confirmButton.setForeground(theme.getInteractableForegroundColor()); |  | ||||||
|  | 		confirmButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		GridBagConstraints gbc_confirmButton = new GridBagConstraints(); | 		confirmButton.setForeground(theme.getInteractableForegroundColor()); | ||||||
| 		gbc_confirmButton.gridx		= 0; |  | ||||||
| 		gbc_confirmButton.gridy		= 2; | 		GridBagConstraints gbc_confirmButton = new GridBagConstraints(); | ||||||
| 		gbc_confirmButton.gridwidth	= 2; | 		gbc_confirmButton.gridx		= 0; | ||||||
| 		gbc_confirmButton.insets	= new Insets(5, 5, 5, 5); | 		gbc_confirmButton.gridy		= 2; | ||||||
|  | 		gbc_confirmButton.gridwidth	= 2; | ||||||
| 		standardPanel.add(confirmButton, gbc_confirmButton); | 		gbc_confirmButton.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		confirmButton.addActionListener((evt) -> { | 		standardPanel.add(confirmButton, gbc_confirmButton); | ||||||
| 			if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { |  | ||||||
| 				// load other panel | 		confirmButton.addActionListener((evt) -> { | ||||||
| 				setDimensions(false); | 			if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) { | ||||||
| 				loadSecondaryPage(theme); | 				// load other panel | ||||||
| 			} else { | 				setDimensions(false); | ||||||
| 				newThemeAction.accept(nameEnterTextArea.getText()); | 				loadSecondaryPage(theme); | ||||||
| 				dispose(); | 			} else { | ||||||
| 			} | 				newThemeAction.accept(nameEnterTextArea.getText()); | ||||||
| 		}); | 				dispose(); | ||||||
| 	} | 			} | ||||||
|  | 		}); | ||||||
| 	private void loadSecondaryPage(Theme theme) { | 	} | ||||||
| 		// ContentPane |  | ||||||
| 		getContentPane().removeAll(); | 	private void loadSecondaryPage(Theme theme) { | ||||||
|  | 		// ContentPane | ||||||
| 		GridBagLayout gbl_secondaryPanel = new GridBagLayout(); | 		getContentPane().removeAll(); | ||||||
|  |  | ||||||
| 		gbl_secondaryPanel.columnWidths		= new int[] { 1, 1 }; | 		GridBagLayout gbl_secondaryPanel = new GridBagLayout(); | ||||||
| 		gbl_secondaryPanel.rowHeights		= new int[] { 1, 1, 1, 1 }; |  | ||||||
| 		gbl_secondaryPanel.columnWeights	= new double[] { 1, 1 }; | 		gbl_secondaryPanel.columnWidths		= new int[] { 1, 1 }; | ||||||
| 		gbl_secondaryPanel.rowWeights		= new double[] { 1, 1, 1, 1 }; | 		gbl_secondaryPanel.rowHeights		= new int[] { 1, 1, 1, 1 }; | ||||||
|  | 		gbl_secondaryPanel.columnWeights	= new double[] { 1, 1 }; | ||||||
| 		getContentPane().add(secondaryPanel, BorderLayout.CENTER); | 		gbl_secondaryPanel.rowWeights		= new double[] { 1, 1, 1, 1 }; | ||||||
| 		secondaryPanel.setLayout(gbl_secondaryPanel); |  | ||||||
|  | 		getContentPane().add(secondaryPanel, BorderLayout.CENTER); | ||||||
| 		// text.setFont(new Font()); | 		secondaryPanel.setLayout(gbl_secondaryPanel); | ||||||
| 		text.setText("Please enter a name for the new Theme"); |  | ||||||
| 		text.setAlignmentX(CENTER_ALIGNMENT); | 		// text.setFont(new Font()); | ||||||
| 		text.setBackground(theme.getCellColor()); | 		text.setText("Please enter a name for the new Theme"); | ||||||
| 		text.setForeground(theme.getUserNameColor()); | 		text.setAlignmentX(CENTER_ALIGNMENT); | ||||||
| 		text.setEditable(false); | 		text.setBackground(theme.getCellColor()); | ||||||
|  | 		text.setForeground(theme.getUserNameColor()); | ||||||
| 		GridBagConstraints gbc_text = new GridBagConstraints(); | 		text.setEditable(false); | ||||||
| 		gbc_text.fill		= GridBagConstraints.HORIZONTAL; |  | ||||||
| 		gbc_text.gridx		= 0; | 		GridBagConstraints gbc_text = new GridBagConstraints(); | ||||||
| 		gbc_text.gridy		= 0; | 		gbc_text.fill		= GridBagConstraints.HORIZONTAL; | ||||||
| 		gbc_text.gridwidth	= 2; | 		gbc_text.gridx		= 0; | ||||||
| 		gbc_text.insets		= new Insets(5, 5, 5, 5); | 		gbc_text.gridy		= 0; | ||||||
|  | 		gbc_text.gridwidth	= 2; | ||||||
| 		secondaryPanel.add(text, gbc_text); | 		gbc_text.insets		= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		nameEnterTextArea.setBackground(theme.getCellColor()); | 		secondaryPanel.add(text, gbc_text); | ||||||
| 		nameEnterTextArea.setForeground(theme.getTypingMessageColor()); |  | ||||||
| 		nameEnterTextArea.setEditable(false); | 		nameEnterTextArea.setBackground(theme.getCellColor()); | ||||||
|  | 		nameEnterTextArea.setForeground(theme.getTypingMessageColor()); | ||||||
| 		GridBagConstraints gbc_input = new GridBagConstraints(); | 		nameEnterTextArea.setEditable(false); | ||||||
| 		gbc_input.fill		= GridBagConstraints.HORIZONTAL; |  | ||||||
| 		gbc_input.gridx		= 0; | 		GridBagConstraints gbc_input = new GridBagConstraints(); | ||||||
| 		gbc_input.gridy		= 1; | 		gbc_input.fill		= GridBagConstraints.HORIZONTAL; | ||||||
| 		gbc_input.gridwidth	= 2; | 		gbc_input.gridx		= 0; | ||||||
| 		gbc_input.insets	= new Insets(5, 5, 5, 5); | 		gbc_input.gridy		= 1; | ||||||
|  | 		gbc_input.gridwidth	= 2; | ||||||
| 		secondaryPanel.add(nameEnterTextArea, gbc_input); | 		gbc_input.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		errorText.setText("The name does already exist. Choose another one or overwrite the old theme."); | 		secondaryPanel.add(nameEnterTextArea, gbc_input); | ||||||
| 		errorText.setAlignmentX(CENTER_ALIGNMENT); |  | ||||||
| 		errorText.setBackground(theme.getCellColor()); | 		errorText.setText("The name does already exist. Choose another one or overwrite the old theme."); | ||||||
| 		errorText.setForeground(theme.getUserNameColor()); | 		errorText.setAlignmentX(CENTER_ALIGNMENT); | ||||||
| 		errorText.setEditable(false); | 		errorText.setBackground(theme.getCellColor()); | ||||||
|  | 		errorText.setForeground(theme.getUserNameColor()); | ||||||
| 		GridBagConstraints gbc_errorText = new GridBagConstraints(); | 		errorText.setEditable(false); | ||||||
| 		gbc_errorText.fill		= GridBagConstraints.HORIZONTAL; |  | ||||||
| 		gbc_errorText.gridx		= 0; | 		GridBagConstraints gbc_errorText = new GridBagConstraints(); | ||||||
| 		gbc_errorText.gridy		= 2; | 		gbc_errorText.fill		= GridBagConstraints.HORIZONTAL; | ||||||
| 		gbc_errorText.gridwidth	= 2; | 		gbc_errorText.gridx		= 0; | ||||||
| 		gbc_errorText.insets	= new Insets(5, 5, 5, 5); | 		gbc_errorText.gridy		= 2; | ||||||
|  | 		gbc_errorText.gridwidth	= 2; | ||||||
| 		secondaryPanel.add(errorText, gbc_errorText); | 		gbc_errorText.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		otherName.setBackground(theme.getInteractableBackgroundColor()); | 		secondaryPanel.add(errorText, gbc_errorText); | ||||||
| 		otherName.setForeground(theme.getInteractableForegroundColor()); |  | ||||||
|  | 		otherName.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		GridBagConstraints gbc_otherName = new GridBagConstraints(); | 		otherName.setForeground(theme.getInteractableForegroundColor()); | ||||||
| 		gbc_otherName.gridx		= 0; |  | ||||||
| 		gbc_otherName.gridy		= 3; | 		GridBagConstraints gbc_otherName = new GridBagConstraints(); | ||||||
| 		gbc_otherName.insets	= new Insets(5, 5, 5, 5); | 		gbc_otherName.gridx		= 0; | ||||||
|  | 		gbc_otherName.gridy		= 3; | ||||||
| 		secondaryPanel.add(otherName, gbc_otherName); | 		gbc_otherName.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		overwrite.setBackground(theme.getInteractableBackgroundColor()); | 		secondaryPanel.add(otherName, gbc_otherName); | ||||||
| 		overwrite.setForeground(theme.getInteractableForegroundColor()); |  | ||||||
|  | 		overwrite.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		GridBagConstraints gbc_overwrite = new GridBagConstraints(); | 		overwrite.setForeground(theme.getInteractableForegroundColor()); | ||||||
| 		gbc_overwrite.gridx		= 1; |  | ||||||
| 		gbc_overwrite.gridy		= 3; | 		GridBagConstraints gbc_overwrite = new GridBagConstraints(); | ||||||
| 		gbc_overwrite.insets	= new Insets(5, 5, 5, 5); | 		gbc_overwrite.gridx		= 1; | ||||||
|  | 		gbc_overwrite.gridy		= 3; | ||||||
| 		secondaryPanel.add(overwrite, gbc_overwrite); | 		gbc_overwrite.insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 		otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); }); | 		secondaryPanel.add(overwrite, gbc_overwrite); | ||||||
|  |  | ||||||
| 		overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); | 		otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); }); | ||||||
| 	} |  | ||||||
| } | 		overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); }); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,7 +1,5 @@ | |||||||
| package envoy.client.ui.settings; | package envoy.client.ui.settings; | ||||||
|  |  | ||||||
| import java.awt.event.ActionListener; |  | ||||||
|  |  | ||||||
| import javax.swing.JPanel; | import javax.swing.JPanel; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -14,7 +12,7 @@ import javax.swing.JPanel; | |||||||
|  * Created: <strong>20 Dec 2019</strong><br> |  * Created: <strong>20 Dec 2019</strong><br> | ||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public abstract class SettingsPanel extends JPanel { | public abstract class SettingsPanel extends JPanel { | ||||||
|  |  | ||||||
| @@ -24,16 +22,9 @@ public abstract class SettingsPanel extends JPanel { | |||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Initializes a {@link SettingsPanel}. | 	 * Initializes a {@link SettingsPanel}. | ||||||
| 	 *  | 	 * | ||||||
| 	 * @param parent the {@link SettingsScreen} as a part of which this | 	 * @param parent the {@link SettingsScreen} as a part of which this | ||||||
| 	 *               {@link SettingsPanel} is displayed | 	 *               {@link SettingsPanel} is displayed | ||||||
| 	 */ | 	 */ | ||||||
| 	public SettingsPanel(SettingsScreen parent) { this.parent = parent; } | 	public SettingsPanel(SettingsScreen parent) { this.parent = parent; } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @return an {@link ActionListener} that should be invoked when the OK button |  | ||||||
| 	 *         is pressed in the {@link SettingsScreen} |  | ||||||
| 	 * @since Envoy v0.2-alpha |  | ||||||
| 	 */ |  | ||||||
| 	public abstract ActionListener getOkButtonAction(); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,8 +11,8 @@ import javax.swing.*; | |||||||
|  |  | ||||||
| import envoy.client.data.Settings; | import envoy.client.data.Settings; | ||||||
| import envoy.client.event.ThemeChangeEvent; | import envoy.client.event.ThemeChangeEvent; | ||||||
| import envoy.client.ui.PrimaryButton; |  | ||||||
| import envoy.client.ui.Theme; | import envoy.client.ui.Theme; | ||||||
|  | import envoy.client.ui.primary.PrimaryButton; | ||||||
| import envoy.event.EventBus; | import envoy.event.EventBus; | ||||||
| import envoy.util.EnvoyLog; | import envoy.util.EnvoyLog; | ||||||
|  |  | ||||||
| @@ -26,7 +26,7 @@ import envoy.util.EnvoyLog; | |||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class SettingsScreen extends JDialog { | public class SettingsScreen extends JDialog { | ||||||
|  |  | ||||||
| @@ -40,7 +40,6 @@ public class SettingsScreen extends JDialog { | |||||||
|  |  | ||||||
| 	// OK and cancel buttons | 	// OK and cancel buttons | ||||||
| 	private final JPanel		buttonPane		= new JPanel(); | 	private final JPanel		buttonPane		= new JPanel(); | ||||||
| 	private final PrimaryButton	okButton		= new PrimaryButton("Save"); |  | ||||||
| 	private final PrimaryButton	cancelButton	= new PrimaryButton("Cancel"); | 	private final PrimaryButton	cancelButton	= new PrimaryButton("Cancel"); | ||||||
|  |  | ||||||
| 	private final Insets insets = new Insets(5, 5, 5, 5); | 	private final Insets insets = new Insets(5, 5, 5, 5); | ||||||
| @@ -52,7 +51,7 @@ public class SettingsScreen extends JDialog { | |||||||
| 	/** | 	/** | ||||||
| 	 * Initializes the settings screen. | 	 * Initializes the settings screen. | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.1-alpha | 	 * @since Envoy Client v0.1-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public SettingsScreen() { | 	public SettingsScreen() { | ||||||
| 		// Initialize settings pages | 		// Initialize settings pages | ||||||
| @@ -138,25 +137,10 @@ public class SettingsScreen extends JDialog { | |||||||
|  |  | ||||||
| 				cancelButton.addActionListener((evt) -> { dispose(); }); | 				cancelButton.addActionListener((evt) -> { dispose(); }); | ||||||
| 			} | 			} | ||||||
| 			{ |  | ||||||
| 				okButton.setActionCommand("OK"); |  | ||||||
| 				okButton.setBorderPainted(false); |  | ||||||
| 				GridBagConstraints gbc_okButton = new GridBagConstraints(); |  | ||||||
| 				gbc_okButton.anchor	= GridBagConstraints.NORTHEAST; |  | ||||||
| 				gbc_okButton.fill	= GridBagConstraints.EAST; |  | ||||||
| 				gbc_okButton.insets	= insets; |  | ||||||
| 				gbc_okButton.gridx	= 2; |  | ||||||
| 				gbc_okButton.gridy	= 0; |  | ||||||
| 				buttonPane.add(okButton, gbc_okButton); |  | ||||||
| 				getRootPane().setDefaultButton(okButton); |  | ||||||
|  |  | ||||||
| 				// Invoke settings panel action on button press |  | ||||||
| 				okButton.addActionListener((evt) -> { if (settingsPanel != null) settingsPanel.getOkButtonAction().actionPerformed(evt); }); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Apply current theme | 		// Apply current theme | ||||||
| 		applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); | 		applyTheme(Settings.getInstance().getCurrentTheme()); | ||||||
|  |  | ||||||
| 		// Respond to theme changes | 		// Respond to theme changes | ||||||
| 		EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); | 		EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); | ||||||
| @@ -179,14 +163,10 @@ public class SettingsScreen extends JDialog { | |||||||
| 		cancelButton.setBackground(theme.getInteractableBackgroundColor()); | 		cancelButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		cancelButton.setForeground(theme.getInteractableForegroundColor()); | 		cancelButton.setForeground(theme.getInteractableForegroundColor()); | ||||||
|  |  | ||||||
| 		// okButton |  | ||||||
| 		okButton.setBackground(theme.getInteractableBackgroundColor()); |  | ||||||
| 		okButton.setForeground(theme.getInteractableForegroundColor()); |  | ||||||
|  |  | ||||||
| 		// options | 		// options | ||||||
| 		options.setSelectionForeground(theme.getUserNameColor()); | 		options.setSelectionForeground(theme.getUserNameColor()); | ||||||
| 		options.setSelectionBackground(theme.getSelectionColor()); | 		options.setSelectionBackground(theme.getSelectionColor()); | ||||||
| 		options.setForeground(theme.getUserNameColor()); | 		options.setForeground(theme.getUserNameColor()); | ||||||
| 		options.setBackground(theme.getCellColor()); | 		options.setBackground(theme.getCellColor()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										119
									
								
								src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,9 +1,6 @@ | |||||||
| package envoy.client.ui.settings; | package envoy.client.ui.settings; | ||||||
|  |  | ||||||
| import java.awt.*; | import java.awt.*; | ||||||
| import java.awt.event.ActionListener; |  | ||||||
| import java.awt.event.ItemEvent; |  | ||||||
| import java.awt.event.ItemListener; |  | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
|  |  | ||||||
| @@ -13,6 +10,7 @@ import envoy.client.data.Settings; | |||||||
| import envoy.client.event.ThemeChangeEvent; | import envoy.client.event.ThemeChangeEvent; | ||||||
| import envoy.client.ui.Color; | import envoy.client.ui.Color; | ||||||
| import envoy.client.ui.Theme; | import envoy.client.ui.Theme; | ||||||
|  | import envoy.client.ui.primary.PrimaryButton; | ||||||
| import envoy.event.EventBus; | import envoy.event.EventBus; | ||||||
| import envoy.util.EnvoyLog; | import envoy.util.EnvoyLog; | ||||||
|  |  | ||||||
| @@ -26,19 +24,19 @@ import envoy.util.EnvoyLog; | |||||||
|  * |  * | ||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| public class ThemeCustomizationPanel extends SettingsPanel { | public class ThemeCustomizationPanel extends SettingsPanel { | ||||||
|  |  | ||||||
| 	private JPanel colorsPanel = new JPanel(); | 	private JPanel colorsPanel = new JPanel(); | ||||||
|  |  | ||||||
| 	private DefaultComboBoxModel<String>	themesModel	= new DefaultComboBoxModel<>( | 	private DefaultComboBoxModel<String>	themesModel; | ||||||
| 			Settings.getInstance().getThemes().keySet().toArray(new String[0])); | 	private JComboBox<String>				themes; | ||||||
| 	private JComboBox<String>				themes		= new JComboBox<>(themesModel); |  | ||||||
| 	private Theme							temporaryTheme; | 	private Theme							temporaryTheme; | ||||||
| 	private boolean							themeChanged; | 	private PrimaryButton					createThemeButton	= new PrimaryButton("Create Theme"); | ||||||
|  |  | ||||||
| 	private final Insets insets = new Insets(5, 5, 5, 5); | 	private boolean			themeChanged; | ||||||
|  | 	private final Insets	insets	= new Insets(5, 5, 5, 5); | ||||||
|  |  | ||||||
| 	private static final Logger	logger				= EnvoyLog.getLogger(ThemeCustomizationPanel.class); | 	private static final Logger	logger				= EnvoyLog.getLogger(ThemeCustomizationPanel.class); | ||||||
| 	private static final long	serialVersionUID	= -8697897390666456624L; | 	private static final long	serialVersionUID	= -8697897390666456624L; | ||||||
| @@ -50,18 +48,28 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
| 	 * | 	 * | ||||||
| 	 * @param parent the {@link SettingsScreen} as a part of which this | 	 * @param parent the {@link SettingsScreen} as a part of which this | ||||||
| 	 *               {@link SettingsPanel} is displayed | 	 *               {@link SettingsPanel} is displayed | ||||||
| 	 * @since Envoy v0.2-alpha | 	 * @since Envoy Client v0.2-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	public ThemeCustomizationPanel(SettingsScreen parent) { | 	public ThemeCustomizationPanel(SettingsScreen parent) { | ||||||
| 		super(parent); | 		super(parent); | ||||||
| 		temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); | 		temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getCurrentTheme()); | ||||||
|  |  | ||||||
|  | 		var		themeNames			= Settings.getInstance().getThemes().keySet().toArray(new String[0]); | ||||||
|  | 		String	currentThemeName	= Settings.getInstance().getCurrentThemeName(); | ||||||
|  | 		for (int i = 0; i < themeNames.length; i++) | ||||||
|  | 			if (currentThemeName.equals(themeNames[i])) { | ||||||
|  | 				themeNames[i]	= themeNames[0]; | ||||||
|  | 				themeNames[0]	= currentThemeName; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		themesModel	= new DefaultComboBoxModel<>(themeNames); | ||||||
|  | 		themes		= new JComboBox<>(themesModel); | ||||||
| 		GridBagLayout gbl_themeLayout = new GridBagLayout(); | 		GridBagLayout gbl_themeLayout = new GridBagLayout(); | ||||||
|  |  | ||||||
| 		gbl_themeLayout.columnWidths	= new int[] { 1, 1 }; | 		gbl_themeLayout.columnWidths	= new int[] { 1, 1 }; | ||||||
| 		gbl_themeLayout.rowHeights		= new int[] { 1, 1 }; | 		gbl_themeLayout.rowHeights		= new int[] { 1, 1, 1 }; | ||||||
| 		gbl_themeLayout.columnWeights	= new double[] { 1.0, 1.0 }; | 		gbl_themeLayout.columnWeights	= new double[] { 1.0, 1.0 }; | ||||||
| 		gbl_themeLayout.rowWeights		= new double[] { 0.01, 1.0 }; | 		gbl_themeLayout.rowWeights		= new double[] { 0.01, 1.0, 0.01 }; | ||||||
|  |  | ||||||
| 		setLayout(gbl_themeLayout); | 		setLayout(gbl_themeLayout); | ||||||
|  |  | ||||||
| @@ -85,7 +93,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
|  |  | ||||||
| 		colorsPanel.setLayout(gbl_colorCustomizations); | 		colorsPanel.setLayout(gbl_colorCustomizations); | ||||||
|  |  | ||||||
| 		Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); | 		Theme theme = Settings.getInstance().getCurrentTheme(); | ||||||
| 		buildCustomizeElements(theme); | 		buildCustomizeElements(theme); | ||||||
|  |  | ||||||
| 		GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); | 		GridBagConstraints gbc_colorsPanel = new GridBagConstraints(); | ||||||
| @@ -97,20 +105,47 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
| 		gbc_colorsPanel.insets		= insets; | 		gbc_colorsPanel.insets		= insets; | ||||||
|  |  | ||||||
| 		add(colorsPanel, gbc_colorsPanel); | 		add(colorsPanel, gbc_colorsPanel); | ||||||
|  |  | ||||||
|  | 		createThemeButton.addActionListener((evt) -> { | ||||||
|  | 			if (themeChanged) { | ||||||
|  | 				new NewThemeScreen(parent, name -> { | ||||||
|  | 					// Create new theme | ||||||
|  | 					logger.log(Level.FINEST, name); | ||||||
|  | 					Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); | ||||||
|  |  | ||||||
|  | 					// Add new theme name to combo box | ||||||
|  | 					themesModel.addElement(name); | ||||||
|  |  | ||||||
|  | 					// Select new theme name | ||||||
|  | 					themes.setSelectedIndex(themesModel.getSize() - 1); | ||||||
|  | 				}, name -> { | ||||||
|  | 					// Modify theme | ||||||
|  | 					Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); | ||||||
|  | 					if (themes.getSelectedItem().equals(name)) | ||||||
|  | 						EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); | ||||||
|  | 					else themes.setSelectedItem(name); | ||||||
|  | 				}).setVisible(true); | ||||||
|  | 				themeChanged = false; | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 		GridBagConstraints gbc_createThemeButton = new GridBagConstraints(); | ||||||
|  | 		gbc_createThemeButton.fill		= GridBagConstraints.HORIZONTAL; | ||||||
|  | 		gbc_createThemeButton.gridx		= 0; | ||||||
|  | 		gbc_createThemeButton.gridy		= 2; | ||||||
|  | 		gbc_createThemeButton.anchor	= GridBagConstraints.CENTER; | ||||||
|  | 		gbc_createThemeButton.insets	= insets; | ||||||
|  | 		add(createThemeButton, gbc_createThemeButton); | ||||||
|  | 		 | ||||||
| 		colorsPanel.setBackground(theme.getCellColor()); | 		colorsPanel.setBackground(theme.getCellColor()); | ||||||
|  |  | ||||||
| 		// Apply theme upon selection | 		// Apply theme upon selection | ||||||
| 		themes.addItemListener(new ItemListener() { | 		themes.addItemListener(e -> { | ||||||
|  | 			String selectedValue = (String) themes.getSelectedItem(); | ||||||
|  | 			logger.log(Level.FINEST, "Selected theme: " + selectedValue); | ||||||
|  |  | ||||||
| 			@Override | 			final Theme currentTheme = Settings.getInstance().getTheme(selectedValue); | ||||||
| 			public void itemStateChanged(ItemEvent e) { | 			Settings.getInstance().setCurrentTheme(selectedValue); | ||||||
| 				String selectedValue = (String) themes.getSelectedItem(); | 			EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); | ||||||
| 				logger.log(Level.FINEST, "Selected theme: " + selectedValue); |  | ||||||
|  |  | ||||||
| 				final Theme currentTheme = Settings.getInstance().getTheme(selectedValue); |  | ||||||
| 				Settings.getInstance().setCurrentTheme(selectedValue); |  | ||||||
| 				EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme)); |  | ||||||
| 			} |  | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| 		// Apply current theme | 		// Apply current theme | ||||||
| @@ -126,39 +161,15 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
| 					}); | 					}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override |  | ||||||
| 	public ActionListener getOkButtonAction() { |  | ||||||
| 		return (evt) -> { |  | ||||||
| 			if (themeChanged) { |  | ||||||
| 				new NewThemeScreen(parent, name -> { |  | ||||||
| 					// Create new theme |  | ||||||
| 					logger.log(Level.FINEST, name); |  | ||||||
| 					Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme)); |  | ||||||
|  |  | ||||||
| 					// Add new theme name to combo box |  | ||||||
| 					themesModel.addElement(name); |  | ||||||
|  |  | ||||||
| 					// Select new theme name |  | ||||||
| 					themes.setSelectedIndex(themesModel.getSize() - 1); |  | ||||||
| 				}, name -> { |  | ||||||
| 					// Modify theme |  | ||||||
| 					Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme)); |  | ||||||
| 					if (themes.getSelectedItem().equals(name)) { |  | ||||||
| 						EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name))); |  | ||||||
| 					} else { |  | ||||||
| 						themes.setSelectedItem(name); |  | ||||||
| 					} |  | ||||||
| 				}).setVisible(true); |  | ||||||
| 				themeChanged = false; |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void applyTheme(Theme theme) { | 	private void applyTheme(Theme theme) { | ||||||
| 		// themeContent | 		// themeContent | ||||||
| 		setForeground(theme.getUserNameColor()); | 		setForeground(theme.getUserNameColor()); | ||||||
| 		setBackground(theme.getCellColor()); | 		setBackground(theme.getCellColor()); | ||||||
|  |  | ||||||
|  | 		// createThemeButton | ||||||
|  | 		createThemeButton.setForeground(theme.getInteractableForegroundColor()); | ||||||
|  | 		createThemeButton.setBackground(theme.getInteractableBackgroundColor()); | ||||||
|  | 		 | ||||||
| 		// themes | 		// themes | ||||||
| 		themes.setBackground(theme.getInteractableBackgroundColor()); | 		themes.setBackground(theme.getInteractableBackgroundColor()); | ||||||
| 		themes.setForeground(theme.getInteractableForegroundColor()); | 		themes.setForeground(theme.getInteractableForegroundColor()); | ||||||
| @@ -181,7 +192,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
| 		buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); | 		buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); | ||||||
| 		buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); | 		buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); | ||||||
| 		buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); | 		buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); | ||||||
| 		buildCustomizeElement(theme, theme.getMessageTextColor(), "Messages Chat", "messageColorChat", 5); | 		buildCustomizeElement(theme, theme.getTextColor(), "Text Color", "textColor", 5); | ||||||
| 		buildCustomizeElement(theme, theme.getDateColor(), "Date Chat", "dateColorChat", 6); | 		buildCustomizeElement(theme, theme.getDateColor(), "Date Chat", "dateColorChat", 6); | ||||||
| 		buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); | 		buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); | ||||||
| 		buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); | 		buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); | ||||||
| @@ -232,4 +243,4 @@ public class ThemeCustomizationPanel extends SettingsPanel { | |||||||
|  |  | ||||||
| 		colorsPanel.add(button, gbc_button); | 		colorsPanel.add(button, gbc_button); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,6 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.2-alpha |  * @since Envoy Client v0.2-alpha | ||||||
|  */ |  */ | ||||||
| package envoy.client.ui.settings; | package envoy.client.ui.settings; | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  * @author Kai S. K. Engelbart |  * @author Kai S. K. Engelbart | ||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @author Maximilian Käfer |  * @author Maximilian Käfer | ||||||
|  * @since Envoy v0.1-beta |  * @since Envoy Client v0.1-beta | ||||||
|  */ |  */ | ||||||
| module envoy { | module envoy { | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/forward.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/forward.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 25 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/read.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/read.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 29 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/received.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/received.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 29 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/sent.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/sent.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/waiting.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/messagestatus/waiting.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/icons/settings.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/icons/settings.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 28 KiB | 
		Reference in New Issue
	
	Block a user
	 delvh
					delvh