Added SelectionMode enum to ComponentList, prepared integration
These changes are not ready to build yet, as ChatWindow and ContactsChooserDialog have to be adjusted first.
This commit is contained in:
		| @@ -131,12 +131,12 @@ public class ChatWindow extends JFrame { | |||||||
|  |  | ||||||
| 			{ | 			{ | ||||||
| 				put("forward selected message", | 				put("forward selected message", | ||||||
| 						evt -> forwardMessageToMultipleUsers(messageList.getSelected().get(0), | 						evt -> forwardMessageToMultipleUsers(messageList.getSelection().get(0), | ||||||
| 								ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelected().get(0), client))); | 								ContactsChooserDialog.showForwardingDialog("Forward selected message to", messageList.getSelection().get(0), client))); | ||||||
| 				put("copy", evt -> { | 				put("copy", evt -> { | ||||||
| 					// TODO should be enhanced to allow also copying of message attachments, | 					// TODO should be enhanced to allow also copying of message attachments, | ||||||
| 					// especially pictures | 					// especially pictures | ||||||
| 					StringSelection copy = new StringSelection(messageList.getSelected().get(0).getText()); | 					StringSelection copy = new StringSelection(messageList.getSelection().get(0).getText()); | ||||||
| 					Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); | 					Toolkit.getDefaultToolkit().getSystemClipboard().setContents(copy, copy); | ||||||
| 				}); | 				}); | ||||||
| 				// TODO insert implementation to edit and delete messages | 				// TODO insert implementation to edit and delete messages | ||||||
|   | |||||||
| @@ -69,7 +69,7 @@ public class ContactsChooserDialog extends JDialog { | |||||||
| 		dialog.getContentPanel() | 		dialog.getContentPanel() | ||||||
| 			.add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); | 			.add(new MessageListRenderer(client.getSender().getId()).getListCellComponent(null, message, false), BorderLayout.NORTH); | ||||||
| 		List<User> results = new ArrayList<>(); | 		List<User> results = new ArrayList<>(); | ||||||
| 		dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelected()); dialog.dispose(); }); | 		dialog.addOkButtonActionListener(e -> { results.addAll(dialog.getContactList().getSelection()); dialog.dispose(); }); | ||||||
| 		ComponentListModel<User> contactListModel = dialog.getContactList().getModel(); | 		ComponentListModel<User> contactListModel = dialog.getContactList().getModel(); | ||||||
| 		client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); | 		client.getContacts().getContacts().forEach(user -> contactListModel.add(user)); | ||||||
| 		dialog.setVisible(true); | 		dialog.setVisible(true); | ||||||
|   | |||||||
| @@ -3,8 +3,8 @@ package envoy.client.ui.list; | |||||||
| import java.awt.event.MouseAdapter; | import java.awt.event.MouseAdapter; | ||||||
| import java.awt.event.MouseEvent; | import java.awt.event.MouseEvent; | ||||||
| import java.awt.event.MouseListener; | import java.awt.event.MouseListener; | ||||||
| import java.util.ArrayList; | import java.util.HashSet; | ||||||
| import java.util.List; | import java.util.Set; | ||||||
|  |  | ||||||
| import javax.swing.*; | import javax.swing.*; | ||||||
|  |  | ||||||
| @@ -25,15 +25,17 @@ public class ComponentList<E> extends JPanel { | |||||||
|  |  | ||||||
| 	private ComponentListModel<E>			model; | 	private ComponentListModel<E>			model; | ||||||
| 	private ComponentListCellRenderer<E>	renderer; | 	private ComponentListCellRenderer<E>	renderer; | ||||||
| 	private boolean							multipleSelectionEnabled	= false; | 	private SelectionMode					selectionMode	= SelectionMode.NONE; | ||||||
|  | 	private Set<Integer>					selection		= new HashSet<>(); | ||||||
| 	private List<Integer> currentSelections = new ArrayList<>(); |  | ||||||
|  |  | ||||||
| 	private static final long serialVersionUID = 1759644503942876737L; | 	private static final long serialVersionUID = 1759644503942876737L; | ||||||
|  |  | ||||||
|  | 	public static enum SelectionMode { | ||||||
|  | 		NONE, SINGLE, MULTIPLE | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Sets the layout of this {@link ComponentList} to be a vertically oriented | 	 * Initializes a default {@link ComponentList} without a model or a renderer. | ||||||
| 	 * BoxLayout. |  | ||||||
| 	 * | 	 * | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| @@ -79,8 +81,8 @@ public class ComponentList<E> extends JPanel { | |||||||
|  |  | ||||||
| 		// Synchronize with new model | 		// Synchronize with new model | ||||||
| 		this.model = model; | 		this.model = model; | ||||||
| 		if (model != null) this.model.setComponentList(this); | 		if (model != null) model.setComponentList(this); | ||||||
| 		if (renderer != null) synchronizeModel(); | 		synchronizeModel(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -92,11 +94,53 @@ public class ComponentList<E> extends JPanel { | |||||||
| 	public void synchronizeModel() { | 	public void synchronizeModel() { | ||||||
| 		if (model != null && renderer != null) { | 		if (model != null && renderer != null) { | ||||||
| 			removeAll(); | 			removeAll(); | ||||||
| 			model.forEach(this::add); | 			model.forEach(this::addElement); | ||||||
| 			revalidate(); | 			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 v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public void selectElement(int index) { | ||||||
|  | 		if (selection.contains(index)) { | ||||||
|  |  | ||||||
|  | 			// Remove selection of element at index | ||||||
|  | 			updateElement(index, false); | ||||||
|  | 			selection.remove(index); | ||||||
|  | 		} else { | ||||||
|  |  | ||||||
|  | 			// Remove old selection if single selection is enabled | ||||||
|  | 			if (selectionMode == SelectionMode.SINGLE) clearSelection(); | ||||||
|  |  | ||||||
|  | 			if (selectionMode != SelectionMode.NONE) { | ||||||
|  |  | ||||||
|  | 				// Assign new selection | ||||||
|  | 				selection.add(index); | ||||||
|  |  | ||||||
|  | 				// Update element | ||||||
|  | 				updateElement(index, true); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		revalidate(); | ||||||
|  | 		repaint(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Removes the current selection. | ||||||
|  | 	 *  | ||||||
|  | 	 * @since Envoy v0.1-alpha | ||||||
|  | 	 */ | ||||||
|  | 	public void clearSelection() { | ||||||
|  | 		selection.forEach(i -> updateElement(i, false)); | ||||||
|  | 		selection.clear(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Adds an object to the list by rendering it with the current | 	 * Adds an object to the list by rendering it with the current | ||||||
| 	 * {@link ComponentListCellRenderer}. | 	 * {@link ComponentListCellRenderer}. | ||||||
| @@ -104,89 +148,26 @@ public class ComponentList<E> extends JPanel { | |||||||
| 	 * @param elem the element to add | 	 * @param elem the element to add | ||||||
| 	 * @since Envoy v0.3-alpha | 	 * @since Envoy v0.3-alpha | ||||||
| 	 */ | 	 */ | ||||||
| 	void add(E elem) { add(elem, getComponentCount(), false); } | 	void addElement(E elem) { addElement(elem, getComponentCount(), false); } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Adds an object to the list by rendering it with the current | 	 * Adds an object to the list by rendering it with the current | ||||||
| 	 * {@link ComponentListRenderer}. | 	 * {@link ComponentListRenderer}. If the renderer is {@code null}, no action is | ||||||
|  | 	 * performed. | ||||||
| 	 * | 	 * | ||||||
| 	 * @param elem       the element to add | 	 * @param elem       the element to add | ||||||
| 	 * @param index      the index at which to add the element | 	 * @param index      the index at which to add the element | ||||||
| 	 * @param isSelected the selection state of the element | 	 * @param isSelected the selection state of the element | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void add(E elem, int index, boolean isSelected) { | 	private void addElement(E elem, int index, boolean isSelected) { | ||||||
| 		if (isSelected && !multipleSelectionEnabled) { |  | ||||||
| 			clearSelections(); |  | ||||||
| 			currentSelections.add(index); |  | ||||||
| 		} |  | ||||||
| 		if (renderer != null) { | 		if (renderer != null) { | ||||||
| 		final JComponent component = renderer.getListCellComponent(this, elem, isSelected); | 			final JComponent component = renderer.getListCellComponent(this, elem, isSelected); | ||||||
| 		component.addMouseListener(getSelectionListener(index)); | 			component.addMouseListener(getSelectionListener(index)); | ||||||
| 		add(component, index); | 			add(component, index); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @param componentIndex the index of the list component to which the mouse |  | ||||||
| 	 *                       listener will be added |  | ||||||
| 	 * @return a mouse listener calling the |  | ||||||
| 	 *         {@link ComponentList#componentSelected(int)} method with the |  | ||||||
| 	 *         component's index when a left click is performed by the user |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	private MouseListener getSelectionListener(int componentIndex) { |  | ||||||
| 		return new MouseAdapter() { |  | ||||||
|  |  | ||||||
| 			@Override |  | ||||||
| 			public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); } |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Gets called when a list component has been clicked on by the user. Any |  | ||||||
| 	 * previous selections are then removed and the selected component gets |  | ||||||
| 	 * redrawn.<br> |  | ||||||
| 	 * <br> |  | ||||||
| 	 * If the currently selected component gets selected again, the selection is |  | ||||||
| 	 * removed. |  | ||||||
| 	 * |  | ||||||
| 	 * @param index the index of the selected component |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	private void componentSelected(int index) { |  | ||||||
| 		// removing selection of element at index |  | ||||||
| 		if (currentSelections.contains(index)) { |  | ||||||
|  |  | ||||||
| 			// Clear selection |  | ||||||
| 			updateSelection(index, false); |  | ||||||
| 			currentSelections.remove(Integer.valueOf(index)); |  | ||||||
| 		} else { |  | ||||||
|  |  | ||||||
| 			// Remove old selection if multipleSelection is disabled |  | ||||||
| 			if (!multipleSelectionEnabled && currentSelections.size() > 0) clearSelections(); |  | ||||||
|  |  | ||||||
| 			// Assign new selection |  | ||||||
| 			currentSelections.add(index); |  | ||||||
|  |  | ||||||
| 			// Update current selection |  | ||||||
| 			updateSelection(index, true); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		revalidate(); |  | ||||||
| 		repaint(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Clears all currently active selections. |  | ||||||
| 	 * |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	private void clearSelections() { |  | ||||||
| 		currentSelections.forEach(index -> updateSelection(index, false)); |  | ||||||
| 		currentSelections.clear(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * Replaces a list element with a newly rendered instance of its contents. | 	 * Replaces a list element with a newly rendered instance of its contents. | ||||||
| 	 * | 	 * | ||||||
| @@ -194,21 +175,33 @@ public class ComponentList<E> extends JPanel { | |||||||
| 	 * @param isSelected the selection state passed to the {@link ListCellRenderer} | 	 * @param isSelected the selection state passed to the {@link ListCellRenderer} | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void updateSelection(int index, boolean isSelected) { | 	private void updateElement(int index, boolean isSelected) { | ||||||
| 		remove(index); | 		remove(index); | ||||||
| 		add(model.get(index), index, isSelected); | 		addElement(model.get(index), index, isSelected); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the selected elements or null if none is selected | 	 * @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 v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public List<E> getSelected() { | 	private MouseListener getSelectionListener(int componentIndex) { | ||||||
| 		List<E> selected = new ArrayList<>(); | 		return new MouseAdapter() { | ||||||
| 		currentSelections.forEach(index -> selected.add(model.get(index))); |  | ||||||
| 		return selected; | 			@Override | ||||||
|  | 			public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) selectElement(componentIndex); } | ||||||
|  | 		}; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @return a set of all selected indices | ||||||
|  | 	 * @since Envoy v0.1-beta | ||||||
|  | 	 */ | ||||||
|  | 	public Set<Integer> getSelection() { return selection; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the model | 	 * @return the model | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| @@ -228,37 +221,14 @@ public class ComponentList<E> extends JPanel { | |||||||
| 	public void setRenderer(ComponentListCellRenderer<E> renderer) { this.renderer = renderer; } | 	public void setRenderer(ComponentListCellRenderer<E> renderer) { this.renderer = renderer; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the multipleSelectionEnabled | 	 * @return the selectionMode | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean isMultipleSelectionEnabled() { return multipleSelectionEnabled; } | 	public SelectionMode getSelectionMode() { return selectionMode; } | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @param multipleSelectionEnabled if true, multiple elements can be selected in | 	 * @param selectionMode the selectionMode to set | ||||||
| 	 *                                 the component list |  | ||||||
| 	 * @since Envoy v0.1-beta | 	 * @since Envoy v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { | 	public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } | ||||||
| 		this.multipleSelectionEnabled = multipleSelectionEnabled; |  | ||||||
| 		if (!multipleSelectionEnabled) clearSelections(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Enables the selection of multiple elements. |  | ||||||
| 	 * |  | ||||||
| 	 * @see ComponentList#disableMultipleSelection |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	public void enableMultipleSelection() { this.multipleSelectionEnabled = true; } |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Allows only one element to be selected. True by default. |  | ||||||
| 	 * |  | ||||||
| 	 * @see ComponentList#enableMultipleSelection |  | ||||||
| 	 * @since Envoy v0.1-beta |  | ||||||
| 	 */ |  | ||||||
| 	public void disableMultipleSelection() { |  | ||||||
| 		this.multipleSelectionEnabled = false; |  | ||||||
| 		clearSelections(); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable { | |||||||
| 	 */ | 	 */ | ||||||
| 	public boolean add(E e) { | 	public boolean add(E e) { | ||||||
| 		if (componentList != null) { | 		if (componentList != null) { | ||||||
| 			componentList.add(e); | 			componentList.addElement(e); | ||||||
| 			componentList.revalidate(); | 			componentList.revalidate(); | ||||||
| 		} | 		} | ||||||
| 		return elements.add(e); | 		return elements.add(e); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user