import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JList;
-import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
{
/**
- * A helper class which listens for {@link ComponentEvent}s from
- * the JList.
- */
- private class ComponentHandler extends ComponentAdapter {
-
- /**
- * Called when the component is hidden. Invalidates the internal
- * layout.
- */
- public void componentResized(ComponentEvent ev) {
- BasicListUI.this.damageLayout();
- }
- }
-
- /**
* A helper class which listens for {@link FocusEvent}s
* from the JList.
*/
*/
public void contentsChanged(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
/**
*/
public void intervalAdded(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
/**
*/
public void intervalRemoved(ListDataEvent e)
{
- BasicListUI.this.damageLayout();
+ list.revalidate();
}
}
*/
public void mouseDragged(MouseEvent event)
{
- // TODO: What should be done here, if anything?
+ Point click = event.getPoint();
+ int index = locationToIndex(list, click);
+ if (index == -1)
+ return;
+ if (!event.isShiftDown() && !event.isControlDown())
+ list.setSelectedIndex(index);
+
+ list.ensureIndexIsVisible(list.getLeadSelectionIndex());
}
/**
}
// Update the updateLayoutStateNeeded flag.
if (e.getPropertyName().equals("model"))
- updateLayoutStateNeeded += modelChanged;
+ updateLayoutStateNeeded |= modelChanged;
else if (e.getPropertyName().equals("selectionModel"))
- updateLayoutStateNeeded += selectionModelChanged;
+ updateLayoutStateNeeded |= selectionModelChanged;
else if (e.getPropertyName().equals("font"))
- updateLayoutStateNeeded += fontChanged;
+ updateLayoutStateNeeded |= fontChanged;
else if (e.getPropertyName().equals("fixedCellWidth"))
- updateLayoutStateNeeded += fixedCellWidthChanged;
+ updateLayoutStateNeeded |= fixedCellWidthChanged;
else if (e.getPropertyName().equals("fixedCellHeight"))
- updateLayoutStateNeeded += fixedCellHeightChanged;
+ updateLayoutStateNeeded |= fixedCellHeightChanged;
else if (e.getPropertyName().equals("prototypeCellValue"))
- updateLayoutStateNeeded += prototypeCellValueChanged;
+ updateLayoutStateNeeded |= prototypeCellValueChanged;
else if (e.getPropertyName().equals("cellRenderer"))
- updateLayoutStateNeeded += cellRendererChanged;
- BasicListUI.this.damageLayout();
+ updateLayoutStateNeeded |= cellRendererChanged;
}
}
/** The property change listener listening to the list. */
protected PropertyChangeListener propertyChangeListener;
-
- /** The component listener that receives notification for resizing the
- * JList component.*/
- private ComponentListener componentListener;
-
/** Saved reference to the list this UI was created for. */
protected JList list;
int maxIndex = Math.max(index1, index2);
Point loc = indexToLocation(list, minIndex);
Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth,
- getRowHeight(minIndex));
-
+ getCellHeight(minIndex));
for (int i = minIndex + 1; i <= maxIndex; i++)
{
Point hiLoc = indexToLocation(list, i);
Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth,
- getRowHeight(i));
+ getCellHeight(i));
bounds = bounds.union(hibounds);
}
}
/**
+ * Calculates the maximum cell height.
+ *
+ * @param index the index of the cell
+ *
+ * @return the maximum cell height
+ */
+ private int getCellHeight(int index)
+ {
+ int height = cellHeight;
+ if (height <= 0)
+ {
+ if (list.getLayoutOrientation() == JList.VERTICAL)
+ height = getRowHeight(index);
+ else
+ {
+ for (int j = 0; j < cellHeights.length; j++)
+ height = Math.max(height, cellHeights[j]);
+ }
+ }
+ return height;
+ }
+
+ /**
* Calculate the Y coordinate of the upper edge of a particular row,
* considering the Y coordinate <code>0</code> to occur at the top of the
* list.
// Update the layout if necessary.
maybeUpdateLayoutState();
- int index = list.getModel().getSize() - 1;;
+ int index = list.getModel().getSize() - 1;
// If a fixed cell height is set, then we can work more efficient.
if (cellHeight > 0)
}
/**
- * Marks the current layout as damaged and requests revalidation from the
- * JList.
- * This is package-private to avoid an accessor method.
- *
- * @see #updateLayoutStateNeeded
- */
- void damageLayout()
- {
- updateLayoutStateNeeded = 1;
- }
-
- /**
* Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded}
* is nonzero, then resets {@link #updateLayoutStateNeeded} to zero.
*/
protected void maybeUpdateLayoutState()
{
- if (updateLayoutStateNeeded != 0)
+ if (updateLayoutStateNeeded != 0 || !list.isValid())
{
updateLayoutState();
updateLayoutStateNeeded = 0;
if (propertyChangeListener == null)
propertyChangeListener = createPropertyChangeListener();
list.addPropertyChangeListener(propertyChangeListener);
-
- // FIXME: Are these two really needed? At least they are not documented.
- //keyListener = new KeyHandler();
- componentListener = new ComponentHandler();
- list.addComponentListener(componentListener);
- //list.addKeyListener(keyListener);
}
/**
list.getModel().removeListDataListener(listDataListener);
list.removeListSelectionListener(listSelectionListener);
list.removeMouseListener(mouseInputListener);
- //list.removeKeyListener(keyListener);
list.removeMouseMotionListener(mouseInputListener);
list.removePropertyChangeListener(propertyChangeListener);
}
*/
public Dimension getPreferredSize(JComponent c)
{
+ maybeUpdateLayoutState();
int size = list.getModel().getSize();
- if (size == 0)
- return new Dimension(0, 0);
int visibleRows = list.getVisibleRowCount();
int layoutOrientation = list.getLayoutOrientation();
- Rectangle bounds = getCellBounds(list, 0, list.getModel().getSize() - 1);
- Dimension retVal = bounds.getSize();
- Component parent = list.getParent();
- if ((visibleRows == -1) && (parent instanceof JViewport))
- {
- JViewport viewport = (JViewport) parent;
- if (layoutOrientation == JList.HORIZONTAL_WRAP)
+ int h;
+ int w;
+ int maxCellHeight = cellHeight;
+ if (maxCellHeight <= 0)
+ {
+ for (int i = 0; i < cellHeights.length; i++)
+ maxCellHeight = Math.max(maxCellHeight, cellHeights[i]);
+ }
+ if (layoutOrientation == JList.HORIZONTAL_WRAP)
+ {
+ if (visibleRows > 0)
{
- int h = viewport.getSize().height;
- int cellsPerCol = h / cellHeight;
- int w = size / cellsPerCol * cellWidth;
- retVal = new Dimension(w, h);
+ // We cast to double here to force double divisions.
+ double modelSize = size;
+ int neededColumns = (int) Math.ceil(modelSize / visibleRows);
+ int adjustedRows = (int) Math.ceil(modelSize / neededColumns);
+ h = maxCellHeight * adjustedRows;
+ w = cellWidth * neededColumns;
}
- else if (layoutOrientation == JList.VERTICAL_WRAP)
+ else
{
- int w = viewport.getSize().width;
- int cellsPerRow = Math.max(w / cellWidth, 1);
- int h = size / cellsPerRow * cellHeight;
- retVal = new Dimension(w, h);
+ int neededColumns = Math.min(1, list.getWidth() / cellWidth);
+ h = size / neededColumns * maxCellHeight;
+ w = neededColumns * cellWidth;
}
}
+ else if (layoutOrientation == JList.VERTICAL_WRAP)
+ {
+ if (visibleRows > 0)
+ h = visibleRows * maxCellHeight;
+ else
+ h = Math.max(list.getHeight(), maxCellHeight);
+ int neededColumns = h / maxCellHeight;
+ w = cellWidth * neededColumns;
+ }
+ else
+ {
+ if (list.getFixedCellWidth() > 0)
+ w = list.getFixedCellWidth();
+ else
+ w = cellWidth;
+ if (list.getFixedCellHeight() > 0)
+ // FIXME: We need to add some cellVerticalMargins here, according
+ // to the specs.
+ h = list.getFixedCellHeight() * size;
+ else
+ h = maxCellHeight * size;
+ }
+ Insets insets = list.getInsets();
+ Dimension retVal = new Dimension(w + insets.left + insets.right,
+ h + insets.top + insets.bottom);
return retVal;
}
int lead = sel.getLeadSelectionIndex();
Rectangle clip = g.getClipBounds();
- int startIndex = list.locationToIndex(new Point(clip.x, clip.y));
- int endIndex = list.locationToIndex(new Point(clip.x + clip.width,
- clip.y + clip.height));
+ int startIndex = locationToIndex(list, new Point(clip.x, clip.y));
+ int endIndex = locationToIndex(list, new Point(clip.x + clip.width,
+ clip.y + clip.height));
for (int row = startIndex; row <= endIndex; ++row)
{
* location lies outside the bounds of the list, the greatest index in the
* list model is returned.
*
- * @param list the list which on which the computation is based on
+ * @param l the list which on which the computation is based on
* @param location the coordinates
*
* @return the index of the list item that is located at the given
* coordinates or <code>-1</code> if the list model is empty
*/
- public int locationToIndex(JList list, Point location)
+ public int locationToIndex(JList l, Point location)
{
int layoutOrientation = list.getLayoutOrientation();
int index = -1;
break;
case JList.HORIZONTAL_WRAP:
// determine visible rows and cells per row
- int visibleRows = list.getVisibleRowCount();
+ int maxCellHeight = getCellHeight(0);
+ int visibleRows = list.getHeight() / maxCellHeight;
int cellsPerRow = -1;
int numberOfItems = list.getModel().getSize();
- Dimension listDim = list.getSize();
- if (visibleRows <= 0)
- {
- try
- {
- cellsPerRow = listDim.width / cellWidth;
- }
- catch (ArithmeticException ex)
- {
- cellsPerRow = 1;
- }
- }
- else
- {
- cellsPerRow = numberOfItems / visibleRows + 1;
- }
+ cellsPerRow = numberOfItems / visibleRows + 1;
// determine index for the given location
int cellsPerColumn = numberOfItems / cellsPerRow + 1;
int gridX = Math.min(location.x / cellWidth, cellsPerRow - 1);
- int gridY = Math.min(location.y / cellHeight, cellsPerColumn);
+ int gridY = Math.min(location.y / maxCellHeight, cellsPerColumn);
index = gridX + gridY * cellsPerRow;
break;
case JList.VERTICAL_WRAP:
// determine visible rows and cells per column
- int visibleRows2 = list.getVisibleRowCount();
- if (visibleRows2 <= 0)
- {
- Dimension listDim2 = list.getSize();
- visibleRows2 = listDim2.height / cellHeight;
- }
+ int maxCellHeight2 = getCellHeight(0);
+ int visibleRows2 = list.getHeight() / maxCellHeight2;
int numberOfItems2 = list.getModel().getSize();
int cellsPerRow2 = numberOfItems2 / visibleRows2 + 1;
int gridX2 = Math.min(location.x / cellWidth, cellsPerRow2 - 1);
- int gridY2 = Math.min(location.y / cellHeight, visibleRows2);
+ int gridY2 = Math.min(location.y / maxCellHeight2, visibleRows2);
index = gridY2 + gridX2 * visibleRows2;
break;
}
return index;
}
- public Point indexToLocation(JList list, int index)
+ public Point indexToLocation(JList l, int index)
{
int layoutOrientation = list.getLayoutOrientation();
Point loc = null;
break;
case JList.HORIZONTAL_WRAP:
// determine visible rows and cells per row
- int visibleRows = list.getVisibleRowCount();
+ int maxCellHeight = getCellHeight(0);
+ int visibleRows = list.getHeight() / maxCellHeight;
int numberOfCellsPerRow = -1;
- if (visibleRows <= 0)
- {
- Dimension listDim = list.getSize();
- numberOfCellsPerRow = Math.max(listDim.width / cellWidth, 1);
- }
- else
- {
- int numberOfItems = list.getModel().getSize();
- numberOfCellsPerRow = numberOfItems / visibleRows + 1;
- }
+ int numberOfItems = list.getModel().getSize();
+ numberOfCellsPerRow = numberOfItems / visibleRows + 1;
+
// compute coordinates inside the grid
int gridX = index % numberOfCellsPerRow;
int gridY = index / numberOfCellsPerRow;
int locX = gridX * cellWidth;
- int locY = gridY * cellHeight;
+ int locY;
+ locY = gridY * maxCellHeight;
loc = new Point(locX, locY);
break;
case JList.VERTICAL_WRAP:
// determine visible rows and cells per column
- int visibleRows2 = list.getVisibleRowCount();
- if (visibleRows2 <= 0)
- {
- Dimension listDim2 = list.getSize();
- visibleRows2 = listDim2.height / cellHeight;
- }
+ int maxCellHeight2 = getCellHeight(0);
+ int visibleRows2 = list.getHeight() / maxCellHeight2;
// compute coordinates inside the grid
if (visibleRows2 > 0)
{
int gridY2 = index % visibleRows2;
int gridX2 = index / visibleRows2;
int locX2 = gridX2 * cellWidth;
- int locY2 = gridY2 * cellHeight;
+ int locY2 = gridY2 * maxCellHeight2;
loc = new Point(locX2, locY2);
}
else