|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package javax.swing.plaf.basic; |
|
|
|
import sun.swing.DefaultLookup; |
|
import sun.swing.UIAction; |
|
|
|
import javax.swing.*; |
|
import javax.swing.event.*; |
|
import javax.swing.plaf.*; |
|
import javax.swing.text.Position; |
|
|
|
import java.awt.*; |
|
import java.awt.event.*; |
|
import java.awt.datatransfer.Transferable; |
|
import java.awt.geom.Point2D; |
|
|
|
import java.beans.PropertyChangeListener; |
|
import java.beans.PropertyChangeEvent; |
|
|
|
import sun.swing.SwingUtilities2; |
|
import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class BasicListUI extends ListUI |
|
{ |
|
private static final StringBuilder BASELINE_COMPONENT_KEY = |
|
new StringBuilder("List.baselineComponent"); |
|
|
|
protected JList list = null; |
|
protected CellRendererPane rendererPane; |
|
|
|
|
|
protected FocusListener focusListener; |
|
protected MouseInputListener mouseInputListener; |
|
protected ListSelectionListener listSelectionListener; |
|
protected ListDataListener listDataListener; |
|
protected PropertyChangeListener propertyChangeListener; |
|
private Handler handler; |
|
|
|
protected int[] cellHeights = null; |
|
protected int cellHeight = -1; |
|
protected int cellWidth = -1; |
|
protected int updateLayoutStateNeeded = modelChanged; |
|
|
|
|
|
|
|
*/ |
|
private int listHeight; |
|
|
|
|
|
|
|
|
|
*/ |
|
private int listWidth; |
|
|
|
|
|
|
|
*/ |
|
private int layoutOrientation; |
|
|
|
// Following ivars are used if the list is laying out horizontally |
|
|
|
|
|
|
|
*/ |
|
private int columnCount; |
|
|
|
|
|
|
|
*/ |
|
private int preferredHeight; |
|
|
|
|
|
|
|
*/ |
|
private int rowsPerColumn; |
|
|
|
|
|
|
|
|
|
*/ |
|
private long timeFactor = 1000L; |
|
|
|
|
|
|
|
*/ |
|
private boolean isFileList = false; |
|
|
|
|
|
|
|
*/ |
|
private boolean isLeftToRight = true; |
|
|
|
/* The bits below define JList property changes that affect layout. |
|
* When one of these properties changes we set a bit in |
|
* updateLayoutStateNeeded. The change is dealt with lazily, see |
|
* maybeUpdateLayoutState. Changes to the JLists model, e.g. the |
|
* models length changed, are handled similarly, see DataListener. |
|
*/ |
|
|
|
protected final static int modelChanged = 1 << 0; |
|
protected final static int selectionModelChanged = 1 << 1; |
|
protected final static int fontChanged = 1 << 2; |
|
protected final static int fixedCellWidthChanged = 1 << 3; |
|
protected final static int fixedCellHeightChanged = 1 << 4; |
|
protected final static int prototypeCellValueChanged = 1 << 5; |
|
protected final static int cellRendererChanged = 1 << 6; |
|
private final static int layoutOrientationChanged = 1 << 7; |
|
private final static int heightChanged = 1 << 8; |
|
private final static int widthChanged = 1 << 9; |
|
private final static int componentOrientationChanged = 1 << 10; |
|
|
|
private static final int DROP_LINE_THICKNESS = 2; |
|
|
|
static void loadActionMap(LazyActionMap map) { |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN)); |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_COLUMN_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_NEXT_COLUMN)); |
|
map.put(new Actions(Actions.SELECT_NEXT_COLUMN_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_NEXT_COLUMN_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_ROW)); |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_ROW_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_PREVIOUS_ROW_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_NEXT_ROW)); |
|
map.put(new Actions(Actions.SELECT_NEXT_ROW_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_NEXT_ROW_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_FIRST_ROW)); |
|
map.put(new Actions(Actions.SELECT_FIRST_ROW_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_FIRST_ROW_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_LAST_ROW)); |
|
map.put(new Actions(Actions.SELECT_LAST_ROW_EXTEND)); |
|
map.put(new Actions(Actions.SELECT_LAST_ROW_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SCROLL_UP)); |
|
map.put(new Actions(Actions.SCROLL_UP_EXTEND)); |
|
map.put(new Actions(Actions.SCROLL_UP_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SCROLL_DOWN)); |
|
map.put(new Actions(Actions.SCROLL_DOWN_EXTEND)); |
|
map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_LEAD)); |
|
map.put(new Actions(Actions.SELECT_ALL)); |
|
map.put(new Actions(Actions.CLEAR_SELECTION)); |
|
map.put(new Actions(Actions.ADD_TO_SELECTION)); |
|
map.put(new Actions(Actions.TOGGLE_AND_ANCHOR)); |
|
map.put(new Actions(Actions.EXTEND_TO)); |
|
map.put(new Actions(Actions.MOVE_SELECTION_TO)); |
|
|
|
map.put(TransferHandler.getCutAction().getValue(Action.NAME), |
|
TransferHandler.getCutAction()); |
|
map.put(TransferHandler.getCopyAction().getValue(Action.NAME), |
|
TransferHandler.getCopyAction()); |
|
map.put(TransferHandler.getPasteAction().getValue(Action.NAME), |
|
TransferHandler.getPasteAction()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void paintCell( |
|
Graphics g, |
|
int row, |
|
Rectangle rowBounds, |
|
ListCellRenderer cellRenderer, |
|
ListModel dataModel, |
|
ListSelectionModel selModel, |
|
int leadIndex) |
|
{ |
|
Object value = dataModel.getElementAt(row); |
|
boolean cellHasFocus = list.hasFocus() && (row == leadIndex); |
|
boolean isSelected = selModel.isSelectedIndex(row); |
|
|
|
Component rendererComponent = |
|
cellRenderer.getListCellRendererComponent(list, value, row, isSelected, cellHasFocus); |
|
|
|
int cx = rowBounds.x; |
|
int cy = rowBounds.y; |
|
int cw = rowBounds.width; |
|
int ch = rowBounds.height; |
|
|
|
if (isFileList) { |
|
// Shrink renderer to preferred size. This is mostly used on Windows |
|
// where selection is only shown around the file name, instead of |
|
|
|
int w = Math.min(cw, rendererComponent.getPreferredSize().width + 4); |
|
if (!isLeftToRight) { |
|
cx += (cw - w); |
|
} |
|
cw = w; |
|
} |
|
|
|
rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void paint(Graphics g, JComponent c) { |
|
Shape clip = g.getClip(); |
|
paintImpl(g, c); |
|
g.setClip(clip); |
|
|
|
paintDropLine(g); |
|
} |
|
|
|
private void paintImpl(Graphics g, JComponent c) |
|
{ |
|
switch (layoutOrientation) { |
|
case JList.VERTICAL_WRAP: |
|
if (list.getHeight() != listHeight) { |
|
updateLayoutStateNeeded |= heightChanged; |
|
redrawList(); |
|
} |
|
break; |
|
case JList.HORIZONTAL_WRAP: |
|
if (list.getWidth() != listWidth) { |
|
updateLayoutStateNeeded |= widthChanged; |
|
redrawList(); |
|
} |
|
break; |
|
default: |
|
break; |
|
} |
|
maybeUpdateLayoutState(); |
|
|
|
ListCellRenderer renderer = list.getCellRenderer(); |
|
ListModel dataModel = list.getModel(); |
|
ListSelectionModel selModel = list.getSelectionModel(); |
|
int size; |
|
|
|
if ((renderer == null) || (size = dataModel.getSize()) == 0) { |
|
return; |
|
} |
|
|
|
|
|
Rectangle paintBounds = g.getClipBounds(); |
|
|
|
int startColumn, endColumn; |
|
if (c.getComponentOrientation().isLeftToRight()) { |
|
startColumn = convertLocationToColumn(paintBounds.x, |
|
paintBounds.y); |
|
endColumn = convertLocationToColumn(paintBounds.x + |
|
paintBounds.width, |
|
paintBounds.y); |
|
} else { |
|
startColumn = convertLocationToColumn(paintBounds.x + |
|
paintBounds.width, |
|
paintBounds.y); |
|
endColumn = convertLocationToColumn(paintBounds.x, |
|
paintBounds.y); |
|
} |
|
int maxY = paintBounds.y + paintBounds.height; |
|
int leadIndex = adjustIndex(list.getLeadSelectionIndex(), list); |
|
int rowIncrement = (layoutOrientation == JList.HORIZONTAL_WRAP) ? |
|
columnCount : 1; |
|
|
|
|
|
for (int colCounter = startColumn; colCounter <= endColumn; |
|
colCounter++) { |
|
|
|
int row = convertLocationToRowInColumn(paintBounds.y, colCounter); |
|
int rowCount = getRowCount(colCounter); |
|
int index = getModelIndex(colCounter, row); |
|
Rectangle rowBounds = getCellBounds(list, index, index); |
|
|
|
if (rowBounds == null) { |
|
|
|
return; |
|
} |
|
while (row < rowCount && rowBounds.y < maxY && |
|
index < size) { |
|
rowBounds.height = getHeight(colCounter, row); |
|
g.setClip(rowBounds.x, rowBounds.y, rowBounds.width, |
|
rowBounds.height); |
|
g.clipRect(paintBounds.x, paintBounds.y, paintBounds.width, |
|
paintBounds.height); |
|
paintCell(g, index, rowBounds, renderer, dataModel, selModel, |
|
leadIndex); |
|
rowBounds.y += rowBounds.height; |
|
index += rowIncrement; |
|
row++; |
|
} |
|
} |
|
|
|
rendererPane.removeAll(); |
|
} |
|
|
|
private void paintDropLine(Graphics g) { |
|
JList.DropLocation loc = list.getDropLocation(); |
|
if (loc == null || !loc.isInsert()) { |
|
return; |
|
} |
|
|
|
Color c = DefaultLookup.getColor(list, this, "List.dropLineColor", null); |
|
if (c != null) { |
|
g.setColor(c); |
|
Rectangle rect = getDropLineRect(loc); |
|
g.fillRect(rect.x, rect.y, rect.width, rect.height); |
|
} |
|
} |
|
|
|
private Rectangle getDropLineRect(JList.DropLocation loc) { |
|
int size = list.getModel().getSize(); |
|
|
|
if (size == 0) { |
|
Insets insets = list.getInsets(); |
|
if (layoutOrientation == JList.HORIZONTAL_WRAP) { |
|
if (isLeftToRight) { |
|
return new Rectangle(insets.left, insets.top, DROP_LINE_THICKNESS, 20); |
|
} else { |
|
return new Rectangle(list.getWidth() - DROP_LINE_THICKNESS - insets.right, |
|
insets.top, DROP_LINE_THICKNESS, 20); |
|
} |
|
} else { |
|
return new Rectangle(insets.left, insets.top, |
|
list.getWidth() - insets.left - insets.right, |
|
DROP_LINE_THICKNESS); |
|
} |
|
} |
|
|
|
Rectangle rect = null; |
|
int index = loc.getIndex(); |
|
boolean decr = false; |
|
|
|
if (layoutOrientation == JList.HORIZONTAL_WRAP) { |
|
if (index == size) { |
|
decr = true; |
|
} else if (index != 0 && convertModelToRow(index) |
|
!= convertModelToRow(index - 1)) { |
|
|
|
Rectangle prev = getCellBounds(list, index - 1); |
|
Rectangle me = getCellBounds(list, index); |
|
Point p = loc.getDropPoint(); |
|
|
|
if (isLeftToRight) { |
|
decr = Point2D.distance(prev.x + prev.width, |
|
prev.y + (int)(prev.height / 2.0), |
|
p.x, p.y) |
|
< Point2D.distance(me.x, |
|
me.y + (int)(me.height / 2.0), |
|
p.x, p.y); |
|
} else { |
|
decr = Point2D.distance(prev.x, |
|
prev.y + (int)(prev.height / 2.0), |
|
p.x, p.y) |
|
< Point2D.distance(me.x + me.width, |
|
me.y + (int)(prev.height / 2.0), |
|
p.x, p.y); |
|
} |
|
} |
|
|
|
if (decr) { |
|
index--; |
|
rect = getCellBounds(list, index); |
|
if (isLeftToRight) { |
|
rect.x += rect.width; |
|
} else { |
|
rect.x -= DROP_LINE_THICKNESS; |
|
} |
|
} else { |
|
rect = getCellBounds(list, index); |
|
if (!isLeftToRight) { |
|
rect.x += rect.width - DROP_LINE_THICKNESS; |
|
} |
|
} |
|
|
|
if (rect.x >= list.getWidth()) { |
|
rect.x = list.getWidth() - DROP_LINE_THICKNESS; |
|
} else if (rect.x < 0) { |
|
rect.x = 0; |
|
} |
|
|
|
rect.width = DROP_LINE_THICKNESS; |
|
} else if (layoutOrientation == JList.VERTICAL_WRAP) { |
|
if (index == size) { |
|
index--; |
|
rect = getCellBounds(list, index); |
|
rect.y += rect.height; |
|
} else if (index != 0 && convertModelToColumn(index) |
|
!= convertModelToColumn(index - 1)) { |
|
|
|
Rectangle prev = getCellBounds(list, index - 1); |
|
Rectangle me = getCellBounds(list, index); |
|
Point p = loc.getDropPoint(); |
|
if (Point2D.distance(prev.x + (int)(prev.width / 2.0), |
|
prev.y + prev.height, |
|
p.x, p.y) |
|
< Point2D.distance(me.x + (int)(me.width / 2.0), |
|
me.y, |
|
p.x, p.y)) { |
|
|
|
index--; |
|
rect = getCellBounds(list, index); |
|
rect.y += rect.height; |
|
} else { |
|
rect = getCellBounds(list, index); |
|
} |
|
} else { |
|
rect = getCellBounds(list, index); |
|
} |
|
|
|
if (rect.y >= list.getHeight()) { |
|
rect.y = list.getHeight() - DROP_LINE_THICKNESS; |
|
} |
|
|
|
rect.height = DROP_LINE_THICKNESS; |
|
} else { |
|
if (index == size) { |
|
index--; |
|
rect = getCellBounds(list, index); |
|
rect.y += rect.height; |
|
} else { |
|
rect = getCellBounds(list, index); |
|
} |
|
|
|
if (rect.y >= list.getHeight()) { |
|
rect.y = list.getHeight() - DROP_LINE_THICKNESS; |
|
} |
|
|
|
rect.height = DROP_LINE_THICKNESS; |
|
} |
|
|
|
return rect; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getBaseline(JComponent c, int width, int height) { |
|
super.getBaseline(c, width, height); |
|
int rowHeight = list.getFixedCellHeight(); |
|
UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults(); |
|
Component renderer = (Component)lafDefaults.get( |
|
BASELINE_COMPONENT_KEY); |
|
if (renderer == null) { |
|
ListCellRenderer lcr = (ListCellRenderer)UIManager.get( |
|
"List.cellRenderer"); |
|
|
|
// fix for 6711072 some LAFs like Nimbus do not provide this |
|
|
|
if (lcr == null) { |
|
lcr = new DefaultListCellRenderer(); |
|
} |
|
renderer = lcr.getListCellRendererComponent( |
|
list, "a", -1, false, false); |
|
lafDefaults.put(BASELINE_COMPONENT_KEY, renderer); |
|
} |
|
renderer.setFont(list.getFont()); |
|
// JList actually has much more complex behavior here. |
|
// If rowHeight != -1 the rowHeight is either the max of all cell |
|
// heights (layout orientation != VERTICAL), or is variable depending |
|
// upon the cell. We assume a default size. |
|
// We could theoretically query the real renderer, but that would |
|
// not work for an empty model and the results may vary with |
|
|
|
if (rowHeight == -1) { |
|
rowHeight = renderer.getPreferredSize().height; |
|
} |
|
return renderer.getBaseline(Integer.MAX_VALUE, rowHeight) + |
|
list.getInsets().top; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Component.BaselineResizeBehavior getBaselineResizeBehavior( |
|
JComponent c) { |
|
super.getBaselineResizeBehavior(c); |
|
return Component.BaselineResizeBehavior.CONSTANT_ASCENT; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Dimension getPreferredSize(JComponent c) { |
|
maybeUpdateLayoutState(); |
|
|
|
int lastRow = list.getModel().getSize() - 1; |
|
if (lastRow < 0) { |
|
return new Dimension(0, 0); |
|
} |
|
|
|
Insets insets = list.getInsets(); |
|
int width = cellWidth * columnCount + insets.left + insets.right; |
|
int height; |
|
|
|
if (layoutOrientation != JList.VERTICAL) { |
|
height = preferredHeight; |
|
} |
|
else { |
|
Rectangle bounds = getCellBounds(list, lastRow); |
|
|
|
if (bounds != null) { |
|
height = bounds.y + bounds.height + insets.bottom; |
|
} |
|
else { |
|
height = 0; |
|
} |
|
} |
|
return new Dimension(width, height); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void selectPreviousIndex() { |
|
int s = list.getSelectedIndex(); |
|
if(s > 0) { |
|
s -= 1; |
|
list.setSelectedIndex(s); |
|
list.ensureIndexIsVisible(s); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void selectNextIndex() |
|
{ |
|
int s = list.getSelectedIndex(); |
|
if((s + 1) < list.getModel().getSize()) { |
|
s += 1; |
|
list.setSelectedIndex(s); |
|
list.ensureIndexIsVisible(s); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void installKeyboardActions() { |
|
InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED); |
|
|
|
SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, |
|
inputMap); |
|
|
|
LazyActionMap.installLazyActionMap(list, BasicListUI.class, |
|
"List.actionMap"); |
|
} |
|
|
|
InputMap getInputMap(int condition) { |
|
if (condition == JComponent.WHEN_FOCUSED) { |
|
InputMap keyMap = (InputMap)DefaultLookup.get( |
|
list, this, "List.focusInputMap"); |
|
InputMap rtlKeyMap; |
|
|
|
if (isLeftToRight || |
|
((rtlKeyMap = (InputMap)DefaultLookup.get(list, this, |
|
"List.focusInputMap.RightToLeft")) == null)) { |
|
return keyMap; |
|
} else { |
|
rtlKeyMap.setParent(keyMap); |
|
return rtlKeyMap; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void uninstallKeyboardActions() { |
|
SwingUtilities.replaceUIActionMap(list, null); |
|
SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void installListeners() |
|
{ |
|
TransferHandler th = list.getTransferHandler(); |
|
if (th == null || th instanceof UIResource) { |
|
list.setTransferHandler(defaultTransferHandler); |
|
// default TransferHandler doesn't support drop |
|
|
|
if (list.getDropTarget() instanceof UIResource) { |
|
list.setDropTarget(null); |
|
} |
|
} |
|
|
|
focusListener = createFocusListener(); |
|
mouseInputListener = createMouseInputListener(); |
|
propertyChangeListener = createPropertyChangeListener(); |
|
listSelectionListener = createListSelectionListener(); |
|
listDataListener = createListDataListener(); |
|
|
|
list.addFocusListener(focusListener); |
|
list.addMouseListener(mouseInputListener); |
|
list.addMouseMotionListener(mouseInputListener); |
|
list.addPropertyChangeListener(propertyChangeListener); |
|
list.addKeyListener(getHandler()); |
|
|
|
ListModel model = list.getModel(); |
|
if (model != null) { |
|
model.addListDataListener(listDataListener); |
|
} |
|
|
|
ListSelectionModel selectionModel = list.getSelectionModel(); |
|
if (selectionModel != null) { |
|
selectionModel.addListSelectionListener(listSelectionListener); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void uninstallListeners() |
|
{ |
|
list.removeFocusListener(focusListener); |
|
list.removeMouseListener(mouseInputListener); |
|
list.removeMouseMotionListener(mouseInputListener); |
|
list.removePropertyChangeListener(propertyChangeListener); |
|
list.removeKeyListener(getHandler()); |
|
|
|
ListModel model = list.getModel(); |
|
if (model != null) { |
|
model.removeListDataListener(listDataListener); |
|
} |
|
|
|
ListSelectionModel selectionModel = list.getSelectionModel(); |
|
if (selectionModel != null) { |
|
selectionModel.removeListSelectionListener(listSelectionListener); |
|
} |
|
|
|
focusListener = null; |
|
mouseInputListener = null; |
|
listSelectionListener = null; |
|
listDataListener = null; |
|
propertyChangeListener = null; |
|
handler = null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void installDefaults() |
|
{ |
|
list.setLayout(null); |
|
|
|
LookAndFeel.installBorder(list, "List.border"); |
|
|
|
LookAndFeel.installColorsAndFont(list, "List.background", "List.foreground", "List.font"); |
|
|
|
LookAndFeel.installProperty(list, "opaque", Boolean.TRUE); |
|
|
|
if (list.getCellRenderer() == null) { |
|
list.setCellRenderer((ListCellRenderer)(UIManager.get("List.cellRenderer"))); |
|
} |
|
|
|
Color sbg = list.getSelectionBackground(); |
|
if (sbg == null || sbg instanceof UIResource) { |
|
list.setSelectionBackground(UIManager.getColor("List.selectionBackground")); |
|
} |
|
|
|
Color sfg = list.getSelectionForeground(); |
|
if (sfg == null || sfg instanceof UIResource) { |
|
list.setSelectionForeground(UIManager.getColor("List.selectionForeground")); |
|
} |
|
|
|
Long l = (Long)UIManager.get("List.timeFactor"); |
|
timeFactor = (l!=null) ? l.longValue() : 1000L; |
|
|
|
updateIsFileList(); |
|
} |
|
|
|
private void updateIsFileList() { |
|
boolean b = Boolean.TRUE.equals(list.getClientProperty("List.isFileList")); |
|
if (b != isFileList) { |
|
isFileList = b; |
|
Font oldFont = list.getFont(); |
|
if (oldFont == null || oldFont instanceof UIResource) { |
|
Font newFont = UIManager.getFont(b ? "FileChooser.listFont" : "List.font"); |
|
if (newFont != null && newFont != oldFont) { |
|
list.setFont(newFont); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void uninstallDefaults() |
|
{ |
|
LookAndFeel.uninstallBorder(list); |
|
if (list.getFont() instanceof UIResource) { |
|
list.setFont(null); |
|
} |
|
if (list.getForeground() instanceof UIResource) { |
|
list.setForeground(null); |
|
} |
|
if (list.getBackground() instanceof UIResource) { |
|
list.setBackground(null); |
|
} |
|
if (list.getSelectionBackground() instanceof UIResource) { |
|
list.setSelectionBackground(null); |
|
} |
|
if (list.getSelectionForeground() instanceof UIResource) { |
|
list.setSelectionForeground(null); |
|
} |
|
if (list.getCellRenderer() instanceof UIResource) { |
|
list.setCellRenderer(null); |
|
} |
|
if (list.getTransferHandler() instanceof UIResource) { |
|
list.setTransferHandler(null); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void installUI(JComponent c) |
|
{ |
|
list = (JList)c; |
|
|
|
layoutOrientation = list.getLayoutOrientation(); |
|
|
|
rendererPane = new CellRendererPane(); |
|
list.add(rendererPane); |
|
|
|
columnCount = 1; |
|
|
|
updateLayoutStateNeeded = modelChanged; |
|
isLeftToRight = list.getComponentOrientation().isLeftToRight(); |
|
|
|
installDefaults(); |
|
installListeners(); |
|
installKeyboardActions(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void uninstallUI(JComponent c) |
|
{ |
|
uninstallListeners(); |
|
uninstallDefaults(); |
|
uninstallKeyboardActions(); |
|
|
|
cellWidth = cellHeight = -1; |
|
cellHeights = null; |
|
|
|
listWidth = listHeight = -1; |
|
|
|
list.remove(rendererPane); |
|
rendererPane = null; |
|
list = null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static ComponentUI createUI(JComponent list) { |
|
return new BasicListUI(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int locationToIndex(JList list, Point location) { |
|
maybeUpdateLayoutState(); |
|
return convertLocationToModel(location.x, location.y); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Point indexToLocation(JList list, int index) { |
|
maybeUpdateLayoutState(); |
|
Rectangle rect = getCellBounds(list, index, index); |
|
|
|
if (rect != null) { |
|
return new Point(rect.x, rect.y); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Rectangle getCellBounds(JList list, int index1, int index2) { |
|
maybeUpdateLayoutState(); |
|
|
|
int minIndex = Math.min(index1, index2); |
|
int maxIndex = Math.max(index1, index2); |
|
|
|
if (minIndex >= list.getModel().getSize()) { |
|
return null; |
|
} |
|
|
|
Rectangle minBounds = getCellBounds(list, minIndex); |
|
|
|
if (minBounds == null) { |
|
return null; |
|
} |
|
if (minIndex == maxIndex) { |
|
return minBounds; |
|
} |
|
Rectangle maxBounds = getCellBounds(list, maxIndex); |
|
|
|
if (maxBounds != null) { |
|
if (layoutOrientation == JList.HORIZONTAL_WRAP) { |
|
int minRow = convertModelToRow(minIndex); |
|
int maxRow = convertModelToRow(maxIndex); |
|
|
|
if (minRow != maxRow) { |
|
minBounds.x = 0; |
|
minBounds.width = list.getWidth(); |
|
} |
|
} |
|
else if (minBounds.x != maxBounds.x) { |
|
|
|
minBounds.y = 0; |
|
minBounds.height = list.getHeight(); |
|
} |
|
minBounds.add(maxBounds); |
|
} |
|
return minBounds; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private Rectangle getCellBounds(JList list, int index) { |
|
maybeUpdateLayoutState(); |
|
|
|
int row = convertModelToRow(index); |
|
int column = convertModelToColumn(index); |
|
|
|
if (row == -1 || column == -1) { |
|
return null; |
|
} |
|
|
|
Insets insets = list.getInsets(); |
|
int x; |
|
int w = cellWidth; |
|
int y = insets.top; |
|
int h; |
|
switch (layoutOrientation) { |
|
case JList.VERTICAL_WRAP: |
|
case JList.HORIZONTAL_WRAP: |
|
if (isLeftToRight) { |
|
x = insets.left + column * cellWidth; |
|
} else { |
|
x = list.getWidth() - insets.right - (column+1) * cellWidth; |
|
} |
|
y += cellHeight * row; |
|
h = cellHeight; |
|
break; |
|
default: |
|
x = insets.left; |
|
if (cellHeights == null) { |
|
y += (cellHeight * row); |
|
} |
|
else if (row >= cellHeights.length) { |
|
y = 0; |
|
} |
|
else { |
|
for(int i = 0; i < row; i++) { |
|
y += cellHeights[i]; |
|
} |
|
} |
|
w = list.getWidth() - (insets.left + insets.right); |
|
h = getRowHeight(index); |
|
break; |
|
} |
|
return new Rectangle(x, y, w, h); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected int getRowHeight(int row) |
|
{ |
|
return getHeight(0, row); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected int convertYToRow(int y0) |
|
{ |
|
return convertLocationToRow(0, y0, false); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected int convertRowToY(int row) |
|
{ |
|
if (row >= getRowCount(0) || row < 0) { |
|
return -1; |
|
} |
|
Rectangle bounds = getCellBounds(list, row, row); |
|
return bounds.y; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private int getHeight(int column, int row) { |
|
if (column < 0 || column > columnCount || row < 0) { |
|
return -1; |
|
} |
|
if (layoutOrientation != JList.VERTICAL) { |
|
return cellHeight; |
|
} |
|
if (row >= list.getModel().getSize()) { |
|
return -1; |
|
} |
|
return (cellHeights == null) ? cellHeight : |
|
((row < cellHeights.length) ? cellHeights[row] : -1); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int convertLocationToRow(int x, int y0, boolean closest) { |
|
int size = list.getModel().getSize(); |
|
|
|
if (size <= 0) { |
|
return -1; |
|
} |
|
Insets insets = list.getInsets(); |
|
if (cellHeights == null) { |
|
int row = (cellHeight == 0) ? 0 : |
|
((y0 - insets.top) / cellHeight); |
|
if (closest) { |
|
if (row < 0) { |
|
row = 0; |
|
} |
|
else if (row >= size) { |
|
row = size - 1; |
|
} |
|
} |
|
return row; |
|
} |
|
else if (size > cellHeights.length) { |
|
return -1; |
|
} |
|
else { |
|
int y = insets.top; |
|
int row = 0; |
|
|
|
if (closest && y0 < y) { |
|
return 0; |
|
} |
|
int i; |
|
for (i = 0; i < size; i++) { |
|
if ((y0 >= y) && (y0 < y + cellHeights[i])) { |
|
return row; |
|
} |
|
y += cellHeights[i]; |
|
row += 1; |
|
} |
|
return i - 1; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int convertLocationToRowInColumn(int y, int column) { |
|
int x = 0; |
|
|
|
if (layoutOrientation != JList.VERTICAL) { |
|
if (isLeftToRight) { |
|
x = column * cellWidth; |
|
} else { |
|
x = list.getWidth() - (column+1)*cellWidth - list.getInsets().right; |
|
} |
|
} |
|
return convertLocationToRow(x, y, true); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int convertLocationToModel(int x, int y) { |
|
int row = convertLocationToRow(x, y, true); |
|
int column = convertLocationToColumn(x, y); |
|
|
|
if (row >= 0 && column >= 0) { |
|
return getModelIndex(column, row); |
|
} |
|
return -1; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private int getRowCount(int column) { |
|
if (column < 0 || column >= columnCount) { |
|
return -1; |
|
} |
|
if (layoutOrientation == JList.VERTICAL || |
|
(column == 0 && columnCount == 1)) { |
|
return list.getModel().getSize(); |
|
} |
|
if (column >= columnCount) { |
|
return -1; |
|
} |
|
if (layoutOrientation == JList.VERTICAL_WRAP) { |
|
if (column < (columnCount - 1)) { |
|
return rowsPerColumn; |
|
} |
|
return list.getModel().getSize() - (columnCount - 1) * |
|
rowsPerColumn; |
|
} |
|
|
|
int diff = columnCount - (columnCount * rowsPerColumn - |
|
list.getModel().getSize()); |
|
|
|
if (column >= diff) { |
|
return Math.max(0, rowsPerColumn - 1); |
|
} |
|
return rowsPerColumn; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private int getModelIndex(int column, int row) { |
|
switch (layoutOrientation) { |
|
case JList.VERTICAL_WRAP: |
|
return Math.min(list.getModel().getSize() - 1, rowsPerColumn * |
|
column + Math.min(row, rowsPerColumn-1)); |
|
case JList.HORIZONTAL_WRAP: |
|
return Math.min(list.getModel().getSize() - 1, row * columnCount + |
|
column); |
|
default: |
|
return row; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private int convertLocationToColumn(int x, int y) { |
|
if (cellWidth > 0) { |
|
if (layoutOrientation == JList.VERTICAL) { |
|
return 0; |
|
} |
|
Insets insets = list.getInsets(); |
|
int col; |
|
if (isLeftToRight) { |
|
col = (x - insets.left) / cellWidth; |
|
} else { |
|
col = (list.getWidth() - x - insets.right - 1) / cellWidth; |
|
} |
|
if (col < 0) { |
|
return 0; |
|
} |
|
else if (col >= columnCount) { |
|
return columnCount - 1; |
|
} |
|
return col; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int convertModelToRow(int index) { |
|
int size = list.getModel().getSize(); |
|
|
|
if ((index < 0) || (index >= size)) { |
|
return -1; |
|
} |
|
|
|
if (layoutOrientation != JList.VERTICAL && columnCount > 1 && |
|
rowsPerColumn > 0) { |
|
if (layoutOrientation == JList.VERTICAL_WRAP) { |
|
return index % rowsPerColumn; |
|
} |
|
return index / columnCount; |
|
} |
|
return index; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int convertModelToColumn(int index) { |
|
int size = list.getModel().getSize(); |
|
|
|
if ((index < 0) || (index >= size)) { |
|
return -1; |
|
} |
|
|
|
if (layoutOrientation != JList.VERTICAL && rowsPerColumn > 0 && |
|
columnCount > 1) { |
|
if (layoutOrientation == JList.VERTICAL_WRAP) { |
|
return index / rowsPerColumn; |
|
} |
|
return index % columnCount; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void maybeUpdateLayoutState() |
|
{ |
|
if (updateLayoutStateNeeded != 0) { |
|
updateLayoutState(); |
|
updateLayoutStateNeeded = 0; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void updateLayoutState() |
|
{ |
|
/* If both JList fixedCellWidth and fixedCellHeight have been |
|
* set, then initialize cellWidth and cellHeight, and set |
|
* cellHeights to null. |
|
*/ |
|
|
|
int fixedCellHeight = list.getFixedCellHeight(); |
|
int fixedCellWidth = list.getFixedCellWidth(); |
|
|
|
cellWidth = (fixedCellWidth != -1) ? fixedCellWidth : -1; |
|
|
|
if (fixedCellHeight != -1) { |
|
cellHeight = fixedCellHeight; |
|
cellHeights = null; |
|
} |
|
else { |
|
cellHeight = -1; |
|
cellHeights = new int[list.getModel().getSize()]; |
|
} |
|
|
|
/* If either of JList fixedCellWidth and fixedCellHeight haven't |
|
* been set, then initialize cellWidth and cellHeights by |
|
* scanning through the entire model. Note: if the renderer is |
|
* null, we just set cellWidth and cellHeights[*] to zero, |
|
* if they're not set already. |
|
*/ |
|
|
|
if ((fixedCellWidth == -1) || (fixedCellHeight == -1)) { |
|
|
|
ListModel dataModel = list.getModel(); |
|
int dataModelSize = dataModel.getSize(); |
|
ListCellRenderer renderer = list.getCellRenderer(); |
|
|
|
if (renderer != null) { |
|
for(int index = 0; index < dataModelSize; index++) { |
|
Object value = dataModel.getElementAt(index); |
|
Component c = renderer.getListCellRendererComponent(list, value, index, false, false); |
|
rendererPane.add(c); |
|
Dimension cellSize = c.getPreferredSize(); |
|
if (fixedCellWidth == -1) { |
|
cellWidth = Math.max(cellSize.width, cellWidth); |
|
} |
|
if (fixedCellHeight == -1) { |
|
cellHeights[index] = cellSize.height; |
|
} |
|
} |
|
} |
|
else { |
|
if (cellWidth == -1) { |
|
cellWidth = 0; |
|
} |
|
if (cellHeights == null) { |
|
cellHeights = new int[dataModelSize]; |
|
} |
|
for(int index = 0; index < dataModelSize; index++) { |
|
cellHeights[index] = 0; |
|
} |
|
} |
|
} |
|
|
|
columnCount = 1; |
|
if (layoutOrientation != JList.VERTICAL) { |
|
updateHorizontalLayoutState(fixedCellWidth, fixedCellHeight); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void updateHorizontalLayoutState(int fixedCellWidth, |
|
int fixedCellHeight) { |
|
int visRows = list.getVisibleRowCount(); |
|
int dataModelSize = list.getModel().getSize(); |
|
Insets insets = list.getInsets(); |
|
|
|
listHeight = list.getHeight(); |
|
listWidth = list.getWidth(); |
|
|
|
if (dataModelSize == 0) { |
|
rowsPerColumn = columnCount = 0; |
|
preferredHeight = insets.top + insets.bottom; |
|
return; |
|
} |
|
|
|
int height; |
|
|
|
if (fixedCellHeight != -1) { |
|
height = fixedCellHeight; |
|
} |
|
else { |
|
|
|
int maxHeight = 0; |
|
if (cellHeights.length > 0) { |
|
maxHeight = cellHeights[cellHeights.length - 1]; |
|
for (int counter = cellHeights.length - 2; |
|
counter >= 0; counter--) { |
|
maxHeight = Math.max(maxHeight, cellHeights[counter]); |
|
} |
|
} |
|
height = cellHeight = maxHeight; |
|
cellHeights = null; |
|
} |
|
// The number of rows is either determined by the visible row |
|
|
|
rowsPerColumn = dataModelSize; |
|
if (visRows > 0) { |
|
rowsPerColumn = visRows; |
|
columnCount = Math.max(1, dataModelSize / rowsPerColumn); |
|
if (dataModelSize > 0 && dataModelSize > rowsPerColumn && |
|
dataModelSize % rowsPerColumn != 0) { |
|
columnCount++; |
|
} |
|
if (layoutOrientation == JList.HORIZONTAL_WRAP) { |
|
// Because HORIZONTAL_WRAP flows differently, the |
|
|
|
rowsPerColumn = (dataModelSize / columnCount); |
|
if (dataModelSize % columnCount > 0) { |
|
rowsPerColumn++; |
|
} |
|
} |
|
} |
|
else if (layoutOrientation == JList.VERTICAL_WRAP && height != 0) { |
|
rowsPerColumn = Math.max(1, (listHeight - insets.top - |
|
insets.bottom) / height); |
|
columnCount = Math.max(1, dataModelSize / rowsPerColumn); |
|
if (dataModelSize > 0 && dataModelSize > rowsPerColumn && |
|
dataModelSize % rowsPerColumn != 0) { |
|
columnCount++; |
|
} |
|
} |
|
else if (layoutOrientation == JList.HORIZONTAL_WRAP && cellWidth > 0 && |
|
listWidth > 0) { |
|
columnCount = Math.max(1, (listWidth - insets.left - |
|
insets.right) / cellWidth); |
|
rowsPerColumn = dataModelSize / columnCount; |
|
if (dataModelSize % columnCount > 0) { |
|
rowsPerColumn++; |
|
} |
|
} |
|
preferredHeight = rowsPerColumn * cellHeight + insets.top + |
|
insets.bottom; |
|
} |
|
|
|
private Handler getHandler() { |
|
if (handler == null) { |
|
handler = new Handler(); |
|
} |
|
return handler; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class MouseInputHandler implements MouseInputListener |
|
{ |
|
public void mouseClicked(MouseEvent e) { |
|
getHandler().mouseClicked(e); |
|
} |
|
|
|
public void mouseEntered(MouseEvent e) { |
|
getHandler().mouseEntered(e); |
|
} |
|
|
|
public void mouseExited(MouseEvent e) { |
|
getHandler().mouseExited(e); |
|
} |
|
|
|
public void mousePressed(MouseEvent e) { |
|
getHandler().mousePressed(e); |
|
} |
|
|
|
public void mouseDragged(MouseEvent e) { |
|
getHandler().mouseDragged(e); |
|
} |
|
|
|
public void mouseMoved(MouseEvent e) { |
|
getHandler().mouseMoved(e); |
|
} |
|
|
|
public void mouseReleased(MouseEvent e) { |
|
getHandler().mouseReleased(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected MouseInputListener createMouseInputListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public class FocusHandler implements FocusListener |
|
{ |
|
protected void repaintCellFocus() |
|
{ |
|
getHandler().repaintCellFocus(); |
|
} |
|
|
|
/* The focusGained() focusLost() methods run when the JList |
|
* focus changes. |
|
*/ |
|
|
|
public void focusGained(FocusEvent e) { |
|
getHandler().focusGained(e); |
|
} |
|
|
|
public void focusLost(FocusEvent e) { |
|
getHandler().focusLost(e); |
|
} |
|
} |
|
|
|
protected FocusListener createFocusListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class ListSelectionHandler implements ListSelectionListener |
|
{ |
|
public void valueChanged(ListSelectionEvent e) |
|
{ |
|
getHandler().valueChanged(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected ListSelectionListener createListSelectionListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
private void redrawList() { |
|
list.revalidate(); |
|
list.repaint(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class ListDataHandler implements ListDataListener |
|
{ |
|
public void intervalAdded(ListDataEvent e) { |
|
getHandler().intervalAdded(e); |
|
} |
|
|
|
|
|
public void intervalRemoved(ListDataEvent e) |
|
{ |
|
getHandler().intervalRemoved(e); |
|
} |
|
|
|
|
|
public void contentsChanged(ListDataEvent e) { |
|
getHandler().contentsChanged(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected ListDataListener createListDataListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class PropertyChangeHandler implements PropertyChangeListener |
|
{ |
|
public void propertyChange(PropertyChangeEvent e) |
|
{ |
|
getHandler().propertyChange(e); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected PropertyChangeListener createPropertyChangeListener() { |
|
return getHandler(); |
|
} |
|
|
|
|
|
* change the lead, and not select it. */ |
|
private static final int CHANGE_LEAD = 0; |
|
|
|
* change the selection and lead. */ |
|
private static final int CHANGE_SELECTION = 1; |
|
|
|
* extend the selection from the anchor to the next index. */ |
|
private static final int EXTEND_SELECTION = 2; |
|
|
|
|
|
private static class Actions extends UIAction { |
|
private static final String SELECT_PREVIOUS_COLUMN = |
|
"selectPreviousColumn"; |
|
private static final String SELECT_PREVIOUS_COLUMN_EXTEND = |
|
"selectPreviousColumnExtendSelection"; |
|
private static final String SELECT_PREVIOUS_COLUMN_CHANGE_LEAD = |
|
"selectPreviousColumnChangeLead"; |
|
private static final String SELECT_NEXT_COLUMN = "selectNextColumn"; |
|
private static final String SELECT_NEXT_COLUMN_EXTEND = |
|
"selectNextColumnExtendSelection"; |
|
private static final String SELECT_NEXT_COLUMN_CHANGE_LEAD = |
|
"selectNextColumnChangeLead"; |
|
private static final String SELECT_PREVIOUS_ROW = "selectPreviousRow"; |
|
private static final String SELECT_PREVIOUS_ROW_EXTEND = |
|
"selectPreviousRowExtendSelection"; |
|
private static final String SELECT_PREVIOUS_ROW_CHANGE_LEAD = |
|
"selectPreviousRowChangeLead"; |
|
private static final String SELECT_NEXT_ROW = "selectNextRow"; |
|
private static final String SELECT_NEXT_ROW_EXTEND = |
|
"selectNextRowExtendSelection"; |
|
private static final String SELECT_NEXT_ROW_CHANGE_LEAD = |
|
"selectNextRowChangeLead"; |
|
private static final String SELECT_FIRST_ROW = "selectFirstRow"; |
|
private static final String SELECT_FIRST_ROW_EXTEND = |
|
"selectFirstRowExtendSelection"; |
|
private static final String SELECT_FIRST_ROW_CHANGE_LEAD = |
|
"selectFirstRowChangeLead"; |
|
private static final String SELECT_LAST_ROW = "selectLastRow"; |
|
private static final String SELECT_LAST_ROW_EXTEND = |
|
"selectLastRowExtendSelection"; |
|
private static final String SELECT_LAST_ROW_CHANGE_LEAD = |
|
"selectLastRowChangeLead"; |
|
private static final String SCROLL_UP = "scrollUp"; |
|
private static final String SCROLL_UP_EXTEND = |
|
"scrollUpExtendSelection"; |
|
private static final String SCROLL_UP_CHANGE_LEAD = |
|
"scrollUpChangeLead"; |
|
private static final String SCROLL_DOWN = "scrollDown"; |
|
private static final String SCROLL_DOWN_EXTEND = |
|
"scrollDownExtendSelection"; |
|
private static final String SCROLL_DOWN_CHANGE_LEAD = |
|
"scrollDownChangeLead"; |
|
private static final String SELECT_ALL = "selectAll"; |
|
private static final String CLEAR_SELECTION = "clearSelection"; |
|
|
|
|
|
private static final String ADD_TO_SELECTION = "addToSelection"; |
|
|
|
|
|
private static final String TOGGLE_AND_ANCHOR = "toggleAndAnchor"; |
|
|
|
|
|
private static final String EXTEND_TO = "extendTo"; |
|
|
|
|
|
private static final String MOVE_SELECTION_TO = "moveSelectionTo"; |
|
|
|
Actions(String name) { |
|
super(name); |
|
} |
|
public void actionPerformed(ActionEvent e) { |
|
String name = getName(); |
|
JList list = (JList)e.getSource(); |
|
BasicListUI ui = (BasicListUI)BasicLookAndFeel.getUIOfType( |
|
list.getUI(), BasicListUI.class); |
|
|
|
if (name == SELECT_PREVIOUS_COLUMN) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextColumnIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_PREVIOUS_COLUMN_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextColumnIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_PREVIOUS_COLUMN_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextColumnIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_NEXT_COLUMN) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextColumnIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_NEXT_COLUMN_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextColumnIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_NEXT_COLUMN_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextColumnIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_PREVIOUS_ROW) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_PREVIOUS_ROW_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_PREVIOUS_ROW_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextIndex(list, ui, -1), -1); |
|
} |
|
else if (name == SELECT_NEXT_ROW) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_NEXT_ROW_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_NEXT_ROW_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextIndex(list, ui, 1), 1); |
|
} |
|
else if (name == SELECT_FIRST_ROW) { |
|
changeSelection(list, CHANGE_SELECTION, 0, -1); |
|
} |
|
else if (name == SELECT_FIRST_ROW_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, 0, -1); |
|
} |
|
else if (name == SELECT_FIRST_ROW_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, 0, -1); |
|
} |
|
else if (name == SELECT_LAST_ROW) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
list.getModel().getSize() - 1, 1); |
|
} |
|
else if (name == SELECT_LAST_ROW_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
list.getModel().getSize() - 1, 1); |
|
} |
|
else if (name == SELECT_LAST_ROW_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
list.getModel().getSize() - 1, 1); |
|
} |
|
else if (name == SCROLL_UP) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextPageIndex(list, -1), -1); |
|
} |
|
else if (name == SCROLL_UP_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextPageIndex(list, -1), -1); |
|
} |
|
else if (name == SCROLL_UP_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextPageIndex(list, -1), -1); |
|
} |
|
else if (name == SCROLL_DOWN) { |
|
changeSelection(list, CHANGE_SELECTION, |
|
getNextPageIndex(list, 1), 1); |
|
} |
|
else if (name == SCROLL_DOWN_EXTEND) { |
|
changeSelection(list, EXTEND_SELECTION, |
|
getNextPageIndex(list, 1), 1); |
|
} |
|
else if (name == SCROLL_DOWN_CHANGE_LEAD) { |
|
changeSelection(list, CHANGE_LEAD, |
|
getNextPageIndex(list, 1), 1); |
|
} |
|
else if (name == SELECT_ALL) { |
|
selectAll(list); |
|
} |
|
else if (name == CLEAR_SELECTION) { |
|
clearSelection(list); |
|
} |
|
else if (name == ADD_TO_SELECTION) { |
|
int index = adjustIndex( |
|
list.getSelectionModel().getLeadSelectionIndex(), list); |
|
|
|
if (!list.isSelectedIndex(index)) { |
|
int oldAnchor = list.getSelectionModel().getAnchorSelectionIndex(); |
|
list.setValueIsAdjusting(true); |
|
list.addSelectionInterval(index, index); |
|
list.getSelectionModel().setAnchorSelectionIndex(oldAnchor); |
|
list.setValueIsAdjusting(false); |
|
} |
|
} |
|
else if (name == TOGGLE_AND_ANCHOR) { |
|
int index = adjustIndex( |
|
list.getSelectionModel().getLeadSelectionIndex(), list); |
|
|
|
if (list.isSelectedIndex(index)) { |
|
list.removeSelectionInterval(index, index); |
|
} else { |
|
list.addSelectionInterval(index, index); |
|
} |
|
} |
|
else if (name == EXTEND_TO) { |
|
changeSelection( |
|
list, EXTEND_SELECTION, |
|
adjustIndex(list.getSelectionModel().getLeadSelectionIndex(), list), |
|
0); |
|
} |
|
else if (name == MOVE_SELECTION_TO) { |
|
changeSelection( |
|
list, CHANGE_SELECTION, |
|
adjustIndex(list.getSelectionModel().getLeadSelectionIndex(), list), |
|
0); |
|
} |
|
} |
|
|
|
public boolean isEnabled(Object c) { |
|
Object name = getName(); |
|
if (name == SELECT_PREVIOUS_COLUMN_CHANGE_LEAD || |
|
name == SELECT_NEXT_COLUMN_CHANGE_LEAD || |
|
name == SELECT_PREVIOUS_ROW_CHANGE_LEAD || |
|
name == SELECT_NEXT_ROW_CHANGE_LEAD || |
|
name == SELECT_FIRST_ROW_CHANGE_LEAD || |
|
name == SELECT_LAST_ROW_CHANGE_LEAD || |
|
name == SCROLL_UP_CHANGE_LEAD || |
|
name == SCROLL_DOWN_CHANGE_LEAD) { |
|
|
|
// discontinuous selection actions are only enabled for |
|
|
|
return c != null && ((JList)c).getSelectionModel() |
|
instanceof DefaultListSelectionModel; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
private void clearSelection(JList list) { |
|
list.clearSelection(); |
|
} |
|
|
|
private void selectAll(JList list) { |
|
int size = list.getModel().getSize(); |
|
if (size > 0) { |
|
ListSelectionModel lsm = list.getSelectionModel(); |
|
int lead = adjustIndex(lsm.getLeadSelectionIndex(), list); |
|
|
|
if (lsm.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) { |
|
if (lead == -1) { |
|
int min = adjustIndex(list.getMinSelectionIndex(), list); |
|
lead = (min == -1 ? 0 : min); |
|
} |
|
|
|
list.setSelectionInterval(lead, lead); |
|
list.ensureIndexIsVisible(lead); |
|
} else { |
|
list.setValueIsAdjusting(true); |
|
|
|
int anchor = adjustIndex(lsm.getAnchorSelectionIndex(), list); |
|
|
|
list.setSelectionInterval(0, size - 1); |
|
|
|
|
|
SwingUtilities2.setLeadAnchorWithoutSelection(lsm, anchor, lead); |
|
|
|
list.setValueIsAdjusting(false); |
|
} |
|
} |
|
} |
|
|
|
private int getNextPageIndex(JList list, int direction) { |
|
if (list.getModel().getSize() == 0) { |
|
return -1; |
|
} |
|
|
|
int index = -1; |
|
Rectangle visRect = list.getVisibleRect(); |
|
ListSelectionModel lsm = list.getSelectionModel(); |
|
int lead = adjustIndex(lsm.getLeadSelectionIndex(), list); |
|
Rectangle leadRect = |
|
(lead==-1) ? new Rectangle() : list.getCellBounds(lead, lead); |
|
|
|
if (list.getLayoutOrientation() == JList.VERTICAL_WRAP && |
|
list.getVisibleRowCount() <= 0) { |
|
if (!list.getComponentOrientation().isLeftToRight()) { |
|
direction = -direction; |
|
} |
|
// apply for horizontal scrolling: the step for next |
|
|
|
if (direction < 0) { |
|
|
|
visRect.x = leadRect.x + leadRect.width - visRect.width; |
|
Point p = new Point(visRect.x - 1, leadRect.y); |
|
index = list.locationToIndex(p); |
|
Rectangle cellBounds = list.getCellBounds(index, index); |
|
if (visRect.intersects(cellBounds)) { |
|
p.x = cellBounds.x - 1; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
} |
|
|
|
if (cellBounds.y != leadRect.y) { |
|
p.x = cellBounds.x + cellBounds.width; |
|
index = list.locationToIndex(p); |
|
} |
|
} |
|
else { |
|
|
|
visRect.x = leadRect.x; |
|
Point p = new Point(visRect.x + visRect.width, leadRect.y); |
|
index = list.locationToIndex(p); |
|
Rectangle cellBounds = list.getCellBounds(index, index); |
|
if (visRect.intersects(cellBounds)) { |
|
p.x = cellBounds.x + cellBounds.width; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
} |
|
if (cellBounds.y != leadRect.y) { |
|
p.x = cellBounds.x - 1; |
|
index = list.locationToIndex(p); |
|
} |
|
} |
|
} |
|
else { |
|
if (direction < 0) { |
|
// up |
|
|
|
Point p = new Point(leadRect.x, visRect.y); |
|
index = list.locationToIndex(p); |
|
if (lead <= index) { |
|
// if lead is the first visible cell (or above it) |
|
|
|
visRect.y = leadRect.y + leadRect.height - visRect.height; |
|
p.y = visRect.y; |
|
index = list.locationToIndex(p); |
|
Rectangle cellBounds = list.getCellBounds(index, index); |
|
// go one cell down if first visible cell doesn't fit |
|
|
|
if (cellBounds.y < visRect.y) { |
|
p.y = cellBounds.y + cellBounds.height; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
} |
|
// if index isn't less then lead |
|
|
|
if (cellBounds.y >= leadRect.y) { |
|
p.y = leadRect.y - 1; |
|
index = list.locationToIndex(p); |
|
} |
|
} |
|
} |
|
else { |
|
// down |
|
|
|
Point p = new Point(leadRect.x, |
|
visRect.y + visRect.height - 1); |
|
index = list.locationToIndex(p); |
|
Rectangle cellBounds = list.getCellBounds(index, index); |
|
// go up one cell if last visible cell doesn't fit |
|
|
|
if (cellBounds.y + cellBounds.height > |
|
visRect.y + visRect.height) { |
|
p.y = cellBounds.y - 1; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
index = Math.max(index, lead); |
|
} |
|
|
|
if (lead >= index) { |
|
// if lead is the last completely visible index |
|
|
|
visRect.y = leadRect.y; |
|
p.y = visRect.y + visRect.height - 1; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
// go one cell up if last visible cell doesn't fit |
|
|
|
if (cellBounds.y + cellBounds.height > |
|
visRect.y + visRect.height) { |
|
p.y = cellBounds.y - 1; |
|
index = list.locationToIndex(p); |
|
cellBounds = list.getCellBounds(index, index); |
|
} |
|
// if index isn't greater then lead |
|
|
|
if (cellBounds.y <= leadRect.y) { |
|
p.y = leadRect.y + leadRect.height; |
|
index = list.locationToIndex(p); |
|
} |
|
} |
|
} |
|
} |
|
return index; |
|
} |
|
|
|
private void changeSelection(JList list, int type, |
|
int index, int direction) { |
|
if (index >= 0 && index < list.getModel().getSize()) { |
|
ListSelectionModel lsm = list.getSelectionModel(); |
|
|
|
|
|
if (type == CHANGE_LEAD && |
|
list.getSelectionMode() |
|
!= ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) { |
|
|
|
type = CHANGE_SELECTION; |
|
} |
|
|
|
// IMPORTANT - This needs to happen before the index is changed. |
|
// This is because JFileChooser, which uses JList, also scrolls |
|
// the selected item into view. If that happens first, then |
|
|
|
adjustScrollPositionIfNecessary(list, index, direction); |
|
|
|
if (type == EXTEND_SELECTION) { |
|
int anchor = adjustIndex(lsm.getAnchorSelectionIndex(), list); |
|
if (anchor == -1) { |
|
anchor = 0; |
|
} |
|
|
|
list.setSelectionInterval(anchor, index); |
|
} |
|
else if (type == CHANGE_SELECTION) { |
|
list.setSelectedIndex(index); |
|
} |
|
else { |
|
// casting should be safe since the action is only enabled |
|
|
|
((DefaultListSelectionModel)lsm).moveLeadSelectionIndex(index); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void adjustScrollPositionIfNecessary(JList list, int index, |
|
int direction) { |
|
if (direction == 0) { |
|
return; |
|
} |
|
Rectangle cellBounds = list.getCellBounds(index, index); |
|
Rectangle visRect = list.getVisibleRect(); |
|
if (cellBounds != null && !visRect.contains(cellBounds)) { |
|
if (list.getLayoutOrientation() == JList.VERTICAL_WRAP && |
|
list.getVisibleRowCount() <= 0) { |
|
|
|
if (list.getComponentOrientation().isLeftToRight()) { |
|
if (direction > 0) { |
|
|
|
int x =Math.max(0, |
|
cellBounds.x + cellBounds.width - visRect.width); |
|
int startIndex = |
|
list.locationToIndex(new Point(x, cellBounds.y)); |
|
Rectangle startRect = list.getCellBounds(startIndex, |
|
startIndex); |
|
if (startRect.x < x && startRect.x < cellBounds.x) { |
|
startRect.x += startRect.width; |
|
startIndex = |
|
list.locationToIndex(startRect.getLocation()); |
|
startRect = list.getCellBounds(startIndex, |
|
startIndex); |
|
} |
|
cellBounds = startRect; |
|
} |
|
cellBounds.width = visRect.width; |
|
} |
|
else { |
|
if (direction > 0) { |
|
|
|
int x = cellBounds.x + visRect.width; |
|
int rightIndex = |
|
list.locationToIndex(new Point(x, cellBounds.y)); |
|
Rectangle rightRect = list.getCellBounds(rightIndex, |
|
rightIndex); |
|
if (rightRect.x + rightRect.width > x && |
|
rightRect.x > cellBounds.x) { |
|
rightRect.width = 0; |
|
} |
|
cellBounds.x = Math.max(0, |
|
rightRect.x + rightRect.width - visRect.width); |
|
cellBounds.width = visRect.width; |
|
} |
|
else { |
|
cellBounds.x += Math.max(0, |
|
cellBounds.width - visRect.width); |
|
|
|
cellBounds.width = Math.min(cellBounds.width, |
|
visRect.width); |
|
} |
|
} |
|
} |
|
else { |
|
|
|
if (direction > 0 && |
|
(cellBounds.y < visRect.y || |
|
cellBounds.y + cellBounds.height |
|
> visRect.y + visRect.height)) { |
|
|
|
int y = Math.max(0, |
|
cellBounds.y + cellBounds.height - visRect.height); |
|
int startIndex = |
|
list.locationToIndex(new Point(cellBounds.x, y)); |
|
Rectangle startRect = list.getCellBounds(startIndex, |
|
startIndex); |
|
if (startRect.y < y && startRect.y < cellBounds.y) { |
|
startRect.y += startRect.height; |
|
startIndex = |
|
list.locationToIndex(startRect.getLocation()); |
|
startRect = |
|
list.getCellBounds(startIndex, startIndex); |
|
} |
|
cellBounds = startRect; |
|
cellBounds.height = visRect.height; |
|
} |
|
else { |
|
|
|
cellBounds.height = Math.min(cellBounds.height, visRect.height); |
|
} |
|
} |
|
list.scrollRectToVisible(cellBounds); |
|
} |
|
} |
|
|
|
private int getNextColumnIndex(JList list, BasicListUI ui, |
|
int amount) { |
|
if (list.getLayoutOrientation() != JList.VERTICAL) { |
|
int index = adjustIndex(list.getLeadSelectionIndex(), list); |
|
int size = list.getModel().getSize(); |
|
|
|
if (index == -1) { |
|
return 0; |
|
} else if (size == 1) { |
|
|
|
return 0; |
|
} else if (ui == null || ui.columnCount <= 1) { |
|
return -1; |
|
} |
|
|
|
int column = ui.convertModelToColumn(index); |
|
int row = ui.convertModelToRow(index); |
|
|
|
column += amount; |
|
if (column >= ui.columnCount || column < 0) { |
|
|
|
return -1; |
|
} |
|
int maxRowCount = ui.getRowCount(column); |
|
if (row >= maxRowCount) { |
|
return -1; |
|
} |
|
return ui.getModelIndex(column, row); |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
private int getNextIndex(JList list, BasicListUI ui, int amount) { |
|
int index = adjustIndex(list.getLeadSelectionIndex(), list); |
|
int size = list.getModel().getSize(); |
|
|
|
if (index == -1) { |
|
if (size > 0) { |
|
if (amount > 0) { |
|
index = 0; |
|
} |
|
else { |
|
index = size - 1; |
|
} |
|
} |
|
} else if (size == 1) { |
|
|
|
index = 0; |
|
} else if (list.getLayoutOrientation() == JList.HORIZONTAL_WRAP) { |
|
if (ui != null) { |
|
index += ui.columnCount * amount; |
|
} |
|
} else { |
|
index += amount; |
|
} |
|
|
|
return index; |
|
} |
|
} |
|
|
|
|
|
private class Handler implements FocusListener, KeyListener, |
|
ListDataListener, ListSelectionListener, |
|
MouseInputListener, PropertyChangeListener, |
|
BeforeDrag { |
|
// |
|
// KeyListener |
|
|
|
private String prefix = ""; |
|
private String typedString = ""; |
|
private long lastTime = 0L; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void keyTyped(KeyEvent e) { |
|
JList src = (JList)e.getSource(); |
|
ListModel model = src.getModel(); |
|
|
|
if (model.getSize() == 0 || e.isAltDown() || |
|
BasicGraphicsUtils.isMenuShortcutKeyDown(e) || |
|
isNavigationKey(e)) { |
|
|
|
return; |
|
} |
|
boolean startingFromSelection = true; |
|
|
|
char c = e.getKeyChar(); |
|
|
|
long time = e.getWhen(); |
|
int startIndex = adjustIndex(src.getLeadSelectionIndex(), list); |
|
if (time - lastTime < timeFactor) { |
|
typedString += c; |
|
if((prefix.length() == 1) && (c == prefix.charAt(0))) { |
|
// Subsequent same key presses move the keyboard focus to the next |
|
|
|
startIndex++; |
|
} else { |
|
prefix = typedString; |
|
} |
|
} else { |
|
startIndex++; |
|
typedString = "" + c; |
|
prefix = typedString; |
|
} |
|
lastTime = time; |
|
|
|
if (startIndex < 0 || startIndex >= model.getSize()) { |
|
startingFromSelection = false; |
|
startIndex = 0; |
|
} |
|
int index = src.getNextMatch(prefix, startIndex, |
|
Position.Bias.Forward); |
|
if (index >= 0) { |
|
src.setSelectedIndex(index); |
|
src.ensureIndexIsVisible(index); |
|
} else if (startingFromSelection) { |
|
index = src.getNextMatch(prefix, 0, |
|
Position.Bias.Forward); |
|
if (index >= 0) { |
|
src.setSelectedIndex(index); |
|
src.ensureIndexIsVisible(index); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void keyPressed(KeyEvent e) { |
|
if ( isNavigationKey(e) ) { |
|
prefix = ""; |
|
typedString = ""; |
|
lastTime = 0L; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void keyReleased(KeyEvent e) { |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean isNavigationKey(KeyEvent event) { |
|
InputMap inputMap = list.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); |
|
KeyStroke key = KeyStroke.getKeyStrokeForEvent(event); |
|
|
|
if (inputMap != null && inputMap.get(key) != null) { |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
// |
|
// PropertyChangeListener |
|
|
|
public void propertyChange(PropertyChangeEvent e) { |
|
String propertyName = e.getPropertyName(); |
|
|
|
|
|
|
|
*/ |
|
if (propertyName == "model") { |
|
ListModel oldModel = (ListModel)e.getOldValue(); |
|
ListModel newModel = (ListModel)e.getNewValue(); |
|
if (oldModel != null) { |
|
oldModel.removeListDataListener(listDataListener); |
|
} |
|
if (newModel != null) { |
|
newModel.addListDataListener(listDataListener); |
|
} |
|
updateLayoutStateNeeded |= modelChanged; |
|
redrawList(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
else if (propertyName == "selectionModel") { |
|
ListSelectionModel oldModel = (ListSelectionModel)e.getOldValue(); |
|
ListSelectionModel newModel = (ListSelectionModel)e.getNewValue(); |
|
if (oldModel != null) { |
|
oldModel.removeListSelectionListener(listSelectionListener); |
|
} |
|
if (newModel != null) { |
|
newModel.addListSelectionListener(listSelectionListener); |
|
} |
|
updateLayoutStateNeeded |= modelChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "cellRenderer") { |
|
updateLayoutStateNeeded |= cellRendererChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "font") { |
|
updateLayoutStateNeeded |= fontChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "prototypeCellValue") { |
|
updateLayoutStateNeeded |= prototypeCellValueChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "fixedCellHeight") { |
|
updateLayoutStateNeeded |= fixedCellHeightChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "fixedCellWidth") { |
|
updateLayoutStateNeeded |= fixedCellWidthChanged; |
|
redrawList(); |
|
} |
|
else if (propertyName == "selectionForeground") { |
|
list.repaint(); |
|
} |
|
else if (propertyName == "selectionBackground") { |
|
list.repaint(); |
|
} |
|
else if ("layoutOrientation" == propertyName) { |
|
updateLayoutStateNeeded |= layoutOrientationChanged; |
|
layoutOrientation = list.getLayoutOrientation(); |
|
redrawList(); |
|
} |
|
else if ("visibleRowCount" == propertyName) { |
|
if (layoutOrientation != JList.VERTICAL) { |
|
updateLayoutStateNeeded |= layoutOrientationChanged; |
|
redrawList(); |
|
} |
|
} |
|
else if ("componentOrientation" == propertyName) { |
|
isLeftToRight = list.getComponentOrientation().isLeftToRight(); |
|
updateLayoutStateNeeded |= componentOrientationChanged; |
|
redrawList(); |
|
|
|
InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED); |
|
SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, |
|
inputMap); |
|
} else if ("List.isFileList" == propertyName) { |
|
updateIsFileList(); |
|
redrawList(); |
|
} else if ("dropLocation" == propertyName) { |
|
JList.DropLocation oldValue = (JList.DropLocation)e.getOldValue(); |
|
repaintDropLocation(oldValue); |
|
repaintDropLocation(list.getDropLocation()); |
|
} |
|
} |
|
|
|
private void repaintDropLocation(JList.DropLocation loc) { |
|
if (loc == null) { |
|
return; |
|
} |
|
|
|
Rectangle r; |
|
|
|
if (loc.isInsert()) { |
|
r = getDropLineRect(loc); |
|
} else { |
|
r = getCellBounds(list, loc.getIndex()); |
|
} |
|
|
|
if (r != null) { |
|
list.repaint(r); |
|
} |
|
} |
|
|
|
// |
|
// ListDataListener |
|
|
|
public void intervalAdded(ListDataEvent e) { |
|
updateLayoutStateNeeded = modelChanged; |
|
|
|
int minIndex = Math.min(e.getIndex0(), e.getIndex1()); |
|
int maxIndex = Math.max(e.getIndex0(), e.getIndex1()); |
|
|
|
/* Sync the SelectionModel with the DataModel. |
|
*/ |
|
|
|
ListSelectionModel sm = list.getSelectionModel(); |
|
if (sm != null) { |
|
sm.insertIndexInterval(minIndex, maxIndex - minIndex+1, true); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
redrawList(); |
|
} |
|
|
|
|
|
public void intervalRemoved(ListDataEvent e) |
|
{ |
|
updateLayoutStateNeeded = modelChanged; |
|
|
|
/* Sync the SelectionModel with the DataModel. |
|
*/ |
|
|
|
ListSelectionModel sm = list.getSelectionModel(); |
|
if (sm != null) { |
|
sm.removeIndexInterval(e.getIndex0(), e.getIndex1()); |
|
} |
|
|
|
/* Repaint the entire list, from the origin of |
|
* the first removed cell, to the bottom of the |
|
* component. |
|
*/ |
|
|
|
redrawList(); |
|
} |
|
|
|
|
|
public void contentsChanged(ListDataEvent e) { |
|
updateLayoutStateNeeded = modelChanged; |
|
redrawList(); |
|
} |
|
|
|
|
|
// |
|
// ListSelectionListener |
|
|
|
public void valueChanged(ListSelectionEvent e) { |
|
maybeUpdateLayoutState(); |
|
|
|
int size = list.getModel().getSize(); |
|
int firstIndex = Math.min(size - 1, Math.max(e.getFirstIndex(), 0)); |
|
int lastIndex = Math.min(size - 1, Math.max(e.getLastIndex(), 0)); |
|
|
|
Rectangle bounds = getCellBounds(list, firstIndex, lastIndex); |
|
|
|
if (bounds != null) { |
|
list.repaint(bounds.x, bounds.y, bounds.width, bounds.height); |
|
} |
|
} |
|
|
|
// |
|
// MouseListener |
|
|
|
public void mouseClicked(MouseEvent e) { |
|
} |
|
|
|
public void mouseEntered(MouseEvent e) { |
|
} |
|
|
|
public void mouseExited(MouseEvent e) { |
|
} |
|
|
|
// Whether or not the mouse press (which is being considered as part |
|
// of a drag sequence) also caused the selection change to be fully |
|
|
|
private boolean dragPressDidSelection; |
|
|
|
public void mousePressed(MouseEvent e) { |
|
if (SwingUtilities2.shouldIgnore(e, list)) { |
|
return; |
|
} |
|
|
|
boolean dragEnabled = list.getDragEnabled(); |
|
boolean grabFocus = true; |
|
|
|
|
|
if (dragEnabled) { |
|
int row = SwingUtilities2.loc2IndexFileList(list, e.getPoint()); |
|
|
|
if (row != -1 && DragRecognitionSupport.mousePressed(e)) { |
|
dragPressDidSelection = false; |
|
|
|
if (BasicGraphicsUtils.isMenuShortcutKeyDown(e)) { |
|
// do nothing for control - will be handled on release |
|
|
|
return; |
|
} else if (!e.isShiftDown() && list.isSelectedIndex(row)) { |
|
// clicking on something that's already selected |
|
|
|
list.addSelectionInterval(row, row); |
|
return; |
|
} |
|
|
|
|
|
grabFocus = false; |
|
|
|
dragPressDidSelection = true; |
|
} |
|
} else { |
|
// When drag is enabled mouse drags won't change the selection |
|
// in the list, so we only set the isAdjusting flag when it's |
|
|
|
list.setValueIsAdjusting(true); |
|
} |
|
|
|
if (grabFocus) { |
|
SwingUtilities2.adjustFocus(list); |
|
} |
|
|
|
adjustSelection(e); |
|
} |
|
|
|
private void adjustSelection(MouseEvent e) { |
|
int row = SwingUtilities2.loc2IndexFileList(list, e.getPoint()); |
|
if (row < 0) { |
|
// If shift is down in multi-select, we should do nothing. |
|
|
|
if (isFileList && |
|
e.getID() == MouseEvent.MOUSE_PRESSED && |
|
(!e.isShiftDown() || |
|
list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION)) { |
|
list.clearSelection(); |
|
} |
|
} |
|
else { |
|
int anchorIndex = adjustIndex(list.getAnchorSelectionIndex(), list); |
|
boolean anchorSelected; |
|
if (anchorIndex == -1) { |
|
anchorIndex = 0; |
|
anchorSelected = false; |
|
} else { |
|
anchorSelected = list.isSelectedIndex(anchorIndex); |
|
} |
|
|
|
if (BasicGraphicsUtils.isMenuShortcutKeyDown(e)) { |
|
if (e.isShiftDown()) { |
|
if (anchorSelected) { |
|
list.addSelectionInterval(anchorIndex, row); |
|
} else { |
|
list.removeSelectionInterval(anchorIndex, row); |
|
if (isFileList) { |
|
list.addSelectionInterval(row, row); |
|
list.getSelectionModel().setAnchorSelectionIndex(anchorIndex); |
|
} |
|
} |
|
} else if (list.isSelectedIndex(row)) { |
|
list.removeSelectionInterval(row, row); |
|
} else { |
|
list.addSelectionInterval(row, row); |
|
} |
|
} else if (e.isShiftDown()) { |
|
list.setSelectionInterval(anchorIndex, row); |
|
} else { |
|
list.setSelectionInterval(row, row); |
|
} |
|
} |
|
} |
|
|
|
public void dragStarting(MouseEvent me) { |
|
if (BasicGraphicsUtils.isMenuShortcutKeyDown(me)) { |
|
int row = SwingUtilities2.loc2IndexFileList(list, me.getPoint()); |
|
list.addSelectionInterval(row, row); |
|
} |
|
} |
|
|
|
public void mouseDragged(MouseEvent e) { |
|
if (SwingUtilities2.shouldIgnore(e, list)) { |
|
return; |
|
} |
|
|
|
if (list.getDragEnabled()) { |
|
DragRecognitionSupport.mouseDragged(e, this); |
|
return; |
|
} |
|
|
|
if (e.isShiftDown() || BasicGraphicsUtils.isMenuShortcutKeyDown(e)) { |
|
return; |
|
} |
|
|
|
int row = locationToIndex(list, e.getPoint()); |
|
if (row != -1) { |
|
|
|
if (isFileList) { |
|
return; |
|
} |
|
Rectangle cellBounds = getCellBounds(list, row, row); |
|
if (cellBounds != null) { |
|
list.scrollRectToVisible(cellBounds); |
|
list.setSelectionInterval(row, row); |
|
} |
|
} |
|
} |
|
|
|
public void mouseMoved(MouseEvent e) { |
|
} |
|
|
|
public void mouseReleased(MouseEvent e) { |
|
if (SwingUtilities2.shouldIgnore(e, list)) { |
|
return; |
|
} |
|
|
|
if (list.getDragEnabled()) { |
|
MouseEvent me = DragRecognitionSupport.mouseReleased(e); |
|
if (me != null) { |
|
SwingUtilities2.adjustFocus(list); |
|
if (!dragPressDidSelection) { |
|
adjustSelection(me); |
|
} |
|
} |
|
} else { |
|
list.setValueIsAdjusting(false); |
|
} |
|
} |
|
|
|
// |
|
// FocusListener |
|
|
|
protected void repaintCellFocus() |
|
{ |
|
int leadIndex = adjustIndex(list.getLeadSelectionIndex(), list); |
|
if (leadIndex != -1) { |
|
Rectangle r = getCellBounds(list, leadIndex, leadIndex); |
|
if (r != null) { |
|
list.repaint(r.x, r.y, r.width, r.height); |
|
} |
|
} |
|
} |
|
|
|
/* The focusGained() focusLost() methods run when the JList |
|
* focus changes. |
|
*/ |
|
|
|
public void focusGained(FocusEvent e) { |
|
repaintCellFocus(); |
|
} |
|
|
|
public void focusLost(FocusEvent e) { |
|
repaintCellFocus(); |
|
} |
|
} |
|
|
|
private static int adjustIndex(int index, JList list) { |
|
return index < list.getModel().getSize() ? index : -1; |
|
} |
|
|
|
private static final TransferHandler defaultTransferHandler = new ListTransferHandler(); |
|
|
|
static class ListTransferHandler extends TransferHandler implements UIResource { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected Transferable createTransferable(JComponent c) { |
|
if (c instanceof JList) { |
|
JList list = (JList) c; |
|
Object[] values = list.getSelectedValues(); |
|
|
|
if (values == null || values.length == 0) { |
|
return null; |
|
} |
|
|
|
StringBuffer plainBuf = new StringBuffer(); |
|
StringBuffer htmlBuf = new StringBuffer(); |
|
|
|
htmlBuf.append("<html>\n<body>\n<ul>\n"); |
|
|
|
for (int i = 0; i < values.length; i++) { |
|
Object obj = values[i]; |
|
String val = ((obj == null) ? "" : obj.toString()); |
|
plainBuf.append(val + "\n"); |
|
htmlBuf.append(" <li>" + val + "\n"); |
|
} |
|
|
|
|
|
plainBuf.deleteCharAt(plainBuf.length() - 1); |
|
htmlBuf.append("</ul>\n</body>\n</html>"); |
|
|
|
return new BasicTransferable(plainBuf.toString(), htmlBuf.toString()); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
public int getSourceActions(JComponent c) { |
|
return COPY; |
|
} |
|
|
|
} |
|
} |