QD as XML editor. More details later.
This commit is contained in:
parent
4070c5ccee
commit
a98849d3eb
7 changed files with 1170 additions and 142 deletions
24
source/org/thdl/quilldriver/QDConfiguration.java
Normal file
24
source/org/thdl/quilldriver/QDConfiguration.java
Normal 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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
||||||
getContentPane().add(qd);
|
qd = new QD(configURL, editURL, newURL, dtdURL);
|
||||||
setJMenuBar(getQDShellMenu());
|
getContentPane().add(qd);
|
||||||
|
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,48 +206,8 @@ 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
|
JMenu keyboardMenu = new JMenu(messages.getString("Keyboard"));
|
||||||
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"));
|
|
||||||
|
|
||||||
for (int i = 0; i < keybdMgr.size(); i++) {
|
for (int i = 0; i < keybdMgr.size(); i++) {
|
||||||
final JskadKeyboard kbd = keybdMgr.elementAt(i);
|
final JskadKeyboard kbd = keybdMgr.elementAt(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
|
||||||
|
|
||||||
|
|
43
source/org/thdl/quilldriver/RenderingOptions.java
Normal file
43
source/org/thdl/quilldriver/RenderingOptions.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
788
source/org/thdl/quilldriver/XMLEditor.java
Normal file
788
source/org/thdl/quilldriver/XMLEditor.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
77
source/org/thdl/quilldriver/XMLTagInfo.java
Normal file
77
source/org/thdl/quilldriver/XMLTagInfo.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
48
source/org/thdl/quilldriver/XMLUtilities.java
Normal file
48
source/org/thdl/quilldriver/XMLUtilities.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
126
source/org/thdl/quilldriver/XMLView.java
Normal file
126
source/org/thdl/quilldriver/XMLView.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue