diff --git a/source/org/thdl/quilldriver/TranscriptNavigator.java b/source/org/thdl/quilldriver/TranscriptNavigator.java index 7a4fde9..6cfb216 100644 --- a/source/org/thdl/quilldriver/TranscriptNavigator.java +++ b/source/org/thdl/quilldriver/TranscriptNavigator.java @@ -1,76 +1,30 @@ package org.thdl.quilldriver; -import org.jaxen.jdom.JDOMXPath; import org.jaxen.XPath; +import org.jaxen.JaxenException; +import org.jaxen.jdom.JDOMXPath; +import java.util.List; -public class TranscriptNavigator { - private boolean autoInsertFlag = false; - private TranscriptMediator mediator; +public class TranscriptNavigator { + private TranscriptNavigator() {} //can't instantiate this class - TranscriptNavigator(TranscriptMediator mediator) { - this.mediator = mediator; - } - - /* - Next = ancestor-or-self::S/following-sibling:: - */ - - public boolean edit(String xpathExpression) { - return false; - } - - public boolean editNextText(String elementName) { - int pos = mediator.getPane().getCaretPosition(); - - Object next = next(pos, elementName); - if (next == null) { - if (autoInsertFlag) { - //insert after - return false; - } else - return false; + public static Object findSingleNode(Object jdomNode, String xpathExpression) { + List l = findNodeSet(jdomNode, xpathExpression); + if (l == null || l.size() == 0) + return null; + else { + return l.get(0); } - return false; } - - public boolean editPrevText(String elementName) { - pos = mediator.getPane().getCaretPosition(); - - Object prev = prev(pos, elementName); - if (prev == null) { - if (autoInsertFlag) { - //insert after - return false; - } else - return false; - } - - return false; - } - - public boolean highlightNext(String elementName) { - return false; - } - - public boolean highlightPrev(String elementName) { - return false; - } - - public Object next(int pos, String elementName) { - Object jdomNode = mediator.getNodeAtPos(int position); + public static List findNodeSet(Object jdomNode, String xpathExpression) { if (jdomNode == null) return null; - XPath path = new JDOMXPath("a/b/c"); - List results = path.selectNodes(jdomNode); - return null; - } - - public Object prev(int pos, String elementName) { - Object jdomNode = mediator.getNodeAtPos(int position); - if (jdomNode == null) + try { + XPath path = new JDOMXPath(xpathExpression); + return path.selectNodes(jdomNode); + } catch (JaxenException je) { + je.printStackTrace(); return null; - XPath path = new JDOMXPath("a/b/c"); - List results = path.selectNodes(jdomNode); - return null; + } } } diff --git a/source/org/thdl/quilldriver/TranscriptRenderer.java b/source/org/thdl/quilldriver/TranscriptRenderer.java new file mode 100644 index 0000000..f1a123e --- /dev/null +++ b/source/org/thdl/quilldriver/TranscriptRenderer.java @@ -0,0 +1,180 @@ +package org.thdl.quilldriver; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.Attribute; +import org.jdom.Text; +import java.awt.Color; +import java.util.List; +import java.util.Set; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import javax.swing.JTextPane; +import javax.swing.text.Position; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.BadLocationException; + +public class TranscriptRenderer { + private Document xml; + private JTextPane pane; + private StyledDocument doc; + private Map startOffsets, endOffsets; + private final float indentIncrement = 15.0F; + private final Color tagColor = Color.magenta; + private final Color attColor = Color.pink; + private final Color textColor = Color.gray; + + public TranscriptRenderer(Document xmlDoc, JTextPane textPane) { + xml = xmlDoc; + pane = textPane; + render(); + } + + public void render() { + doc = pane.getStyledDocument(); + int len = doc.getLength(); + if (len > 0) { + try { + doc.remove(0, len); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + startOffsets = new HashMap(); + endOffsets = new HashMap(); + Element root = xml.getRootElement(); + renderElement(root, 0.0F); + + //replace Integer values in startOffsets and endOffsets with Positions + Set startKeys = startOffsets.keySet(); + Iterator iter = startKeys.iterator(); + while (iter.hasNext()) { + Object key = iter.next(); + Integer val = (Integer)startOffsets.get(key); + try { + startOffsets.put(key, doc.createPosition(val.intValue())); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + Set endKeys = endOffsets.keySet(); + iter = endKeys.iterator(); + while (iter.hasNext()) { + Object key = iter.next(); + Integer val = (Integer)endOffsets.get(key); + try { + endOffsets.put(key, doc.createPosition(val.intValue())); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + } + + private void renderElement(Element e, float indent) { + SimpleAttributeSet eAttributes = new SimpleAttributeSet(); + StyleConstants.setLeftIndent(eAttributes, indent); + SimpleAttributeSet eColor = new SimpleAttributeSet(); + StyleConstants.setForeground(eColor, tagColor); + eColor.addAttribute("xmlnode", e); + try { + int start = doc.getLength(); + startOffsets.put(e, new Integer(start)); + doc.insertString(doc.getLength(), e.getQualifiedName(), eColor); //insert element begin tag + List attributes = e.getAttributes(); + Iterator iter = attributes.iterator(); + while (iter.hasNext()) { + Attribute att = (Attribute)iter.next(); + renderAttribute(att); + } + doc.insertString(doc.getLength(), " {", eColor); + doc.setParagraphAttributes(start, doc.getLength(), eAttributes, false); + doc.insertString(doc.getLength(), "\n", null); + List list = e.getContent(); + iter = list.iterator(); + while (iter.hasNext()) { + Object next = iter.next(); + if (next instanceof Element) + renderElement((Element)next, indent + indentIncrement); + else if (next instanceof Text) { + Text t = (Text)next; + if (t.getTextTrim().length() > 0) + renderText(t, indent + indentIncrement); + } + // Also: Comment ProcessingInstruction CDATA EntityRef + } + start = doc.getLength(); + doc.insertString(start, "}", eColor); //insert element end tag + doc.setParagraphAttributes(start, doc.getLength(), eAttributes, false); + endOffsets.put(e, new Integer(doc.getLength())); + doc.insertString(doc.getLength(), "\n", null); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + + private void renderAttribute(Attribute att) { + SimpleAttributeSet aColor = new SimpleAttributeSet(); + StyleConstants.setForeground(aColor, attColor); + SimpleAttributeSet tColor = new SimpleAttributeSet(); + StyleConstants.setForeground(tColor, textColor); + tColor.addAttribute("xmlnode", att); + String name = att.getQualifiedName(); + String value = att.getValue(); + try { + doc.insertString(doc.getLength(), " "+att.getQualifiedName()+"=", aColor); + startOffsets.put(att, new Integer(doc.getLength())); + doc.insertString(doc.getLength(), "\"" +att.getValue()+"\"", tColor); + endOffsets.put(att, new Integer(doc.getLength())); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + + private void renderText(Text t, float indent) { + SimpleAttributeSet tAttributes = new SimpleAttributeSet(); + StyleConstants.setLeftIndent(tAttributes, indent); + StyleConstants.setForeground(tAttributes, textColor); + tAttributes.addAttribute("xmlnode", t); + try { + String s = t.getTextTrim(); + int start = doc.getLength()-1; + startOffsets.put(t, new Integer(start)); + doc.insertString(doc.getLength(), s, null); //insert text + int end = doc.getLength(); + endOffsets.put(t, new Integer(end)); + doc.setParagraphAttributes(start+1, end-start, tAttributes, false); + doc.insertString(doc.getLength(), "\n", null); + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + + public Object getNodeForOffset(int offset) { + AttributeSet attSet = doc.getCharacterElement(offset).getAttributes(); + return attSet.getAttribute("xmlnode"); + } + + public int getStartOffsetForNode(Object node) { + Position pos = (Position)startOffsets.get(node); + if (pos == null) return -1; + else return pos.getOffset(); + } + + public int getEndOffsetForNode(Object node) { + Position pos = (Position)endOffsets.get(node); + if (pos == null) return -1; + else return pos.getOffset(); + } + + public boolean isEditable(Object node) { + if (node == null) return false; + else if (node instanceof Element) return false; + else if (node instanceof Text) return true; + else if (node instanceof Attribute) return true; + else return false; + } +}