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 {
|
||||
|
||||
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
|
||||
* clean */
|
||||
/*
|
||||
private final static JskadKeyboardManager keybdMgr
|
||||
= new JskadKeyboardManager(JskadKeyboardFactory.getAllAvailableJskadKeyboards());
|
||||
|
||||
*/
|
||||
/** When opening a file, this is the only extension QuillDriver
|
||||
cares about. This is case-insensitive. */
|
||||
protected final static String dotQuillDriver = ".xml";
|
||||
|
||||
ResourceBundle messages = null;
|
||||
QD qd = null;
|
||||
QDConfiguration qdConfig;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
|
@ -59,10 +62,12 @@ public class QDShell extends JFrame {
|
|||
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
|
@ -70,14 +75,26 @@ public class QDShell extends JFrame {
|
|||
catch (Exception e) {
|
||||
}
|
||||
|
||||
QDShell qdsh = new QDShell();
|
||||
QDShell qdsh = new QDShell(args);
|
||||
qdsh.setVisible(true);
|
||||
} catch (NoClassDefFoundError 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");
|
||||
messages = ThdlI18n.getResourceBundle();
|
||||
|
||||
|
@ -98,42 +115,51 @@ public class QDShell extends JFrame {
|
|||
setVisible(true);
|
||||
}
|
||||
|
||||
qd = new QD();
|
||||
getContentPane().add(qd);
|
||||
setJMenuBar(getQDShellMenu());
|
||||
if (args.length == 4) {
|
||||
qd = new QD(configURL, editURL, newURL, dtdURL);
|
||||
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);
|
||||
addWindowListener(new WindowAdapter () {
|
||||
public void windowClosing (WindowEvent e) {
|
||||
if (getWantSave())
|
||||
getSave();
|
||||
qd.saveTranscript();
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public JMenuBar getQDShellMenu() {
|
||||
JMenu projectMenu = new JMenu(messages.getString("Project"));
|
||||
JMenu projectMenu = new JMenu(messages.getString("File"));
|
||||
|
||||
JMenuItem newItem = new JMenuItem(messages.getString("New"));
|
||||
newItem.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (getWantSave())
|
||||
getSave();
|
||||
qd.clearProject();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem openVideoItem = new JMenuItem(messages.getString("OpenMediaFile"));
|
||||
openVideoItem.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (getWantSave())
|
||||
getSave();
|
||||
|
||||
qd.saveTranscript();
|
||||
String s = "To start a new annotation, first open a video, " +
|
||||
"and then create and save an empty annotation file.";
|
||||
JFileChooser fc = new JFileChooser();
|
||||
if (fc.showDialog(QDShell.this, messages.getString("SelectMedia")) == JFileChooser.APPROVE_OPTION) {
|
||||
File mediaFile = fc.getSelectedFile();
|
||||
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) {
|
||||
murle.printStackTrace();
|
||||
ThdlDebug.noteIffyCode();
|
||||
|
@ -142,31 +168,10 @@ public class QDShell extends JFrame {
|
|||
}
|
||||
});
|
||||
|
||||
JMenuItem openURLItem = new JMenuItem(messages.getString("OpenMediaURL"));
|
||||
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"));
|
||||
JMenuItem openItem = new JMenuItem(messages.getString("Open"));
|
||||
openItem.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (getWantSave())
|
||||
getSave();
|
||||
|
||||
qd.saveTranscript();
|
||||
JFileChooser fc = new JFileChooser();
|
||||
fc.addChoosableFileFilter(new QDFileFilter());
|
||||
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"));
|
||||
saveItem.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
getSave();
|
||||
qd.saveTranscript();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem quitItem = new JMenuItem(messages.getString("Quit"));
|
||||
quitItem.addActionListener(new ThdlActionListener() {
|
||||
public void theRealActionPerformed(ActionEvent e) {
|
||||
if (getWantSave())
|
||||
getSave();
|
||||
qd.saveTranscript();
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
projectMenu.add(newItem);
|
||||
projectMenu.addSeparator();
|
||||
projectMenu.add(openVideoItem);
|
||||
projectMenu.add(openURLItem);
|
||||
projectMenu.addSeparator();
|
||||
projectMenu.add(openItem);
|
||||
projectMenu.addSeparator();
|
||||
// projectMenu.add(closeItem);
|
||||
// projectMenu.addSeparator();
|
||||
projectMenu.add(saveItem);
|
||||
projectMenu.addSeparator();
|
||||
projectMenu.add(quitItem);
|
||||
|
@ -215,48 +206,8 @@ public class QDShell extends JFrame {
|
|||
//Tibetan-specific value: remove in non-Tibetan version
|
||||
//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++) {
|
||||
final JskadKeyboard kbd = keybdMgr.elementAt(i);
|
||||
|
@ -269,7 +220,7 @@ public class QDShell extends JFrame {
|
|||
});
|
||||
keyboardMenu.add(keybdItem);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
JMenu mediaPlayerMenu = new JMenu(messages.getString("MediaPlayer"));
|
||||
java.util.List moviePlayers = SmartPlayerFactory.getAllAvailableSmartPlayers();
|
||||
|
@ -285,7 +236,7 @@ public class QDShell extends JFrame {
|
|||
}
|
||||
|
||||
JMenu preferencesMenu = new JMenu(messages.getString("Preferences"));
|
||||
preferencesMenu.add(keyboardMenu);
|
||||
// preferencesMenu.add(keyboardMenu);
|
||||
if (moviePlayers.size() > 0) {
|
||||
SmartMoviePanel defaultPlayer = (SmartMoviePanel)moviePlayers.get(0);
|
||||
qd.setMediaPlayer(defaultPlayer); //set qd media player to default
|
||||
|
@ -293,43 +244,14 @@ public class QDShell extends JFrame {
|
|||
preferencesMenu.add(mediaPlayerMenu);
|
||||
}
|
||||
|
||||
JMenu[] configMenus = qd.getConfiguredMenus();
|
||||
JMenuBar bar = new JMenuBar();
|
||||
bar.add(projectMenu);
|
||||
for (int i=0; i<configMenus.length; i++) bar.add(configMenus[i]);
|
||||
bar.add(preferencesMenu);
|
||||
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 {
|
||||
// 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