📄 jexttextarea.java
字号:
/* * 03/13/2003 - 17:27:08 * * JextTextArea.java - An extended JEditTextArea * Copyright (C) 1998-2003 Romain Guy * Portions copyright (C) 1998-2000 Slava Pestov * romain.guy@jext.org * www.jext.org * * 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.jext;import gnu.regexp.*;import java.lang.reflect.Method;import java.io.*;import java.util.StringTokenizer;import java.util.zip.*;import java.awt.*;import java.awt.datatransfer.*;import java.awt.event.*;import javax.swing.undo.*;import javax.swing.event.*;import javax.swing.JComboBox;import javax.swing.JPopupMenu;import javax.swing.JOptionPane;import javax.swing.SwingUtilities;import javax.swing.text.Element;import javax.swing.text.Segment;import javax.swing.text.Position;import javax.swing.text.PlainDocument;import javax.swing.text.BadLocationException;import org.jext.event.JextEvent;import org.jext.misc.Workspaces;import org.jext.misc.ZipExplorer;import org.jext.search.*;import org.jext.xml.XPopupReader;import org.gjt.sp.jedit.syntax.*;import org.gjt.sp.jedit.textarea.*;/** * Extending JEditTextArea allow us to support syntax colorization. We also implement * some listeners: for the caret, for the undos and redos, for the keys (indent) * and for the modifications which can occures in the text. This component provides * its own methods to read and save files (even to zip them). * @author Romain Guy * @see Jext */public class JextTextArea extends JEditTextArea implements UndoableEditListener, DocumentListener{ // static fields private static JPopupMenu popupMenu; // private fields private JextFrame parent; // misc properties private String mode; private long modTime; private Position anchor; private int fontSize, fontStyle; private String fontName, currentFile; /*friendly*/ JComboBox lineTermSelector; // undo private boolean undoing; private UndoManager undo = new UndoManager(); private CompoundEdit compoundEdit, currentEdit = new CompoundEdit(); private boolean dirty, newf, operation, protectedCompoundEdit; //newf says whether this is a new file or not // highlighters private SearchHighlight searchHighlight; /** This constant defines the size of the buffer used to read files */ public static final int BUFFER_SIZE = 32768; public static final int DOS_LINE_END = 0; public static final int MACOS_LINE_END = 1; public static final int UNIX_LINE_END = 2; //let's remember the line end of the original file(as of Jext3.2pre3) private String myLineTerm = "\n", origLineTerm = "\n"; /** * The constructor add the necessary listeners, set some stuffs * (caret color, borers, fonts...). * @param parent <code>JextTextArea</code> needs a <code>Jext</code> parent * because it provides a lot of 'vital' methods */ public JextTextArea(JextFrame parent) { super(parent); addCaretListener(new CaretHandler()); addFocusListener(new FocusHandler()); setMouseWheel(); undo.setLimit(1000); setBorder(null); getPainter().setInvalidLinesPainted(false); this.parent = parent; Font defaultFont = new Font("Monospaced", Font.PLAIN, 12); fontName = defaultFont.getName(); fontSize = defaultFont.getSize(); fontStyle = defaultFont.getStyle(); setFont(defaultFont); modTime = -1; if (popupMenu == null) { new JextTextAreaPopupMenu(this); } else setRightClickPopup(popupMenu); newf = true; setTabSize(8); resetLineTerm(); FontMetrics fm = getFontMetrics(getFont()); setMinimumSize(new Dimension(40 * fm.charWidth('m'), 5 * fm.getHeight())); setPreferredSize(new Dimension(80 * fm.charWidth('m'), 15 * fm.getHeight())); add(LEFT_OF_SCROLLBAR, lineTermSelector = new JComboBox(new String[] { "DOS", "Mac", "UNIX" })); lineTermSelector.setSelectedItem(getLineTermName()); lineTermSelector.addActionListener(new ActionListener() { JextFrame parent = JextTextArea.this.getJextParent(); public void actionPerformed(ActionEvent evt) { int idx = lineTermSelector.getSelectedIndex(); setLineTerm(idx); parent.updateStatus(JextTextArea.this); parent.setLineTerm(JextTextArea.this, idx); //this updates the other TextArea if //the JextFrame is splitted if (JextTextArea.this.isDirty()) parent.getTabbedPane().setDirtyIcon(JextTextArea.this); else parent.getTabbedPane().setCleanIcon(JextTextArea.this); parent.setStatus(JextTextArea.this); } }); mode = ""; //Jext.getProperty("editor.colorize.mode"); } private void setLineTerm(String newLineTerm) {//for now it's private so nothing changes. myLineTerm = newLineTerm; } private String getLineTerm() { return myLineTerm; } private void resetLineTerm() { myLineTerm = Jext.getProperty("editor.newLine"); if (myLineTerm == null || "".equals(myLineTerm)) { //happens on first run. //And made 3.2pre3 crash the day before official release, while trying built version. myLineTerm = System.getProperty("line.separator"); Jext.setProperty("editor.newLine", myLineTerm); } storeOrigLineTerm(); } private void storeOrigLineTerm() { origLineTerm = myLineTerm; } public boolean isLineTermChanged() { if (myLineTerm != null) return !myLineTerm.equals(origLineTerm); else return false; } //this will be checked probably by internal JextTextArea methods; I think that JextTextArea will call //something as parent.setChanged, only a bit different. /*friendly*/ void setLineTerm(int lineTermConst) { switch(lineTermConst) { case UNIX_LINE_END: myLineTerm = "\n"; break; case MACOS_LINE_END: myLineTerm = "\r"; break; case DOS_LINE_END: myLineTerm = "\r\n"; break; } } /*friendly*/ String getLineTermName() { if ("\r".equals(myLineTerm)) return "Mac"; if ("\n".equals(myLineTerm)) return "UNIX"; if ("\r\n".equals(myLineTerm)) return "DOS"; return "UNIX"; } /*friendly*/ void rotateLineTerm() { if (myLineTerm.equals("\r")) myLineTerm = "\n"; else if (myLineTerm.equals("\n")) myLineTerm = "\r\n"; else if (myLineTerm.equals("\r\n")) myLineTerm = "\r"; if (isLineTermChanged()) parent.setChanged(this); else if (!isDirty()) parent.setSaved(this); lineTermSelector.setSelectedItem(getLineTermName()); } private void setMouseWheel() { if (Utilities.JDK_VERSION.charAt(2) >= '4') { try { Class cl = Class.forName("org.jext.JavaSupport"); Method m = cl.getMethod("setMouseWheel", new Class[] { getClass() }); if (m != null) m.invoke(null, new Object[] { this }); } catch (Exception e) { } } } /** * Adds a search highlighter if none exists. */ public void initSearchHighlight() { if (searchHighlight == null) { searchHighlight = new SearchHighlight(); getPainter().addCustomHighlight(searchHighlight); } } /** * Returns the associated search highlighter. */ public SearchHighlight getSearchHighlight() { return searchHighlight; } /** * Returns text area popup menu. */ public static JPopupMenu getPopupMenu() { return popupMenu; } /** * Get property inherent to current syntax colorizing mode. */ public String getProperty(String key) { return Jext.getProperty("mode." + mode + '.' + key); } /** * Set a new document */ public void setDocument(org.gjt.sp.jedit.syntax.SyntaxDocument document) { document.removeUndoableEditListener(this); document.removeDocumentListener(this); super.setDocument(document); document.addDocumentListener(this); document.addUndoableEditListener(this); } /** * Return current font's name */ public String getFontName() { return fontName; } /** * Return current font's size */ public int getFontSize() { return fontSize; } /** * Return current font's style (bold, italic...) */ public int getFontStyle() { return fontStyle; } /** * Set the font which has to be used. * @param name The name of the font */ public void setFontName(String name) { fontName = name; changeFont(); } /** * Set the size of the font. * @param size The new font's size */ public void setFontSize(int size) { fontSize = size; changeFont(); FontMetrics fm = getFontMetrics(getFont()); setMinimumSize(new Dimension(80 * fm.charWidth('m'), 5 * fm.getHeight())); repaint(); } /** * Set the style of the font. * @param style The new style to apply */ public void setFontStyle(int style) { fontStyle = style; changeFont(); repaint(); } /** * Set the new font. */ private void changeFont() { getPainter().setFont(new Font(fontName, fontStyle, fontSize)); } /** * Show/hide waiting cursor */ public void waitingCursor(boolean on) { if (on) { parent.showWaitCursor(); } else { parent.hideWaitCursor(); } } /** * This is necessary to determine if we have to indent on tab key press or not. */ public static boolean getTabIndent() { return Jext.getBooleanProperty("editor.tabIndent"); } /** * This is necessary to determine if we have to indent on enter key press or not. */ public static boolean getEnterIndent() { return Jext.getBooleanProperty("editor.enterIndent"); } /** * Return the state of the softtab check menu item. * This is necessary to know if tabs have to be replaced * by whitespaces. */ public static boolean getSoftTab() { return Jext.getBooleanProperty("editor.softTab"); } /** * When an operation has began, setChanged() cannot be called. * This is very important when we need to insert or remove some * parts of the text without turning on the 'to_be_saved' flag. */ public void beginOperation() { operation = true; waitingCursor(true); } /** * Calling this will allow the DocumentListener to use setChanged(). */ public void endOperation() { operation = false; waitingCursor(false); } /** * Return the parent of this component. Note that a LOT of * external functions need to call methods contained in the parent. */ public JextFrame getJextParent() { return parent; } /** * Return true if we can use the setChanged() method, * false otherwise. */ public boolean getOperation() { return operation; } /** * Return current opened file as a <code>File</code> object. */ public File getFile() { return (currentFile == null ? null : new File(currentFile)); } /** * Return the full path of the opened file. */ public String getCurrentFile() { return currentFile; } /** * Set path of current opened file. */ public void setCurrentFile(String path) { currentFile = path; } /** * Performs a 'filtered' paste. A filtered paste is a paste action performed after having * made some search and replace operations over the clipboard text. */ public void filteredPaste() { if (editable) { Clipboard clipboard = getToolkit().getSystemClipboard(); try { // The MacOS MRJ doesn't convert \r to \n, // so do it here String selection = ((String) clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor)).replace('\r', '\n'); String replaced = null; if (Search.getFindPattern().length() > 0) { if (Jext.getBooleanProperty("useregexp")) { RE regexp = new RE(Search.getFindPattern(), (Jext.getBooleanProperty("ignorecase") == true ? RE.REG_ICASE : 0) | RE.REG_MULTILINE, RESyntax.RE_SYNTAX_PERL5); if (regexp == null) return; replaced = regexp.substituteAll(selection, Search.getReplacePattern()); } else { LiteralSearchMatcher matcher = new LiteralSearchMatcher(Search.getFindPattern(), Search.getReplacePattern(), Jext.getBooleanProperty("ignorecase")); replaced = matcher.substitute(selection); } } if (replaced == null) replaced = selection; setSelectedText(replaced); } catch (Exception e) { getToolkit().beep();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -