diff --git a/src/main/java/envoy/client/Startup.java b/src/main/java/envoy/client/Startup.java deleted file mode 100644 index 0633834..0000000 --- a/src/main/java/envoy/client/Startup.java +++ /dev/null @@ -1,64 +0,0 @@ -package envoy.client; - -import java.util.logging.Logger; - -import envoy.client.ui.container.ChatWindow; -import envoy.data.Config; -import envoy.util.EnvoyLog; - -/** - * Starts the Envoy client and prompts the user to enter their name.
- *
- * Project: envoy-client
- * File: Startup.java
- * Created: 12 Oct 2019
- * - * @author Leon Hofmeister - * @author Maximilian Käfer - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-alpha - */ -public class Startup { - - private static final Logger logger = EnvoyLog.getLogger(Startup.class); - - // TODO: Update Javadoc - /** - * Loads the application by first loading the configuration, then acquiring a - * user name and connecting to the server. If the server cannot be reached, - * offline mode is entered if possible. After that, a {@link ChatWindow} - * instance is initialized and then displayed to the user. Upon application - * exit, settings and the local database are saved. - * - * @param args the command line arguments may contain configuration parameters - * and are parsed by the {@link Config} class - * @since Envoy Client v0.1-alpha - */ - public static void main(String[] args) { - // Display ChatWindow and StatusTrayIcon - // EventQueue.invokeLater(() -> { - // try { - // chatWindow.initContent(client, localDB, writeProxy); - // - // - // try { - // new StatusTrayIcon(chatWindow).show(); - // - // // If the tray icon is supported and corresponding settings is set, hide the - // // chat window on close - // Settings.getInstance() - // .getItems() - // .get("onCloseMode") - // .setChangeHandler((onCloseMode) -> chatWindow - // .setDefaultCloseOperation((Boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : - // JFrame.EXIT_ON_CLOSE)); - // } catch (EnvoyException e) { - // logger.warning("The StatusTrayIcon is not supported on this platform!"); - // } - // } catch (Exception e) { - // e.printStackTrace(); - // } - // }); - - } -} diff --git a/src/main/java/envoy/client/ui/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java deleted file mode 100644 index eb92fc4..0000000 --- a/src/main/java/envoy/client/ui/container/ChatWindow.java +++ /dev/null @@ -1,687 +0,0 @@ -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; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import envoy.client.data.Chat; -import envoy.client.data.LocalDB; -import envoy.client.data.Settings; -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.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; -import envoy.data.MessageBuilder; -import envoy.data.User; -import envoy.event.*; -import envoy.util.EnvoyLog; - -/** - * Project: envoy-client
- * File: ChatWindow.java
- * Created: 28 Sep 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @author Leon Hofmeister - * @since Envoy Client v0.1-alpha - */ -public class ChatWindow extends JFrame { - - /** - * This integer defines the maximum amount of chars allowed per message. - * - * @since Envoy 0.1-beta - */ - public static final int MAX_MESSAGE_LENGTH = 200; - - // User specific objects - private Client client; - private WriteProxy writeProxy; - private LocalDB localDB; - private Chat currentChat; - - // GUI components - private JPanel contentPane = new JPanel(); - private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); - private JList userList = new JList<>(); - private DefaultListModel userListModel = new DefaultListModel<>(); - private ComponentList 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(); - private JTextPane contactsDisplay = new JTextPane(); - 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 Model contactsModel = new Model<>(); - private final ComponentList contactList = new ComponentList().setRenderer(ContactSearchComponent::new); - - private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); - - // GUI component spacing - private final static int space = 4; - private static final Insets insets = new Insets(space, space, space, space); - - private static final long serialVersionUID = 0L; - - /** - * Initializes a {@link JFrame} with UI elements used to send and read messages - * to different users. - * - * @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"))); - - contentPane.setBorder(new EmptyBorder(space, space, space, space)); - setContentPane(contentPane); - GridBagLayout gbl_contentPane = new GridBagLayout(); - 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.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 commands = Map.of("forward selected message", evt -> { - final Message selectedMessage = messageList.getSingleSelectedElement(); - List 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() { - - // Update list elements when scroll pane (and thus list) is resized - @Override - public void componentResized(ComponentEvent e) { - messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); - messageList.synchronizeModel(); - } - }); - - GridBagConstraints gbc_scrollPane = new GridBagConstraints(); - gbc_scrollPane.fill = GridBagConstraints.BOTH; - gbc_scrollPane.gridwidth = 2; - gbc_scrollPane.gridheight = 2; - gbc_scrollPane.gridx = 1; - gbc_scrollPane.gridy = 1; - - gbc_scrollPane.insets = insets; - - drawChatBox(gbc_scrollPane); - - // MessageEnterTextArea - messageEnterTextArea.addInputMethodListener(new InputMethodListener() { - - @Override - public void inputMethodTextChanged(InputMethodEvent event) { - checkMessageTextLength(); - checkPostButton(messageEnterTextArea.getText()); - } - - @Override - public void caretPositionChanged(InputMethodEvent event) {} - }); - - messageEnterTextArea.addKeyListener(new KeyAdapter() { - - @Override - public void keyReleased(KeyEvent e) { - if (e.getKeyCode() == KeyEvent.VK_ENTER - && (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_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; - postButton.addActionListener((evt) -> { postMessage(); }); - postButton.setEnabled(false); - contentPane.add(postButton, gbc_postButton); - - // Settings Button - GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); - - gbc_moveSelectionSettingsButton.fill = GridBagConstraints.BOTH; - gbc_moveSelectionSettingsButton.gridx = 2; - gbc_moveSelectionSettingsButton.gridy = 0; - - gbc_moveSelectionSettingsButton.insets = insets; - - settingsButton.addActionListener(evt -> new SettingsScreen().setVisible(true)); - contentPane.add(settingsButton, gbc_moveSelectionSettingsButton); - - // Partner name display - textPane.setFont(new Font("Arial", Font.PLAIN, 20)); - textPane.setEditable(false); - - GridBagConstraints gbc_partnerName = new GridBagConstraints(); - gbc_partnerName.fill = GridBagConstraints.HORIZONTAL; - gbc_partnerName.gridx = 1; - gbc_partnerName.gridy = 0; - - gbc_partnerName.insets = insets; - contentPane.add(textPane, gbc_partnerName); - - userList.setCellRenderer(new UserListRenderer()); - userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - userList.addListSelectionListener((listSelectionEvent) -> { - if (client != null && localDB != null && !listSelectionEvent.getValueIsAdjusting()) { - final JList selectedUserList = (JList) listSelectionEvent.getSource(); - final User user = selectedUserList.getSelectedValue(); - - for (int i = 0; i < contentPane.getComponents().length; i++) - if (contentPane.getComponent(i).equals(searchPane)) drawChatBox(gbc_scrollPane); - if (user != null) { - // Select current chat - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); - - // Read current chat - readCurrentChat(); - - // Set chat title - textPane.setText(currentChat.getRecipient().getName()); - - // Update model and scroll down - // messageList.setModel(currentChat.getModel()); - scrollPane.setChatOpened(true); - - messageList.synchronizeModel(); - revalidate(); - repaint(); - } - } - }); - - userList.setFont(new Font("Arial", Font.PLAIN, 17)); - userList.setBorder(new EmptyBorder(space, space, space, space)); - - GridBagConstraints gbc_userList = new GridBagConstraints(); - gbc_userList.fill = GridBagConstraints.VERTICAL; - gbc_userList.gridx = 0; - gbc_userList.gridy = 2; - gbc_userList.gridheight = 2; - gbc_userList.anchor = GridBagConstraints.PAGE_START; - gbc_userList.insets = insets; - - contentPane.add(userList, gbc_userList); - contentPane.revalidate(); - - // Contacts Search - GridBagConstraints gbc_searchPane = new GridBagConstraints(); - gbc_searchPane.fill = GridBagConstraints.BOTH; - gbc_searchPane.gridwidth = 2; - gbc_searchPane.gridheight = 2; - gbc_searchPane.gridx = 1; - gbc_searchPane.gridy = 1; - - gbc_searchPane.insets = insets; - - GridBagLayout gbl_contactsSearch = new GridBagLayout(); - gbl_contactsSearch.columnWidths = new int[] { 1, 1 }; - gbl_contactsSearch.rowHeights = new int[] { 1, 1 }; - gbl_contactsSearch.columnWeights = new double[] { 1, 0.1 }; - gbl_contactsSearch.rowWeights = new double[] { 0.001, 1 }; - searchPane.setLayout(gbl_contactsSearch); - - GridBagConstraints gbc_searchField = new GridBagConstraints(); - gbc_searchField.fill = GridBagConstraints.BOTH; - gbc_searchField.gridx = 0; - gbc_searchField.gridy = 0; - gbc_searchField.insets = new Insets(7, 4, 4, 4); - - searchPane.add(searchField, gbc_searchField); - - // Sends event to server, if input has changed - searchField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent evt) { - if (client.isOnline()) if (searchField.getText().isEmpty()) { - contactsModel.clear(); - revalidate(); - repaint(); - } else try { - client.sendEvent(new ContactSearchRequest(searchField.getText())); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void insertUpdate(DocumentEvent evt) { - if (client.isOnline()) try { - client.sendEvent(new ContactSearchRequest(searchField.getText())); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void changedUpdate(DocumentEvent evt) {} - }); - - GridBagConstraints gbc_cancelButton = new GridBagConstraints(); - gbc_cancelButton.fill = GridBagConstraints.BOTH; - gbc_cancelButton.gridx = 1; - gbc_cancelButton.gridy = 0; - gbc_cancelButton.insets = new Insets(7, 4, 4, 4); - - cancelButton.addActionListener((evt) -> { drawChatBox(gbc_scrollPane); }); - - searchPane.add(cancelButton, gbc_cancelButton); - - contactList.setModel(contactsModel); - scrollForPossibleContacts.setBorder(new EmptyBorder(space, space, space, space)); - scrollForPossibleContacts.setViewportView(contactList); - - GridBagConstraints gbc_possibleContacts = new GridBagConstraints(); - gbc_possibleContacts.fill = GridBagConstraints.BOTH; - gbc_possibleContacts.gridwidth = 2; - gbc_possibleContacts.gridx = 0; - gbc_possibleContacts.gridy = 1; - - gbc_possibleContacts.insets = insets; - - searchPane.add(scrollForPossibleContacts, gbc_possibleContacts); - - // Contacts Header - GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); - gbc_contactsHeader.fill = GridBagConstraints.BOTH; - gbc_contactsHeader.gridx = 0; - gbc_contactsHeader.gridy = 1; - gbc_contactsHeader.insets = insets; - - GridBagLayout gbl_contactHeader = new GridBagLayout(); - gbl_contactHeader.columnWidths = new int[] { 1, 1 }; - gbl_contactHeader.rowHeights = new int[] { 1 }; - gbl_contactHeader.columnWeights = new double[] { 1, 1 }; - gbl_contactHeader.rowWeights = new double[] { 1 }; - contactsHeader.setLayout(gbl_contactHeader); - - contactsDisplay.setEditable(false); - contactsDisplay.setFont(new Font("Arial", Font.PLAIN, 12)); - contactsDisplay.setText("Contacts"); - - GridBagConstraints gbc_contactsDisplay = new GridBagConstraints(); - gbc_contactsDisplay.fill = GridBagConstraints.BOTH; - gbc_contactsDisplay.gridx = 0; - gbc_contactsDisplay.gridy = 0; - - contactsHeader.add(contactsDisplay, gbc_contactsDisplay); - - addContact.setFont(new Font("Arial", Font.PLAIN, 15)); - - GridBagConstraints gbc_addContact = new GridBagConstraints(); - gbc_addContact.fill = GridBagConstraints.BOTH; - gbc_addContact.gridx = 1; - gbc_addContact.gridy = 0; - gbc_addContact.insets = insets; - - addContact.addActionListener(evt -> drawContactSearch(gbc_searchPane)); - - contactsHeader.add(addContact, gbc_addContact); - - applyTheme(Settings.getInstance().getCurrentTheme()); - - contentPane.add(contactsHeader, gbc_contactsHeader); - contentPane.revalidate(); - - // Listen to theme changes - EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get())); - - // Listen to user status changes - EventBus.getInstance().register(UserStatusChangeEvent.class, evt -> { userList.revalidate(); userList.repaint(); }); - - // Listen to received messages - EventBus.getInstance().register(MessageCreationEvent.class, evt -> { - Message message = evt.get(); - Chat chat = localDB.getChats().stream().filter(c -> c.getRecipient().getID() == message.getSenderID()).findFirst().get(); - // chat.appendMessage(message); - - // Read message and update UI if in current chat - if (chat == currentChat) readCurrentChat(); - - revalidate(); - repaint(); - }); - - // Listen to message status changes - EventBus.getInstance().register(MessageStatusChangeEvent.class, evt -> { - final long id = evt.getID(); - final MessageStatus status = evt.get(); - - for (Chat c : localDB.getChats()) - // for (Message m : c.getModel()) - // if (m.getID() == id) { - // - // // Update message status - // m.setStatus(status); - // - // // Update model and scroll down if current chat - // if (c == currentChat) { - // messageList.setModel(currentChat.getModel()); - // scrollPane.setChatOpened(true); - // } else messageList.synchronizeModel(); - // } - - revalidate(); - repaint(); - }); - - // Listen to contact search results - EventBus.getInstance() - .register(ContactSearchResult.class, - evt -> { - contactsModel.clear(); - final java.util.List contacts = evt.get(); - contacts.forEach(contactsModel::add); - revalidate(); - repaint(); - }); - - // Add new contacts to the contact list - EventBus.getInstance().register(ContactOperationEvent.class, evt -> { - User contact = evt.get(); - - // Clearing the search field and the searchResultList - searchField.setText(""); - contactsModel.clear(); - - // Update LocalDB - userListModel.addElement(contact); - localDB.getUsers().put(contact.getName(), contact); - localDB.getChats().add(new Chat(contact)); - - revalidate(); - repaint(); - }); - - revalidate(); - repaint(); - } - - /** - * Used to immediately reload the {@link ChatWindow} when settings were changed. - * - * @param theme the theme to change colors into - * @since Envoy Client v0.2-alpha - */ - private void applyTheme(Theme theme) { - // contentPane - contentPane.setBackground(theme.getBackgroundColor()); - contentPane.setForeground(theme.getUserNameColor()); - // messageList - messageList.setForeground(theme.getTextColor()); - messageList.setBackground(theme.getCellColor()); - messageList.synchronizeModel(); - // scrollPane - scrollPane.applyTheme(theme); - scrollPane.autoscroll(); - // messageEnterTextArea - messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); - messageEnterTextArea.setForeground(theme.getTypingMessageColor()); - messageEnterTextArea.setBackground(theme.getCellColor()); - // postButton - postButton.setForeground(theme.getInteractableForegroundColor()); - postButton.setBackground(theme.getInteractableBackgroundColor()); - // settingsButton - settingsButton.setForeground(theme.getInteractableForegroundColor()); - settingsButton.setBackground(theme.getInteractableBackgroundColor()); - // textPane - textPane.setBackground(theme.getBackgroundColor()); - textPane.setForeground(theme.getUserNameColor()); - // userList - userList.setSelectionForeground(theme.getUserNameColor()); - userList.setSelectionBackground(theme.getSelectionColor()); - userList.setForeground(theme.getUserNameColor()); - userList.setBackground(theme.getCellColor()); - // contacts header - contactsHeader.setBackground(theme.getCellColor()); - contactsDisplay.setBackground(theme.getCellColor()); - contactsDisplay.setForeground(theme.getUserNameColor()); - addContact.setBackground(theme.getInteractableBackgroundColor()); - addContact.setForeground(theme.getInteractableForegroundColor()); - // SearchPane - searchPane.setBackground(theme.getCellColor()); - searchField.setBackground(theme.getBackgroundColor()); - searchField.setForeground(theme.getUserNameColor()); - cancelButton.setBackground(theme.getInteractableBackgroundColor()); - cancelButton.setForeground(theme.getInteractableForegroundColor()); - 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(); - - // 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 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); - - // Update UI - revalidate(); - repaint(); - - // Request a new id generator if all IDs were used - if (!localDB.getIDGenerator().hasNext()) client.requestIdGenerator(); - - } catch (Exception e) { - JOptionPane.showMessageDialog(this, "Error sending message:\n" + e.toString(), "Message sending error", JOptionPane.ERROR_MESSAGE); - e.printStackTrace(); - } - } - - private void readCurrentChat() { - try { - currentChat.read(writeProxy); - if (messageList.getRenderer() != null) messageList.synchronizeModel(); - } catch (IOException e) { - e.printStackTrace(); - logger.log(Level.WARNING, "Couldn't notify server about message status change", e); - } - } - - private void drawChatBox(GridBagConstraints gbc_scrollPane) { - contentPane.remove(searchPane); - contentPane.add(scrollPane, gbc_scrollPane); - contentPane.revalidate(); - contentPane.repaint(); - } - - private void drawContactSearch(GridBagConstraints gbc_searchPane) { - currentChat = null; - userList.removeSelectionInterval(0, userList.getModel().getSize() - 1); - messageList.setModel(null); - textPane.setText(""); - contentPane.remove(scrollPane); - contentPane.add(searchPane, gbc_searchPane); - contentPane.revalidate(); - contentPane.repaint(); - } - - /** - * Initializes the components responsible server communication and - * persistence.
- *
- * This will trigger the display of the contact list. - * - * @param client the client used to send and receive messages - * @param localDB the local database used to manage stored messages - * and users - * @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 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 -> { - userListModel.addElement(user); - - // Check if user exists in local DB - if (localDB.getChats().stream().noneMatch(c -> c.getRecipient().getID() == user.getID())) localDB.getChats().add(new Chat(user)); - }); - SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); - - revalidate(); - repaint(); - }).start(); - } - - /** - * Checks whether the length of the text inside messageEnterTextArea >= - * {@link ChatWindow#MAX_MESSAGE_LENGTH} - * and splits the text into the allowed part, if that is the case. - * - * @since Envoy Client v0.1-beta - */ - private void checkMessageTextLength() { - String input = messageEnterTextArea.getText(); - if (input.length() >= MAX_MESSAGE_LENGTH) { - messageEnterTextArea.setText(input.substring(0, MAX_MESSAGE_LENGTH - 1)); - // TODO: current notification is like being hit with a hammer, maybe it should - // be replaced with a more subtle notification - JOptionPane.showMessageDialog(messageEnterTextArea, - "the maximum length for a message has been reached", - "maximum message length reached", - JOptionPane.WARNING_MESSAGE); - } - } - - private void checkPostButton(String text) { postButton.setEnabled(!text.trim().isBlank()); } -} diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java deleted file mode 100755 index 4c81aad..0000000 --- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java +++ /dev/null @@ -1,145 +0,0 @@ -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.
- *
- * Project: envoy-client
- * File: ContactsChooserDialog.java
- * Created: 15 Mar 2020
- * - * @author Leon Hofmeister - * @since Envoy Client v0.1-beta - */ -public class ContactsChooserDialog extends JDialog { - - private static final long serialVersionUID = 0L; - - private ComponentList contactList = new ComponentList().setModel(new Model()) - .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 - * ArrayList. - * - * @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 showForwardingDialog(String title, Component parent, Message message, Collection users) { - ContactsChooserDialog dialog = new ContactsChooserDialog(parent); - dialog.setTitle(title); - dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE); - dialog.addCancelButtonActionListener(e -> dialog.dispose()); - - List results = new ArrayList<>(); - dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelectedElements()); dialog.dispose(); }); - Model 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 getContactList() { return contactList; } - - private void addOkButtonActionListener(ActionListener l) { okButton.addActionListener(l); } - - private void addCancelButtonActionListener(ActionListener l) { cancelButton.addActionListener(l); } -} diff --git a/src/main/java/envoy/client/ui/container/ContextMenu.java b/src/main/java/envoy/client/ui/container/ContextMenu.java deleted file mode 100755 index 2043985..0000000 --- a/src/main/java/envoy/client/ui/container/ContextMenu.java +++ /dev/null @@ -1,255 +0,0 @@ -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.
- *
- * Project: envoy-client
- * File: ContextMenu.java
- * Created: 17 Mar 2020
- * - * @author Leon Hofmeister - * @since Envoy Client v0.1-beta - */ -public class ContextMenu extends JPopupMenu { - - private static final long serialVersionUID = 0L; - - /** - * 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 items = new HashMap<>(); - private Map icons = new HashMap<>(); - private Map 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 itemsWithActions, Map itemIcons, - Map 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 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 items) { this.items = items; } - - /** - * @return the icons - * @since Envoy Client v0.1-beta - */ - public Map getIcons() { return icons; } - - /** - * @param icons the icons to set - * @since Envoy Client v0.1-beta - */ - public void setIcons(Map 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 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 mnemonics) { this.mnemonics = mnemonics; } - - /** - * {@inheritDoc}
- * 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}
- * 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()); - } -} diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java deleted file mode 100644 index c3cb2ec..0000000 --- a/src/main/java/envoy/client/ui/list/ComponentList.java +++ /dev/null @@ -1,261 +0,0 @@ -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 Model}. Similar to {@link javax.swing.JList} but capable - * of rendering {@link JPanel}s.
- *
- * Project: envoy-client
- * File: ComponentList.java
- * Created: 25.01.2020
- * - * @param the type of object displayed in this list - * @author Kai S. K. Engelbart - * @since Envoy Client v0.3-alpha - */ -public class ComponentList extends JPanel { - - private Model model; - private Renderer renderer; - private SelectionHandler selectionHandler; - private SelectionMode selectionMode = SelectionMode.NONE; - private Set selection = new HashSet<>(); - - private static final long serialVersionUID = 0L; - - /** - * Defines the possible modes of selection that can be performed by the user - * - * @since Envoy Client v0.1-beta - */ - 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}. - * - * @since Envoy Client v0.3-alpha - */ - public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } - - /** - * Removes all child components and then adds all components representing the - * elements of the {@link Model}. - * - * @since Envoy Client v0.3-alpha - */ - public void synchronizeModel() { - if (model != null) { - removeAll(); - model.forEach(this::addElement); - revalidate(); - } - } - - /** - * 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 Client v0.1-beta - */ - 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); - - } else { - - // Remove old selection if single selection is enabled - if (selectionMode == SelectionMode.SINGLE) clearSelection(); - - // Select item - if (selectionMode != SelectionMode.NONE) { - - // Assign new selection - selection.add(index); - - // Update element - if (selectionHandler != null) selectionHandler.selectionChanged(model.get(index), element, true); - } - } - - revalidate(); - repaint(); - } - - /** - * Removes the current selection. - * - * @since Envoy Client v0.1-alpha - */ - 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 getSelection() { return selection; } - - /** - * @return a set of all selected elements - * @since Envoy Client v0.1-beta - */ - public Set getSelectedElements() { - var selectedElements = new HashSet(); - 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 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 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 Client v0.1-beta - */ - public Renderer getRenderer() { return renderer; } - - /** - * @param renderer the renderer to set - * @return this component list - * @since Envoy Client v0.1-beta - */ - public ComponentList setRenderer(Renderer 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 setSelectionMode(SelectionMode selectionMode) { - this.selectionMode = selectionMode; - clearSelection(); - return this; - } - - /** - * @return the selection handler - * @since Envoy Client v0.1-beta - */ - public SelectionHandler getSelectionHandler() { return selectionHandler; } - - /** - * @param selectionHandler the selection handler to set - * @since Envoy Client v0.1-beta - */ - public void setSelectionHandler(SelectionHandler selectionHandler) { this.selectionHandler = selectionHandler; } -} diff --git a/src/main/java/envoy/client/ui/list/Model.java b/src/main/java/envoy/client/ui/list/Model.java deleted file mode 100644 index 4f13636..0000000 --- a/src/main/java/envoy/client/ui/list/Model.java +++ /dev/null @@ -1,120 +0,0 @@ -package envoy.client.ui.list; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Stores objects that will be displayed in a {@link ComponentList}.
- *
- * Project: envoy-client
- * File: Model.java
- * Created: 25.01.2020
- * - * @param the type of object displayed in this list - * @author Kai S. K. Engelbart - * @since Envoy Client v0.3-alpha - */ -public final class Model implements Iterable, Serializable { - - private List elements = new ArrayList<>(); - transient private ComponentList componentList; - - private static final long serialVersionUID = 0L; - - /** - * Adds an element to this model and notifies the associated - * {@link ComponentList} to add the corresponding component. - * - * @param e the element to add - * @return {@code true} - * @see java.util.List#add(java.lang.Object) - * @since Envoy Client v0.3-alpha - */ - public boolean add(E e) { - if (componentList != null) { - componentList.addElement(e); - componentList.revalidate(); - } - return elements.add(e); - } - - /** - * Removes all elements from this model and clears the associated - * {@link ComponentList}. - * - * @see java.util.List#clear() - * @since Envoy Client v0.3-alpha - */ - public void clear() { - elements.clear(); - if (componentList != null) componentList.removeAll(); - } - - /** - * @param index the index to retrieve the element from - * @return the element located at the index - * @see java.util.List#get(int) - * @since Envoy Client v0.3-alpha - */ - public E get(int index) { return elements.get(index); } - - /** - * Removes the element at a specific index from this model and the corresponding - * component from the {@link ComponentList}. - * - * @param index the index of the element to remove - * @return the removed element - * @see java.util.List#remove(int) - * @since Envoy Client v0.3-alpha - */ - public E remove(int index) { - if (componentList != null) componentList.remove(index); - return elements.remove(index); - } - - /** - * @return the amount of elements in this list model - * @see java.util.List#size() - * @since Envoy Client v0.3-alpha - */ - public int size() { return elements.size(); } - - /** - * @return {@code true} if this model contains no elements - * @see java.util.List#isEmpty() - */ - public boolean isEmpty() { return elements.isEmpty(); } - - /** - * @return an iterator over the elements of this list model - * @see java.util.List#iterator() - * @since Envoy Client v0.3-alpha - */ - @Override - public Iterator iterator() { - return new Iterator<>() { - - Iterator iter = elements.iterator(); - - @Override - public boolean hasNext() { return iter.hasNext(); } - - @Override - public E next() { return iter.next(); } - }; - } - - /** - * Sets the component list displaying the elements of this model and triggers a - * synchronization. - * - * @param componentList the component list to set - * @since Envoy Client v0.3-alpha - */ - void setComponentList(ComponentList componentList) { - this.componentList = componentList; - if (componentList != null && componentList.getRenderer() != null) componentList.synchronizeModel(); - } -} diff --git a/src/main/java/envoy/client/ui/list/Renderer.java b/src/main/java/envoy/client/ui/list/Renderer.java deleted file mode 100644 index f2d3ad9..0000000 --- a/src/main/java/envoy/client/ui/list/Renderer.java +++ /dev/null @@ -1,31 +0,0 @@ -package envoy.client.ui.list; - -import javax.swing.JComponent; - -/** - * Allows a {@link ComponentList} convert its elements into Swing components - * that can be rendered.
- *
- * Project: envoy-client
- * File: Renderer.java
- * Created: 25.01.2020
- * - * @param the type of object displayed in this list - * @author Kai S. K. Engelbart - * @since Envoy Client v0.3-alpha - */ -@FunctionalInterface -public interface Renderer { - - /** - * Provides a Swing component representing a list element. - * - * @param list the list in which the component will be displayed - * @param value the list element that will be converted - * @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 Client v0.3-alpha - */ - 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 deleted file mode 100644 index d8c1984..0000000 --- a/src/main/java/envoy/client/ui/list/SelectionHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -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 - * @param the type of the underlying {@link ComponentList} - * @since Envoy Client 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 Client v0.1-beta - */ - void selectionChanged(E element, JComponent component, boolean isSelected); -} diff --git a/src/main/java/envoy/client/ui/list/package-info.java b/src/main/java/envoy/client/ui/list/package-info.java deleted file mode 100644 index 50d553b..0000000 --- a/src/main/java/envoy/client/ui/list/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * This package defines a Swing component that can be used to display lists of - * other components to the user. - * - * @author Kai S. K. Engelbart - * @author Leon Hofmeister - * @author Maximilian Käfer - * @since Envoy Client v0.3-alpha - */ -package envoy.client.ui.list; diff --git a/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java b/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java deleted file mode 100644 index edba839..0000000 --- a/src/main/java/envoy/client/ui/list_component/ContactSearchComponent.java +++ /dev/null @@ -1,73 +0,0 @@ -package envoy.client.ui.list_component; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; - -import javax.swing.*; - -import envoy.client.data.Settings; -import envoy.client.event.SendEvent; -import envoy.client.ui.list.ComponentList; -import envoy.client.ui.primary.PrimaryButton; -import envoy.data.User; -import envoy.event.ContactOperationEvent; -import envoy.event.EventBus; - -/** - * Project: envoy-client - * File: ContactSearchComponent.java - * Created: 21.03.2020 - * - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-beta - */ -public class ContactSearchComponent extends JComponent { - - private static final long serialVersionUID = 0L; - - /** - * @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 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().getCurrentTheme().getTextColor()); - display.setAlignmentX(Component.LEFT_ALIGNMENT); - display.setAlignmentY(Component.CENTER_ALIGNMENT); - display.setFont(new Font("Arial", Font.PLAIN, 16)); - add(display); - - PrimaryButton add = new PrimaryButton("+"); - add.setFont(new Font("Arial", Font.PLAIN, 19)); - add.setPreferredSize(new Dimension(45, 45)); - add.setMinimumSize(new Dimension(45, 45)); - add.setMaximumSize(new Dimension(45, 45)); - - add.setBackground(list.getBackground()); - add.setForeground(list.getForeground()); - - add.addActionListener(evt -> { - ContactOperationEvent contactsOperationEvent = new ContactOperationEvent(user, ContactOperationEvent.Operation.ADD); - EventBus.getInstance().dispatch(contactsOperationEvent); - EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent)); - }); - - add(add); - - // Define some space to the messages below - setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder())); - - // Define a maximum height of 50px - Dimension size = new Dimension(435, 50); - setMaximumSize(size); - setMinimumSize(size); - setPreferredSize(size); - } -} diff --git a/src/main/java/envoy/client/ui/list_component/MessageComponent.java b/src/main/java/envoy/client/ui/list_component/MessageComponent.java deleted file mode 100644 index 9ceb413..0000000 --- a/src/main/java/envoy/client/ui/list_component/MessageComponent.java +++ /dev/null @@ -1,127 +0,0 @@ -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: envoy-client - * File: MessageComponent.java - * Created: 21.03.2020 - * - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-beta - */ -public class MessageComponent extends JPanel { - - private static final long serialVersionUID = 0L; - - private static EnumMap 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 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); - } -} diff --git a/src/main/java/envoy/client/ui/list_component/UserComponent.java b/src/main/java/envoy/client/ui/list_component/UserComponent.java deleted file mode 100644 index 4d3332e..0000000 --- a/src/main/java/envoy/client/ui/list_component/UserComponent.java +++ /dev/null @@ -1,69 +0,0 @@ -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}.
- *
- * Project: envoy-client - * File: UserComponent.java - * Created: 21.03.2020 - * - * @author Kai S. K. Engelbart - * @since Envoy Client v0.1-beta - */ -public class UserComponent extends JPanel { - - private static final long serialVersionUID = 0L; - - /** - * @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); - } -} diff --git a/src/main/java/envoy/client/ui/list_component/package-info.java b/src/main/java/envoy/client/ui/list_component/package-info.java deleted file mode 100644 index 89da45c..0000000 --- a/src/main/java/envoy/client/ui/list_component/package-info.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This package contains swing components that can be displayed by - * {@link envoy.client.ui.list.ComponentList}.
- *
- * Project: envoy-client
- * File: package-info.java
- * Created: 21 Mar 2020
- * - * @author Leon Hofmeister - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy Client v0.1-beta - */ -package envoy.client.ui.list_component; diff --git a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java b/src/main/java/envoy/client/ui/renderer/UserListRenderer.java deleted file mode 100644 index 0ed15a2..0000000 --- a/src/main/java/envoy/client/ui/renderer/UserListRenderer.java +++ /dev/null @@ -1,65 +0,0 @@ -package envoy.client.ui.renderer; - -import java.awt.Component; -import java.awt.Dimension; - -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -import envoy.client.data.Settings; -import envoy.data.User; -import envoy.data.User.UserStatus; - -/** - * Defines how the {@code UserList} is displayed.
- *
- * Project: envoy-client
- * File: UserListRenderer.java
- * Created: 12 Oct 2019
- * - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy Client v0.1-alpha - */ -public class UserListRenderer extends JLabel implements ListCellRenderer { - - private static final long serialVersionUID = 5164417379767181198L; - - /** - * {@inheritDoc} - */ - @Override - public Component getListCellRendererComponent(JList list, User value, int index, boolean isSelected, boolean cellHasFocus) { - if (isSelected) { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } else { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } - - // Enable background rendering - setOpaque(true); - - final String name = value.getName(); - final UserStatus status = value.getStatus(); - - this.setPreferredSize(new Dimension(100, 35)); - - // Getting the UserNameColor of the current theme - String textColor = null; - textColor = Settings.getInstance().getCurrentTheme().getUserNameColor().toHex(); - switch (status) { - case ONLINE: - setText(String - .format("

%s

%s", status, textColor, name)); - break; - case OFFLINE: - setText(String - .format("

%s

%s", status, textColor, name)); - break; - } - return this; - } -} diff --git a/src/main/java/envoy/client/ui/renderer/package-info.java b/src/main/java/envoy/client/ui/renderer/package-info.java deleted file mode 100644 index 6a6f58e..0000000 --- a/src/main/java/envoy/client/ui/renderer/package-info.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This package contains all Envoy-specific renderers for lists that store an - * arbitrary number of JComponents.
- *
- * Project: envoy-client
- * File: package-info.java
- * Created: 14 Mar 2020
- * - * @author Leon Hofmeister - * @author Kai S. K. Engelbart - * @author Maximilian Käfer - * @since Envoy Client v0.1-beta - */ -package envoy.client.ui.renderer;