/*
 *  Copyright (C) 2004  The Concord Consortium, Inc.,
 *  10 Concord Crossing, Concord, MA 01742
 *
 *  Web Site: http://www.concord.org
 *  Email: info@concord.org
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * END LICENSE */

package org.concord.swing;

import java.awt.BorderLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.CDATASection;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

public class PageView
extends JPanel
implements HyperlinkListener, SwingConstants
{
	private static final long serialVersionUID = 1L;
	protected JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
	protected JMenuBar menuBar = new JMenuBar();
	protected JFileChooser imageFileChooser = new JFileChooser();
	protected JFileChooser componentFileChooser = new JFileChooser();
	protected JFileChooser openFileChooser = new JFileChooser();
	protected JFileChooser saveFileChooser = new JFileChooser();
	protected Editor editor;
	protected boolean editable = true;
	protected File currentOpenFile;
	protected JScrollPane scrollPane;
	protected JFrame viewFrame;
	protected PageView viewPage;
	protected Map actionMap = new HashMap();
	protected Map menuMap = new HashMap();
	protected Action insertImage = new AbstractAction()
	{
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent event)
		{
			if (imageFileChooser.showOpenDialog(editor) == JFileChooser.APPROVE_OPTION)
			{
				File imageFile = imageFileChooser.getSelectedFile();
				try
				{
					URL iconURL = imageFile.toURL();
					editor.insertIcon(iconURL);
				}
				catch (Exception e)
				{
					System.out.println("" + e);
				}
			}
		}
	};
	protected Action insertComponent = new AbstractAction()
	{
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent event)
		{
			if (componentFileChooser.showOpenDialog(editor) == JFileChooser.APPROVE_OPTION)
			{
				File componentFile = componentFileChooser.getSelectedFile();
				try
				{
					URL componentURL = componentFile.toURL();
					editor.insertComponent(componentURL);
				}
				catch (Exception e)
				{
					System.out.println("" + e);
				}
			}
		}
	};
	protected Action saveAction = new AbstractAction()
	{
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent event)
		{
			if (saveFileChooser.showSaveDialog(editor) == JFileChooser.APPROVE_OPTION)
			{
				File file = saveFileChooser.getSelectedFile();
				try
				{
					OutputStream output = new FileOutputStream(file);
					editor.write(output);
					output.close();
				}
				catch (Exception e)
				{
					System.out.println("" + e);
				}
			}
		}
	};
	protected Action openAction = new AbstractAction()
	{
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent event)
		{
			if (openFileChooser.showOpenDialog(editor) == JFileChooser.APPROVE_OPTION)
			{
				File file = openFileChooser.getSelectedFile();
				try
				{
					currentOpenFile = file;
					InputStream input = new FileInputStream(file);
					editor.read(input, null);
					input.close();
				}
				catch (Exception e)
				{
					System.out.println("" + e);
				}
			}
		}
	};
	protected Action viewAction = new AbstractAction()
	{
		private static final long serialVersionUID = 1L;

		public void actionPerformed(ActionEvent event)
		{
			if (currentOpenFile != null)
			{
				if (viewPage == null)
				{
					viewFrame = new JFrame("PageView");
					viewPage = new PageView();
					viewFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
					viewFrame.getContentPane().add(viewPage);
					viewFrame.setBounds(100, 100, 800, 600);
				}
			}
			try
			{
				viewPage.setEditable(true);
				viewPage.readInput(new FileInputStream(currentOpenFile));
				viewPage.setEditable(false);
			}
			catch (FileNotFoundException e)
			{
			}
			viewFrame.setVisible(true);
		}
	};
	protected String [][] commands =
	{
		{ "OpenAction", "Open", null, "Actions", "images/open.gif" },
		{ "SaveAction", "Save", null, "Actions", "images/save.gif" },
		{ "ViewAction", "View", null, "Actions", null },
		{ "copy-to-clipboard", "Copy", null, "Edit", "images/copy.gif" },
		{ "cut-to-clipboard", "Cut", null, "Edit", "images/cut.gif" },
		{ "paste-from-clipboard", "Paste", null, "Edit", "images/paste.gif" },
		{ "separator", null, null, "Edit", null },
		{ "select-all", "Select All", null, "Edit", null },
		{ "left-justify", "Left", "Edit", "Align", "images/AlignLeft.gif" },
		{ "center-justify", "Center", "Edit", "Align", "images/AlignCenter.gif" },
		{ "right-justify", "Right", "Edit", "Align", "images/AlignRight.gif" },
		{ "font-size-8", "8", "Font", "Size", null },
		{ "font-size-10", "10", "Font", "Size", null },
		{ "font-size-12", "12", "Font", "Size", null },
		{ "font-size-14", "14", "Font", "Size", null },
		{ "font-size-16", "16", "Font", "Size", null },
		{ "font-size-18", "18", "Font", "Size", null },
		{ "font-size-24", "24", "Font", "Size", null },
		{ "font-size-36", "36", "Font", "Size", null },
		{ "font-size-48", "48", "Font", "Size", null },
		{ "font-family-Serif", "Serif", "Font", "Family", null },
		{ "font-family-SansSerif", "SansSerif", "Font", "Family", null },
		{ "font-family-Monospaced", "Monospaced", "Font", "Family", null },
		{ "font-bold", "Bold", "Font", "Style", "images/Bold.gif" },
		{ "font-italic", "Italic", "Font", "Style", "images/Italic.gif" },
		{ "font-underline", "Underline", "Font", "Style", "images/Underline.gif" },
		{ "InsertImage", "Image", null, "Insert", "images/InsertPicture.gif" },
		{ "InsertComponent", "Component", null, "Insert", "images/InsertComponent.gif" },
	};
	
	public PageView()
	{
		this(true);
	}
	
	public PageView(boolean editable)
	{
		setLayout(new BorderLayout());
		editor = new Editor(editable);
		scrollPane = new JScrollPane(editor);
		initializeCommands();
		setEditable(editable);
	}
	
	protected void initializeCommands()
	{
		actionMap.put("InsertImage", insertImage);
		actionMap.put("InsertComponent", insertComponent);
		actionMap.put("OpenAction", openAction);
		actionMap.put("SaveAction", saveAction);
		actionMap.put("ViewAction", viewAction);
		Action [] actions = editor.getEditorKit().getActions();
		for (int i = 0; i < actions.length; i++)
		{
			String name = actions[i].getValue(Action.NAME).toString();
			actionMap.put(name, actions[i]);
		}
		for (int i = 0; i < commands.length; i++)
		{
			String [] command = commands[i];
			Action action = (Action) actionMap.get(command[0]);
			URL imageURL = null;
			JMenu parentMenu = null;
			JMenu menu = null;
			JMenuItem item = null;
			if (command[2] != null)
			{
				parentMenu = (JMenu) menuMap.get(command[2]);
				if (parentMenu == null)
				{
					parentMenu = new JMenu(command[2]);
					menuMap.put(command[2], parentMenu);
					menuBar.add(parentMenu);
				}
			}
			menu = (JMenu) menuMap.get(command[3]);
			if (menu == null)
			{
				menu = new JMenu(command[3]);
				menuMap.put(command[3], menu);
				if (parentMenu != null)
					parentMenu.add(menu);
				else
					menuBar.add(menu);
			}
			if (command[1] != null)
			{
				item = menu.add(action);
				item.setText(command[1]);
			}
			if (command[4] != null)
			{
				imageURL = this.getClass().getResource(command[4]);
				JButton button = toolBar.add(action);
				button.setText(null);
				button.setIcon(new ImageIcon(imageURL));
				if (item != null)
					item.setIcon(button.getIcon());
			}
			if (command[0].equals("separator"))
			{
				menu.addSeparator();
			}
		}
		toolBar.setFloatable(true);
		add(scrollPane, "Center");
	}
	
	public void readInput(InputStream input)
	{
		editor.read(input, null);
		try
		{
			input.close();
		}
		catch (IOException e)
		{
		}
	}
	
	public boolean isEditable()
	{
		return editable;
	}
	
	public void setEditable(boolean value)
	{
		editable = value;
		if (editable)
		{
			add(toolBar, "West");
			add(menuBar, "North");
		}
		else
		{
			remove(toolBar);
			remove(menuBar);
		}
		editor.setEditable(editable);
		validate();
	}

	public void hyperlinkUpdate(HyperlinkEvent event)
	{
	}
	
	public static void main(String [] args)
	{
		JFrame frame = new JFrame("PageView");
		PageView view = new PageView();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(view);
		frame.setBounds(100, 100, 800, 600);
		frame.setVisible(true);
	}
	
	public static class StyleMethods
	{
		protected Map getters = new HashMap();
		protected Map setters = new HashMap();
		protected final String SET = "set";
		protected final String GET = "get";
		protected final String IS = "is";
		protected final String FONT = "font";
		protected final Class [][] primitives =
		{
			{ Integer.TYPE, Integer.class },
			{ Long.TYPE, Long.class },
			{ Short.TYPE, Short.class },
			{ Byte.TYPE, Byte.class },
			{ Float.TYPE, Float.class },
			{ Double.TYPE, Double.class },
			{ Character.TYPE, Character.class },
			{ Boolean.TYPE, Boolean.class }
		};
		protected Map typeMap = new HashMap();
		
		public StyleMethods()
		{
			Method [] methods = StyleConstants.class.getMethods();
			for (int i = 0; i < methods.length; i++)
			{
				Method method = methods[i];
				String methodName = method.getName();
				if (methodName.startsWith(GET))
				{
					createProperty(methodName, GET.length(), method, getters);
				}
				else if (methodName.startsWith(IS))
				{
					createProperty(methodName, IS.length(), method, getters);
				}
				else if (methodName.startsWith(SET))
				{
					createProperty(methodName, SET.length(), method, setters);
				}
			}
			for (int i = 0; i < primitives.length; i++)
			{
				typeMap.put(primitives[i][0], primitives[i][1]);
			}
		}
		
		protected Class getTypeClass(Class type)
		{
			Class typeClass = (Class) typeMap.get(type);
			if (typeClass == null)
				return type;
			return typeClass;
		}
		
		protected void createProperty(String methodName, int prefixLength, Method method, Map table)
		{
			String propertyName = methodName.substring(prefixLength);
			propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
			table.put(propertyName, method);
			if (propertyName.startsWith(FONT))
			{
				propertyName = propertyName.substring(FONT.length());
				propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
				table.put(propertyName, method);
			}
		}
		
		public Object get(AttributeSet attributeSet, String propertyName)
		{
			propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
			Method method = (Method) getters.get(propertyName);
			if (method != null)
			{
				try
				{
					return method.invoke(null, new Object [] { attributeSet });
				}
				catch (IllegalArgumentException e)
				{
					System.out.println(e);
				}
				catch (IllegalAccessException e)
				{
					System.out.println(e);
				}
				catch (InvocationTargetException e)
				{
					System.out.println(e);
				}
			}
			return null;
		}
		
		public void set(MutableAttributeSet attributeSet, String propertyName, Object value)
		{
			propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
			Method method = (Method) setters.get(propertyName);
			if (method != null)
			{
				try
				{
					if (value instanceof String)
					{
						Class [] argClasses = method.getParameterTypes();
						Class argType = getTypeClass(argClasses[1]);
						Constructor constructor = argType.getConstructor(new Class [] { String.class });
						value = constructor.newInstance(new Object [] { value });
					}
					method.invoke(null, new Object [] { attributeSet, value });
				}
				catch (IllegalArgumentException e)
				{
					System.out.println(e);
				}
				catch (IllegalAccessException e)
				{
					System.out.println(e);
				}
				catch (InvocationTargetException e)
				{
					System.out.println(e);
				}
				catch (NoSuchMethodException e)
				{
					System.out.println(e);
				}
				catch (InstantiationException e)
				{
					System.out.println(e);
				}
			}
		}
	}
	
	
	public static class Editor
	extends JTextPane
	implements SelectableContainer, CaretListener
	{
		private static final long serialVersionUID = 1L;
		protected DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
		protected DocumentBuilder builder;
		protected StyleContext styleContext = StyleContext.getDefaultStyleContext();
		protected Style sectionStyle = styleContext.addStyle("Section", null);
		protected Style paragraphStyle = styleContext.addStyle("Paragraph", sectionStyle);
		protected Style contentStyle = styleContext.addStyle("Content", paragraphStyle);
		protected StyleMethods styleMethods = new StyleMethods();
        protected Map componentMap = new HashMap();
        protected Map iconMap = new HashMap();
        protected Map locationMap = new HashMap();
        protected SelectionManager selectionManager = new SelectionManager();
        protected ComponentFramework state = new DefaultComponentFramework();
		
		public Editor(boolean editable)
		{
			builderFactory.setValidating(false);
	        setMargin(new Insets(5,5,5,5));
			super.setEditable(true);
			selectionManager.setSelectableContainer(this);
			addCaretListener(this);
			try
			{
				builder = builderFactory.newDocumentBuilder();
			}
			catch (Exception e)
			{
				System.out.println(e);
			}
		}
		
		public void setEditable(boolean value)
		{
			super.setEditable(value);
			if (componentMap != null)
			{
				Iterator components = componentMap.keySet().iterator();
				while (components.hasNext())
				{
					PageComponent pageComponent = (PageComponent) components.next();
					pageComponent.setEditable(value);
				}
			}
		}
		
		public void insertIcon(URL iconURL)
		{
			ImageIcon icon = new ImageIcon(iconURL);
			super.insertIcon(icon);
			iconMap.put(icon, iconURL);
		}
		
		public void insertComponent(URL componentURL)
		{
			PageComponent component = new PageComponent(componentURL);
			component.setSelectionManager(selectionManager);
			super.insertComponent(component);
			componentMap.put(component, componentURL);
		}
		
		public void write(OutputStream outputStream)
		{
		    AbstractDocument doc = (AbstractDocument) getDocument();
			Element root = doc.getDefaultRootElement();
			Document document = builder.newDocument();
			writeTree(root, document, document);
			try
			{
	   		    Transformer t = TransformerFactory.newInstance().newTransformer();
	           	t.setOutputProperty(OutputKeys.INDENT,"yes");
		        t.setOutputProperty(OutputKeys.METHOD, "xml");
		        t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"yes");
		        t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","4");
	        	t.transform(new DOMSource(document),new StreamResult(outputStream));
			}
			catch (Exception e)
			{
				System.out.println("write = " + e);
			}
		}
		
		protected void writeElement(Element element, Document document, Node parent, Object key, Map map)
		{
            AttributeSet attributes = element.getAttributes();
            Object value = attributes.getAttribute(key);
			URL url = (URL) map.get(value);
			org.w3c.dom.Element xmlElement = document.createElement(key.toString());
			parent.appendChild(xmlElement);
			xmlElement.setAttribute("href", url.toString());
			xmlElement.setAttribute("start", "" + element.getStartOffset());
			xmlElement.setAttribute("end", "" + element.getEndOffset());
		}
		
		protected void writeIconElement(Element element, Document document, Node parent)
		{
			Object iconKey = StyleConstants.CharacterConstants.IconAttribute;
			writeElement(element, document, parent, iconKey, iconMap);
		}
		
		protected void writeComponentElement(Element element, Document document, Node parent)
		{
            Object componentKey = StyleConstants.CharacterConstants.ComponentAttribute;
            writeElement(element, document, parent, componentKey, componentMap);
		}
		
		protected void writeTree(Element element, Document document, Node parent)
		{
		    String elementName = element.getName();
		    if (elementName.equals("icon"))
		    	writeIconElement(element, document, parent);
		    else if (elementName.equals("component"))
		    	writeComponentElement(element, document, parent);
		    else
		    {
				org.w3c.dom.Element xmlElement = document.createElement(elementName);
				parent.appendChild(xmlElement);
				if (parent == document)
				{
					try
					{
						StringWriter writer = new StringWriter();
						super.write(writer);
						String data = writer.toString();
						Node dataNode = document.createCDATASection(data);
						document.getDocumentElement().appendChild(dataNode);
					}
					catch (Exception e)
					{
						System.out.println("writeData = " + e);
					}
				}
				Enumeration eNames = ((AttributeSet) element).getAttributeNames();
				while (eNames.hasMoreElements())
				{
					Object name = eNames.nextElement();
					if (name.toString().equals("resolver"))
						continue;
					Object value = ((AttributeSet) element).getAttribute(name);
					xmlElement.setAttribute(name.toString(), value.toString());
				}
				if (element.isLeaf())
				{
					xmlElement.setAttribute("start", "" + element.getStartOffset());
					xmlElement.setAttribute("end", "" + element.getEndOffset());
				}
				else
				{
					for (int i = 0; i < element.getElementCount(); i++)
					{
						Element childElement = element.getElement(i);
						writeTree(childElement, document, xmlElement);
					}
				}
		    }
		}
		
		protected void installComponents()
		{
			Iterator componentUrls = locationMap.keySet().iterator();
			while (componentUrls.hasNext())
			{
				String urlString = (String) componentUrls.next();
				Integer location = (Integer) locationMap.get(urlString);
				int start = location.intValue();
				DefaultStyledDocument doc = (DefaultStyledDocument) getDocument();
				try
				{
					URL componentURL = new URL(urlString);
					doc.remove(start, 1);
					int dot = getCaret().getDot();
					getCaret().setDot(start);
					insertComponent(componentURL);
					getCaret().setDot(dot);
				}
				catch (MalformedURLException e)
				{
				}
				catch (BadLocationException e)
				{
				}
			}
		}
		
		public void read(InputStream input, Object desc)
		{
			removeCaretListener(this);
			try
			{
				Document document = builder.parse(new InputSource(input));
				readTree(document, document);
				installComponents();
			}
			catch (Exception e)
			{
				
			}
			addCaretListener(this);
		}
		
		protected void readDocumentElement(Node node, Style style)
		{
			style.removeAttributes(style);
			NamedNodeMap attributes = node.getAttributes();
			for (int i = 0; i < attributes.getLength(); i++)
			{
				Node attributeNode = attributes.item(i);
				String nodeName = attributeNode.getNodeName();
				Object nodeValue = attributeNode.getNodeValue();
				styleMethods.set(style, nodeName, nodeValue);
			}
		}
		
		protected void readContentElement(Node node)
		{
			contentStyle.removeAttributes(contentStyle);
			NamedNodeMap attributes = node.getAttributes();
			Node attributeNode = attributes.getNamedItem("start");
			int start = Integer.decode(attributeNode.getNodeValue()).intValue();
			attributeNode = attributes.getNamedItem("end");
			int end = Integer.decode(attributeNode.getNodeValue()).intValue();
			DefaultStyledDocument doc = (DefaultStyledDocument) getDocument();
			for (int i = 0; i < attributes.getLength(); i++)
			{
				attributeNode = attributes.item(i);
				String nodeName = attributeNode.getNodeName();
				Object nodeValue = attributeNode.getNodeValue();
				if (nodeName.equals("start"))
					continue;
				if (nodeName.equals("end"))
					continue;
				styleMethods.set(contentStyle, nodeName, nodeValue);
			}
			try
			{
				int length = end - start;
				if ((length > 0) && (end <= doc.getLength()))
				{
					String text = doc.getText(start, length);
					doc.replace(start, length, text, contentStyle);
					doc.setParagraphAttributes(start, length, paragraphStyle, false);
				}
			}
			catch (DOMException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			catch (BadLocationException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		protected void readIconElement(Node node)
		{
			NamedNodeMap xmlAttributes = node.getAttributes();
			Node attributeNode = xmlAttributes.getNamedItem("href");
			String urlString = attributeNode.getNodeValue();
			attributeNode = xmlAttributes.getNamedItem("start");
			int start = Integer.decode(attributeNode.getNodeValue()).intValue();
			DefaultStyledDocument doc = (DefaultStyledDocument) getDocument();
			try
			{
				URL iconURL = new URL(urlString);
				doc.remove(start, 1);
				int dot = getCaret().getDot();
				getCaret().setDot(start);
				insertIcon(iconURL);
				getCaret().setDot(dot);
			}
			catch (MalformedURLException e)
			{
			}
			catch (BadLocationException e)
			{
			}
		}
		
		protected void readComponentElement(Node node)
		{
			NamedNodeMap xmlAttributes = node.getAttributes();
			Node attributeNode = xmlAttributes.getNamedItem("href");
			String urlString = attributeNode.getNodeValue();
			attributeNode = xmlAttributes.getNamedItem("start");
			int start = Integer.decode(attributeNode.getNodeValue()).intValue();
			locationMap.put(urlString, new Integer(start));
		}
		
		public void readTree(Document document, Node node)
		{
			if (node instanceof CDATASection)
			{
				try
				{
					String text = node.getNodeValue();
					StringReader reader = new StringReader(text);
					super.read(reader, null);
				}
				catch (Exception e)
				{
					
				}
			}
			else
			{
				if (node.getNodeName().equals(AbstractDocument.SectionElementName))
				{
					readDocumentElement(node, sectionStyle);
				}
				else if (node.getNodeName().equals(AbstractDocument.ParagraphElementName))
				{
					readDocumentElement(node, paragraphStyle);
				}
				else if (node.getNodeName().equals(AbstractDocument.ContentElementName))
				{
					readContentElement(node);
				}
				else if (node.getNodeName().equals("icon"))
				{
					readIconElement(node);
				}
				else if (node.getNodeName().equals("component"))
				{
					readComponentElement(node);
				}
				NodeList list = node.getChildNodes();
				for (int i = 0; i < list.getLength(); i++)
				{
					node = list.item(i);
					readTree(document, node);
				}
			}
		}

		public Selectable findSelectable(MouseEvent event, int x, int y)
		{
			return (Selectable) event.getSource();
		}

		public Selectable getActiveObject()
		{
			return null;
		}

		public Point getOffset()
		{
			return null;
		}

		public void select(Selectable selectable, boolean multiple)
		{
			selectable.setSelected(true);
		}

		public void deselect()
		{
		}

		public void dragAction(int dx, int dy, Selectable selectable)
		{
		}

		public void dragActionDone(Selectable selectable)
		{
		}

		public void caretUpdate(CaretEvent e)
		{
			if (selectionManager != null)
			{
				Selectable selected = selectionManager.getSelectedObject();
				if (selected != null)
					selected.setSelected(false);
			}
		}
	}
}

