diff --git a/src/main/java/envoy/client/data/Chat.java b/src/main/java/envoy/client/data/Chat.java index 30b6bc6..dadeaaa 100644 --- a/src/main/java/envoy/client/data/Chat.java +++ b/src/main/java/envoy/client/data/Chat.java @@ -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; @@ -28,7 +28,7 @@ public class Chat implements Serializable { private static final long serialVersionUID = -7751248474547242056L; private final User recipient; - private final ComponentListModel model = new ComponentListModel<>(); + private final Model model = new Model<>(); /** * Provides the list of messages that the recipient receives.
@@ -80,7 +80,7 @@ public class Chat implements Serializable { * @return all messages in the current chat * @since Envoy v0.1-alpha */ - public ComponentListModel getModel() { return model; } + public Model getModel() { return model; } /** * @return the recipient of a message diff --git a/src/main/java/envoy/client/data/Settings.java b/src/main/java/envoy/client/data/Settings.java index 89dea67..fd0170c 100644 --- a/src/main/java/envoy/client/data/Settings.java +++ b/src/main/java/envoy/client/data/Settings.java @@ -112,13 +112,19 @@ public class Settings { * @param theme the {@link Theme} to add * @since Envoy 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 */ - 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 v0.1-beta + */ + public Theme getCurrentTheme() { return getTheme(getCurrentThemeName()); } /** * Sets the name of the current {@link Theme}. diff --git a/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java b/src/main/java/envoy/client/ui/ContactSearchComponent.java similarity index 51% rename from src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java rename to src/main/java/envoy/client/ui/ContactSearchComponent.java index 60a0ef2..39ae50b 100644 --- a/src/main/java/envoy/client/ui/renderer/ContactsSearchRenderer.java +++ b/src/main/java/envoy/client/ui/ContactSearchComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui.renderer; +package envoy.client.ui; import java.awt.Component; import java.awt.Dimension; @@ -8,45 +8,36 @@ import javax.swing.*; import envoy.client.data.Settings; import envoy.client.event.SendEvent; -import envoy.client.ui.Color; 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.
- *
- * Project: envoy-client
- * File: ContactsSearchRenderer.java
- * Created: 08.02.2020
+ * Project: envoy-client + * File: ContactSearchComponent.java + * Created: 21.03.2020 * - * @author Maximilian Käfer * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha + * @since Envoy v0.1-beta */ -public class ContactsSearchRenderer implements ComponentListCellRenderer { +public class ContactSearchComponent extends JComponent { - @Override - public JComponent getListCellComponent(ComponentList 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; + + public ContactSearchComponent(ComponentList 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().getMessageTextColor()); 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)); @@ -63,17 +54,15 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer { 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); } } diff --git a/src/main/java/envoy/client/ui/ContextMenu.java b/src/main/java/envoy/client/ui/ContextMenu.java index 1ba5d14..ff19ac8 100644 --- a/src/main/java/envoy/client/ui/ContextMenu.java +++ b/src/main/java/envoy/client/ui/ContextMenu.java @@ -50,7 +50,6 @@ public class ContextMenu extends JPopupMenu { private ButtonGroup radioButtonGroup = new ButtonGroup(); private boolean built = false; - private boolean visible = false; /** * @param parent the component which will call this @@ -110,8 +109,10 @@ public class ContextMenu extends JPopupMenu { if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); add(item); }); - getInvoker().addMouseListener(getShowingListener()); - built = true; + if (getInvoker() != null) { + getInvoker().addMouseListener(getShowingListener()); + built = true; + } return this; } @@ -138,10 +139,8 @@ public class ContextMenu extends JPopupMenu { if (!built) build(); if (e.isPopupTrigger()) { // hides the menu if already visible - visible = !visible; - if (visible) show(e.getComponent(), e.getX(), e.getY()); + if (!isVisible()) show(e.getComponent(), e.getX(), e.getY()); else setVisible(false); - } } }; diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageComponent.java similarity index 56% rename from src/main/java/envoy/client/ui/renderer/MessageListRenderer.java rename to src/main/java/envoy/client/ui/MessageComponent.java index 27a5a0d..a4a83a0 100644 --- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageComponent.java @@ -1,4 +1,4 @@ -package envoy.client.ui.renderer; +package envoy.client.ui; import java.awt.*; import java.io.IOException; @@ -8,60 +8,41 @@ import java.util.EnumMap; import javax.swing.*; import envoy.client.data.Settings; -import envoy.client.ui.Color; -import envoy.client.ui.IconUtil; import envoy.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListCellRenderer; import envoy.data.Message; import envoy.data.Message.MessageStatus; /** - * Defines how a message is displayed.
- *
- * Project: envoy-client
- * File: MessageListRenderer.java
- * Created: 19 Oct 2019
+ * Project: envoy-client + * File: MessageComponent.java + * Created: 21.03.2020 * * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @author Leon Hofmeister - * @since Envoy v0.1-alpha + * @since Envoy v0.1-beta */ -public class MessageListRenderer implements ComponentListCellRenderer { +public class MessageComponent extends JPanel { + + private static final long serialVersionUID = 103920706139926996L; private static EnumMap statusIcons; private static ImageIcon forwardIcon; static { try { - statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); + statusIcons = IconUtil.loadByEnum(MessageStatus.class, 16); forwardIcon = IconUtil.load("/icons/forward.png", 16); } catch (IOException e) { e.printStackTrace(); } } - private final long senderId; + public MessageComponent(ComponentList list, Message message, long senderId) { + this(list.getMaximumSize().width, message, senderId); + } - /** - * Initializes a message list renderer. Messages with the given sender ID will - * be aligned on the right side, while all other messages will be aligned on - * the left side - * - * @param senderId the sender ID of the messages to align on the right side - * @since Envoy v0.1-beta - */ - public MessageListRenderer(long senderId) { this.senderId = senderId; } - - // TODO: Handle message attachments - - @Override - public JPanel getListCellComponent(ComponentList list, Message message, boolean isSelected) { - final var theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - // Panel - final var panel = new JPanel(); - final int padding = (int) (list.getWidth() * 0.35); + public MessageComponent(int width, Message message, long senderId) { + 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 }; @@ -69,8 +50,8 @@ public class MessageListRenderer implements ComponentListCellRenderer { gbl_panel.columnWeights = new double[] { 1, 1 }; gbl_panel.rowWeights = new double[] { 1, 1 }; - panel.setLayout(gbl_panel); - panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); + 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())); @@ -83,7 +64,7 @@ public class MessageListRenderer implements ComponentListCellRenderer { gbc_dateLabel.fill = GridBagConstraints.BOTH; gbc_dateLabel.gridx = 0; gbc_dateLabel.gridy = 0; - panel.add(dateLabel, gbc_dateLabel); + add(dateLabel, gbc_dateLabel); // Message area - The JTextArea that displays the text content of a message. var messageTextArea = new JTextArea(message.getText()); @@ -95,13 +76,13 @@ public class MessageListRenderer implements ComponentListCellRenderer { messageTextArea.setEditable(false); var font = new Font("Arial", Font.PLAIN, 14); messageTextArea.setFont(font); - messageTextArea.setSize(list.getMaximumSize().width - padding - 16, 10); + messageTextArea.setSize(width - padding - 16, 10); var gbc_messageTextArea = new GridBagConstraints(); gbc_messageTextArea.fill = GridBagConstraints.HORIZONTAL; gbc_messageTextArea.gridx = 0; gbc_messageTextArea.gridy = 1; - panel.add(messageTextArea, gbc_messageTextArea); + add(messageTextArea, gbc_messageTextArea); // Status Label - displays the status of the message var statusLabel = new JLabel(statusIcons.get(message.getStatus())); @@ -109,32 +90,31 @@ public class MessageListRenderer implements ComponentListCellRenderer { var gbc_statusLabel = new GridBagConstraints(); gbc_statusLabel.gridx = 1; gbc_statusLabel.gridy = 1; - panel.add(statusLabel, gbc_statusLabel); + add(statusLabel, gbc_statusLabel); // Forwarding if (message.isForwarded()) { var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER); - forwardLabel.setBackground(panel.getBackground()); + 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; - panel.add(forwardLabel, gbc_forwardLabel); + add(forwardLabel, gbc_forwardLabel); } // Define an etched border and some space to the messages below var ours = senderId == message.getSenderId(); - panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, ours ? padding : 0, 10, ours ? 0 : padding), + setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(0, ours ? padding : 10, 10, ours ? 0 : padding), BorderFactory.createEtchedBorder())); - var size = new Dimension(list.getMaximumSize().width - 50, panel.getPreferredSize().height); + var size = new Dimension(width - 50, getPreferredSize().height); - panel.setPreferredSize(size); - panel.setMinimumSize(size); - panel.setMaximumSize(size); - - return panel; + setPreferredSize(size); + setMinimumSize(size); + setMaximumSize(size); } } diff --git a/src/main/java/envoy/client/ui/UserComponent.java b/src/main/java/envoy/client/ui/UserComponent.java new file mode 100644 index 0000000..7fd4392 --- /dev/null +++ b/src/main/java/envoy/client/ui/UserComponent.java @@ -0,0 +1,62 @@ +package envoy.client.ui; + +import java.awt.BorderLayout; +import java.awt.Dimension; + +import javax.swing.JComponent; +import javax.swing.JLabel; + +import envoy.client.data.Settings; +import envoy.client.ui.list.ComponentList; +import envoy.data.User; +import envoy.data.User.UserStatus; + +/** + * Project: envoy-client + * File: UserComponent.java + * Created: 21.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +public class UserComponent extends JComponent { + + private static final long serialVersionUID = 8450602172939729585L; + + public UserComponent(ComponentList list, 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); + } +} diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java index 7d883c2..41e9614 100644 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ b/src/main/java/envoy/client/ui/container/ChatWindow.java @@ -22,16 +22,13 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.event.ThemeChangeEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; -import envoy.client.ui.ContextMenu; -import envoy.client.ui.Theme; +import envoy.client.ui.*; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; -import envoy.client.ui.list.ComponentListModel; +import envoy.client.ui.list.Model; import envoy.client.ui.primary.PrimaryButton; import envoy.client.ui.primary.PrimaryScrollPane; import envoy.client.ui.primary.PrimaryTextArea; -import envoy.client.ui.renderer.ContactsSearchRenderer; -import envoy.client.ui.renderer.MessageListRenderer; import envoy.client.ui.renderer.UserListRenderer; import envoy.client.ui.settings.SettingsScreen; import envoy.data.Message; @@ -54,8 +51,7 @@ import envoy.util.EnvoyLog; 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 */ @@ -77,7 +73,6 @@ public class ChatWindow extends JFrame { private JTextPane textPane = new JTextPane(); private PrimaryButton postButton = new PrimaryButton("Post"); private PrimaryButton settingsButton = new PrimaryButton("Settings"); - @SuppressWarnings("unused") private JPopupMenu contextMenu; // Contacts Header @@ -86,13 +81,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 contactsModel = new ComponentListModel<>(); - private final ComponentList 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 contactsModel = new Model<>(); + private final ComponentList contactList = new ComponentList().setRenderer(ContactSearchComponent::new); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); @@ -125,16 +119,14 @@ public class ChatWindow extends JFrame { gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; contentPane.setLayout(gbl_contentPane); - messageList.setBorder(new EmptyBorder(space, space, space, space)); - messageList.setSelectionMode(SelectionMode.SINGLE); + // ContextMenu Map commands = new HashMap<>() { private static final long serialVersionUID = -2755235774946990126L; { put("forward selected message", - evt -> forwardMessageToMultipleUsers(messageList - .getSingleSelectedElement(), + evt -> forwardMessageToMultipleUsers(messageList.getSingleSelectedElement(), ContactsChooserDialog .showForwardingDialog("Forward selected message to", messageList.getSingleSelectedElement(), client))); put("copy", evt -> { @@ -151,6 +143,14 @@ public class ChatWindow extends JFrame { }; contextMenu = new ContextMenu(null, messageList, commands, null, null).build(); + 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.show(comp, 0, 0); + }); + scrollPane.setViewportView(messageList); scrollPane.addComponentListener(new ComponentAdapter() { @@ -396,11 +396,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(); @@ -645,7 +645,7 @@ public class ChatWindow extends JFrame { this.localDb = localDb; this.writeProxy = writeProxy; - messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); + messageList.setRenderer((list, message) -> new MessageComponent(list, message, client.getSender().getId())); // Load users and chats new Thread(() -> { diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java index 467d43f..8171b82 100644 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java @@ -14,11 +14,10 @@ import javax.swing.border.EmptyBorder; import envoy.client.data.Settings; import envoy.client.net.Client; import envoy.client.ui.Theme; +import envoy.client.ui.UserComponent; import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList.SelectionMode; -import envoy.client.ui.list.ComponentListModel; -import envoy.client.ui.renderer.MessageListRenderer; -import envoy.client.ui.renderer.UserComponentListRenderer; +import envoy.client.ui.list.Model; import envoy.data.Message; import envoy.data.User; @@ -36,11 +35,11 @@ public class ContactsChooserDialog extends JDialog { private static final long serialVersionUID = -5774558118579032256L; - private ComponentList contactList = new ComponentList<>(new UserComponentListRenderer()); + private ComponentList contactList = new ComponentList().setRenderer(UserComponent::new); private JButton okButton = new JButton("Ok"); private JButton cancelButton = new JButton("Cancel"); - private final Theme theme = Settings.getInstance().getTheme(Settings.getInstance().getCurrentTheme()); + private final Theme theme = Settings.getInstance().getCurrentTheme(); private final JPanel contentPanel = new JPanel(); @@ -67,16 +66,18 @@ public class ContactsChooserDialog extends JDialog { dialog.setTitle(title); dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); dialog.addCancelButtonActionListener(e -> dialog.dispose()); - dialog.getContentPanel() - .add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); + // dialog.getContentPanel() + // .add(new + // MessageListRenderer(client.getSender().getId()).getListCellComponent(null, + // message, false), BorderLayout.NORTH); List results = new ArrayList<>(); dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); - ComponentListModel contactListModel = dialog.getContactList().getModel(); + Model contactListModel = dialog.getContactList().getModel(); client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); dialog.setVisible(true); dialog.repaint(); dialog.revalidate(); - return results.size() > 0 ? results : null; + return results; } /** @@ -84,7 +85,8 @@ public class ContactsChooserDialog extends JDialog { */ private ContactsChooserDialog() { contactList.setSelectionMode(SelectionMode.MULTIPLE); - // setBounds(100, 100, 450, 300); + contactList + .setSelectionHandler((user, comp, isSelected) -> comp.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor())); setModal(true); getContentPane().setLayout(new BorderLayout()); setBackground(theme.getBackgroundColor()); @@ -121,6 +123,4 @@ public class ContactsChooserDialog extends JDialog { private void addOkButtonActionListener(ActionListener l) { okButton.addActionListener(l); } private void addCancelButtonActionListener(ActionListener l) { cancelButton.addActionListener(l); } - - private JPanel getContentPanel() { return contentPanel; } } diff --git a/src/main/java/envoy/client/ui/container/LoginDialog.java b/src/main/java/envoy/client/ui/container/LoginDialog.java index 51d9817..8780358 100644 --- a/src/main/java/envoy/client/ui/container/LoginDialog.java +++ b/src/main/java/envoy/client/ui/container/LoginDialog.java @@ -291,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()); diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java index 199946d..44d98de 100644 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ b/src/main/java/envoy/client/ui/list/ComponentList.java @@ -10,7 +10,7 @@ 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.
*
* Project: envoy-client
@@ -23,10 +23,11 @@ import javax.swing.*; */ public class ComponentList extends JPanel { - private ComponentListModel model; - private ComponentListCellRenderer renderer; - private SelectionMode selectionMode = SelectionMode.NONE; - private Set selection = new HashSet<>(); + private Model model; + private Renderer renderer; + private SelectionHandler selectionHandler; + private SelectionMode selectionMode = SelectionMode.NONE; + private Set selection = new HashSet<>(); private static final long serialVersionUID = 1759644503942876737L; @@ -53,64 +54,20 @@ public class ComponentList extends JPanel { } /** - * Initializes a default {@link ComponentList} without a model or a renderer. + * Creates an instance of {@link ComponentList}. * - * @since Envoy v0.1-beta + * @since Envoy v0.3-alpha */ public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } - /** - * Creates an instance of {@link ComponentList}. - * - * @param renderer the list cell renderer used to display elements provided by - * the {@link ComponentListModel} - * @since Envoy v0.3-alpha - */ - public ComponentList(ComponentListCellRenderer renderer) { - this(); - setRenderer(renderer); - } - - /** - * 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 - */ - public ComponentList(ComponentListModel model, ComponentListCellRenderer renderer) { - this(renderer); - 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 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(); - } - /** * 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 */ public void synchronizeModel() { - if (model != null && renderer != null) { + if (model != null) { removeAll(); model.forEach(this::addElement); revalidate(); @@ -125,10 +82,12 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-beta */ public void selectElement(int index) { + final JComponent element = getComponent(index); + if (selection.contains(index)) { // Remove selection of element at index - updateElement(index, false); + if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); selection.remove(index); } else { @@ -141,7 +100,7 @@ public class ComponentList extends JPanel { selection.add(index); // Update element - updateElement(index, true); + if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); } } @@ -155,49 +114,25 @@ public class ComponentList extends JPanel { * @since Envoy v0.1-alpha */ public void clearSelection() { - selection.forEach(i -> updateElement(i, false)); + 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 ComponentListCellRenderer}. + * {@link Renderer}. * * @param elem the element to add * @since Envoy v0.3-alpha */ - void addElement(E elem) { addElement(elem, getComponentCount(), false); } - - /** - * Adds an object to the list by rendering it with the current - * {@link ComponentListRenderer}. If the renderer is {@code null}, no action is - * performed. - * - * @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 addElement(E elem, int index, boolean isSelected) { + void addElement(E elem) { if (renderer != null) { - final JComponent component = renderer.getListCellComponent(this, elem, isSelected); - component.addMouseListener(getSelectionListener(index)); - add(component, index); + final JComponent component = renderer.getListCellComponent(this, elem); + component.addMouseListener(getSelectionListener(getComponentCount())); + add(component, getComponentCount()); } } - /** - * Replaces a list element with a newly rendered instance of its contents. - * - * @param index the index of the element to update - * @param isSelected the selection state passed to the {@link ListCellRenderer} - * @since Envoy v0.1-beta - */ - private void updateElement(int index, boolean isSelected) { - remove(index); - addElement(model.get(index), index, isSelected); - } - /** * @param componentIndex the index of the list component to which the mouse * listener will be added @@ -214,6 +149,9 @@ public class ComponentList extends JPanel { }; } + @Override + public JComponent getComponent(int n) { return (JComponent) super.getComponent(n); } + /** * @return a set of all selected indices * @since Envoy v0.1-beta @@ -248,19 +186,45 @@ public class ComponentList extends JPanel { * @return the model * @since Envoy v0.1-beta */ - public ComponentListModel getModel() { return model; } + public Model 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 v0.3-alpha + */ + public ComponentList setModel(Model 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 v0.1-beta */ - public ComponentListCellRenderer getRenderer() { return renderer; } + public Renderer getRenderer() { return renderer; } /** * @param renderer the renderer to set + * @return this component list * @since Envoy v0.1-beta */ - public void setRenderer(ComponentListCellRenderer renderer) { this.renderer = renderer; } + public ComponentList setRenderer(Renderer renderer) { + this.renderer = renderer; + return this; + } /** * @return the selection mode @@ -269,8 +233,28 @@ public class ComponentList extends JPanel { 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 v0.1-beta */ - public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } + public ComponentList setSelectionMode(SelectionMode selectionMode) { + this.selectionMode = selectionMode; + clearSelection(); + return this; + } + + /** + * @return the selection handler + * @since Envoy v0.1-beta + */ + public SelectionHandler getSelectionHandler() { return selectionHandler; } + + /** + * @param selectionHandler the selection handler to set + * @since Envoy v0.1-beta + */ + public void setSelectionHandler(SelectionHandler selectionHandler) { this.selectionHandler = selectionHandler; } } diff --git a/src/main/java/envoy/client/ui/list/ComponentListModel.java b/src/main/java/envoy/client/ui/list/Model.java similarity index 93% rename from src/main/java/envoy/client/ui/list/ComponentListModel.java rename to src/main/java/envoy/client/ui/list/Model.java index 05ef7d4..6dca5eb 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListModel.java +++ b/src/main/java/envoy/client/ui/list/Model.java @@ -9,19 +9,19 @@ import java.util.List; * Stores objects that will be displayed in a {@link ComponentList}.
*
* Project: envoy-client
- * File: ComponentListModel.java
+ * File: Model.java
* Created: 25.01.2020
* * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public final class ComponentListModel implements Iterable, Serializable { +public final class Model implements Iterable, Serializable { private List elements = new ArrayList<>(); transient private ComponentList componentList; - private static final long serialVersionUID = 4815005915255497331L; + private static final long serialVersionUID = 0L; /** * Adds an element to this model and notifies the associated diff --git a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java b/src/main/java/envoy/client/ui/list/Renderer.java similarity index 86% rename from src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java rename to src/main/java/envoy/client/ui/list/Renderer.java index a8bdda6..58e6ad9 100644 --- a/src/main/java/envoy/client/ui/list/ComponentListCellRenderer.java +++ b/src/main/java/envoy/client/ui/list/Renderer.java @@ -7,14 +7,15 @@ import javax.swing.JComponent; * that can be rendered.
*
* Project: envoy-client
- * File: ComponentListCellRenderer.java
+ * File: Renderer.java
* Created: 25.01.2020
* * @param the type of object displayed in this list * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ -public interface ComponentListCellRenderer { +@FunctionalInterface +public interface Renderer { /** * Provides a Swing component representing a list element. @@ -26,5 +27,5 @@ public interface ComponentListCellRenderer { * @return the component representing the list element * @since Envoy v0.3-alpha */ - JComponent getListCellComponent(ComponentList list, E value, boolean isSelected); + JComponent getListCellComponent(ComponentList list, E value); } diff --git a/src/main/java/envoy/client/ui/list/SelectionHandler.java b/src/main/java/envoy/client/ui/list/SelectionHandler.java new file mode 100644 index 0000000..b6ed40a --- /dev/null +++ b/src/main/java/envoy/client/ui/list/SelectionHandler.java @@ -0,0 +1,27 @@ +package envoy.client.ui.list; + +import javax.swing.JComponent; + +/** + * Handles the selection of elements in a {@link ComponentList}.
+ *
+ * Project: envoy-client + * File: SelectionHandler.java + * Created: 21.03.2020 + * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-beta + */ +@FunctionalInterface +public interface SelectionHandler { + + /** + * Notifies the handler about a selection. + * + * @param element the selected element + * @param component the selected component + * @param isSelected contains the selection state + * @since Envoy v0.1-beta + */ + void selectionChanged(E element, JComponent component, boolean isSelected); +} diff --git a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java index 7dd560e..59846fa 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryScrollBar.java @@ -1,11 +1,6 @@ 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; @@ -98,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(); diff --git a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java index 30ee098..fea465f 100644 --- a/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java +++ b/src/main/java/envoy/client/ui/primary/PrimaryToggleSwitch.java @@ -52,7 +52,7 @@ public class PrimaryToggleSwitch extends JButton { 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.setColor(Settings.getInstance().getCurrentTheme().getInteractableBackgroundColor()); g.fillRoundRect(state ? 25 : 0, 0, 25, 25, 25, 25); } } diff --git a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java deleted file mode 100644 index f19f17e..0000000 --- a/src/main/java/envoy/client/ui/renderer/UserComponentListRenderer.java +++ /dev/null @@ -1,70 +0,0 @@ -package envoy.client.ui.renderer; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.io.Serializable; - -import javax.swing.JComponent; -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.client.ui.list.ComponentList; -import envoy.client.ui.list.ComponentListCellRenderer; -import envoy.data.User; -import envoy.data.User.UserStatus; - -/** - * Project: envoy-client
- * File: UserComponentListRenderer.java
- * Created: 15 Mar 2020
- * - * @author Leon Hofmeister - * @since Envoy v0.1-beta - */ -public class UserComponentListRenderer implements ComponentListCellRenderer, Serializable { - - private static final long serialVersionUID = -2379244319112111284L; - - @Override - public JComponent getListCellComponent(ComponentList list, User user, boolean isSelected) { - final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); - - final JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - - // Panel background - panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); - panel.setOpaque(true); - panel.setPreferredSize(new Dimension(100, 35)); - - // TODO add profile picture support in BorderLayout.West - - JLabel username = new JLabel(user.getName()); - username.setForeground(theme.getUserNameColor()); - panel.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); - panel.add(statusLabel, BorderLayout.NORTH); - return panel; - } -} diff --git a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java index 7f6bc0c..89435df 100644 --- a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java @@ -46,7 +46,7 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // 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 diff --git a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java index c85c048..fbc3952 100644 --- a/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java +++ b/src/main/java/envoy/client/ui/settings/GeneralSettingsPanel.java @@ -43,7 +43,7 @@ public class GeneralSettingsPanel extends SettingsPanel { */ public GeneralSettingsPanel(SettingsScreen parent) { super(parent); - theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + theme = Settings.getInstance().getCurrentTheme(); setBackground(theme.getCellColor()); diff --git a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java index 4fdab10..906bb91 100644 --- a/src/main/java/envoy/client/ui/settings/NewThemeScreen.java +++ b/src/main/java/envoy/client/ui/settings/NewThemeScreen.java @@ -61,7 +61,7 @@ public class NewThemeScreen extends JDialog { setDimensions(true); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + Theme theme = Settings.getInstance().getCurrentTheme(); getContentPane().setLayout(new BorderLayout()); standardPanel.setBackground(theme.getBackgroundColor()); diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index e1ae290..22a24a4 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -156,7 +156,7 @@ public class SettingsScreen extends JDialog { } // 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())); diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index 8772064..5408a05 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -38,8 +38,9 @@ public class ThemeCustomizationPanel extends SettingsPanel { 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; + private static final Settings settings = Settings.getInstance(); + private static final Logger logger = EnvoyLog.getLogger(ThemeCustomizationPanel.class); + private static final long serialVersionUID = -8697897390666456624L; /** * Initializes a {@link ThemeCustomizationPanel} that enables the user to change @@ -52,7 +53,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { */ public ThemeCustomizationPanel(SettingsScreen parent) { super(parent); - temporaryTheme = new Theme("temporaryTheme", Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme())); + temporaryTheme = new Theme("temporaryTheme", settings.getCurrentTheme()); GridBagLayout gbl_themeLayout = new GridBagLayout(); @@ -63,7 +64,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { setLayout(gbl_themeLayout); - themes.setSelectedItem(Settings.getInstance().getCurrentTheme()); + themes.setSelectedItem(settings.getCurrentTheme()); GridBagConstraints gbc_themes = new GridBagConstraints(); gbc_themes.fill = GridBagConstraints.HORIZONTAL; @@ -83,7 +84,7 @@ public class ThemeCustomizationPanel extends SettingsPanel { colorsPanel.setLayout(gbl_colorCustomizations); - Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); + Theme theme = settings.getCurrentTheme(); buildCustomizeElements(theme); GridBagConstraints gbc_colorsPanel = new GridBagConstraints();