📄 xmleditor.java
字号:
/*
* Copyright (c) 2006, University of Kent
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 1. Neither the name of the University of Kent nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 2. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.
*
* 3. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* 4. YOU AGREE THAT THE EXCLUSIONS IN PARAGRAPHS 2 AND 3 ABOVE ARE REASONABLE
* IN THE CIRCUMSTANCES. IN PARTICULAR, YOU ACKNOWLEDGE (1) THAT THIS
* SOFTWARE HAS BEEN MADE AVAILABLE TO YOU FREE OF CHARGE, (2) THAT THIS
* SOFTWARE IS NOT "PRODUCT" QUALITY, BUT HAS BEEN PRODUCED BY A RESEARCH
* GROUP WHO DESIRE TO MAKE THIS SOFTWARE FREELY AVAILABLE TO PEOPLE WHO WISH
* TO USE IT, AND (3) THAT BECAUSE THIS SOFTWARE IS NOT OF "PRODUCT" QUALITY
* IT IS INEVITABLE THAT THERE WILL BE BUGS AND ERRORS, AND POSSIBLY MORE
* SERIOUS FAULTS, IN THIS SOFTWARE.
*
* 5. This license is governed, except to the extent that local laws
* necessarily apply, by the laws of England and Wales.
*/
/*
* XMLEditor.java - 18/01/2006
*/
package issrg.utils.xml;
import javax.swing.JPanel;
import javax.swing.event.EventListenerList;
import java.util.*;
import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.stream.*;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xml.serialize.LineSeparator;
import org.w3c.dom.*;
import org.xml.sax.*;
/**
* An Abstract class, that handles core XML editing functions.
*
* @author Christian Azzopardi
*/
public abstract class XMLEditor extends JPanel
{
/**
* Flag that is used to notify if there is any event on the undo Stack
*/
public boolean canUndo = false;
/**
* Flag that is used to notify if there is any event on the redo Stack
*/
public boolean canRedo = false;
/**
* Stack that keeps a list of items that can be undone
*/
public Stack done = new Stack();
/**
* Stack that keeps a list of items that can be redone
*/
public Stack undone = new Stack();
/**
* org.w3c.dom.Document where the elements are stored
*/
public Document DOM;
/**
* Root element of the Document DOM
*/
Element root;
public PolicyValidator policyValidator;
/** Creates a new instance of XMLEditor */
public XMLEditor()
{
}
/**
* A list of components registered as XML Change Listeners
*/
EventListenerList XMLChangeListeners = new EventListenerList();
/**
* Method to add a listener to any XML Change
*
* @param listener the component that listens to XML Changes to be added to
* the listener list.
*/
public void addXMLChangeListener(XMLChangeListener listener)
{
XMLChangeListeners.add(XMLChangeListener.class, listener);
}
/**
* Method to remove a listener to any XML Change
*
* @param listener the component to be removed from the listener list
*/
public void removeXMLChangeListener(XMLChangeListener listener)
{
XMLChangeListeners.remove(XMLChangeListener.class, listener);
}
/**
* Constructs the XMLChangeEvent to Modify the Element's Attributes with the
* list of their respective values.
*
* @param parent The Element to modify
* @param attribs A String Array of attributes to modify
* @param values The corresponding values of the attributes to set
*/
public void setAttributeValue(Element parent, String attribs[], String values[])
{
String oldValues[] = new String[attribs.length];
for (int i = 0; i < parent.getAttributes().getLength(); i++)
{
oldValues[i] = parent.getAttribute(attribs[i]);
}
XMLChangeEvent xmle = new XMLChangeEvent(this, parent, attribs, values, oldValues, "NODE_MODIFIED");
canRedo = false;
undone.clear();
doEvent(xmle);
}
public void replaceNode(Element parent, Element oldChild, Element newChild)
{
XMLChangeEvent xmle = new XMLChangeEvent(this, parent, oldChild, newChild, "NODE_REPLACED");
canRedo = false;
undone.clear();
doEvent(xmle);
}
/**
* Method that undoes the last performed action stored on the done stack.
* This last performed action is taken off the done stack and stored in
* the undone stack to be able to redo.
*/
public void undo()
{
if (done.empty()) return ;
XMLChangeEvent ev = (XMLChangeEvent)done.pop();
undone.push(ev);
canRedo=true;
processEvent(not(ev));
}
/**
* Method that redoes the first XMLChangeEvent that is on the undone Stack.
* This last performed redo action is then taken off the undone stack.
*/
public void redo()
{
if (undone.empty()) return;
XMLChangeEvent ev = (XMLChangeEvent)undone.pop();
doEvent(ev);
}
/**
* Method that fires XMLChanged notifications to a list of registered
* listeners.
*/
public void notifyChanges(XMLChangeEvent ev)
{
EventListener[] listeners = XMLChangeListeners.getListeners(XMLChangeListener.class);
for(int i = 0; i < listeners.length ; i++)
{
((issrg.utils.xml.XMLChangeListener)listeners[i]).XMLChanged(ev);
}
}
/**
* Initializes the done Stack.
*/
public void newDoneStack()
{
this.done = new Stack();
}
/**
* Initializes the undone Stack.
*/
public void newUnDoneStack()
{
this.undone = new Stack();
}
/**
* This method will identify what type of XMLChangedEvent
* has just been fired, and act upon it. This can have one of
* four forms that will be passed with the XMLChangeEvent:
* NODE_ADDED - when a node is being added to XML.
* NODE_DELETED - when a node is being deleted to XML.
* NODE_MODIFIED - when a node is being changed from the XML.
* NEW_XML - when a new policy is created.
* <p>
* It will then call notifyChanges, to notify any registered listeners
* with the changes.
*/
public void processEvent(XMLChangeEvent ev)
{
//request focus on any XML changed event to help with undo/redo...
if(ev.getAction() == "NODE_ADDED")
{
int pos = ev.getChildIndex();
if (pos >= ev.getParentNode().getChildNodes().getLength())
{
ev.getParentNode().appendChild(ev.getChildNode());
}
else
{
NodeList nl = ev.getParentNode().getChildNodes();
ev.getParentNode().insertBefore(ev.getChildNode(), nl.item(pos));
}
}
else if(ev.getAction() == "NODE_DELETED")
{
ev.getParentNode().removeChild(ev.getChildNode());
}
else if(ev.getAction() == "NODE_MODIFIED")
{
for (int i = 0; i < ev.getAttributeNames().length; i++)
{
ev.getChildNode().setAttribute(ev.getAttributeNames()[i], ev.getAttributeValues()[i]);
}
}
else if(ev.getAction() == "NODE_REPLACED")
{
ev.getParentNode().replaceChild(ev.getNewChildNode(), ev.getChildNode());
}
else if(ev.getAction() == "NEW_XML")
{
}
notifyChanges(ev);
}
/**
* Obtains the converse of an XMLChangeEvent. This is used in cases were we
* need to undo/redo. The XMLChangeEvent is popped out of the stack, and the
* converse is needed to do the opposite action.
*
* @param ev the event needed to convert.
* @return the converse XMLChangeEvent.
*/
public XMLChangeEvent not(XMLChangeEvent ev)
{
if(ev.getAction() == "NODE_REPLACED") return new XMLChangeEvent(this, ev.getParentNode(), ev.getChildNode(), ev.getNewChildNode(), "NODE_REPLACED");
if(ev.getAction() == "NODE_MODIFIED") return new XMLChangeEvent(this, ev.getChildNode(), ev.getAttributeNames(), ev.getOldAttribValues(), ev.getAttributeValues(), "NODE_MODIFIED");
if(ev.getAction() == "NODE_DELETED") return new XMLChangeEvent(this,ev.getChildNode(),ev.getParentNode(),"NODE_ADDED", ev.getChildIndex());
return new XMLChangeEvent(this,ev.getChildNode(), ev.getParentNode(),"NODE_DELETED", ev.getChildIndex());
}
/**
* Adds the child element to a parent element in XML.
*
* @param childNode The child element to add
* @param parentNode The parent element to add to
*/
public void addItem(Element childNode, Element parentNode)
{
addItem(childNode, parentNode, parentNode.getChildNodes().getLength());
}
/**
* Adds the child element to a parent element in XML, at a
* specified position. Constructs the necessary XMLChangeEvent.
*
* @param childNode The child element to add
* @param parentNode The parent element to add to
* @param childIndex The child's position in the parent's set of child nodes
*/
public void addItem(Element childNode, Element parentNode, int childIndex)
{
XMLChangeEvent xmle = new XMLChangeEvent(this, childNode, parentNode, "NODE_ADDED", childIndex);
canRedo = false;
undone.clear();
doEvent(xmle);
}
/**
* Deletes a child element from the parent element.
* Constructs the necessary XMLChangeEvent.
*
* @param childNode The child element to delete
* @param parentNode The parent element to delete from
*/
public void deleteItem(Element childNode, Element parentNode)
{
XMLChangeEvent xmle = new XMLChangeEvent(this, childNode, parentNode, "NODE_DELETED");
canRedo = false;
undone.clear();
doEvent(xmle);
}
/**
* This method adds to the done stack that something has just been
* done and calls processEvent with the received XMLChangeEvent
*
* @param ev The XMLChangeEvent that specifies was is being done.
*/
protected void doEvent(XMLChangeEvent ev)
{
done.push(ev);
processEvent(ev);
}
/**
* Generates the XML file, with Serializing. This enables better
* readability when opening a policy in a text editor.
*
* @param baos An output stream (file) to write to.
*/
public void GenerateXML(OutputStream baos)
{
StreamResult result = null;
byte strBytes[];
try
{
OutputFormat format = new OutputFormat();
format.setLineSeparator(LineSeparator.Windows); // "\n" wouldnt work well..
format.setIndenting(true);
XMLSerializer serializer = new XMLSerializer (baos, format);
serializer.serialize(this.DOM);
}
catch (IOException ioe)
{
}
}
/**
* Calls the previous overloaded method GenerateXML(OutputStream),
* converts the stream into a string, and returns it.
*
* @return String The current XML
*/
public String GenerateXML()
{
String strXML;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GenerateXML(baos);
strXML = baos.toString();
return strXML;
}
/**
* Method to open a Document given an XML String input.
* This calls CreateDOM(byte bytesDOM[]).
*
* @param xml This String should contain the XML policy to open
*/
public void createDOM(String xml)
{
byte [] bytes = null;
if (xml != null) bytes = xml.getBytes();
createDOM(bytes);
}
/**
* Method to open a Document given an XML byte array input.
* This calls CreateDOM(InputStream bais).
*
* @param bytesDOM A byte Array that should contain the XML policy to open
*/
public void createDOM(byte bytesDOM[])
{
ByteArrayInputStream bais = null;
if (bytesDOM != null) bais = new ByteArrayInputStream(bytesDOM);
createDOM(bais);
}
/**
* Method to open a Document given an XML String input.
* This last of 3 overloaded methods has the actual code to verify,
* the InputStream with the policyValidator provided.
*
* @param bais An InputStream containing the XML to open
*/
public void createDOM(InputStream bais)
{
if(bais!=null)
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try
{
DocumentBuilder builder = factory.newDocumentBuilder();
this.DOM = builder.parse(bais);
policyValidator.setDocument(DOM);
policyValidator.validateDocument();
this.root = this.DOM.getDocumentElement();
}
catch (SAXException sxe) { }
catch (ParserConfigurationException pce) { }
catch (IOException ioe) { }
catch (SecurityException se) { }
catch (ValidationException ve) { }
}
else //create a default DOM with a root element
{
try
{
policyValidator.setDocument(null);
this.DOM = policyValidator.getValidDocument();
this.root = DOM.getDocumentElement();
}
catch(DOMException doe) { }
}
XMLChangeEvent xmle = new XMLChangeEvent(this, "NEW_XML");
processEvent(xmle);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -