Merge pull request #123 from informatik-ag-ngl/f/forward_messages
Added message forwarding capability
This commit is contained in:
commit
c1087a8c6a
@ -1,4 +1,4 @@
|
||||
package envoy.client.ui;
|
||||
package envoy.client;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.io.File;
|
||||
@ -15,6 +15,9 @@ import javax.swing.SwingUtilities;
|
||||
import envoy.client.data.*;
|
||||
import envoy.client.net.Client;
|
||||
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.Message;
|
||||
import envoy.data.User.UserStatus;
|
||||
@ -31,7 +34,7 @@ import envoy.util.EnvoyLog;
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public class Startup {
|
||||
|
||||
@ -48,7 +51,7 @@ public class Startup {
|
||||
*
|
||||
* @param args the command line arguments may contain configuration parameters
|
||||
* 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) {
|
||||
ClientConfig config = ClientConfig.getInstance();
|
||||
@ -127,11 +130,9 @@ public class Startup {
|
||||
// Save all users to the local database and flush cache
|
||||
localDb.setUsers(client.getUsers());
|
||||
writeProxy.flushCache();
|
||||
} else {
|
||||
|
||||
} else
|
||||
// Set all contacts to offline mode
|
||||
localDb.getUsers().values().stream().filter(u -> u != localDb.getUser()).forEach(u -> u.setStatus(UserStatus.OFFLINE));
|
||||
}
|
||||
|
||||
// Display ChatWindow and StatusTrayIcon
|
||||
EventQueue.invokeLater(() -> {
|
||||
@ -173,4 +174,4 @@ public class Startup {
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ import envoy.util.EnvoyLog;
|
||||
*
|
||||
* @param <T> the type of cached elements
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
*
|
||||
* @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; }
|
||||
|
||||
@ -51,7 +51,7 @@ public class Cache<T> implements Consumer<T>, Serializable {
|
||||
* Relays all cached elements to the processor.
|
||||
*
|
||||
* @throws IllegalStateException if the processor is not initialized
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void relay() {
|
||||
if (processor == null) throw new IllegalStateException("Processor is not defined");
|
||||
|
@ -4,7 +4,7 @@ import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
|
||||
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.MessageStatus;
|
||||
import envoy.data.User;
|
||||
@ -21,21 +21,21 @@ import envoy.event.MessageStatusChangeEvent;
|
||||
* @author Maximilian Käfer
|
||||
* @author Leon Hofmeister
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public class Chat implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7751248474547242056L;
|
||||
|
||||
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>
|
||||
* Saves the Messages in the corresponding chat at that Point.
|
||||
*
|
||||
* @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; }
|
||||
|
||||
@ -43,7 +43,7 @@ public class Chat implements Serializable {
|
||||
* Appends a message to the bottom of this chat
|
||||
*
|
||||
* @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); }
|
||||
|
||||
@ -56,17 +56,15 @@ public class Chat implements Serializable {
|
||||
* the message status changes
|
||||
* @throws IOException if a {@link MessageStatusChangeEvent} could not be
|
||||
* delivered to the server
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void read(WriteProxy writeProxy) throws IOException {
|
||||
for (int i = model.size() - 1; i >= 0; --i) {
|
||||
final Message m = model.get(i);
|
||||
if (m.getSenderId() == recipient.getId()) {
|
||||
if (m.getStatus() == MessageStatus.READ) break;
|
||||
else {
|
||||
m.setStatus(MessageStatus.READ);
|
||||
writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m));
|
||||
}
|
||||
if (m.getSenderId() == recipient.getId()) if (m.getStatus() == MessageStatus.READ) break;
|
||||
else {
|
||||
m.setStatus(MessageStatus.READ);
|
||||
writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,19 +72,19 @@ public class Chat implements Serializable {
|
||||
/**
|
||||
* @return {@code true} if the newest message received in the chat doesn't have
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public User getRecipient() { return recipient; }
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import envoy.data.LoginCredentials;
|
||||
* Created: <strong>01.03.2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public class ClientConfig extends Config {
|
||||
|
||||
@ -26,7 +26,7 @@ public class ClientConfig extends Config {
|
||||
|
||||
/**
|
||||
* @return the singleton instance of the client config
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public static ClientConfig getInstance() {
|
||||
if (config == null) config = new ClientConfig();
|
||||
@ -47,68 +47,68 @@ public class ClientConfig extends Config {
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
/**
|
||||
* @return the user name
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public String getUser() { return (String) items.get("user").get(); }
|
||||
|
||||
/**
|
||||
* @return the password
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public char[] getPassword() { return (char[]) items.get("password").get(); }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return login credentials for the specified user name and password, without
|
||||
* the registration option
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public LoginCredentials getLoginCredentials() {
|
||||
try {
|
||||
|
@ -16,7 +16,7 @@ import envoy.event.MessageStatusChangeEvent;
|
||||
* Created: <strong>3 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public abstract class LocalDb {
|
||||
|
||||
@ -30,7 +30,7 @@ public abstract class LocalDb {
|
||||
/**
|
||||
* 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() {}
|
||||
|
||||
@ -39,7 +39,7 @@ public abstract class LocalDb {
|
||||
* as well. The message id generator will also be saved if present.
|
||||
*
|
||||
* @throws Exception if the saving process failed
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void save() throws Exception {}
|
||||
|
||||
@ -47,7 +47,7 @@ public abstract class LocalDb {
|
||||
* Loads all user data.
|
||||
*
|
||||
* @throws Exception if the loading process failed
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void loadUsers() throws Exception {}
|
||||
|
||||
@ -55,21 +55,21 @@ public abstract class LocalDb {
|
||||
* Loads all data of the client user.
|
||||
*
|
||||
* @throws Exception if the loading process failed
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void loadUserData() throws Exception {}
|
||||
|
||||
/**
|
||||
* 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() {}
|
||||
|
||||
/**
|
||||
* @return a {@code Map<String, User>} of all users stored locally with their
|
||||
* user names as keys
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
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
|
||||
* sender
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
**/
|
||||
public List<Chat> getChats() { return chats; }
|
||||
|
||||
@ -92,55 +92,55 @@ public abstract class LocalDb {
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the message ID generator
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public IdGenerator getIdGenerator() { return idGenerator; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the offline message cache
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public Cache<Message> getMessageCache() { return messageCache; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the offline status cache
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public Cache<MessageStatusChangeEvent> getStatusCache() { return statusCache; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
@ -150,7 +150,7 @@ public abstract class LocalDb {
|
||||
* @param id the ID of the message to search for
|
||||
* @return the message with the corresponding ID, or {@code null} if no message
|
||||
* has been found
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public Message getMessage(long id) {
|
||||
for (Chat c : chats)
|
||||
|
@ -19,7 +19,7 @@ import envoy.util.SerializationUtils;
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
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}
|
||||
* {@link ConfigItem}.
|
||||
*
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public PersistentLocalDb() {}
|
||||
|
||||
@ -42,7 +42,7 @@ public class PersistentLocalDb extends LocalDb {
|
||||
*
|
||||
* @param localDbDir the directory in which to store users and chats
|
||||
* @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 {
|
||||
localDBDir = localDbDir;
|
||||
@ -58,7 +58,7 @@ public class PersistentLocalDb extends LocalDb {
|
||||
* Creates a database file for a user-specific list of chats.
|
||||
*
|
||||
* @throws NullPointerException if the client user is not yet specified
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
@Override
|
||||
public void initializeUserStorage() {
|
||||
@ -100,4 +100,4 @@ public class PersistentLocalDb extends LocalDb {
|
||||
idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class);
|
||||
} catch (ClassNotFoundException | IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import envoy.util.SerializationUtils;
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class Settings {
|
||||
|
||||
@ -49,7 +49,7 @@ public class Settings {
|
||||
* The way to instantiate the settings.
|
||||
* Is set to private to deny other instances of that object.
|
||||
*
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
private Settings() {
|
||||
// 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.
|
||||
*
|
||||
* @return the instance of Settings
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
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
|
||||
* file
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public void save() throws IOException {
|
||||
// Save settings to settings file
|
||||
@ -110,21 +110,27 @@ public class Settings {
|
||||
* Adds new theme to the theme map.
|
||||
*
|
||||
* @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}
|
||||
* @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}.
|
||||
*
|
||||
* @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); }
|
||||
|
||||
@ -132,7 +138,7 @@ public class Settings {
|
||||
* @return {@code true}, if pressing the {@code Enter} key suffices to send a
|
||||
* message. Otherwise it has to be pressed in conjunction with the
|
||||
* {@code Control} key.
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
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
|
||||
* the {@code Enter} key. Otherwise it has to be pressed in
|
||||
* 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); }
|
||||
|
||||
/**
|
||||
* @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(); }
|
||||
|
||||
@ -156,7 +162,7 @@ public class Settings {
|
||||
* Sets the current on close mode.
|
||||
*
|
||||
* @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); }
|
||||
|
||||
@ -172,7 +178,7 @@ public class Settings {
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
@ -180,14 +186,14 @@ public class Settings {
|
||||
* Sets the {@code Map<String, Theme>} of all themes with their names as keys
|
||||
*
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @param themeName the name of the {@link Theme} to get
|
||||
* @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); }
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import java.util.function.Consumer;
|
||||
|
||||
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
|
||||
@ -19,7 +19,7 @@ import envoy.client.ui.PrimaryToggleSwitch;
|
||||
*
|
||||
* @param <T> the type of this {@link SettingsItem}'s value
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class SettingsItem<T> implements Serializable {
|
||||
|
||||
@ -45,7 +45,7 @@ public class SettingsItem<T> implements Serializable {
|
||||
* @param value the default value
|
||||
* @param userFriendlyName the user friendly name (short)
|
||||
* @param description the description (long)
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public SettingsItem(T value, String userFriendlyName, String description) {
|
||||
this(value, componentClasses.get(value.getClass()));
|
||||
@ -61,7 +61,7 @@ public class SettingsItem<T> implements Serializable {
|
||||
*
|
||||
* @param value the default value
|
||||
* @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) {
|
||||
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}
|
||||
* @throws ReflectiveOperationException 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 {
|
||||
if (componentClass == null) throw new NullPointerException("Component class is null");
|
||||
@ -81,7 +81,7 @@ public class SettingsItem<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public T get() { return value; }
|
||||
|
||||
@ -90,7 +90,7 @@ public class SettingsItem<T> implements Serializable {
|
||||
* defined, it will be invoked with this value.
|
||||
*
|
||||
* @param value the value to set
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void set(T value) {
|
||||
if (changeHandler != null && value != this.value) changeHandler.accept(value);
|
||||
@ -99,37 +99,37 @@ public class SettingsItem<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* @return the componentClass
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public Class<? extends JComponent> getComponentClass() { return componentClass; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the userFriendlyName
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public String getUserFriendlyName() { return userFriendlyName; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the description
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public String getDescription() { return description; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
@ -139,7 +139,7 @@ public class SettingsItem<T> implements Serializable {
|
||||
* when the value changes.
|
||||
*
|
||||
* @param changeHandler the changeHandler to set
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void setChangeHandler(Consumer<T> changeHandler) {
|
||||
this.changeHandler = changeHandler;
|
||||
|
@ -9,7 +9,7 @@ package envoy.client.data;
|
||||
* Created: <strong>3 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class TransientLocalDb extends LocalDb {
|
||||
}
|
||||
|
@ -4,6 +4,6 @@
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.data;
|
||||
|
@ -10,7 +10,7 @@ import envoy.event.Event;
|
||||
* Created: <strong>8 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class HandshakeSuccessfulEvent extends Event.Valueless {
|
||||
|
||||
|
@ -9,7 +9,7 @@ import envoy.event.Event;
|
||||
* Created: <strong>4 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class MessageCreationEvent extends Event<Message> {
|
||||
|
||||
|
@ -9,7 +9,7 @@ import envoy.event.Event;
|
||||
* Created: <strong>4 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class MessageModificationEvent extends Event<Message> {
|
||||
|
||||
|
@ -9,7 +9,7 @@ import envoy.event.Event;
|
||||
*
|
||||
* @author: Maximilian Käfer
|
||||
*
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class SendEvent extends Event<Event<?>> {
|
||||
|
||||
|
@ -9,7 +9,7 @@ import envoy.event.Event;
|
||||
* Created: <strong>15 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class ThemeChangeEvent extends Event<Theme> {
|
||||
|
||||
@ -20,7 +20,7 @@ public class ThemeChangeEvent extends Event<Theme> {
|
||||
* of the {@link Theme} currently in use
|
||||
*
|
||||
* @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); }
|
||||
}
|
||||
|
@ -4,6 +4,6 @@
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.event;
|
||||
|
@ -30,7 +30,7 @@ import envoy.util.SerializationUtils;
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public class Client implements Closeable {
|
||||
|
||||
@ -124,7 +124,7 @@ public class Client implements Closeable {
|
||||
* initialization
|
||||
* @throws IOException if no {@link IdGenerator} is present and none could be
|
||||
* 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 {
|
||||
checkOnline();
|
||||
@ -181,7 +181,7 @@ public class Client implements Closeable {
|
||||
*
|
||||
* @param message the message to send
|
||||
* @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 {
|
||||
writeObject(message);
|
||||
@ -200,7 +200,7 @@ public class Client implements Closeable {
|
||||
* Requests a new {@link IdGenerator} from 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 {
|
||||
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
|
||||
* user names as keys
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Map<String, User> getUsers() {
|
||||
checkOnline();
|
||||
@ -232,7 +232,7 @@ public class Client implements Closeable {
|
||||
|
||||
/**
|
||||
* @return the sender object that represents this client.
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public User getSender() { return sender; }
|
||||
|
||||
@ -240,7 +240,7 @@ public class Client implements Closeable {
|
||||
* Sets the client user which is used to send messages.
|
||||
*
|
||||
* @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; }
|
||||
|
||||
@ -251,19 +251,19 @@ public class Client implements Closeable {
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
|
||||
/**
|
||||
* @return the contacts of this {@link Client}
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public Contacts getContacts() { return contacts; }
|
||||
|
||||
/**
|
||||
* @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; }
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import envoy.util.EnvoyLog;
|
||||
* Created: <strong>4 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class MessageStatusChangeEventProcessor implements Consumer<MessageStatusChangeEvent> {
|
||||
|
||||
@ -25,7 +25,7 @@ public class MessageStatusChangeEventProcessor implements Consumer<MessageStatus
|
||||
* {@code RECEIVED} or {@code READ}.
|
||||
*
|
||||
* @param evt the status change event
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
@Override
|
||||
public void accept(MessageStatusChangeEvent evt) {
|
||||
|
@ -15,7 +15,7 @@ import envoy.util.EnvoyLog;
|
||||
* Created: <strong>31.12.2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class ReceivedMessageProcessor implements Consumer<Message> {
|
||||
|
||||
|
@ -19,7 +19,7 @@ import envoy.util.SerializationUtils;
|
||||
* Created: <strong>30.12.2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class Receiver extends Thread {
|
||||
|
||||
@ -85,4 +85,4 @@ public class Receiver extends Thread {
|
||||
* Removes all object processors registered at this {@link Receiver}.
|
||||
*/
|
||||
public void removeAllProcessors() { processors.clear(); }
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import envoy.event.UserStatusChangeEvent;
|
||||
* Created: <strong>2 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
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
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public UserStatusChangeProcessor(LocalDb localDb) { this.localDb = localDb; }
|
||||
|
||||
|
@ -19,7 +19,7 @@ import envoy.util.EnvoyLog;
|
||||
* Created: <strong>6 Feb 2020</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class WriteProxy {
|
||||
|
||||
@ -36,7 +36,7 @@ public class WriteProxy {
|
||||
* events
|
||||
* @param localDb the local database used to cache messages and message status
|
||||
* change events
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public WriteProxy(Client client, LocalDb localDb) {
|
||||
this.client = client;
|
||||
@ -68,7 +68,7 @@ public class WriteProxy {
|
||||
* Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the
|
||||
* server.
|
||||
*
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void flushCache() {
|
||||
// Send messages
|
||||
@ -84,7 +84,7 @@ public class WriteProxy {
|
||||
*
|
||||
* @param message the message to send
|
||||
* @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 {
|
||||
if (client.isOnline()) client.sendMessage(message);
|
||||
@ -97,7 +97,7 @@ public class WriteProxy {
|
||||
*
|
||||
* @param evt the event to send
|
||||
* @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 {
|
||||
if (client.isOnline()) client.sendEvent(evt);
|
||||
|
@ -4,6 +4,6 @@
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.net;
|
||||
|
@ -11,7 +11,7 @@ import java.awt.color.ColorSpace;
|
||||
* Created: <strong>23.12.2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
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
|
||||
* 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()); }
|
||||
|
||||
/**
|
||||
* @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()); }
|
||||
}
|
||||
|
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>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class StatusTrayIcon {
|
||||
|
||||
@ -41,7 +41,7 @@ public class StatusTrayIcon {
|
||||
* notifications are displayed
|
||||
* @throws EnvoyException if the currently used OS does not support the System
|
||||
* Tray API
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public StatusTrayIcon(Window focusTarget) throws EnvoyException {
|
||||
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
|
||||
* tray for system-internal reasons
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public void show() throws EnvoyException {
|
||||
try {
|
||||
@ -94,4 +94,4 @@ public class StatusTrayIcon {
|
||||
throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
37
src/main/java/envoy/client/ui/Theme.java
Normal file → Executable file
37
src/main/java/envoy/client/ui/Theme.java
Normal file → Executable file
@ -10,7 +10,7 @@ import java.util.Map;
|
||||
* Created: <strong>23 Nov 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class Theme implements Serializable {
|
||||
|
||||
@ -29,15 +29,16 @@ public class Theme implements Serializable {
|
||||
* elements
|
||||
* @param interactableBackgroundColor the color of interactable background UI
|
||||
* 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 selectionColor the section color
|
||||
* @param typingMessageColor the color of currently typed messages
|
||||
* @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,
|
||||
Color messageColorChat, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) {
|
||||
Color textColor, Color dateColorChat, Color selectionColor, Color typingMessageColor, Color userNameColor) {
|
||||
|
||||
this.themeName = themeName;
|
||||
|
||||
@ -45,7 +46,7 @@ public class Theme implements Serializable {
|
||||
colors.put("cellColor", cellColor);
|
||||
colors.put("interactableForegroundColor", interactableForegroundColor);
|
||||
colors.put("interactableBackgroundColor", interactableBackgroundColor);
|
||||
colors.put("messageColorChat", messageColorChat);
|
||||
colors.put("textColor", textColor);
|
||||
colors.put("dateColorChat", dateColorChat);
|
||||
colors.put("selectionColor", selectionColor);
|
||||
colors.put("typingMessageColor", typingMessageColor);
|
||||
@ -58,7 +59,7 @@ public class Theme implements Serializable {
|
||||
*
|
||||
* @param name the name of the {@link Theme}
|
||||
* @param other the {@link Theme} to copy
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Theme(String name, Theme other) {
|
||||
themeName = name;
|
||||
@ -68,69 +69,69 @@ public class Theme implements Serializable {
|
||||
/**
|
||||
* @return a {@code Map<String, Color>} of all colors defined for this theme
|
||||
* with their names as keys
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Map<String, Color> getColors() { return colors; }
|
||||
|
||||
/**
|
||||
* @return name of the theme
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public String getThemeName() { return themeName; }
|
||||
|
||||
/**
|
||||
* @return interactableForegroundColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); }
|
||||
|
||||
/**
|
||||
* @return the {@link Color} in which the text content of a message should be
|
||||
* 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
|
||||
* displayed
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getDateColor() { return colors.get("dateColorChat"); }
|
||||
|
||||
/**
|
||||
* @return selectionColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getSelectionColor() { return colors.get("selectionColor"); }
|
||||
|
||||
/**
|
||||
* @return typingMessageColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getTypingMessageColor() { return colors.get("typingMessageColor"); }
|
||||
|
||||
/**
|
||||
* @return backgroundColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getBackgroundColor() { return colors.get("backgroundColor"); }
|
||||
|
||||
/**
|
||||
* @return cellColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getCellColor() { return colors.get("cellColor"); }
|
||||
|
||||
/**
|
||||
* @return interactableBackgroundColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public Color getInteractableBackgroundColor() { return colors.get("interactableBackgroundColor"); }
|
||||
|
||||
/**
|
||||
* @return userNameColor
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
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.datatransfer.StringSelection;
|
||||
import java.awt.event.*;
|
||||
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.Logger;
|
||||
|
||||
@ -18,8 +23,16 @@ import envoy.client.event.MessageCreationEvent;
|
||||
import envoy.client.event.ThemeChangeEvent;
|
||||
import envoy.client.net.Client;
|
||||
import envoy.client.net.WriteProxy;
|
||||
import envoy.client.ui.Theme;
|
||||
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.data.Message;
|
||||
import envoy.data.Message.MessageStatus;
|
||||
@ -36,13 +49,12 @@ import envoy.util.EnvoyLog;
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @author Leon Hofmeister
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public class ChatWindow extends JFrame {
|
||||
|
||||
/**
|
||||
* This int defines the maximum amount of chars allowed per message. Currently
|
||||
* set at 200.
|
||||
* This integer defines the maximum amount of chars allowed per message.
|
||||
*
|
||||
* @since Envoy 0.1-beta
|
||||
*/
|
||||
@ -59,11 +71,12 @@ public class ChatWindow extends JFrame {
|
||||
private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space);
|
||||
private JList<User> userList = new JList<>();
|
||||
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 JTextPane textPane = new JTextPane();
|
||||
private PrimaryButton postButton = new PrimaryButton("Post");
|
||||
private PrimaryButton settingsButton = new PrimaryButton("Settings");
|
||||
private JPopupMenu contextMenu;
|
||||
|
||||
// Contacts Header
|
||||
private JPanel contactsHeader = new JPanel();
|
||||
@ -71,13 +84,12 @@ public class ChatWindow extends JFrame {
|
||||
private PrimaryButton addContact = new PrimaryButton("+");
|
||||
|
||||
// Search Contacts
|
||||
private final JPanel searchPane = new JPanel();
|
||||
private final PrimaryButton cancelButton = new PrimaryButton("x");
|
||||
private final PrimaryTextArea searchField = new PrimaryTextArea(space);
|
||||
private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane();
|
||||
private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer();
|
||||
private final ComponentListModel<User> contactsModel = new ComponentListModel<>();
|
||||
private final ComponentList<User> contactList = new ComponentList<>(contactRenderer);
|
||||
private final JPanel searchPane = new JPanel();
|
||||
private final PrimaryButton cancelButton = new PrimaryButton("x");
|
||||
private final PrimaryTextArea searchField = new PrimaryTextArea(space);
|
||||
private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane();
|
||||
private final Model<User> contactsModel = new Model<>();
|
||||
private final ComponentList<User> contactList = new ComponentList<User>().setRenderer(ContactSearchComponent::new);
|
||||
|
||||
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
|
||||
* to different users.
|
||||
*
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public ChatWindow() {
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setBounds(100, 100, 600, 800);
|
||||
setMinimumSize(new Dimension(400, 300));
|
||||
setTitle("Envoy");
|
||||
setLocationRelativeTo(null);
|
||||
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.rowHeights = new int[] { 1, 1, 1, 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);
|
||||
|
||||
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.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.addComponentListener(new ComponentAdapter() {
|
||||
|
||||
// updates list elements when list is resized
|
||||
// Update list elements when scroll pane (and thus list) is resized
|
||||
@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();
|
||||
gbc_scrollPane.fill = GridBagConstraints.BOTH;
|
||||
@ -135,7 +175,10 @@ public class ChatWindow extends JFrame {
|
||||
messageEnterTextArea.addInputMethodListener(new InputMethodListener() {
|
||||
|
||||
@Override
|
||||
public void inputMethodTextChanged(InputMethodEvent event) { checkMessageTextLength(); }
|
||||
public void inputMethodTextChanged(InputMethodEvent event) {
|
||||
checkMessageTextLength();
|
||||
checkPostButton(messageEnterTextArea.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void caretPositionChanged(InputMethodEvent event) {}
|
||||
@ -146,32 +189,30 @@ public class ChatWindow extends JFrame {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
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();
|
||||
// Checking if text is too long
|
||||
checkMessageTextLength();
|
||||
checkPostButton(messageEnterTextArea.getText());
|
||||
}
|
||||
});
|
||||
|
||||
GridBagConstraints gbc_scrollPaneForTextInput = new GridBagConstraints();
|
||||
gbc_scrollPaneForTextInput.fill = GridBagConstraints.BOTH;
|
||||
gbc_scrollPaneForTextInput.gridx = 1;
|
||||
gbc_scrollPaneForTextInput.gridy = 3;
|
||||
|
||||
gbc_scrollPaneForTextInput.insets = insets;
|
||||
|
||||
contentPane.add(messageEnterTextArea, gbc_scrollPaneForTextInput);
|
||||
GridBagConstraints gbc_messageEnterTextArea = new GridBagConstraints();
|
||||
gbc_messageEnterTextArea.fill = GridBagConstraints.BOTH;
|
||||
gbc_messageEnterTextArea.gridx = 1;
|
||||
gbc_messageEnterTextArea.gridy = 3;
|
||||
gbc_messageEnterTextArea.insets = insets;
|
||||
contentPane.add(messageEnterTextArea, gbc_messageEnterTextArea);
|
||||
|
||||
// Post Button
|
||||
GridBagConstraints gbc_postButton = new GridBagConstraints();
|
||||
|
||||
gbc_postButton.fill = GridBagConstraints.BOTH;
|
||||
gbc_postButton.gridx = 2;
|
||||
gbc_postButton.gridy = 3;
|
||||
|
||||
gbc_postButton.insets = insets;
|
||||
|
||||
gbc_postButton.insets = insets;
|
||||
postButton.addActionListener((evt) -> { postMessage(); });
|
||||
postButton.setEnabled(false);
|
||||
contentPane.add(postButton, gbc_postButton);
|
||||
|
||||
// Settings Button
|
||||
@ -353,11 +394,11 @@ public class ChatWindow extends JFrame {
|
||||
gbc_addContact.gridy = 0;
|
||||
gbc_addContact.insets = insets;
|
||||
|
||||
addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); });
|
||||
addContact.addActionListener(evt -> drawContactSearch(gbc_searchPane));
|
||||
|
||||
contactsHeader.add(addContact, gbc_addContact);
|
||||
|
||||
applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
|
||||
applyTheme(Settings.getInstance().getCurrentTheme());
|
||||
|
||||
contentPane.add(contactsHeader, gbc_contactsHeader);
|
||||
contentPane.revalidate();
|
||||
@ -440,15 +481,16 @@ public class ChatWindow extends JFrame {
|
||||
* Used to immediately reload the {@link ChatWindow} when settings were changed.
|
||||
*
|
||||
* @param theme the theme to change colors into
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
private void applyTheme(Theme theme) {
|
||||
// contentPane
|
||||
contentPane.setBackground(theme.getBackgroundColor());
|
||||
contentPane.setForeground(theme.getUserNameColor());
|
||||
// messageList
|
||||
messageList.setForeground(theme.getMessageTextColor());
|
||||
messageList.setForeground(theme.getTextColor());
|
||||
messageList.setBackground(theme.getCellColor());
|
||||
messageList.synchronizeModel();
|
||||
// scrollPane
|
||||
scrollPane.applyTheme(theme);
|
||||
scrollPane.autoscroll();
|
||||
@ -482,33 +524,68 @@ public class ChatWindow extends JFrame {
|
||||
searchField.setForeground(theme.getUserNameColor());
|
||||
cancelButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
cancelButton.setForeground(theme.getInteractableForegroundColor());
|
||||
contactList.setForeground(theme.getMessageTextColor());
|
||||
contactList.setForeground(theme.getTextColor());
|
||||
contactList.setBackground(theme.getCellColor());
|
||||
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() {
|
||||
if (userList.isSelectionEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE);
|
||||
return;
|
||||
}
|
||||
String text = messageEnterTextArea.getText().trim();
|
||||
if (!text.isEmpty()) checkMessageTextLength();
|
||||
|
||||
if (!messageEnterTextArea.getText().isEmpty()) try {
|
||||
checkMessageTextLength();
|
||||
// Create message
|
||||
final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator())
|
||||
.setText(messageEnterTextArea.getText())
|
||||
.build();
|
||||
// Create message
|
||||
final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator())
|
||||
.setText(text)
|
||||
.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
|
||||
writeProxy.writeMessage(message);
|
||||
|
||||
// Add message to PersistentLocalDb and update UI
|
||||
currentChat.appendMessage(message);
|
||||
|
||||
// Clear text field
|
||||
messageEnterTextArea.setText("");
|
||||
|
||||
// Update UI
|
||||
revalidate();
|
||||
repaint();
|
||||
@ -525,7 +602,7 @@ public class ChatWindow extends JFrame {
|
||||
private void readCurrentChat() {
|
||||
try {
|
||||
currentChat.read(writeProxy);
|
||||
messageList.synchronizeModel();
|
||||
if (messageList.getRenderer() != null) messageList.synchronizeModel();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
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
|
||||
* events to the server or cache them inside the local
|
||||
* database
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) {
|
||||
this.client = client;
|
||||
this.localDb = localDb;
|
||||
this.writeProxy = writeProxy;
|
||||
|
||||
messageList.setRenderer((list, message) -> new MessageComponent(list, message, client.getSender().getId()));
|
||||
|
||||
// Load users and chats
|
||||
new Thread(() -> {
|
||||
localDb.getUsers().values().forEach(user -> {
|
||||
@ -589,7 +668,7 @@ public class ChatWindow extends JFrame {
|
||||
* {@link ChatWindow#MAX_MESSAGE_LENGTH}
|
||||
* 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() {
|
||||
String input = messageEnterTextArea.getText();
|
||||
@ -603,4 +682,6 @@ public class ChatWindow extends JFrame {
|
||||
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.event.ItemEvent;
|
||||
@ -16,6 +16,8 @@ import javax.swing.border.EmptyBorder;
|
||||
import envoy.client.data.*;
|
||||
import envoy.client.event.HandshakeSuccessfulEvent;
|
||||
import envoy.client.net.Client;
|
||||
import envoy.client.ui.Theme;
|
||||
import envoy.client.ui.primary.PrimaryButton;
|
||||
import envoy.data.LoginCredentials;
|
||||
import envoy.data.Message;
|
||||
import envoy.data.User;
|
||||
@ -31,7 +33,7 @@ import envoy.util.EnvoyLog;
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
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 receivedMessageCache the cache that stored messages received during
|
||||
* the handshake
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public LoginDialog(Client client, LocalDb localDb, Cache<Message> receivedMessageCache) {
|
||||
this.client = client;
|
||||
@ -281,7 +283,7 @@ public class LoginDialog extends JDialog {
|
||||
/**
|
||||
* Resets the text stored in the password fields.
|
||||
*
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
private void clearPasswordFields() {
|
||||
passwordField.setText(null);
|
||||
@ -289,7 +291,7 @@ public class LoginDialog extends JDialog {
|
||||
}
|
||||
|
||||
private void setTheme() {
|
||||
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
||||
Theme theme = Settings.getInstance().getCurrentTheme();
|
||||
|
||||
// Panels
|
||||
contentPanel.setBackground(theme.getBackgroundColor());
|
||||
@ -335,7 +337,7 @@ public class LoginDialog extends JDialog {
|
||||
/**
|
||||
* Shuts the system down properly if the login was aborted.
|
||||
*
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
private void abortLogin() {
|
||||
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.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
@ -17,141 +19,90 @@ import javax.swing.*;
|
||||
*
|
||||
* @param <E> the type of object displayed in this list
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class ComponentList<E> extends JPanel {
|
||||
|
||||
private ComponentListModel<E> model;
|
||||
private ComponentListCellRenderer<E> renderer;
|
||||
|
||||
private int currentSelection = -1;
|
||||
private Model<E> model;
|
||||
private Renderer<E> renderer;
|
||||
private SelectionHandler<E> selectionHandler;
|
||||
private SelectionMode selectionMode = SelectionMode.NONE;
|
||||
private Set<Integer> selection = new HashSet<>();
|
||||
|
||||
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
|
||||
* the {@link ComponentListModel}
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public ComponentList(ComponentListCellRenderer<E> renderer) {
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
this.renderer = renderer;
|
||||
public static enum SelectionMode {
|
||||
/**
|
||||
* 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}.
|
||||
*
|
||||
* @param model the list model providing the list elements to render
|
||||
* @param renderer the list cell renderer used to display elements provided by
|
||||
* the {@link ComponentListModel}
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public ComponentList(ComponentListModel<E> model, ComponentListCellRenderer<E> renderer) {
|
||||
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();
|
||||
}
|
||||
public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); }
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
removeAll();
|
||||
if (model != null) model.forEach(this::add);
|
||||
revalidate();
|
||||
if (model != null) {
|
||||
removeAll();
|
||||
model.forEach(this::addElement);
|
||||
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
|
||||
* listener will be added
|
||||
* @return a mouse listener calling the
|
||||
* {@link ComponentList#componentSelected(int)} method with the
|
||||
* component's index when a left click is performed by the user
|
||||
* @since Envoy v0.1-beta
|
||||
*/
|
||||
private MouseListener getSelectionListener(int componentIndex) {
|
||||
return new MouseAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called when a list component has been clicked on by the user. Any
|
||||
* previous selections are then removed and the selected component gets
|
||||
* redrawn.<br>
|
||||
* <br>
|
||||
* If the currently selected component gets selected again, the selection is
|
||||
* removed.
|
||||
* Selects a list element by index. If the element is already selected, it is
|
||||
* removed from the selection.
|
||||
*
|
||||
* @param index the index of the selected component
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
private void componentSelected(int index) {
|
||||
if (index == currentSelection) {
|
||||
public void selectElement(int index) {
|
||||
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 {
|
||||
|
||||
// Remove old selection
|
||||
if (currentSelection >= 0) update(currentSelection, false);
|
||||
// Remove old selection if single selection is enabled
|
||||
if (selectionMode == SelectionMode.SINGLE) clearSelection();
|
||||
|
||||
// Assign new selection
|
||||
currentSelection = index;
|
||||
// Select item
|
||||
if (selectionMode != SelectionMode.NONE) {
|
||||
|
||||
// Update current selection
|
||||
update(currentSelection, true);
|
||||
// Assign new selection
|
||||
selection.add(index);
|
||||
|
||||
// Update element
|
||||
if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* @param isSelected the selection state passed to the {@link ListCellRenderer}
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
private void update(int index, boolean isSelected) {
|
||||
remove(index);
|
||||
add(model.get(index), index, isSelected);
|
||||
public void clearSelection() {
|
||||
if (selectionHandler != null) selection.forEach(i -> selectionHandler.selectionChanged(model.get(i), getComponent(i), false));
|
||||
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>
|
||||
* <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>
|
||||
*
|
||||
* @param <E> the type of object displayed in this list
|
||||
* @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<>();
|
||||
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
|
||||
@ -30,11 +30,11 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable {
|
||||
* @param e the element to add
|
||||
* @return {@code true}
|
||||
* @see java.util.List#add(java.lang.Object)
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public boolean add(E e) {
|
||||
if (componentList != null) {
|
||||
componentList.add(e);
|
||||
componentList.addElement(e);
|
||||
componentList.revalidate();
|
||||
}
|
||||
return elements.add(e);
|
||||
@ -45,7 +45,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable {
|
||||
* {@link ComponentList}.
|
||||
*
|
||||
* @see java.util.List#clear()
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public void 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
|
||||
* @return the element located at the index
|
||||
* @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); }
|
||||
|
||||
@ -67,7 +67,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable {
|
||||
* @param index the index of the element to remove
|
||||
* @return the removed element
|
||||
* @see java.util.List#remove(int)
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public E remove(int 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
|
||||
* @see java.util.List#size()
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
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
|
||||
* @see java.util.List#iterator()
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
@ -111,10 +111,10 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable {
|
||||
* synchronization.
|
||||
*
|
||||
* @param componentList the component list to set
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
void setComponentList(ComponentList<E> 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>
|
||||
* <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>
|
||||
*
|
||||
* @param <E> the type of object displayed in this list
|
||||
* @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.
|
||||
@ -24,7 +25,7 @@ public interface ComponentListCellRenderer<E> {
|
||||
* @param isSelected {@code true} if the user has selected the list cell in
|
||||
* which the list element is rendered
|
||||
* @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 Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.3-alpha
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
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.Dimension;
|
||||
@ -9,42 +9,40 @@ import javax.swing.*;
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.event.SendEvent;
|
||||
import envoy.client.ui.list.ComponentList;
|
||||
import envoy.client.ui.list.ComponentListCellRenderer;
|
||||
import envoy.client.ui.primary.PrimaryButton;
|
||||
import envoy.data.User;
|
||||
import envoy.event.ContactOperationEvent;
|
||||
import envoy.event.EventBus;
|
||||
|
||||
/**
|
||||
* Defines how a contact is displayed.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>ContactsSearchRenderer.java</strong><br>
|
||||
* Created: <strong>08.02.2020</strong><br>
|
||||
* Project: <strong>envoy-client</strong>
|
||||
* File: <strong>ContactSearchComponent.java</strong>
|
||||
* Created: <strong>21.03.2020</strong>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @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
|
||||
public JComponent getListCellComponent(ComponentList<? extends User> list, User user, boolean isSelected) {
|
||||
final JPanel panel = new JPanel();
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
||||
if (isSelected) {
|
||||
panel.setBackground(Color.DARK_GRAY);
|
||||
panel.setForeground(Color.RED);
|
||||
} else {
|
||||
panel.setBackground(list.getBackground());
|
||||
panel.setForeground(list.getForeground());
|
||||
}
|
||||
private static final long serialVersionUID = 3166795412575239455L;
|
||||
|
||||
/**
|
||||
* @param list the {@link ComponentList} that is used to display search results
|
||||
* @param user the {@link User} that appears as a search result
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
public ContactSearchComponent(ComponentList<? extends User> list, User user) {
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
|
||||
setBackground(list.getBackground());
|
||||
setForeground(list.getForeground());
|
||||
|
||||
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.setAlignmentY(Component.CENTER_ALIGNMENT);
|
||||
display.setFont(new Font("Arial", Font.PLAIN, 16));
|
||||
panel.add(display);
|
||||
add(display);
|
||||
|
||||
PrimaryButton add = new PrimaryButton("+");
|
||||
add.setFont(new Font("Arial", Font.PLAIN, 19));
|
||||
@ -61,17 +59,15 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer<User> {
|
||||
EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent));
|
||||
});
|
||||
|
||||
panel.add(add);
|
||||
add(add);
|
||||
|
||||
// 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
|
||||
Dimension size = new Dimension(435, 50);
|
||||
panel.setMaximumSize(size);
|
||||
panel.setMinimumSize(size);
|
||||
panel.setPreferredSize(size);
|
||||
|
||||
return panel;
|
||||
setMaximumSize(size);
|
||||
setMinimumSize(size);
|
||||
setPreferredSize(size);
|
||||
}
|
||||
}
|
||||
}
|
@ -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 Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.ui;
|
||||
|
@ -1,63 +1,63 @@
|
||||
package envoy.client.ui;
|
||||
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
/**
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>PrimaryButton.javaEvent.java</strong><br>
|
||||
* Created: <strong>07.12.2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
*/
|
||||
public class PrimaryButton extends JButton {
|
||||
|
||||
private static final long serialVersionUID = 3662266120667728364L;
|
||||
|
||||
private int arcSize;
|
||||
|
||||
/**
|
||||
* Creates a primary button
|
||||
*
|
||||
* @param title the title of the button
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public PrimaryButton(String title) { this(title, 6); }
|
||||
|
||||
/**
|
||||
* Creates a primary button
|
||||
*
|
||||
* @param title the title of the button
|
||||
* @param arcSize the size of the arc used to draw the round button edges
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public PrimaryButton(String title, int arcSize) {
|
||||
super(title);
|
||||
setBorderPainted(false);
|
||||
setFocusPainted(false);
|
||||
setContentAreaFilled(false);
|
||||
this.arcSize = arcSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
g.setColor(getBackground());
|
||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize);
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the arcSize
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public int getArcSize() { return arcSize; }
|
||||
|
||||
/**
|
||||
* @param arcSize the arcSize to set
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public void setArcSize(int arcSize) { this.arcSize = arcSize; }
|
||||
}
|
||||
package envoy.client.ui.primary;
|
||||
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
/**
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>PrimaryButton.javaEvent.java</strong><br>
|
||||
* Created: <strong>07.12.2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class PrimaryButton extends JButton {
|
||||
|
||||
private static final long serialVersionUID = 3662266120667728364L;
|
||||
|
||||
private int arcSize;
|
||||
|
||||
/**
|
||||
* Creates a primary button
|
||||
*
|
||||
* @param title the title of the button
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public PrimaryButton(String title) { this(title, 6); }
|
||||
|
||||
/**
|
||||
* Creates a primary button
|
||||
*
|
||||
* @param title the title of the button
|
||||
* @param arcSize the size of the arc used to draw the round button edges
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public PrimaryButton(String title, int arcSize) {
|
||||
super(title);
|
||||
setBorderPainted(false);
|
||||
setFocusPainted(false);
|
||||
setContentAreaFilled(false);
|
||||
this.arcSize = arcSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
g.setColor(getBackground());
|
||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), arcSize, arcSize);
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the arcSize
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public int getArcSize() { return arcSize; }
|
||||
|
||||
/**
|
||||
* @param arcSize the arcSize to set
|
||||
* @since Envoy 0.2-alpha
|
||||
*/
|
||||
public void setArcSize(int arcSize) { this.arcSize = arcSize; }
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
package envoy.client.ui;
|
||||
package envoy.client.ui.primary;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.*;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
@ -13,6 +8,7 @@ import javax.swing.JScrollBar;
|
||||
import javax.swing.plaf.basic.BasicScrollBarUI;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.ui.Theme;
|
||||
|
||||
/**
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
@ -20,7 +16,7 @@ import envoy.client.data.Settings;
|
||||
* Created: <strong>14.12.2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class PrimaryScrollBar extends BasicScrollBarUI {
|
||||
|
||||
@ -97,11 +93,11 @@ public class PrimaryScrollBar extends BasicScrollBarUI {
|
||||
g2.setPaint(color);
|
||||
if (isVertical) {
|
||||
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);
|
||||
} else {
|
||||
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.dispose();
|
@ -1,7 +1,9 @@
|
||||
package envoy.client.ui;
|
||||
package envoy.client.ui.primary;
|
||||
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import envoy.client.ui.Theme;
|
||||
|
||||
/**
|
||||
* Project: <strong>envoy-client</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
|
||||
*
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public PrimaryScrollPane() { setBorder(null); }
|
||||
|
||||
@ -28,7 +30,7 @@ public class PrimaryScrollPane extends JScrollPane {
|
||||
* Styles the vertical and horizontal scroll bars.
|
||||
*
|
||||
* @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) {
|
||||
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>
|
||||
* are added. (Besides see first point)
|
||||
*
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public void autoscroll() {
|
||||
// Automatic scrolling to the bottom
|
||||
@ -77,7 +79,7 @@ public class PrimaryScrollPane extends JScrollPane {
|
||||
* triggering it to automatically scroll down.
|
||||
*
|
||||
* @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; }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package envoy.client.ui;
|
||||
package envoy.client.ui.primary;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
@ -12,7 +12,7 @@ import javax.swing.border.EmptyBorder;
|
||||
* Created: <strong>07.12.2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class PrimaryTextArea extends JTextArea {
|
||||
|
@ -1,57 +1,58 @@
|
||||
package envoy.client.ui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.data.SettingsItem;
|
||||
|
||||
/**
|
||||
* This component can be used to toggle between two options. This will change
|
||||
* the state of a {@code boolean} {@link SettingsItem}.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>PrimaryToggleSwitch.java</strong><br>
|
||||
* Created: <strong>21 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public class PrimaryToggleSwitch extends JButton {
|
||||
|
||||
private boolean state;
|
||||
|
||||
private static final long serialVersionUID = -721155303106833184L;
|
||||
|
||||
/**
|
||||
* Initializes a {@link PrimaryToggleSwitch}.
|
||||
*
|
||||
* @param settingsItem the {@link SettingsItem} that is controlled by this
|
||||
* {@link PrimaryToggleSwitch}
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) {
|
||||
setPreferredSize(new Dimension(50, 25));
|
||||
setMinimumSize(new Dimension(50, 25));
|
||||
setMaximumSize(new Dimension(50, 25));
|
||||
|
||||
setBorderPainted(false);
|
||||
setFocusPainted(false);
|
||||
setContentAreaFilled(false);
|
||||
|
||||
state = settingsItem.get();
|
||||
addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY);
|
||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25);
|
||||
|
||||
g.setColor(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getInteractableBackgroundColor());
|
||||
g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25);
|
||||
}
|
||||
}
|
||||
package envoy.client.ui.primary;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.data.SettingsItem;
|
||||
import envoy.client.ui.Color;
|
||||
|
||||
/**
|
||||
* This component can be used to toggle between two options. This will change
|
||||
* the state of a {@code boolean} {@link SettingsItem}.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>PrimaryToggleSwitch.java</strong><br>
|
||||
* Created: <strong>21 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class PrimaryToggleSwitch extends JButton {
|
||||
|
||||
private boolean state;
|
||||
|
||||
private static final long serialVersionUID = -721155303106833184L;
|
||||
|
||||
/**
|
||||
* Initializes a {@link PrimaryToggleSwitch}.
|
||||
*
|
||||
* @param settingsItem the {@link SettingsItem} that is controlled by this
|
||||
* {@link PrimaryToggleSwitch}
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public PrimaryToggleSwitch(SettingsItem<Boolean> settingsItem) {
|
||||
setPreferredSize(new Dimension(50, 25));
|
||||
setMinimumSize(new Dimension(50, 25));
|
||||
setMaximumSize(new Dimension(50, 25));
|
||||
|
||||
setBorderPainted(false);
|
||||
setFocusPainted(false);
|
||||
setContentAreaFilled(false);
|
||||
|
||||
state = settingsItem.get();
|
||||
addActionListener((evt) -> { state = !state; settingsItem.set(state); revalidate(); repaint(); });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
g.setColor(state ? Color.GREEN : Color.LIGHT_GRAY);
|
||||
g.fillRoundRect(0, 0, getWidth(), getHeight(), 25, 25);
|
||||
|
||||
g.setColor(Settings.getInstance().getCurrentTheme().getInteractableBackgroundColor());
|
||||
g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25);
|
||||
}
|
||||
}
|
17
src/main/java/envoy/client/ui/primary/package-info.java
Normal file
17
src/main/java/envoy/client/ui/primary/package-info.java
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* This package defines all "primary" components that were defined specifically
|
||||
* for the visual improvement of Envoy. However, they can still be used in
|
||||
* general for other projects.<br>
|
||||
* Primary elements are supposed to provide the main functionality of a UI
|
||||
* component.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>package-info.java</strong><br>
|
||||
* Created: <strong>14 Mar 2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.ui.primary;
|
@ -1,4 +1,4 @@
|
||||
package envoy.client.ui;
|
||||
package envoy.client.ui.renderer;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
@ -20,7 +20,7 @@ import envoy.data.User.UserStatus;
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
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
|
||||
String textColor = null;
|
||||
textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex();
|
||||
textColor = Settings.getInstance().getCurrentTheme().getUserNameColor().toHex();
|
||||
switch (status) {
|
||||
case ONLINE:
|
||||
setText(String
|
||||
@ -59,4 +59,4 @@ public class UserListRenderer extends JLabel implements ListCellRenderer<User> {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
14
src/main/java/envoy/client/ui/renderer/package-info.java
Normal file
14
src/main/java/envoy/client/ui/renderer/package-info.java
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* This package contains all Envoy-specific renderers for lists that store an
|
||||
* arbitrary number of JComponents.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>package-info.java</strong><br>
|
||||
* Created: <strong>14 Mar 2020</strong><br>
|
||||
*
|
||||
* @author Leon Hofmeister
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
package envoy.client.ui.renderer;
|
@ -1,93 +1,89 @@
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextPane;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.data.SettingsItem;
|
||||
import envoy.client.ui.Theme;
|
||||
import envoy.util.EnvoyLog;
|
||||
|
||||
/**
|
||||
* Displays GUI components that allow general settings regarding the client.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>GeneralSettingsPanel.java</strong><br>
|
||||
* Created: <strong>21 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public class GeneralSettingsPanel extends SettingsPanel {
|
||||
|
||||
private Theme theme;
|
||||
|
||||
private static final String[] items = { "onCloseMode", "enterToSend" };
|
||||
private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class);
|
||||
private static final long serialVersionUID = -7470848775130754239L;
|
||||
|
||||
/**
|
||||
* This is the constructor for the General class. Here the user can set general
|
||||
* settings for the client.
|
||||
*
|
||||
* @param parent the {@link SettingsScreen} as a part of which this
|
||||
* {@link SettingsPanel} is displayed
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public GeneralSettingsPanel(SettingsScreen parent) {
|
||||
super(parent);
|
||||
theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
||||
|
||||
setBackground(theme.getCellColor());
|
||||
|
||||
GridBagLayout gbl_general = new GridBagLayout();
|
||||
gbl_general.columnWidths = new int[] { 1, 1 };
|
||||
gbl_general.rowHeights = new int[] { 1, 1, 1 };
|
||||
gbl_general.columnWeights = new double[] { 1.0, 0.1 };
|
||||
gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 };
|
||||
|
||||
setLayout(gbl_general);
|
||||
|
||||
for (int i = 0; i < items.length; i++)
|
||||
try {
|
||||
createSettingElement(i, Settings.getInstance().getItems().get(items[i]));
|
||||
} catch (SecurityException | ReflectiveOperationException e) {
|
||||
logger.log(Level.WARNING, "Could not create settings item", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createSettingElement(int gridy, SettingsItem<?> settingsItem) throws SecurityException, ReflectiveOperationException {
|
||||
JTextPane descriptionText = new JTextPane();
|
||||
|
||||
JComponent settingComponent = settingsItem.getComponent();
|
||||
|
||||
GridBagConstraints gbc_toggleSwitch = new GridBagConstraints();
|
||||
gbc_toggleSwitch.gridx = 1;
|
||||
gbc_toggleSwitch.gridy = gridy;
|
||||
|
||||
add(settingComponent, gbc_toggleSwitch);
|
||||
|
||||
descriptionText.setText(settingsItem.getDescription());
|
||||
descriptionText.setBackground(theme.getBackgroundColor());
|
||||
descriptionText.setForeground(theme.getBackgroundColor().invert());
|
||||
descriptionText.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_descriptionText = new GridBagConstraints();
|
||||
gbc_descriptionText.fill = GridBagConstraints.BOTH;
|
||||
gbc_descriptionText.gridx = 0;
|
||||
gbc_descriptionText.gridy = gridy;
|
||||
gbc_descriptionText.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
add(descriptionText, gbc_descriptionText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionListener getOkButtonAction() { return evt -> {}; }
|
||||
}
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextPane;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.data.SettingsItem;
|
||||
import envoy.client.ui.Theme;
|
||||
import envoy.util.EnvoyLog;
|
||||
|
||||
/**
|
||||
* Displays GUI components that allow general settings regarding the client.<br>
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>GeneralSettingsPanel.java</strong><br>
|
||||
* Created: <strong>21 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class GeneralSettingsPanel extends SettingsPanel {
|
||||
|
||||
private Theme theme;
|
||||
|
||||
private static final String[] items = { "onCloseMode", "enterToSend" };
|
||||
private static final Logger logger = EnvoyLog.getLogger(GeneralSettingsPanel.class);
|
||||
private static final long serialVersionUID = -7470848775130754239L;
|
||||
|
||||
/**
|
||||
* This is the constructor for the General class. Here the user can set general
|
||||
* settings for the client.
|
||||
*
|
||||
* @param parent the {@link SettingsScreen} as a part of which this
|
||||
* {@link SettingsPanel} is displayed
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public GeneralSettingsPanel(SettingsScreen parent) {
|
||||
super(parent);
|
||||
theme = Settings.getInstance().getCurrentTheme();
|
||||
|
||||
setBackground(theme.getCellColor());
|
||||
|
||||
GridBagLayout gbl_general = new GridBagLayout();
|
||||
gbl_general.columnWidths = new int[] { 1, 1 };
|
||||
gbl_general.rowHeights = new int[] { 1, 1, 1 };
|
||||
gbl_general.columnWeights = new double[] { 1.0, 0.1 };
|
||||
gbl_general.rowWeights = new double[] { 0.02, 0.02, 1.0 };
|
||||
|
||||
setLayout(gbl_general);
|
||||
|
||||
for (int i = 0; i < items.length; i++)
|
||||
try {
|
||||
createSettingElement(i, Settings.getInstance().getItems().get(items[i]));
|
||||
} catch (SecurityException | ReflectiveOperationException e) {
|
||||
logger.log(Level.WARNING, "Could not create settings item", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createSettingElement(int gridy, SettingsItem<?> settingsItem) throws SecurityException, ReflectiveOperationException {
|
||||
JTextPane descriptionText = new JTextPane();
|
||||
|
||||
JComponent settingComponent = settingsItem.getComponent();
|
||||
|
||||
GridBagConstraints gbc_toggleSwitch = new GridBagConstraints();
|
||||
gbc_toggleSwitch.gridx = 1;
|
||||
gbc_toggleSwitch.gridy = gridy;
|
||||
|
||||
add(settingComponent, gbc_toggleSwitch);
|
||||
|
||||
descriptionText.setText(settingsItem.getDescription());
|
||||
descriptionText.setBackground(theme.getBackgroundColor());
|
||||
descriptionText.setForeground(theme.getBackgroundColor().invert());
|
||||
descriptionText.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_descriptionText = new GridBagConstraints();
|
||||
gbc_descriptionText.fill = GridBagConstraints.BOTH;
|
||||
gbc_descriptionText.gridx = 0;
|
||||
gbc_descriptionText.gridy = gridy;
|
||||
gbc_descriptionText.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
add(descriptionText, gbc_descriptionText);
|
||||
}
|
||||
}
|
||||
|
@ -1,226 +1,228 @@
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextPane;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
import envoy.client.ui.PrimaryButton;
|
||||
import envoy.client.ui.PrimaryTextArea;
|
||||
import envoy.client.ui.Theme;
|
||||
|
||||
/**
|
||||
* Displays window where you can choose a name for the new {@link Theme}.
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>NewThemeScreen.java</strong><br>
|
||||
* Created: <strong>26 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public class NewThemeScreen extends JDialog {
|
||||
|
||||
private final JPanel standardPanel = new JPanel();
|
||||
private final JPanel secondaryPanel = new JPanel();
|
||||
private JTextPane text = new JTextPane();
|
||||
private PrimaryTextArea nameEnterTextArea = new PrimaryTextArea(4);
|
||||
private PrimaryButton confirmButton = new PrimaryButton("Confirm");
|
||||
|
||||
private JTextPane errorText = new JTextPane();
|
||||
private PrimaryButton otherName = new PrimaryButton("Other Name");
|
||||
private PrimaryButton overwrite = new PrimaryButton("Overwrite");
|
||||
|
||||
private final Consumer<String> newThemeAction, modifyThemeAction;
|
||||
|
||||
private static final long serialVersionUID = 2369985550946300976L;
|
||||
|
||||
/**
|
||||
* Creates a window, where you can choose a name for a new {@link Theme}. <br>
|
||||
* There are two versions of this Window. The first one is responsible for
|
||||
* 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 newThemeAction is executed when a new theme name is entered
|
||||
* @param modifyThemeAction is executed when an existing theme name is entered and confirmed
|
||||
* @since Envoy v0.3-alpha
|
||||
*/
|
||||
public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) {
|
||||
this.newThemeAction = newThemeAction;
|
||||
this.modifyThemeAction = modifyThemeAction;
|
||||
|
||||
setLocationRelativeTo(parent);
|
||||
setTitle("New Theme");
|
||||
setModal(true);
|
||||
|
||||
setDimensions(true);
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
|
||||
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
||||
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
standardPanel.setBackground(theme.getBackgroundColor());
|
||||
secondaryPanel.setBackground(theme.getBackgroundColor());
|
||||
loadStandardContent(theme);
|
||||
}
|
||||
|
||||
private void setDimensions(boolean isStandard) {
|
||||
Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
}
|
||||
|
||||
private void loadStandardContent(Theme theme) {
|
||||
getContentPane().removeAll();
|
||||
|
||||
// ContentPane
|
||||
GridBagLayout gbl_contentPanel = new GridBagLayout();
|
||||
|
||||
gbl_contentPanel.columnWidths = new int[] { 1, 1 };
|
||||
gbl_contentPanel.rowHeights = new int[] { 1, 1, 1 };
|
||||
gbl_contentPanel.columnWeights = new double[] { 1, 1 };
|
||||
gbl_contentPanel.rowWeights = new double[] { 1, 1, 1 };
|
||||
|
||||
getContentPane().add(standardPanel, BorderLayout.CENTER);
|
||||
standardPanel.setLayout(gbl_contentPanel);
|
||||
|
||||
// text.setFont(new Font());
|
||||
text.setText("Please enter a name for the new Theme");
|
||||
text.setAlignmentX(CENTER_ALIGNMENT);
|
||||
text.setBackground(theme.getCellColor());
|
||||
text.setForeground(theme.getUserNameColor());
|
||||
text.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_text = new GridBagConstraints();
|
||||
gbc_text.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_text.gridx = 0;
|
||||
gbc_text.gridy = 0;
|
||||
gbc_text.gridwidth = 2;
|
||||
gbc_text.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(text, gbc_text);
|
||||
|
||||
nameEnterTextArea.setBackground(theme.getCellColor());
|
||||
nameEnterTextArea.setForeground(theme.getTypingMessageColor());
|
||||
nameEnterTextArea.setText("");
|
||||
nameEnterTextArea.setEditable(true);
|
||||
|
||||
GridBagConstraints gbc_input = new GridBagConstraints();
|
||||
gbc_input.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_input.gridx = 0;
|
||||
gbc_input.gridy = 1;
|
||||
gbc_input.gridwidth = 2;
|
||||
gbc_input.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(nameEnterTextArea, gbc_input);
|
||||
|
||||
confirmButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
confirmButton.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_confirmButton = new GridBagConstraints();
|
||||
gbc_confirmButton.gridx = 0;
|
||||
gbc_confirmButton.gridy = 2;
|
||||
gbc_confirmButton.gridwidth = 2;
|
||||
gbc_confirmButton.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(confirmButton, gbc_confirmButton);
|
||||
|
||||
confirmButton.addActionListener((evt) -> {
|
||||
if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) {
|
||||
// load other panel
|
||||
setDimensions(false);
|
||||
loadSecondaryPage(theme);
|
||||
} else {
|
||||
newThemeAction.accept(nameEnterTextArea.getText());
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadSecondaryPage(Theme theme) {
|
||||
// ContentPane
|
||||
getContentPane().removeAll();
|
||||
|
||||
GridBagLayout gbl_secondaryPanel = new GridBagLayout();
|
||||
|
||||
gbl_secondaryPanel.columnWidths = new int[] { 1, 1 };
|
||||
gbl_secondaryPanel.rowHeights = new int[] { 1, 1, 1, 1 };
|
||||
gbl_secondaryPanel.columnWeights = new double[] { 1, 1 };
|
||||
gbl_secondaryPanel.rowWeights = new double[] { 1, 1, 1, 1 };
|
||||
|
||||
getContentPane().add(secondaryPanel, BorderLayout.CENTER);
|
||||
secondaryPanel.setLayout(gbl_secondaryPanel);
|
||||
|
||||
// text.setFont(new Font());
|
||||
text.setText("Please enter a name for the new Theme");
|
||||
text.setAlignmentX(CENTER_ALIGNMENT);
|
||||
text.setBackground(theme.getCellColor());
|
||||
text.setForeground(theme.getUserNameColor());
|
||||
text.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_text = new GridBagConstraints();
|
||||
gbc_text.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_text.gridx = 0;
|
||||
gbc_text.gridy = 0;
|
||||
gbc_text.gridwidth = 2;
|
||||
gbc_text.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(text, gbc_text);
|
||||
|
||||
nameEnterTextArea.setBackground(theme.getCellColor());
|
||||
nameEnterTextArea.setForeground(theme.getTypingMessageColor());
|
||||
nameEnterTextArea.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_input = new GridBagConstraints();
|
||||
gbc_input.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_input.gridx = 0;
|
||||
gbc_input.gridy = 1;
|
||||
gbc_input.gridwidth = 2;
|
||||
gbc_input.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(nameEnterTextArea, gbc_input);
|
||||
|
||||
errorText.setText("The name does already exist. Choose another one or overwrite the old theme.");
|
||||
errorText.setAlignmentX(CENTER_ALIGNMENT);
|
||||
errorText.setBackground(theme.getCellColor());
|
||||
errorText.setForeground(theme.getUserNameColor());
|
||||
errorText.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_errorText = new GridBagConstraints();
|
||||
gbc_errorText.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_errorText.gridx = 0;
|
||||
gbc_errorText.gridy = 2;
|
||||
gbc_errorText.gridwidth = 2;
|
||||
gbc_errorText.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(errorText, gbc_errorText);
|
||||
|
||||
otherName.setBackground(theme.getInteractableBackgroundColor());
|
||||
otherName.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_otherName = new GridBagConstraints();
|
||||
gbc_otherName.gridx = 0;
|
||||
gbc_otherName.gridy = 3;
|
||||
gbc_otherName.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(otherName, gbc_otherName);
|
||||
|
||||
overwrite.setBackground(theme.getInteractableBackgroundColor());
|
||||
overwrite.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_overwrite = new GridBagConstraints();
|
||||
gbc_overwrite.gridx = 1;
|
||||
gbc_overwrite.gridy = 3;
|
||||
gbc_overwrite.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(overwrite, gbc_overwrite);
|
||||
|
||||
otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); });
|
||||
|
||||
overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); });
|
||||
}
|
||||
}
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextPane;
|
||||
|
||||
import envoy.client.data.Settings;
|
||||
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}.
|
||||
* <br>
|
||||
* Project: <strong>envoy-client</strong><br>
|
||||
* File: <strong>NewThemeScreen.java</strong><br>
|
||||
* Created: <strong>26 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public class NewThemeScreen extends JDialog {
|
||||
|
||||
private final JPanel standardPanel = new JPanel();
|
||||
private final JPanel secondaryPanel = new JPanel();
|
||||
private JTextPane text = new JTextPane();
|
||||
private PrimaryTextArea nameEnterTextArea = new PrimaryTextArea(4);
|
||||
private PrimaryButton confirmButton = new PrimaryButton("Confirm");
|
||||
|
||||
private JTextPane errorText = new JTextPane();
|
||||
private PrimaryButton otherName = new PrimaryButton("Other Name");
|
||||
private PrimaryButton overwrite = new PrimaryButton("Overwrite");
|
||||
|
||||
private final Consumer<String> newThemeAction, modifyThemeAction;
|
||||
|
||||
private static final long serialVersionUID = 2369985550946300976L;
|
||||
|
||||
/**
|
||||
* Creates a window, where you can choose a name for a new {@link Theme}. <br>
|
||||
* There are two versions of this Window. The first one is responsible for
|
||||
* 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 newThemeAction is executed when a new theme name is entered
|
||||
* @param modifyThemeAction is executed when an existing theme name is entered
|
||||
* and confirmed
|
||||
* @since Envoy Client v0.3-alpha
|
||||
*/
|
||||
public NewThemeScreen(SettingsScreen parent, Consumer<String> newThemeAction, Consumer<String> modifyThemeAction) {
|
||||
this.newThemeAction = newThemeAction;
|
||||
this.modifyThemeAction = modifyThemeAction;
|
||||
|
||||
setLocationRelativeTo(parent);
|
||||
setTitle("New Theme");
|
||||
setModal(true);
|
||||
|
||||
setDimensions(true);
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
|
||||
Theme theme = Settings.getInstance().getCurrentTheme();
|
||||
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
standardPanel.setBackground(theme.getBackgroundColor());
|
||||
secondaryPanel.setBackground(theme.getBackgroundColor());
|
||||
loadStandardContent(theme);
|
||||
}
|
||||
|
||||
private void setDimensions(boolean isStandard) {
|
||||
Dimension size = isStandard ? new Dimension(300, 170) : new Dimension(300, 225);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
}
|
||||
|
||||
private void loadStandardContent(Theme theme) {
|
||||
getContentPane().removeAll();
|
||||
|
||||
// ContentPane
|
||||
GridBagLayout gbl_contentPanel = new GridBagLayout();
|
||||
|
||||
gbl_contentPanel.columnWidths = new int[] { 1, 1 };
|
||||
gbl_contentPanel.rowHeights = new int[] { 1, 1, 1 };
|
||||
gbl_contentPanel.columnWeights = new double[] { 1, 1 };
|
||||
gbl_contentPanel.rowWeights = new double[] { 1, 1, 1 };
|
||||
|
||||
getContentPane().add(standardPanel, BorderLayout.CENTER);
|
||||
standardPanel.setLayout(gbl_contentPanel);
|
||||
|
||||
// text.setFont(new Font());
|
||||
text.setText("Please enter a name for the new Theme");
|
||||
text.setAlignmentX(CENTER_ALIGNMENT);
|
||||
text.setBackground(theme.getCellColor());
|
||||
text.setForeground(theme.getUserNameColor());
|
||||
text.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_text = new GridBagConstraints();
|
||||
gbc_text.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_text.gridx = 0;
|
||||
gbc_text.gridy = 0;
|
||||
gbc_text.gridwidth = 2;
|
||||
gbc_text.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(text, gbc_text);
|
||||
|
||||
nameEnterTextArea.setBackground(theme.getCellColor());
|
||||
nameEnterTextArea.setForeground(theme.getTypingMessageColor());
|
||||
nameEnterTextArea.setText("");
|
||||
nameEnterTextArea.setEditable(true);
|
||||
|
||||
GridBagConstraints gbc_input = new GridBagConstraints();
|
||||
gbc_input.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_input.gridx = 0;
|
||||
gbc_input.gridy = 1;
|
||||
gbc_input.gridwidth = 2;
|
||||
gbc_input.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(nameEnterTextArea, gbc_input);
|
||||
|
||||
confirmButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
confirmButton.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_confirmButton = new GridBagConstraints();
|
||||
gbc_confirmButton.gridx = 0;
|
||||
gbc_confirmButton.gridy = 2;
|
||||
gbc_confirmButton.gridwidth = 2;
|
||||
gbc_confirmButton.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
standardPanel.add(confirmButton, gbc_confirmButton);
|
||||
|
||||
confirmButton.addActionListener((evt) -> {
|
||||
if (!nameEnterTextArea.getText().isEmpty()) if (Settings.getInstance().getThemes().containsKey(nameEnterTextArea.getText())) {
|
||||
// load other panel
|
||||
setDimensions(false);
|
||||
loadSecondaryPage(theme);
|
||||
} else {
|
||||
newThemeAction.accept(nameEnterTextArea.getText());
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadSecondaryPage(Theme theme) {
|
||||
// ContentPane
|
||||
getContentPane().removeAll();
|
||||
|
||||
GridBagLayout gbl_secondaryPanel = new GridBagLayout();
|
||||
|
||||
gbl_secondaryPanel.columnWidths = new int[] { 1, 1 };
|
||||
gbl_secondaryPanel.rowHeights = new int[] { 1, 1, 1, 1 };
|
||||
gbl_secondaryPanel.columnWeights = new double[] { 1, 1 };
|
||||
gbl_secondaryPanel.rowWeights = new double[] { 1, 1, 1, 1 };
|
||||
|
||||
getContentPane().add(secondaryPanel, BorderLayout.CENTER);
|
||||
secondaryPanel.setLayout(gbl_secondaryPanel);
|
||||
|
||||
// text.setFont(new Font());
|
||||
text.setText("Please enter a name for the new Theme");
|
||||
text.setAlignmentX(CENTER_ALIGNMENT);
|
||||
text.setBackground(theme.getCellColor());
|
||||
text.setForeground(theme.getUserNameColor());
|
||||
text.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_text = new GridBagConstraints();
|
||||
gbc_text.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_text.gridx = 0;
|
||||
gbc_text.gridy = 0;
|
||||
gbc_text.gridwidth = 2;
|
||||
gbc_text.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(text, gbc_text);
|
||||
|
||||
nameEnterTextArea.setBackground(theme.getCellColor());
|
||||
nameEnterTextArea.setForeground(theme.getTypingMessageColor());
|
||||
nameEnterTextArea.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_input = new GridBagConstraints();
|
||||
gbc_input.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_input.gridx = 0;
|
||||
gbc_input.gridy = 1;
|
||||
gbc_input.gridwidth = 2;
|
||||
gbc_input.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(nameEnterTextArea, gbc_input);
|
||||
|
||||
errorText.setText("The name does already exist. Choose another one or overwrite the old theme.");
|
||||
errorText.setAlignmentX(CENTER_ALIGNMENT);
|
||||
errorText.setBackground(theme.getCellColor());
|
||||
errorText.setForeground(theme.getUserNameColor());
|
||||
errorText.setEditable(false);
|
||||
|
||||
GridBagConstraints gbc_errorText = new GridBagConstraints();
|
||||
gbc_errorText.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc_errorText.gridx = 0;
|
||||
gbc_errorText.gridy = 2;
|
||||
gbc_errorText.gridwidth = 2;
|
||||
gbc_errorText.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(errorText, gbc_errorText);
|
||||
|
||||
otherName.setBackground(theme.getInteractableBackgroundColor());
|
||||
otherName.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_otherName = new GridBagConstraints();
|
||||
gbc_otherName.gridx = 0;
|
||||
gbc_otherName.gridy = 3;
|
||||
gbc_otherName.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(otherName, gbc_otherName);
|
||||
|
||||
overwrite.setBackground(theme.getInteractableBackgroundColor());
|
||||
overwrite.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
GridBagConstraints gbc_overwrite = new GridBagConstraints();
|
||||
gbc_overwrite.gridx = 1;
|
||||
gbc_overwrite.gridy = 3;
|
||||
gbc_overwrite.insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
secondaryPanel.add(overwrite, gbc_overwrite);
|
||||
|
||||
otherName.addActionListener((evt) -> { setDimensions(true); loadStandardContent(theme); });
|
||||
|
||||
overwrite.addActionListener((evt) -> { modifyThemeAction.accept(nameEnterTextArea.getText()); dispose(); });
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
@ -14,7 +12,7 @@ import javax.swing.JPanel;
|
||||
* Created: <strong>20 Dec 2019</strong><br>
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public abstract class SettingsPanel extends JPanel {
|
||||
|
||||
@ -24,16 +22,9 @@ public abstract class SettingsPanel extends JPanel {
|
||||
|
||||
/**
|
||||
* Initializes a {@link SettingsPanel}.
|
||||
*
|
||||
*
|
||||
* @param parent the {@link SettingsScreen} as a part of which this
|
||||
* {@link SettingsPanel} is displayed
|
||||
*/
|
||||
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.event.ThemeChangeEvent;
|
||||
import envoy.client.ui.PrimaryButton;
|
||||
import envoy.client.ui.Theme;
|
||||
import envoy.client.ui.primary.PrimaryButton;
|
||||
import envoy.event.EventBus;
|
||||
import envoy.util.EnvoyLog;
|
||||
|
||||
@ -26,7 +26,7 @@ import envoy.util.EnvoyLog;
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class SettingsScreen extends JDialog {
|
||||
|
||||
@ -40,7 +40,6 @@ public class SettingsScreen extends JDialog {
|
||||
|
||||
// OK and cancel buttons
|
||||
private final JPanel buttonPane = new JPanel();
|
||||
private final PrimaryButton okButton = new PrimaryButton("Save");
|
||||
private final PrimaryButton cancelButton = new PrimaryButton("Cancel");
|
||||
|
||||
private final Insets insets = new Insets(5, 5, 5, 5);
|
||||
@ -52,7 +51,7 @@ public class SettingsScreen extends JDialog {
|
||||
/**
|
||||
* Initializes the settings screen.
|
||||
*
|
||||
* @since Envoy v0.1-alpha
|
||||
* @since Envoy Client v0.1-alpha
|
||||
*/
|
||||
public SettingsScreen() {
|
||||
// Initialize settings pages
|
||||
@ -138,25 +137,10 @@ public class SettingsScreen extends JDialog {
|
||||
|
||||
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
|
||||
applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
|
||||
applyTheme(Settings.getInstance().getCurrentTheme());
|
||||
|
||||
// Respond to theme changes
|
||||
EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get()));
|
||||
@ -179,14 +163,10 @@ public class SettingsScreen extends JDialog {
|
||||
cancelButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
cancelButton.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
// okButton
|
||||
okButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
okButton.setForeground(theme.getInteractableForegroundColor());
|
||||
|
||||
// options
|
||||
options.setSelectionForeground(theme.getUserNameColor());
|
||||
options.setSelectionBackground(theme.getSelectionColor());
|
||||
options.setForeground(theme.getUserNameColor());
|
||||
options.setBackground(theme.getCellColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
119
src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java
Normal file → Executable file
119
src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java
Normal file → Executable file
@ -1,9 +1,6 @@
|
||||
package envoy.client.ui.settings;
|
||||
|
||||
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.Logger;
|
||||
|
||||
@ -13,6 +10,7 @@ import envoy.client.data.Settings;
|
||||
import envoy.client.event.ThemeChangeEvent;
|
||||
import envoy.client.ui.Color;
|
||||
import envoy.client.ui.Theme;
|
||||
import envoy.client.ui.primary.PrimaryButton;
|
||||
import envoy.event.EventBus;
|
||||
import envoy.util.EnvoyLog;
|
||||
|
||||
@ -26,19 +24,19 @@ import envoy.util.EnvoyLog;
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
|
||||
private JPanel colorsPanel = new JPanel();
|
||||
|
||||
private DefaultComboBoxModel<String> themesModel = new DefaultComboBoxModel<>(
|
||||
Settings.getInstance().getThemes().keySet().toArray(new String[0]));
|
||||
private JComboBox<String> themes = new JComboBox<>(themesModel);
|
||||
private DefaultComboBoxModel<String> themesModel;
|
||||
private JComboBox<String> themes;
|
||||
private Theme temporaryTheme;
|
||||
private boolean themeChanged;
|
||||
private PrimaryButton createThemeButton = new PrimaryButton("Create Theme");
|
||||
|
||||
private final Insets insets = new Insets(5, 5, 5, 5);
|
||||
private boolean themeChanged;
|
||||
private final Insets insets = new Insets(5, 5, 5, 5);
|
||||
|
||||
private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class);
|
||||
private static final long serialVersionUID = -8697897390666456624L;
|
||||
@ -50,18 +48,28 @@ public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
*
|
||||
* @param parent the {@link SettingsScreen} as a part of which this
|
||||
* {@link SettingsPanel} is displayed
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
public ThemeCustomizationPanel(SettingsScreen 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();
|
||||
|
||||
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.rowWeights = new double[] { 0.01, 1.0 };
|
||||
gbl_themeLayout.rowWeights = new double[] { 0.01, 1.0, 0.01 };
|
||||
|
||||
setLayout(gbl_themeLayout);
|
||||
|
||||
@ -85,7 +93,7 @@ public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
|
||||
colorsPanel.setLayout(gbl_colorCustomizations);
|
||||
|
||||
Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
|
||||
Theme theme = Settings.getInstance().getCurrentTheme();
|
||||
buildCustomizeElements(theme);
|
||||
|
||||
GridBagConstraints gbc_colorsPanel = new GridBagConstraints();
|
||||
@ -97,20 +105,47 @@ public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
gbc_colorsPanel.insets = insets;
|
||||
|
||||
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());
|
||||
|
||||
// Apply theme upon selection
|
||||
themes.addItemListener(new ItemListener() {
|
||||
themes.addItemListener(e -> {
|
||||
String selectedValue = (String) themes.getSelectedItem();
|
||||
logger.log(Level.FINEST, "Selected theme: " + selectedValue);
|
||||
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
String selectedValue = (String) themes.getSelectedItem();
|
||||
logger.log(Level.FINEST, "Selected theme: " + selectedValue);
|
||||
|
||||
final Theme currentTheme = Settings.getInstance().getTheme(selectedValue);
|
||||
Settings.getInstance().setCurrentTheme(selectedValue);
|
||||
EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme));
|
||||
}
|
||||
final Theme currentTheme = Settings.getInstance().getTheme(selectedValue);
|
||||
Settings.getInstance().setCurrentTheme(selectedValue);
|
||||
EventBus.getInstance().dispatch(new ThemeChangeEvent(currentTheme));
|
||||
});
|
||||
|
||||
// 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) {
|
||||
// themeContent
|
||||
setForeground(theme.getUserNameColor());
|
||||
setBackground(theme.getCellColor());
|
||||
|
||||
// createThemeButton
|
||||
createThemeButton.setForeground(theme.getInteractableForegroundColor());
|
||||
createThemeButton.setBackground(theme.getInteractableBackgroundColor());
|
||||
|
||||
// themes
|
||||
themes.setBackground(theme.getInteractableBackgroundColor());
|
||||
themes.setForeground(theme.getInteractableForegroundColor());
|
||||
@ -181,7 +192,7 @@ public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2);
|
||||
buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3);
|
||||
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.getSelectionColor(), "Selection", "selectionColor", 7);
|
||||
buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8);
|
||||
@ -232,4 +243,4 @@ public class ThemeCustomizationPanel extends SettingsPanel {
|
||||
|
||||
colorsPanel.add(button, gbc_button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,6 @@
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.2-alpha
|
||||
* @since Envoy Client v0.2-alpha
|
||||
*/
|
||||
package envoy.client.ui.settings;
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @author Kai S. K. Engelbart
|
||||
* @author Leon Hofmeister
|
||||
* @author Maximilian Käfer
|
||||
* @since Envoy v0.1-beta
|
||||
* @since Envoy Client v0.1-beta
|
||||
*/
|
||||
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