diff --git a/source/org/thdl/quilldriver/QD.java b/source/org/thdl/quilldriver/QD.java index e217b51..4e05558 100644 --- a/source/org/thdl/quilldriver/QD.java +++ b/source/org/thdl/quilldriver/QD.java @@ -41,8 +41,16 @@ import org.jdom.transform.JDOMSource; import javax.xml.transform.stream.*; import javax.xml.transform.*; +import org.thdl.util.ThdlDebug; +import org.thdl.util.ThdlActionListener; +import org.thdl.util.ThdlAbstractAction; + public class QD extends JDesktopPane { + /** When opening a file, this is the only extension QuillDriver + cares about. This is case-insensitive. */ + protected final static String dotQuillDriver = ".xml"; + //project related data protected Project project; @@ -97,16 +105,16 @@ public QD(ResourceBundle messages) { fileChooser = new JFileChooser(); fileChooser.addChoosableFileFilter(new XMLFilter()); - Action insert1TimeAction = new AbstractAction("insert1Time", null) { - public void actionPerformed(ActionEvent e) { + Action insert1TimeAction = new ThdlAbstractAction("insert1Time", null) { + public void theRealActionPerformed(ActionEvent e) { new TimePoint(pane, clockIcon, tcp.getOutTime()); tcp.setInTime(tcp.getOutTime().intValue()); tcp.setOutTime(player.getLastTime()); } }; - Action insert2TimesAction = new AbstractAction("insert2Times", null) { - public void actionPerformed(ActionEvent e) { + Action insert2TimesAction = new ThdlAbstractAction("insert2Times", null) { + public void theRealActionPerformed(ActionEvent e) { int p1 = pane.getSelectionStart(); int p2 = pane.getSelectionEnd(); pane.setCaretPosition(p1); @@ -120,8 +128,8 @@ public QD(ResourceBundle messages) { } }; - Action saveAction = new AbstractAction("saveTranscript", null) { - public void actionPerformed(ActionEvent e) { + Action saveAction = new ThdlAbstractAction("saveTranscript", null) { + public void theRealActionPerformed(ActionEvent e) { getSave(); } }; @@ -282,6 +290,7 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene pos = doc.createPosition(tp.getCaretPosition()-1); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } public void setTime(Integer t) { @@ -315,6 +324,7 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene dge.startDrag(null, transferable, this); } catch (InvalidDnDOperationException idoe) { idoe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } public void dragEnter(DragSourceDragEvent dsde) { @@ -332,6 +342,7 @@ class TimePoint extends JLabel implements DragGestureListener, DragSourceListene doc.remove(pos.getOffset(), 1); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } } @@ -400,9 +411,11 @@ public class TimePointDropTarget implements DropTargetListener { new TimePoint(pane, clockIcon, time); } catch (UnsupportedFlavorException ufe) { ufe.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } return true; @@ -423,8 +436,8 @@ class TimeCodeManager extends JPanel { inPanel.add(inButton); inPanel.add(inSpinner); - inButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + inButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { int k = player.when(); if (k != -1) setInTime(k); @@ -441,8 +454,8 @@ class TimeCodeManager extends JPanel { outPanel.add(outButton); outPanel.add(outSpinner); - outButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + outButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { int k = player.when(); if (k != -1) { setOutTime(k); @@ -453,8 +466,8 @@ class TimeCodeManager extends JPanel { JButton playSegButton = new JButton(messages.getString("PlaySegment")); - playSegButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + playSegButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { Integer in = getInTime(); Integer out = getOutTime(); if (out.intValue() > in.intValue()) @@ -468,14 +481,14 @@ class TimeCodeManager extends JPanel { JButton playButton = new JButton(messages.getString("Play")); JButton pauseButton = new JButton(messages.getString("Pause")); - playButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + playButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { if (player != null) player.cmd_play(); } }); - pauseButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + pauseButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { if (player != null) player.cmd_stop(); } @@ -593,6 +606,7 @@ public void setMedia(File f) { startTimer(); } catch (MalformedURLException murle) { murle.printStackTrace(); + ThdlDebug.noteIffyCode(); } } } @@ -696,7 +710,7 @@ public boolean getSave() { fileChooser.setSelectedFile(null); else { String path = project.getMedia().getPath(); - path = path.substring(0, path.lastIndexOf('.')) + ".xml"; + path = path.substring(0, path.lastIndexOf('.')) + QD.dotQuillDriver; fileChooser.setSelectedFile(new File(path)); } if (fileChooser.showSaveDialog(QD.this) == JFileChooser.APPROVE_OPTION) { @@ -838,12 +852,15 @@ if (keyboard_url != null) { return true; } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } catch (TransformerException e) { e.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } } @@ -950,6 +967,7 @@ if (keyboard_url != null) { tDoc.insertString(tDoc.getLength(), "\n", null); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } */ new TimePoint(dp, clockIcon, Integer.valueOf(e.getAttributeValue("t"))); @@ -961,6 +979,7 @@ if (keyboard_url != null) { tDoc.insertString(tDoc.getLength(), "\n", null); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } */ dp.insertComponent(new JLabel(" ", icons[Integer.parseInt(e.getAttributeValue("id"))], SwingConstants.LEFT)); @@ -984,6 +1003,7 @@ project.setTranscript(t); return true; } catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); return false; } } @@ -999,8 +1019,8 @@ SpeakerManager(final SpeakerTable sTable) { setLayout(new BorderLayout()); JButton addButton = new JButton(messages.getString("Add")); - addButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + addButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { SpeakerData sd = (SpeakerData)sTable.getModel(); JPanel p0 = new JPanel(new GridLayout(0,1)); JPanel p1 = new JPanel(); @@ -1021,8 +1041,8 @@ SpeakerManager(final SpeakerTable sTable) { } }); JButton editButton = new JButton(messages.getString("Edit")); - editButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + editButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { int row = sTable.getSelectedRow(); if (row == -1) return; @@ -1062,6 +1082,7 @@ SpeakerManager(final SpeakerTable sTable) { doc2.remove(i,1); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } pane.setCaretPosition(i); pane.insertComponent(new JLabel(" ", icons[combo.getSelectedIndex()], SwingConstants.LEFT)); @@ -1075,8 +1096,8 @@ SpeakerManager(final SpeakerTable sTable) { } }); JButton deleteButton = new JButton(messages.getString("Remove")); - deleteButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + deleteButton.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { int row = sTable.getSelectedRow(); if (row > -1 && JOptionPane.showConfirmDialog(SpeakerManager.this, messages.getString("SureDeleteSpeaker"), messages.getString("Warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { SpeakerData sd = (SpeakerData)sTable.getModel(); @@ -1096,6 +1117,7 @@ SpeakerManager(final SpeakerTable sTable) { k2--; } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } } @@ -1187,8 +1209,8 @@ class SpeakerData extends AbstractTableModel for (int k=0; k + + + + + +Provides facilitates for authoring content to be used by Savant. +

+In the future, this may be combined with Savant, in which case this +will be the edit mode. For now, QuillDriver is a stand-alone +application. +

+

Related Documentation

+@see org.thdl.savant + + diff --git a/source/org/thdl/savant/JdkVersionHacks.java b/source/org/thdl/savant/JdkVersionHacks.java index 5ae18f1..f599f8f 100644 --- a/source/org/thdl/savant/JdkVersionHacks.java +++ b/source/org/thdl/savant/JdkVersionHacks.java @@ -22,6 +22,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Field; +import java.awt.Dimension; import java.awt.Frame; import java.awt.Toolkit; @@ -49,7 +50,7 @@ import org.thdl.util.ThdlLazyException; * deconstruct the mechanism. * * This class is not instantiable. */ -final class JdkVersionHacks { +public final class JdkVersionHacks { /** Don't instantiate this class. */ private JdkVersionHacks() { } @@ -182,14 +183,33 @@ final class JdkVersionHacks { } } + public static Object getJSpinner(Dimension dim, + Object spinnerValue, + int value, int minimum, + int maximum, int stepSize) { + /* In Java 1.4, do the following: + + SpinnerNumberModel snm1 + = new SpinnerNumberModel(value, minimum, maximum, stepSize); + JSpinner spinner = new JSpinner(snm1); + spinner.setPreferredSize(dim); + spinner.setValue(spinnerValue); + return spinner; + */ + /* FIXME; */ + return null; + } + + + /** Coming soon: Does what the user desires (via the options he or - she has set) with this SecurityException, one encountered - during the process of reflection. + she has set) with this SecurityException, one encountered + during the process of reflection. - Currently: does nothing. + Currently: does nothing. - FIXME */ + FIXME */ private static void handleSecurityException(SecurityException ex) throws SecurityException { @@ -198,10 +218,10 @@ final class JdkVersionHacks { } /** Returns the value of Frame.MAXIMIZED_BOTH, wrapped in an - Integer. + Integer. - @throws NoSuchFieldException the field does not exist or - cannot be accessed because security settings are too limiting */ + @throws NoSuchFieldException the field does not exist or + cannot be accessed because security settings are too limiting */ private static Object maximizedBothOption() throws NoSuchFieldException { @@ -209,7 +229,7 @@ final class JdkVersionHacks { try { maxBothOptionField = Frame.class.getField("MAXIMIZED_BOTH"); - /* Don't catch NoSuchFieldException */ + /* Don't catch NoSuchFieldException */ } catch (SecurityException ex) { /* We'll never know if we're using JDK 1.4 or later. */ handleSecurityException(ex); @@ -229,3 +249,4 @@ final class JdkVersionHacks { } } }; + diff --git a/source/org/thdl/savant/Savant.java b/source/org/thdl/savant/Savant.java index 1f9094b..d821b96 100644 --- a/source/org/thdl/savant/Savant.java +++ b/source/org/thdl/savant/Savant.java @@ -59,6 +59,9 @@ import javax.swing.*; import javax.swing.text.*; import javax.swing.text.rtf.RTFEditorKit; +import org.thdl.util.ThdlDebug; +import org.thdl.util.ThdlActionListener; + public class Savant extends JDesktopPane { protected SoundPanel sp = null; @@ -142,6 +145,7 @@ public class Savant extends JDesktopPane open(views, new URL(video), new URL(vocabulary)); } catch (MalformedURLException murle) { murle.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -159,8 +163,8 @@ public class Savant extends JDesktopPane viewNames[i] = new String(views[i].getTitle()); JComboBox viewOptions = new JComboBox(viewNames); - viewOptions.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) + viewOptions.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { JComboBox jcb = (JComboBox)e.getSource(); setTranscriptView(views[jcb.getSelectedIndex()]); @@ -201,8 +205,10 @@ public class Savant extends JDesktopPane vocabPane.getCaret().setDot(0); } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } vocabFrame = new JInternalFrame("About the Video", false, false, false, true); vocabFrame.setContentPane(vocabPanel); diff --git a/source/org/thdl/savant/SavantFileView.java b/source/org/thdl/savant/SavantFileView.java index 9d8d0da..3e41a9c 100644 --- a/source/org/thdl/savant/SavantFileView.java +++ b/source/org/thdl/savant/SavantFileView.java @@ -23,30 +23,85 @@ import java.util.*; import javax.swing.*; import javax.swing.filechooser.*; +import org.thdl.util.ThdlDebug; + +/** + * The SavantFileView "sees through" a *.savant file and + * returns the title associated with it. A *.savant file + * is a properties file like the following: + *
+ * #Tue May 14 16:07:15 EDT 2002
+ * TRANSCRIPT=MST4.xml
+ * PROJECT=THDL
+ * MEDIA=MST4.mpg
+ * TITLE=MST Chapter 4 (video)
+ * 
+ * @author Edward Garrett */ public class SavantFileView extends FileView { + /** When opening a file, this is the only extension Savant cares + about. This is case-insensitive. */ + public final static String dotSavant = ".savant"; + + /** This loads *.savant files as properties files and + returns an associated TITLE attribute. For any other type of + file, or for a properties file that does not specify a + non-empty-string TITLE attribute, this returns null. */ public String getName(File f) { if (f.isDirectory()) return null; + + /* Unless a developer has chosen to do otherwise, examine only + *.savant files. If you don't do this, you waste a lot of + time, making any file chooser that uses this class + unresponsive. In addition, you'll cause the floppy drive + to spin up every time you refresh or cd in the file + chooser. */ + if (!Boolean.getBoolean("THDL_TREAT_ALL_FILES_AS_DOT_SAVANT_FILES_REGARDLESS_OF_EXTENSION")) { /* FIXME */ + if (!f.getName().toLowerCase().endsWith(dotSavant)) + return null; + } Properties p = new Properties(); try { p.load(new FileInputStream(f)); - return p.getProperty("TITLE"); + String ttl = p.getProperty("TITLE"); + if (ttl.equals("")) + return null; /* We never want the user to see nothing + at all, so let the L&F file view + handle this. */ + else + return ttl; } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); } return null; } + + /** Returns null always, which lets the default look-and-feel's + * FileView take over. + * @return null */ public String getDescription(File f) { - return null; + return null; // let the L&F FileView figure this out } + + /** Returns null always, which lets the default look-and-feel's + * FileView take over. + * @return null */ public Boolean isTraversable(File f) { return null; // let the L&F FileView figure this out } + + /** Returns null always, which lets the default look-and-feel's + * FileView take over. + * @return null */ public String getTypeDescription(File f) { - return null; + return null; // let the L&F FileView figure this out } + + /* FIXME: why not same as above? */ /* public Icon getIcon(File f) { } diff --git a/source/org/thdl/savant/SavantShell.java b/source/org/thdl/savant/SavantShell.java index b6aa1ae..228b7b0 100644 --- a/source/org/thdl/savant/SavantShell.java +++ b/source/org/thdl/savant/SavantShell.java @@ -30,6 +30,8 @@ import javax.swing.text.rtf.*; import org.thdl.savant.ucuchi.*; import org.thdl.savant.tib.*; import org.thdl.util.TeeStream; +import org.thdl.util.ThdlDebug; +import org.thdl.util.ThdlActionListener; public class SavantShell extends JFrame { @@ -44,56 +46,49 @@ public class SavantShell extends JFrame public static void main(String[] args) { try { - PrintStream psOut - = new TeeStream(System.out, - new PrintStream(new FileOutputStream("savant.log"))); - PrintStream psErr - = new TeeStream(System.err, - new PrintStream(new FileOutputStream("savant.log"))); - System.setErr(psErr); - System.setOut(psOut); - } - catch (Exception e) { - } + ThdlDebug.attemptToSetUpLogFile("savant.log"); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception e) {} + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) {} - RTFEditorKit rtf = new RTFEditorKit(); - InputStream in1 = SavantShell.class.getResourceAsStream("savanthelp.rtf"); - InputStream in2 = SavantShell.class.getResourceAsStream("aboutsavant.rtf"); - if (in1 == null) { - System.out.println("Can't find savanthelp.rtf."); - System.exit(1); + RTFEditorKit rtf = new RTFEditorKit(); + InputStream in1 = SavantShell.class.getResourceAsStream("savanthelp.rtf"); + InputStream in2 = SavantShell.class.getResourceAsStream("aboutsavant.rtf"); + if (in1 == null) { + System.out.println("Can't find savanthelp.rtf."); + System.exit(1); + } + if (in2 == null) { + System.out.println("Can't find aboutsavant.rtf."); + System.exit(1); + } + DefaultStyledDocument doc1 = new DefaultStyledDocument(); + DefaultStyledDocument doc2 = new DefaultStyledDocument(); + try { + rtf.read(in1, doc1, 0); + rtf.read(in2, doc2, 0); + } catch (BadLocationException ioe) { + return; + } catch (IOException ioe) { + System.out.println("Can't find one of savanthelp.rtf or aboutsavant.rtf."); + System.exit(1); + } + + JTextPane pane1 = new JTextPane(doc1); + JTextPane pane2 = new JTextPane(doc2); + pane1.setEditable(false); + pane2.setEditable(false); + + helpPane = new JScrollPane(pane1); + aboutPane = new JScrollPane(pane2); + + SavantShell ssh = new SavantShell(); + ssh.setVisible(true); + ssh.initFileChooser(); + } catch (NoClassDefFoundError err) { + ThdlDebug.handleClasspathError("Savant's CLASSPATH", err); } - if (in2 == null) { - System.out.println("Can't find aboutsavant.rtf."); - System.exit(1); - } - DefaultStyledDocument doc1 = new DefaultStyledDocument(); - DefaultStyledDocument doc2 = new DefaultStyledDocument(); - try { - rtf.read(in1, doc1, 0); - rtf.read(in2, doc2, 0); - } catch (BadLocationException ioe) { - return; - } catch (IOException ioe) { - System.out.println("Can't find one of savanthelp.rtf or aboutsavant.rtf."); - System.exit(1); - } - - JTextPane pane1 = new JTextPane(doc1); - JTextPane pane2 = new JTextPane(doc2); - pane1.setEditable(false); - pane2.setEditable(false); - - helpPane = new JScrollPane(pane1); - aboutPane = new JScrollPane(pane2); - - SavantShell ssh = new SavantShell(); - ssh.setVisible(true); - ssh.initFileChooser(); } public void initFileChooser() { @@ -114,21 +109,7 @@ public class SavantShell extends JFrame if (f.isDirectory()) { return true; } - - String fName = f.getName(); - int i = fName.lastIndexOf('.'); - - if (i < 0) - return false; - - else { - String ext = fName.substring(i+1).toLowerCase(); - - if (ext.equals("savant")) - return true; - else - return false; - } + return f.getName().toLowerCase().endsWith(SavantFileView.dotSavant); } //the description of this filter @@ -137,6 +118,33 @@ public class SavantShell extends JFrame } } + /** Closes one open title, if there is one open. Returns true if + one was closed, or false if no titles are open. */ + private boolean closeOneSavantTitle() { + if (savant != null) { + ThdlDebug.verify("There should be one or more Savant titles open: ", + numberOfSavantsOpen >= 1); + if (numberOfSavantsOpen < 2) { + savant.close(); + savant = null; + getContentPane().removeAll(); + setTitle("Savant"); + invalidate(); + validate(); + repaint(); + } else { + savant.close(); + dispose(); + } + numberOfSavantsOpen--; + return true; + } else { + ThdlDebug.verify("There should be zero Savant titles open: ", + numberOfSavantsOpen == 0); + return false; + } + } + public SavantShell() { setTitle("Savant"); @@ -146,8 +154,8 @@ public class SavantShell extends JFrame JMenuItem openItem = new JMenuItem("Open"); openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,2)); - openItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + openItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { if (fileChooser.showOpenDialog(SavantShell.this) != JFileChooser.APPROVE_OPTION) return; Properties p = new Properties(); @@ -158,48 +166,66 @@ public class SavantShell extends JFrame newSavantWindow(p.getProperty("PROJECT"), p.getProperty("TITLE"), new URL(path + p.getProperty("TRANSCRIPT")), new URL(path + p.getProperty("MEDIA")), null); } catch (MalformedURLException murle) { murle.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } }); JMenuItem closeItem = new JMenuItem("Close"); closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,2)); - closeItem.addActionListener(new ActionListener() + closeItem.addActionListener(new ThdlActionListener() { - public void actionPerformed(ActionEvent e) + public void theRealActionPerformed(ActionEvent e) { - if (savant != null) - { - if (numberOfSavantsOpen < 2) - { - savant.close(); - savant = null; - getContentPane().removeAll(); - setTitle("Savant"); - invalidate(); - validate(); - repaint(); - } else { - savant.close(); - dispose(); - } - numberOfSavantsOpen--; - } + // Return value doesn't matter: + closeOneSavantTitle(); + } + }); + + JMenuItem quitItem = new JMenuItem("Quit"); + quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,2)); + quitItem.addActionListener(new ThdlActionListener() + { + public void theRealActionPerformed(ActionEvent e) + { + // Close all Savant titles: + while (closeOneSavantTitle()) + ; + + // Exit normally: + System.exit(0); } }); + /* Hey developers: To test ThdlActionListener, use this: + + JMenuItem errorThrowerItem = new JMenuItem("ErrorThrower"); + errorThrowerItem.addActionListener(new ThdlActionListener() + { + public void theRealActionPerformed(ActionEvent e) + { + throw new Error("Testing ThdlActionListener"); + } + }); + fileMenu.add(errorThrowerItem); + */ + fileMenu.add(openItem); fileMenu.add(closeItem); + fileMenu.addSeparator(); + fileMenu.add(quitItem); JMenu infoMenu = new JMenu("Information"); JMenuItem helpItem = new JMenuItem("Help"); - helpItem.addActionListener(new ActionListener() + helpItem.addActionListener(new ThdlActionListener() { - public void actionPerformed(ActionEvent e) + public void theRealActionPerformed(ActionEvent e) { JFrame h = new JFrame("Help"); h.setSize(500,400); @@ -218,9 +244,9 @@ public class SavantShell extends JFrame } }); JMenuItem aboutItem = new JMenuItem("About"); - aboutItem.addActionListener(new ActionListener() + aboutItem.addActionListener(new ThdlActionListener() { - public void actionPerformed(ActionEvent e) + public void theRealActionPerformed(ActionEvent e) { JFrame h = new JFrame("About"); h.setSize(500,400); @@ -286,15 +312,19 @@ public class SavantShell extends JFrame public void newSavantWindow(String project, String titleName, URL trn, URL vid, URL abt) { - if (numberOfSavantsOpen == 0) - openSavant(project, titleName, trn, vid, abt); - else { - SavantShell scp = new SavantShell(); - scp.setVisible(true); - scp.openSavant(project, titleName, trn, vid, abt); - scp.setFileChooser(fileChooser); + try { + if (numberOfSavantsOpen == 0) + openSavant(project, titleName, trn, vid, abt); + else { + SavantShell scp = new SavantShell(); + scp.setVisible(true); + scp.openSavant(project, titleName, trn, vid, abt); + scp.setFileChooser(fileChooser); + } + numberOfSavantsOpen++; + } catch (NoClassDefFoundError err) { + ThdlDebug.handleClasspathError("Savant's CLASSPATH", err); } - numberOfSavantsOpen++; } public void openSavant(String project, String titleName, URL trn, URL vid, URL abt) diff --git a/source/org/thdl/savant/SoundPanel.java b/source/org/thdl/savant/SoundPanel.java index 76634d0..fb8bfc6 100644 --- a/source/org/thdl/savant/SoundPanel.java +++ b/source/org/thdl/savant/SoundPanel.java @@ -26,6 +26,8 @@ import java.awt.*; import javax.swing.*; import javax.swing.event.*; +import org.thdl.util.ThdlDebug; + /*-----------------------------------------------------------------------*/ public class SoundPanel extends Panel implements ControllerListener { @@ -346,10 +348,12 @@ System.out.println("soundpanel - "+sound.toString()); } catch (javax.media.NoPlayerException e) { System.err.println("noplayer exception"); e.printStackTrace(); + ThdlDebug.noteIffyCode(); return; } catch (java.io.IOException ex) { System.err.println("IO exception"); ex.printStackTrace(); + ThdlDebug.noteIffyCode(); return; } if (player != null) diff --git a/source/org/thdl/savant/TextHighlightPlayer.java b/source/org/thdl/savant/TextHighlightPlayer.java index 54a4053..87c0452 100644 --- a/source/org/thdl/savant/TextHighlightPlayer.java +++ b/source/org/thdl/savant/TextHighlightPlayer.java @@ -24,6 +24,8 @@ import javax.swing.*; import javax.swing.text.*; import java.awt.event.MouseListener; +import org.thdl.util.ThdlDebug; + public class TextHighlightPlayer extends JPanel implements AnnotationPlayer { protected JTextComponent text; @@ -108,6 +110,7 @@ public class TextHighlightPlayer extends JPanel implements AnnotationPlayer catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/TextPlayer.java b/source/org/thdl/savant/TextPlayer.java index 849122b..dbac382 100644 --- a/source/org/thdl/savant/TextPlayer.java +++ b/source/org/thdl/savant/TextPlayer.java @@ -23,6 +23,8 @@ import java.util.*; import javax.swing.*; import javax.swing.text.*; +import org.thdl.util.ThdlDebug; + public class TextPlayer extends JPanel implements AnnotationPlayer { private JTextComponent text; @@ -97,6 +99,7 @@ public class TextPlayer extends JPanel implements AnnotationPlayer catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/TwoWayTextPlayer.java b/source/org/thdl/savant/TwoWayTextPlayer.java index 014c294..f73cc18 100644 --- a/source/org/thdl/savant/TwoWayTextPlayer.java +++ b/source/org/thdl/savant/TwoWayTextPlayer.java @@ -30,6 +30,8 @@ import java.util.Enumeration; import java.util.NoSuchElementException; import javax.swing.text.JTextComponent; +import org.thdl.util.ThdlDebug; + public class TwoWayTextPlayer extends TextHighlightPlayer { protected TreeMap orderedOffsets = null; @@ -106,6 +108,7 @@ public class TwoWayTextPlayer extends TextHighlightPlayer catch (NoSuchElementException nsee) { nsee.printStackTrace(); + ThdlDebug.noteIffyCode(); } } }); diff --git a/source/org/thdl/savant/package.html b/source/org/thdl/savant/package.html new file mode 100644 index 0000000..02f8920 --- /dev/null +++ b/source/org/thdl/savant/package.html @@ -0,0 +1,24 @@ + + + + + + +Provides classes and methods for displaying foreign-language text, +audio, and video side-by-side. +

+Savant works for only a couple of languages right now, but can +be extended to work with many more. + + diff --git a/source/org/thdl/savant/tib/English.java b/source/org/thdl/savant/tib/English.java index 0dda0ed..71c0a44 100644 --- a/source/org/thdl/savant/tib/English.java +++ b/source/org/thdl/savant/tib/English.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class English implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class English implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -174,6 +177,7 @@ public class English implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/Tibetan.java b/source/org/thdl/savant/tib/Tibetan.java index 74cd0b7..0929a15 100644 --- a/source/org/thdl/savant/tib/Tibetan.java +++ b/source/org/thdl/savant/tib/Tibetan.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class Tibetan implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class Tibetan implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -179,10 +182,12 @@ public class Tibetan implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (InvalidWylieException iwe) { iwe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/TibetanEnglish.java b/source/org/thdl/savant/tib/TibetanEnglish.java index 4e4414b..0579f63 100644 --- a/source/org/thdl/savant/tib/TibetanEnglish.java +++ b/source/org/thdl/savant/tib/TibetanEnglish.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class TibetanEnglish implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class TibetanEnglish implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -187,10 +190,12 @@ public class TibetanEnglish implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (InvalidWylieException iwe) { iwe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/TibetanWylie.java b/source/org/thdl/savant/tib/TibetanWylie.java index fd6f1b9..c3dfa45 100644 --- a/source/org/thdl/savant/tib/TibetanWylie.java +++ b/source/org/thdl/savant/tib/TibetanWylie.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class TibetanWylie implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class TibetanWylie implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -190,10 +193,12 @@ public class TibetanWylie implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (InvalidWylieException iwe) { iwe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/TibetanWylieEnglish.java b/source/org/thdl/savant/tib/TibetanWylieEnglish.java index 4caa621..4a73a6b 100644 --- a/source/org/thdl/savant/tib/TibetanWylieEnglish.java +++ b/source/org/thdl/savant/tib/TibetanWylieEnglish.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class TibetanWylieEnglish implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class TibetanWylieEnglish implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -192,10 +195,12 @@ public class TibetanWylieEnglish implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (InvalidWylieException iwe) { iwe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/Wylie.java b/source/org/thdl/savant/tib/Wylie.java index 5b9a189..58e9e39 100644 --- a/source/org/thdl/savant/tib/Wylie.java +++ b/source/org/thdl/savant/tib/Wylie.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class Wylie implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class Wylie implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -174,6 +177,7 @@ public class Wylie implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/WylieEnglish.java b/source/org/thdl/savant/tib/WylieEnglish.java index 36c2229..4568fce 100644 --- a/source/org/thdl/savant/tib/WylieEnglish.java +++ b/source/org/thdl/savant/tib/WylieEnglish.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import org.thdl.tib.input.*; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class WylieEnglish implements TranscriptView { private JTextPane text = null; @@ -60,6 +62,7 @@ public class WylieEnglish implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -187,6 +190,7 @@ public class WylieEnglish implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/tib/package.html b/source/org/thdl/savant/tib/package.html new file mode 100644 index 0000000..4a95b9d --- /dev/null +++ b/source/org/thdl/savant/tib/package.html @@ -0,0 +1,23 @@ + + + + + + +Provides Savant with the power to display Tibetan language +text beside video or audio of Tibetan speakers. +

+Supports Wylie, English, and Tibetan. + + diff --git a/source/org/thdl/savant/ucuchi/All.java b/source/org/thdl/savant/ucuchi/All.java index c17768c..e8b8a83 100644 --- a/source/org/thdl/savant/ucuchi/All.java +++ b/source/org/thdl/savant/ucuchi/All.java @@ -29,6 +29,8 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class All implements TranscriptView { private JTextPane text = null; @@ -57,6 +59,7 @@ public class All implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -203,6 +206,7 @@ public class All implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/ucuchi/English.java b/source/org/thdl/savant/ucuchi/English.java index 5825369..3dc3fe9 100644 --- a/source/org/thdl/savant/ucuchi/English.java +++ b/source/org/thdl/savant/ucuchi/English.java @@ -29,6 +29,8 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class English implements TranscriptView { private JTextPane text = null; @@ -57,6 +59,7 @@ public class English implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -174,6 +177,7 @@ public class English implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/ucuchi/Quechua.java b/source/org/thdl/savant/ucuchi/Quechua.java index 0a3cb18..d54706c 100644 --- a/source/org/thdl/savant/ucuchi/Quechua.java +++ b/source/org/thdl/savant/ucuchi/Quechua.java @@ -29,6 +29,8 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class Quechua implements TranscriptView { private JTextPane text = null; @@ -57,6 +59,7 @@ public class Quechua implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -173,6 +176,7 @@ public class Quechua implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/ucuchi/QuechuaEnglish.java b/source/org/thdl/savant/ucuchi/QuechuaEnglish.java index c1191bc..9dddd0e 100644 --- a/source/org/thdl/savant/ucuchi/QuechuaEnglish.java +++ b/source/org/thdl/savant/ucuchi/QuechuaEnglish.java @@ -29,6 +29,8 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class QuechuaEnglish implements TranscriptView { private JTextPane text = null; @@ -57,6 +59,7 @@ public class QuechuaEnglish implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -195,6 +198,7 @@ public class QuechuaEnglish implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/ucuchi/SegmentedQuechua.java b/source/org/thdl/savant/ucuchi/SegmentedQuechua.java index cdaa07b..97c3f40 100644 --- a/source/org/thdl/savant/ucuchi/SegmentedQuechua.java +++ b/source/org/thdl/savant/ucuchi/SegmentedQuechua.java @@ -30,6 +30,8 @@ import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.thdl.savant.*; +import org.thdl.util.ThdlDebug; + public class SegmentedQuechua implements TranscriptView { private JTextPane text = null; @@ -58,6 +60,7 @@ public class SegmentedQuechua implements TranscriptView catch (JDOMException jdome) { jdome.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -195,6 +198,7 @@ public class SegmentedQuechua implements TranscriptView catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/savant/ucuchi/package.html b/source/org/thdl/savant/ucuchi/package.html new file mode 100644 index 0000000..243f12b --- /dev/null +++ b/source/org/thdl/savant/ucuchi/package.html @@ -0,0 +1,23 @@ + + + + + + +Provides Savant with the power to display Quechua language +text beside video or audio of Quechua speakers. +

+Supports Quechua and English. + + diff --git a/source/org/thdl/tib/input/DuffPane.java b/source/org/thdl/tib/input/DuffPane.java index 60a367b..c55b6cc 100644 --- a/source/org/thdl/tib/input/DuffPane.java +++ b/source/org/thdl/tib/input/DuffPane.java @@ -32,6 +32,8 @@ import org.thdl.tib.text.*; import java.io.*; import javax.swing.text.rtf.*; +import org.thdl.util.ThdlDebug; + /** * Enables input of Tibetan text * using Tibetan Computer Company's free cross-platform TibetanMachineWeb fonts. @@ -764,6 +766,7 @@ class RTFSelection implements ClipboardOwner, Transferable { newDoc.insertString(i-offset, s, as); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } rtfOut = new ByteArrayOutputStream(); @@ -771,8 +774,10 @@ class RTFSelection implements ClipboardOwner, Transferable { plainText = getText(offset, length); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); } } public void lostOwnership(Clipboard clipboard, Transferable contents) { @@ -816,6 +821,7 @@ class RTFSelection implements ClipboardOwner, Transferable { rtfBoard.setContents(rtfSelection, rtfSelection); } catch (IllegalStateException ise) { ise.printStackTrace(); + ThdlDebug.noteIffyCode(); } } if (remove) @@ -823,6 +829,7 @@ class RTFSelection implements ClipboardOwner, Transferable { getDocument().remove(p1, p2-p1); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -853,6 +860,7 @@ public void paste(int offset) { doc.insertString(p1+i, s, as); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } } else if (contents.isDataFlavorSupported(DataFlavor.stringFlavor)) { @@ -861,12 +869,16 @@ public void paste(int offset) { } } catch (UnsupportedFlavorException ufe) { ufe.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (IOException ioe) { ioe.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (IllegalStateException ise) { ise.printStackTrace(); + ThdlDebug.noteIffyCode(); } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -1347,6 +1359,7 @@ public void paste(int offset) { } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } @@ -1368,6 +1381,7 @@ public void paste(int offset) { offset++; } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } else { TibetanDocument.DuffData[] dd = TibetanDocument.getTibetanMachineWeb(next); @@ -1444,6 +1458,7 @@ public void paste(int offset) { } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } } diff --git a/source/org/thdl/tib/input/Jskad.java b/source/org/thdl/tib/input/Jskad.java index 92e4ca6..53cfe50 100644 --- a/source/org/thdl/tib/input/Jskad.java +++ b/source/org/thdl/tib/input/Jskad.java @@ -32,7 +32,9 @@ import javax.swing.text.*; import javax.swing.text.rtf.*; import org.thdl.tib.text.*; -import org.thdl.util.TeeStream; +import org.thdl.util.ThdlDebug; +import org.thdl.util.ThdlActionListener; + /** * A simple Tibetan text editor. Jskad editors lack most of the @@ -97,8 +99,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem newItem = new JMenuItem("New"); // newItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,2)); //Ctrl-n - newItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + newItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { newFile(); } }); @@ -106,8 +108,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem openItem = new JMenuItem("Open"); // openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,2)); //Ctrl-o - openItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + openItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { openFile(); } }); @@ -115,8 +117,8 @@ public class Jskad extends JPanel implements DocumentListener { if (parentObject instanceof JFrame) { JMenuItem closeItem = new JMenuItem("Close"); - closeItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + closeItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { if (!hasChanged || hasChanged && checkSave()) { numberOfTibsRTFOpen--; @@ -134,8 +136,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem saveItem = new JMenuItem("Save"); // saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,2)); //Ctrl-s - saveItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + saveItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { if (fileName == null) saveAsFile(); else @@ -147,8 +149,8 @@ public class Jskad extends JPanel implements DocumentListener { fileMenu.add(saveItem); JMenuItem saveAsItem = new JMenuItem("Save as"); - saveAsItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + saveAsItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { saveAsFile(); } }); @@ -162,8 +164,8 @@ public class Jskad extends JPanel implements DocumentListener { if (parentObject instanceof JFrame || parentObject instanceof JInternalFrame) { JMenuItem cutItem = new JMenuItem("Cut"); cutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,2)); //Ctrl-x - cutItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + cutItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { cutSelection(); } }); @@ -171,8 +173,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem copyItem = new JMenuItem("Copy"); copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,2)); //Ctrl-c - copyItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + copyItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { copySelection(); } }); @@ -180,8 +182,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem pasteItem = new JMenuItem("Paste"); pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,2)); //Ctrl-v - pasteItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + pasteItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { pasteSelection(); } }); @@ -190,8 +192,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenuItem selectallItem = new JMenuItem("Select All"); selectallItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,2)); //Ctrl-a - selectallItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + selectallItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { dp.setSelectionStart(0); dp.setSelectionEnd(dp.getDocument().getLength()); } @@ -200,8 +202,8 @@ public class Jskad extends JPanel implements DocumentListener { } JMenuItem preferencesItem = new JMenuItem("Preferences"); - preferencesItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + preferencesItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { getPreferences(); } }); @@ -213,16 +215,16 @@ public class Jskad extends JPanel implements DocumentListener { JMenu toolsMenu = new JMenu("Tools"); JMenuItem TMWWylieItem = new JMenuItem("Convert Tibetan to Wylie"); - TMWWylieItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + TMWWylieItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { toWylie(); } }); toolsMenu.add(TMWWylieItem); JMenuItem wylieTMWItem = new JMenuItem("Convert Wylie to Tibetan"); - wylieTMWItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + wylieTMWItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { toTibetan(); } }); @@ -230,8 +232,8 @@ public class Jskad extends JPanel implements DocumentListener { if (parentObject instanceof JFrame || parentObject instanceof JInternalFrame) { JMenuItem importItem = new JMenuItem("Import Wylie as Tibetan"); - importItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + importItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { importWylie(); } }); @@ -244,8 +246,8 @@ public class Jskad extends JPanel implements DocumentListener { JMenu infoMenu = new JMenu("Info"); JMenuItem aboutItem = new JMenuItem("About"); - aboutItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + aboutItem.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(Jskad.this, "Copyright 2001 Tibetan and Himalayan Digital Library\n"+ "Programmed by Edward Garrett\n\n"+ @@ -275,8 +277,8 @@ public class Jskad extends JPanel implements DocumentListener { String[] input_modes = {"Tibetan","Roman"}; final JComboBox inputmethods = new JComboBox(input_modes); - inputmethods.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + inputmethods.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { switch (inputmethods.getSelectedIndex()) { case 0: //Tibetan if (dp.isRomanMode()) @@ -300,8 +302,8 @@ public class Jskad extends JPanel implements DocumentListener { String[] keyboard_options = {"Extended Wylie","TCC Keyboard #1","TCC Keyboard #2","Sambhota Keymap One"}; final JComboBox keyboards = new JComboBox(keyboard_options); - keyboards.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + keyboards.addActionListener(new ThdlActionListener() { + public void theRealActionPerformed(ActionEvent e) { switch (keyboards.getSelectedIndex()) { case 0: //Extended Wylie installKeyboard("wylie"); @@ -599,9 +601,11 @@ public class Jskad extends JPanel implements DocumentListener { hasChanged = false; } catch (IOException exception) { exception.printStackTrace(); + ThdlDebug.noteIffyCode(); return null; } catch (BadLocationException ble) { ble.printStackTrace(); + ThdlDebug.noteIffyCode(); } return f_name; } @@ -899,26 +903,12 @@ public class Jskad extends JPanel implements DocumentListener { } /** -* Runs Jskad. -* System output, including errors, is redirected to jskad.log. -* If you discover a bug, please send us an email, making sure -* to include the jskad.log file as an attachment. -*/ +* Runs Jskad. System output, including errors, is redirected to +* jskad.log in addition to appearing on the console as per usual. If +* you discover a bug, please send us an email, making sure to include +* the jskad.log file as an attachment. */ public static void main(String[] args) { - - try { - PrintStream psOut - = new TeeStream(System.out, - new PrintStream(new FileOutputStream("jskad.log"))); - PrintStream psErr - = new TeeStream(System.err, - new PrintStream(new FileOutputStream("jskad.log"))); - System.setErr(psErr); - System.setOut(psOut); - } - catch (Exception e) { - } - + ThdlDebug.attemptToSetUpLogFile("jskad.log"); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); diff --git a/source/org/thdl/tib/input/Jskad2JavaScript.java b/source/org/thdl/tib/input/Jskad2JavaScript.java index d98e373..7b2f01b 100644 --- a/source/org/thdl/tib/input/Jskad2JavaScript.java +++ b/source/org/thdl/tib/input/Jskad2JavaScript.java @@ -22,9 +22,11 @@ import java.applet.Applet; import java.awt.*; import java.awt.event.*; import javax.swing.*; -import org.thdl.tib.text.*; import netscape.javascript.JSObject; +import org.thdl.tib.text.*; +import org.thdl.util.ThdlActionListener; + /** * A version of Jskad which can be embedded into * a web page as an applet. It includes all of the functionality @@ -54,9 +56,9 @@ public class Jskad2JavaScript extends JApplet { jskad = new Jskad(this); panel.add("Center", jskad); JButton submit = new JButton("Submit"); - submit.addActionListener(new ActionListener() + submit.addActionListener(new ThdlActionListener() { - public void actionPerformed(ActionEvent e) + public void theRealActionPerformed(ActionEvent e) { try { TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); diff --git a/source/org/thdl/tib/input/JskadConversionTool.java b/source/org/thdl/tib/input/JskadConversionTool.java index 96f0c71..37f133f 100644 --- a/source/org/thdl/tib/input/JskadConversionTool.java +++ b/source/org/thdl/tib/input/JskadConversionTool.java @@ -22,9 +22,11 @@ import java.applet.Applet; import java.awt.*; import java.awt.event.*; import javax.swing.*; -import org.thdl.tib.text.*; import netscape.javascript.JSObject; +import org.thdl.tib.text.*; +import org.thdl.util.ThdlActionListener; + /** * A version of Jskad which can be embedded into * a web page as an applet. It includes all of the functionality @@ -54,9 +56,9 @@ public class JskadConversionTool extends JApplet { jskad = new Jskad(this); panel.add("Center", jskad); JButton submit = new JButton("Submit"); - submit.addActionListener(new ActionListener() + submit.addActionListener(new ThdlActionListener() { - public void actionPerformed(ActionEvent e) + public void theRealActionPerformed(ActionEvent e) { try { TibetanDocument t_doc = (TibetanDocument)jskad.dp.getDocument(); diff --git a/source/org/thdl/tib/input/package.html b/source/org/thdl/tib/input/package.html index b19eba2..3b0ff6b 100644 --- a/source/org/thdl/tib/input/package.html +++ b/source/org/thdl/tib/input/package.html @@ -1,35 +1,35 @@ - - - - - - -Provides classes and methods for inputting Tibetan text. -

-Designed for use with the Tibetan Computer -Company's free cross-platform TibetanMachineWeb fonts, this package -contains methods for inputting Tibetan using various keyboard -input methods, including true Wylie-based input, as well as -user-defined keyboards. -

-The package includes a simple Tibetan text editor, Jskad, -which can be run as an local application or embedded in a -web page. Jskad supports a wide range of functions, including -conversion back and forth between TibetanMachineWeb and -Extended Wylie. -

-

Related Documentation

-@see org.thdl.tib.text - - + + + + + + +Provides classes and methods for inputting Tibetan text. +

+Designed for use with the Tibetan Computer +Company's free cross-platform TibetanMachineWeb fonts, this package +contains methods for inputting Tibetan using various keyboard +input methods, including true Wylie-based input, as well as +user-defined keyboards. +

+The package includes a simple Tibetan text editor, Jskad, +which can be run as an local application or embedded in a +web page. Jskad supports a wide range of functions, including +conversion back and forth between TibetanMachineWeb and +Extended Wylie. +

+

Related Documentation

+@see org.thdl.tib.text + + diff --git a/source/org/thdl/tib/scanner/AboutDialog.java b/source/org/thdl/tib/scanner/AboutDialog.java index 6626b61..d125601 100644 --- a/source/org/thdl/tib/scanner/AboutDialog.java +++ b/source/org/thdl/tib/scanner/AboutDialog.java @@ -36,6 +36,9 @@ class AboutDialog extends Dialog implements ActionListener, WindowListener setSize(240,300); // the size ipaq's window. } + /* FIXME: what happens if this throws an exception? We'll just + see it on the console--it won't terminate the program. And the + user may not see the console! See ThdlActionListener. -DC */ public void actionPerformed(ActionEvent e) { hide(); @@ -116,4 +119,4 @@ class AboutDialog extends Dialog implements ActionListener, WindowListener public void windowOpened(WindowEvent e) { } -} \ No newline at end of file +} diff --git a/source/org/thdl/tib/scanner/AppletScannerFilter.java b/source/org/thdl/tib/scanner/AppletScannerFilter.java index 37a76ef..8249785 100644 --- a/source/org/thdl/tib/scanner/AppletScannerFilter.java +++ b/source/org/thdl/tib/scanner/AppletScannerFilter.java @@ -42,7 +42,7 @@ import org.thdl.tib.text.TibetanDocument; @author Andrés Montano Pellegrini @see RemoteScannerFilter - @see ScannerPannel + @see ScannerPanel */ public class AppletScannerFilter extends JApplet implements ActionListener, FocusListener, ItemListener { @@ -154,6 +154,9 @@ public class AppletScannerFilter extends JApplet implements ActionListener, Focu /* mnuEdit.setEnabled(false); objModified=null;*/ } + /* FIXME: what happens if this throws an exception? We'll just + see it on the console--it won't terminate the program. And the + user may not see the console! See ThdlActionListener. -DC */ public void actionPerformed(ActionEvent e) { Object clicked = e.getSource(); diff --git a/source/org/thdl/tib/scanner/DictionarySource.java b/source/org/thdl/tib/scanner/DictionarySource.java index 2c00c1a..1f5c3b3 100644 --- a/source/org/thdl/tib/scanner/DictionarySource.java +++ b/source/org/thdl/tib/scanner/DictionarySource.java @@ -28,7 +28,7 @@ public class DictionarySource { private int dicts; - /** Last bit of word. 1 if there are more brothers.*/ + /** Last bit of word; 1 if there are more brothers.*/ private static final int lastBit=32768; private static final int allDicts=lastBit-1; @@ -134,4 +134,4 @@ public class DictionarySource { dicts = 0; } -} \ No newline at end of file +} diff --git a/source/org/thdl/tib/scanner/FileSyllableListTree.java b/source/org/thdl/tib/scanner/FileSyllableListTree.java index 75a7728..6279b59 100644 --- a/source/org/thdl/tib/scanner/FileSyllableListTree.java +++ b/source/org/thdl/tib/scanner/FileSyllableListTree.java @@ -19,16 +19,16 @@ package org.thdl.tib.scanner; import java.io.*; -/** Searches the words directly in a file; not the prefered +/** Searches the words directly in a file; not the preferred implementation. The search is too slow! - The prefered implementation is the CachedSyllableList. + The preferred implementation is the CachedSyllableListTree.

The words must be stored in a binary file tree structure format. This can be done using the BinaryFileGenerator.

@author Andrés Montano Pellegrini @see TibetanScanner - @see CachedSyllableList + @see CachedSyllableListTree @see BinaryFileGenerator */ @@ -158,4 +158,4 @@ public class FileSyllableListTree implements SyllableListTree } return null; } -} \ No newline at end of file +} diff --git a/source/org/thdl/tib/scanner/ScannerPanel.java b/source/org/thdl/tib/scanner/ScannerPanel.java index f5801a0..7717c04 100644 --- a/source/org/thdl/tib/scanner/ScannerPanel.java +++ b/source/org/thdl/tib/scanner/ScannerPanel.java @@ -167,6 +167,9 @@ public abstract class ScannerPanel extends Panel implements ActionListener } } + /* FIXME: what happens if this throws an exception? We'll just + see it on the console--it won't terminate the program. And the + user may not see the console! See ThdlActionListener. -DC */ public void actionPerformed(ActionEvent e) { translate(); @@ -176,4 +179,4 @@ public abstract class ScannerPanel extends Panel implements ActionListener public abstract void clear(); public void setEnableTibetanScript(boolean enabled) {} public void addFocusListener(FocusListener fl) {} -} \ No newline at end of file +} diff --git a/source/org/thdl/tib/scanner/WindowScannerFilter.java b/source/org/thdl/tib/scanner/WindowScannerFilter.java index 6b243e4..44ba1f2 100644 --- a/source/org/thdl/tib/scanner/WindowScannerFilter.java +++ b/source/org/thdl/tib/scanner/WindowScannerFilter.java @@ -246,7 +246,10 @@ public class WindowScannerFilter implements WindowListener, FocusListener, Actio mnuDelete.setEnabled(false); mnuSelectAll.setEnabled(false); } - + + /* FIXME: what happens if this throws an exception? We'll just + see it on the console--it won't terminate the program. And the + user may not see the console! See ThdlActionListener. -DC */ public void actionPerformed(ActionEvent e) { Object clicked = e.getSource(); diff --git a/source/org/thdl/tib/scanner/package.html b/source/org/thdl/tib/scanner/package.html new file mode 100644 index 0000000..bf7b40e --- /dev/null +++ b/source/org/thdl/tib/scanner/package.html @@ -0,0 +1,21 @@ + + + + + + +Provides classes and methods for translating Tibetan text to English. +

+Right now, this package scans Tibetan text, but we aim to make it parse Tibetan text. +

+Author: Andrés Montano Pellegrini +

+

Related Documentation

+@see org.thdl.tib.text +@see org.thdl.tib.input + + diff --git a/source/org/thdl/tib/text/TibetanDocument.java b/source/org/thdl/tib/text/TibetanDocument.java index 94b274e..aaf1115 100644 --- a/source/org/thdl/tib/text/TibetanDocument.java +++ b/source/org/thdl/tib/text/TibetanDocument.java @@ -1,1264 +1,1295 @@ -/* -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.tib.text; - -import java.util.*; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.text.rtf.RTFEditorKit; -import java.io.*; - -/** -* Provides methods for converting back and forth between -* Extended Wylie and TibetanMachineWeb, and for inserting Tibetan -* into a styled document. -*

-* The class provides a variety of static methods for -* converting back and forth between Extended Wylie and TibetanMachineWeb. -* The Wylie can be accessed as a String, while the TibetanMachineWeb -* can be exported as Rich Text Format. -*

-* When instantiated as an instance object, -* this class also provides methods for inserting Tibetan -* (as TibetanMachineWeb) into a styled document. -* @author Edward Garrett, Tibetan and Himalayan Digital Library -* @version 1.0 -*/ -public class TibetanDocument extends DefaultStyledDocument { - private static List chars = new ArrayList(); - private int tibetanFontSize = 36; - -/** -* Creates a TibetanDocument. -* @param styles a StyleContext, which is simply passed on -* to DefaultStyledDocument's constructor -*/ - public TibetanDocument(StyleContext styles) { - super(styles); - } - -/** -* Sets the point size used by default for Tibetan text. -* @param size the point size for Tibetan text -*/ - public void setTibetanFontSize(int size) { - tibetanFontSize = size; - } - -/** -* Gets the point size for Tibetan text. -* @return the point size used for Tibetan text -*/ - public int getTibetanFontSize() { - return tibetanFontSize; - } - -/** -* Writes the document to an OutputStream as Rich Text Format (.rtf). -* @param out the OutputStream to write to -*/ - public void writeRTFOutputStream(OutputStream out) throws IOException { - RTFEditorKit rtf = new RTFEditorKit(); - - try { - rtf.write(out, this, 0, getLength()); - } - catch (BadLocationException ble) { - } - } - -/** -* Inserts Tibetan text into the document. The font size is applied automatically, -* according to the current Tibetan font size. -* @param offset the position at which you want to insert text -* @param s the string you want to insert -* @param attr the attributes to apply, normally a particular TibetanMachineWeb font -* @see #setTibetanFontSize(int size) -*/ - public void appendDuff(int offset, String s, MutableAttributeSet attr) { - try { - StyleConstants.setFontSize(attr, tibetanFontSize); - insertString(offset, s, attr); - } - catch (BadLocationException ble) { - } - } - -/** -* Inserts a stretch of TibetanMachineWeb data into the document. -* @param glyphs the array of Tibetan data you want to insert -* @param pos the position at which you want to insert text -*/ - public void insertDuff(int pos, DuffData[] glyphs) { - if (glyphs == null) - return; - - MutableAttributeSet mas; - for (int i=0; i -* 1 - TibetanMachineWeb
-* 2 - TibetanMachineWeb1
-* ...
-* 10 - TibetanMachineWeb9
-*

-* The string represents a contiguous stretch of data in that -* font, i.e. a stretch of TibetanMachineWeb that doesn't require a font change. -*/ - public static class DuffData { -/** -* a string of text -*/ - public String text; -/** -* the font number for this text -*/ - public int font; - -/** -* @param s a string of TibetanMachineWeb text -* @param i a TibetanMachineWeb font number -*/ - public DuffData(String s, int i) { - text = s; - font = i; - } - } - -/** -* Converts a list of glyphs into an array of {@link TibetanDocument.DuffData DuffData}. -* The motivation for this is that most processes - for example using -* TibetanMachineWeb in HTML - only need to know what -* text to output, and when to change fonts. In general, they don't -* need to have an explicit indication for each glyph of the font -* for that glyph. -* @param glyphs the list of TibetanMachineWeb glyphs -* you want to convert -* @return an array of DuffData corresponding to this -* list of glyphs -*/ - public static DuffData[] convertGlyphs(List glyphs) { - if (glyphs.size() == 0) - return null; - List data = new ArrayList(); - StringBuffer sb = new StringBuffer(); - Iterator iter = glyphs.iterator(); - DuffCode dc = (DuffCode)iter.next(); - int lastfont = dc.fontNum; - sb.append(dc.character); - - while (iter.hasNext()) { - dc = (DuffCode)iter.next(); - if (dc.fontNum == lastfont) - sb.append(dc.character); - else { - data.add(new DuffData(sb.toString(), lastfont)); - lastfont = dc.fontNum; - sb = new StringBuffer(); - sb.append(dc.character); - } - } - - data.add(new DuffData(sb.toString(), lastfont)); - - DuffData[] dd = new DuffData[0]; - dd = (DuffData[])data.toArray(dd); - return dd; - } - -/** -* Figures out how to arrange a list of characters into glyphs. For example, if the user types 'bsgr' -* using the Extended Wylie keyboard, this method figures out that this should be represented -* as a 'b' glyph followed by a 's-g-r' glyph. If you know that the characters do not -* contain Sanskrit stacks, or do not contain Tibetan stacks, then you can specify this -* to speed the process up. Otherwise, the method will first check to see if the characters -* correspond to any Tibetan stacks, and if not, then it will check for Sanskrit stacks. -* @param chars the list of Tibetan characters you want to find glyphs for -* @param areStacksOnRight whether stacking should try to maximize from right to left (true) -* or from left to right (false). In the Extended Wylie keyboard, you try to stack from -* right to left. Thus, the character sequence r-g-r would be stacked as r followed by gr, -* rather than rg followed by r. In the Sambhota and TCC keyboards, the stack direction -* is reversed. -* @param definitelyTibetan should be true if the characters are known to be Tibetan and -* not Sanskrit -* @param definitelySanskrit should be true if the characters are known to be Sanskrit and -* not Tibetan -*/ - public static List getGlyphs(List chars, boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) { - StringBuffer tibBuffer, sanBuffer; - String tibCluster, sanCluster; - - boolean checkTibetan, checkSanskrit; - - if (!(definitelyTibetan || definitelySanskrit)) { - checkTibetan = true; - checkSanskrit = true; - } - else { - checkTibetan = definitelyTibetan; - checkSanskrit = definitelySanskrit; - } - - int length = chars.size(); - - List glyphs = new ArrayList(); - glyphs.clear(); - - if (areStacksOnRight) { - for (int i=0; i-1; i--) { - tibBuffer = new StringBuffer(); - tibCluster = null; - - sanBuffer = new StringBuffer(); - sanCluster = null; - - Iterator iter = chars.iterator(); - - for (int k=0; k 1) { - dc = (DuffCode)glyphs.get(glyphs.size()-1); - if (!TibetanMachineWeb.isWyliePunc(TibetanMachineWeb.getWylieForGlyph(dc))) { - DuffCode dc_2 = (DuffCode)glyphs.removeLast(); - DuffCode dc_1 = (DuffCode)glyphs.removeLast(); - glyphs.addAll(getVowel(dc_1, dc_2, next)); - break vowel_block; - } - } - DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); - dc = dc_array[TibetanMachineWeb.TMW]; - glyphs.addAll(getVowel(dc, next)); - } - - chars.clear(); - } - - isSanskrit = false; - } - - else if (TibetanMachineWeb.isWylieChar(next)) { - if (!isSanskrit) //add char to list - it is not sanskrit - chars.add(next); - - else if (wasLastSanskritStackingKey) { //add char to list - it is still part of sanskrit stack - chars.add(next); - wasLastSanskritStackingKey = false; - } - - else { //char is no longer part of sanskrit stack, therefore compute and add previous stack - glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); - chars.clear(); - chars.add(next); - isSanskrit = false; - wasLastSanskritStackingKey = false; - } - } - - else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY))) { - if (!chars.isEmpty()) - glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); - - chars.clear(); - isSanskrit = false; - } - - else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_SANSKRIT_STACKING_KEY))) { - if (!isSanskrit) { //begin sanskrit stack - switch (chars.size()) { - case 0: - break; //'+' is not "pre-stacking" key - - case 1: - isSanskrit = true; - wasLastSanskritStackingKey = true; - break; - - default: - String top_char = (String)chars.get(chars.size()-1); - chars.remove(chars.size()-1); - glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); - chars.clear(); - chars.add(top_char); - isSanskrit = true; - wasLastSanskritStackingKey = true; - break; - } - } - } - - else if (TibetanMachineWeb.isFormatting(next.charAt(0))) { - if (!chars.isEmpty()) - glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); - - dc = new DuffCode(1,next.charAt(0)); - glyphs.add(dc); - chars.clear(); - isSanskrit = false; - } - - if (next != null) - start += next.length(); - } - - if (!chars.isEmpty()) { - glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); - chars.clear(); - } - - DuffData[] dd = convertGlyphs(glyphs); - return dd; - } - -/** -* Gets the bindu sequence for a given context. -* In the TibetanMachineWeb fonts, bindu (anusvara) is realized -* differently depending on which vowel it attaches to. Although -* the default bindu glyph is affixed to consonants and subscript vowels, -* for superscript vowels (i, e, o, etc), there is a single glyph -* which merges the bindu and that vowel together. When you pass this -* method a glyph context, it will return a List of glyphs which -* will either consist of the original glyph followed by the default -* bindu glyph, or a composite vowel+bindu glyph. -* Note that there is only one glyph in the context. This means that -* bindus will not affix properly if superscript vowels are allowed to directly -* precede subscript vowels (e.g. pou). -* @param dc the DuffCode of the glyph you -* want to attach a bindu to -* @return a List of DuffCode glyphs that include the -* original dc, as well as a bindu -*/ - public static List getBindu(DuffCode dc) { - List bindus = new ArrayList(); - - if (null == dc) { - bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); - return bindus; - } - - if (!TibetanMachineWeb.getBinduMap().containsKey(dc)) { - bindus.add(dc); - bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); - return bindus; - } - - bindus.add((DuffCode)TibetanMachineWeb.getBinduMap().get(dc)); - return bindus; - } - -/** -* Gets the vowel sequence for a given vowel in a given context. -* Given a context, this method affixes a vowel and returns the -* context plus the vowel. Generally, it is enough to provide just -* one glyph for context. -* @param context the glyph preceding the vowel you want to affix -* @param vowel the vowel you want to affix, in Wylie -* @return a List of glyphs equal to the vowel in context -*/ - public static List getVowel(DuffCode context, String vowel) { - return getVowel(null, context, vowel); - } - -/** -* Gets the vowel sequence for a given vowel in a given context. -* Given a context, this method affixes a vowel and returns the context plus the vowel. -* Since the choice of vowel glyph depends on the consonant to which it is attached, -* generally it is enough to provide just the immediately preceding context. However, -* in some cases, double vowels are allowed - for example 'buo'. To find the correct -* glyph for 'o', we need 'b' in this case, not 'u'. Note also that some Extended -* Wylie vowels correspond to multiple glyphs in TibetanMachineWeb. For example, -* the vowel I consists of both an achung and a reverse gigu. All required glyphs -* are part of the returned List. -* @param context_1 the glyph occurring two glyphs before the vowel you want to affix -* @param context_2 the glyph immediately before the vowel you want to affix -* @param vowel the vowel you want to affix, in Wylie -* @return a List of glyphs equal to the vowel in context -*/ - - public static List getVowel(DuffCode context_1, DuffCode context_2, String vowel) { - List vowels = new ArrayList(); - -//this vowel doesn't correspond to a glyph - -//so you just return the original context - - if ( vowel.equals(TibetanMachineWeb.WYLIE_aVOWEL) || - TibetanMachineWeb.isTopVowel(context_2)) { - if (context_1 != null) - vowels.add(context_1); - - vowels.add(context_2); - return vowels; - } - -//first, the three easiest cases: ai, au, and 0 || !glyphList.isEmpty()) { - if (needsVowel) - wylieBuffer.append(withA(glyphList)); - else - wylieBuffer.append(withoutA(glyphList)); - - glyphList.clear(); - needsVowel = true; - isLastVowel = false; - } - - wylieBuffer.append(ch); - } - else { - wylie = TibetanMachineWeb.getWylieForGlyph(dcs[i]); - - boolean containsBindu = false; - if (wylie.length() > 1 && wylie.charAt(wylie.length()-1) == TibetanMachineWeb.BINDU) { - char[] cArray = wylie.toCharArray(); - wylie = new String(cArray, 0, wylie.length()-1); - containsBindu = true; - } - - process_block: { - if (TibetanMachineWeb.isWyliePunc(wylie)) { - isLastVowel = false; - - if (glyphList.isEmpty()) - wylieBuffer.append(wylie); - - else { - if (needsVowel) - wylieBuffer.append(withA(glyphList)); - else - wylieBuffer.append(withoutA(glyphList)); - - wylieBuffer.append(wylie); //append the punctuation - - glyphList.clear(); - } - needsVowel = true; //next consonants are syllable onset, so we are awaiting vowel - } - - //isChar must come before isVowel because ACHEN has priority over WYLIE_aVOWEL - else if (TibetanMachineWeb.isWylieChar(wylie)) { - isLastVowel = false; - glyphList.add(dcs[i]); - } - - else if (TibetanMachineWeb.isWylieVowel(wylie)) { - if (isLastVowel) { - int len = wylieBuffer.length(); - int A_len = TibetanMachineWeb.A_VOWEL.length(); - - if (wylieBuffer.substring(len-A_len).equals(TibetanMachineWeb.A_VOWEL)) { - try { - if (wylie.equals(TibetanMachineWeb.i_VOWEL)) { - wylieBuffer.delete(len-A_len, len); - wylieBuffer.append(TibetanMachineWeb.I_VOWEL); - isLastVowel = false; - break process_block; - } - else if (wylie.equals(TibetanMachineWeb.reverse_i_VOWEL)) { - wylieBuffer.delete(len-A_len, len); - wylieBuffer.append(TibetanMachineWeb.reverse_I_VOWEL); - isLastVowel = false; - break process_block; - } - } - catch (StringIndexOutOfBoundsException se) { - } - - wylieBuffer.append(wylie); //append current vowel - isLastVowel = false; - } - else - wylieBuffer.append(wylie); //append current vowel - } - else { - int glyphCount = glyphList.size(); - boolean insertDisAmbig = false; - - if (0 != glyphCount) { - DuffCode top_dc = (DuffCode)glyphList.get(glyphCount-1); - String top_wylie = TibetanMachineWeb.getWylieForGlyph(top_dc); - - if (top_wylie.equals(TibetanMachineWeb.ACHEN)) { - glyphList.remove(glyphCount-1); - - if (glyphCount-1 == 0) - top_dc = null; - else { - insertDisAmbig = true; - top_dc = (DuffCode)glyphList.get(glyphCount-2); - } - } - - if (top_dc == null || !TibetanMachineWeb.getWylieForGlyph(top_dc).equals(TibetanMachineWeb.ACHUNG)) - wylieBuffer.append(withoutA(glyphList)); //append consonants in glyphList - else { - glyphCount = glyphList.size(); - glyphList.remove(glyphCount-1); - - if (glyphCount-1 != 0) - wylieBuffer.append(withA(glyphList)); - - wylieBuffer.append(TibetanMachineWeb.ACHUNG); - } - } - - if (insertDisAmbig) - wylieBuffer.append(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY); - - wylieBuffer.append(wylie); //append vowel - - glyphList.clear(); - isLastVowel = true; - needsVowel = false; - } - } - else { //must be a stack - isLastVowel = false; - glyphList.add(dcs[i]); - } - } - - if (containsBindu) { - isLastVowel = false; - wylieBuffer.append(withoutA(glyphList)); - wylieBuffer.append(TibetanMachineWeb.BINDU); //append the bindu - glyphList.clear(); - } - } - } - - //replace TMW with Wylie - - if (!glyphList.isEmpty()) { - if (needsVowel) - wylieBuffer.append(withA(glyphList)); - else - wylieBuffer.append(withoutA(glyphList)); - } - - if (wylieBuffer.length() > 0) - return wylieBuffer.toString(); - else - return null; - } -} \ No newline at end of file +/* +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.tib.text; + +import java.util.*; +import javax.swing.*; +import javax.swing.text.*; +import javax.swing.text.rtf.RTFEditorKit; +import java.io.*; + +import org.thdl.util.ThdlDebug; + +/** +* Provides methods for converting back and forth between +* Extended Wylie and TibetanMachineWeb, and for inserting Tibetan +* into a styled document. +*

+* The class provides a variety of static methods for +* converting back and forth between Extended Wylie and TibetanMachineWeb. +* The Wylie can be accessed as a String, while the TibetanMachineWeb +* can be exported as Rich Text Format. +*

+* When instantiated as an instance object, +* this class also provides methods for inserting Tibetan +* (as TibetanMachineWeb) into a styled document. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class TibetanDocument extends DefaultStyledDocument { + private static List chars = new ArrayList(); + private int tibetanFontSize = 36; + +/** +* Creates a TibetanDocument. +* @param styles a StyleContext, which is simply passed on +* to DefaultStyledDocument's constructor +*/ + public TibetanDocument(StyleContext styles) { + super(styles); + } + +/** +* Sets the point size used by default for Tibetan text. +* @param size the point size for Tibetan text +*/ + public void setTibetanFontSize(int size) { + tibetanFontSize = size; + } + +/** +* Gets the point size for Tibetan text. +* @return the point size used for Tibetan text +*/ + public int getTibetanFontSize() { + return tibetanFontSize; + } + +/** +* Writes the document to an OutputStream as Rich Text Format (.rtf). +* @param out the OutputStream to write to +*/ + public void writeRTFOutputStream(OutputStream out) throws IOException { + RTFEditorKit rtf = new RTFEditorKit(); + + try { + rtf.write(out, this, 0, getLength()); + } + catch (BadLocationException ble) { + } + } + +/** +* Inserts Tibetan text into the document. The font size is applied automatically, +* according to the current Tibetan font size. +* @param offset the position at which you want to insert text +* @param s the string you want to insert +* @param attr the attributes to apply, normally a particular TibetanMachineWeb font +* @see #setTibetanFontSize(int size) +*/ + public void appendDuff(int offset, String s, MutableAttributeSet attr) { + try { + StyleConstants.setFontSize(attr, tibetanFontSize); + insertString(offset, s, attr); + } + catch (BadLocationException ble) { + } + } + +/** +* Inserts a stretch of TibetanMachineWeb data into the document. +* @param glyphs the array of Tibetan data you want to insert +* @param pos the position at which you want to insert text +*/ + public int insertDuff(int pos, DuffData[] glyphs) { + if (glyphs == null) + return pos; + + MutableAttributeSet mas; + for (int i=0; i +* 1 - TibetanMachineWeb
+* 2 - TibetanMachineWeb1
+* ...
+* 10 - TibetanMachineWeb9
+*

+* The string represents a contiguous stretch of data in that +* font, i.e. a stretch of TibetanMachineWeb that doesn't require a font change. +*/ + public static class DuffData { +/** +* a string of text +*/ + public String text; +/** +* the font number for this text +*/ + public int font; + +/** +* @param s a string of TibetanMachineWeb text +* @param i a TibetanMachineWeb font number +*/ + public DuffData(String s, int i) { + text = s; + font = i; + } + } + +/** +* Converts a list of glyphs into an array of {@link TibetanDocument.DuffData DuffData}. +* The motivation for this is that most processes - for example using +* TibetanMachineWeb in HTML - only need to know what +* text to output, and when to change fonts. In general, they don't +* need to have an explicit indication for each glyph of the font +* for that glyph. +* @param glyphs the list of TibetanMachineWeb glyphs +* you want to convert +* @return an array of DuffData corresponding to this +* list of glyphs +*/ + public static DuffData[] convertGlyphs(List glyphs) { + if (glyphs.size() == 0) + return null; + List data = new ArrayList(); + StringBuffer sb = new StringBuffer(); + Iterator iter = glyphs.iterator(); + DuffCode dc = (DuffCode)iter.next(); + int lastfont = dc.fontNum; + sb.append(dc.character); + + while (iter.hasNext()) { + dc = (DuffCode)iter.next(); + if (dc.fontNum == lastfont) + sb.append(dc.character); + else { + data.add(new DuffData(sb.toString(), lastfont)); + lastfont = dc.fontNum; + sb = new StringBuffer(); + sb.append(dc.character); + } + } + + data.add(new DuffData(sb.toString(), lastfont)); + + DuffData[] dd = new DuffData[0]; + dd = (DuffData[])data.toArray(dd); + return dd; + } + +/** +* Figures out how to arrange a list of characters into glyphs. For example, if the user types 'bsgr' +* using the Extended Wylie keyboard, this method figures out that this should be represented +* as a 'b' glyph followed by a 's-g-r' glyph. If you know that the characters do not +* contain Sanskrit stacks, or do not contain Tibetan stacks, then you can specify this +* to speed the process up. Otherwise, the method will first check to see if the characters +* correspond to any Tibetan stacks, and if not, then it will check for Sanskrit stacks. +* @param chars the list of Tibetan characters you want to find glyphs for +* @param areStacksOnRight whether stacking should try to maximize from right to left (true) +* or from left to right (false). In the Extended Wylie keyboard, you try to stack from +* right to left. Thus, the character sequence r-g-r would be stacked as r followed by gr, +* rather than rg followed by r. In the Sambhota and TCC keyboards, the stack direction +* is reversed. +* @param definitelyTibetan should be true if the characters are known to be Tibetan and +* not Sanskrit +* @param definitelySanskrit should be true if the characters are known to be Sanskrit and +* not Tibetan +*/ + public static List getGlyphs(List chars, boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) { + StringBuffer tibBuffer, sanBuffer; + String tibCluster, sanCluster; + + boolean checkTibetan, checkSanskrit; + + if (!(definitelyTibetan || definitelySanskrit)) { + checkTibetan = true; + checkSanskrit = true; + } + else { + checkTibetan = definitelyTibetan; + checkSanskrit = definitelySanskrit; + } + + int length = chars.size(); + + List glyphs = new ArrayList(); + glyphs.clear(); + + if (areStacksOnRight) { + for (int i=0; i-1; i--) { + tibBuffer = new StringBuffer(); + tibCluster = null; + + sanBuffer = new StringBuffer(); + sanCluster = null; + + Iterator iter = chars.iterator(); + + for (int k=0; k 1) { + dc = (DuffCode)glyphs.get(glyphs.size()-1); + if (!TibetanMachineWeb.isWyliePunc(TibetanMachineWeb.getWylieForGlyph(dc))) { + DuffCode dc_2 = (DuffCode)glyphs.removeLast(); + DuffCode dc_1 = (DuffCode)glyphs.removeLast(); + glyphs.addAll(getVowel(dc_1, dc_2, next)); + break vowel_block; + } + } + DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); + dc = dc_array[TibetanMachineWeb.TMW]; + glyphs.addAll(getVowel(dc, next)); + } + + chars.clear(); + } + + isSanskrit = false; + } + + else if (TibetanMachineWeb.isWylieChar(next)) { + if (!isSanskrit) //add char to list - it is not sanskrit + chars.add(next); + + else if (wasLastSanskritStackingKey) { //add char to list - it is still part of sanskrit stack + chars.add(next); + wasLastSanskritStackingKey = false; + } + + else { //char is no longer part of sanskrit stack, therefore compute and add previous stack + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + chars.add(next); + isSanskrit = false; + wasLastSanskritStackingKey = false; + } + } + + else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY))) { + if (!chars.isEmpty()) + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + + chars.clear(); + isSanskrit = false; + } + + else if (next.equals(String.valueOf(TibetanMachineWeb.WYLIE_SANSKRIT_STACKING_KEY))) { + if (!isSanskrit) { //begin sanskrit stack + switch (chars.size()) { + case 0: + break; //'+' is not "pre-stacking" key + + case 1: + isSanskrit = true; + wasLastSanskritStackingKey = true; + break; + + default: + String top_char = (String)chars.get(chars.size()-1); + chars.remove(chars.size()-1); + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + chars.add(top_char); + isSanskrit = true; + wasLastSanskritStackingKey = true; + break; + } + } + } + + else if (TibetanMachineWeb.isFormatting(next.charAt(0))) { + if (!chars.isEmpty()) + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + + dc = new DuffCode(1,next.charAt(0)); + glyphs.add(dc); + chars.clear(); + isSanskrit = false; + } + + if (next != null) + start += next.length(); + } + + if (!chars.isEmpty()) { + glyphs.addAll(getGlyphs(chars, true, !isSanskrit, isSanskrit)); + chars.clear(); + } + + DuffData[] dd = convertGlyphs(glyphs); + return dd; + } + +/** +* Gets the bindu sequence for a given context. +* In the TibetanMachineWeb fonts, bindu (anusvara) is realized +* differently depending on which vowel it attaches to. Although +* the default bindu glyph is affixed to consonants and subscript vowels, +* for superscript vowels (i, e, o, etc), there is a single glyph +* which merges the bindu and that vowel together. When you pass this +* method a glyph context, it will return a List of glyphs which +* will either consist of the original glyph followed by the default +* bindu glyph, or a composite vowel+bindu glyph. +* Note that there is only one glyph in the context. This means that +* bindus will not affix properly if superscript vowels are allowed to directly +* precede subscript vowels (e.g. pou). +* @param dc the DuffCode of the glyph you +* want to attach a bindu to +* @return a List of DuffCode glyphs that include the +* original dc, as well as a bindu +*/ + public static List getBindu(DuffCode dc) { + List bindus = new ArrayList(); + + if (null == dc) { + bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); + return bindus; + } + + if (!TibetanMachineWeb.getBinduMap().containsKey(dc)) { + bindus.add(dc); + bindus.add(TibetanMachineWeb.getGlyph(String.valueOf(TibetanMachineWeb.BINDU))); + return bindus; + } + + bindus.add((DuffCode)TibetanMachineWeb.getBinduMap().get(dc)); + return bindus; + } + +/** +* Gets the vowel sequence for a given vowel in a given context. +* Given a context, this method affixes a vowel and returns the +* context plus the vowel. Generally, it is enough to provide just +* one glyph for context. +* @param context the glyph preceding the vowel you want to affix +* @param vowel the vowel you want to affix, in Wylie +* @return a List of glyphs equal to the vowel in context +*/ + public static List getVowel(DuffCode context, String vowel) { + return getVowel(null, context, vowel); + } + +/** +* Gets the vowel sequence for a given vowel in a given context. +* Given a context, this method affixes a vowel and returns the context plus the vowel. +* Since the choice of vowel glyph depends on the consonant to which it is attached, +* generally it is enough to provide just the immediately preceding context. However, +* in some cases, double vowels are allowed - for example 'buo'. To find the correct +* glyph for 'o', we need 'b' in this case, not 'u'. Note also that some Extended +* Wylie vowels correspond to multiple glyphs in TibetanMachineWeb. For example, +* the vowel I consists of both an achung and a reverse gigu. All required glyphs +* are part of the returned List. +* @param context_1 the glyph occurring two glyphs before the vowel you want to affix +* @param context_2 the glyph immediately before the vowel you want to affix +* @param vowel the vowel you want to affix, in Wylie +* @return a List of glyphs equal to the vowel in context +*/ + + public static List getVowel(DuffCode context_1, DuffCode context_2, String vowel) { + List vowels = new ArrayList(); + +//this vowel doesn't correspond to a glyph - +//so you just return the original context + + if ( vowel.equals(TibetanMachineWeb.WYLIE_aVOWEL) || + TibetanMachineWeb.isTopVowel(context_2)) { + if (context_1 != null) + vowels.add(context_1); + + vowels.add(context_2); + return vowels; + } + +//first, the three easiest cases: ai, au, and = end) + return ""; + + java.util.List dcs = new ArrayList(); + int i = begin; + StringBuffer wylieBuffer = new StringBuffer(); + + try { + while (i < end) { + attr = getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + ch = getText(i,1).charAt(0); + + //current character is formatting + if (ch == '\n' || ch == '\t') { + if (dcs.size() > 0) { + DuffCode[] dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + wylieBuffer.append(TibetanDocument.getWylie(dc_array)); + dcs.clear(); + } + wylieBuffer.append(ch); + } + + //current character isn't TMW + else if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName)))) { + if (dcs.size() > 0) { + DuffCode[] dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + wylieBuffer.append(TibetanDocument.getWylie(dc_array)); + dcs.clear(); + } + } + + //current character is convertable + else { + dc = new DuffCode(fontNum, ch); + dcs.add(dc); + } + i++; + } + if (dcs.size() > 0) { + DuffCode[] dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + wylieBuffer.append(TibetanDocument.getWylie(dc_array)); + } + return wylieBuffer.toString(); + } + catch (BadLocationException ble) { + ble.printStackTrace(); + ThdlDebug.noteIffyCode(); + } + + return ""; + } + +/** +* Gets the Extended Wylie for a set of glyphs. +* @param dcs an array of glyphs +* @return the Extended Wylie corresponding to these glyphs +*/ + public static String getWylie(DuffCode[] dcs) { + if (dcs.length == 0) + return null; + + AttributeSet attr; + String fontName; + int fontNum; + char ch; + String wylie; + + List glyphList = new ArrayList(); + boolean needsVowel = true; + boolean isLastVowel = false; + int start = 0; + StringBuffer wylieBuffer = new StringBuffer(); + + for (int i=start; i 0 || !glyphList.isEmpty()) { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + + glyphList.clear(); + needsVowel = true; + isLastVowel = false; + } + + wylieBuffer.append(ch); + } + else { + wylie = TibetanMachineWeb.getWylieForGlyph(dcs[i]); + + boolean containsBindu = false; + if (wylie.length() > 1 && wylie.charAt(wylie.length()-1) == TibetanMachineWeb.BINDU) { + char[] cArray = wylie.toCharArray(); + wylie = new String(cArray, 0, wylie.length()-1); + containsBindu = true; + } + + process_block: { + if (TibetanMachineWeb.isWyliePunc(wylie)) { + isLastVowel = false; + + if (glyphList.isEmpty()) + wylieBuffer.append(wylie); + + else { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + + wylieBuffer.append(wylie); //append the punctuation + + glyphList.clear(); + } + needsVowel = true; //next consonants are syllable onset, so we are awaiting vowel + } + + //isChar must come before isVowel because ACHEN has priority over WYLIE_aVOWEL + else if (TibetanMachineWeb.isWylieChar(wylie)) { + isLastVowel = false; + glyphList.add(dcs[i]); + } + + else if (TibetanMachineWeb.isWylieVowel(wylie)) { + if (isLastVowel) { + int len = wylieBuffer.length(); + int A_len = TibetanMachineWeb.A_VOWEL.length(); + + if (wylieBuffer.substring(len-A_len).equals(TibetanMachineWeb.A_VOWEL)) { + try { + if (wylie.equals(TibetanMachineWeb.i_VOWEL)) { + wylieBuffer.delete(len-A_len, len); + wylieBuffer.append(TibetanMachineWeb.I_VOWEL); + isLastVowel = false; + break process_block; + } + else if (wylie.equals(TibetanMachineWeb.reverse_i_VOWEL)) { + wylieBuffer.delete(len-A_len, len); + wylieBuffer.append(TibetanMachineWeb.reverse_I_VOWEL); + isLastVowel = false; + break process_block; + } + } + catch (StringIndexOutOfBoundsException se) { + } + + wylieBuffer.append(wylie); //append current vowel + isLastVowel = false; + } + else + wylieBuffer.append(wylie); //append current vowel + } + else { + int glyphCount = glyphList.size(); + boolean insertDisAmbig = false; + + if (0 != glyphCount) { + DuffCode top_dc = (DuffCode)glyphList.get(glyphCount-1); + String top_wylie = TibetanMachineWeb.getWylieForGlyph(top_dc); + + if (top_wylie.equals(TibetanMachineWeb.ACHEN)) { + glyphList.remove(glyphCount-1); + + if (glyphCount-1 == 0) + top_dc = null; + else { + insertDisAmbig = true; + top_dc = (DuffCode)glyphList.get(glyphCount-2); + } + } + + if (top_dc == null || !TibetanMachineWeb.getWylieForGlyph(top_dc).equals(TibetanMachineWeb.ACHUNG)) + wylieBuffer.append(withoutA(glyphList)); //append consonants in glyphList + else { + glyphCount = glyphList.size(); + glyphList.remove(glyphCount-1); + + if (glyphCount-1 != 0) + wylieBuffer.append(withA(glyphList)); + + wylieBuffer.append(TibetanMachineWeb.ACHUNG); + } + } + + if (insertDisAmbig) + wylieBuffer.append(TibetanMachineWeb.WYLIE_DISAMBIGUATING_KEY); + + wylieBuffer.append(wylie); //append vowel + + glyphList.clear(); + isLastVowel = true; + needsVowel = false; + } + } + else { //must be a stack + isLastVowel = false; + glyphList.add(dcs[i]); + } + } + + if (containsBindu) { + isLastVowel = false; + wylieBuffer.append(withoutA(glyphList)); + wylieBuffer.append(TibetanMachineWeb.BINDU); //append the bindu + glyphList.clear(); + } + } + } + + //replace TMW with Wylie + + if (!glyphList.isEmpty()) { + if (needsVowel) + wylieBuffer.append(withA(glyphList)); + else + wylieBuffer.append(withoutA(glyphList)); + } + + if (wylieBuffer.length() > 0) + return wylieBuffer.toString(); + else + return null; + } +} diff --git a/source/org/thdl/tib/text/package.html b/source/org/thdl/tib/text/package.html index 7df6b80..a14ce46 100644 --- a/source/org/thdl/tib/text/package.html +++ b/source/org/thdl/tib/text/package.html @@ -5,7 +5,7 @@ @(#)package.html - Copyright 2001 Tibetan and Himalayan Digital Library + Copyright 2001-2002 Tibetan and Himalayan Digital Library This software is the confidential and proprietary information of the Tibetan and Himalayan Digital Library. You shall use such @@ -33,6 +33,6 @@ Here, you can also find methods for installing and managing Tibetan keyboards. Four keyboards have been provided in this release, but users may also create their own keyboards.

Related Documentation

-@see org.thdl.tib.input +@see org.thdl.tib.input diff --git a/source/org/thdl/util/TeeStream.java b/source/org/thdl/util/TeeStream.java index c711ba9..ff457fe 100644 --- a/source/org/thdl/util/TeeStream.java +++ b/source/org/thdl/util/TeeStream.java @@ -22,7 +22,9 @@ import java.io.PrintStream; /** * All writes to this print stream are copied to two print streams of - * your choice. */ + * your choice. + * @author David Chandler + */ public class TeeStream extends PrintStream { private PrintStream out; public TeeStream(PrintStream out1, PrintStream out2) { diff --git a/source/org/thdl/util/ThdlAbstractAction.java b/source/org/thdl/util/ThdlAbstractAction.java new file mode 100644 index 0000000..82b421e --- /dev/null +++ b/source/org/thdl/util/ThdlAbstractAction.java @@ -0,0 +1,85 @@ +/* +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.util; + +import javax.swing.AbstractAction; +import javax.swing.Icon; +import java.awt.event.ActionEvent; + +import org.thdl.util.ThdlDebug; + +/** + * This ActionListener is like any other except in the way that it + * handles exceptions or errors thrown during the execution of + * actionPerformed(). Because event listeners are on + * threads, an exception during actionPerformed() is just + * printed out on the console by + * java.awt.EventDispatchThread.run(). It does not cause + * the program to terminate. In our code, it helps developers more + * quickly get to the root of a problem if the program terminates as + * soon after a problem as possible. + * + * Thus, this class calls System.exit(1) when an + * exception is throw by theRealActionPerformed(), which + * is the method that subclasses should implement. + * + * @see ThdlActionListener + * + * @author David Chandler + * + * There is a pertinent Usenet thread at http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&threadm=6ntgl6%244hl%241%40tarantula.europe.shiva.com&rnum=2&prev=/groups%3Fq%3Dexception%2BactionPerformed%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3Dutf-8%26selm%3D6ntgl6%25244hl%25241%2540tarantula.europe.shiva.com%26rnum%3D2. + */ +public class ThdlAbstractAction extends AbstractAction { + + /** Just calls the super's constructor with the same args. */ + public ThdlAbstractAction(String s, Icon i) { + super(s, i); + } + + /** Subclasses don't override this. Instead, they override + * theRealActionPerformed(). + * @see #actionPerformed(ActionEvent) + */ + public final void actionPerformed(ActionEvent e) { + try { + theRealActionPerformed(e); + } catch (NoClassDefFoundError err) { + /* This is an especially common exception, and is in fact + the motivating force behind the ThdlActionListener + class and this class. Handle it well so that users + know what's up: */ + ThdlDebug.handleClasspathError(null, err); + } catch (Throwable t) { + System.err.println("THDL_ERR 107: This application failed due to the following exception: "); + t.printStackTrace(System.err); + System.exit(1); + } + } + + /** Subclasses should override this method to do the real action + * performed. + * @see #actionPerformed(ActionEvent) + */ + protected void theRealActionPerformed(ActionEvent e) + throws Throwable + { + /* do nothing */ + } +} + diff --git a/source/org/thdl/util/ThdlActionListener.java b/source/org/thdl/util/ThdlActionListener.java new file mode 100644 index 0000000..1e37521 --- /dev/null +++ b/source/org/thdl/util/ThdlActionListener.java @@ -0,0 +1,157 @@ +/* +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.util; + +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +import org.thdl.util.ThdlDebug; + +/** + * This ActionListener is like any other except in the way that it + * handles exceptions or errors thrown during the execution of + * actionPerformed(). Because event listeners are on + * threads, an exception during actionPerformed() is just + * printed out on the console by + * java.awt.EventDispatchThread.run(). It does not cause + * the program to terminate. In our code, it helps developers more + * quickly get to the root of a problem if the program terminates as + * soon after a problem as possible. + * + * Thus, this class calls System.exit(1) when an + * exception is throw by theRealActionPerformed(), which + * is the method that subclasses should implement. + * + * @see ThdlAbstractAction + * + * @author David Chandler + * + * Here is a pertinent Usenet thread from http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=utf-8&threadm=6ntgl6%244hl%241%40tarantula.europe.shiva.com&rnum=2&prev=/groups%3Fq%3Dexception%2BactionPerformed%26hl%3Den%26lr%3D%26ie%3DUTF-8%26oe%3Dutf-8%26selm%3D6ntgl6%25244hl%25241%2540tarantula.europe.shiva.com%26rnum%3D2: + + +
+From: Denis (denisb@europe.shiva.com)
+Subject: Exception in event handlers
+ 
+View this article only
+Newsgroups: comp.lang.java.gui, comp.lang.java.help, comp.lang.java.programmer
+Date: 1998/07/07
+
+Hi everyone !
+
+I've got a wee question regarding propagation of exceptions in event
+handlers :
+here's the fun :
+
+Say, you've got a method A() that is called from within an event handler
+(mostly it'll be in actionPerformed(ActionEvent) from ActionListener
+interface).
+Now this A() method produces an exception. This exception will be propagated
+up to the caller of actionPerformed which is into the event handler queue.
+This exception never gets propagated higher than the handler (and produces a
+message "exception occured in event handler")
+
+Now I would like this exception NOT to be caught there but to propagate
+until the program terminates or it is caught somewhere else.
+
+Is there a way to do that ? There's no mean to re-throw that exception as
+the event handler is part of the core java.
+
+Basically what I would like to do is catch ANY exception that occurs in a
+java application in order to display a message box, without having to put
+try{} catch{} blocks all other the place...
+
+Thanks for any help on that
+
+Chunk of code to illustrate :
+
+class MyClass extends Object implements ActionListener {
+// blah blah
+
+    public void actionPerformed(ActionEvent event) {
+        A(); //May throw an exception here but the actionPerformed is called
+        // from the event handler and the exception is caught into it
+
+        //So the actionPerformed finishes because of the exception but the
+        // rest of the app is likely to be in an unstable state, but still running
+    }
+
+   // So here the exception has been caught without an explicit try{}
+   // catch{} WHICH I DONT WANT
+
+   //You then can happily do something else....even if A() failed....
+
+}//MyClass
+
+Message 2 in thread
+From: David Holmes (dholmes@mri.mq.edu.au)
+Subject: Re: Exception in event handlers
+ 
+View this article only
+Newsgroups: comp.lang.java.gui, comp.lang.java.help, comp.lang.java.programmer
+Date: 1998/07/09
+
+Denis <denisb@europe.shiva.com> wrote in article
+<6ntgl6$4hl$1@tarantula.europe.shiva.com>...
+> Now I would like this exception NOT to be caught there but to propagate
+> until the program terminates or it is caught somewhere else.
+
+Once an exception is caught it is up to the catcher what to do with it. The
+event dispatch thread simply catches the exception and tells you about it.
+There is no way to make this exception go any further - indeed there is
+nowhere further for it to go. Exceptions occur per-thread and if the thread
+doesn't catch it the thread will terminate. A more sophisticated event
+mechanism might allow you to register a handler/listener to take some
+action when this occurred but the current AWT does not.
+
+David
+
+ + */ +public class ThdlActionListener implements ActionListener { + /** Subclasses don't override this. Instead, they override + * theRealActionPerformed(). + * @see #actionPerformed(ActionEvent) + */ + public final void actionPerformed(ActionEvent e) { + try { + theRealActionPerformed(e); + } catch (NoClassDefFoundError err) { + /* This is an especially common exception, and is in fact + the motivating force behind the ThdlActionListener + class. Handle it well so that users know what's up: */ + ThdlDebug.handleClasspathError(null, err); + } catch (Throwable t) { + System.err.println("THDL_ERR 106: This application failed due to the following exception: "); + t.printStackTrace(System.err); + System.exit(1); + } + } + + /** Subclasses should override this method to do the real action + * performed by this action listener. + * @see #actionPerformed(ActionEvent) + */ + protected void theRealActionPerformed(ActionEvent e) + throws Throwable + { + /* do nothing */ + } +} + diff --git a/source/org/thdl/util/ThdlDebug.java b/source/org/thdl/util/ThdlDebug.java new file mode 100644 index 0000000..759bff6 --- /dev/null +++ b/source/org/thdl/util/ThdlDebug.java @@ -0,0 +1,136 @@ +/* +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.util; + +import java.io.PrintStream; +import java.io.FileOutputStream; + +import org.thdl.util.TeeStream; + +/** + * This uninstantiable class provides assertions and the like in a + * JVM-version-independent fashion. + * @author David Chandler + */ +public class ThdlDebug { + /* FIXME: make this configurable. */ + static final String contactMsg + = " Please visit http://thdltools.sf.net/ or contact thdltools-devel@lists.sourceforge.net and give us a bug report so that we can improve the quality of this software."; + + /** Do not instantiate this class. */ + private ThdlDebug() { } + + /** Throws an unchecked exception if condition is not true. Note that + * unlike a real assertion, this happens always. We can certainly + * use AspectJ (with which I, DC, am intimately familiar) to avoid + * the overhead of such things in release builds if performance + * becomes a real issue. */ + public static void verify(boolean condition) { + verify(null, condition); + } + + /** Throws an unchecked exception if condition is not true. The + * exception's message will include the string msg if msg is not + * null. Note that unlike a real assertion, this happens always. + * We can certainly use AspectJ (with which I, DC, am intimately + * familiar) to avoid the overhead of such things in release + * builds if performance becomes a real issue. + * + * Throws a THDL-specific exception so that you can catch these + * specially in case you want to ignore them. + * + * @throws ThdlLazyException if condition is not true */ + public static void verify(String msg, boolean condition) + throws ThdlLazyException + { + if (!condition) { + throw new ThdlLazyException(new Error(((msg == null) + ? "THDL Tools sanity check: " + : msg) + + "An assertion failed. This means that there is a bug in this software." + + contactMsg)); + } + } + + /** Call this from control-flow paths that are not well thought + * out. For example, if you have to catch an IOException, but + * you're fairly certain that it'll never be thrown, call this + * function if it is indeed thrown. Developers can set the + * THDL_DIE_EAGERLY property to true (using 'java + * -DTHDL_DIE_ON_IFFY_CODE=true') in order to test the + * code's robustness. + * + * Throws a THDL-specific exception so that you can catch these + * specially in case you want to ignore them. + * + * @throws ThdlLazyException if the THDL_DIE_ON_IFFY_CODE system + * property is set to "true" */ + public static void noteIffyCode() + throws ThdlLazyException + { + + /* FIXME: find all calls to this function and rethink or shore + up the calling code. */ + + if (Boolean.getBoolean("THDL_DIE_ON_IFFY_CODE")) + throw new ThdlLazyException(new Error("You've reached some iffy code, some code that's not well thought-out. Because you invoked the Java runtime environment with the property THDL_DIE_ON_IFFY_CODE set to true (developers: use 'ant -Dthdl.die.on.iffy=false' to prevent this), the program is now aborting.")); + } + + /** Exits the program with a message that the CLASSPATH is not set + properly. */ + public static void handleClasspathError(String whoseWhat, Throwable error) { + System.err.println(((whoseWhat == null) ? "Your CLASSPATH" : whoseWhat) + + " is not set properly."); + + /* FIXME */ + System.err.println("Note that Savant and QuillDriver CANNOT be invoked via the"); + System.err.println("'java -jar Savant-xyz.jar' option, because that silently ignores"); + System.err.println("the CLASSPATH. This means that double-clicking them won't work"); + System.err.println("either, because we don't set the JARs' manifest files to contain"); + System.err.println("Class-path attributes. See installation instructions."); /* FIXME: we don't HAVE installation instructions, do we? */ + System.err.println(""); + System.err.println("Details: Missing class: " + + ((error == null) + ? "unknown!" : error.getMessage())); + if (Boolean.getBoolean("THDL_DEBUG")) { + System.err.println("Details: Stack trace: " + + ((error == null) + ? "unknown!" : error.getMessage())); + error.printStackTrace(System.err); + } + System.exit(1); + } + + /** Sets it up so that a call to System.out or System.err prints + * to standard output/error but ALSO prints to the log file named + * logFile. */ + public static void attemptToSetUpLogFile(String logFile) { + try { + PrintStream logFilePrintStream + = new PrintStream(new FileOutputStream(logFile)); + PrintStream psOut = new TeeStream(System.out, logFilePrintStream); + PrintStream psErr = new TeeStream(System.err, logFilePrintStream); + System.setErr(psErr); + System.setOut(psOut); + } catch (Exception e) { + /* don't let this stop us. */ + noteIffyCode(); + } + } +}; diff --git a/source/org/thdl/util/package.html b/source/org/thdl/util/package.html new file mode 100644 index 0000000..8202974 --- /dev/null +++ b/source/org/thdl/util/package.html @@ -0,0 +1,22 @@ + + + + + + +Provides classes and methods not specific to any one application. +

+These classes aim to be of general use to the THDL's Java programs. + + diff --git a/source/overview.html b/source/overview.html new file mode 100644 index 0000000..203ba97 --- /dev/null +++ b/source/overview.html @@ -0,0 +1,112 @@ + + + + + + +Provides facilities for manipulating text, audio, and video in Tibetan and other Himalayan languages. + +

+From the THDL Tools project's + + News archive: + +

+Posted By: eg3p
+Date: 2002-09-26 12:14
+Summary:THDL Projects and Goals
+
+ +

+Hello. You'll see that we at the Tibetan and Himalayan Digital Library +have been developing several Tibetan language and culture related +software tools, all of which take advantage of Tony Duff's free +cross-platform TibetanMachineWeb fonts. We think these tools have +reached a level of development that they now need the active +participation of the larger programming community in order to +progress. +

+ +

+On the one hand, we've developed Java-based tools for inputting and +displaying Tibetan script (Jskad), as well as for the transcription of +Tibetan-language videos (QuillDriver), and the synchronized playback +of videos along with their associated transcripts (Savant). +

+ +

+On the other hand, recognizing the ubiquity of Word, we've also +developed Visual Basic macros for inputting Tibetan script (WylieWord) +and diacritics useful for Asian studies (DiacriticsForWord, +DiacriticsForWin2k) into Microsoft Word. +

+ +

+The Java side of our project has several goals. First, we'd like to +create a high quality cross-platform word processor/display engine +optimized for Tibetan script input and display. This probably means +embedding Jskad in an established open source text editor. +

+ +

+Second, we are developing educational and research-oriented software +that takes advantage of these basic Tibetan display +capabilities. QuillDriver, designed for transcription of videos, and +Savant, an integrated tool for learning language from digital video, +are examples of this. Here, several tasks are on the horizon: merging +QuillDriver and Savant into the same tool, which has both edit +(QuillDriver) and display (Savant) modes; and integrating both with +Tibetan dictionary, grammar and pedagogy modules also being developed +at the THDL. Finally, note that unlike Jskad, both QuillDriver and +Savant are meant to be truly multilingual, and not just specialized +Tibetan software. +

+ +

+Still, we know that no matter what the open source community does, +Microsoft Word will still remain the most dominant (and arguably the +best) word-processor. There will always be people, and always +occasions, to type Tibetan into Word. Therefore, we are also pushing +our Visual Basic macros for Tibetan and diacritic input. Our main +goals with these tools is to make them as bug-free and user-friendly +as possible, and to develop stable Mac versions. Another possible goal +would be to extend these tools to work with other Office applications, +such as Excel or Access. +

+ +

+Given the various projects, we are setting up several forums for +specialized discussion: +

+ +

+1) General +2) Jskad +3) QuillDriver/Savant +4) WylieWord +5) Diacritics +

+ +

+Please occasionally consult those forums of interest to you. Also, +please take a look at the mailing lists and subscribe to those you +want to follow. +

+ +

+Spread the word: THDL Tools are on SourceForge! +

+ + +