filebot/source/net/filebot/util/ui/ListView.java

188 lines
4.6 KiB
Java

package net.filebot.util.ui;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.FilteredImageSource;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DropMode;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JList;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
public class ListView extends JList {
protected final BlockSelectionHandler blockSelectionHandler = new BlockSelectionHandler();
public ListView(ListModel dataModel) {
super(dataModel);
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
// better selection behaviour
putClientProperty("List.isFileList", Boolean.TRUE);
setDropMode(DropMode.ON);
setLayoutOrientation(JList.VERTICAL_WRAP);
setVisibleRowCount(-1);
setCellRenderer(new ListViewRenderer());
addMouseListener(blockSelectionHandler);
addMouseMotionListener(blockSelectionHandler);
}
public void addSelectionInterval(Rectangle selection) {
Point p1 = selection.getLocation();
Point p2 = new Point(p1.x + selection.width, p1.y + selection.height);
int startIndex = locationToIndex(p1);
int endIndex = locationToIndex(p2);
for (int i = startIndex; i <= endIndex; i++) {
Rectangle cell = getCellBounds(i, i);
if (cell != null && selection.intersects(cell)) {
addSelectionInterval(i, i);
}
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle selection = blockSelectionHandler.getSelection();
// paint block selection
if (selection != null) {
paintBlockSelection((Graphics2D) g, selection);
}
}
protected void paintBlockSelection(Graphics2D g2d, Rectangle selection) {
g2d.setPaint(SwingUI.derive(getSelectionBackground(), 0.3f));
g2d.fill(selection);
g2d.setPaint(getSelectionBackground());
g2d.draw(selection);
}
protected String convertValueToText(Object value) {
return value.toString();
}
protected Icon convertValueToIcon(Object value) {
return null;
}
protected class ListViewRenderer extends DefaultListCellRenderer {
public ListViewRenderer() {
setOpaque(false);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Icon icon = convertValueToIcon(value);
if (isSelected && icon != null) {
// apply selection color tint
icon = new ImageIcon(createImage(new FilteredImageSource(SwingUI.getImage(icon).getSource(), new ColorTintImageFilter(list.getSelectionBackground(), 0.5f))));
}
setText(convertValueToText(value));
setIcon(icon);
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
@Override
protected void paintComponent(Graphics g) {
// paint selection background for the text area only, not the whole cell
int iconWidth = (getIcon() == null ? 0 : getIcon().getIconHeight());
int startX = iconWidth + getIconTextGap();
Rectangle2D text = getFontMetrics(getFont()).getStringBounds(getText(), g);
g.setColor(getBackground());
g.fillRect(startX - 2, 1, (int) (text.getWidth() + 6), getHeight() - 1);
super.paintComponent(g);
}
};
protected class BlockSelectionHandler extends MouseInputAdapter {
private Rectangle selection;
private Point origin;
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && !isSelectedIndex(locationToIndex(e.getPoint()))) {
origin = e.getPoint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (origin == null)
return;
// begin selection
if (selection == null)
selection = new Rectangle();
// keep point within component bounds
Point p2 = e.getPoint();
p2.x = Math.max(0, Math.min(getWidth() - 1, p2.x));
p2.y = Math.max(0, Math.min(getHeight() - 1, p2.y));
// update selection bounds
selection.setFrameFromDiagonal(origin, p2);
// auto-scroll
ensureIndexIsVisible(locationToIndex(p2));
// update list selection
clearSelection();
addSelectionInterval(selection);
// update view
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
origin = null;
// end selection
selection = null;
// update view
repaint();
}
public Rectangle getSelection() {
return selection;
}
};
}