⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtextareaui.java~1~

📁 具有不同语法高亮的编辑器实例
💻 JAVA~1~
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -