/* * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ 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; /** * An extensible implementation of {@code ListUI}. * <p> * {@code BasicListUI} instances cannot be shared between multiple * lists. * * @author Hans Muller * @author Philip Milne * @author Shannon Hickey (drag and drop) */public class BasicListUI extends ListUI{ private static final StringBuilder BASELINE_COMPONENT_KEY = new StringBuilder("List.baselineComponent"); protected JList list = null; protected CellRendererPane rendererPane; // Listeners that this UI attaches to the JList 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; /** * Height of the list. When asked to paint, if the current size of * the list differs, this will update the layout state. */ private int listHeight; /** * Width of the list. When asked to paint, if the current size of * the list differs, this will update the layout state. */ private int listWidth; /** * The layout orientation of the list. */ private int layoutOrientation; // Following ivars are used if the list is laying out horizontally /** * Number of columns to create. */ private int columnCount; /** * Preferred height to make the list, this is only used if the * the list is layed out horizontally. */ private int preferredHeight; /** * Number of rows per column. This is only used if the row height is * fixed. */ private int rowsPerColumn; /** * The time factor to treate the series of typed alphanumeric key * as prefix for first letter navigation. */ private long timeFactor = 1000L; /** * Local cache of JList's client property "List.isFileList" */ private boolean isFileList = false; /** * Local cache of JList's component orientation property */ 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()); } /** * Paint one List cell: compute the relevant state, get the "rubber stamp" * cell renderer component, and then use the CellRendererPane to paint it. * Subclasses may want to override this method rather than paint(). * * @see #paint */ 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 // across the whole list cell. 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); } /** * Paint the rows that intersect the Graphics objects clipRect. This * method calls paintCell as necessary. Subclasses * may want to override these methods. * * @see #paintCell */ 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; } // Determine how many columns we need to paint 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++) { // And then how many rows in this columnn int row = convertLocationToRowInColumn(paintBounds.y, colCounter); int rowCount = getRowCount(colCounter); int index = getModelIndex(colCounter, row); Rectangle rowBounds = getCellBounds(list, index, index); if (rowBounds == null) { // Not valid, bail! 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++; } } // Empty out the renderer pane, allowing renderers to be gc'ed. 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; } /** * Returns the baseline. * * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */ 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 // UIManager key and we should not through a NPE here because of it 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 // the content.Lines 1–500 of 2880. Load more
/* * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ 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; /** * An extensible implementation of {@code ListUI}. * <p> * {@code BasicListUI} instances cannot be shared between multiple * lists. * * @author Hans Muller * @author Philip Milne * @author Shannon Hickey (drag and drop) */ public class BasicListUI extends ListUI { private static final StringBuilder BASELINE_COMPONENT_KEY = new StringBuilder("List.baselineComponent"); protected JList list = null; protected CellRendererPane rendererPane; // Listeners that this UI attaches to the JList 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; /** * Height of the list. When asked to paint, if the current size of * the list differs, this will update the layout state. */ private int listHeight; /** * Width of the list. When asked to paint, if the current size of * the list differs, this will update the layout state. */ private int listWidth; /** * The layout orientation of the list. */ private int layoutOrientation; // Following ivars are used if the list is laying out horizontally /** * Number of columns to create. */ private int columnCount; /** * Preferred height to make the list, this is only used if the * the list is layed out horizontally. */ private int preferredHeight; /** * Number of rows per column. This is only used if the row height is * fixed. */ private int rowsPerColumn; /** * The time factor to treate the series of typed alphanumeric key * as prefix for first letter navigation. */ private long timeFactor = 1000L; /** * Local cache of JList's client property "List.isFileList" */ private boolean isFileList = false; /** * Local cache of JList's component orientation property */ 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()); } /** * Paint one List cell: compute the relevant state, get the "rubber stamp" * cell renderer component, and then use the CellRendererPane to paint it. * Subclasses may want to override this method rather than paint(). * * @see #paint */ 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 // across the whole list cell. 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); } /** * Paint the rows that intersect the Graphics objects clipRect. This * method calls paintCell as necessary. Subclasses * may want to override these methods. * * @see #paintCell */ 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; } // Determine how many columns we need to paint 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++) { // And then how many rows in this columnn int row = convertLocationToRowInColumn(paintBounds.y, colCounter); int rowCount = getRowCount(colCounter); int index = getModelIndex(colCounter, row); Rectangle rowBounds = getCellBounds(list, index, index); if (rowBounds == null) { // Not valid, bail! 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++; } } // Empty out the renderer pane, allowing renderers to be gc'ed. 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; } /** * Returns the baseline. * * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @see javax.swing.JComponent#getBaseline(int, int) * @since 1.6 */ 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 // UIManager key and we should not through a NPE here because of it 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 // the content.