added missing merge content,mnemonics support(ContextMenu)and Nullchecks
This commit is contained in:
		| @@ -44,17 +44,20 @@ public class ContextMenu extends JPopupMenu { | ||||
| 	 */ | ||||
| 	public static final String	subMenuItem			= "SubMI"; | ||||
|  | ||||
| 	private Map<String, ActionListener>	items	= new HashMap<>(); | ||||
| 	private Map<String, Icon>			icons	= new HashMap<>(); | ||||
| 	private Map<String, ActionListener>	items		= new HashMap<>(); | ||||
| 	private Map<String, Icon>			icons		= new HashMap<>(); | ||||
| 	private Map<String, Integer>		mnemonics	= new HashMap<>(); | ||||
|  | ||||
| 	private ButtonGroup	radioButtonGroup	= new ButtonGroup(); | ||||
| 	private boolean		built				= false; | ||||
| 	private boolean		visible				= false; | ||||
|  | ||||
| 	/** | ||||
| 	 * @param parent the component which will call this | ||||
| 	 *               {@link ContextMenu} | ||||
| 	 * @since Envoy v0.1-beta | ||||
| 	 */ | ||||
| 	public ContextMenu() {} | ||||
| 	public ContextMenu(Component parent) { setInvoker(parent); } | ||||
|  | ||||
| 	/** | ||||
| 	 * @param label            the string that a UI may use to display as a title | ||||
| @@ -67,13 +70,18 @@ public class ContextMenu extends JPopupMenu { | ||||
| 	 *                         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 v0.1-beta | ||||
| 	 */ | ||||
| 	public ContextMenu(String label, Component parent, Map<String, ActionListener> itemsWithActions, Map<String, Icon> itemIcons) { | ||||
| 	public ContextMenu(String label, Component parent, Map<String, ActionListener> itemsWithActions, Map<String, Icon> itemIcons, | ||||
| 			Map<String, Integer> itemMnemonics) { | ||||
| 		super(label); | ||||
| 		setInvoker(parent); | ||||
| 		this.items	= (itemsWithActions != null) ? itemsWithActions : items; | ||||
| 		this.icons	= (itemIcons != null) ? itemIcons : icons; | ||||
| 		this.items		= (itemsWithActions != null) ? itemsWithActions : items; | ||||
| 		this.icons		= (itemIcons != null) ? itemIcons : icons; | ||||
| 		this.mnemonics	= (itemMnemonics != null) ? itemMnemonics : mnemonics; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -87,27 +95,20 @@ public class ContextMenu extends JPopupMenu { | ||||
| 	public ContextMenu build() { | ||||
| 		items.forEach((text, action) -> { | ||||
| 			// case radio button wanted | ||||
| 			AbstractButton item; | ||||
| 			if (text.startsWith(radioButtonMenuItem)) { | ||||
| 				var item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||
| 				item.addActionListener(action); | ||||
| 				item = new JRadioButtonMenuItem(text.substring(radioButtonMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||
| 				radioButtonGroup.add(item); | ||||
| 				add(item); | ||||
| 				// case check box wanted | ||||
| 			} else if (text.startsWith(checkboxMenuItem)) { | ||||
| 				var item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||
| 				item.addActionListener(action); | ||||
| 				add(item); | ||||
| 				// case sub-menu wanted | ||||
| 			} else if (text.startsWith(subMenuItem)) { | ||||
| 				var item = new JMenu(text.substring(subMenuItem.length())); | ||||
| 				item.addActionListener(action); | ||||
| 				add(item); | ||||
| 			} else { | ||||
| 				// normal JMenuItem wanted | ||||
| 				var item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); | ||||
| 				item.addActionListener(action); | ||||
| 				add(item); | ||||
| 			} | ||||
| 			} else if (text.startsWith(checkboxMenuItem)) | ||||
| 				item = new JCheckBoxMenuItem(text.substring(checkboxMenuItem.length()), icons.containsKey(text) ? icons.get(text) : null); | ||||
| 			// case sub-menu wanted | ||||
| 			else if (text.startsWith(subMenuItem)) item = new JMenu(text.substring(subMenuItem.length())); | ||||
| 			else // normal JMenuItem wanted | ||||
| 				item = new JMenuItem(text, icons.containsKey(text) ? icons.get(text) : null); | ||||
| 			item.addActionListener(action); | ||||
| 			if (mnemonics.containsKey(text)) item.setMnemonic(mnemonics.get(text)); | ||||
| 			add(item); | ||||
| 		}); | ||||
| 		getInvoker().addMouseListener(getShowingListener()); | ||||
| 		built = true; | ||||
| @@ -136,10 +137,10 @@ public class ContextMenu extends JPopupMenu { | ||||
| 			private void action(MouseEvent e) { | ||||
| 				if (!built) build(); | ||||
| 				if (e.isPopupTrigger()) { | ||||
| 					show(e.getComponent(), e.getX(), e.getY()); | ||||
| 					// hides the menu if already visible | ||||
| 					visible = !visible; | ||||
| 					setVisible(visible); | ||||
| 					if (visible) show(e.getComponent(), e.getX(), e.getY()); | ||||
| 					else setVisible(false); | ||||
|  | ||||
| 				} | ||||
| 			} | ||||
| @@ -153,8 +154,9 @@ public class ContextMenu extends JPopupMenu { | ||||
| 	 */ | ||||
| 	public void clear() { | ||||
| 		removeAll(); | ||||
| 		items	= new HashMap<>(); | ||||
| 		icons	= new HashMap<>(); | ||||
| 		items		= new HashMap<>(); | ||||
| 		icons		= new HashMap<>(); | ||||
| 		mnemonics	= new HashMap<>(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -181,4 +183,19 @@ public class ContextMenu extends JPopupMenu { | ||||
| 	 * @since Envoy v0.1-beta | ||||
| 	 */ | ||||
| 	public void setIcons(Map<String, Icon> icons) { this.icons = icons; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the mnemonics (the keyboard shortcuts that automatically execute the | ||||
| 	 *         command for a {@link JMenuItem} with corresponding text) | ||||
| 	 * @since Envoy v0.1-beta | ||||
| 	 */ | ||||
| 	public Map<String, Integer> getMnemonics() { return mnemonics; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @param mnemonics the keyboard shortcuts that need to be pressed to | ||||
| 	 *                  automatically execute the {@link JMenuItem} with the given | ||||
| 	 *                  text | ||||
| 	 * @since Envoy v0.1-beta | ||||
| 	 */ | ||||
| 	public void setMnemonics(Map<String, Integer> mnemonics) { this.mnemonics = mnemonics; } | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,7 @@ 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.list.ComponentList; | ||||
| import envoy.client.ui.list.ComponentListModel; | ||||
| @@ -29,6 +30,7 @@ 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; | ||||
| @@ -74,6 +76,7 @@ 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 | ||||
| @@ -107,6 +110,7 @@ public class ChatWindow extends JFrame { | ||||
| 	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"))); | ||||
| @@ -121,44 +125,37 @@ public class ChatWindow extends JFrame { | ||||
| 		contentPane.setLayout(gbl_contentPane); | ||||
|  | ||||
| 		messageList.setBorder(new EmptyBorder(space, space, space, space)); | ||||
| 		messageList.addMouseListener(new MouseAdapter() { | ||||
| 		Map<String, ActionListener> commands = new HashMap<>() { | ||||
|  | ||||
| 			@Override | ||||
| 			public void mouseClicked(MouseEvent e) { | ||||
| 				if (e.isPopupTrigger()) { | ||||
| 					contextMenu = new JPopupMenu("message options"); | ||||
| 					Map<String, ActionListener> commands = new HashMap<>() { | ||||
| 			private static final long serialVersionUID = -2755235774946990126L; | ||||
|  | ||||
| 						private static final long serialVersionUID = -2755235774946990126L; | ||||
|  | ||||
| 						{ | ||||
| 							put("forward selected message", | ||||
| 									evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), | ||||
| 											ContactsChooserDialog | ||||
| 												.showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); | ||||
| 							put("copy", evt -> { | ||||
| 								// TODO should be enhanced to allow also copying of message attachments, | ||||
| 								// especially pictures | ||||
| 								StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); | ||||
| 								Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); | ||||
| 							}); | ||||
| 							// TODO insert implementation to edit and delete messages | ||||
| 							put("delete", evt -> {}); | ||||
| 							put("edit", evt -> {}); | ||||
| 							put("quote", evt -> {}); | ||||
| 						} | ||||
| 					}; | ||||
| 					commands.forEach((name, action) -> { var item = new JMenuItem(name); item.addActionListener(action); contextMenu.add(item); }); | ||||
| 					contextMenu.show(e.getComponent(), e.getX(), e.getY()); | ||||
| 				} | ||||
| 			{ | ||||
| 				put("forward selected message", | ||||
| 						evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), | ||||
| 								ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); | ||||
| 				put("copy", evt -> { | ||||
| 					// TODO should be enhanced to allow also copying of message attachments, | ||||
| 					// especially pictures | ||||
| 					StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); | ||||
| 					Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); | ||||
| 				}); | ||||
| 				// TODO insert implementation to edit and delete messages | ||||
| 				put("delete", evt -> {}); | ||||
| 				put("edit", evt -> {}); | ||||
| 				put("quote", evt -> {}); | ||||
| 			} | ||||
| 		}); | ||||
| 		}; | ||||
| 		contextMenu = new ContextMenu(null, messageList, commands, null, null).build(); | ||||
|  | ||||
| 		scrollPane.setViewportView(messageList); | ||||
| 		scrollPane.addComponentListener(new ComponentAdapter() { | ||||
|  | ||||
| 			// updates list elements when list is resized | ||||
| 			// Update list elements when scroll pane (and thus list) is resized | ||||
| 			@Override | ||||
| 			public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); } | ||||
| 			public void componentResized(ComponentEvent e) { | ||||
| 				messageList.setMaximumSize(new Dimension(scrollPane.getWidth(), Integer.MAX_VALUE)); | ||||
| 				messageList.synchronizeModel(); | ||||
| 			} | ||||
| 		}); | ||||
| 		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); | ||||
|  | ||||
| @@ -600,7 +597,7 @@ public class ChatWindow extends JFrame { | ||||
| 	private void readCurrentChat() { | ||||
| 		try { | ||||
| 			currentChat.read(writeProxy); | ||||
| 			messageList.synchronizeModel(); | ||||
| 			if (messageList.getRenderer() != null) messageList.synchronizeModel(); | ||||
| 		} catch (IOException e) { | ||||
| 			e.printStackTrace(); | ||||
| 			logger.log(Level.WARNING, "Couldn't notify server about message status change", e); | ||||
| @@ -644,6 +641,8 @@ public class ChatWindow extends JFrame { | ||||
| 		this.localDb	= localDb; | ||||
| 		this.writeProxy	= writeProxy; | ||||
|  | ||||
| 		messageList.setRenderer(new MessageListRenderer(client.getSender().getId())); | ||||
|  | ||||
| 		// Load users and chats | ||||
| 		new Thread(() -> { | ||||
| 			localDb.getUsers().values().forEach(user -> { | ||||
|   | ||||
| @@ -31,6 +31,12 @@ public class ComponentList<E> extends JPanel { | ||||
|  | ||||
| 	private static final long serialVersionUID = 1759644503942876737L; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the layout of this {@link ComponentList} to be a vertically oriented | ||||
| 	 * BoxLayout. | ||||
| 	 * | ||||
| 	 * @since Envoy v0.1-beta | ||||
| 	 */ | ||||
| 	public ComponentList() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); } | ||||
|  | ||||
| 	/** | ||||
| @@ -74,7 +80,7 @@ public class ComponentList<E> extends JPanel { | ||||
| 		// Synchronize with new model | ||||
| 		this.model = model; | ||||
| 		if (model != null) this.model.setComponentList(this); | ||||
| 		synchronizeModel(); | ||||
| 		if (renderer != null) synchronizeModel(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -84,9 +90,11 @@ public class ComponentList<E> extends JPanel { | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void synchronizeModel() { | ||||
| 		removeAll(); | ||||
| 		if (model != null) model.forEach(this::add); | ||||
| 		revalidate(); | ||||
| 		if (model != null && renderer != null) { | ||||
| 			removeAll(); | ||||
| 			model.forEach(this::add); | ||||
| 			revalidate(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -112,9 +120,11 @@ public class ComponentList<E> extends JPanel { | ||||
| 			clearSelections(); | ||||
| 			currentSelections.add(index); | ||||
| 		} | ||||
| 		if (renderer != null) { | ||||
| 		final JComponent component = renderer.getListCellComponent(this, elem, isSelected); | ||||
| 		component.addMouseListener(getSelectionListener(index)); | ||||
| 		add(component, index); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -115,6 +115,6 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | ||||
| 	 */ | ||||
| 	void setComponentList(ComponentList<E> componentList) { | ||||
| 		this.componentList = componentList; | ||||
| 		if (componentList != null) componentList.synchronizeModel(); | ||||
| 		if (componentList != null && componentList.getRenderer() != null) componentList.synchronizeModel(); | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 delvh
					delvh