QD as XML editor. More details later.

This commit is contained in:
eg3p 2003-03-12 12:48:18 +00:00
parent 4070c5ccee
commit a98849d3eb
7 changed files with 1170 additions and 142 deletions

View file

@ -0,0 +1,24 @@
/*
The contents of this file are subject to the THDL Open Community License
Version 1.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License on the THDL web site
(http://www.thdl.org/).
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific terms governing rights and limitations under the
License.
The Initial Developer of this software is the Tibetan and Himalayan Digital
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
All Rights Reserved.
Contributor(s): ______________________________________.
*/
package org.thdl.quilldriver;
public class QDConfiguration {
}

View file

@ -40,18 +40,21 @@ import org.thdl.savant.JdkVersionHacks;
public class QDShell extends JFrame { public class QDShell extends JFrame {
protected static final String defaultConfiguration = new String("http://iris.lib.virginia.edu/tibet/education/tllr/xml/lacito-thdl_qdConfig.xml");
/** the middleman that keeps code regarding Tibetan keyboards /** the middleman that keeps code regarding Tibetan keyboards
* clean */ * clean */
/*
private final static JskadKeyboardManager keybdMgr private final static JskadKeyboardManager keybdMgr
= new JskadKeyboardManager(JskadKeyboardFactory.getAllAvailableJskadKeyboards()); = new JskadKeyboardManager(JskadKeyboardFactory.getAllAvailableJskadKeyboards());
*/
/** When opening a file, this is the only extension QuillDriver /** When opening a file, this is the only extension QuillDriver
cares about. This is case-insensitive. */ cares about. This is case-insensitive. */
protected final static String dotQuillDriver = ".xml"; protected final static String dotQuillDriver = ".xml";
ResourceBundle messages = null; ResourceBundle messages = null;
QD qd = null; QD qd = null;
QDConfiguration qdConfig;
public static void main(String[] args) { public static void main(String[] args) {
try { try {
@ -59,10 +62,12 @@ public class QDShell extends JFrame {
Locale locale; Locale locale;
if (args.length == 2) { /*
locale = new Locale(new String(args[0]), new String(args[1])); if (args.length == 3) {
locale = new Locale(new String(args[1]), new String(args[2]));
ThdlI18n.setLocale(locale); ThdlI18n.setLocale(locale);
} }
*/
try { try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
@ -70,14 +75,26 @@ public class QDShell extends JFrame {
catch (Exception e) { catch (Exception e) {
} }
QDShell qdsh = new QDShell(); QDShell qdsh = new QDShell(args);
qdsh.setVisible(true); qdsh.setVisible(true);
} catch (NoClassDefFoundError err) { } catch (NoClassDefFoundError err) {
ThdlDebug.handleClasspathError("QuillDriver's CLASSPATH", err); ThdlDebug.handleClasspathError("QuillDriver's CLASSPATH", err);
} }
} }
public QDShell() { public QDShell(String[] args) {
String configURL = null;
String newURL = null;
String editURL = null;
String dtdURL = null;
switch (args.length) {
case 4: dtdURL = new String(args[3]);
case 3: newURL = new String(args[2]);
case 2: editURL = new String(args[1]);
case 1: configURL = new String(args[0]);
}
setTitle("QuillDriver"); setTitle("QuillDriver");
messages = ThdlI18n.getResourceBundle(); messages = ThdlI18n.getResourceBundle();
@ -98,42 +115,51 @@ public class QDShell extends JFrame {
setVisible(true); setVisible(true);
} }
qd = new QD(); if (args.length == 4) {
qd = new QD(configURL, editURL, newURL, dtdURL);
getContentPane().add(qd); getContentPane().add(qd);
setJMenuBar(getQDShellMenu()); setJMenuBar(getQDShellMenu());
} else {
try {
String home = System.getProperty("user.home");
String sep = System.getProperty("file.separator");
String path = "file:" + home + sep + "put-in-home-directory" + sep;
qd = new QD(path+"config.xml", path+"edit.xsl", path+"new.xsl", path+"dtd.dtd");
getContentPane().add(qd);
setJMenuBar(getQDShellMenu());
} catch (SecurityException se) {
se.printStackTrace();
}
}
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter () { addWindowListener(new WindowAdapter () {
public void windowClosing (WindowEvent e) { public void windowClosing (WindowEvent e) {
if (getWantSave()) qd.saveTranscript();
getSave();
System.exit(0); System.exit(0);
} }
}); });
} }
public JMenuBar getQDShellMenu() { public JMenuBar getQDShellMenu() {
JMenu projectMenu = new JMenu(messages.getString("Project")); JMenu projectMenu = new JMenu(messages.getString("File"));
JMenuItem newItem = new JMenuItem(messages.getString("New")); JMenuItem newItem = new JMenuItem(messages.getString("New"));
newItem.addActionListener(new ThdlActionListener() { newItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) { public void theRealActionPerformed(ActionEvent e) {
if (getWantSave()) qd.saveTranscript();
getSave(); String s = "To start a new annotation, first open a video, " +
qd.clearProject(); "and then create and save an empty annotation file.";
}
});
JMenuItem openVideoItem = new JMenuItem(messages.getString("OpenMediaFile"));
openVideoItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) {
if (getWantSave())
getSave();
JFileChooser fc = new JFileChooser(); JFileChooser fc = new JFileChooser();
if (fc.showDialog(QDShell.this, messages.getString("SelectMedia")) == JFileChooser.APPROVE_OPTION) { if (fc.showDialog(QDShell.this, messages.getString("SelectMedia")) == JFileChooser.APPROVE_OPTION) {
File mediaFile = fc.getSelectedFile(); File mediaFile = fc.getSelectedFile();
try { try {
qd.newProject(mediaFile.toURL()); JFileChooser fc2 = new JFileChooser();
fc2.addChoosableFileFilter(new QDFileFilter());
if (fc2.showDialog(QDShell.this, messages.getString("SaveTranscript")) == JFileChooser.APPROVE_OPTION) {
File transcriptFile = fc2.getSelectedFile();
String mediaString = mediaFile.toURL().toString();
qd.newTranscript(transcriptFile, mediaString);
}
} catch (MalformedURLException murle) { } catch (MalformedURLException murle) {
murle.printStackTrace(); murle.printStackTrace();
ThdlDebug.noteIffyCode(); ThdlDebug.noteIffyCode();
@ -142,31 +168,10 @@ public class QDShell extends JFrame {
} }
}); });
JMenuItem openURLItem = new JMenuItem(messages.getString("OpenMediaURL")); JMenuItem openItem = new JMenuItem(messages.getString("Open"));
openURLItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) {
String url = JOptionPane.showInputDialog(QDShell.this,
messages.getString("TypeMediaURL"));
if (url != null) {
if (getWantSave())
getSave();
try {
qd.newProject(new URL(url));
} catch (MalformedURLException murle) {
murle.printStackTrace();
ThdlDebug.noteIffyCode();
}
}
}
});
JMenuItem openItem = new JMenuItem(messages.getString("OpenTranscript"));
openItem.addActionListener(new ThdlActionListener() { openItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) { public void theRealActionPerformed(ActionEvent e) {
if (getWantSave()) qd.saveTranscript();
getSave();
JFileChooser fc = new JFileChooser(); JFileChooser fc = new JFileChooser();
fc.addChoosableFileFilter(new QDFileFilter()); fc.addChoosableFileFilter(new QDFileFilter());
if (fc.showDialog(QDShell.this, messages.getString("OpenTranscript")) == JFileChooser.APPROVE_OPTION) { if (fc.showDialog(QDShell.this, messages.getString("OpenTranscript")) == JFileChooser.APPROVE_OPTION) {
@ -176,38 +181,24 @@ public class QDShell extends JFrame {
} }
}); });
/*
JMenuItem closeItem = new JMenuItem(messages.getString("Close"));
closeItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) {
if (getSave())
qd.clearProject();
}
});
*/
JMenuItem saveItem = new JMenuItem(messages.getString("Save")); JMenuItem saveItem = new JMenuItem(messages.getString("Save"));
saveItem.addActionListener(new ThdlActionListener() { saveItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) { public void theRealActionPerformed(ActionEvent e) {
getSave(); qd.saveTranscript();
} }
}); });
JMenuItem quitItem = new JMenuItem(messages.getString("Quit")); JMenuItem quitItem = new JMenuItem(messages.getString("Quit"));
quitItem.addActionListener(new ThdlActionListener() { quitItem.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) { public void theRealActionPerformed(ActionEvent e) {
if (getWantSave()) qd.saveTranscript();
getSave();
System.exit(0); System.exit(0);
} }
}); });
projectMenu.add(newItem); projectMenu.add(newItem);
projectMenu.addSeparator(); projectMenu.addSeparator();
projectMenu.add(openVideoItem);
projectMenu.add(openURLItem);
projectMenu.add(openItem); projectMenu.add(openItem);
projectMenu.addSeparator();
// projectMenu.add(closeItem);
// projectMenu.addSeparator();
projectMenu.add(saveItem); projectMenu.add(saveItem);
projectMenu.addSeparator(); projectMenu.addSeparator();
projectMenu.add(quitItem); projectMenu.add(quitItem);
@ -215,47 +206,7 @@ public class QDShell extends JFrame {
//Tibetan-specific value: remove in non-Tibetan version //Tibetan-specific value: remove in non-Tibetan version
//non-Tibetan specific version would have Transcription Language option here instead //non-Tibetan specific version would have Transcription Language option here instead
/*
/* Note that on the Mac, you radio buttons don't appear possible as
submenus on menu bars. They just don't show up.
JRadioButton[] buttons = new JRadioButton[4];
buttons[0] = new JRadioButton("THDL Extended Wylie");
buttons[1] = new JRadioButton("TCC Keyboard 1");
buttons[2] = new JRadioButton("TCC Keyboard 2");
buttons[3] = new JRadioButton("Sambhota Keymap One");
buttons[0].setActionCommand("wylie");
buttons[1].setActionCommand("tcc1");
buttons[2].setActionCommand("tcc2");
buttons[3].setActionCommand("sambhota1");
ThdlActionListener l1 = new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) {
qd.changeKeyboard(e);
}
};
buttons[0].addActionListener(l1);
buttons[1].addActionListener(l1);
buttons[2].addActionListener(l1);
buttons[3].addActionListener(l1);
ButtonGroup bg = new ButtonGroup();
bg.add(buttons[0]);
bg.add(buttons[1]);
bg.add(buttons[2]);
bg.add(buttons[3]);
JPanel b1 = new JPanel(new GridLayout(0,1));
b1.add(buttons[0]);
b1.add(buttons[1]);
b1.add(buttons[2]);
b1.add(buttons[3]);
int initialKeyboard
= ThdlOptions.getIntegerOption("thdl.default.tibetan.keyboard", 0);
buttons[initialKeyboard].setSelected(true);
*/
JMenu keyboardMenu = new JMenu(messages.getString("Keyboard")); JMenu keyboardMenu = new JMenu(messages.getString("Keyboard"));
for (int i = 0; i < keybdMgr.size(); i++) { for (int i = 0; i < keybdMgr.size(); i++) {
@ -269,7 +220,7 @@ public class QDShell extends JFrame {
}); });
keyboardMenu.add(keybdItem); keyboardMenu.add(keybdItem);
} }
} }*/
JMenu mediaPlayerMenu = new JMenu(messages.getString("MediaPlayer")); JMenu mediaPlayerMenu = new JMenu(messages.getString("MediaPlayer"));
java.util.List moviePlayers = SmartPlayerFactory.getAllAvailableSmartPlayers(); java.util.List moviePlayers = SmartPlayerFactory.getAllAvailableSmartPlayers();
@ -285,7 +236,7 @@ public class QDShell extends JFrame {
} }
JMenu preferencesMenu = new JMenu(messages.getString("Preferences")); JMenu preferencesMenu = new JMenu(messages.getString("Preferences"));
preferencesMenu.add(keyboardMenu); // preferencesMenu.add(keyboardMenu);
if (moviePlayers.size() > 0) { if (moviePlayers.size() > 0) {
SmartMoviePanel defaultPlayer = (SmartMoviePanel)moviePlayers.get(0); SmartMoviePanel defaultPlayer = (SmartMoviePanel)moviePlayers.get(0);
qd.setMediaPlayer(defaultPlayer); //set qd media player to default qd.setMediaPlayer(defaultPlayer); //set qd media player to default
@ -293,43 +244,14 @@ public class QDShell extends JFrame {
preferencesMenu.add(mediaPlayerMenu); preferencesMenu.add(mediaPlayerMenu);
} }
JMenu[] configMenus = qd.getConfiguredMenus();
JMenuBar bar = new JMenuBar(); JMenuBar bar = new JMenuBar();
bar.add(projectMenu); bar.add(projectMenu);
for (int i=0; i<configMenus.length; i++) bar.add(configMenus[i]);
bar.add(preferencesMenu); bar.add(preferencesMenu);
return bar; return bar;
} }
private boolean getWantSave() {
if (qd.pane.getDocument().getLength() == 0 && qd.speakerTable.getRowCount() == 0)
return false; //nothing to save
if (JOptionPane.showConfirmDialog(QDShell.this, messages.getString("WantSave"), null, JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION)
return true;
else
return false;
}
private void getSave() {
if (qd.pane.getDocument().getLength() == 0 && qd.speakerTable.getRowCount() == 0)
return; //nothing to save
JFileChooser fc = new JFileChooser();
if (qd.project.getTranscript() == null) {
if (qd.project.getMedia() == null)
fc.setSelectedFile(null);
else {
String path = qd.project.getMedia().getPath();
path = path.substring(0, path.lastIndexOf('.')) + QDShell.dotQuillDriver;
fc.setSelectedFile(new File(path));
}
} else
fc.setSelectedFile(qd.project.getTranscript());
int op = fc.showSaveDialog(QDShell.this);
if (op == JFileChooser.APPROVE_OPTION) {
File f = fc.getSelectedFile();
qd.project.setTranscript(f);
qd.saveTranscript();
}
}
private class QDFileFilter extends javax.swing.filechooser.FileFilter { private class QDFileFilter extends javax.swing.filechooser.FileFilter {
// accepts all directories and all savant files // accepts all directories and all savant files

View file

@ -0,0 +1,43 @@
package org.thdl.quilldriver;
import java.util.HashMap;
public class XMLParameters {
private HashMap displayYesNo, displayContentsYesNo, displays;
public XMLParameters() {
displayYesNo = new HashMap();
displayContentsYesNo = new HashMap();
displays = new HashMap();
}
public boolean containsTag(String tag) {
if (displayYesNo.get(tag) == null) return false;
else return true;
}
public void addTagOptions(String tag, Boolean display, Boolean displayContents, String displayAs) {
displayYesNo.put(tag, display);
displayContentsYesNo.put(tag, displayContents);
displays.put(tag, displayAs);
}
public void removeTagOptions(String tag) {
displayYesNo.remove(tag);
displayContentsYesNo.remove(tag);
displays.remove(tag);
}
public boolean isTagForDisplay(String tag) {
Object obj = displayYesNo.get(tag);
if (obj == null) return false;
else return ((Boolean)obj).booleanValue();
}
public boolean areTagContentsForDisplay(String tag) {
Object obj = displayContentsYesNo.get(tag);
if (obj == null) return false;
else return ((Boolean)obj).booleanValue();
}
public getDisplayForTag(String tag) {
Object obj = displayAs.get(tag);
if (obj == null) return null;
else return (String)obj;
}
}

View file

@ -0,0 +1,788 @@
package org.thdl.quilldriver;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Attribute;
import org.jdom.Text;
import org.jdom.DocType;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.KeyEvent;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.List;
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.EventObject;
import java.util.EventListener;
import javax.swing.JTextPane;
import javax.swing.text.JTextComponent;
import javax.swing.Action;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import javax.swing.text.Keymap;
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;
import javax.swing.text.DefaultEditorKit;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.CaretEvent;
import javax.swing.event.EventListenerList;
public class XMLEditor {
private EventListenerList listenerList = new EventListenerList();
private Document xml;
private JTextPane pane;
private StyledDocument doc;
private DocumentListener docListen;
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.darkGray;
private Cursor textCursor;
private Cursor defaultCursor;
private boolean isEditing = false;
private Object editingNode = null;
private boolean hasChanged = false;
private Hashtable actions;
private CaretListener editabilityTracker;
private XMLTagInfo tagInfo;
public XMLEditor(Document xmlDoc, JTextPane textPane, XMLTagInfo tagInfo) {
xml = xmlDoc;
pane = textPane;
this.tagInfo = tagInfo;
startOffsets = new HashMap();
endOffsets = new HashMap();
docListen = new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
hasChanged = true;
}
public void insertUpdate(DocumentEvent e) {
hasChanged = true;
if (getStartOffsetForNode(editingNode) > e.getOffset()) {
javax.swing.text.Document d = e.getDocument();
try {
startOffsets.put(editingNode, d.createPosition(e.getOffset()));
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
public void removeUpdate(DocumentEvent e) {
hasChanged = true;
}
};
render();
textCursor = new Cursor(Cursor.TEXT_CURSOR);
defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR);
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.viewToModel(e.getPoint());
if (isEditable(offset)) p.setCursor(textCursor);
else p.setCursor(defaultCursor);
}
});
MouseListener[] listeners = (MouseListener[])pane.getListeners(MouseListener.class);
for (int i=0; i<listeners.length; i++) pane.removeMouseListener(listeners[i]);
pane.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.viewToModel(e.getPoint());
if (isEditable(offset)) {
p.requestFocus();
if (isEditing) fireEndEditEvent();
fireStartEditEvent(getNodeForOffset(offset));
p.setCaretPosition(offset);
} else {
Object node = getNodeForOffset(offset);
if (isEditing) fireEndEditEvent();
if (node != null) fireCantEditEvent(getNodeForOffset(offset));
}
}
});
pane.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
JTextPane p = (JTextPane)e.getSource();
if (isEditable(p.getCaretPosition()))
fireStartEditEvent(getNodeForOffset(p.getCaretPosition()));
}
public void focusLost(FocusEvent e) {
JTextPane p = (JTextPane)e.getSource();
if (isEditing) fireEndEditEvent();
}
});
editabilityTracker = new CaretListener() {
public void caretUpdate(CaretEvent e) {
int dot = e.getDot();
if (getNodeForOffset(dot) != getNodeForOffset(e.getMark()))
pane.getCaret().setDot(dot);
if (!isEditable(dot)) {
while (!isEditable(dot) && dot<pane.getDocument().getLength()) dot++;
if (dot == pane.getDocument().getLength()) {
dot = e.getDot();
do {
dot--;
} while (!isEditable(dot) && dot>-1);
if (dot == -1) return; //what to do? there's nothing to edit in this pane
}
if (isEditable(dot)) {
pane.getCaret().setDot(dot);
if (getNodeForOffset(dot) != null) fireStartEditEvent(getNodeForOffset(dot));
}
} else if (editingNode == null) //need to start editing because cursor happens to be on an editable node
fireStartEditEvent(getNodeForOffset(dot));
}
};
Action nextNodeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int prePos = p.getCaretPosition();
Object node = getNodeForOffset(prePos);
int i = prePos+1;
while (i<p.getDocument().getLength() && isEditable(i) && getNodeForOffset(i) == node) i++;
while (i<p.getDocument().getLength() && !isEditable(i)) i++;
node = getNodeForOffset(i);
while (i<p.getDocument().getLength() && isEditable(i) && getNodeForOffset(i) == node) i++;
if (isEditing) fireEndEditEvent();
i--;
fireStartEditEvent(getNodeForOffset(i));
p.setCaretPosition(i);
}
};
Action selectNodeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
Object node = getNodeForOffset(p.getCaretPosition());
if (node != null) {
p.setSelectionStart(((Position)startOffsets.get(node)).getOffset());
int end = ((Position)endOffsets.get(node)).getOffset();
if (node instanceof Text) p.setSelectionEnd(end);
else if (node instanceof Attribute) p.setSelectionEnd(end-1);
}
}
};
Action selForwardAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
Object node = getNodeForOffset(offset);
int last = (((Position)endOffsets.get(node)).getOffset());
if (node instanceof Attribute) last--;
if (offset < last) p.getCaret().moveDot(offset++);
}
};
Action selBackwardAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
int first = (((Position)startOffsets.get(getNodeForOffset(offset))).getOffset());
if (offset > first) p.getCaret().moveDot(offset--);
}
};
Action selectToNodeEndAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
Object node = getNodeForOffset(p.getCaret().getMark());
if (node != null) {
int last = (((Position)endOffsets.get(node)).getOffset());
if (node instanceof Attribute) last--;
p.getCaret().moveDot(last);
}
}
};
Action selectToNodeStartAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
Object node = getNodeForOffset(p.getCaret().getMark());
if (node != null) {
int first = (((Position)startOffsets.get(node)).getOffset());
p.getCaret().moveDot(first);
}
}
};
Action backwardAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int prePos = p.getCaretPosition();
int newPos = prePos-1;
while (newPos>-1 && !isEditable(newPos)) newPos--;
if (newPos != -1) {
if (getNodeForOffset(prePos) != getNodeForOffset(newPos)) {
fireEndEditEvent();
fireStartEditEvent(getNodeForOffset(newPos));
}
p.setCaretPosition(newPos);
}
}
};
Action forwardAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int prePos = p.getCaretPosition();
int newPos = prePos+1;
while (newPos<p.getDocument().getLength() && !isEditable(newPos)) newPos++;
if (newPos != p.getDocument().getLength()) {
if (getNodeForOffset(prePos) != getNodeForOffset(newPos)) {
fireEndEditEvent();
fireStartEditEvent(getNodeForOffset(newPos));
}
p.setCaretPosition(newPos);
}
}
};
Action begNodeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
Object node = getNodeForOffset(p.getCaretPosition());
p.setCaretPosition(((Position)startOffsets.get(node)).getOffset());
}
};
Action endNodeAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
Object node = getNodeForOffset(p.getCaretPosition());
p.setCaretPosition(((Position)endOffsets.get(node)).getOffset());
}
};
Action deleteNextAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
int last = (((Position)endOffsets.get(getNodeForOffset(offset))).getOffset());
if (offset < last) {
StyledDocument d = p.getStyledDocument();
try {
d.remove(offset, 1);
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
};
Action deletePrevAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
int first = (((Position)startOffsets.get(getNodeForOffset(offset))).getOffset());
if (offset > first) {
StyledDocument d = p.getStyledDocument();
try {
d.remove(offset-1, 1);
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
};
Action loseFocusAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
p.transferFocus(); //moves focus to next component
}
};
/* Action selForwardAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JTextPane p = (JTextPane)e.getSource();
int offset = p.getCaretPosition();
}
};
*/
createActionTable(pane);
JTextPane tp = new JTextPane();
Keymap keymap = tp.addKeymap("KeyBindings", tp.getKeymap());
KeyStroke[] selectAllKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectAllAction));
if (selectAllKeys != null)
for (int i=0; i<selectAllKeys.length; i++)
keymap.addActionForKeyStroke(selectAllKeys[i], selectNodeAction);
KeyStroke[] selLineKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectLineAction));
if (selLineKeys != null)
for (int i=0; i<selLineKeys.length; i++)
keymap.addActionForKeyStroke(selLineKeys[i], selectNodeAction);
KeyStroke[] selParaKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectParagraphAction));
if (selParaKeys != null)
for (int i=0; i<selParaKeys.length; i++)
keymap.addActionForKeyStroke(selParaKeys[i], selectNodeAction);
KeyStroke[] selEndLineKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionEndLineAction));
if (selEndLineKeys != null)
for (int i=0; i<selEndLineKeys.length; i++)
keymap.addActionForKeyStroke(selEndLineKeys[i], selectToNodeEndAction);
KeyStroke[] selEndParaKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionEndParagraphAction));
if (selEndParaKeys != null)
for (int i=0; i<selEndParaKeys.length; i++)
keymap.addActionForKeyStroke(selEndParaKeys[i], selectToNodeEndAction);
KeyStroke[] selBegLineKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionBeginLineAction));
if (selBegLineKeys != null)
for (int i=0; i<selBegLineKeys.length; i++)
keymap.addActionForKeyStroke(selBegLineKeys[i], selectToNodeStartAction);
KeyStroke[] selBegParaKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionBeginParagraphAction));
if (selBegParaKeys != null)
for (int i=0; i<selBegParaKeys.length; i++)
keymap.addActionForKeyStroke(selBegParaKeys[i], selectToNodeStartAction);
KeyStroke[] tabKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.insertTabAction));
if (tabKeys != null)
for (int i=0; i<tabKeys.length; i++)
keymap.addActionForKeyStroke(tabKeys[i], nextNodeAction);
KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
if (enterKey != null) keymap.addActionForKeyStroke(enterKey, nextNodeAction);
KeyStroke[] endLineKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.endLineAction));
if (endLineKeys != null)
for (int i=0; i<endLineKeys.length; i++)
keymap.addActionForKeyStroke(endLineKeys[i], endNodeAction);
KeyStroke[] endParaKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.endParagraphAction));
if (endParaKeys != null)
for (int i=0; i<endParaKeys.length; i++)
keymap.addActionForKeyStroke(endParaKeys[i], endNodeAction);
KeyStroke[] begLineKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.beginLineAction));
if (begLineKeys != null)
for (int i=0; i<begLineKeys.length; i++)
keymap.addActionForKeyStroke(begLineKeys[i], begNodeAction);
KeyStroke[] begParaKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.beginParagraphAction));
if (begParaKeys != null)
for (int i=0; i<begParaKeys.length; i++)
keymap.addActionForKeyStroke(begParaKeys[i], begNodeAction);
KeyStroke[] backwardKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.backwardAction));
if (backwardKeys != null)
for (int i=0; i<backwardKeys.length; i++)
keymap.addActionForKeyStroke(backwardKeys[i], backwardAction);
KeyStroke[] forwardKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.forwardAction));
if (forwardKeys != null)
for (int i=0; i<forwardKeys.length; i++)
keymap.addActionForKeyStroke(forwardKeys[i], forwardAction);
KeyStroke[] delNextKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.deleteNextCharAction));
if (delNextKeys != null)
for (int i=0; i<delNextKeys.length; i++)
keymap.addActionForKeyStroke(delNextKeys[i], deleteNextAction);
KeyStroke[] delPrevKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.deletePrevCharAction));
if (delPrevKeys != null)
for (int i=0; i<delPrevKeys.length; i++)
keymap.addActionForKeyStroke(delPrevKeys[i], deletePrevAction);
KeyStroke[] selForwardKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionForwardAction));
if (selForwardKeys != null)
for (int i=0; i<selForwardKeys.length; i++)
keymap.addActionForKeyStroke(selForwardKeys[i], selForwardAction);
KeyStroke[] selBackKeys = keymap.getKeyStrokesForAction(getActionByName(DefaultEditorKit.selectionBackwardAction));
if (selBackKeys != null)
for (int i=0; i<selBackKeys.length; i++)
keymap.addActionForKeyStroke(selBackKeys[i], selBackwardAction);
KeyStroke escapeKey = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
if (escapeKey != null) keymap.addActionForKeyStroke(escapeKey, loseFocusAction);
/*
Actions that still need to be defined:
Fields inherited from class javax.swing.text.DefaultEditorKit
beepAction, beginAction, beginWordAction, copyAction, cutAction,
defaultKeyTypedAction,
downAction, endAction, EndOfLineStringProperty,
endWordAction, insertBreakAction, insertContentAction,
nextWordAction, pageDownAction, pageUpAction,
pasteAction, previousWordAction, readOnlyAction
selectionBeginAction, selectionBeginWordAction,
selectionDownAction, selectionEndAction, selectionEndWordAction,
selectionNextWordAction, selectionPreviousWordAction,
selectionUpAction, selectWordAction,
upAction, writableAction
*/
pane.setKeymap(keymap);
}
private void createActionTable(JTextComponent textComponent) {
actions = new Hashtable();
Action[] actionsArray = textComponent.getActions();
for (int i = 0; i < actionsArray.length; i++) {
Action a = actionsArray[i];
actions.put(a.getValue(Action.NAME), a);
}
}
private Action getActionByName(String name) {
return (Action)(actions.get(name));
}
public void setEditabilityTracker(boolean bool) {
if (bool) {
int p = pane.getCaretPosition();
int q;
if (pane.getDocument().getLength() == 0)
q=0;
else {
if (p>0) q=p-1;
else q=p+1;
}
pane.setCaretPosition(q);
pane.addCaretListener(editabilityTracker); //shouldn't do if already installed
pane.setCaretPosition(p);
}
else pane.removeCaretListener(editabilityTracker);
}
public void updateNode(Object node) {
System.out.println("updating: " + node.toString());
if (node == null)
return;
try {
if (node instanceof Text) {
int p1 = ((Position)startOffsets.get(node)).getOffset();
int p2 = ((Position)endOffsets.get(node)).getOffset();
String val = pane.getDocument().getText(p1, p2-p1).trim();
Text text = (Text)node;
text.setText(val);
} else if (node instanceof Attribute) {
int p1 = ((Position)startOffsets.get(node)).getOffset();
int p2 = ((Position)endOffsets.get(node)).getOffset()-1; //remove right quote
String val = pane.getDocument().getText(p1, p2-p1).trim();
Attribute att = (Attribute)node;
att.setValue(val);
}
System.out.println("updated: " + node.toString());
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
interface NodeEditListener extends EventListener {
public void nodeEditPerformed(NodeEditEvent ned);
}
public void addNodeEditListener(NodeEditListener ned) {
listenerList.add(NodeEditListener.class, ned);
}
public void removeNodeEditListener(NodeEditListener ned) {
listenerList.remove(NodeEditListener.class, ned);
}
class NodeEditEvent extends EventObject {
Object node;
NodeEditEvent(Object node) {
super(node);
this.node = node;
}
public Object getNode() {
return node;
}
}
class StartEditEvent extends NodeEditEvent {
StartEditEvent(Object node) {
super(node);
}
}
class EndEditEvent extends NodeEditEvent {
public EndEditEvent(Object node) {
super(node);
}
public boolean hasBeenEdited() {
return hasChanged;
}
}
class CantEditEvent extends NodeEditEvent {
public CantEditEvent(Object node) {
super(node);
}
}
public void fireStartEditEvent(Object node) {
//see javadocs on EventListenerList for how following array is structured
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==NodeEditListener.class)
((NodeEditListener)listeners[i+1]).nodeEditPerformed(new StartEditEvent(node));
}
isEditing = true;
editingNode = node;
hasChanged = false;
}
public void fireEndEditEvent() {
if (!isEditing) return;
//see javadocs on EventListenerList for how following array is structured
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==NodeEditListener.class)
((NodeEditListener)listeners[i+1]).nodeEditPerformed(new EndEditEvent(editingNode));
}
if (hasChanged) updateNode(editingNode);
isEditing = false;
editingNode = null;
hasChanged = false;
}
public void fireCantEditEvent(Object node) {
//see javadocs on EventListenerList for how following array is structured
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==NodeEditListener.class)
((NodeEditListener)listeners[i+1]).nodeEditPerformed(new CantEditEvent(node));
}
}
public void setXMLDocument(Document d, String doctype_elementName, String doctype_systemID) {
xml = d;
xml.setDocType(new DocType(doctype_elementName, doctype_systemID));
render();
}
public void render() {
System.out.println("Rendering the document");
doc = pane.getStyledDocument();
int len = doc.getLength();
try {
if (len > 0) doc.remove(0, len);
doc.insertString(0, "\n", null);
} catch (BadLocationException ble) {
ble.printStackTrace();
}
startOffsets.clear();
endOffsets.clear();
Element root = xml.getRootElement();
renderElement(root, 0.0F, doc.getLength());
SimpleAttributeSet eColor = new SimpleAttributeSet();
eColor.addAttribute("xmlnode", root);
doc.setParagraphAttributes(doc.getLength(), 1, eColor, false);
fixOffsets();
doc.addDocumentListener(docListen);
pane.setCaretPosition(0);
setEditabilityTracker(true);
}
public void fixOffsets() {
//replace Integer values in startOffsets and endOffsets with Positions
Set startKeys = startOffsets.keySet();
Iterator iter = startKeys.iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object obj = startOffsets.get(key);
//if (obj instanceof Position)
// startOffsets.put(key, obj); //actually we don't have to do anything here, do we
//since the startoffsets are already set!!
//else
if (obj instanceof Integer) try {
Integer val = (Integer)obj;
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();
Object obj = endOffsets.get(key);
//if (obj instanceof Position)
// endOffsets.put(key, obj); //actually we don't have to do anything here, do we
//since the endoffsets are already set!!
//else
if (obj instanceof Integer) try {
Integer val = (Integer)obj;
endOffsets.put(key, doc.createPosition(val.intValue()));
} catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
public int renderElement(Element e, float indent, int insertOffset) {
try {
Position pos = doc.createPosition(insertOffset);
SimpleAttributeSet eAttributes = new SimpleAttributeSet();
StyleConstants.setLeftIndent(eAttributes, indent);
SimpleAttributeSet eColor = new SimpleAttributeSet();
//StyleConstants.setLeftIndent(eColor, indent);
StyleConstants.setForeground(eColor, tagColor);
eColor.addAttribute("xmlnode", e);
if (pos.getOffset()>0) {
String s = doc.getText(pos.getOffset()-1, 1);
if (s.charAt(0)!='\n') {
AttributeSet attSet = doc.getCharacterElement(pos.getOffset()-1).getAttributes();
doc.insertString(pos.getOffset(), "\n", attSet);
}
}
int start = pos.getOffset();
startOffsets.put(e, new Integer(start));
String tagDisplay;
if (tagInfo == null) tagDisplay = e.getQualifiedName();
else tagDisplay = tagInfo.getTagDisplay(e);
doc.insertString(pos.getOffset(), tagDisplay, eColor); //insert element begin tag
if (tagInfo == null || tagInfo.areTagContentsForDisplay(e.getQualifiedName())) {
List attributes = e.getAttributes();
Iterator iter = attributes.iterator();
while (iter.hasNext()) {
Attribute att = (Attribute)iter.next();
if (tagInfo == null || tagInfo.isAttributeForDisplay(att.getQualifiedName(), e.getQualifiedName()))
renderAttribute(att, pos.getOffset());
}
doc.insertString(pos.getOffset(), ":", eColor);
doc.setParagraphAttributes(start, pos.getOffset()-start, eAttributes, false);
//doc.insertString(pos.getOffset(), "\n", null);
List list = e.getContent();
iter = list.iterator();
while (iter.hasNext()) {
Object next = iter.next();
if (next instanceof Element) {
Element ne = (Element)next;
if (tagInfo == null || tagInfo.isTagForDisplay(ne.getQualifiedName()))
renderElement(ne, indent + indentIncrement, pos.getOffset());
} else if (next instanceof Text) {
Text t = (Text)next;
if (t.getParent().getContent().size() == 1 || t.getTextTrim().length() > 0)
renderText(t, indent + indentIncrement, pos.getOffset());
}
// Also: Comment ProcessingInstruction CDATA EntityRef
}
}
//start = pos.getOffset();
//doc.insertString(start, "}", eColor); //insert element end tag
//doc.setParagraphAttributes(start, pos.getOffset(), eAttributes, false);
if (pos.getOffset()>0) {
//String s = doc.getText(pos.getOffset()-1, 1);
if (doc.getText(pos.getOffset()-1,1).charAt(0)=='\n')
endOffsets.put(e, new Integer(pos.getOffset()-1));
else
endOffsets.put(e, new Integer(pos.getOffset()));
}
//endOffsets.put(e, new Integer(pos.getOffset()));
return pos.getOffset();
//doc.insertString(pos.getOffset(), "\n", null);
} catch (BadLocationException ble) {
ble.printStackTrace();
return -1;
}
}
public int renderAttribute(Attribute att, int insertOffset) {
try {
Position pos = doc.createPosition(insertOffset);
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();
if (pos.getOffset()>0) {
String s = doc.getText(pos.getOffset()-1, 1);
if (s.charAt(0)!='\n') {
AttributeSet attSet = doc.getCharacterElement(pos.getOffset()-1).getAttributes();
doc.insertString(pos.getOffset(), " ", attSet);
}
}
String displayName;
if (tagInfo == null) displayName = att.getQualifiedName();
else displayName = tagInfo.getAttributeDisplay(att.getQualifiedName(), att.getParent().getQualifiedName());
doc.insertString(pos.getOffset(), displayName+"=", aColor);
startOffsets.put(att, new Integer(pos.getOffset()+1)); //add one so that begin quote is not part of attribute value
doc.insertString(pos.getOffset(), "\"" + att.getValue()+"\"", tColor);
endOffsets.put(att, new Integer(pos.getOffset()));
return pos.getOffset();
} catch (BadLocationException ble) {
ble.printStackTrace();
return -1;
}
}
public int renderText(Text t, float indent, int insertOffset) {
try {
Position pos = doc.createPosition(insertOffset);
SimpleAttributeSet tAttributes = new SimpleAttributeSet();
//StyleConstants.setLeftIndent(tAttributes, indent);
StyleConstants.setForeground(tAttributes, textColor);
tAttributes.addAttribute("xmlnode", t);
doc.insertString(pos.getOffset(), " ", tAttributes); //insert space with text attributes so first character has correct color, xmlnode attribute, etc.
String s = t.getTextTrim();
int start = pos.getOffset();
startOffsets.put(t, new Integer(start));
doc.insertString(pos.getOffset(), s, tAttributes); //insert text
int end = pos.getOffset();
endOffsets.put(t, new Integer(end));
doc.insertString(pos.getOffset(), "\n", tAttributes);
return pos.getOffset();
} catch (BadLocationException ble) {
ble.printStackTrace();
return -1;
}
}
public void removeNode(Object node) {
if (startOffsets.containsKey(node)) { //note: should recursively eliminate all sub-nodes too!!
startOffsets.remove(node);
endOffsets.remove(node);
}
}
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(int offset) {
Object node = getNodeForOffset(offset);
if ((node instanceof Text) &&
(offset<getStartOffsetForNode(node) || offset>getEndOffsetForNode(node)))
return false;
else if (node instanceof Attribute &&
(offset<getStartOffsetForNode(node) || offset>getEndOffsetForNode(node)-1))
return false;
else
return isEditable(node);
}
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;
}
public JTextPane getTextPane() {
return pane;
}
public Document getXMLDocument() {
return xml;
}
}

View file

@ -0,0 +1,77 @@
package org.thdl.quilldriver;
import java.util.HashMap;
import org.jdom.Element;
import org.thdl.quilldriver.XMLUtilities;
public class XMLTagInfo {
private HashMap displayYesNo, displayContentsYesNo, displayAs;
private HashMap attributeDisplayYesNo, attributeDisplayAs;
public XMLTagInfo() {
displayYesNo = new HashMap();
displayContentsYesNo = new HashMap();
displayAs = new HashMap();
attributeDisplayYesNo = new HashMap();
attributeDisplayAs = new HashMap();
}
public boolean containsTag(String tag) {
if (displayYesNo.get(tag) == null) return false;
else return true;
}
public void addTag(String tag, Boolean display, Boolean displayContents, String displayAs) {
displayYesNo.put(tag, display);
displayContentsYesNo.put(tag, displayContents);
this.displayAs.put(tag, displayAs);
}
public void removeTag(String tag) {
displayYesNo.remove(tag);
displayContentsYesNo.remove(tag);
displayAs.remove(tag);
}
public void addAttribute(String name, String parentTag, Boolean display, String displayAs) {
String s = parentTag + "/@" + name;
attributeDisplayYesNo.put(s, display);
attributeDisplayAs.put(s, displayAs);
}
public void removeAttribute(String name, String parentTag) {
String s = parentTag + "/@" + name;
attributeDisplayYesNo.remove(s);
attributeDisplayAs.remove(s);
}
public boolean isTagForDisplay(String tag) {
Object obj = displayYesNo.get(tag);
if (obj == null) return true;
else return ((Boolean)obj).booleanValue();
}
public boolean areTagContentsForDisplay(String tag) {
Object obj = displayContentsYesNo.get(tag);
if (obj == null) return true;
else return ((Boolean)obj).booleanValue();
}
public String getTagDisplay(Element tag) {
String name = tag.getQualifiedName();
Object obj = displayAs.get(name);
if (obj == null) return name;
String val = (String)obj;
if (val.startsWith("XPATH:")) {
Object node = XMLUtilities.findSingleNode(tag, val.substring(val.indexOf(':')+1));
if (node == null) return name;
String s = XMLUtilities.getTextForNode(node);
if (s == null) return name;
else return s;
} else return val;
}
public boolean isAttributeForDisplay(String name, String parentTag) {
String s = parentTag + "/@" + name;
Object obj = attributeDisplayYesNo.get(s);
if (obj == null) return true;
else return ((Boolean)obj).booleanValue();
}
public String getAttributeDisplay(String name, String parentTag) {
String s = parentTag + "/@" + name;
Object obj = attributeDisplayAs.get(s);
if (obj == null) return name;
else return (String)obj;
}
}

View file

@ -0,0 +1,48 @@
package org.thdl.quilldriver;
import org.jdom.Text;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jaxen.XPath;
import org.jaxen.JaxenException;
import org.jaxen.jdom.JDOMXPath;
import java.util.List;
public class XMLUtilities {
private XMLUtilities() {}
public static Object findSingleNode(Object jdomNode, String xpathExpression) {
if (jdomNode == null)
return null;
try {
JDOMXPath path = new JDOMXPath(xpathExpression);
return path.selectSingleNode(jdomNode);
} catch (JaxenException je) {
je.printStackTrace();
return null;
}
}
public static List findNodeSet(Object jdomNode, String xpathExpression) {
if (jdomNode == null)
return null;
try {
JDOMXPath path = new JDOMXPath(xpathExpression);
return path.selectNodes(jdomNode);
} catch (JaxenException je) {
je.printStackTrace();
return null;
}
}
public static String getTextForNode(Object jdomNode) {
if (jdomNode instanceof Text) {
Text t = (Text)jdomNode;
return t.getText();
} else if (jdomNode instanceof Attribute) {
Attribute a = (Attribute)jdomNode;
return a.getValue();
} else if (jdomNode instanceof Element) {
Element e = (Element)jdomNode;
return e.getTextTrim();
} else return null;
}
}

