|  |  |  | @@ -3,8 +3,8 @@ package envoy.client.ui.list; | 
		
	
		
			
				|  |  |  |  | import java.awt.event.MouseAdapter; | 
		
	
		
			
				|  |  |  |  | import java.awt.event.MouseEvent; | 
		
	
		
			
				|  |  |  |  | import java.awt.event.MouseListener; | 
		
	
		
			
				|  |  |  |  | import java.util.ArrayList; | 
		
	
		
			
				|  |  |  |  | import java.util.List; | 
		
	
		
			
				|  |  |  |  | import java.util.HashSet; | 
		
	
		
			
				|  |  |  |  | import java.util.Set; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | import javax.swing.*; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -25,15 +25,17 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	private ComponentListModel<E>			model; | 
		
	
		
			
				|  |  |  |  | 	private ComponentListCellRenderer<E>	renderer; | 
		
	
		
			
				|  |  |  |  | 	private boolean							multipleSelectionEnabled	= false; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	private List<Integer> currentSelections = new ArrayList<>(); | 
		
	
		
			
				|  |  |  |  | 	private SelectionMode					selectionMode	= SelectionMode.NONE; | 
		
	
		
			
				|  |  |  |  | 	private Set<Integer>					selection		= new HashSet<>(); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	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 | 
		
	
		
			
				|  |  |  |  | 	 * BoxLayout. | 
		
	
		
			
				|  |  |  |  | 	 * Initializes a default {@link ComponentList} without a model or a renderer. | 
		
	
		
			
				|  |  |  |  | 	 * | 
		
	
		
			
				|  |  |  |  | 	 * @since Envoy v0.1-beta | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -79,8 +81,8 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		// Synchronize with new model | 
		
	
		
			
				|  |  |  |  | 		this.model = model; | 
		
	
		
			
				|  |  |  |  | 		if (model != null) this.model.setComponentList(this); | 
		
	
		
			
				|  |  |  |  | 		if (renderer != null) synchronizeModel(); | 
		
	
		
			
				|  |  |  |  | 		if (model != null) model.setComponentList(this); | 
		
	
		
			
				|  |  |  |  | 		synchronizeModel(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/** | 
		
	
	
		
			
				
					
					|  |  |  | @@ -92,11 +94,53 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  | 	public void synchronizeModel() { | 
		
	
		
			
				|  |  |  |  | 		if (model != null && renderer != null) { | 
		
	
		
			
				|  |  |  |  | 			removeAll(); | 
		
	
		
			
				|  |  |  |  | 			model.forEach(this::add); | 
		
	
		
			
				|  |  |  |  | 			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 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 | 
		
	
		
			
				|  |  |  |  | 	 * {@link ComponentListCellRenderer}. | 
		
	
	
		
			
				
					
					|  |  |  | @@ -104,22 +148,19 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  | 	 * @param elem the element to add | 
		
	
		
			
				|  |  |  |  | 	 * @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 | 
		
	
		
			
				|  |  |  |  | 	 * {@link ComponentListRenderer}. | 
		
	
		
			
				|  |  |  |  | 	 * {@link ComponentListRenderer}. If the renderer is {@code null}, no action is | 
		
	
		
			
				|  |  |  |  | 	 * performed. | 
		
	
		
			
				|  |  |  |  | 	 * | 
		
	
		
			
				|  |  |  |  | 	 * @param elem       the element to add | 
		
	
		
			
				|  |  |  |  | 	 * @param index      the index at which to add the element | 
		
	
		
			
				|  |  |  |  | 	 * @param isSelected the selection state of the element | 
		
	
		
			
				|  |  |  |  | 	 * @since Envoy v0.1-beta | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	private void add(E elem, int index, boolean isSelected) { | 
		
	
		
			
				|  |  |  |  | 		if (isSelected && !multipleSelectionEnabled) { | 
		
	
		
			
				|  |  |  |  | 			clearSelections(); | 
		
	
		
			
				|  |  |  |  | 			currentSelections.add(index); | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	private void addElement(E elem, int index, boolean isSelected) { | 
		
	
		
			
				|  |  |  |  | 		if (renderer != null) { | 
		
	
		
			
				|  |  |  |  | 			final JComponent component = renderer.getListCellComponent(this, elem, isSelected); | 
		
	
		
			
				|  |  |  |  | 			component.addMouseListener(getSelectionListener(index)); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -127,66 +168,6 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/** | 
		
	
		
			
				|  |  |  |  | 	 * @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. | 
		
	
		
			
				|  |  |  |  | 	 * | 
		
	
	
		
			
				
					
					|  |  |  | @@ -194,21 +175,33 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  | 	 * @param isSelected the selection state passed to the {@link ListCellRenderer} | 
		
	
		
			
				|  |  |  |  | 	 * @since Envoy v0.1-beta | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	private void updateSelection(int index, boolean isSelected) { | 
		
	
		
			
				|  |  |  |  | 	private void updateElement(int index, boolean isSelected) { | 
		
	
		
			
				|  |  |  |  | 		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 | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	public List<E> getSelected() { | 
		
	
		
			
				|  |  |  |  | 		List<E> selected = new ArrayList<>(); | 
		
	
		
			
				|  |  |  |  | 		currentSelections.forEach(index -> selected.add(model.get(index))); | 
		
	
		
			
				|  |  |  |  | 		return selected; | 
		
	
		
			
				|  |  |  |  | 	private MouseListener getSelectionListener(int componentIndex) { | 
		
	
		
			
				|  |  |  |  | 		return new MouseAdapter() { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			@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 | 
		
	
		
			
				|  |  |  |  | 	 * @since Envoy v0.1-beta | 
		
	
	
		
			
				
					
					|  |  |  | @@ -228,37 +221,14 @@ public class ComponentList<E> extends JPanel { | 
		
	
		
			
				|  |  |  |  | 	public void setRenderer(ComponentListCellRenderer<E> renderer) { this.renderer = renderer; } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	/** | 
		
	
		
			
				|  |  |  |  | 	 * @return the multipleSelectionEnabled | 
		
	
		
			
				|  |  |  |  | 	 * @return the selectionMode | 
		
	
		
			
				|  |  |  |  | 	 * @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 | 
		
	
		
			
				|  |  |  |  | 	 *                                 the component list | 
		
	
		
			
				|  |  |  |  | 	 * @param selectionMode the selectionMode to set | 
		
	
		
			
				|  |  |  |  | 	 * @since Envoy v0.1-beta | 
		
	
		
			
				|  |  |  |  | 	 */ | 
		
	
		
			
				|  |  |  |  | 	public void setMultipleSelectionEnabled(boolean multipleSelectionEnabled) { | 
		
	
		
			
				|  |  |  |  | 		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(); | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	public void setSelectionMode(SelectionMode selectionMode) { this.selectionMode = selectionMode; } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  |   |