This repository has been archived on 2021-12-05. You can view files and clone it, but cannot push or open issues or pull requests.
envoy/src/main/java/envoy/client/ui/list/ComponentList.java

262 lines
6.8 KiB
Java

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.<br>
* <br>
* Project: <strong>envoy-client</strong><br>
* File: <strong>ComponentList.java</strong><br>
* Created: <strong>25.01.2020</strong><br>
*
* @param <E> the type of object displayed in this list
* @author Kai S. K. Engelbart
* @since Envoy Client v0.3-alpha
*/
public class ComponentList<E> extends JPanel {
private Model<E> model;
private Renderer<E> renderer;
private SelectionHandler<E> selectionHandler;
private SelectionMode selectionMode = SelectionMode.NONE;
private Set<Integer> 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<Integer> getSelection() { return selection; }
/**
* @return a set of all selected elements
* @since Envoy Client v0.1-beta
*/
public Set<E> getSelectedElements() {
var selectedElements = new HashSet<E>();
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<E> 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<E> setModel(Model<E> 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<E> getRenderer() { return renderer; }
/**
* @param renderer the renderer to set
* @return this component list
* @since Envoy Client v0.1-beta
*/
public ComponentList<E> setRenderer(Renderer<E> 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<E> setSelectionMode(SelectionMode selectionMode) {
this.selectionMode = selectionMode;
clearSelection();
return this;
}
/**
* @return the selection handler
* @since Envoy Client v0.1-beta
*/
public SelectionHandler<E> getSelectionHandler() { return selectionHandler; }
/**
* @param selectionHandler the selection handler to set
* @since Envoy Client v0.1-beta
*/
public void setSelectionHandler(SelectionHandler<E> selectionHandler) { this.selectionHandler = selectionHandler; }
}