205 lines
4.7 KiB
Java
205 lines
4.7 KiB
Java
|
|
package net.sourceforge.tuned.ui;
|
|
|
|
|
|
import static java.lang.Math.*;
|
|
|
|
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(TunedUtilities.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(TunedUtilities.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;
|
|
|
|
|
|
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 = max(0, min(getWidth() - 1, p2.x));
|
|
p2.y = max(0, 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;
|
|
}
|
|
};
|
|
|
|
}
|