Merge pull request #123 from informatik-ag-ngl/f/forward_messages
Added message forwarding capability
This commit is contained in:
commit
2b501f0329
@ -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(() -> {
|
@ -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,37 +56,35 @@ 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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() {
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
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();
|
||||||
@ -75,9 +88,8 @@ public class ChatWindow extends JFrame {
|
|||||||
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 {
|
|
||||||
checkMessageTextLength();
|
|
||||||
// Create message
|
// Create message
|
||||||
final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator())
|
final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator())
|
||||||
.setText(messageEnterTextArea.getText())
|
.setText(text)
|
||||||
.build();
|
.build();
|
||||||
|
sendMessage(message);
|
||||||
|
// 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() {
|
||||||
|
if (model != null) {
|
||||||
removeAll();
|
removeAll();
|
||||||
if (model != null) model.forEach(this::add);
|
model.forEach(this::addElement);
|
||||||
revalidate();
|
revalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an object to the list by rendering it with the current
|
|
||||||
* {@link ComponentListCellRenderer}.
|
|
||||||
*
|
|
||||||
* @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
|
* Selects a list element by index. If the element is already selected, it is
|
||||||
* listener will be added
|
* removed from the selection.
|
||||||
* @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();
|
||||||
|
|
||||||
|
// Select item
|
||||||
|
if (selectionMode != SelectionMode.NONE) {
|
||||||
|
|
||||||
// Assign new selection
|
// Assign new selection
|
||||||
currentSelection = index;
|
selection.add(index);
|
||||||
|
|
||||||
// Update current selection
|
// Update element
|
||||||
update(currentSelection, true);
|
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,4 +1,4 @@
|
|||||||
package envoy.client.ui;
|
package envoy.client.ui.primary;
|
||||||
|
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import javax.swing.JButton;
|
|||||||
*
|
*
|
||||||
* @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 {
|
||||||
|
|
@ -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,4 +1,4 @@
|
|||||||
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;
|
||||||
@ -7,6 +7,7 @@ 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
|
* This component can be used to toggle between two options. This will change
|
||||||
@ -18,7 +19,7 @@ import envoy.client.data.SettingsItem;
|
|||||||
*
|
*
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @since Envoy v0.3-alpha
|
* @since Envoy Client v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public class PrimaryToggleSwitch extends JButton {
|
public class PrimaryToggleSwitch extends JButton {
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ public class PrimaryToggleSwitch extends JButton {
|
|||||||
*
|
*
|
||||||
* @param settingsItem the {@link SettingsItem} that is controlled by this
|
* @param settingsItem the {@link SettingsItem} that is controlled by this
|
||||||
* {@link PrimaryToggleSwitch}
|
* {@link PrimaryToggleSwitch}
|
||||||
* @since Envoy v0.3-alpha
|
* @since Envoy Client v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) {
|
public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) {
|
||||||
setPreferredSize(new Dimension(50, 25));
|
setPreferredSize(new Dimension(50, 25));
|
||||||
@ -51,7 +52,7 @@ public class PrimaryToggleSwitch extends JButton {
|
|||||||
g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY);
|
g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY);
|
||||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25);
|
g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25);
|
||||||
|
|
||||||
g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor());
|
g.setColor(Settings.getInstance().getCurrentTheme().getInteractableBackgroundColor());
|
||||||
g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25);
|
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
|
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;
|
@ -3,7 +3,6 @@ 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;
|
||||||
|
|
||||||
@ -23,7 +22,7 @@ import envoy.util.EnvoyLog;
|
|||||||
* Created: <strong>21 Dec 2019</strong><br>
|
* Created: <strong>21 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 GeneralSettingsPanel extends SettingsPanel {
|
public class GeneralSettingsPanel extends SettingsPanel {
|
||||||
|
|
||||||
@ -39,11 +38,11 @@ public class GeneralSettingsPanel 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.3-alpha
|
* @since Envoy Client v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public GeneralSettingsPanel(SettingsScreen parent) {
|
public GeneralSettingsPanel(SettingsScreen parent) {
|
||||||
super(parent);
|
super(parent);
|
||||||
theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
theme = Settings.getInstance().getCurrentTheme();
|
||||||
|
|
||||||
setBackground(theme.getCellColor());
|
setBackground(theme.getCellColor());
|
||||||
|
|
||||||
@ -87,7 +86,4 @@ public class GeneralSettingsPanel extends SettingsPanel {
|
|||||||
|
|
||||||
add(descriptionText, gbc_descriptionText);
|
add(descriptionText, gbc_descriptionText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ActionListener getOkButtonAction() { return evt -> {}; }
|
|
||||||
}
|
}
|
@ -8,9 +8,9 @@ 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.PrimaryTextArea;
|
|
||||||
import envoy.client.ui.Theme;
|
import envoy.client.ui.Theme;
|
||||||
|
import envoy.client.ui.primary.PrimaryButton;
|
||||||
|
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}.
|
||||||
@ -20,7 +20,7 @@ import envoy.client.ui.Theme;
|
|||||||
* 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 {
|
||||||
|
|
||||||
@ -43,10 +43,12 @@ public class NewThemeScreen extends JDialog {
|
|||||||
* 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
|
||||||
|
* this {@link SettingsScreen}
|
||||||
* @param newThemeAction is executed when a new theme name is entered
|
* @param newThemeAction is executed when a new theme name is entered
|
||||||
* @param modifyThemeAction is executed when an existing theme name is entered and confirmed
|
* @param modifyThemeAction is executed when an existing theme name is entered
|
||||||
* @since Envoy v0.3-alpha
|
* and confirmed
|
||||||
|
* @since Envoy Client v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) {
|
public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) {
|
||||||
this.newThemeAction = newThemeAction;
|
this.newThemeAction = newThemeAction;
|
||||||
@ -59,7 +61,7 @@ public class NewThemeScreen extends JDialog {
|
|||||||
setDimensions(true);
|
setDimensions(true);
|
||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||||
|
|
||||||
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
Theme theme = Settings.getInstance().getCurrentTheme();
|
||||||
|
|
||||||
getContentPane().setLayout(new BorderLayout());
|
getContentPane().setLayout(new BorderLayout());
|
||||||
standardPanel.setBackground(theme.getBackgroundColor());
|
standardPanel.setBackground(theme.getBackgroundColor());
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
@ -29,11 +27,4 @@ public abstract class SettingsPanel extends JPanel {
|
|||||||
* {@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,10 +163,6 @@ 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());
|
||||||
|
105
src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java
Normal file → Executable file
105
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,18 +24,18 @@ 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 boolean themeChanged;
|
||||||
private final Insets insets = new Insets(5, 5, 5, 5);
|
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);
|
||||||
@ -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 -> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void itemStateChanged(ItemEvent e) {
|
|
||||||
String selectedValue = (String) themes.getSelectedItem();
|
String selectedValue = (String) themes.getSelectedItem();
|
||||||
logger.log(Level.FINEST, "Selected theme: " + selectedValue);
|
logger.log(Level.FINEST, "Selected theme: " + selectedValue);
|
||||||
|
|
||||||
final Theme currentTheme = Settings.getInstance().getTheme(selectedValue);
|
final Theme currentTheme = Settings.getInstance().getTheme(selectedValue);
|
||||||
Settings.getInstance().setCurrentTheme(selectedValue);
|
Settings.getInstance().setCurrentTheme(selectedValue);
|
||||||
EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme));
|
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);
|
||||||
|
@ -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