📄 rtadroptargetlistener.java~1~
字号:
/*
* 07/29/2004
*
* RTADropTargetListener.java - Listens for drag-and-drop operations about to
* "drop" data into an RTextArea and handles things like scrolling the
* text area, selecting a location for the drop, etc.
* Copyright (C) 2004 Robert Futrell
* email@address.com
* www.website.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.fife.ui.rtextarea;
import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.*;
import javax.swing.*;
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;
/**
* Extends the "drop" functionality of an <code>RTextArea</code> so that a user
* that is dropping data into an <code>RTextArea</code> will have the text area
* scrolled if necessary, visually shows the drop location, etc.<p>
* This class is pretty much a ripoff of an inner class of
* <code>BasicTextUI</code>.
*
* @author Robert Futrell
* @version 0.1
*/
class RTADropTargetListener implements DropTargetListener, ActionListener {
private Timer timer;
private Point lastPosition;
private Rectangle outer = new Rectangle();
private Rectangle inner = new Rectangle();
private int hysteresis = 10;
private boolean canImport;
int dot;
int mark;
boolean visible;
/**
* The current component. The value is cached from the drop events and used
* by the timer. When a drag exits or a drop occurs, this value is cleared.
*/
private JComponent component;
/*****************************************************************************/
/**
* construct a DropTargetAutoScroller
* <P>
* @param c the <code>Component</code>
* @param p the <code>Point</code>
*/
protected RTADropTargetListener() {
}
/*****************************************************************************/
/**
* called to save the state of a component in case it needs to
* be restored because a drop is not performed.
*/
protected void saveComponentState() {
JTextComponent c = (JTextComponent)component;
Caret caret = c.getCaret();
dot = caret.getDot();
mark = caret.getMark();
visible = caret.isVisible();//caret instanceof DefaultCaret ?
//((DefaultCaret)caret).isActive() :
//caret.isVisible();
caret.setVisible(true);
}
/*****************************************************************************/
/**
* called to restore the state of a component
* because a drop was not performed.
*/
protected void restoreComponentState() {
JTextComponent c = (JTextComponent)component;
Caret caret = c.getCaret();
caret.setDot(mark);
caret.moveDot(dot);
caret.setVisible(visible);
}
/*****************************************************************************/
/**
* called to restore the state of a component
* because a drop was performed.
*/
protected void restoreComponentStateForDrop() {
JTextComponent c = (JTextComponent)component;
Caret caret = c.getCaret();
caret.setVisible(visible);
}
/*****************************************************************************/
/**
* called to set the insertion location to match the current
* mouse pointer coordinates.
*/
protected void updateInsertionLocation(Point p) {
JTextComponent c = (JTextComponent)component;
c.setCaretPosition(c.viewToModel(p));
}
/*****************************************************************************/
/**
* Update the geometry of the autoscroll region. The geometry is
* maintained as a pair of rectangles. The region can cause
* a scroll if the pointer sits inside it for the duration of the
* timer. The region that causes the timer countdown is the area
* between the two rectangles.
* <p>
* This is implemented to use the visible area of the component
* as the outer rectangle and the insets are based upon the
* Scrollable information (if any). If the Scrollable is
* scrollable along an axis, the step increment is used as
* the autoscroll inset. If the component is not scrollable,
* the insets will be zero (i.e. autoscroll will not happen).
*/
void updateAutoscrollRegion(JComponent c) {
// compute the outer
Rectangle visible = c.getVisibleRect();
outer.setBounds(visible.x, visible.y, visible.width, visible.height);
// compute the insets
// TBD - the thing with the scrollable
Insets i = new Insets(0, 0, 0, 0);
if (c instanceof Scrollable) {
Scrollable s = (Scrollable) c;
i.left = s.getScrollableUnitIncrement(visible, SwingConstants.HORIZONTAL, 1);
i.top = s.getScrollableUnitIncrement(visible, SwingConstants.VERTICAL, 1);
i.right = s.getScrollableUnitIncrement(visible, SwingConstants.HORIZONTAL, -1);
i.bottom = s.getScrollableUnitIncrement(visible, SwingConstants.VERTICAL, -1);
}
// set the inner from the insets
inner.setBounds(visible.x + i.left,
visible.y + i.top,
visible.width - (i.left + i.right),
visible.height - (i.top + i.bottom));
}
/*****************************************************************************/
/**
* Perform an autoscroll operation. This is implemented to scroll by the
* unit increment of the Scrollable using scrollRectToVisible. If the
* cursor is in a corner of the autoscroll region, more than one axis will
* scroll.
*/
void autoscroll(JComponent c, Point pos) {
if (c instanceof Scrollable) {
Scrollable s = (Scrollable) c;
if (pos.y < inner.y) {
// scroll top downward
int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, 1);
Rectangle r = new Rectangle(inner.x, outer.y - dy, inner.width, dy);
c.scrollRectToVisible(r);
}
else if (pos.y > (inner.y + inner.height)) {
// scroll bottom upward
int dy = s.getScrollableUnitIncrement(outer, SwingConstants.VERTICAL, -1);
Rectangle r = new Rectangle(inner.x, outer.y + outer.height, inner.width, dy);
c.scrollRectToVisible(r);
}
if (pos.x < inner.x) {
// scroll left side to the right
int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, 1);
Rectangle r = new Rectangle(outer.x - dx, inner.y, dx, inner.height);
c.scrollRectToVisible(r);
}
else if (pos.x > (inner.x + inner.width)) {
// scroll right side to the left
int dx = s.getScrollableUnitIncrement(outer, SwingConstants.HORIZONTAL, -1);
Rectangle r = new Rectangle(outer.x + outer.width, inner.y, dx, inner.height);
c.scrollRectToVisible(r);
}
}
}
/*****************************************************************************/
/**
* Initializes the internal properties if they haven't been already
* inited. This is done lazily to avoid loading of desktop properties.
*/
private void initPropertiesIfNecessary() {
if (timer == null) {
Toolkit t = Toolkit.getDefaultToolkit();
Integer initial = new Integer(100);
Integer interval = new Integer(100);
try {
initial = (Integer)t.getDesktopProperty(
"DnD.Autoscroll.initialDelay");
} catch (Exception e) {
// ignore
}
try {
interval = (Integer)t.getDesktopProperty(
"DnD.Autoscroll.interval");
} catch (Exception e) {
// ignore
}
timer = new Timer(interval.intValue(), this);
timer.setCoalesce(true);
timer.setInitialDelay(initial.intValue());
try {
hysteresis = ((Integer)t.getDesktopProperty(
"DnD.Autoscroll.cursorHysteresis")).intValue();
} catch (Exception e) {
// ignore
}
}
}
/*****************************************************************************/
static JComponent getComponent(DropTargetEvent e) {
DropTargetContext context = e.getDropTargetContext();
return (JComponent) context.getComponent();
}
/*****************************************************************************/
/**
* The timer fired, perform autoscroll if the pointer is within the
* autoscroll region.
* <P>
* @param e the <code>ActionEvent</code>
*/
public synchronized void actionPerformed(ActionEvent e) {
updateAutoscrollRegion(component);
if (outer.contains(lastPosition) && !inner.contains(lastPosition))
autoscroll(component, lastPosition);
}
/*****************************************************************************/
public void dragEnter(DropTargetDragEvent e) {
component = getComponent(e);
TransferHandler th = component.getTransferHandler();
canImport = th.canImport(component, e.getCurrentDataFlavors());
if (canImport) {
saveComponentState();
lastPosition = e.getLocation();
updateAutoscrollRegion(component);
initPropertiesIfNecessary();
}
}
/*****************************************************************************/
public void dragOver(DropTargetDragEvent e) {
if (canImport) {
Point p = e.getLocation();
updateInsertionLocation(p);
// check autoscroll
synchronized(this) {
if (Math.abs(p.x - lastPosition.x) > hysteresis ||
Math.abs(p.y - lastPosition.y) > hysteresis) {
// no autoscroll
if (timer.isRunning())
timer.stop();
}
else {
if (!timer.isRunning())
timer.start();
}
lastPosition = p;
}
}
}
/*****************************************************************************/
public void dragExit(DropTargetEvent e) {
if (canImport)
restoreComponentState();
cleanup();
}
/*****************************************************************************/
public void drop(DropTargetDropEvent e) {
if (canImport)
restoreComponentStateForDrop();
cleanup();
}
/*****************************************************************************/
public void dropActionChanged(DropTargetDragEvent e) {
}
/*****************************************************************************/
/**
* Cleans up internal state after the drop has finished (either succeeded
* or failed).
*/
private void cleanup() {
if (timer != null)
timer.stop();
component = null;
lastPosition = null;
}
/*****************************************************************************/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -