org.openide.nodes.IndexedCustomizer Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.openide.nodes;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.Autoscroll;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.dnd.InvalidDnDOperationException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.Customizer;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.util.NbBundle;
import org.openide.util.datatransfer.ExTransferable;
/** A dialog for reordering nodes. This dialog can reorder
* nodes for all implementors of the {@link Index} cookie.
* The dialog can invoke reorder actions on a given Index
* implementation immediatelly, or these actions can be accumulated
* and invoked at once, when the dialog is closed.
*
* This class is final only for performance reasons.
*
* @author Jan Jancura, Ian Formanek, Dafe Simonek
* @deprecated Better to use {@link Index.Support#showIndexedCustomizer} which behaves better
* with the window system.
*/
@Deprecated
public final class IndexedCustomizer extends JDialog implements Customizer {
// initializations ................................................................................
static final long serialVersionUID = -8731362267771694641L;
// variables .....................................................................................
/** The actual JList control */
private JList control;
/** Buttons */
private JButton buttonUp;
/** Buttons */
private JButton buttonDown;
/** Buttons */
private JButton buttonClose;
/** index to sort */
private Index index;
private Node[] nodes;
/** Whether or not change the order immediatelly */
private boolean immediateReorder = true;
/** Permutation array, which stores moves in case when
* immediateReorder property is false */
private int[] permutation;
/** Listener to the changes in the nodes */
private ChangeListener nodeChangesL;
/** Construct a new customizer. */
public IndexedCustomizer() {
this(null, true);
}
/** Construct a dummy customizer.
* Might not actually be used as a JDialog, however its GUI
* layout and logic will be used.
* Cf. #9323.
* @param p a container on which to draw the GUI
* @param closeButton if true, add a Close button and other dialog logic, else no
*/
IndexedCustomizer(Container p, boolean closeButton) {
super(TMUtil.mainWindow(), true);
GridBagConstraints constraints;
if (closeButton) {
setDefaultCloseOperation(javax.swing.JDialog.DISPOSE_ON_CLOSE);
// attach cancel also to Escape key
getRootPane().registerKeyboardAction(
new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
setVisible(false);
dispose();
}
}, javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ESCAPE, 0, true),
javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW
);
setTitle(Node.getString("LAB_order"));
}
// closeButton
if (p == null) {
p = getContentPane();
}
p.setLayout(new GridBagLayout());
JLabel l = new JLabel(Node.getString("LAB_listOrder"));
l.setDisplayedMnemonic(Node.getString("LAB_listOrder_Mnemonic").charAt(0));
constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.WEST;
constraints.insets = new Insets(12, 12, 2, 12);
p.add(l, constraints);
control = new AutoscrollJList();
l.setLabelFor(control);
control.addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (control.isSelectionEmpty()) {
buttonUp.setEnabled(false);
buttonDown.setEnabled(false);
} else {
int i = control.getSelectedIndex();
if (i > 0) { //PENDING - jeste testovat, jestli jsou OrderedCookie.Child
buttonUp.setEnabled(true);
} else {
buttonUp.setEnabled(false);
}
if (i < (nodes.length - 1)) {
buttonDown.setEnabled(true);
} else {
buttonDown.setEnabled(false);
}
}
}
}
);
control.setCellRenderer(new IndexedListCellRenderer());
control.setVisibleRowCount(15);
control.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// list has to be scrolling
constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 1;
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1.0;
constraints.weighty = 1.0;
constraints.insets = new Insets(0, 12, 11, 11);
p.add(new JScrollPane(control), constraints);
JPanel bb = new JPanel();
if (closeButton) {
buttonClose = new JButton(Node.getString("Button_close"));
buttonClose.setMnemonic(Node.getString("Button_close_Mnemonic").charAt(0));
}
buttonUp = new JButton(Node.getString("Button_up"));
buttonUp.setMnemonic(Node.getString("Button_up_Mnemonic").charAt(0));
buttonDown = new JButton(Node.getString("Button_down"));
buttonDown.setMnemonic(Node.getString("Button_down_Mnemonic").charAt(0));
bb.setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.NORTH;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets = new Insets(0, 0, 5, 11);
bb.add(buttonUp, constraints);
constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 1;
constraints.anchor = GridBagConstraints.NORTH;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.weighty = 1.0;
constraints.insets = new Insets(0, 0, 0, 11);
bb.add(buttonDown, constraints);
if (closeButton) {
constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 2;
constraints.anchor = GridBagConstraints.SOUTH;
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.insets = new Insets(0, 0, 11, 11);
bb.add(buttonClose, constraints);
}
buttonUp.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i = control.getSelectedIndex();
moveUp(i);
updateList();
control.setSelectedIndex(i - 1);
control.ensureIndexIsVisible(i - 1);
control.repaint();
}
}
);
buttonDown.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i = control.getSelectedIndex();
moveDown(i);
updateList();
control.setSelectedIndex(i + 1);
control.ensureIndexIsVisible(i + 1);
control.repaint();
}
}
);
if (closeButton) {
buttonClose.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
doClose();
dispose();
}
}
);
}
buttonUp.setEnabled(false);
buttonDown.setEnabled(false);
constraints = new GridBagConstraints();
constraints.gridx = 1;
constraints.gridy = 1;
constraints.fill = GridBagConstraints.VERTICAL;
p.add(bb, constraints);
// disable drag support, as DnD crashes all environment
// under current implementation of VMs on unixes, ans causes
// some deadlocks on windows...
//dragSupport = new IndexedDragSource(control);
//dropSupport = new IndexedDropTarget(this, dragSupport);
if (closeButton) {
pack();
setBounds(org.openide.util.Utilities.findCenterBounds(getSize()));
buttonClose.requestFocus(); // to get shortcuts to work
buttonClose.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_close"));
}
buttonUp.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_up"));
buttonDown.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_Button_down"));
control.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_ListOrder"));
p.getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_IndexedCustomizer"));
getAccessibleContext().setAccessibleDescription(Node.getString("ACSD_IndexedCustomizer"));
}
/** Simulate behavior of the Close button, minus actual dialog disposal.
* Might do the same as setImmediateReorder(true), but I am not sure.
*/
void doClose() {
if ((!immediateReorder) && (index != null) && (permutation != null)) {
int[] realPerm = new int[permutation.length];
for (int i = 0; i < realPerm.length; i++) {
realPerm[permutation[i]] = i;
//System.out.println (i + "-->" + permutation[i]); // NOI18N
}
index.reorder(realPerm);
}
}
// other methods ................................................................................
/** Called when an explored context changes and the list needs to be
* recreated.
*/
private void updateList() {
if (index == null) {
return;
}
Node[] localNodes = index.getNodes();
//System.out.println ("Nodes taken, size: " + localNodes.length); // NOI18N
// obtain nodes with help from permutation array, if
// conditions met
if (!immediateReorder) {
getPermutation();
int origLength = permutation.length;
int newLength = localNodes.length;
if (origLength < newLength) {
// some nodes added, we must synchronize the permutation
nodes = new Node[newLength];
int[] newPerm = new int[newLength];
System.arraycopy(newPerm, 0, permutation, 0, origLength);
for (int i = 0; i < newLength; i++) {
if (i < origLength) {
nodes[i] = localNodes[permutation[i]];
} else {
// added nodes....
nodes[i] = localNodes[i];
newPerm[i] = i;
}
}
permutation = newPerm;
} else if (origLength > newLength) {
// some nodes removed, we must re-initialize the permutation
nodes = new Node[newLength];
permutation = new int[newLength];
for (int i = 0; i < newLength; i++) {
nodes[i] = localNodes[i];
permutation[i] = i;
}
} else {
// node count is the same, only permute the nodes
nodes = new Node[newLength];
for (int i = 0; i < newLength; i++)
nodes[i] = localNodes[permutation[i]];
}
} else {
nodes = localNodes.clone();
}
control.setListData(nodes);
if ((nodes.length > 0) && (control.getSelectedIndex() == -1)) {
control.setSelectedIndex(0);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, super.getPreferredSize().height);
}
/** Will reorders be reflected immediately?
* @return true
if so
*/
public boolean isImmediateReorder() {
return immediateReorder;
}
/** Set whether reorders will take effect immediately.
* @param immediateReorder true
if so
*/
public void setImmediateReorder(boolean immediateReorder) {
if (this.immediateReorder == immediateReorder) {
return;
}
this.immediateReorder = immediateReorder;
if (immediateReorder) {
if (permutation != null) {
index.reorder(permutation);
permutation = null;
updateList();
}
}
}
// implementation of Customizer ............................................................
/** Set the nodes to reorder.
* @param bean must implement {@link Index}
* @throws IllegalArgumentException if not
*/
public void setObject(Object bean) {
if (bean instanceof Index) {
index = (Index) bean;
// add weak listener to the Index
nodeChangesL = new ChangeListener() {
public void stateChanged(ChangeEvent ev) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
updateList();
}
}
);
}
};
updateList();
control.invalidate();
validate();
index.addChangeListener(org.openide.util.WeakListeners.change(nodeChangesL, index));
} else {
throw new IllegalArgumentException();
}
}
// I don't change any property...
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
}
/** Moves up. Performs differently according to
* immediateReorder property value.
*/
private void moveUp(final int position) {
if (index == null) {
return;
}
if (immediateReorder) {
index.moveUp(position);
} else {
getPermutation();
int temp = permutation[position];
permutation[position] = permutation[position - 1];
permutation[position - 1] = temp;
}
}
/** Moves down. Performs differently according to
* immediateReorder property value.
*/
private void moveDown(final int position) {
if (index == null) {
return;
}
if (immediateReorder) {
index.moveDown(position);
} else {
getPermutation();
int temp = permutation[position];
permutation[position] = permutation[position + 1];
permutation[position + 1] = temp;
}
}
/** Safe getter for permutation.
* Initializes permutation to identical permutation if it is null.
* index variable must not be null when this method called */
private int[] getPermutation() {
if (permutation == null) {
if (nodes == null) {
nodes = index.getNodes().clone();
}
permutation = new int[nodes.length];
for (int i = 0; i < nodes.length; permutation[i] = i++)
;
}
return permutation;
}
/** Permute the list as given permutation dictates.
* Sets selection to the given selected index.
* Called from dropSupport as result of succesfull DnD operation.
*/
void performReorder(int[] perm, int selected) {
if (immediateReorder) {
index.reorder(perm);
} else {
// merge current and reversed given permutation
// (reverse given permutation first)
int[] reversed = new int[perm.length];
for (int i = 0; i < reversed.length; i++)
reversed[perm[i]] = i;
int[] orig = getPermutation();
permutation = new int[orig.length];
for (int i = 0; i < orig.length; i++) {
permutation[i] = orig[reversed[i]];
// System.out.println(permutation[i] + " ----> " + i); // NOI18N
}
}
updateList();
control.setSelectedIndex(selected);
control.repaint();
}
/** Implementation of drag functionality in
* reorder dialog. */
private static final class IndexedDragSource implements DragGestureListener, DragSourceListener {
/** Asociated JList component where the drag will
* take place */
JList comp;
/** User gesture that initiated the drag */
DragGestureEvent dge;
/** Out data flavor used to transfer the index */
DataFlavor myFlavor;
/** Creates drag source with asociated list where drag
* will take place.
* Also creates the default gesture and asociates this with
* given component */
IndexedDragSource(JList comp) {
this.comp = comp;
// initialize gesture
DragSource ds = DragSource.getDefaultDragSource();
ds.createDefaultDragGestureRecognizer(comp, DnDConstants.ACTION_MOVE, this);
}
/** Initiating the drag */
public void dragGestureRecognized(DragGestureEvent dge) {
// check allowed actions
if ((dge.getDragAction() & DnDConstants.ACTION_MOVE) == 0) {
return;
}
// prepare transferable and start the drag
int index = comp.locationToIndex(dge.getDragOrigin());
// no index, then no dragging...
if (index < 0) {
return;
}
// System.out.println("Starting drag..."); // NOI18N
// create our flavor for transferring the index
myFlavor = new DataFlavor(
String.class, NbBundle.getBundle(IndexedCustomizer.class).getString("IndexedFlavor")
);
try {
dge.startDrag(DragSource.DefaultMoveDrop, new IndexTransferable(myFlavor, index), this);
// remember the gesture
this.dge = dge;
} catch (InvalidDnDOperationException exc) {
Logger.getLogger(IndexedCustomizer.class.getName()).log(Level.WARNING, null, exc);
// PENDING notify user - cannot start the drag
}
}
public void dragEnter(DragSourceDragEvent dsde) {
}
public void dragOver(DragSourceDragEvent dsde) {
}
public void dropActionChanged(DragSourceDragEvent dsde) {
}
public void dragExit(DragSourceEvent dse) {
}
public void dragDropEnd(DragSourceDropEvent dsde) {
}
/** Utility accessor */
DragGestureEvent getDragGestureEvent() {
return dge;
}
}
// end of IndexedDragSource
/** Implementation of drop functionality in
* reorder dialog. */
private static final class IndexedDropTarget implements DropTargetListener {
/** Asociated JList component for dropping */
JList comp;
/** Cell renderer which renders the list items */
IndexedListCellRenderer cellRenderer;
/** Indexed dialog */
IndexedCustomizer dialog;
/** Drag source support instance */
IndexedDragSource ids;
/** last index dragged over */
int lastIndex = -1;
/** Creates the instance, makes given component active for
* drop operation. */
IndexedDropTarget(IndexedCustomizer dialog, IndexedDragSource ids) {
this.dialog = dialog;
this.comp = dialog.control;
this.cellRenderer = (IndexedListCellRenderer) this.comp.getCellRenderer();
this.ids = ids;
new DropTarget(comp, DnDConstants.ACTION_MOVE, this, true);
}
/** User is starting to drag over us */
public void dragEnter(DropTargetDragEvent dtde) {
if (!checkConditions(dtde)) {
dtde.rejectDrag();
} else {
lastIndex = comp.locationToIndex(dtde.getLocation());
cellRenderer.draggingEnter(lastIndex, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation());
comp.repaint(comp.getCellBounds(lastIndex, lastIndex));
}
}
/** User drag over us */
public void dragOver(DropTargetDragEvent dtde) {
if (!checkConditions(dtde)) {
dtde.rejectDrag();
if (lastIndex >= 0) {
cellRenderer.draggingExit();
comp.repaint(comp.getCellBounds(lastIndex, lastIndex));
lastIndex = -1;
}
} else {
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
int index = comp.locationToIndex(dtde.getLocation());
if (lastIndex == index) {
cellRenderer.draggingOver(index, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation());
} else {
if (lastIndex < 0) {
lastIndex = index;
}
cellRenderer.draggingExit();
cellRenderer.draggingEnter(index, ids.getDragGestureEvent().getDragOrigin(), dtde.getLocation());
comp.repaint(comp.getCellBounds(lastIndex, index));
lastIndex = index;
}
}
}
public void dropActionChanged(DropTargetDragEvent dtde) {
}
/** User exits the dragging */
public void dragExit(DropTargetEvent dte) {
if (lastIndex >= 0) {
cellRenderer.draggingExit();
comp.repaint(comp.getCellBounds(lastIndex, lastIndex));
}
}
/** Takes given index transferable and reorders
* the items as appropriate (and if possible) */
public void drop(DropTargetDropEvent dtde) {
// reject all but local moves
if ((DnDConstants.ACTION_MOVE != dtde.getDropAction()) || !dtde.isLocalTransfer()) {
dtde.rejectDrop();
}
int target = comp.locationToIndex(dtde.getLocation());
if (target < 0) {
dtde.rejectDrop();
return;
}
Transferable t = dtde.getTransferable();
// System.out.println("Dropping..."); // NOI18N
dtde.acceptDrop(DnDConstants.ACTION_MOVE);
try {
int source = Integer.parseInt((String) t.getTransferData(ids.myFlavor));
if (source != target) {
performReorder(source, target);
dtde.dropComplete(true);
} else {
dtde.dropComplete(false);
}
} catch (IOException exc) {
dtde.dropComplete(false);
} catch (UnsupportedFlavorException exc) {
dtde.dropComplete(false);
} catch (NumberFormatException exc) {
dtde.dropComplete(false);
}
}
/** Actually performs the reordering which results from
* succesfull drag-drop operation.
* @param source
*/
void performReorder(int source, int target) {
int[] myPerm = new int[comp.getModel().getSize()];
// positions will change only between source and target
// indexes, the rest remains the same
for (int i = 0; i < Math.min(source, target); i++)
myPerm[i] = i;
for (int i = Math.max(source, target) + 1; i < myPerm.length; i++)
myPerm[i] = i;
// reorder the rest
myPerm[source] = target;
if (source > target) {
// dragging was up the list
for (int i = target; i < source; i++)
myPerm[i] = i + 1;
} else {
// dragging was down the list
for (int i = source + 1; i < (target + 1); i++)
myPerm[i] = i - 1;
}
// and finally perform the reordering
dialog.performReorder(myPerm, target);
}
/** @return True if conditions to continue with DnD
* operation were satisfied */
boolean checkConditions(DropTargetDragEvent dtde) {
int index = comp.locationToIndex(dtde.getLocation());
return (DnDConstants.ACTION_MOVE == dtde.getDropAction()) && (index >= 0);
}
}
// end of IndexedDropTarget
/** This class takes responsibility of presenting the
* asociated index as transferable object.
*/
private static final class IndexTransferable extends ExTransferable.Single {
/** Index to transfer */
int index;
/** Creates transferable of given index */
IndexTransferable(DataFlavor flavor, int index) {
super(flavor);
this.index = index;
}
/* Returns string representation of index */
protected Object getData() throws IOException, UnsupportedFlavorException {
return String.valueOf(index);
}
}
// end of IndexTransferable
/** Implements drag and drop visual feedback
* support for node list cell rendeder.
*/
private static final class IndexedListCellRenderer implements javax.swing.ListCellRenderer {
static final long serialVersionUID = -5526451942677242944L;
protected static Border hasFocusBorder;
static {
hasFocusBorder = new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N
}
/** delegate to use for rendering. Usually NodeRenderer, but if run
* without explorer, then it uses DefaultListCellRenderer
*/
private javax.swing.ListCellRenderer delegate = TMUtil.findListCellRenderer();
/** Index of currently drag under cell in parent list */
int dragIndex;
/** Creates new renderer */
IndexedListCellRenderer() {
dragIndex = -1;
}
/** DnD operation enters, update visual
* presentation to the drag under state */
public void draggingEnter(int index, Point startingLoc, Point currentLoc) {
// System.out.println("Entering index: " + index); // NOI18N
this.dragIndex = index;
}
/** DnD operation dragging over. */
public void draggingOver(int index, Point startingLoc, Point currentLoc) {
}
/** DnD operation exits, reset visual state
* back to the normal */
public void draggingExit() {
dragIndex = -1;
}
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus
) {
JComponent result = (JComponent) delegate.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus
);
if (index == dragIndex) {
// System.out.println("Drawing...."); // NOI18N
result.setBorder(hasFocusBorder);
}
return result;
}
}
// end of IndexedListCellRenderer
/** Implements autoscrolling support for JList.
* However, JList must be contained in some JViewport.
*/
private static class AutoscrollJList extends JList implements Autoscroll {
static final long serialVersionUID = 5495776972406885734L;
/** Autoscroll insets */
Insets scrollInsets;
/** Insets for the autoscroll method to decide
* whether really perform or not */
Insets realInsets;
/** Viewport we are in */
JViewport viewport;
AutoscrollJList() {
}
/** notify the Component to autoscroll */
public void autoscroll(Point cursorLoc) {
JViewport viewport = getViewport();
Point viewPos = viewport.getViewPosition();
int viewHeight = viewport.getExtentSize().height;
if ((cursorLoc.y - viewPos.y) <= realInsets.top) {
// scroll up
viewport.setViewPosition(new Point(viewPos.x, Math.max(viewPos.y - realInsets.top, 0)));
} else if (((viewPos.y + viewHeight) - cursorLoc.y) <= realInsets.bottom) {
// scroll down
viewport.setViewPosition(
new Point(viewPos.x, Math.min(viewPos.y + realInsets.bottom, this.getHeight() - viewHeight))
);
}
}
/** @return the Insets describing the autoscrolling
* region or border relative to the geometry of the
* implementing Component.
*/
public Insets getAutoscrollInsets() {
if (scrollInsets == null) {
int height = this.getHeight();
scrollInsets = new Insets(height, 0, height, 0);
// compute also autoscroll insets for viewport
//Rectangle rect = getViewport().getViewRect();
realInsets = new Insets(15, 0, 15, 0);
}
return scrollInsets;
}
/** Asociates given viewport with this list.
* (Viewport is usually parent containing this component) */
JViewport getViewport() {
if (viewport == null) {
Component comp = this;
while (!(comp instanceof JViewport) && (comp != null)) {
comp = comp.getParent();
}
viewport = (JViewport) comp;
}
return viewport;
}
}
// end of AutoscrollJViewport
}