📄 rtextarea.java
字号:
/*
* 11/14/2003
*
* RTextArea.java - An extension of JTextArea that adds many features (see
* below).
* Copyright (C) 2003 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.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.UndoableEditEvent;
import javax.swing.plaf.TextUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.CompoundEdit;
import javax.swing.undo.UndoableEdit;
import javax.swing.undo.UndoManager;
import org.fife.print.RPrintUtilities;
import org.fife.ui.rtextarea.Macro.MacroRecord;
import org.fife.ui.search.FindDialog;
/**
* An extension of <code>JTextArea</code> that adds the following features:
* <ul>
* <li>Insert/Overwrite modes (can be toggled via the Insert key)
* <li>A right-click popup menu with standard editing options
* <li>Macro support
* <li>"Mark all" functionality.
* <li>A way to change the background to an image (gif/jpg)
* <li>Highlight the current line (can be toggled)
* <li>An easy way to print its text (implements Printable)
* <li>Hard/soft (emulated with spaces) tabs
* <li>Fixes a bug with setTabSize
* <li>Other handy new methods
* </ul>
* NOTE: If the background for an <code>RTextArea</code> is set to a color,
* its opaque property is set to <code>true</code> for performance reasons. If
* the background is set to an image, then the opaque property is set to
* <code>false</code>. This slows things down a little, but if it didn't happen
* then we would see garbage on-screen when the user scrolled through a document
* using the arrow keys (not the page-up/down keys though). You should never
* have to set the opaque property yourself; it is always done for you.
*
*
* @author Robert Futrell
* @version 1.0
*/
public class RTextArea
extends RTextAreaBase
implements Printable, Serializable {
/**
*
*/
private static final long serialVersionUID = 1232990564347480997L;
/**
* Constant representing insert mode.
*/
public static final int INSERT_MODE = 0;
/**
* Constant representing overwrite mode.
*/
public static final int OVERWRITE_MODE = 1;
public static final String MARK_ALL_COLOR_PROPERTY = "RTextArea.markAllColor";
/**
* Constants for all actions.
*/
private static final int MIN_ACTION_CONSTANT = 0;
public static final int CUT_ACTION = 0;
public static final int COPY_ACTION = 1;
public static final int PASTE_ACTION = 2;
public static final int DELETE_ACTION = 3;
public static final int UNDO_ACTION = 4;
public static final int REDO_ACTION = 5;
public static final int SELECT_ALL_ACTION = 6;
private static final int MAX_ACTION_CONSTANT = 6;
private static final Color DEFAULT_MARK_ALL_COLOR = Color.ORANGE;
private int textMode; // Either INSERT_MODE or OVERWRITE_MODE.
// All macros are shared across all RTextAreas.
private static boolean recordingMacro; // Whether we're recording a macro.
private static Macro currentMacro;
private static JPopupMenu rightClickMenu;
private static RecordableTextAction cutAction;
private static RecordableTextAction copyAction;
private static RecordableTextAction pasteAction;
private static RecordableTextAction deleteAction;
private static RecordableTextAction undoAction;
private static RecordableTextAction redoAction;
private static RecordableTextAction selectAllAction;
private static IconGroup iconGroup; // Info on icons for actions.
private RUndoManager undoManager;
private ArrayList markAllHighlights; // Highlights from "mark all".
private String markedWord; // Expression marked in "mark all."
private ChangableHighlightPainter markAllHighlightPainter;
private boolean inUndoRedo;
public static final int INSERT_CARET = 0;
public static final int OVERWRITE_CARET = 1;
private int[] carets; // Index 0=>insert caret, 1=>overwrite.
private static String cantUndoText;
private static String cantRedoText;
private static final String RESOURCE_BUNDLE =
"org.fife.ui.rtextarea.RTextArea";
/*****************************************************************************/
/**
* Creates a new <code>RTextArea</code> with the following properties:
* 10-point monospaced font, no word wrap, INSERT_MODE, Plain white
* background, tab size of 5 spaces, and font color of black.
*/
public RTextArea() {
this(new Font("monospaced", Font.PLAIN, 10), false, INSERT_MODE);
}
/*****************************************************************************/
/**
* Creates a new <code>RTextArea</code>.
*
* @param font The font to use in this text area.
* @param wordWrapEnabled Whether or not to use word wrap.
* @param textMode Either <code>INSERT_MODE</code> or
* <code>OVERWRITE_MODE</code>.
*/
public RTextArea(Font font, boolean wordWrapEnabled, int textMode) {
super(font, wordWrapEnabled);
// Create and initialize our actions. This will only do so once
// when the first RTextArea is created) as these actions are shared.
initActions(this);
// Set the line terminator property of the document to default to the
// OS value. We do this because by default, Documents do NOT have
// this property set (it only gets set when the document is populated
// via an EditorKit.read(doc, ...) method call). This mess up RText's
// "Document Properties" dialog, as it wants to display a line-terminator
// value even if the document is a new (unsaved) one. So, we'll just
// give it a default here.
getDocument().putProperty(
RTextAreaEditorKit.EndOfLineStringProperty,
System.getProperty("line.separator"));
// Set the defaults for various stuff.
Color markAllHighlightColor = getDefaultMarkAllHighlightColor();
markAllHighlightPainter = new ChangableHighlightPainter(
markAllHighlightColor);
setMarkAllHighlightColor(markAllHighlightColor);
carets = new int[2];
carets[INSERT_CARET] = ConfigurableCaret.VERTICAL_LINE_STYLE;
carets[OVERWRITE_CARET] = ConfigurableCaret.BLOCK_STYLE;
setDragEnabled(true); // Enable drag-and-drop.
// Set values for stuff the user passed in.
setTextMode(textMode); // carets array must be initialized first!
// Install the undo manager.
undoManager = new RUndoManager(this);
getDocument().addUndoableEditListener(undoManager);
// Fix the odd "Ctrl+H <=> Backspace" Java behavior.
fixCtrlH();
}
/*****************************************************************************/
/**
* Adds an action event to the current macro. This shouldn't be called
* directly, as it is called by the actions themselves.
*
* @param id The ID of the recordable text action.
* @param actionCommand The "command" of the action event passed to it.
*/
static synchronized void addToCurrentMacro(String id,
String actionCommand) {
currentMacro.addMacroRecord(new Macro.MacroRecord(id, actionCommand));
}
/*****************************************************************************/
/**
* Begins recording a macro. After this method is called, all input/caret
* events, etc. are recorded until <code>endMacroRecording</code> is
* called. If this method is called but the text component is already
* recording a macro, nothing happens (but the macro keeps recording).
*
* @see #isRecordingMacro
* @see #endRecordingMacro
*/
public static synchronized void beginRecordingMacro() {
if (isRecordingMacro()) {
//System.err.println("Macro already being recorded!");
return;
}
//JOptionPane.showMessageDialog(this, "Now recording a macro");
if (currentMacro != null) {
currentMacro = null; // May help gc?
}
currentMacro = new Macro();
recordingMacro = true;
}
/*****************************************************************************/
/**
* Clears any "mark all" highlights, if any.
*
* @see #markAll
* @see #getMarkAllHighlightColor
* @see #setMarkAllHighlightColor
*/
public void clearMarkAllHighlights() {
Highlighter h = getHighlighter();
if (h != null && markAllHighlights != null) {
int count = markAllHighlights.size();
for (int i = 0; i < count; i++) {
h.removeHighlight(markAllHighlights.get(i));
}
markAllHighlights.clear();
}
markedWord = null;
repaint();
}
/*****************************************************************************/
/**
* Returns the document to use for an <code>RTextArea</code>.
*
* @return The document.
*/
protected Document createDefaultModel() {
// return super.createDefaultModel();
return new RTextAreaDocument();
}
/*****************************************************************************/
/**
* Returns the caret event/mouse listener for <code>RTextArea</code>s.
*
* @return The caret event/mouse listener.
*/
protected RTAMouseListener createMouseListener() {
return new RTextAreaMutableCaretEvent(this);
}
/*****************************************************************************/
/**
* Initializes the right-click popup menu with appropriate actions.
*/
private static void createRightClickMenu() {
rightClickMenu = new JPopupMenu();
JMenuItem menuItem;
menuItem = new JMenuItem(undoAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
menuItem = new JMenuItem(redoAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
rightClickMenu.addSeparator();
menuItem = new JMenuItem(cutAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
menuItem = new JMenuItem(copyAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
menuItem = new JMenuItem(pasteAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
menuItem = new JMenuItem(deleteAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
rightClickMenu.addSeparator();
menuItem = new JMenuItem(selectAllAction);
menuItem.setAccelerator(null);
menuItem.setToolTipText(null);
rightClickMenu.add(menuItem);
}
/*****************************************************************************/
/**
* Returns the a real UI to install on this text area.
*
* @return The UI.
*/
protected RTextAreaUI createRTextAreaUI() {
return new RTextAreaUI(this);
}
/*****************************************************************************/
/**
* Removes all undoable edits from this document's undo manager. This
* method also makes the undo/redo actions disabled.<br><br>
*
* NOTE: For some reason, it appears I have to create an entirely new
* <code>undoManager</code> for undo/redo to continue functioning
* properly; if I don't, it only ever lets you do one undo. Not
* too sure why this is...
*/
public void discardAllEdits() {
undoManager.discardAllEdits();
getDocument().removeUndoableEditListener(undoManager);
undoManager = new RUndoManager(this);
getDocument().addUndoableEditListener(undoManager);
undoManager.updateActions();
}
/*****************************************************************************/
/**
* Ends recording a macro. If this method is called but the text component
* is not recording a macro, nothing happens.
*
* @see #isRecordingMacro
* @see #beginRecordingMacro
*/
/*
* FIXME: This should throw an exception if we're not recording a macro.
*/
public static synchronized void endRecordingMacro() {
if (!isRecordingMacro()) {
//System.err.println("Not recording a macro!");
return;
}
recordingMacro = false;
}
/*****************************************************************************/
/**
* Finds the next instance of the string/regular expression specified
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -