?? macro.java
字號:
/*
* 09/16/2004
*
* Macro.java - A macro as recorded/played back by an 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.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.fife.io.UnicodeReader;
/**
* A macro as recorded/played back by an <code>RTextArea</code>.
*
* @author Robert Futrell
* @version 0.1
*/
public class Macro {
private String name;
private ArrayList macroRecords;
private static final String ROOT_ELEMENT = "macro";
private static final String MACRO_NAME = "macroName";
private static final String ACTION = "action";
private static final String ID = "id";
private static final String UNTITLED_MACRO_NAME = "<Untitled>";
/*****************************************************************************/
/**
* Constructor.
*/
public Macro() {
this(UNTITLED_MACRO_NAME);
}
/*****************************************************************************/
/**
* Loads a macro from a file on disk.
*
* @param file The file from which to load the macro.
* @throws java.io.EOFException If an EOF is reached unexpectedly (i.e.,
* the file is corrupt).
* @throws FileNotFoundException If the specified file does not exist, is
* a directory instead of a regular file, or
* otherwise cannot be opened.
* @throws IOException If an I/O exception occurs while reading the file.
* @see #saveToFile
*/
public Macro(File file) throws EOFException, FileNotFoundException,
IOException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
//InputSource is = new InputSource(new FileReader(file));
InputSource is = new InputSource(new UnicodeReader(
new FileInputStream(file), "UTF-8"));
is.setEncoding("UTF-8");
doc = db.parse(is);//db.parse(file);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
macroRecords = new ArrayList();
// Traverse the XML tree.
boolean parsedOK = initializeFromXMLFile(doc);
if (parsedOK==false) {
name = null;
macroRecords.clear();
macroRecords = null;
throw new IOException("Error parsing XML!");
}
}
/*****************************************************************************/
/**
* Constructor.
*
* @param name The name of the macro.
*/
public Macro(String name) {
this(name, null);
}
/*****************************************************************************/
/**
* Constructor.
*
* @param name The name of the macro.
* @param records The initial records of the macro.
*/
public Macro(String name, List records) {
this.name = name;
if (records!=null) {
macroRecords = new ArrayList(records.size());
Iterator i = records.iterator();
while (i.hasNext()) {
MacroRecord record = (MacroRecord)i.next();
macroRecords.add(record);
}
}
else {
macroRecords = new ArrayList(10);
}
}
/*****************************************************************************/
/**
* Adds a macro record to this macro.
*
* @param record The record to add. If <code>null</code>, nothing happens.
* @see #getMacroRecords
*/
public void addMacroRecord(MacroRecord record) {
if (record!=null)
macroRecords.add(record);
}
/*****************************************************************************/
/**
* Returns the macro records that make up this macro.
*
* @return The macro records.
* @see #addMacroRecord
*/
public List getMacroRecords() {
return macroRecords;
}
/*****************************************************************************/
/**
* Returns the name of this macro.
*
* @return The macro's name.
* @see #setName
*/
public String getName() {
return name;
}
/*****************************************************************************/
/**
* Used in parsing an XML document containing a macro. This method
* initializes this macro with the data contained in the passed-in node.
*
* @param node The root node of the parsed XML document.
* @return <code>true</code> if the macro initialization went okay;
* <code>false</code> if an error occured.
*/
private boolean initializeFromXMLFile(Node node) {
/*
* This method expects the XML document to be in the following format:
*
* <?xml version="1.0" encoding="UTF-8" ?>
* <macro>
* <macroName>test</macroName>
* <action id="default-typed">abcdefg</action>
* [<action id=...>...</action>]
* ...
* </macro>
*
*/
if (node==null)
return false;
int type = node.getNodeType();
switch (type) {
// Handle document nodes.
case Node.DOCUMENT_NODE:
boolean rc = initializeFromXMLFile(((Document)node).getDocumentElement());
if (rc==false)
return false;
break;
// Handle element nodes.
case Node.ELEMENT_NODE:
String nodeName = node.getNodeName();
if (nodeName.equals(MACRO_NAME)) {
NodeList childNodes = node.getChildNodes();
if (childNodes==null)
return false;
if (childNodes.getLength()==0) {
// Don't error out, just be "unnamed."
name = UNTITLED_MACRO_NAME;
}
else {
node = childNodes.item(0);
if (node.getNodeType()!=Node.TEXT_NODE)
return false;
name = node.getNodeValue().trim();
}
System.err.println("Macro name==" + name);
}
else if (nodeName.equals(ROOT_ELEMENT)) {
System.err.println("Beginning macro parsing!");
NodeList childNodes = node.getChildNodes();
if (childNodes!=null) {
int length = childNodes.getLength();
System.err.println("... num child nodes: " + length);
for (int i=0; i<length; i++) {
rc = initializeFromXMLFile(childNodes.item(i));
if (rc==false)
return false;
}
}
System.err.println("Done with macro parsing!");
}
else if (nodeName.equals(ACTION)) {
NamedNodeMap attributes = node.getAttributes();
if (attributes==null || attributes.getLength()!=1)
return false;
Node node2 = attributes.item(0);
MacroRecord macroRecord = new MacroRecord();
if (node2.getNodeType()!=Node.ATTRIBUTE_NODE) {
System.err.println("not an attribute type...");
return false;
}
if (!node2.getNodeName().equals(ID)) {
System.err.println("'id' expected but not found...");
return false;
}
macroRecord.id = node2.getNodeValue();
NodeList childNodes = node.getChildNodes();
int length = childNodes.getLength();
if (length==0) { // Could be empty "" command.
System.err.println("... empty actionCommand");
macroRecord.actionCommand = "";
System.err.println("... adding action: " + macroRecord);
macroRecords.add(macroRecord);
break;
}
else if (length!=1) {
System.err.println("childNodes invalid - " + childNodes);
return false;
}
node = childNodes.item(0);
if (node.getNodeType()!=Node.TEXT_NODE) {
System.err.println("Not a text node...");
return false;
}
macroRecord.actionCommand = node.getNodeValue();
System.err.println("... adding action: " + macroRecord);
macroRecords.add(macroRecord);
}
break;
case Node.TEXT_NODE:
System.err.println("... Throwaway whitespace node: '" + node.getNodeValue() + "'");
break;
// An error occured?
default:
System.err.println("... ERROR!!!");
return false;
}
// Everything went okay.
return true;
}
/*****************************************************************************/
/**
* Saves this macro to a text file. This file can later be read in by
* the constructor taking a <code>File</code> parameter; this is the
* mechanism for saving macros.
*
* @param fileName The name of the file in which to save the macro.
* @throws IOException If an error occurs while generating the XML for the
* output file.
*/
public void saveToFile(String fileName) throws IOException {
/*
* This method writes the XML document in the following format:
*
* <?xml version="1.0" encoding="UTF-8" ?>
* <macro>
* <macroName>test</macroName>
* <action id="default-typed">abcdefg</action>
* [<action id=...>...</action>]
* ...
* </macro>
*
*/
try {
DocumentBuilder db = DocumentBuilderFactory.newInstance().
newDocumentBuilder();
DOMImplementation impl = db.getDOMImplementation();
Document doc = impl.createDocument(null, ROOT_ELEMENT, null);
Element rootElement = doc.getDocumentElement();
// Write the name of the macro.
Element nameElement = doc.createElement(MACRO_NAME);
rootElement.appendChild(nameElement);
// Write all actions (the meat) in the macro.
int numActions = macroRecords.size();
for (int i=0; i<numActions; i++) {
MacroRecord record = (MacroRecord)macroRecords.get(i);
Element actionElement = doc.createElementNS(null, ACTION);
actionElement.setAttributeNS(null, ID, record.id);
if (record.actionCommand!=null &&
!record.actionCommand.equals("")) {
// Remove illegal characters. I'm no XML expert, but
// I'm not sure what I'm doing wrong. If we don't
// strip out chars with Unicode value < 32, our
// generator will insert '&#<value>', which will cause
// our parser to barf when reading the macro back in
// (it says "Invalid XML character"). But why doesn't
// our generator tell us the character is invalid too?
String command = record.actionCommand;
for (int j=0; j<command.length(); j++) {
if (command.charAt(j)<32) {
command = command.substring(0,j);
if (j<command.length()-1)
command += command.substring(j+1);
}
}
Node n = doc.createTextNode(command);
actionElement.appendChild(n);
}
rootElement.appendChild(actionElement);
}
// Dump the XML out to the file.
StreamResult result = new StreamResult(new File(fileName));
DOMSource source = new DOMSource(doc);
TransformerFactory transFac = TransformerFactory.newInstance();
Transformer transformer = transFac.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.transform(source, result);
} catch (Exception e) {
throw new IOException("Error generating XML!");
}
}
/*****************************************************************************/
/**
* Sets the name of this macro.
*
* @param name The new name for the macro.
* @see #getName
*/
public void setName(String name) {
this.name = name;
}
/*****************************************************************************/
/**************************** INNER CLASSES **********************************/
/*****************************************************************************/
/**
* A "record" of a macro is a single action in the macro (corresponding to
* a key type and some action in the editor, such as a letter inserted into
* the document, scrolling one page down, selecting the current line,
* etc.).
*/
static class MacroRecord {
public String id;
public String actionCommand;
public MacroRecord() {
this(null, null);
}
public MacroRecord(String id, String actionCommand) {
this.id = id;
this.actionCommand = actionCommand;
}
}
/*****************************************************************************/
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -