Code
@Override public void setSelectionInterval(int anchor, int lead) {
if (checkedIndex < 0 && isDragging()) {
super.setSelectionInterval(anchor, lead);
} else {
EventQueue.invokeLater(() -> {
if (checkedIndex >= 0 && lead == anchor && checkedIndex == anchor) {
super.addSelectionInterval(checkedIndex, checkedIndex);
} else {
super.setSelectionInterval(anchor, lead);
}
});
}
}
protected boolean isDragging() {
Rectangle r = getRubberBand().getBounds();
return r.width != 0 || r.height != 0;
}
@Override public void removeSelectionInterval(int index0, int index1) {
if (checkedIndex < 0) {
super.removeSelectionInterval(index0, index1);
} else {
EventQueue.invokeLater(() -> super.removeSelectionInterval(index0, index1));
}
}
private static <E> Optional<AbstractButton> getItemCheckBox(
JList<E> list, MouseEvent e, int index) {
if (e.isShiftDown() || e.isControlDown() || e.isAltDown()) {
return Optional.empty();
}
E proto = list.getPrototypeCellValue();
ListCellRenderer<? super E> cr = list.getCellRenderer();
Component c = cr.getListCellRendererComponent(
list, proto, index, false, false);
Rectangle r = list.getCellBounds(index, index);
c.setBounds(r);
Point pt = e.getPoint();
pt.translate(-r.x, -r.y);
return Optional
.ofNullable(SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y))
.filter(AbstractButton.class::isInstance)
.map(AbstractButton.class::cast);
}
private final class ItemCheckBoxesListener extends MouseAdapter {
private final Point srcPoint = new Point();
@Override public void mouseDragged(MouseEvent e) {
checkedIndex = -1;
JList<?> l = (JList<?>) e.getComponent();
l.setFocusable(true);
Point destPoint = e.getPoint();
Path2D rb = getRubberBand();
rb.reset();
rb.moveTo(srcPoint.x, srcPoint.y);
rb.lineTo(destPoint.x, srcPoint.y);
rb.lineTo(destPoint.x, destPoint.y);
rb.lineTo(srcPoint.x, destPoint.y);
rb.closePath();
int[] indices = IntStream.range(0, l.getModel().getSize())
.filter(i -> rb.intersects(l.getCellBounds(i, i))).toArray();
l.setSelectedIndices(indices);
l.repaint();
}
@Override public void mouseExited(MouseEvent e) {
rollOverIndex = -1;
e.getComponent().repaint();
}
@Override public void mouseMoved(MouseEvent e) {
Point pt = e.getPoint();
int idx = locationToIndex(pt);
if (!getCellBounds(idx, idx).contains(pt)) {
idx = -1;
}
Rectangle rect = new Rectangle();
if (idx > 0) {
rect.add(getCellBounds(idx, idx));
if (rollOverIndex >= 0 && idx != rollOverIndex) {
rect.add(getCellBounds(rollOverIndex, rollOverIndex));
}
rollOverIndex = idx;
} else {
if (rollOverIndex >= 0) {
rect.add(getCellBounds(rollOverIndex, rollOverIndex));
}
rollOverIndex = -1;
}
((JComponent) e.getComponent()).repaint(rect);
}
@Override public void mouseReleased(MouseEvent e) {
getRubberBand().reset();
Component c = e.getComponent();
c.setFocusable(true);
c.repaint();
}
@Override public void mousePressed(MouseEvent e) {
JList<?> l = (JList<?>) e.getComponent();
int index = l.locationToIndex(e.getPoint());
if (l.getCellBounds(index, index).contains(e.getPoint())) {
l.setFocusable(true);
cellPressed(l, e, index);
} else {
l.setFocusable(false);
l.clearSelection();
l.getSelectionModel().setAnchorSelectionIndex(-1);
l.getSelectionModel().setLeadSelectionIndex(-1);
}
srcPoint.setLocation(e.getPoint());
l.repaint();
}
private void cellPressed(JList<?> l, MouseEvent e, int index) {
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() > 1) {
ListItem item = getModel().getElementAt(index);
JOptionPane.showMessageDialog(l.getRootPane(), item.title);
} else {
checkedIndex = -1;
getItemCheckBox(l, e.getPoint(), index).ifPresent(rb -> {
checkedIndex = index;
if (l.isSelectedIndex(index)) {
l.setFocusable(false);
removeSelectionInterval(index, index);
} else {
setSelectionInterval(index, index);
}
});
}
}
}
References