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/MessageComponent.java b/src/main/java/envoy/client/ui/MessageComponent.java
new file mode 100644
index 0000000..045e725
--- /dev/null
+++ b/src/main/java/envoy/client/ui/MessageComponent.java
@@ -0,0 +1,120 @@
+package envoy.client.ui;
+
+import java.awt.*;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.EnumMap;
+
+import javax.swing.*;
+
+import envoy.client.data.Settings;
+import envoy.client.ui.list.ComponentList;
+import envoy.data.Message;
+import envoy.data.Message.MessageStatus;
+
+/**
+ * Project: envoy-client
+ * File: MessageComponent.java
+ * Created: 21.03.2020
+ *
+ * @author Kai S. K. Engelbart
+ * @since Envoy v0.1-beta
+ */
+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);
+ forwardIcon = IconUtil.load("/icons/forward.png", 16);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public MessageComponent(ComponentList extends Message> list, Message message, boolean isSelected, long senderId) {
+ this(list.getMaximumSize().width, message, isSelected, senderId);
+ }
+
+ public MessageComponent(int width, Message message, boolean isSelected, long senderId) {
+ final var theme = Settings.getInstance().getThemes().get(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(isSelected ? theme.getSelectionColor() : 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.getMessageTextColor());
+ 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/container/ChatWindow.java b/src/main/java/envoy/client/ui/container/ChatWindow.java
index 7d883c2..808a4f7 100644
--- a/src/main/java/envoy/client/ui/container/ChatWindow.java
+++ b/src/main/java/envoy/client/ui/container/ChatWindow.java
@@ -125,16 +125,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 +149,11 @@ 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.setSelectionListener((list, comp) ->
+ contextMenu.show(comp, 0, 0));
+
scrollPane.setViewportView(messageList);
scrollPane.addComponentListener(new ComponentAdapter() {
diff --git a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java
index 467d43f..3add91a 100644
--- a/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java
+++ b/src/main/java/envoy/client/ui/container/ContactsChooserDialog.java
@@ -76,7 +76,7 @@ public class ContactsChooserDialog extends JDialog {
dialog.setVisible(true);
dialog.repaint();
dialog.revalidate();
- return results.size() > 0 ? results : null;
+ return results;
}
/**
diff --git a/src/main/java/envoy/client/ui/list/ComponentList.java b/src/main/java/envoy/client/ui/list/ComponentList.java
index 199946d..a4b4953 100644
--- a/src/main/java/envoy/client/ui/list/ComponentList.java
+++ b/src/main/java/envoy/client/ui/list/ComponentList.java
@@ -5,6 +5,7 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.BiConsumer;
import javax.swing.*;
@@ -23,10 +24,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 ComponentListModel model;
+ private ComponentListCellRenderer renderer;
+ private SelectionMode selectionMode = SelectionMode.NONE;
+ private Set selection = new HashSet<>();
+ private BiConsumer, JComponent> selectionListener;
private static final long serialVersionUID = 1759644503942876737L;
@@ -142,6 +144,9 @@ public class ComponentList extends JPanel {
// Update element
updateElement(index, true);
+
+ // Trigger selection listener
+ if (selectionListener != null) selectionListener.accept(this, (JComponent) getComponents()[index]);
}
}
@@ -273,4 +278,14 @@ public class ComponentList extends JPanel {
* @since Envoy v0.1-beta
*/
public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; }
+
+ /**
+ * @return the selectionListener
+ */
+ public BiConsumer, JComponent> getSelectionListener() { return selectionListener; }
+
+ /**
+ * @param selectionListener the selectionListener to set
+ */
+ public void setSelectionListener(BiConsumer, JComponent> selectionListener) { this.selectionListener = selectionListener; }
}
diff --git a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java
index 27a5a0d..a3c20bd 100644
--- a/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java
+++ b/src/main/java/envoy/client/ui/renderer/MessageListRenderer.java
@@ -1,19 +1,11 @@
package envoy.client.ui.renderer;
-import java.awt.*;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.EnumMap;
+import javax.swing.JPanel;
-import javax.swing.*;
-
-import envoy.client.data.Settings;
-import envoy.client.ui.Color;
-import envoy.client.ui.IconUtil;
+import envoy.client.ui.MessageComponent;
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.
@@ -29,18 +21,6 @@ import envoy.data.Message.MessageStatus;
*/
public class MessageListRenderer implements ComponentListCellRenderer {
- 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();
- }
- }
-
private final long senderId;
/**
@@ -57,84 +37,6 @@ public class MessageListRenderer implements ComponentListCellRenderer {
@Override
public JPanel getListCellComponent(ComponentList extends Message> 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);
-
- 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 };
-
- panel.setLayout(gbl_panel);
- panel.setBackground(isSelected ? theme.getSelectionColor() : 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;
- panel.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.getMessageTextColor());
- messageTextArea.setAlignmentX(0.5f);
- messageTextArea.setBackground(theme.getCellColor());
- messageTextArea.setEditable(false);
- var font = new Font("Arial", Font.PLAIN, 14);
- messageTextArea.setFont(font);
- messageTextArea.setSize(list.getMaximumSize().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);
-
- // 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;
- panel.add(statusLabel, gbc_statusLabel);
-
- // Forwarding
- if (message.isForwarded()) {
- var forwardLabel = new JLabel("Forwarded", forwardIcon, SwingConstants.CENTER);
- forwardLabel.setBackground(panel.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);
- }
-
- // 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),
- BorderFactory.createEtchedBorder()));
-
- var size = new Dimension(list.getMaximumSize().width - 50, panel.getPreferredSize().height);
-
- panel.setPreferredSize(size);
- panel.setMinimumSize(size);
- panel.setMaximumSize(size);
-
- return panel;
+ return new MessageComponent(list, message, isSelected, senderId);
}
}