View file

@ -0,0 +1,126 @@
package org.thdl.quilldriver;
import java.util.List;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.Collection;
import javax.swing.text.JTextComponent;
import org.jdom.Document;
import org.thdl.savant.TranscriptView;
import org.thdl.quilldriver.XMLEditor;
import org.thdl.quilldriver.XMLUtilities;
public class XMLView implements TranscriptView {
private XMLEditor editor;
private Map startTimeMap;
private Map endTimeMap;
private Map startOffsetMap;
private Map endOffsetMap;
private Object jdomContextNode;
private String getNodesXPath;
private String getStartXPath;
private String getEndXPath;
public XMLView(XMLEditor editor, Object jdomContextNode, String getNodesXPath, String getStartXPath, String getEndXPath) {
this.editor = editor;
this.jdomContextNode = jdomContextNode;
this.getNodesXPath = getNodesXPath;
this.getStartXPath = getStartXPath;
this.getEndXPath = getEndXPath;
startTimeMap = new HashMap();
endTimeMap = new HashMap();
startOffsetMap = new HashMap();
endOffsetMap = new HashMap();
refresh();
}
public void refresh(Object newContextNode) {
this.jdomContextNode = newContextNode;
refresh();
}
public void refresh() {
startTimeMap.clear();
endTimeMap.clear();
startOffsetMap.clear();
endOffsetMap.clear();
List audioNodes = XMLUtilities.findNodeSet(jdomContextNode, getNodesXPath);
Iterator iter = audioNodes.iterator();
while (iter.hasNext()) {
Object node = iter.next();
String id = String.valueOf(node.hashCode());
Object start = XMLUtilities.findSingleNode(node, getStartXPath);
String startVal = XMLUtilities.getTextForNode(start);
Object end = XMLUtilities.findSingleNode(node, getEndXPath);
String endVal = XMLUtilities.getTextForNode(end);
int startOffset = editor.getStartOffsetForNode(node);
int endOffset = editor.getEndOffsetForNode(node);
if (!(startVal == null || endVal == null || startOffset == -1 || endOffset == -1)) {
startTimeMap.put(id, startVal);
endTimeMap.put(id, endVal);
startOffsetMap.put(id, String.valueOf(startOffset));
endOffsetMap.put(id, String.valueOf(endOffset));
}
}
}
public String getTitle() {
return "No Title";
}
public JTextComponent getTextComponent() {
return (JTextComponent)editor.getTextPane();
}
public String getIDs() {
Set idSet = startTimeMap.keySet();
Iterator iter = idSet.iterator();
StringBuffer idBuff = new StringBuffer();
while (iter.hasNext()) {
idBuff.append((String)iter.next());
idBuff.append(',');
}
return idBuff.toString();
}
public String getT1s() {
Collection c = startTimeMap.values();
Iterator iter = c.iterator();
StringBuffer buff = new StringBuffer();
while (iter.hasNext()) {
buff.append((String)iter.next());
buff.append(',');
}
return buff.toString();
}
public String getT2s() {
Collection c = endTimeMap.values();
Iterator iter = c.iterator();
StringBuffer buff = new StringBuffer();
while (iter.hasNext()) {
buff.append((String)iter.next());
buff.append(',');
}
return buff.toString();
}
public String getStartOffsets() {
Collection c = startOffsetMap.values();
Iterator iter = c.iterator();
StringBuffer buff = new StringBuffer();
while (iter.hasNext()) {
buff.append((String)iter.next());
buff.append(',');
}
return buff.toString();
}
public String getEndOffsets() {
Collection c = endOffsetMap.values();
Iterator iter = c.iterator();
StringBuffer buff = new StringBuffer();
while (iter.hasNext()) {
buff.append((String)iter.next());
buff.append(',');
}
return buff.toString();
}
public Document getDocument() {
return editor.getXMLDocument();
}
}