📄 rtextareaui.java~1~
字号:
/*
* 07/29/2004
*
* RTextAreaUI.java - UI used by instances of RTextArea.
* 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.beans.PropertyChangeEvent;
import java.awt.*;
import java.awt.dnd.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import java.awt.event.*;
import java.util.HashSet;
import java.util.Set;
import java.util.TooManyListenersException;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.text.*;
import javax.swing.plaf.*;
/**
* The UI used by instances of <code>RTextArea</code>. This UI takes into
* account all of the "extras" involved in an <code>RTextArea</code>, including
* having a special caret (for insert and overwrite), background images,
* highlighting the current line, etc.
*
* @author Robert Futrell
* @version 0.2
*/
public class RTextAreaUI extends TextUI implements ViewFactory {
private static final String RTEXTAREA_KEYMAP_NAME = "RTextAreaKeymap";
private static final String SHARED_ACTION_MAP_NAME = "RTextAreaUI.actionMap";
private static final String SHARED_INPUT_MAP_NAME = "RTextAreaUI.inputMap";
protected RTextArea textArea; // The text area for which we are the UI.
RTARootView rootView; // Our root view.
protected boolean painted;
private static final EditorKit defaultKit = new RTextAreaEditorKit();
private static final Position.Bias[] discardBias = new Position.Bias[1];
// Listeners.
private TextDragGestureRecognizer defaultDragRecognizer = new TextDragGestureRecognizer();
private RTAUpdateHandler updateHandler = new RTAUpdateHandler(this);
private static final RTATextTransferHandler transferHandler = new RTATextTransferHandler();
static RTADropTargetListener dropTargetListener = null;
/*****************************************************************************/
/**
* Creates a UI for an RTextArea.
*
* @param rTextArea A text area.
* @return The UI.
*/
public static ComponentUI createUI(JComponent rTextArea) {
return new RTextAreaUI(rTextArea);
}
/*****************************************************************************/
/**
* Constructor.
*
* @param rTextArea An instance of <code>RTextArea</code>.
* @throws IllegalArgumentException If <code>rTextArea</code> is not an
* instance of <code>RTextArea</code>.
*/
public RTextAreaUI(JComponent rTextArea) {
super();
if (!(rTextArea instanceof RTextArea)) {
throw new IllegalArgumentException("RTextAreaUI is for " +
"instances of RTextArea only!");
}
}
/*****************************************************************************/
/**
* Creates the view for an element. Returns a WrappedPlainView or
* PlainView.
*
* @param elem The element.
* @return The view.
*/
public View create(Element elem) {
if (textArea.getLineWrap())
return new WrappedPlainView(elem, textArea.getWrapStyleWord());
else
return new PlainView(elem);
}
/*****************************************************************************/
/**
* Create a default action map. This action map contains actions for all
* basic text area work - cut, copy, paste, select, caret motion, etc.
*/
ActionMap createActionMap() {
// Get the actions of the text area (which in turn gets them from its
// DefaultEditorKit).
ActionMap map = new ActionMapUIResource();
Action[] actions = textArea.getActions();
int n = actions.length;
for (int i = 0; i < n; i++) {
Action a = actions[i];
map.put(a.getValue(Action.NAME), a);
}
// Make some basic actions shared only between instances of RTextArea
// (as opposed to all JTextComponents) so we can do with them what we
// like.
// FIXME: Make sure I'm right!
map.put(DefaultEditorKit.cutAction, RTextArea.getAction(RTextArea.CUT_ACTION));
map.put(DefaultEditorKit.copyAction, RTextArea.getAction(RTextArea.COPY_ACTION));
map.put(DefaultEditorKit.pasteAction, RTextArea.getAction(RTextArea.PASTE_ACTION));
map.put(DefaultEditorKit.deleteNextCharAction, RTextArea.getAction(RTextArea.DELETE_ACTION));
map.put(DefaultEditorKit.selectAllAction, RTextArea.getAction(RTextArea.SELECT_ALL_ACTION));
// Not sure if we need these; not sure they are ever called
// (check their NAMEs).
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());
return map;
}
/*****************************************************************************/
/**
* Returns the default caret for an <code>RTextArea</code>. This caret is
* capable of displaying itself differently for insert/overwrite modes.
*/
protected Caret createCaret() {
Caret caret = new ConfigurableCaret();
caret.setBlinkRate(500);
return caret;
}
/*****************************************************************************/
/**
* Creates the default highlighter for this text area.
*/
protected Highlighter createHighlighter() {
return new DefaultHighlighter();
}
/*****************************************************************************/
/**
* Creates the keymap for this text area. This simply returns the default
* <code>JTextComponent</code> keymap, which I believe is empty, as Sun
* likes the <code>InputMap</code>/<code>ActionMap</code> approach to input
* better.
*/
protected Keymap createKeymap() {
// Load the keymap we'll be using (it's saved by
// JTextComponent.addKeymap).
// NOTE that this is EMPTY because the preferred route is to use
// the InputMap/ActionMap route now (right?).
Keymap map = JTextComponent.getKeymap(RTEXTAREA_KEYMAP_NAME);
if (map == null) {
Keymap parent = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
map = JTextComponent.addKeymap(RTEXTAREA_KEYMAP_NAME, parent);
map.setDefaultAction(new RTextAreaEditorKit.DefaultKeyTypedAction());
}
return map;
}
/*****************************************************************************/
/**
* Causes the portion of the view responsible for the
* given part of the model to be repainted. Does nothing if
* the view is not currently painted.
*
* @param tc the text component for which this UI is installed
* @param p0 the beginning of the range >= 0
* @param p1 the end of the range >= p0
* @see TextUI#damageRange
*/
public void damageRange(JTextComponent tc, int p0, int p1) {
damageRange(tc, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
}
/*****************************************************************************/
/**
* Causes the portion of the view responsible for the
* given part of the model to be repainted.
*
* @param p0 the beginning of the range >= 0
* @param p1 the end of the range >= p0
*/
public void damageRange(JTextComponent t, int p0, int p1,
Position.Bias p0Bias, Position.Bias p1Bias) {
if (painted) {
Rectangle alloc = getVisibleEditorRect();
RTextAreaDocument doc = (RTextAreaDocument)t.getDocument();
doc.readLock();
try {
rootView.setSize(alloc.width, alloc.height);
Shape toDamage = rootView.modelToView(p0, p0Bias,
p1, p1Bias, alloc);
Rectangle rect = (toDamage instanceof Rectangle) ?
(Rectangle)toDamage : toDamage.getBounds();
textArea.repaint(rect.x, rect.y, rect.width, rect.height);
} catch (BadLocationException e) {
}finally {
doc.readUnlock();
}
}
}
/*****************************************************************************/
/**
* Fetch an action map to use.
*/
ActionMap getActionMap() {
// Get the UIManager-cached action map; if this is the first
// RTextArea created, create the action map and cache it.
ActionMap map = (ActionMap)UIManager.get(getActionMapName());
if (map==null) {
map = createActionMap();
UIManager.put(SHARED_ACTION_MAP_NAME, map);
}
ActionMap componentMap = new ActionMapUIResource();
componentMap.put("requestFocus", new FocusAction());
if (map != null)
componentMap.setParent(map);
return componentMap;
}
/*****************************************************************************/
/**
* Returns the name to use to cache/fetch the shared action map. This
* should be overridden by subclasses if the subclass has its own custom
* editor kit to install, so its actions get picked up.
*
* @return The name of the cached action map.
*/
protected String getActionMapName() {
return SHARED_ACTION_MAP_NAME;
}
/*****************************************************************************/
/**
* Fetches the EditorKit for the UI.
*
* @param tc the text component for which this UI is installed
* @return the editor capabilities
* @see TextUI#getEditorKit
*/
public EditorKit getEditorKit(JTextComponent tc) {
return defaultKit;
}
/*****************************************************************************/
/**
* Get the InputMap to use for the UI.
*/
protected InputMap getInputMap() {
InputMap map = new InputMapUIResource();
InputMap shared = (InputMap)UIManager.get(SHARED_INPUT_MAP_NAME);
if (shared==null) {
shared = new RTADefaultInputMap();
UIManager.put(SHARED_INPUT_MAP_NAME, shared);
}
//KeyStroke[] keys = shared.allKeys();
//for (int i=0; i<keys.length; i++)
// System.err.println(keys[i] + " -> " + shared.get(keys[i]));
if (shared != null)
map.setParent(shared);
return map;
}
/*****************************************************************************/
/**
* Gets the minimum size for the editor component.
*
* @param c the editor component
* @return the size
*/
public Dimension getMinimumSize(JComponent c) {
RTextAreaDocument doc = (RTextAreaDocument)textArea.getDocument();
Insets i = c.getInsets();
Dimension d = new Dimension();
doc.readLock();
try {
d.width = (int) rootView.getMinimumSpan(View.X_AXIS) + i.left + i.right;
d.height = (int) rootView.getMinimumSpan(View.Y_AXIS) + i.top + i.bottom;
} finally {
doc.readUnlock();
}
return d;
}
/*****************************************************************************/
/**
* Gets the maximum size for the editor component.
*
* @param c the editor component
* @return the size
*/
public Dimension getMaximumSize(JComponent c) {
RTextAreaDocument doc = (RTextAreaDocument)textArea.getDocument();
Insets i = c.getInsets();
Dimension d = new Dimension();
doc.readLock();
try {
d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS) +
(long) i.left + (long) i.right, Integer.MAX_VALUE);
d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS) +
(long) i.top + (long) i.bottom, Integer.MAX_VALUE);
} finally {
doc.readUnlock();
}
return d;
}
/*****************************************************************************/
/**
* Provides a way to determine the next visually represented model
* location that one might place a caret. Some views may not be visible,
* they might not be in the same order found in the model, or they just
* might not allow access to some of the locations in the model.
*
* @param t The RTextArea for which to get the next visual position.
* @param pos The position to convert >= 0
* @param b The bias.
* @param direction The direction from the current position that can
* be thought of as the arrow keys typically found on a keyboard.
* This may be SwingConstants.WEST, SwingConstants.EAST,
* SwingConstants.NORTH, or SwingConstants.SOUTH.
* @return the location within the model that best represents the next
* location visual position.
* @exception BadLocationException
* @exception IllegalArgumentException for an invalid direction
*/
public int getNextVisualPositionFrom(JTextComponent t, int pos,
Position.Bias b, int direction, Position.Bias[] biasRet)
throws BadLocationException{
RTextAreaDocument doc = (RTextAreaDocument)textArea.getDocument();
doc.readLock();
try {
if (painted) {
Rectangle alloc = getVisibleEditorRect();
rootView.setSize(alloc.width, alloc.height);
return rootView.getNextVisualPositionFrom(pos, b, alloc,
direction, biasRet);
}
}
finally {
doc.readUnlock();
}
return -1;
}
/*****************************************************************************/
/**
* Gets the preferred size for the editor component. If the component
* has been given a size prior to receiving this request, it will
* set the size of the view hierarchy to reflect the size of the component
* before requesting the preferred size of the view hierarchy. This
* allows formatted views to format to the current component size before
* answering the request. Other views don't care about currently formatted
* size and give the same answer either way.
*
* @param c the editor component
* @return the size
*/
public Dimension getPreferredSize(JComponent c) {
RTextAreaDocument doc = (RTextAreaDocument)textArea.getDocument();
Insets i = c.getInsets();
Dimension d = c.getSize();
doc.readLock();
try {
if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) {
rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom);
}
else if (d.width == 0 && d.height == 0) {
// Probably haven't been layed out yet, force some sort of
// initial sizing.
rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
d.width = (int) Math.min((long) rootView.getPreferredSpan(View.X_AXIS) +
(long) i.left + (long) i.right, Integer.MAX_VALUE);
d.height = (int) Math.min((long) rootView.getPreferredSpan(View.Y_AXIS) +
(long) i.top + (long) i.bottom, Integer.MAX_VALUE);
} finally {
doc.readUnlock();
}
return d;
}
/*****************************************************************************/
/**
* Fetches the name used as a key to look up properties through the
* UIManager. This is used as a prefix to all the standard
* text properties.
*
* @return The name ("TextArea")
*/
protected String getPropertyPrefix() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -