diff --git a/source/org/thdl/tib/input/DuffPane.java b/source/org/thdl/tib/input/DuffPane.java index 0354ecd..60a367b 100644 --- a/source/org/thdl/tib/input/DuffPane.java +++ b/source/org/thdl/tib/input/DuffPane.java @@ -1,1376 +1,1450 @@ -/* -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.input; - -import java.util.*; -import java.awt.*; -import java.awt.datatransfer.*; -import java.awt.font.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.text.*; -import java.lang.*; -import org.thdl.tib.text.*; - -/** -* Enables input of Tibetan text -* using Tibetan Computer Company's free cross-platform TibetanMachineWeb fonts. -* Two modes of text entry are allowed. In Tibetan mode, keystrokes are intercepted -* and reinterpreted according to the Tibetan keyboard installed. The result, of -* course, is Tibetan text, in the TibetanMachineWeb encoding. In Roman mode, -* keystrokes are not intercepted, and the font defaults to a Roman or user-defined font. -* @author Edward Garrett, Tibetan and Himalayan Digital Library -* @version 1.0 -*/ -public class DuffPane extends JTextPane implements KeyListener, FocusListener { -/* -* A central part of the Tibetan keyboard. As keys are typed, they are -* added to charList if they constitute a valid Wylie character. charList -* is added to in this manner until the user types punctuation, a vowel, -* or some action or function key. Later, when glyphs are printed to the -* screen, the {@link #newGlyphList glyphList}) is computed on the basis -* of charList. -*/ - private java.util.LinkedList charList; -/* -* This field holds a copy of the last {@link #newGlyphList}. -* Then, when a key is pressed, {@link #charList} is updated, a new -* newGlyphList is computed, and the newGlyphList is compared against -* this field. The text on the screen is then modified to reflect -* the new newGlyphList. -*/ - private java.util.List oldGlyphList; -/* -* A central component of the Tibetan input method. While {@link #charList charList} -* keeps track of the characters that have been entered, it does not organize them -* correctly into the proper glyphs. For example, charList might have four characters -* in it, 'b', 's', 'g', and 'r', but it does not know that they should be drawn as -* two glyphs, 'b' and 's-g-r'. newGlyphList is a list of glyphs -* ({@link thdl.tibetan.text.DuffCode DuffCodes}) which is formed by -* @link #recomputeGlyphs(boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) recomputeGlyphs}, -* which constructs an optimal arrangement of glyphs from the charList. -*/ - private java.util.List newGlyphList; -/* -* This field keeps track of what is currently being typed, to account -* for characters (such as Wylie 'tsh') which correspond to more than one -* keystroke in the keyboard. It is cleared or readjusted when it is clear -* that the user has moved on to a different character. For example, after the -* user types 'khr', holdCurrent will contain only 'r', since 'khr' is not -* a valid character. -*/ - private StringBuffer holdCurrent; -/* -* This field says whether or not the character atop {@link #charList} has -* been finalized, and therefore whether subsequent keystrokes are -* allowed to displace this character. For example, if 'k' is at the top -* of charList, and isTopHypothesis is true, then typing 'h' would replace -* 'k' with 'kh'. On the other hand, were isTopHypothesis false, then typing -* 'h' would add 'h' to the top of charList instead. -*/ - private boolean isTopHypothesis; -/* -* Is the user in the process of typing a vowel? -*/ - private boolean isTypingVowel; -/* -* Is it definitely the case that the user is typing Tibetan, rather than -* Sanskrit? -*/ - private boolean isDefinitelyTibetan; -/* -* According to the active keyboard, what value is -* {@link #isDefinitelyTibetan} assigned by default when the -* keyboard is initialized by {@link #initKeyboard() initKeyboard}? -*/ - private boolean isDefinitelyTibetan_default; -/* -* According to the active keyboard, what value should -* be assigned to {@link #isDefinitelyTibetan} if the -* user has initiated a stack by typing a stack key? -* For example, in the Wylie keyboard, there is a Sanskrit -* stacking key ('+'), but no Tibetan stacking key. -* Therefore, if the user is stacking with '+', this field -* should be false, since what the user is typing must -* be Sanskrit, not Tibetan. -*/ - private boolean isDefinitelyTibetan_withStackKey; -/* -* Is it definitely the case that the user is typing Sanskrit -* (e.g. a Sanskrit stack), rather than Tibetan? -*/ - private boolean isDefinitelySanskrit; -/* -* According to the active keyboard, what value is -* {@link #isDefinitelySanskrit} assigned by default when the -* keyboard is initialized by {@link #initKeyboard() initKeyboard}? -*/ - private boolean isDefinitelySanskrit_default; -/* -* According to the active keyboard, what value should -* be assigned to {@link #isDefinitelySanskrit} if the -* user has initiated a stack by typing a stack key? -* For example, in the Wylie keyboard, there is a Sanskrit -* stacking key ('+'), but no Tibetan stacking key. -* Therefore, if the user is stacking with '+', this field -* should be true, since what the user is typing must -* be Sanskrit, not Tibetan. -*/ - private boolean isDefinitelySanskrit_withStackKey; -/* -* Is consonant stacking allowed at the moment? In the Wylie -* keyboard, consonant stacking is usually on, since stacking -* is automatic. However, in the TCC and Sambhota keyboards, -* stacking is off by default, since you can only stack when -* you've pressed a stacking key. -*/ - private boolean isStackingOn; -/* -* According to the active keyboard, is stacking on by -* default or not, assuming no stack key has been pressed? -*/ - private boolean isStackingOn_default; -/* -* Automatic stacking in Wylie is from right to left. For -* example, if the user types 'brg', the resulting glyph -* sequence is 'b' plus 'rg', not 'br' plus 'g'. If -* stacking results from the use of a stack key, -* it is from left to right. -*/ - private boolean isStackingRightToLeft; -/* -* If the character last displayed was a vowel, -* how many glyphs is the vowel composed of? -* (Some vowels, such as Wylie 'I', consist of -* two glyphs.) -*/ - private int numberOfGlyphsForLastVowel; -/* -* used for tracking changes in Wylie to TMW conversion -*/ - private int lastStart; -/* -* is the user in Tibetan typing mode? this is true -* by default -*/ - private boolean isTibetan = true; -/* -* is the user allowed to type non-Tibetan? this is true -* by default -*/ - private boolean isRomanEnabled = true; -/* -* The document displayed by this object. -*/ - private TibetanDocument doc; -/* -* The caret of {@link #doc}, used to keep track of the -* current entry/edit/deletion position. -*/ - private Caret caret; - private StyledEditorKit editorKit; - private StyleContext styleContext; - private Style rootStyle; - private boolean skipUpdate = false; - private boolean isCutAndPasteEnabled = true; - - private String romanFontFamily; - private int romanFontSize; - private MutableAttributeSet romanAttributeSet; - - public DuffPane() { - this(new StyledEditorKit()); - } - - public DuffPane(TibetanKeyboard keyboard) { - this(new StyledEditorKit(), keyboard); - } - - public DuffPane(java.net.URL keyboardURL) { - this(new StyledEditorKit(), keyboardURL); - } - - public DuffPane(StyledEditorKit styledEditorKit) { - setupKeyboard(); - setupEditor(styledEditorKit); - } - - public DuffPane(StyledEditorKit styledEditorKit, TibetanKeyboard keyboard) { - TibetanMachineWeb.setKeyboard(keyboard); - setupKeyboard(); - setupEditor(styledEditorKit); - } - - public DuffPane(StyledEditorKit styledEditorKit, java.net.URL keyboardURL) { - TibetanMachineWeb.setKeyboard(keyboardURL); - setupKeyboard(); - setupEditor(styledEditorKit); - } - -/** -* This method sets up the editor, assigns fonts and point sizes, -* sets the document, the caret, and adds key and focus listeners. -* -* @param sek the StyledEditorKit for the editing window -*/ - private void setupEditor(StyledEditorKit sek) { - romanFontFamily = "Serif"; - romanFontSize = 14; - setRomanAttributeSet(romanFontFamily, romanFontSize); - - editorKit = sek; - setEditorKit(editorKit); - styleContext = new StyleContext(); - - Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE); - rootStyle = styleContext.addStyle("RootStyle", defaultStyle); - StyleConstants.setFontFamily(rootStyle, "TibetanMachineWeb"); - StyleConstants.setFontSize(rootStyle, 36); - setLogicalStyle(rootStyle); - - newDocument(); - caret = getCaret(); - - addKeyListener(this); - addFocusListener(this); - } - -/** -* This method sets up the Tibetan keyboard. Initially it is called -* by the constructor, but it is also called internally whenever -* the active keyboard is changed. It first sets various values with -* respect to stacking, and concerning the differences between -* Tibetan and Sanskrit; and then it initializes the input method. -*/ - private void setupKeyboard() { - if (TibetanMachineWeb.hasTibetanStackingKey()) { - if (TibetanMachineWeb.hasSanskritStackingKey()) { - isDefinitelyTibetan_default = false; - isDefinitelySanskrit_default = false; - isStackingOn_default = false; - isDefinitelyTibetan_withStackKey = false; - isDefinitelySanskrit_withStackKey = false; - } - else { - isDefinitelyTibetan_default = false; - isDefinitelySanskrit_default = true; - isStackingOn_default = true; - isDefinitelyTibetan_withStackKey = true; - isDefinitelySanskrit_withStackKey = false; - } - } - else { - if (TibetanMachineWeb.hasSanskritStackingKey()) { - isDefinitelyTibetan_default = true; - isDefinitelySanskrit_default = false; - isStackingOn_default = true; - isDefinitelyTibetan_withStackKey = false; - isDefinitelySanskrit_withStackKey = true; - } - else { //no stacking key at all - isDefinitelyTibetan_default = false; - isDefinitelySanskrit_default = false; - isStackingOn_default = true; - } - } - charList = new LinkedList(); - oldGlyphList = new ArrayList(); - newGlyphList = new ArrayList(); - initKeyboard(); - } - -/** -* Registers the Extended Wylie keyboard, and sets it as -* the active keyboard. -* Unpredictable behavior will result -* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} -* but don't register it here. -*/ - public void registerKeyboard() { - TibetanKeyboard tk = null; - registerKeyboard(tk); - } - -/** -* Registers a keyboard, and sets it as -* the active keyboard. * Unpredictable behavior will result -* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} -* but don't register it in here. -* @param keyboardURL the URL of the keyboard you want to install -*/ - public void registerKeyboard(java.net.URL keyboardURL) { - TibetanMachineWeb.setKeyboard(keyboardURL); - setupKeyboard(); - } - -/** -* Registers a keyboard, and sets it as -* the active keyboard. -* Unpredictable behavior will result -* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} -* but don't register it in here. -* @param keyboard the keyboard you want to install -*/ - public void registerKeyboard(TibetanKeyboard keyboard) { - TibetanMachineWeb.setKeyboard(keyboard); - setupKeyboard(); - } - -/** -* Clears the current document. -*/ - public void newDocument() { - doc = new TibetanDocument(styleContext); - doc.setTibetanFontSize(36); - setDocument(doc); - setLogicalStyle(rootStyle); - } - -/** -* Initializes the keyboard input interpreter, setting all properties -* back to their default states. This method is called whenever an action -* or function key is pressed, and also whenever the user types punctuation -* or a vowel. It is not called when the user is typing characters that -* could be part of a stack, or require manipulation of glyphs - e.g. -* backspacing, redrawing, etc. -*/ - public void initKeyboard() { - charList.clear(); - oldGlyphList.clear(); - holdCurrent = new StringBuffer(); - isTopHypothesis = false; - isTypingVowel = false; - numberOfGlyphsForLastVowel = 0; - - //for keyboard - isStackingOn = isStackingOn_default; - isStackingRightToLeft = true; - isDefinitelyTibetan = isDefinitelyTibetan_default; - isDefinitelySanskrit = isDefinitelySanskrit_default; - } - -/** -* Enables typing of Roman (non-Tibetan) text along -* with Tibetan. -*/ - public void enableRoman() { - isRomanEnabled = true; - } - -/** -* Disables typing of Roman (non-Tibetan) text. -*/ - public void disableRoman() { - isRomanEnabled = false; - } - -/** -* Checks to see if Roman input is enabled. -* @return true if so, false if not -*/ - public boolean isRomanEnabled() { - return isRomanEnabled; - } - -/** -* Checks to see if currently in Roman input mode. -* @return true if so, false if not -*/ - public boolean isRomanMode() { - return !isTibetan; - } - -/** -* Toggles between Tibetan and Roman input modes. -* Does nothing if Roman input is disabled. -* @see #enableRoman() -* @see #disableRoman() -*/ - public void toggleLanguage() { - if (isTibetan && isRomanEnabled) - isTibetan = false; - else - isTibetan = true; - } - -/** -* Inserts Roman text into this object's document, -* at the position of the caret. -* @param attr the attributes for the text to insert -* @param s the string of text to insert -*/ - public void append(String s, MutableAttributeSet attr) { - append(caret.getDot(), s, attr); - } - -/** -* Inserts Roman text into this object's document. -* @param offset the position at which to insert text -* @param attr the attributes for the text to insert -* @param s the string of text to insert -*/ - public void append(int offset, String s, MutableAttributeSet attr) { - try { - doc.insertString(offset, s, attr); - } - catch (BadLocationException ble) { - } - } - -/** -* Changes the default font size for Tibetan text entry mode. -* -* @param size a point size -*/ - public void setTibetanFontSize(int size) { - if (size > 0) - doc.setTibetanFontSize(size); - } - -/** -* Gets the current point size for Tibetan text. -* @return the current default font size for Tibetan -* text entry mode -*/ - public int getTibetanFontSize() { - return doc.getTibetanFontSize(); - } - -/** -* Changes the default font and font size for -* non-Tibetan (Roman) text entry mode. -* -* @param font a font name -* @param size a point size -*/ - public void setRomanAttributeSet(String font, int size) { - romanAttributeSet = new SimpleAttributeSet(); - StyleConstants.setFontFamily(romanAttributeSet, font); - StyleConstants.setFontSize(romanAttributeSet, size); - } - -/** -* Gets the current point size for non-Tibetan text. -* @return the current default font size for non-Tibetan -* (Roman) text entry mode -*/ - public int getRomanFontSize() { - return romanFontSize; - } - -/** -* Gets the current font used for non-Tibetan text. -* @return the current default font for non-Tibetan -* (Roman) text entry mode -*/ - public String getRomanFontFamily() { - return romanFontFamily; - } - -/** -* Backspace and remove k elements from the current caret position. -* -* @param k the number of glyphs to remove by backspace -*/ - private void backSpace(int k) { - try { - doc.remove(caret.getDot()-k, k); - } - catch (BadLocationException ble) { - } - } - -/** -* Takes an old glyph list, which should be the currently visible set of glyphs preceding the cursor, and -* then tries to redraw the glyphs in light of the newly acquired keyboard input (which led to a revised -* 'new' glyph list). For example, the old glyph list might contain 'l' and 'n', because the user had typed -* 'ln' in Extended Wylie mode. This is what you'd see on the screen. But assume that the new glyph list -* contains the stacked glyph 'l-ng', because the user has just finished typing 'lng'. This method -* compares the glyphs, then figures out whether or not backspacing is necessary, and draws whatever characters -* need to be drawn. -* For example, suppose that oldGlyphList contains the two glyphs 'l' and 'n', and newGlyphList contains a single glyph, 'lng'. -* In this case, redrawGlyphs will be instructed to backspace over both 'l' and 'n', and then insert 'lng'. -*/ - private java.util.List redrawGlyphs(java.util.List oldGlyphList, java.util.List newGlyphList) { - if (newGlyphList.isEmpty()) - return newGlyphList; - - Iterator newIter = newGlyphList.iterator(); - DuffCode newDc = (DuffCode)newIter.next(); - - int oldGlyphCount = oldGlyphList.size(); - int newGlyphCount = newGlyphList.size(); - int beginDifference = -1; //at what point does the new glyph list begin to differ from the old one? - int k=0; - - if (oldGlyphCount!=0) { - int smallerGlyphCount; - DuffCode oldDc; - - if (oldGlyphCount < newGlyphCount) - smallerGlyphCount = oldGlyphCount; - else - smallerGlyphCount = newGlyphCount; - - Iterator oldIter = oldGlyphList.iterator(); - - for (; k newGlyphCount) - backSpace(oldGlyphCount-newGlyphCount); //deals with 'pd+m' problem - - return newGlyphList; //there is no difference between new and old glyph lists - } - } - - if (beginDifference != -1) - backSpace(oldGlyphCount - beginDifference); - - java.util.List sublist = newGlyphList.subList(k, newGlyphCount); - TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(sublist); - doc.insertDuff(caret.getDot(), dd); - return newGlyphList; - } - -/** -* Tries to insert the vowel v at the position of the caret. -* This method must deal with various issues, such as: can the preceding -* glyph take a vowel? If not, then what? If the preceding glyph can be -* followed by a vowel, then the method has to figure out what vowel -* glyph to affix, which may depend on the immediately preceding glyph, -* but may depend on other factors as well. For example, when affixing -* gigu to the consonantal stack "k'" (ie k plus achung), the value of -* the gigu will depend on "k", not "'". -* -* @param v the vowel (in Wylie) you want to insert -*/ - private void putVowel(String v) { - if (caret.getDot()==0) { - if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) - printAChenWithVowel(v); - - return; - } - - AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); - String fontName = StyleConstants.getFontFamily(attr); - int fontNum; - - if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { - try { - char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); - int k = (int)c2; - if (k<32 || k>126) { //if previous character is formatting or some other non-character - if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) - printAChenWithVowel(v); - - return; - } - - String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); - if (TibetanMachineWeb.isWyliePunc(wylie)) { - if (charList.isEmpty() && !TibetanMachineWeb.isAChenRequiredBeforeVowel()) { - printAChenWithVowel(v); - return; - } - } - - DuffCode dc_1 = null; - DuffCode dc_2 = new DuffCode(fontNum, c2); - - if (caret.getDot() > 2) { - attr = doc.getCharacterElement(caret.getDot()-2).getAttributes(); - fontName = StyleConstants.getFontFamily(attr); - if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { - c2 = doc.getText(caret.getDot()-2, 1).charAt(0); - dc_1 = new DuffCode(fontNum, c2); - } - } - - java.util.List before_vowel = new ArrayList(); - if (null != dc_1) - before_vowel.add(dc_1); - - before_vowel.add(dc_2); - java.util.List after_vowel = TibetanDocument.getVowel(dc_1, dc_2, v); - redrawGlyphs(before_vowel, after_vowel); - } - catch(BadLocationException ble) { - System.out.println("no--can't insert here"); - } - } - else { //0 font means not Tibetan font, so begin new Tibetan font section - if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) - printAChenWithVowel(v); - } - } - -/** -* Prints ACHEN together with the vowel v. When using the Wylie -* keyboard, or any other keyboard in which {@link thdl.tibetan.text.TibetanMachineWeb#isAChenRequiredBeforeVowel() isAChenRequiredBeforeVowel()} -* is false, this method is called frequently. -* -* @param v the vowel (in Wylie) which you want to print with ACHEN -*/ - private void printAChenWithVowel(String v) { - DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); - DuffCode dc = dc_array[TibetanMachineWeb.TMW]; - java.util.List achenlist = TibetanDocument.getVowel(dc,v); - TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(achenlist); - doc.insertDuff(caret.getDot(), dd); - } - -/** -* Puts a bindu/anusvara at the current caret position. -* In the TibetanMachineWeb font, top vowels (like gigu, -* drengbu, etc.) are merged together with bindu in a -* single glyph. This method deals with the problem of -* correctly displaying a bindu given this complication. -*/ - private void putBindu() { - special_bindu_block: { - if (caret.getDot()==0) - break special_bindu_block; - - AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); - String fontName = StyleConstants.getFontFamily(attr); - int fontNum; - - if (0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) - break special_bindu_block; - - try { - char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); - int k = (int)c2; - if (k<32 || k>126) //if previous character is formatting or some other non-character - break special_bindu_block; - - String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); - if (!TibetanMachineWeb.isWylieVowel(wylie)) - break special_bindu_block; - - DuffCode dc = new DuffCode(fontNum, c2); - java.util.List beforecaret = new ArrayList(); - beforecaret.add(dc); - java.util.List bindulist = TibetanDocument.getBindu(dc); - redrawGlyphs(beforecaret, bindulist); - initKeyboard(); - return; - } - catch(BadLocationException ble) { - System.out.println("no--can't do this bindu maneuver"); - } - } - - TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(TibetanDocument.getBindu(null)); - doc.insertDuff(caret.getDot(), dd); - initKeyboard(); - } - -/** -* Required by implementations of the -* {@link java.awt.event.FocusListener FocusListener} interface, -* this method simply initializes the keyboard whenever this -* object gains focus. -* -* @param e a FocusEvent -*/ - public void focusGained(FocusEvent e) { - } - -/** -* Required by implementations of the -* {@link java.awt.event.FocusListener FocusListener} interface, -* this method does nothing. -* -* @param e a FocusEvent -*/ - public void focusLost(FocusEvent e) { - initKeyboard(); - } - -/** -* Cuts or copies the specified portion of this object's document -* to the system clipboard. What is cut/copied is Wylie text - -* so, if you cut/copy a region of TibetanMachineWeb, it first converts -* it to Wylie before putting it on the clipboard. If the user -* tries to cut/copy non-TibetanMachineWeb, only the text preceding the -* first non-TibetanMachineWeb character is cut/copied. -* @param start the begin offset of the copy -* @param end the end offset of the copy -* @param remove this should be true if the operation is 'cut', -* false if it is 'copy' -*/ - public void copy(int start, int end, boolean remove) { - if (start < end) { - java.util.List dcs = new ArrayList(); - - try { - AttributeSet attr; - String fontName; - int fontNum; - DuffCode dc; - char ch; - - int i = start; - - while (i < end+1) { - attr = doc.getCharacterElement(i).getAttributes(); - fontName = StyleConstants.getFontFamily(attr); - - if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==end) { - if (i != start) { - DuffCode[] dc_array = new DuffCode[0]; - dc_array = (DuffCode[])dcs.toArray(dc_array); - StringSelection data = new StringSelection(TibetanDocument.getWylie(dc_array)); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(data, data); - if (remove) { - doc.remove(start, i-start); - setSelectionEnd(start); - } - else { - setSelectionStart(start); - setSelectionEnd(i); - } - return; - } - else { - setSelectionEnd(start); - return; - } - } - else { - ch = doc.getText(i,1).charAt(0); - dc = new DuffCode(fontNum, ch); - dcs.add(dc); - } - i++; - } - } - catch (BadLocationException ble) { - ble.printStackTrace(); - } - } - } - -/** -* Pastes the contents of the system clipboard into this object's -* document, at the specified position. The only kind of -* text accepted from the clipboard is Wylie text. -* This Wylie is converted and pasted into the document as -* TibetanMachineWeb. If the text to paste is invalid Wylie, -* then it will not be pasted, and instead an error message will -* appear. -* @param offset the position in the document you want to paste to -*/ - public void paste(int offset) { - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - Transferable data = clipboard.getContents(this); - - String s = null; - try { - s = (String)(data.getTransferData(DataFlavor.stringFlavor)); - } - catch (Exception e) { - s = data.toString(); - } - - if (s != null) - toTibetanMachineWeb(s, offset); - } - -/** -* Enables cutting and pasting of Tibetan text. -*/ - public void enableCutAndPaste() { - isCutAndPasteEnabled = true; - } - -/** -* Disables cutting and pasting of Tibetan text. -* Cut and paste must be disabled if Jskad's -* parent is an applet, because it violates the -* Java security sandbox to cut and paste from an -* applet to the system clipboard. -*/ - public void disableCutAndPaste() { - isCutAndPasteEnabled = false; - } - -/** -* This method is required as part of the -* implementation of the KeyListener -* interface. -* -* Basically this method only handles action keys - -* Escape, Ctrl-c, Ctrl-x, etc, and TAB and ENTER. -* Other keystrokes are handled by keyTyped. -*/ - public void keyPressed(KeyEvent e) { - if (e.isActionKey()) - initKeyboard(); - - int code = e.getKeyCode(); - - switch (code) { - case KeyEvent.VK_ESCAPE: - e.consume(); - initKeyboard(); -// toggleLanguage(); - break; - - case KeyEvent.VK_A: - if (e.isControlDown() && isCutAndPasteEnabled) { - e.consume(); - setSelectionStart(0); - setSelectionEnd(doc.getLength()); - } - break; - - case KeyEvent.VK_C: - if (e.isControlDown() && isCutAndPasteEnabled) { - e.consume(); - copy(getSelectionStart(), getSelectionEnd(), false); - } - break; - - case KeyEvent.VK_X: - if (e.isControlDown() && isCutAndPasteEnabled) { - e.consume(); - copy(getSelectionStart(), getSelectionEnd(), true); - } - break; - - case KeyEvent.VK_V: - if (e.isControlDown() && isCutAndPasteEnabled) { - e.consume(); - paste(caret.getDot()); - } - break; - - case KeyEvent.VK_TAB: - e.consume(); - initKeyboard(); - if (isTibetan) - doc.appendDuff(caret.getDot()," ",TibetanMachineWeb.getAttributeSet(1)); - else - append(" ", romanAttributeSet); - break; - - case KeyEvent.VK_ENTER: - e.consume(); - initKeyboard(); - if (isTibetan) - doc.appendDuff(caret.getDot(),"\n",TibetanMachineWeb.getAttributeSet(1)); - else - append("\n", romanAttributeSet); - break; - } - } - -/** -* Required of implementations of the Key Listener interface, -* this method does (almost) nothing. -* -* @param e the KeyEvent -*/ - public void keyReleased(KeyEvent e) { -/* -* Apparently it works best to check for backspace -* and init the keyboard here in key released -* though i don't really know why... -*/ - int code = e.getKeyCode(); - - if (code == KeyEvent.VK_BACK_SPACE) - initKeyboard(); - } - -/** -* Required of implementations of the KeyListener interface, -* this method handles the pressing of non-control and non-action keys. If the user -* is in Tibetan typing mode, then the KeyEvent -* e is consumed, and passed on to {@link #processTibetan(KeyEvent e)}, which -* contains the meat of the keyboard logic. If the user is in English mode, then -* {@link #append(String s, MutableAttributeSet attr) append} is called. -* -* @param e a KeyEvent -*/ - public void keyTyped(KeyEvent e) { - e.consume(); - - if (isTibetan) - processTibetan(e); - else { - if (e.isControlDown() || e.isAltDown()) - return; - - char c = e.getKeyChar(); - - switch (c) { - case KeyEvent.VK_TAB: - case KeyEvent.VK_ENTER: - case KeyEvent.VK_ESCAPE: - break; - - case KeyEvent.VK_BACK_SPACE: - backSpace(1); - break; - - default: - append(String.valueOf(c), romanAttributeSet); - } - } - } - -/** -* Interprets a key typed during Tibetan input mode. -* This method keeps track of which characters the user has and is typing, -* and also of whether or not the user is in stacking -* mode. Most of the keyboard logic can be found here. -* -* @param e a KeyEvent -*/ - public void processTibetan(KeyEvent e) { - char c = e.getKeyChar(); - - int start = getSelectionStart(); - int end = getSelectionEnd(); - boolean shouldIBackSpace = true; - - if (e.isControlDown() || e.isAltDown()) - return; - - if (start != end) { - if (e.getKeyCode() != KeyEvent.VK_ESCAPE) { - try { - initKeyboard(); - doc.remove(start, end-start); - shouldIBackSpace = false; - } - catch (BadLocationException ble) { - } - } - } - - key_block: - { - - if (TibetanMachineWeb.hasDisambiguatingKey()) - if (c == TibetanMachineWeb.getDisambiguatingKey()) { - initKeyboard(); - break key_block; - }; - - if (TibetanMachineWeb.hasSanskritStackingKey() || TibetanMachineWeb.hasTibetanStackingKey()) { - if (c == TibetanMachineWeb.getStackingKey()) { - if (TibetanMachineWeb.isStackingMedial()) { - int size = charList.size(); - - if (size == 0) - initKeyboard(); - - else if (size > 1 && isStackingRightToLeft) { - String s = (String)charList.removeLast(); - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - initKeyboard(); - charList.add(s); - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - holdCurrent = new StringBuffer(); - isTopHypothesis = false; - isStackingOn = true; - isStackingRightToLeft = false; - isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; - isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; - } - else { - holdCurrent = new StringBuffer(); - isTopHypothesis = false; - isStackingOn = true; - isStackingRightToLeft = false; - isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; - isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; - } - break key_block; - } - else { //stacking must be pre/post - if (!isStackingOn || (isStackingOn && isDefinitelyTibetan==isDefinitelyTibetan_default)) { - initKeyboard(); - isStackingOn = true; - isStackingRightToLeft = false; - isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; - isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; - } - else {try { - char ch = doc.getText(caret.getDot()-1, 1).charAt(0); - AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); - String fontName = StyleConstants.getFontFamily(attr); - int fontNum = TibetanMachineWeb.getTMWFontNumber(fontName); - - if (0 == fontNum) { - initKeyboard(); - isStackingOn = true; - isStackingRightToLeft = false; - isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; - isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; - } - else { - initKeyboard(); - DuffCode dc = new DuffCode(fontNum, ch); - - if (!TibetanMachineWeb.isStack(dc) && !TibetanMachineWeb.isSanskritStack(dc)) { - isStackingOn = true; - isStackingRightToLeft = false; - isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; - isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; - } - } - } - catch (BadLocationException ble) { - initKeyboard(); - }} - break key_block; - } - } - } - - switch (c) { - case KeyEvent.VK_TAB: - case KeyEvent.VK_ENTER: - case KeyEvent.VK_ESCAPE: - initKeyboard(); - break; - - case KeyEvent.VK_BACK_SPACE: - if (shouldIBackSpace) { - backSpace(1); - break; - } - - default: - String val = String.valueOf(c); - - if (TibetanMachineWeb.isPunc(val)) { //punctuation - val = TibetanMachineWeb.getWylieForPunc(val); - - if (val.charAt(0) == TibetanMachineWeb.BINDU) - putBindu(); - - else { - DuffCode puncDc = TibetanMachineWeb.getGlyph(val); - MutableAttributeSet mas = TibetanMachineWeb.getAttributeSet(puncDc.getFontNum()); - doc.appendDuff(caret.getDot(), String.valueOf(puncDc.getCharacter()), mas); - } - - initKeyboard(); - return; - } - - if (charList.size()==0) { //add current character to charList if possible - holdCurrent.append(c); - String s = holdCurrent.toString(); - - if (TibetanMachineWeb.isVowel(s)) { - s = TibetanMachineWeb.getWylieForVowel(s); - - if (isTypingVowel) //note: this takes care of multiple keystroke vowels like 'ai' - backSpace(numberOfGlyphsForLastVowel); - - putVowel(s); - isTypingVowel = true; - } - else { - if (isTypingVowel) { - isTypingVowel = false; - s = String.valueOf(c); - holdCurrent = new StringBuffer(s); - } - - if (TibetanMachineWeb.isVowel(s)) { - s = TibetanMachineWeb.getWylieForVowel(s); - putVowel(s); - isTypingVowel = true; - } - - else if (TibetanMachineWeb.isChar(s)) { - s = TibetanMachineWeb.getWylieForChar(s); - charList.add(s); - isTopHypothesis = true; - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - } - else - isTopHypothesis = false; - } - } - else { //there is already a character in charList - holdCurrent.append(c); - String s = holdCurrent.toString(); - - if (TibetanMachineWeb.isVowel(s)) { //the holding string is a vowel - s = TibetanMachineWeb.getWylieForVowel(s); - initKeyboard(); - isTypingVowel = true; - putVowel(s); - } - else if (TibetanMachineWeb.isChar(s)) { //the holding string is a character - String s2 = TibetanMachineWeb.getWylieForChar(s); - - if (isTopHypothesis) { - if (TibetanMachineWeb.isAChungConsonant() && isStackingOn && charList.size()>1 && s2.equals(TibetanMachineWeb.ACHUNG)) { - charList.removeLast(); - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - putVowel(TibetanMachineWeb.A_VOWEL); - initKeyboard(); - break key_block; - } - charList.set(charList.size()-1, s2); - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - } - else { - if (!isStackingOn) { - initKeyboard(); - holdCurrent = new StringBuffer(s); - } - else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { - putVowel(TibetanMachineWeb.A_VOWEL); - initKeyboard(); - break key_block; - } - - charList.add(s2); - isTopHypothesis = true; - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - } - } - else { //the holding string is not a character - if (isTopHypothesis) { //finalize top character and add new hypothesis to top - holdCurrent = new StringBuffer(); - holdCurrent.append(c); - s = holdCurrent.toString(); - - if (TibetanMachineWeb.isVowel(s)) { - String s2 = TibetanMachineWeb.getWylieForVowel(s); - putVowel(s2); - initKeyboard(); - isTypingVowel = true; - holdCurrent = new StringBuffer(s); - } - else { - if (TibetanMachineWeb.isStackingMedial() && !isStackingRightToLeft) - initKeyboard(); - - if (TibetanMachineWeb.isChar(s)) { - String s2 = TibetanMachineWeb.getWylieForChar(s); - - if (!isStackingOn) - initKeyboard(); - - else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { - putVowel(TibetanMachineWeb.A_VOWEL); - initKeyboard(); - break key_block; - } - - charList.add(s2); - newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); - oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); - } - else { - holdCurrent = new StringBuffer(s); - isTopHypothesis = false; - } - } - } - else { //top char is just a guess! just keep it in holdCurrent - } - } - } - } //end switch - } //end key_block - } - -/** -* Converts the entire document to Extended Wylie. -*/ - public void toWylie() { - int start = getSelectionStart(); - int end = getSelectionEnd(); - - toWylie(start, end); - } - -/** -* Converts the specified portion -* of this object's document to Extended Wylie. -* -* @param start the point from which to begin converting to Wylie -* @param end the point at which to stop converting to Wylie -*/ - public void toWylie(int start, int end) { - if (start == end) - return; - - DuffCode[] dc_array; - AttributeSet attr; - String fontName; - Position endPos; - int fontNum; - DuffCode dc; - char ch; - int i; - - java.util.List dcs = new ArrayList(); - - try { - endPos = doc.createPosition(end); - i = start; - - while (i < endPos.getOffset()+1) { - attr = doc.getCharacterElement(i).getAttributes(); - fontName = StyleConstants.getFontFamily(attr); - - if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { - if (i != start) { - dc_array = new DuffCode[0]; - dc_array = (DuffCode[])dcs.toArray(dc_array); - doc.remove(start, i-start); - append(start, TibetanDocument.getWylie(dc_array), romanAttributeSet); - dcs.clear(); - } - start = i+1; - } - else { - ch = doc.getText(i,1).charAt(0); - dc = new DuffCode(fontNum, ch); - dcs.add(dc); - } - - i++; - } - } - catch (BadLocationException ble) { - ble.printStackTrace(); - } - } - -/** -* Converts a string of Extended Wylie to TibetanMachineWeb, and -* inserts it at the specified position. -* -* @param wylie the string of Wylie to convert -* @param offset the position at which to insert the conversion -*/ - public void toTibetanMachineWeb(String wylie, int offset) { - try { - TibetanDocument.DuffData[] dd = TibetanDocument.getTibetanMachineWeb(wylie); - doc.insertDuff(offset, dd); - } - catch (InvalidWylieException iwe) { - JOptionPane.showMessageDialog(this, - "The Wylie you are trying to convert is invalid, " + - "beginning from:\n " + iwe.getCulpritInContext() + "\n" + - "The culprit is probably the character '"+iwe.getCulprit()+"'."); - } - - } - -/** -* Converts the currently selected text from Extended Wylie to TibetanMachineWeb. -*/ - public void toTibetanMachineWeb() { - int start = getSelectionStart(); - int end = getSelectionEnd(); - - toTibetanMachineWeb(start, end); - } - -/** -* Converts a stretch of text from Extended Wylie to TibetanMachineWeb. -* @param start the begin point for the conversion -* @param end the end point for the conversion -*/ - public void toTibetanMachineWeb(int start, int end) { - if (start == end) - return; - - StringBuffer sb; - AttributeSet attr; - String fontName; - int fontNum; - Position endPos; - int i; - - try { - sb = new StringBuffer(); - endPos = doc.createPosition(end); - i = start; - - while (i < endPos.getOffset()+1) { - attr = doc.getCharacterElement(i).getAttributes(); - fontName = StyleConstants.getFontFamily(attr); - - if ((0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { - if (i != start) { - try { - TibetanDocument.DuffData[] duffdata = TibetanDocument.getTibetanMachineWeb(sb.toString()); - doc.remove(start, i-start); - doc.insertDuff(start, duffdata); - } - catch (InvalidWylieException iwe) { - JOptionPane.showMessageDialog(this, - "The Wylie you are trying to convert is invalid, " + - "beginning from:\n " + iwe.getCulpritInContext() + - "\nThe culprit is probably the character '" + - iwe.getCulprit() + "'."); - return; - } - } - start = i+1; - } - else - sb.append(doc.getText(i, 1)); - - i++; - } - } - catch (BadLocationException ble) { - ble.printStackTrace(); - } - } -} +/* +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.input; + +import java.util.*; +import java.awt.*; +import java.awt.datatransfer.*; +import java.awt.font.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.text.*; + +import java.lang.*; +import org.thdl.tib.text.*; + +import java.io.*; +import javax.swing.text.rtf.*; + +/** +* Enables input of Tibetan text +* using Tibetan Computer Company's free cross-platform TibetanMachineWeb fonts. +* Two modes of text entry are allowed. In Tibetan mode, keystrokes are intercepted +* and reinterpreted according to the Tibetan keyboard installed. The result, of +* course, is Tibetan text, in the TibetanMachineWeb encoding. In Roman mode, +* keystrokes are not intercepted, and the font defaults to a Roman or user-defined font. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class DuffPane extends JTextPane implements KeyListener, FocusListener { +/* +* A central part of the Tibetan keyboard. As keys are typed, they are +* added to charList if they constitute a valid Wylie character. charList +* is added to in this manner until the user types punctuation, a vowel, +* or some action or function key. Later, when glyphs are printed to the +* screen, the {@link #newGlyphList glyphList}) is computed on the basis +* of charList. +*/ + private java.util.LinkedList charList; +/* +* This field holds a copy of the last {@link #newGlyphList}. +* Then, when a key is pressed, {@link #charList} is updated, a new +* newGlyphList is computed, and the newGlyphList is compared against +* this field. The text on the screen is then modified to reflect +* the new newGlyphList. +*/ + private java.util.List oldGlyphList; +/* +* A central component of the Tibetan input method. While {@link #charList charList} +* keeps track of the characters that have been entered, it does not organize them +* correctly into the proper glyphs. For example, charList might have four characters +* in it, 'b', 's', 'g', and 'r', but it does not know that they should be drawn as +* two glyphs, 'b' and 's-g-r'. newGlyphList is a list of glyphs +* ({@link thdl.tibetan.text.DuffCode DuffCodes}) which is formed by +* @link #recomputeGlyphs(boolean areStacksOnRight, boolean definitelyTibetan, boolean definitelySanskrit) recomputeGlyphs}, +* which constructs an optimal arrangement of glyphs from the charList. +*/ + private java.util.List newGlyphList; +/* +* This field keeps track of what is currently being typed, to account +* for characters (such as Wylie 'tsh') which correspond to more than one +* keystroke in the keyboard. It is cleared or readjusted when it is clear +* that the user has moved on to a different character. For example, after the +* user types 'khr', holdCurrent will contain only 'r', since 'khr' is not +* a valid character. +*/ + private StringBuffer holdCurrent; +/* +* This field says whether or not the character atop {@link #charList} has +* been finalized, and therefore whether subsequent keystrokes are +* allowed to displace this character. For example, if 'k' is at the top +* of charList, and isTopHypothesis is true, then typing 'h' would replace +* 'k' with 'kh'. On the other hand, were isTopHypothesis false, then typing +* 'h' would add 'h' to the top of charList instead. +*/ + private boolean isTopHypothesis; +/* +* Is the user in the process of typing a vowel? +*/ + private boolean isTypingVowel; +/* +* Is it definitely the case that the user is typing Tibetan, rather than +* Sanskrit? +*/ + private boolean isDefinitelyTibetan; +/* +* According to the active keyboard, what value is +* {@link #isDefinitelyTibetan} assigned by default when the +* keyboard is initialized by {@link #initKeyboard() initKeyboard}? +*/ + private boolean isDefinitelyTibetan_default; +/* +* According to the active keyboard, what value should +* be assigned to {@link #isDefinitelyTibetan} if the +* user has initiated a stack by typing a stack key? +* For example, in the Wylie keyboard, there is a Sanskrit +* stacking key ('+'), but no Tibetan stacking key. +* Therefore, if the user is stacking with '+', this field +* should be false, since what the user is typing must +* be Sanskrit, not Tibetan. +*/ + private boolean isDefinitelyTibetan_withStackKey; +/* +* Is it definitely the case that the user is typing Sanskrit +* (e.g. a Sanskrit stack), rather than Tibetan? +*/ + private boolean isDefinitelySanskrit; +/* +* According to the active keyboard, what value is +* {@link #isDefinitelySanskrit} assigned by default when the +* keyboard is initialized by {@link #initKeyboard() initKeyboard}? +*/ + private boolean isDefinitelySanskrit_default; +/* +* According to the active keyboard, what value should +* be assigned to {@link #isDefinitelySanskrit} if the +* user has initiated a stack by typing a stack key? +* For example, in the Wylie keyboard, there is a Sanskrit +* stacking key ('+'), but no Tibetan stacking key. +* Therefore, if the user is stacking with '+', this field +* should be true, since what the user is typing must +* be Sanskrit, not Tibetan. +*/ + private boolean isDefinitelySanskrit_withStackKey; +/* +* Is consonant stacking allowed at the moment? In the Wylie +* keyboard, consonant stacking is usually on, since stacking +* is automatic. However, in the TCC and Sambhota keyboards, +* stacking is off by default, since you can only stack when +* you've pressed a stacking key. +*/ + private boolean isStackingOn; +/* +* According to the active keyboard, is stacking on by +* default or not, assuming no stack key has been pressed? +*/ + private boolean isStackingOn_default; +/* +* Automatic stacking in Wylie is from right to left. For +* example, if the user types 'brg', the resulting glyph +* sequence is 'b' plus 'rg', not 'br' plus 'g'. If +* stacking results from the use of a stack key, +* it is from left to right. +*/ + private boolean isStackingRightToLeft; +/* +* If the character last displayed was a vowel, +* how many glyphs is the vowel composed of? +* (Some vowels, such as Wylie 'I', consist of +* two glyphs.) +*/ + private int numberOfGlyphsForLastVowel; +/* +* used for tracking changes in Wylie to TMW conversion +*/ + private int lastStart; +/* +* is the user in Tibetan typing mode? this is true +* by default +*/ + private boolean isTibetan = true; +/* +* is the user allowed to type non-Tibetan? this is true +* by default +*/ + private boolean isRomanEnabled = true; +/* +* The document displayed by this object. +*/ + private TibetanDocument doc; +/* +* The caret of {@link #doc}, used to keep track of the +* current entry/edit/deletion position. +*/ + private Caret caret; +// private StyledEditorKit editorKit; + private StyleContext styleContext; + private Style rootStyle; + private boolean skipUpdate = false; + private boolean isCutAndPasteEnabled = true; + + private String romanFontFamily; + private int romanFontSize; + private MutableAttributeSet romanAttributeSet; + +public Clipboard rtfBoard; +public DataFlavor rtfFlavor; +public RTFEditorKit rtfEd = null; + + public DuffPane() { + setupKeyboard(); + setupEditor(); +// this(new StyledEditorKit()); + } + + public DuffPane(TibetanKeyboard keyboard) { + TibetanMachineWeb.setKeyboard(keyboard); + setupKeyboard(); + setupEditor(); +// this(new StyledEditorKit(), keyboard); + } + + public DuffPane(java.net.URL keyboardURL) { + TibetanMachineWeb.setKeyboard(keyboardURL); + setupKeyboard(); + setupEditor(); +// this(new StyledEditorKit(), keyboardURL); + } + +/* + public DuffPane() { + setupKeyboard(); + setupEditor(styledEditorKit); + } + + public DuffPane(TibetanKeyboard keyboard) { + TibetanMachineWeb.setKeyboard(keyboard); + setupKeyboard(); + setupEditor(); + } + + public DuffPane(java.net.URL keyboardURL) { + TibetanMachineWeb.setKeyboard(keyboardURL); + setupKeyboard(); + setupEditor(); + } +*/ + +/** +* This method sets up the editor, assigns fonts and point sizes, +* sets the document, the caret, and adds key and focus listeners. +* +* @param sek the StyledEditorKit for the editing window +*/ + public void setupEditor() { + rtfBoard = getToolkit().getSystemClipboard(); + rtfFlavor = new DataFlavor("text/rtf", "Rich Text Format"); + rtfEd = new RTFEditorKit(); + setEditorKit(rtfEd); + styleContext = new StyleContext(); + + doc = new TibetanDocument(styleContext); + doc.setTibetanFontSize(36); + setDocument(doc); + + Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE); + StyleConstants.setFontFamily(defaultStyle, "TibetanMachineWeb"); + StyleConstants.setFontSize(defaultStyle, 36); + + romanFontFamily = "Serif"; + romanFontSize = 14; + setRomanAttributeSet(romanFontFamily, romanFontSize); + +// newDocument(); + caret = getCaret(); + + addKeyListener(this); + addFocusListener(this); + } + +/** +* This method sets up the Tibetan keyboard. Initially it is called +* by the constructor, but it is also called internally whenever +* the active keyboard is changed. It first sets various values with +* respect to stacking, and concerning the differences between +* Tibetan and Sanskrit; and then it initializes the input method. +*/ + public void setupKeyboard() { + if (TibetanMachineWeb.hasTibetanStackingKey()) { + if (TibetanMachineWeb.hasSanskritStackingKey()) { + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = false; + isStackingOn_default = false; + isDefinitelyTibetan_withStackKey = false; + isDefinitelySanskrit_withStackKey = false; + } + else { + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = true; + isStackingOn_default = true; + isDefinitelyTibetan_withStackKey = true; + isDefinitelySanskrit_withStackKey = false; + } + } + else { + if (TibetanMachineWeb.hasSanskritStackingKey()) { + isDefinitelyTibetan_default = true; + isDefinitelySanskrit_default = false; + isStackingOn_default = true; + isDefinitelyTibetan_withStackKey = false; + isDefinitelySanskrit_withStackKey = true; + } + else { //no stacking key at all + isDefinitelyTibetan_default = false; + isDefinitelySanskrit_default = false; + isStackingOn_default = true; + } + } + charList = new LinkedList(); + oldGlyphList = new ArrayList(); + newGlyphList = new ArrayList(); + initKeyboard(); + } + +/** +* Registers the Extended Wylie keyboard, and sets it as +* the active keyboard. +* Unpredictable behavior will result +* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} +* but don't register it here. +*/ + public void registerKeyboard() { + TibetanKeyboard tk = null; + registerKeyboard(tk); + } + +/** +* Registers a keyboard, and sets it as the active keyboard. +* Unpredictable behavior will result if you set the keyboard in {@link +* org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} but don't +* register it in here. +* @param keyboardURL the URL of the keyboard you want to install */ + public void registerKeyboard(java.net.URL keyboardURL) { + TibetanMachineWeb.setKeyboard(keyboardURL); + setupKeyboard(); + } + +/** +* Registers a keyboard, and sets it as +* the active keyboard. +* Unpredictable behavior will result +* if you set the keyboard in {@link org.thdl.tib.text.TibetanMachineWeb TibetanMachineWeb} +* but don't register it in here. +* @param keyboard the keyboard you want to install +*/ + public void registerKeyboard(TibetanKeyboard keyboard) { + TibetanMachineWeb.setKeyboard(keyboard); + setupKeyboard(); + } + +/** +* Clears the current document. +*/ + public void newDocument() { + styleContext = new StyleContext(); + + doc = new TibetanDocument(styleContext); + doc.setTibetanFontSize(36); + setDocument(doc); + + Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE); + StyleConstants.setFontFamily(defaultStyle, "TibetanMachineWeb"); + StyleConstants.setFontSize(defaultStyle, 36); + } + +/** +* Initializes the keyboard input interpreter, setting all properties +* back to their default states. This method is called whenever an action +* or function key is pressed, and also whenever the user types punctuation +* or a vowel. It is not called when the user is typing characters that +* could be part of a stack, or require manipulation of glyphs - e.g. +* backspacing, redrawing, etc. +*/ + public void initKeyboard() { + charList.clear(); + oldGlyphList.clear(); + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isTypingVowel = false; + numberOfGlyphsForLastVowel = 0; + + //for keyboard + isStackingOn = isStackingOn_default; + isStackingRightToLeft = true; + isDefinitelyTibetan = isDefinitelyTibetan_default; + isDefinitelySanskrit = isDefinitelySanskrit_default; + } + +/** +* Enables typing of Roman (non-Tibetan) text along +* with Tibetan. +*/ + public void enableRoman() { + isRomanEnabled = true; + } + +/** +* Disables typing of Roman (non-Tibetan) text. +*/ + public void disableRoman() { + isRomanEnabled = false; + } + +/** +* Checks to see if Roman input is enabled. +* @return true if so, false if not +*/ + public boolean isRomanEnabled() { + return isRomanEnabled; + } + +/** +* Checks to see if currently in Roman input mode. +* @return true if so, false if not +*/ + public boolean isRomanMode() { + return !isTibetan; + } + +/** +* Toggles between Tibetan and Roman input modes. +* Does nothing if Roman input is disabled. +* @see #enableRoman() +* @see #disableRoman() +*/ + public void toggleLanguage() { + if (isTibetan && isRomanEnabled) + isTibetan = false; + else + isTibetan = true; + } + +/** +* Inserts Roman text into this object's document, +* at the position of the caret. +* @param attr the attributes for the text to insert +* @param s the string of text to insert +*/ + public void append(String s, MutableAttributeSet attr) { + append(caret.getDot(), s, attr); + } + +/** +* Inserts Roman text into this object's document. +* @param offset the position at which to insert text +* @param attr the attributes for the text to insert +* @param s the string of text to insert +*/ + public void append(int offset, String s, MutableAttributeSet attr) { + try { + doc.insertString(offset, s, attr); + } + catch (BadLocationException ble) { + } + } + +/** +* Changes the default font size for Tibetan text entry mode. +* +* @param size a point size +*/ + public void setTibetanFontSize(int size) { + if (size > 0) + doc.setTibetanFontSize(size); + } + +/** +* Gets the current point size for Tibetan text. +* @return the current default font size for Tibetan +* text entry mode +*/ + public int getTibetanFontSize() { + return doc.getTibetanFontSize(); + } + +/** +* Changes the default font and font size for +* non-Tibetan (Roman) text entry mode. +* +* @param font a font name +* @param size a point size +*/ + public void setRomanAttributeSet(String font, int size) { + romanAttributeSet = new SimpleAttributeSet(); + StyleConstants.setFontFamily(romanAttributeSet, font); + StyleConstants.setFontSize(romanAttributeSet, size); + } + +/** +* Gets the current point size for non-Tibetan text. +* @return the current default font size for non-Tibetan +* (Roman) text entry mode +*/ + public int getRomanFontSize() { + return romanFontSize; + } + +/** +* Gets the current font used for non-Tibetan text. +* @return the current default font for non-Tibetan +* (Roman) text entry mode +*/ + public String getRomanFontFamily() { + return romanFontFamily; + } + +/** +* Backspace and remove k elements from the current caret position. +* +* @param k the number of glyphs to remove by backspace +*/ + private void backSpace(int k) { + try { + doc.remove(caret.getDot()-k, k); + } + catch (BadLocationException ble) { + } + } + +/** +* Takes an old glyph list, which should be the currently visible set of glyphs preceding the cursor, and +* then tries to redraw the glyphs in light of the newly acquired keyboard input (which led to a revised +* 'new' glyph list). For example, the old glyph list might contain 'l' and 'n', because the user had typed +* 'ln' in Extended Wylie mode. This is what you'd see on the screen. But assume that the new glyph list +* contains the stacked glyph 'l-ng', because the user has just finished typing 'lng'. This method +* compares the glyphs, then figures out whether or not backspacing is necessary, and draws whatever characters +* need to be drawn. +* For example, suppose that oldGlyphList contains the two glyphs 'l' and 'n', and newGlyphList contains a single glyph, 'lng'. +* In this case, redrawGlyphs will be instructed to backspace over both 'l' and 'n', and then insert 'lng'. +*/ + private java.util.List redrawGlyphs(java.util.List oldGlyphList, java.util.List newGlyphList) { + if (newGlyphList.isEmpty()) + return newGlyphList; + + Iterator newIter = newGlyphList.iterator(); + DuffCode newDc = (DuffCode)newIter.next(); + + int oldGlyphCount = oldGlyphList.size(); + int newGlyphCount = newGlyphList.size(); + int beginDifference = -1; //at what point does the new glyph list begin to differ from the old one? + int k=0; + + if (oldGlyphCount!=0) { + int smallerGlyphCount; + DuffCode oldDc; + + if (oldGlyphCount < newGlyphCount) + smallerGlyphCount = oldGlyphCount; + else + smallerGlyphCount = newGlyphCount; + + Iterator oldIter = oldGlyphList.iterator(); + + for (; k newGlyphCount) + backSpace(oldGlyphCount-newGlyphCount); //deals with 'pd+m' problem + + return newGlyphList; //there is no difference between new and old glyph lists + } + } + + if (beginDifference != -1) + backSpace(oldGlyphCount - beginDifference); + + java.util.List sublist = newGlyphList.subList(k, newGlyphCount); + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(sublist); + doc.insertDuff(caret.getDot(), dd); + return newGlyphList; + } + +/** +* Tries to insert the vowel v at the position of the caret. +* This method must deal with various issues, such as: can the preceding +* glyph take a vowel? If not, then what? If the preceding glyph can be +* followed by a vowel, then the method has to figure out what vowel +* glyph to affix, which may depend on the immediately preceding glyph, +* but may depend on other factors as well. For example, when affixing +* gigu to the consonantal stack "k'" (ie k plus achung), the value of +* the gigu will depend on "k", not "'". +* +* @param v the vowel (in Wylie) you want to insert +*/ + private void putVowel(String v) { + if (caret.getDot()==0) { + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + + return; + } + + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum; + + if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { + try { + char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); + int k = (int)c2; + if (k<32 || k>126) { //if previous character is formatting or some other non-character + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + + return; + } + + String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); + if (TibetanMachineWeb.isWyliePunc(wylie)) { + if (charList.isEmpty() && !TibetanMachineWeb.isAChenRequiredBeforeVowel()) { + printAChenWithVowel(v); + return; + } + } + + DuffCode dc_1 = null; + DuffCode dc_2 = new DuffCode(fontNum, c2); + + if (caret.getDot() > 2) { + attr = doc.getCharacterElement(caret.getDot()-2).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + if (0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) { + c2 = doc.getText(caret.getDot()-2, 1).charAt(0); + dc_1 = new DuffCode(fontNum, c2); + } + } + + java.util.List before_vowel = new ArrayList(); + if (null != dc_1) + before_vowel.add(dc_1); + + before_vowel.add(dc_2); + java.util.List after_vowel = TibetanDocument.getVowel(dc_1, dc_2, v); + redrawGlyphs(before_vowel, after_vowel); + } + catch(BadLocationException ble) { + System.out.println("no--can't insert here"); + } + } + else { //0 font means not Tibetan font, so begin new Tibetan font section + if (!TibetanMachineWeb.isAChenRequiredBeforeVowel()) + printAChenWithVowel(v); + } + } + +/** +* Prints ACHEN together with the vowel v. When using the Wylie +* keyboard, or any other keyboard in which {@link org.thdl.tib.text.TibetanMachineWeb#isAChenRequiredBeforeVowel() isAChenRequiredBeforeVowel()} +* is false, this method is called frequently. +* +* @param v the vowel (in Wylie) which you want to print with ACHEN +*/ + private void printAChenWithVowel(String v) { + DuffCode[] dc_array = (DuffCode[])TibetanMachineWeb.getTibHash().get(TibetanMachineWeb.ACHEN); + DuffCode dc = dc_array[TibetanMachineWeb.TMW]; + java.util.List achenlist = TibetanDocument.getVowel(dc,v); + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(achenlist); + doc.insertDuff(caret.getDot(), dd); + } + +/** +* Puts a bindu/anusvara at the current caret position. +* In the TibetanMachineWeb font, top vowels (like gigu, +* drengbu, etc.) are merged together with bindu in a +* single glyph. This method deals with the problem of +* correctly displaying a bindu given this complication. +*/ + private void putBindu() { + special_bindu_block: { + if (caret.getDot()==0) + break special_bindu_block; + + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum; + + if (0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) + break special_bindu_block; + + try { + char c2 = doc.getText(caret.getDot()-1, 1).charAt(0); + int k = (int)c2; + if (k<32 || k>126) //if previous character is formatting or some other non-character + break special_bindu_block; + + String wylie = TibetanMachineWeb.getWylieForGlyph(fontNum, k); + if (!TibetanMachineWeb.isWylieVowel(wylie)) + break special_bindu_block; + + DuffCode dc = new DuffCode(fontNum, c2); + java.util.List beforecaret = new ArrayList(); + beforecaret.add(dc); + java.util.List bindulist = TibetanDocument.getBindu(dc); + redrawGlyphs(beforecaret, bindulist); + initKeyboard(); + return; + } + catch(BadLocationException ble) { + System.out.println("no--can't do this bindu maneuver"); + } + } + + TibetanDocument.DuffData[] dd = TibetanDocument.convertGlyphs(TibetanDocument.getBindu(null)); + doc.insertDuff(caret.getDot(), dd); + initKeyboard(); + } + +/** +* Required by implementations of the +* {@link java.awt.event.FocusListener FocusListener} interface, +* this method simply initializes the keyboard whenever this +* object gains focus. +* +* @param e a FocusEvent +*/ + public void focusGained(FocusEvent e) { + } + +/** +* Required by implementations of the +* {@link java.awt.event.FocusListener FocusListener} interface, +* this method does nothing. +* +* @param e a FocusEvent +*/ + public void focusLost(FocusEvent e) { + initKeyboard(); + } + +class RTFSelection implements ClipboardOwner, Transferable { + DataFlavor[] supportedFlavor; + ByteArrayOutputStream rtfOut; + String plainText; + + RTFSelection(StyledDocument doc, int offset, int length) { + supportedFlavor = new DataFlavor[2]; + supportedFlavor[0] = rtfFlavor; + supportedFlavor[1] = DataFlavor.stringFlavor; + try { + //construct new document that contains only portion of text you want to copy + //this workaround is due to bug 4129911, which will not be fixed (see below after source code) + StyledDocument newDoc = new DefaultStyledDocument(); + for (int i=offset; i 1 && isStackingRightToLeft) { + String s = (String)charList.removeLast(); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + initKeyboard(); + charList.add(s); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else { + holdCurrent = new StringBuffer(); + isTopHypothesis = false; + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + break key_block; + } + else { //stacking must be pre/post + if (!isStackingOn || (isStackingOn && isDefinitelyTibetan==isDefinitelyTibetan_default)) { + initKeyboard(); + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else {try { + char ch = doc.getText(caret.getDot()-1, 1).charAt(0); + AttributeSet attr = doc.getCharacterElement(caret.getDot()-1).getAttributes(); + String fontName = StyleConstants.getFontFamily(attr); + int fontNum = TibetanMachineWeb.getTMWFontNumber(fontName); + + if (0 == fontNum) { + initKeyboard(); + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + else { + initKeyboard(); + DuffCode dc = new DuffCode(fontNum, ch); + + if (!TibetanMachineWeb.isStack(dc) && !TibetanMachineWeb.isSanskritStack(dc)) { + isStackingOn = true; + isStackingRightToLeft = false; + isDefinitelyTibetan = isDefinitelyTibetan_withStackKey; + isDefinitelySanskrit = isDefinitelySanskrit_withStackKey; + } + } + } + catch (BadLocationException ble) { + initKeyboard(); + }} + break key_block; + } + } + } + + switch (c) { + case KeyEvent.VK_TAB: + case KeyEvent.VK_ENTER: + case KeyEvent.VK_ESCAPE: + initKeyboard(); + break; + + case KeyEvent.VK_BACK_SPACE: + if (shouldIBackSpace) { + backSpace(1); + break; + } + + default: + String val = String.valueOf(c); + + if (TibetanMachineWeb.isPunc(val)) { //punctuation + val = TibetanMachineWeb.getWylieForPunc(val); + + if (val.charAt(0) == TibetanMachineWeb.BINDU) + putBindu(); + + else { + DuffCode puncDc = TibetanMachineWeb.getGlyph(val); + MutableAttributeSet mas = TibetanMachineWeb.getAttributeSet(puncDc.getFontNum()); + doc.appendDuff(caret.getDot(), String.valueOf(puncDc.getCharacter()), mas); + } + + initKeyboard(); + return; + } + + if (charList.size()==0) { //add current character to charList if possible + holdCurrent.append(c); + String s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { + s = TibetanMachineWeb.getWylieForVowel(s); + + if (isTypingVowel) //note: this takes care of multiple keystroke vowels like 'ai' + backSpace(numberOfGlyphsForLastVowel); + + putVowel(s); + isTypingVowel = true; + } + else { + if (isTypingVowel) { + isTypingVowel = false; + s = String.valueOf(c); + holdCurrent = new StringBuffer(s); + } + + if (TibetanMachineWeb.isVowel(s)) { + s = TibetanMachineWeb.getWylieForVowel(s); + putVowel(s); + isTypingVowel = true; + } + + else if (TibetanMachineWeb.isChar(s)) { + s = TibetanMachineWeb.getWylieForChar(s); + charList.add(s); + isTopHypothesis = true; + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else + isTopHypothesis = false; + } + } + else { //there is already a character in charList + holdCurrent.append(c); + String s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { //the holding string is a vowel + s = TibetanMachineWeb.getWylieForVowel(s); + initKeyboard(); + isTypingVowel = true; + putVowel(s); + } + else if (TibetanMachineWeb.isChar(s)) { //the holding string is a character + String s2 = TibetanMachineWeb.getWylieForChar(s); + + if (isTopHypothesis) { + if (TibetanMachineWeb.isAChungConsonant() && isStackingOn && charList.size()>1 && s2.equals(TibetanMachineWeb.ACHUNG)) { + charList.removeLast(); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + charList.set(charList.size()-1, s2); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else { + if (!isStackingOn) { + initKeyboard(); + holdCurrent = new StringBuffer(s); + } + else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + + charList.add(s2); + isTopHypothesis = true; + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + } + else { //the holding string is not a character + if (isTopHypothesis) { //finalize top character and add new hypothesis to top + holdCurrent = new StringBuffer(); + holdCurrent.append(c); + s = holdCurrent.toString(); + + if (TibetanMachineWeb.isVowel(s)) { + String s2 = TibetanMachineWeb.getWylieForVowel(s); + putVowel(s2); + initKeyboard(); + isTypingVowel = true; + holdCurrent = new StringBuffer(s); + } + else { + if (TibetanMachineWeb.isStackingMedial() && !isStackingRightToLeft) + initKeyboard(); + + if (TibetanMachineWeb.isChar(s)) { + String s2 = TibetanMachineWeb.getWylieForChar(s); + + if (!isStackingOn) + initKeyboard(); + + else if (TibetanMachineWeb.isAChungConsonant() && s2.equals(TibetanMachineWeb.ACHUNG)) { + putVowel(TibetanMachineWeb.A_VOWEL); + initKeyboard(); + break key_block; + } + + charList.add(s2); + newGlyphList = TibetanDocument.getGlyphs(charList, isStackingRightToLeft, isDefinitelyTibetan, isDefinitelySanskrit); + oldGlyphList = redrawGlyphs(oldGlyphList, newGlyphList); + } + else { + holdCurrent = new StringBuffer(s); + isTopHypothesis = false; + } + } + } + else { //top char is just a guess! just keep it in holdCurrent + } + } + } + } //end switch + } //end key_block + } + +/** +* Converts the entire document to Extended Wylie. +*/ + public void toWylie() { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + toWylie(start, end); + } + +/** +* Converts the specified portion +* of this object's document to Extended Wylie. +* +* @param start the point from which to begin converting to Wylie +* @param end the point at which to stop converting to Wylie +*/ + public void toWylie(int start, int end) { + if (start == end) + return; + + DuffCode[] dc_array; + AttributeSet attr; + String fontName; + Position endPos; + int fontNum; + DuffCode dc; + char ch; + int i; + + java.util.List dcs = new ArrayList(); + + try { + endPos = doc.createPosition(end); + i = start; + + while (i < endPos.getOffset()+1) { + attr = doc.getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + if ((0 == (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { + if (i != start) { + dc_array = new DuffCode[0]; + dc_array = (DuffCode[])dcs.toArray(dc_array); + doc.remove(start, i-start); + append(start, TibetanDocument.getWylie(dc_array), romanAttributeSet); + dcs.clear(); + } + start = i+1; + } + else { + ch = doc.getText(i,1).charAt(0); + dc = new DuffCode(fontNum, ch); + dcs.add(dc); + } + + i++; + } + } + catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + +/** +* Converts a string of Extended Wylie to TibetanMachineWeb, and +* inserts it at the specified position. +* +* @param wylie the string of Wylie to convert +* @param offset the position at which to insert the conversion +*/ + public void toTibetanMachineWeb(String wylie, int offset) { + try { + StringTokenizer sTok = new StringTokenizer(wylie, "\n\t", true); + while (sTok.hasMoreTokens()) { + String next = sTok.nextToken(); + if (next.equals("\n") || next.equals("\t")) { + try { + doc.insertString(offset, next, null); + offset++; + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } else { + TibetanDocument.DuffData[] dd = TibetanDocument.getTibetanMachineWeb(next); + offset = doc.insertDuff(offset, dd); + } + } + } + catch (InvalidWylieException iwe) { + JOptionPane.showMessageDialog(this, + "The Wylie you are trying to convert is invalid, " + + "beginning from:\n " + iwe.getCulpritInContext() + "\n" + + "The culprit is probably the character '"+iwe.getCulprit()+"'."); + } + } + +/** +* Converts the currently selected text from Extended Wylie to TibetanMachineWeb. +*/ + public void toTibetanMachineWeb() { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + toTibetanMachineWeb(start, end); + } + +/** +* Converts a stretch of text from Extended Wylie to TibetanMachineWeb. +* @param start the begin point for the conversion +* @param end the end point for the conversion +*/ + public void toTibetanMachineWeb(int start, int end) { + if (start == end) + return; + + StringBuffer sb; + AttributeSet attr; + String fontName; + int fontNum; + Position endPos; + int i; + + try { + sb = new StringBuffer(); + endPos = doc.createPosition(end); + i = start; + + while (i < endPos.getOffset()+1) { + attr = doc.getCharacterElement(i).getAttributes(); + fontName = StyleConstants.getFontFamily(attr); + + if ((0 != (fontNum = TibetanMachineWeb.getTMWFontNumber(fontName))) || i==endPos.getOffset()) { + if (i != start) { + try { + TibetanDocument.DuffData[] duffdata = TibetanDocument.getTibetanMachineWeb(sb.toString()); + doc.remove(start, i-start); + doc.insertDuff(start, duffdata); + } + catch (InvalidWylieException iwe) { + JOptionPane.showMessageDialog(this, + "The Wylie you are trying to convert is invalid, " + + "beginning from:\n " + iwe.getCulpritInContext() + + "\nThe culprit is probably the character '" + + iwe.getCulprit() + "'."); + return; + } + } + start = i+1; + } + else + sb.append(doc.getText(i, 1)); + + i++; + } + } + catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + +} diff --git a/source/org/thdl/tib/text/DuffCellRenderer.java b/source/org/thdl/tib/text/DuffCellRenderer.java index 7955a38..dec8097 100644 --- a/source/org/thdl/tib/text/DuffCellRenderer.java +++ b/source/org/thdl/tib/text/DuffCellRenderer.java @@ -30,9 +30,10 @@ import java.io.Serializable; /** Used by DictionaryTable to display a Tibetan word or phrase (in either Roman or Tibetan script) in a single cell. + + This THDL version does not include DictionaryTable. @author Andrés Montano Pellegrini - @see DictionaryTable */ public class DuffCellRenderer extends DuffPane implements TableCellRenderer, Serializable { @@ -137,4 +138,4 @@ public class DuffCellRenderer extends DuffPane implements TableCellRenderer, Ser } doc.insertDuff(0, (DuffData []) value); } -} \ No newline at end of file +} diff --git a/source/org/thdl/tib/text/TibetanMachineWeb.java b/source/org/thdl/tib/text/TibetanMachineWeb.java index ba04ee6..0d92a99 100644 --- a/source/org/thdl/tib/text/TibetanMachineWeb.java +++ b/source/org/thdl/tib/text/TibetanMachineWeb.java @@ -1,1122 +1,1109 @@ -/* -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 java.net.URL; -import java.io.*; -import java.lang.*; -import java.awt.Font; -import java.awt.event.KeyEvent; -import javax.swing.text.*; -import java.awt.font.*; - -/** -* Interfaces between Extended Wylie and the TibetanMachineWeb fonts. -* To do this this must first read the code table, which lives in "tibwn.ini", -* and which must be found in the same directory as this class. -* @author Edward Garrett, Tibetan and Himalayan Digital Library -* @version 1.0 -*/ -public class TibetanMachineWeb { - private static boolean hasReadData = false; - private static TibetanKeyboard keyboard = null; - private static final String DEFAULT_KEYBOARD = "default_keyboard.ini"; - private static Set charSet = null; - private static Set vowelSet = null; - private static Set puncSet = null; - private static Set leftSet = null; - private static Set rightSet = null; - private static Set farRightSet = null; - private static Map tibHash = new HashMap(); - private static Map binduMap = new HashMap(); - private static String[][] toHashKey = new String[11][95]; //note: 0 slot is not used - private static DuffCode[][] TMtoTMW = new DuffCode[5][255-32]; - private static String fileName = "tibwn.ini"; - private static final String DELIMITER = "~"; - private static Set top_vowels; - private static SimpleAttributeSet[] webFontAttributeSet = new SimpleAttributeSet[11]; - private static boolean hasDisambiguatingKey; //to disambiguate gy and g.y= - private static char disambiguating_key; - private static boolean hasSanskritStackingKey; //for stacking Sanskrit - private static boolean hasTibetanStackingKey; //for stacking Tibetan - private static boolean isStackingMedial; //ie g+y, not +gy - private static char stacking_key; - private static boolean isAChenRequiredBeforeVowel; - private static boolean isAChungConsonant; - private static boolean hasAVowel; - private static String aVowel; - - public static final String[] tmFontNames = { - null, - "TibetanMachine", - "TibetanMachineSkt1", - "TibetanMachineSkt2", - "TibetanMachineSkt3", - "TibetanMachineSkt4" - }; - public static final String[] tmwFontNames = { - null, - "TibetanMachineWeb", - "TibetanMachineWeb1", - "TibetanMachineWeb2", - "TibetanMachineWeb3", - "TibetanMachineWeb4", - "TibetanMachineWeb5", - "TibetanMachineWeb6", - "TibetanMachineWeb7", - "TibetanMachineWeb8", - "TibetanMachineWeb9" - }; -/** -* the Wylie for bindu/anusvara -*/ - public static final char BINDU = 'M'; -/** -* the Wylie for tsheg -*/ - public static final char TSHEG = ' '; //this character occurs in all ten TMW fonts -/** -* the Wylie for whitespace -*/ - public static final char SPACE = '_'; //this character occurs in all ten TMW fonts -/** -* the Sanskrit stacking separator used in Extended Wylie -*/ - public static final char WYLIE_SANSKRIT_STACKING_KEY = '+'; -/** -* the Wylie disambiguating key, as a char -*/ - public static final char WYLIE_DISAMBIGUATING_KEY = '.'; -/** -* the Wylie for the invisible 'a' vowel -*/ - public static final String WYLIE_aVOWEL = "a"; -/** -* the Wylie for achung -*/ - public static final String ACHUNG = "'"; -/** -* the Wylie for achen -*/ - public static final String ACHEN = "a"; -/** -* the Wylie for gigu -*/ - public static final String i_VOWEL = "i"; -/** -* the Wylie for zhebju -*/ - public static final String u_VOWEL = "u"; -/** -* the Wylie for drengbu -*/ - public static final String e_VOWEL = "e"; -/** -* the Wylie for naro -*/ - public static final String o_VOWEL = "o"; -/** -* the Wylie for double drengbu -*/ - public static final String ai_VOWEL = "ai"; -/** -* the Wylie for double naro -*/ - public static final String au_VOWEL = "au"; -/** -* the Wylie for the subscript achung vowel -*/ - public static final String A_VOWEL = "A"; -/** -* the Wylie for log yig gigu -*/ - public static final String reverse_i_VOWEL = "-i"; -/** -* the Wylie for the vowel achung + gigu -*/ - public static final String I_VOWEL = "I"; -/** -* the Wylie for the vowel achung + zhebju -*/ - public static final String U_VOWEL = "U"; -/** -* the Wylie for the vowel achung + log yig gigu -*/ - public static final String reverse_I_VOWEL = "-I"; -/** -* represents where in an array of DuffCodes you -* find the TibetanMachine equivalence of a glyph -*/ - public static final int TM = 0; -/** -* represents where in an array of DuffCodes you -* find the reduced character equivalent of a TMW glyph -*/ - public static final int REDUCED_C = 1; -/** -* represents where in an array of DuffCodes you -* find the TibetanMachineWeb glyph -*/ - public static final int TMW = 2; -/** -* represents where in an array of DuffCodes you -* find the gigu value for a given glyph -*/ - public static final int VOWEL_i = 3; -/** -* represents where in an array of DuffCodes you -* find the zhebju value for a given glyph -*/ - public static final int VOWEL_u = 4; -/** -* represents where in an array of DuffCodes you -* find the drengbu value for a given glyph -*/ - public static final int VOWEL_e = 5; -/** -* represents where in an array of DuffCodes you -* find the naro value for a given glyph -*/ - public static final int VOWEL_o = 6; -/** -* represents where in an array of DuffCodes you -* find the achung value for a given glyph -*/ - public static final int VOWEL_A = 7; -/** -* represents where in an array of DuffCodes you -* find the achung + zhebju value for a given glyph -*/ - public static final int VOWEL_U = 8; -/** -* represents where in an array of DuffCodes you -* find the Unicode equivalence of a given glyph -*/ - public static final int UNICODE = 9; -/** -* represents where in an array of DuffCodes you -* find the half height equivalence of a given glyph -*/ - public static final int HALF_C = 10; - - private static final String lefts = "g,d,b,m,'"; - private static final String rights = "g,ng,d,n,b,m,r,l,s,',T"; - private static final String farrights = "d,s,ng"; - - static { - readData(); - - URL keyboard_url = TibetanMachineWeb.class.getResource(DEFAULT_KEYBOARD); - if (null != keyboard_url) { - try { - TibetanKeyboard kb = new TibetanKeyboard(keyboard_url); - setKeyboard(kb); - } - catch (TibetanKeyboard.InvalidKeyboardException ike) { - System.out.println("invalid keyboard file or file not found"); - setKeyboard(keyboard); - } - } - else - setKeyboard(keyboard); - } - -/* -* This method reads the data file ("tibwn.ini"), constructs -* the character, punctuation, and vowel lists, as well as -* performing other acts of initialization. -*/ - private static void readData() { - webFontAttributeSet[0] = null; - for (int i=1; i")) { - isSanskrit = false; - hashOn = false; - line = in.readLine(); - charSet = new HashSet(); - StringTokenizer st = new StringTokenizer(line,","); - while (st.hasMoreTokens()) - charSet.add(st.nextToken()); - } - else if (line.equalsIgnoreCase("")) { - isSanskrit = false; - hashOn = false; - line = in.readLine(); - vowelSet = new HashSet(); - StringTokenizer st = new StringTokenizer(line,","); - while (st.hasMoreTokens()) - vowelSet.add(st.nextToken()); - } - else if (line.equalsIgnoreCase("")) { - isSanskrit = false; - hashOn = false; - line = in.readLine(); - puncSet = new HashSet(); - StringTokenizer st = new StringTokenizer(line,","); - while (st.hasMoreTokens()) - puncSet.add(st.nextToken()); - } - - else if (line.equalsIgnoreCase("") - || line.equalsIgnoreCase("") - || line.equalsIgnoreCase("")) { - isSanskrit = false; - hashOn = true; - ignore = false; - } - else if (line.equalsIgnoreCase("")) { - isSanskrit = true; - hashOn = true; - ignore = false; - } - else if (line.equalsIgnoreCase("")) { - isSanskrit = false; - hashOn = false; - ignore = false; - } - else if (line.equalsIgnoreCase("")) - ignore = true; - } - else if (line.startsWith("//")) //comment - ; - else if (line.equals("")) //empty string - ; - else if (!ignore) { - StringTokenizer st = new StringTokenizer(line,DELIMITER,true); - - String wylie = new String(); - DuffCode[] duffCodes = new DuffCode[11]; - - int k = 0; - - while (st.hasMoreTokens()) { - String val = st.nextToken(); - - if (val.equals(DELIMITER)) - k++; - - else if (!val.equals("")) { - switch (k) { - case 0: //wylie key - wylie = val; - break; - - case 1: - duffCodes[TM] = new DuffCode(val,false); - break; - - case 2: //reduced-size character if there is one - duffCodes[REDUCED_C] = new DuffCode(val,true); - break; - - case 3: //TibetanMachineWeb code - duffCodes[k-1] = new DuffCode(val,true); - TMtoTMW[duffCodes[TM].fontNum-1][duffCodes[TM].charNum-32] = duffCodes[TMW]; - break; - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - duffCodes[k-1] = new DuffCode(val,true); - break; - - case 10: //Unicode: ignore for now - break; - - case 11: //half-height character if there is one - duffCodes[HALF_C] = new DuffCode(val,true); - break; - - case 12: //special bindu-value if vowel+bindu are one glyph - DuffCode binduCode = new DuffCode(val,true); - binduMap.put(duffCodes[TMW],binduCode); - break; - } - } - } - - if (hashOn) - tibHash.put(wylie,duffCodes); - - int font = duffCodes[2].fontNum; - int code = duffCodes[2].charNum-32; - toHashKey[font][code] = wylie; - } - } - } - catch (IOException e) { - System.out.println("file Disappeared"); - } - - hasReadData = true; - } - -/** -* (Re-)sets the keyboard. -* @param kb the keyboard to be installed. If null, then the -* Extended Wylie keyboard is installed -* @return true if the keyboard was successfully set, false -* if there was an error -*/ -public static boolean setKeyboard(TibetanKeyboard kb) { - keyboard = kb; - - if (keyboard == null) { //wylie keyboard - hasDisambiguatingKey = true; - disambiguating_key = WYLIE_DISAMBIGUATING_KEY; - hasSanskritStackingKey = true; - hasTibetanStackingKey = false; - isStackingMedial = true; - stacking_key = WYLIE_SANSKRIT_STACKING_KEY; - isAChenRequiredBeforeVowel = false; - isAChungConsonant = false; - hasAVowel = true; - aVowel = WYLIE_aVOWEL; - if (!vowelSet.contains(WYLIE_aVOWEL)) - vowelSet.add(WYLIE_aVOWEL); - } - else { - hasDisambiguatingKey = keyboard.hasDisambiguatingKey(); - if (hasDisambiguatingKey) - disambiguating_key = keyboard.getDisambiguatingKey(); - - hasSanskritStackingKey = keyboard.hasSanskritStackingKey(); - hasTibetanStackingKey = keyboard.hasTibetanStackingKey(); - if (hasSanskritStackingKey || hasTibetanStackingKey) { - isStackingMedial = keyboard.isStackingMedial(); - stacking_key = keyboard.getStackingKey(); - } - - isAChenRequiredBeforeVowel = keyboard.isAChenRequiredBeforeVowel(); - isAChungConsonant = keyboard.isAChungConsonant(); - hasAVowel = keyboard.hasAVowel(); - } - return true; -} - -/** -* (Re-)sets the keyboard. -* @param url the URL of the keyboard to be installed. -* If null, then the Extended Wylie keyboard is -* installed -* @return true if the keyboard was successfully set, false -* if there was an error -*/ -public static boolean setKeyboard(URL url) { - TibetanKeyboard kb; - - try { - kb = new TibetanKeyboard(url); - if (setKeyboard(kb)) - return true; - else - return false; - } - catch (TibetanKeyboard.InvalidKeyboardException ike) { - System.out.println("can't create this keyboard"); - return false; - } -} - -/** -* Gets the AttributeSet for the given TibetanMachineWeb font. -* This information is required in order to be able to put styled -* text into {@link TibetanDocument TibetanDocument}. -* @param font the number of the TibetanMachineWeb font for which -* you want the SimpleAttributeSet: TibetanMachineWeb = 1, -* TibetanMachineWeb1 = 2, TibetanMachineWeb = 3, etc. up to 10 -* @return a SimpleAttributeSet for the given font - that is, -* a way of encoding the font itself -*/ -public static SimpleAttributeSet getAttributeSet(int font) { - if (font > -1 && font < webFontAttributeSet.length) - return webFontAttributeSet[font]; - else - return null; -} - -/** -* Says whether or not the character is formatting. -* @param c the character to be checked -* @return true if c is formatting (TAB or -* ENTER), false if not -*/ -public static boolean isFormatting(char c) { - if ( c == KeyEvent.VK_TAB - || c == KeyEvent.VK_ENTER) - - return true; - else - return false; -} - -/** -* Checks to see if the passed string -* is a character in the installed keyboard. -* -* @param s the string you want to check -* @return true if s is a character in the current keyboard, -* false if not -*/ -public static boolean isChar(String s) { - if (keyboard == null) { - if (charSet.contains(s)) - return true; - else - return false; - } - else - if (keyboard.isChar(s)) - return true; - else - return false; -} - -/** -* Checks to see if the passed string -* is a character in Extended Wylie. -* @param s the string to be checked -* @return true if s is a character in -* Extended Wylie transliteration, false if not -*/ -public static boolean isWylieChar(String s) { - if (charSet.contains(s)) - return true; - - return false; -} - -/** -* Checks to see if the passed string -* is punctuation in the installed keyboard. -* @param s the string you want to check -* @return true if s is punctuation in the current -* keyboard, false if not -*/ -public static boolean isPunc(String s) { - if (keyboard == null) { - if (puncSet.contains(s)) - return true; - else - return false; - } - else - if (keyboard.isPunc(s)) - return true; - else - return false; -} - -/** -* This method checks to see if the passed string -* is punctuation in Extended Wylie. -* @param s the string to be checked -* @return true if s is punctuation in -* Extended Wylie transliteration, false if not -*/ -public static boolean isWyliePunc(String s) { - if (puncSet.contains(s)) - return true; - - return false; -} - -/** -* Checks to see if the passed string -* is a vowel in the installed keyboard. -* @param s the string you want to check -* @return true if s is a vowel in the current -* keyboard, false if not -*/ -public static boolean isVowel(String s) { - if (keyboard == null) { - if (vowelSet.contains(s)) - return true; - else - return false; - } - else - if (keyboard.isVowel(s)) - return true; - else - return false; -} - -/** -* Checks to see if the passed string -* is a vowel in Extended Wylie. -* @param s the string to be checked -* @return true if s is a vowel in -* Extended Wylie transliteration, false if not -*/ -public static boolean isWylieVowel(String s) { - if (vowelSet.contains(s)) - return true; - - return false; -} - -/** -* Is this Wylie valid as a leftmost character -* in a Tibetan syllable? For example, in the -* syllable 'brgyad', 'b' is the leftmost -* character. Valid leftmost characters include -* g, d, b, and m. -* @param s the (Wylie) string to be checked -* @return true if s is a possible leftmost -* character in a Tibetan syllable, false -* if not. -*/ -public static boolean isWylieLeft(String s) { - if (keyboard != null) - s = keyboard.getWylieForChar(s); - - if (leftSet.contains(s)) - return true; - else - return false; -} - -/** -* Is this Wylie valid as a right (post-vowel) -* character in a Tibetan syllable? For example, -* in the syllable 'lags', 'g' is in the right -* character position. Valid right characters -* include g, ng, d, n, b, m, r, l, s, ', and T. -* @param s the (Wylie) string to be checked -* @return true if s is a possible right -* character in a Tibetan syllable, false -* if not. -*/ -public static boolean isWylieRight(String s) { - if (keyboard != null) - s = keyboard.getWylieForChar(s); - - if (rightSet.contains(s)) - return true; - else - return false; -} - -/** -* Is this Wylie valid as a leftmost character -* in a Tibetan syllable? -* @param s the string to be checked -* @return true if s is a possible leftmost -* character in a Tibetan syllable, false -* if not. -*/ -public static boolean isWylieFarRight(String s) { - if (keyboard != null) - s = keyboard.getWylieForChar(s); - - if (farRightSet.contains(s)) - return true; - else - return false; -} - -/** -* Converts character to its Extended Wylie correspondence. -* This assumes that the passed string is a character -* in the current keyboard. -* @param s the string to be converted -* @return the Wylie character corresponding to -* s, or null if there is no such character -* @see TibetanKeyboard -*/ -public static String getWylieForChar(String s) { - if (keyboard == null) - return s; - - return keyboard.getWylieForChar(s); -} - -/** -* Converts punctuation to its Extended Wylie correspondence. -* This assumes that the passed string is punctuation -* in the current keyboard. -* @param s the string to be converted -* @return the Wylie punctuation corresponding to -* s, or null if there is no such punctuation -* @see TibetanKeyboard -*/ -public static String getWylieForPunc(String s) { - if (keyboard == null) - return s; - - return keyboard.getWylieForPunc(s); -} - -/** -* Converts vowel to its Extended Wylie correspondence. -* This assumes that the passed string is a vowel -* in the current keyboard. -* @param s the string to be converted -* @return the Wylie vowel corresponding to -* s, or null if there is no such vowel -* @see TibetanKeyboard -*/ -public static String getWylieForVowel(String s) { - if (keyboard == null) - return s; - - return keyboard.getWylieForVowel(s); -} - -/** -* Gets the DuffCode required for a vowel, if -* affixed to the given hashKey. -* @param hashKey the key for the character the -* vowel is to be affixed to -* @param vowel the vowel you want the DuffCode for -* @return the DuffCode for the vowel in the given -* context, or null if there is no such vowel in -* the context -* @see DuffCode -*/ -public static DuffCode getVowel(String hashKey, int vowel) { - DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); - - if (null == dc) - return null; - - return dc[vowel]; //either a vowel or null -} - -/** -* Checks to see if a glyph exists for this hash key. -* @param hashKey the key to be checked -* @return true if there is a glyph corresponding to -* hashKey, false if not -*/ -public static boolean hasGlyph(String hashKey) { - if (tibHash.get(hashKey)==null) - return false; - else - return true; -} - -/** -* Gets a glyph for this hash key. Hash keys are not identical to Extended -* Wylie. The hash key for a Tibetan stack separates the members of the stack -* with '-', for example, 's-g-r'. In Sanskrit stacks, '+' is used, e.g. 'g+h+g+h'. -* @param hashKey the key for which you want a DuffCode -* @return the TibetanMachineWeb DuffCode value for hashKey -* @see DuffCode -*/ -public static DuffCode getGlyph(String hashKey) { - DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); - return dc[TMW]; -} - -/** -* Gets the half height character for this hash key. -* @param hashKey the key you want a half height glyph for -* @return the TibetanMachineWeb DuffCode of hashKey's -* reduced height glyph, or null if there is no such glyph -* @see DuffCode -*/ -public static DuffCode getHalfHeightGlyph(String hashKey) { - DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); - if (dc == null) - return null; - - return dc[REDUCED_C]; -} - -private static DuffCode getTMtoTMW(int font, int code) { - if (code > 255-32) { - switch (code) { - case 8218-32: //sby - code = 130-32; - break; - - case 8230-32: //sgr - code = 133-32; - break; - - case 8225-32: //spr - code = 135-32; - break; - - case 8117-32: //tshw - code = 146-32; - break; - - case 8126-32: //rw - code = 149-32; - break; - - case 8482-32: //grw - code = 153-32; - break; - - default: - return null; - } - } - - return TMtoTMW[font][code]; -} - -private static int getTMFontNumber(String name) { - for (int i=1; i -1) - return hashKey; //because '+' remains part of Extended Wylie for Sanskrit stacks - - if (hashKey.charAt(0) == '-') - return hashKey; //because must be '-i' or '-I' vowels - - StringTokenizer st = new StringTokenizer(hashKey, "-"); - StringBuffer sb = new StringBuffer(); - - while (st.hasMoreTokens()) - sb.append(st.nextToken()); - - return sb.toString(); -} - -/** -* Gets the Extended Wylie value for this glyph. -* @param font the font of the TibetanMachineWeb -* glyph you want the Wylie of -* @param code the TibetanMachineWeb glyph -* you want the Wylie of -* @return the Wylie value corresponding to the -* glyph denoted by font, code -*/ -public static String getWylieForGlyph(int font, int code) { - String hashKey = getHashKeyForGlyph(font, code); - return wylieForGlyph(hashKey); -} - -/** -* Gets the Extended Wylie value for this glyph. -* @param dc the DuffCode of the glyph you want -* the Wylie of -* @return the Wylie value corresponding to the -* glyph denoted by dc -*/ -public static String getWylieForGlyph(DuffCode dc) { - String hashKey = getHashKeyForGlyph(dc); - return wylieForGlyph(hashKey); -} - -/** -* Says whether or not this glyph involves a Sanskrit stack. -* @param font the font of a TibetanMachineWeb glyph -* @param code the ASCII value of a TibetanMachineWeb glyph -* @return true if this glyph is a Sanskrit stack, -* false if not -*/ -public static boolean isSanskritStack(int font, int code) { - String val = toHashKey[font][code]; - if (val.indexOf(WYLIE_SANSKRIT_STACKING_KEY) == -1) - return false; - else - return true; -} - -/** -* Says whether or not this glyph involves a Sanskrit stack. -* @param dc the DuffCode of a TibetanMachineWeb glyph -* @return true if this glyph is a Sanskrit stack, -* false if not -*/ -public static boolean isSanskritStack(DuffCode dc) { - int font = dc.fontNum; - int code = dc.charNum-32; - - if (isSanskritStack(font, code)) - return true; - else - return false; -} - -/** -* Says whether or not this glyph involves a Tibetan stack. -* @param font the font of a TibetanMachineWeb glyph -* @param code the ASCII value of a TibetanMachineWeb glyph -* @return true if this glyph is a Tibetan stack, -* false if not -*/ -public static boolean isStack(int font, int code) { - String val = toHashKey[font][code]; - if (val.indexOf('-') < 1) //we allow '-i' and '-I' in as vowels - return false; - else - return true; -} - -/** -* Says whether or not this glyph involves a Tibetan stack. -* @param dc the DuffCode of a TibetanMachineWeb glyph -* @return true if this glyph is a Tibetan stack, -* false if not -*/ -public static boolean isStack(DuffCode dc) { - int font = dc.fontNum; - int code = dc.charNum-32; - - if (isStack(font, code)) - return true; - else - return false; -} - -/** -* Gets the hash with information about each character and stack. -* @return a hash containing a key for each -* entity defined in Wylie, whose object is the -* DuffCode for that key -*/ -public static Map getTibHash() { - return tibHash; -} - -/** -* Gets the hash for characters that require special bindus. -* @return a hash whose keys are all vowel glyphs (DuffCodes) -* that require a special bindu, and whose objects -* are the vowel+bindu glyph (DuffCode) corresponding to each -* such vowel glyph -*/ -public static Map getBinduMap() { - return binduMap; -} - -/** -* Does the keyboard have a disambiguating key? -* @return true if the installed keyboard has a -* disambiguating key, false if not -* @see TibetanKeyboard -*/ -public static boolean hasDisambiguatingKey() { - return hasDisambiguatingKey; -} - -/** -* Gets the disambiguating key. -* @return the disambiguating key for the installed -* keyboard, or ' ' if there is no such key -* @see TibetanKeyboard -*/ -public static char getDisambiguatingKey() { - return disambiguating_key; -} - -/** -* Does the keyboard have a Sanksrit stacking key? -* @return true if a stacking key is required -* to type Sanskrit stacks, false if not -* @see TibetanKeyboard -*/ -public static boolean hasSanskritStackingKey() { - return hasSanskritStackingKey; -} - -/** -* Does the keyboard have a Tibetan stacking key? -* @return true if a stacking key is required to -* type Tibetan stacks, false if not -* @see TibetanKeyboard -*/ -public static boolean hasTibetanStackingKey() { - return hasTibetanStackingKey; -} - -/** -* Is stacking medial? -* @return true if the stacking key is medial, -* false if not, or if there is no stacking key -* @see TibetanKeyboard -*/ -public static boolean isStackingMedial() { - return isStackingMedial; -} - -/** -* Gets the stacking key. -* @return the stacking key, or ' ' if there -* isn't one -* @see TibetanKeyboard -*/ -public static char getStackingKey() { - return stacking_key; -} - -/** -* Is achen required before vowels? -* @return true if you have to type achen first -* before you can get a vowel with achen, false -* if you can just type the vowel by itself -* (as in Wylie) -* @see TibetanKeyboard -*/ -public static boolean isAChenRequiredBeforeVowel() { - return isAChenRequiredBeforeVowel; -} - -/** -* Is achung treated as a consonant? -* @return true if a-chung is considered a consonant -* for the purposes of stacking, false if not -* (as in Wylie) -* @see TibetanKeyboard -*/ -public static boolean isAChungConsonant() { - return isAChungConsonant; -} - -/** -* Is there a key for the invisible 'a' vowel in this keyboard? -* @return true if the installed keyboard has a -* dummy a vowel, false if not -* @see TibetanKeyboard -*/ -public static boolean hasAVowel() { - return hasAVowel; -} - -/** -* Gets the invisible 'a' vowel. -* @return the dummy 'a'-vowel for the installed -* keyboard, or "" if there is no such vowel -* @see TibetanKeyboard -*/ -public static String getAVowel() { - return aVowel; -} - -/** -* Is this glyph a top (superscript) vowel? -* @param a DuffCode representing a TibetanMachineWeb -* glyph -* @return true if the glyph is a top-hanging -* (superscript) vowel (i, u, e, o, ai, or ao) -* and false if not -*/ -public static boolean isTopVowel(DuffCode dc) { - String wylie = getWylieForGlyph(dc); - if (top_vowels.contains(wylie)) - return true; - - return false; -} -} \ 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 java.net.URL; +import java.io.*; +import java.lang.*; +import java.awt.Font; +import java.awt.event.KeyEvent; +import javax.swing.text.*; +import java.awt.font.*; + +/** +* Interfaces between Extended Wylie and the TibetanMachineWeb fonts. +* To do this this must first read the code table, which lives in "tibwn.ini", +* and which must be found in the same directory as this class. +* @author Edward Garrett, Tibetan and Himalayan Digital Library +* @version 1.0 +*/ +public class TibetanMachineWeb { + private static boolean hasReadData = false; + private static TibetanKeyboard keyboard = null; + private static final String DEFAULT_KEYBOARD = "default_keyboard.ini"; + private static Set charSet = null; + private static Set vowelSet = null; + private static Set puncSet = null; + private static Set leftSet = null; + private static Set rightSet = null; + private static Set farRightSet = null; + private static Map tibHash = new HashMap(); + private static Map binduMap = new HashMap(); + private static String[][] toHashKey = new String[11][95]; //note: 0 slot is not used + private static DuffCode[][] TMtoTMW = new DuffCode[5][255-32]; + private static String fileName = "tibwn.ini"; + private static final String DELIMITER = "~"; + private static Set top_vowels; + private static SimpleAttributeSet[] webFontAttributeSet = new SimpleAttributeSet[11]; + private static boolean hasDisambiguatingKey; //to disambiguate gy and g.y= + private static char disambiguating_key; + private static boolean hasSanskritStackingKey; //for stacking Sanskrit + private static boolean hasTibetanStackingKey; //for stacking Tibetan + private static boolean isStackingMedial; //ie g+y, not +gy + private static char stacking_key; + private static boolean isAChenRequiredBeforeVowel; + private static boolean isAChungConsonant; + private static boolean hasAVowel; + private static String aVowel; + + public static final String[] tmFontNames = { + null, + "TibetanMachine", + "TibetanMachineSkt1", + "TibetanMachineSkt2", + "TibetanMachineSkt3", + "TibetanMachineSkt4" + }; + public static final String[] tmwFontNames = { + null, + "TibetanMachineWeb", + "TibetanMachineWeb1", + "TibetanMachineWeb2", + "TibetanMachineWeb3", + "TibetanMachineWeb4", + "TibetanMachineWeb5", + "TibetanMachineWeb6", + "TibetanMachineWeb7", + "TibetanMachineWeb8", + "TibetanMachineWeb9" + }; +/** +* the Wylie for bindu/anusvara +*/ + public static final char BINDU = 'M'; +/** +* the Wylie for tsheg +*/ + public static final char TSHEG = ' '; //this character occurs in all ten TMW fonts +/** +* the Wylie for whitespace +*/ + public static final char SPACE = '_'; //this character occurs in all ten TMW fonts +/** +* the Sanskrit stacking separator used in Extended Wylie +*/ + public static final char WYLIE_SANSKRIT_STACKING_KEY = '+'; +/** +* the Wylie disambiguating key, as a char +*/ + public static final char WYLIE_DISAMBIGUATING_KEY = '.'; +/** +* the Wylie for the invisible 'a' vowel +*/ + public static final String WYLIE_aVOWEL = "a"; +/** +* the Wylie for achung +*/ + public static final String ACHUNG = "'"; +/** +* the Wylie for achen +*/ + public static final String ACHEN = "a"; +/** +* the Wylie for gigu +*/ + public static final String i_VOWEL = "i"; +/** +* the Wylie for zhebju +*/ + public static final String u_VOWEL = "u"; +/** +* the Wylie for drengbu +*/ + public static final String e_VOWEL = "e"; +/** +* the Wylie for naro +*/ + public static final String o_VOWEL = "o"; +/** +* the Wylie for double drengbu +*/ + public static final String ai_VOWEL = "ai"; +/** +* the Wylie for double naro +*/ + public static final String au_VOWEL = "au"; +/** +* the Wylie for the subscript achung vowel +*/ + public static final String A_VOWEL = "A"; +/** +* the Wylie for log yig gigu +*/ + public static final String reverse_i_VOWEL = "-i"; +/** +* the Wylie for the vowel achung + gigu +*/ + public static final String I_VOWEL = "I"; +/** +* the Wylie for the vowel achung + zhebju +*/ + public static final String U_VOWEL = "U"; +/** +* the Wylie for the vowel achung + log yig gigu +*/ + public static final String reverse_I_VOWEL = "-I"; +/** +* represents where in an array of DuffCodes you +* find the TibetanMachine equivalence of a glyph +*/ + public static final int TM = 0; +/** +* represents where in an array of DuffCodes you +* find the reduced character equivalent of a TMW glyph +*/ + public static final int REDUCED_C = 1; +/** +* represents where in an array of DuffCodes you +* find the TibetanMachineWeb glyph +*/ + public static final int TMW = 2; +/** +* represents where in an array of DuffCodes you +* find the gigu value for a given glyph +*/ + public static final int VOWEL_i = 3; +/** +* represents where in an array of DuffCodes you +* find the zhebju value for a given glyph +*/ + public static final int VOWEL_u = 4; +/** +* represents where in an array of DuffCodes you +* find the drengbu value for a given glyph +*/ + public static final int VOWEL_e = 5; +/** +* represents where in an array of DuffCodes you +* find the naro value for a given glyph +*/ + public static final int VOWEL_o = 6; +/** +* represents where in an array of DuffCodes you +* find the achung value for a given glyph +*/ + public static final int VOWEL_A = 7; +/** +* represents where in an array of DuffCodes you +* find the achung + zhebju value for a given glyph +*/ + public static final int VOWEL_U = 8; +/** +* represents where in an array of DuffCodes you +* find the Unicode equivalence of a given glyph +*/ + public static final int UNICODE = 9; +/** +* represents where in an array of DuffCodes you +* find the half height equivalence of a given glyph +*/ + public static final int HALF_C = 10; + + private static final String lefts = "g,d,b,m,'"; + private static final String rights = "g,ng,d,n,b,m,r,l,s,',T"; + private static final String farrights = "d,s,ng"; + + static { + readData(); + + URL keyboard_url = TibetanMachineWeb.class.getResource(DEFAULT_KEYBOARD); + if (null != keyboard_url) { + try { + TibetanKeyboard kb = new TibetanKeyboard(keyboard_url); + setKeyboard(kb); + } + catch (TibetanKeyboard.InvalidKeyboardException ike) { + System.out.println("invalid keyboard file or file not found"); + setKeyboard(keyboard); + } + } + else + setKeyboard(keyboard); + } + +/* +* This method reads the data file ("tibwn.ini"), constructs +* the character, punctuation, and vowel lists, as well as +* performing other acts of initialization. +*/ + private static void readData() { + webFontAttributeSet[0] = null; + for (int i=1; i")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + charSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + charSet.add(st.nextToken()); + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + vowelSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + vowelSet.add(st.nextToken()); + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + line = in.readLine(); + puncSet = new HashSet(); + StringTokenizer st = new StringTokenizer(line,","); + while (st.hasMoreTokens()) + puncSet.add(st.nextToken()); + } + + else if (line.equalsIgnoreCase("") + || line.equalsIgnoreCase("") + || line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = true; + ignore = false; + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = true; + hashOn = true; + ignore = false; + } + else if (line.equalsIgnoreCase("")) { + isSanskrit = false; + hashOn = false; + ignore = false; + } + else if (line.equalsIgnoreCase("")) + ignore = true; + } + else if (line.startsWith("//")) //comment + ; + else if (line.equals("")) //empty string + ; + else if (!ignore) { + StringTokenizer st = new StringTokenizer(line,DELIMITER,true); + + String wylie = new String(); + DuffCode[] duffCodes = new DuffCode[11]; + + int k = 0; + + while (st.hasMoreTokens()) { + String val = st.nextToken(); + + if (val.equals(DELIMITER)) + k++; + + else if (!val.equals("")) { + switch (k) { + case 0: //wylie key + wylie = val; + break; + + case 1: + duffCodes[TM] = new DuffCode(val,false); + break; + + case 2: //reduced-size character if there is one + duffCodes[REDUCED_C] = new DuffCode(val,true); + break; + + case 3: //TibetanMachineWeb code + duffCodes[k-1] = new DuffCode(val,true); + TMtoTMW[duffCodes[TM].fontNum-1][duffCodes[TM].charNum-32] = duffCodes[TMW]; + break; + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + duffCodes[k-1] = new DuffCode(val,true); + break; + + case 10: //Unicode: ignore for now + break; + + case 11: //half-height character if there is one + duffCodes[HALF_C] = new DuffCode(val,true); + break; + + case 12: //special bindu-value if vowel+bindu are one glyph + DuffCode binduCode = new DuffCode(val,true); + binduMap.put(duffCodes[TMW],binduCode); + break; + } + } + } + + if (hashOn) + tibHash.put(wylie,duffCodes); + + int font = duffCodes[2].fontNum; + int code = duffCodes[2].charNum-32; + toHashKey[font][code] = wylie; + } + } + } + catch (IOException e) { + System.out.println("file Disappeared"); + } + + hasReadData = true; + } + +/** +* (Re-)sets the keyboard. +* @param kb the keyboard to be installed. If null, then the +* Extended Wylie keyboard is installed +* @return true if the keyboard was successfully set, false +* if there was an error +*/ +public static boolean setKeyboard(TibetanKeyboard kb) { + keyboard = kb; + + if (keyboard == null) { //wylie keyboard + hasDisambiguatingKey = true; + disambiguating_key = WYLIE_DISAMBIGUATING_KEY; + hasSanskritStackingKey = true; + hasTibetanStackingKey = false; + isStackingMedial = true; + stacking_key = WYLIE_SANSKRIT_STACKING_KEY; + isAChenRequiredBeforeVowel = false; + isAChungConsonant = false; + hasAVowel = true; + aVowel = WYLIE_aVOWEL; + if (!vowelSet.contains(WYLIE_aVOWEL)) + vowelSet.add(WYLIE_aVOWEL); + } + else { + hasDisambiguatingKey = keyboard.hasDisambiguatingKey(); + if (hasDisambiguatingKey) + disambiguating_key = keyboard.getDisambiguatingKey(); + + hasSanskritStackingKey = keyboard.hasSanskritStackingKey(); + hasTibetanStackingKey = keyboard.hasTibetanStackingKey(); + if (hasSanskritStackingKey || hasTibetanStackingKey) { + isStackingMedial = keyboard.isStackingMedial(); + stacking_key = keyboard.getStackingKey(); + } + + isAChenRequiredBeforeVowel = keyboard.isAChenRequiredBeforeVowel(); + isAChungConsonant = keyboard.isAChungConsonant(); + hasAVowel = keyboard.hasAVowel(); + } + return true; +} + +/** +* (Re-)sets the keyboard. +* @param url the URL of the keyboard to be installed. +* If null, then the Extended Wylie keyboard is +* installed +* @return true if the keyboard was successfully set, false +* if there was an error +*/ +public static boolean setKeyboard(URL url) { + TibetanKeyboard kb; + + try { + kb = new TibetanKeyboard(url); + if (setKeyboard(kb)) + return true; + else + return false; + } + catch (TibetanKeyboard.InvalidKeyboardException ike) { + System.out.println("can't create this keyboard"); + return false; + } +} + +/** +* Gets the AttributeSet for the given TibetanMachineWeb font. +* This information is required in order to be able to put styled +* text into {@link TibetanDocument TibetanDocument}. +* @param font the number of the TibetanMachineWeb font for which +* you want the SimpleAttributeSet: TibetanMachineWeb = 1, +* TibetanMachineWeb1 = 2, TibetanMachineWeb = 3, etc. up to 10 +* @return a SimpleAttributeSet for the given font - that is, +* a way of encoding the font itself +*/ +public static SimpleAttributeSet getAttributeSet(int font) { + if (font > -1 && font < webFontAttributeSet.length) + return webFontAttributeSet[font]; + else + return null; +} + +/** +* Says whether or not the character is formatting. +* @param c the character to be checked +* @return true if c is formatting (TAB or +* ENTER), false if not +*/ +public static boolean isFormatting(char c) { + if (c < 32 || c > 126) + return true; + else + return false; +/* + if ( c == KeyEvent.VK_TAB + || c == KeyEvent.VK_ENTER) + + return true; + else + return false; +*/ +} + +/** +* Checks to see if the passed string +* is a character in the installed keyboard. +* +* @param s the string you want to check +* @return true if s is a character in the current keyboard, +* false if not +*/ +public static boolean isChar(String s) { + if (keyboard == null) { + if (charSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isChar(s)) + return true; + else + return false; +} + +/** +* Checks to see if the passed string +* is a character in Extended Wylie. +* @param s the string to be checked +* @return true if s is a character in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWylieChar(String s) { + if (charSet.contains(s)) + return true; + + return false; +} + +/** +* Checks to see if the passed string +* is punctuation in the installed keyboard. +* @param s the string you want to check +* @return true if s is punctuation in the current +* keyboard, false if not +*/ +public static boolean isPunc(String s) { + if (keyboard == null) { + if (puncSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isPunc(s)) + return true; + else + return false; +} + +/** +* This method checks to see if the passed string +* is punctuation in Extended Wylie. +* @param s the string to be checked +* @return true if s is punctuation in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWyliePunc(String s) { + if (puncSet.contains(s)) + return true; + + return false; +} + +/** +* Checks to see if the passed string +* is a vowel in the installed keyboard. +* @param s the string you want to check +* @return true if s is a vowel in the current +* keyboard, false if not +*/ +public static boolean isVowel(String s) { + if (keyboard == null) { + if (vowelSet.contains(s)) + return true; + else + return false; + } + else + if (keyboard.isVowel(s)) + return true; + else + return false; +} + +/** +* Checks to see if the passed string +* is a vowel in Extended Wylie. +* @param s the string to be checked +* @return true if s is a vowel in +* Extended Wylie transliteration, false if not +*/ +public static boolean isWylieVowel(String s) { + if (vowelSet.contains(s)) + return true; + + return false; +} + +/** +* Returns true iff this Wylie is valid as a leftmost character in a +* Tibetan syllable. For example, in the syllable 'brgyad', 'b' is the +* leftmost character. Valid leftmost characters include g, d, b, and +* m. +* @param s the (Wylie) string to be checked +* @return true if s is a possible leftmost character in a Tibetan +* syllable, false if not. */ +public static boolean isWylieLeft(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (leftSet.contains(s)) + return true; + else + return false; +} + +/** +* Returns true iff this Wylie is valid as a right (post-vowel) +* character in a Tibetan syllable. For example, in the syllable +* 'lags', 'g' is in the right character position. Valid right +* characters include g, ng, d, n, b, m, r, l, s, ', and T. +* @param s the (Wylie) string to be checked +* @return true if s is a possible right character in a Tibetan +* syllable, false if not. */ +public static boolean isWylieRight(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (rightSet.contains(s)) + return true; + else + return false; +} + +/** +* Returns true iff this Wylie is valid as a leftmost character in a +* Tibetan syllable. +* @param s the string to be checked +* @return true if s is a possible leftmost character in a Tibetan +* syllable, false if not. */ +public static boolean isWylieFarRight(String s) { + if (keyboard != null) + s = keyboard.getWylieForChar(s); + + if (farRightSet.contains(s)) + return true; + else + return false; +} + +/** +* Converts character to its Extended Wylie correspondence. +* This assumes that the passed string is a character +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie character corresponding to +* s, or null if there is no such character +* @see TibetanKeyboard +*/ +public static String getWylieForChar(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForChar(s); +} + +/** +* Converts punctuation to its Extended Wylie correspondence. +* This assumes that the passed string is punctuation +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie punctuation corresponding to +* s, or null if there is no such punctuation +* @see TibetanKeyboard +*/ +public static String getWylieForPunc(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForPunc(s); +} + +/** +* Converts vowel to its Extended Wylie correspondence. +* This assumes that the passed string is a vowel +* in the current keyboard. +* @param s the string to be converted +* @return the Wylie vowel corresponding to +* s, or null if there is no such vowel +* @see TibetanKeyboard +*/ +public static String getWylieForVowel(String s) { + if (keyboard == null) + return s; + + return keyboard.getWylieForVowel(s); +} + +/** +* Gets the DuffCode required for a vowel, if +* affixed to the given hashKey. +* @param hashKey the key for the character the +* vowel is to be affixed to +* @param vowel the vowel you want the DuffCode for +* @return the DuffCode for the vowel in the given +* context, or null if there is no such vowel in +* the context +* @see DuffCode +*/ +public static DuffCode getVowel(String hashKey, int vowel) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + + if (null == dc) + return null; + + return dc[vowel]; //either a vowel or null +} + +/** +* Checks to see if a glyph exists for this hash key. +* @param hashKey the key to be checked +* @return true if there is a glyph corresponding to +* hashKey, false if not +*/ +public static boolean hasGlyph(String hashKey) { + if (tibHash.get(hashKey)==null) + return false; + else + return true; +} + +/** +* Gets a glyph for this hash key. Hash keys are not identical to Extended +* Wylie. The hash key for a Tibetan stack separates the members of the stack +* with '-', for example, 's-g-r'. In Sanskrit stacks, '+' is used, e.g. 'g+h+g+h'. +* @param hashKey the key for which you want a DuffCode +* @return the TibetanMachineWeb DuffCode value for hashKey +* @see DuffCode +*/ +public static DuffCode getGlyph(String hashKey) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + return dc[TMW]; +} + +/** +* Gets the half height character for this hash key. +* @param hashKey the key you want a half height glyph for +* @return the TibetanMachineWeb DuffCode of hashKey's +* reduced height glyph, or null if there is no such glyph +* @see DuffCode +*/ +public static DuffCode getHalfHeightGlyph(String hashKey) { + DuffCode[] dc = (DuffCode[])tibHash.get(hashKey); + if (dc == null) + return null; + + return dc[REDUCED_C]; +} + +private static DuffCode getTMtoTMW(int font, int code) { + if (code > 255-32) { + switch (code) { + case 8218-32: //sby + code = 130-32; + break; + + case 8230-32: //sgr + code = 133-32; + break; + + case 8225-32: //spr + code = 135-32; + break; + + case 8117-32: //tshw + code = 146-32; + break; + + case 8126-32: //rw + code = 149-32; + break; + + case 8482-32: //grw + code = 153-32; + break; + + default: + return null; + } + } + + return TMtoTMW[font][code]; +} + +private static int getTMFontNumber(String name) { + for (int i=1; i -1) + return hashKey; //because '+' remains part of Extended Wylie for Sanskrit stacks + + if (hashKey.charAt(0) == '-') + return hashKey; //because must be '-i' or '-I' vowels + + StringTokenizer st = new StringTokenizer(hashKey, "-"); + StringBuffer sb = new StringBuffer(); + + while (st.hasMoreTokens()) + sb.append(st.nextToken()); + + return sb.toString(); +} + +/** +* Gets the Extended Wylie value for this glyph. +* @param font the font of the TibetanMachineWeb +* glyph you want the Wylie of +* @param code the TibetanMachineWeb glyph +* you want the Wylie of +* @return the Wylie value corresponding to the +* glyph denoted by font, code +*/ +public static String getWylieForGlyph(int font, int code) { + String hashKey = getHashKeyForGlyph(font, code); + return wylieForGlyph(hashKey); +} + +/** +* Gets the Extended Wylie value for this glyph. +* @param dc the DuffCode of the glyph you want +* the Wylie of +* @return the Wylie value corresponding to the +* glyph denoted by dc +*/ +public static String getWylieForGlyph(DuffCode dc) { + String hashKey = getHashKeyForGlyph(dc); + return wylieForGlyph(hashKey); +} + +/** +* Says whether or not this glyph involves a Sanskrit stack. +* @param font the font of a TibetanMachineWeb glyph +* @param code the ASCII value of a TibetanMachineWeb glyph +* @return true if this glyph is a Sanskrit stack, +* false if not +*/ +public static boolean isSanskritStack(int font, int code) { + String val = toHashKey[font][code]; + if (val.indexOf(WYLIE_SANSKRIT_STACKING_KEY) == -1) + return false; + else + return true; +} + +/** +* Says whether or not this glyph involves a Sanskrit stack. +* @param dc the DuffCode of a TibetanMachineWeb glyph +* @return true if this glyph is a Sanskrit stack, +* false if not +*/ +public static boolean isSanskritStack(DuffCode dc) { + int font = dc.fontNum; + int code = dc.charNum-32; + + if (isSanskritStack(font, code)) + return true; + else + return false; +} + +/** +* Says whether or not this glyph involves a Tibetan stack. +* @param font the font of a TibetanMachineWeb glyph +* @param code the ASCII value of a TibetanMachineWeb glyph +* @return true if this glyph is a Tibetan stack, +* false if not +*/ +public static boolean isStack(int font, int code) { + String val = toHashKey[font][code]; + if (val.indexOf('-') < 1) //we allow '-i' and '-I' in as vowels + return false; + else + return true; +} + +/** +* Says whether or not this glyph involves a Tibetan stack. +* @param dc the DuffCode of a TibetanMachineWeb glyph +* @return true if this glyph is a Tibetan stack, +* false if not +*/ +public static boolean isStack(DuffCode dc) { + int font = dc.fontNum; + int code = dc.charNum-32; + + if (isStack(font, code)) + return true; + else + return false; +} + +/** +* Gets the hash with information about each character and stack. +* @return a hash containing a key for each +* entity defined in Wylie, whose object is the +* DuffCode for that key +*/ +public static Map getTibHash() { + return tibHash; +} + +/** +* Gets the hash for characters that require special bindus. +* @return a hash whose keys are all vowel glyphs (DuffCodes) +* that require a special bindu, and whose objects +* are the vowel+bindu glyph (DuffCode) corresponding to each +* such vowel glyph +*/ +public static Map getBinduMap() { + return binduMap; +} + +/** +* Returns true iff the keyboard has a disambiguating key. +* @return true if the installed keyboard has a disambiguating key, +* false if not +* @see TibetanKeyboard */ +public static boolean hasDisambiguatingKey() { + return hasDisambiguatingKey; +} + +/** +* Gets the disambiguating key. +* @return the disambiguating key for the installed +* keyboard, or ' ' if there is no such key +* @see TibetanKeyboard +*/ +public static char getDisambiguatingKey() { + return disambiguating_key; +} + +/** +* Returns true iff the keyboard has a Sanksrit stacking key. +* @return true if a stacking key is required to type Sanskrit stacks, +* false if not +* @see TibetanKeyboard */ +public static boolean hasSanskritStackingKey() { + return hasSanskritStackingKey; +} + +/** +* Returns true iff the keyboard has a Tibetan stacking key. +* @return true if a stacking key is required to type Tibetan stacks, +* false if not +* @see TibetanKeyboard */ +public static boolean hasTibetanStackingKey() { + return hasTibetanStackingKey; +} + +/** +* Returns true iff stacking is medial. +* @return true if the stacking key is medial, false if not, or if +* there is no stacking key +* @see TibetanKeyboard */ +public static boolean isStackingMedial() { + return isStackingMedial; +} + +/** +* Gets the stacking key. +* @return the stacking key, or ' ' if there +* isn't one +* @see TibetanKeyboard +*/ +public static char getStackingKey() { + return stacking_key; +} + +/** +* Returns true iff achen is required before vowels. +* @return true if you have to type achen first before you can get a +* vowel with achen, false if you can just type the vowel by itself (as +* in Wylie) +* @see TibetanKeyboard */ +public static boolean isAChenRequiredBeforeVowel() { + return isAChenRequiredBeforeVowel; +} + +/** +* Returns true iff achung is treated as a consonant. +* @return true if a-chung is considered a consonant for the purposes +* of stacking, false if not (as in Wylie) +* @see TibetanKeyboard */ +public static boolean isAChungConsonant() { + return isAChungConsonant; +} + +/** +* Returns true iff there is a key for the invisible 'a' vowel in this +* keyboard. +* @return true if the installed keyboard has a dummy a vowel, false if +* not +* @see TibetanKeyboard */ +public static boolean hasAVowel() { + return hasAVowel; +} + +/** +* Gets the invisible 'a' vowel. +* @return the dummy 'a'-vowel for the installed +* keyboard, or "" if there is no such vowel +* @see TibetanKeyboard +*/ +public static String getAVowel() { + return aVowel; +} + +/** +* Returns true iff this glyph is a top (superscript) vowel. +* @param a DuffCode representing a TibetanMachineWeb glyph +* @return true if the glyph is a top-hanging (superscript) vowel (i, +* u, e, o, ai, or ao) and false if not */ +public static boolean isTopVowel(DuffCode dc) { + String wylie = getWylieForGlyph(dc); + if (top_vowels.contains(wylie)) + return true; + + return false; +} +}