1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1996-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.demo.translit; 10 11 import java.awt.Button; 12 import java.awt.CheckboxMenuItem; 13 import java.awt.FileDialog; 14 import java.awt.Font; 15 import java.awt.Frame; 16 import java.awt.GraphicsEnvironment; 17 import java.awt.Label; 18 import java.awt.Menu; 19 import java.awt.MenuBar; 20 import java.awt.MenuItem; 21 import java.awt.MenuShortcut; 22 import java.awt.TextField; 23 import java.awt.event.ActionEvent; 24 import java.awt.event.ActionListener; 25 import java.awt.event.ItemEvent; 26 import java.awt.event.ItemListener; 27 import java.awt.event.KeyEvent; 28 import java.awt.event.WindowAdapter; 29 import java.awt.event.WindowEvent; 30 import java.io.BufferedReader; 31 import java.io.BufferedWriter; 32 import java.io.File; 33 import java.io.FileInputStream; 34 import java.io.FileOutputStream; 35 import java.io.InputStreamReader; 36 import java.io.OutputStreamWriter; 37 import java.io.PrintWriter; 38 import java.text.CharacterIterator; 39 import java.util.Comparator; 40 import java.util.Enumeration; 41 import java.util.HashMap; 42 import java.util.Iterator; 43 import java.util.Map; 44 import java.util.Set; 45 import java.util.TreeSet; 46 47 import com.ibm.icu.lang.UCharacter; 48 import com.ibm.icu.text.BreakIterator; 49 import com.ibm.icu.text.CanonicalIterator; 50 import com.ibm.icu.text.Normalizer; 51 import com.ibm.icu.text.ReplaceableString; 52 import com.ibm.icu.text.Transliterator; 53 import com.ibm.icu.text.UTF16; 54 import com.ibm.icu.text.UnicodeSet; 55 import com.ibm.icu.text.UnicodeSetIterator; 56 57 /** 58 * A frame that allows the user to experiment with keyboard 59 * transliteration. This class has a main() method so it can be run 60 * as an application. The frame contains an editable text component 61 * and uses keyboard transliteration to process keyboard events. 62 * 63 * <p>Copyright (c) IBM Corporation 1999. All rights reserved. 64 * 65 * @author Alan Liu 66 */ 67 public class Demo extends Frame { 68 69 /** 70 * For serialization 71 */ 72 private static final long serialVersionUID = 1L; 73 static final boolean DEBUG = false; 74 static final String START_TEXT = "(cut,\u03BA\u03C5\u03C4,\u05D0,\u30AF\u30C8,\u4E80,\u091A\u0941\u0924\u094D)"; 75 76 Transliterator translit = null; 77 String fontName = "Arial Unicode MS"; 78 int fontSize = 18; 79 80 81 82 /* 83 boolean compound = false; 84 Transliterator[] compoundTranslit = new Transliterator[MAX_COMPOUND]; 85 static final int MAX_COMPOUND = 128; 86 int compoundCount = 0; 87 */ 88 89 TransliteratingTextComponent text = null; 90 91 Menu translitMenu; 92 CheckboxMenuItem translitItem; 93 CheckboxMenuItem noTranslitItem; 94 95 static final String NO_TRANSLITERATOR = "None"; 96 97 public static void main(String[] args) { 98 Frame f = new Demo(600, 200); 99 f.addWindowListener(new WindowAdapter() { 100 public void windowClosing(WindowEvent e) { 101 com.ibm.icu.dev.demo.impl.DemoApplet.demoFrameClosed(); 102 // System.exit(0); 103 } 104 }); 105 f.setVisible(true); 106 com.ibm.icu.dev.demo.impl.DemoApplet.demoFrameOpened(); 107 } 108 109 public Demo(int width, int height) { 110 super("Transliteration Demo"); 111 112 initMenus(); 113 114 addWindowListener(new WindowAdapter() { 115 public void windowClosing(WindowEvent e) { 116 handleClose(); 117 } 118 }); 119 120 text = new TransliteratingTextComponent(); 121 Font font = new Font(fontName, Font.PLAIN, fontSize); 122 text.setFont(font); 123 text.setSize(width, height); 124 text.setVisible(true); 125 text.setText(START_TEXT); 126 add(text); 127 128 setSize(width, height); 129 setTransliterator("Latin-Greek", null); 130 } 131 132 private void initMenus() { 133 MenuBar mbar; 134 Menu menu; 135 MenuItem mitem; 136 //CheckboxMenuItem citem; 137 138 setMenuBar(mbar = new MenuBar()); 139 mbar.add(menu = new Menu("File")); 140 menu.add(mitem = new MenuItem("Quit")); 141 mitem.addActionListener(new ActionListener() { 142 public void actionPerformed(ActionEvent e) { 143 handleClose(); 144 } 145 }); 146 /* 147 final ItemListener setTransliteratorListener = new ItemListener() { 148 public void itemStateChanged(ItemEvent e) { 149 CheckboxMenuItem item = (CheckboxMenuItem) e.getSource(); 150 if (e.getStateChange() == ItemEvent.DESELECTED) { 151 // Don't let the current transliterator be deselected. 152 // Just reselect it. 153 item.setState(true); 154 } else if (compound) { 155 // Adding an item to a compound transliterator 156 handleAddToCompound(item.getLabel()); 157 } else if (item != translitItem) { 158 // Deselect previous choice. Don't need to call 159 // setState(true) on new choice. 160 translitItem.setState(false); 161 translitItem = item; 162 handleSetTransliterator(item.getLabel()); 163 } 164 } 165 }; 166 */ 167 /* 168 translitMenu.add(translitItem = noTranslitItem = 169 new CheckboxMenuItem(NO_TRANSLITERATOR, true)); 170 noTranslitItem.addItemListener(new ItemListener() { 171 public void itemStateChanged(ItemEvent e) { 172 // Can't uncheck None -- any action here sets None to true 173 setNoTransliterator(); 174 } 175 }); 176 177 translitMenu.addSeparator(); 178 */ 179 180 /* 181 translitMenu.add(citem = new CheckboxMenuItem("Compound")); 182 citem.addItemListener(new ItemListener() { 183 public void itemStateChanged(ItemEvent e) { 184 CheckboxMenuItem item = (CheckboxMenuItem) e.getSource(); 185 if (e.getStateChange() == ItemEvent.DESELECTED) { 186 // If compound gets deselected, then select NONE 187 setNoTransliterator(); 188 } else if (!compound) { 189 // Switching from non-compound to compound 190 translitItem.setState(false); 191 translitItem = item; 192 translit = null; 193 compound = true; 194 compoundCount = 0; 195 for (int i=0; i<MAX_COMPOUND; ++i) { 196 compoundTranslit[i] = null; 197 } 198 } 199 } 200 }); 201 202 translitMenu.addSeparator(); 203 */ 204 205 /* 206 for (Enumeration e=getSystemTransliteratorNames().elements(); 207 e.hasMoreElements(); ) { 208 String s = (String) e.nextElement(); 209 translitMenu.add(citem = new CheckboxMenuItem(s)); 210 citem.addItemListener(setTransliteratorListener); 211 } 212 */ 213 214 Menu fontMenu = new Menu("Font"); 215 String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); 216 for (int i = 0; i < fonts.length; ++i) { 217 MenuItem mItem = new MenuItem(fonts[i]); 218 mItem.addActionListener(new FontActionListener(fonts[i])); 219 fontMenu.add(mItem); 220 } 221 mbar.add(fontMenu); 222 223 Menu sizeMenu = new Menu("Size"); 224 int[] sizes = {9, 10, 12, 14, 18, 24, 36, 48, 72}; 225 for (int i = 0; i < sizes.length; ++i) { 226 MenuItem mItem = new MenuItem("" + sizes[i]); 227 mItem.addActionListener(new SizeActionListener(sizes[i])); 228 sizeMenu.add(mItem); 229 } 230 mbar.add(sizeMenu); 231 232 translit = null; 233 234 mbar.add(translitMenu = new Menu("Transliterator")); 235 236 translitMenu.add(convertSelectionItem = new MenuItem("Transliterate", 237 new MenuShortcut(KeyEvent.VK_K))); 238 convertSelectionItem.addActionListener(new ActionListener() { 239 public void actionPerformed(ActionEvent e) { 240 handleBatchTransliterate(translit); 241 } 242 }); 243 244 translitMenu.add(swapSelectionItem = new MenuItem("Reverse", 245 new MenuShortcut(KeyEvent.VK_S))); 246 swapSelectionItem.addActionListener(new ActionListener() { 247 public void actionPerformed(ActionEvent e) { 248 Transliterator inv; 249 try { 250 inv = translit.getInverse(); 251 } catch (Exception x) { 252 inv = Transliterator.getInstance("null"); 253 } 254 setTransliterator(inv.getID(), null); 255 } 256 }); 257 258 translitMenu.add(convertTypingItem = new MenuItem("No Typing Conversion", 259 new MenuShortcut(KeyEvent.VK_T))); 260 convertTypingItem.addActionListener(new ActionListener() { 261 public void actionPerformed(ActionEvent e) { 262 if (!transliterateTyping) { 263 text.setTransliterator(translit); 264 convertTypingItem.setLabel("No Typing Conversion"); 265 } else { 266 text.flush(); 267 text.setTransliterator(null); 268 convertTypingItem.setLabel("Convert Typing"); 269 } 270 transliterateTyping = !transliterateTyping; 271 } 272 }); 273 274 translitMenu.add(historyMenu = new Menu("Recent")); 275 276 helpDialog = new InfoDialog(this, "Simple Demo", "Instructions", 277 "CTL A, X, C, V have customary meanings.\n" 278 + "Arrow keys, delete and backspace work.\n" 279 + "To get a character from its control point, type the hex, then hit CTL Q" 280 ); 281 helpDialog.getArea().setEditable(false); 282 283 284 Menu helpMenu; 285 mbar.add(helpMenu = new Menu("Extras")); 286 helpMenu.add(mitem = new MenuItem("Help")); 287 mitem.addActionListener(new ActionListener() { 288 public void actionPerformed(ActionEvent e) { 289 helpDialog.show(); 290 } 291 }); 292 293 hexDialog = new InfoDialog(this, "Hex Entry", "Use U+..., \\u..., \\x{...}, or &#x...;", 294 "\\u00E1" 295 ); 296 Button button = new Button("Insert"); 297 button.addActionListener(new ActionListener() { 298 public void actionPerformed(ActionEvent e) { 299 String hexValue = hexDialog.getArea().getText(); 300 text.insertText(fromHex.transliterate(hexValue)); 301 } 302 }); 303 hexDialog.getBottom().add(button); 304 305 helpMenu.add(mitem = new MenuItem("Hex...", 306 new MenuShortcut(KeyEvent.VK_H))); 307 mitem.addActionListener(new ActionListener() { 308 public void actionPerformed(ActionEvent e) { 309 hexDialog.show(); 310 } 311 }); 312 313 // Compound Transliterator 314 315 compoundDialog = new InfoDialog(this, "Compound Transliterator", "", 316 "[^\\u0000-\\u00FF] hex" 317 ); 318 button = new Button("Set"); 319 button.addActionListener(new ActionListener() { 320 public void actionPerformed(ActionEvent e) { 321 String compound = ""; 322 try { 323 compound = compoundDialog.getArea().getText(); 324 setTransliterator(compound, null); 325 } catch (RuntimeException ex) { 326 compoundDialog.getArea().setText(compound + "\n" + ex.getMessage()); 327 } 328 } 329 }); 330 compoundDialog.getBottom().add(button); 331 332 translitMenu.add(mitem = new MenuItem("Multiple...", 333 new MenuShortcut(KeyEvent.VK_M))); 334 mitem.addActionListener(new ActionListener() { 335 public void actionPerformed(ActionEvent e) { 336 compoundDialog.show(); 337 } 338 }); 339 340 // RuleBased Transliterator 341 342 rulesDialog = new InfoDialog(this, "Rule-Based Transliterator", "", 343 "([A-Z]) > &Hex($1) &Name($1);\r\n" 344 + "&Hex-Any($1) < ('\\' [uU] [a-fA-F0-9]*);\r\n" 345 + "&Name-Any($1) < ('{' [^\\}]* '}');" 346 ); 347 button = new Button("Set"); 348 button.addActionListener(new ActionListener() { 349 public void actionPerformed(ActionEvent e) { 350 String compound = ""; 351 try { 352 compound = rulesDialog.getArea().getText(); 353 String id = ruleId.getText(); 354 setTransliterator(compound, id); 355 } catch (RuntimeException ex) { 356 rulesDialog.getArea().setText(compound + "\n#" + ex.getMessage()); 357 } 358 } 359 }); 360 rulesDialog.getBottom().add(button); 361 ruleId = new TextField("test1", 20); 362 Label temp = new Label(" Name:"); 363 rulesDialog.getBottom().add(temp); 364 rulesDialog.getBottom().add(ruleId); 365 366 367 translitMenu.add(mitem = new MenuItem("From Rules...", 368 new MenuShortcut(KeyEvent.VK_R))); 369 mitem.addActionListener(new ActionListener() { 370 public void actionPerformed(ActionEvent e) { 371 rulesDialog.show(); 372 } 373 }); 374 375 376 translitMenu.add(mitem = new MenuItem("From File...", 377 new MenuShortcut(KeyEvent.VK_F))); 378 mitem.addActionListener(new FileListener(this, RULE_FILE)); 379 380 translitMenu.add(mitem = new MenuItem("Test File...")); 381 mitem.addActionListener(new FileListener(this, TEST_FILE)); 382 383 // Flesh out the menu with the installed transliterators 384 385 translitMenu.addSeparator(); 386 387 Iterator sources = add(new TreeSet(), Transliterator.getAvailableSources()).iterator(); 388 while(sources.hasNext()) { 389 String source = (String) sources.next(); 390 Iterator targets = add(new TreeSet(), Transliterator.getAvailableTargets(source)).iterator(); 391 Menu targetMenu = new Menu(source); 392 while(targets.hasNext()) { 393 String target = (String) targets.next(); 394 Set variantSet = add(new TreeSet(), Transliterator.getAvailableVariants(source, target)); 395 if (variantSet.size() < 2) { 396 mitem = new MenuItem(target); 397 mitem.addActionListener(new TransliterationListener(source + "-" + target)); 398 targetMenu.add(mitem); 399 } else { 400 Iterator variants = variantSet.iterator(); 401 Menu variantMenu = new Menu(target); 402 while(variants.hasNext()) { 403 String variant = (String) variants.next(); 404 String menuName = variant.length() == 0 ? "<default>" : variant; 405 //System.out.println("<" + source + "-" + target + "/" + variant + ">, <" + menuName + ">"); 406 mitem = new MenuItem(menuName); 407 mitem.addActionListener(new TransliterationListener(source + "-" + target + "/" + variant)); 408 variantMenu.add(mitem); 409 } 410 targetMenu.add(variantMenu); 411 } 412 } 413 translitMenu.add(targetMenu); 414 } 415 416 417 } 418 419 static final int RULE_FILE = 0, TEST_FILE = 1; 420 // 421 static class FileListener implements ActionListener { 422 Demo frame; 423 int choice; 424 425 FileListener(Demo frame, int choice) { 426 this.frame = frame; 427 this.choice = choice; 428 } 429 430 public void actionPerformed(ActionEvent e) { 431 String id = frame.translit.getID(); 432 int slashPos = id.indexOf('/'); 433 String variant = ""; 434 if (slashPos >= 0) { 435 variant = "_" + id.substring(slashPos+1); 436 id = id.substring(0, slashPos); 437 } 438 439 FileDialog fileDialog = new FileDialog(frame, "Input File"); 440 fileDialog.setFile("Test_" + id + ".txt"); 441 fileDialog.show(); 442 String fileName = fileDialog.getFile(); 443 String fileDirectory = fileDialog.getDirectory(); 444 if (fileName != null) { 445 try { 446 File f = new File(fileDirectory, fileName); 447 if (choice == RULE_FILE) { 448 449 // read stuff into buffer 450 451 StringBuffer buffer = new StringBuffer(); 452 FileInputStream fis = new FileInputStream(f); 453 InputStreamReader isr = new InputStreamReader(fis, "UTF8"); 454 BufferedReader br = new BufferedReader(isr, 32*1024); 455 while (true) { 456 String line = br.readLine(); 457 if (line == null) break; 458 if (line.length() > 0 && line.charAt(0) == '\uFEFF') line = line.substring(1); // strip BOM 459 buffer.append('\n'); 460 buffer.append(line); 461 } 462 br.close(); 463 464 // Transform file name into id 465 if (fileName.startsWith("Transliterator_")) { 466 fileName = fileName.substring("Transliterator_".length()); 467 } 468 int pos = fileName.indexOf('_'); 469 if (pos < 0) { 470 id = fileName; 471 } else { 472 id = fileName.substring(0, pos) + "-"; 473 int pos2 = fileName.indexOf('_', pos+1); 474 if (pos2 < 0) { 475 id += fileName.substring(pos+1); 476 } else { 477 id += fileName.substring(pos+1, pos2) + "/" + fileName.substring(pos2 + 1); 478 } 479 } 480 pos = id.lastIndexOf('.'); 481 if (pos >= 0) id = id.substring(0, pos); 482 483 // Now set 484 485 frame.setTransliterator(buffer.toString(), id); 486 } else if (choice == TEST_FILE) { 487 genTestFile(f, frame.translit, variant); 488 } 489 } catch (Exception e2) { 490 e2.printStackTrace(); 491 System.out.println("Problem opening/reading: " + fileDirectory + ", " + fileName); 492 } 493 } 494 fileDialog.dispose(); 495 } 496 } 497 498 499 boolean transliterateTyping = true; 500 Transliterator fromHex = Transliterator.getInstance("Hex-Any"); 501 InfoDialog helpDialog; 502 InfoDialog hexDialog; 503 InfoDialog compoundDialog; 504 InfoDialog rulesDialog; 505 TextField ruleId; 506 MenuItem convertSelectionItem = null; 507 MenuItem swapSelectionItem = null; 508 MenuItem convertTypingItem = null; 509 Menu historyMenu; 510 Map historyMap = new HashMap(); 511 Set historySet = new TreeSet(new Comparator() { 512 public int compare(Object a, Object b) { 513 MenuItem aa = (MenuItem)a; 514 MenuItem bb = (MenuItem)b; 515 return aa.getLabel().compareTo(bb.getLabel()); 516 } 517 }); 518 519 // ADD Factory since otherwise getInverse blows out 520 static class DummyFactory implements Transliterator.Factory { 521 static DummyFactory singleton = new DummyFactory(); 522 static HashMap m = new HashMap(); 523 524 // Since Transliterators are immutable, we don't have to clone on set & get 525 static void add(String ID, Transliterator t) { 526 m.put(ID, t); 527 System.out.println("Registering: " + ID + ", " + t.toRules(true)); 528 Transliterator.registerFactory(ID, singleton); 529 } 530 public Transliterator getInstance(String ID) { 531 return (Transliterator) m.get(ID); 532 } 533 } 534 535 static void printBreaks(int num, String testSource, BreakIterator brkItr) { 536 String result = ""; 537 int lastPos = 0; 538 while (true) { 539 int pos = brkItr.next(); 540 if (pos == BreakIterator.DONE) break; 541 result += testSource.substring(lastPos, pos) + "&"; 542 lastPos = pos; 543 System.out.println(pos); 544 } 545 System.out.println("Test" + num + ": " + result); 546 } 547 548 static void printIteration(int num, String testSource, CharacterIterator ci) { 549 String result = ""; 550 while (true) { 551 char ch = ci.next(); 552 if (ch == CharacterIterator.DONE) break; 553 result += ch + "(" + ci.getIndex() + ")"; 554 } 555 System.out.println("Test" + num + ": " + result); 556 } 557 558 static void printSources() { 559 String[] list = {"Latin-ThaiLogical", "ThaiLogical-Latin", "Thai-ThaiLogical", "ThaiLogical-Thai"}; 560 UnicodeSet all = new UnicodeSet(); 561 for (int i = 0; i < list.length; ++i) { 562 Transliterator tr = Transliterator.getInstance(list[i]); 563 UnicodeSet src = tr.getSourceSet(); 564 System.out.println(list[i] + ": " + src.toPattern(true)); 565 all.addAll(src); 566 } 567 System.out.println("All: " + all.toPattern(true)); 568 UnicodeSet rem = new UnicodeSet("[[:latin:][:thai:]]"); 569 System.out.println("missing from [:latin:][:thai:]: " + all.removeAll(rem).toPattern(true)); 570 } 571 572 // 200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;; 573 574 static Transliterator title = Transliterator.getInstance("title"); 575 static String hexAndNameRules = " ([:c:]) > \\u200E &hex/unicode($1) ' ( ) ' &name($1) \\u200E ' ';" 576 + "([:mark:]) > \\u200E &hex/unicode($1) ' ( ' \\u200E \u25CC $1 \\u200E ' ) ' &name($1) \\u200E ' ';" 577 + "(.) > \\u200E &hex/unicode($1) ' ( ' \\u200E $1 \\u200E ' ) ' &name($1) ' ' \\u200E;"; 578 579 static Transliterator hexAndName = Transliterator.createFromRules("any-hexAndName", 580 hexAndNameRules, Transliterator.FORWARD); 581 582 583 584 //static Transliterator upper = Transliterator.getInstance("upper"); 585 586 static final byte NONE = 0, TITLEWORD = 1, TITLELINE = 2; 587 588 static void genTestFile(File sourceFile, Transliterator translit, String variant) { 589 BufferedReader in = null; 590 try { 591 592 System.out.println("Reading: " + sourceFile.getCanonicalPath()); 593 in = new BufferedReader( 594 new InputStreamReader( 595 new FileInputStream(sourceFile), "UTF-8")); 596 String targetFile = sourceFile.getCanonicalPath(); 597 int dotPos = targetFile.lastIndexOf('.'); 598 if (dotPos >= 0) targetFile = targetFile.substring(0,dotPos); 599 targetFile += variant; 600 601 File outFile = new File(targetFile + ".html"); 602 System.out.println("Writing: " + outFile.getCanonicalPath()); 603 604 PrintWriter out = new PrintWriter( 605 new BufferedWriter( 606 new OutputStreamWriter( 607 new FileOutputStream(outFile), "UTF-8"))); 608 609 String direction = ""; 610 String id = translit.getID(); 611 if (id.indexOf("Arabic") >= 0 || id.indexOf("Hebrew") >= 0) { 612 direction = " direction: rtl;"; 613 } 614 boolean testRoundTrip = true; 615 boolean generateSets = true; 616 if (id.startsWith("Han-") || id.startsWith("ja-")) { 617 testRoundTrip = false; 618 generateSets = false; 619 } 620 out.println("<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"); 621 out.println("<style><!--"); 622 out.println("td, th { vertical-align: top; border: 1px solid black }"); 623 out.println("td.s { background-color: #EEEEEE;" + direction + " }"); 624 out.println("td.r { background-color: #CCCCCC;" + direction + " }"); 625 out.println("td.n { background-color: #FFFFCC; }"); 626 out.println("td.title { border: 0px solid black}"); 627 out.println("span.d { background-color: #FF6666 }"); 628 out.println("span.r { background-color: #66FF66 }"); 629 630 out.println("body { font-family: 'Arial Unicode MS', 'Lucida Sans Unicode', Arial, sans-serif; margin: 5 }"); 631 out.println("--></style>"); 632 out.println("<title>" + id + " Transliteration Check</title></head>"); 633 out.println("<body bgcolor='#FFFFFF'><p>See <a href='Test_Instructions.html'>Test_Instructions.html</a> for details.</p>"); 634 out.println("<table>"); 635 636 //out.println("<tr><th width='33%'>Thai</th><th width='33%'>Latin</th><th width='33%'>Thai</th></tr>"); 637 638 Transliterator tl = translit; 639 Transliterator lt = tl.getInverse(); 640 641 Transliterator ltFilter = tl.getInverse(); 642 ltFilter.setFilter(new UnicodeSet("[:^Lu:]")); 643 Transliterator tlFilter = lt.getInverse(); 644 tlFilter.setFilter(new UnicodeSet("[:^Lu:]")); 645 646 //Transliterator.getInstance("[:^Lu:]" + lt.getID()); 647 648 BreakIterator sentenceBreak = BreakIterator.getSentenceInstance(); 649 650 byte titleSetting = TITLELINE; 651 //boolean upperfilter = false; 652 boolean first = true; 653 while (true) { 654 String line = in.readLine(); 655 if (line == null) break; 656 line = line.trim(); 657 if (line.length() == 0) continue; 658 if (line.charAt(0) == '\uFEFF') line = line.substring(1); // remove BOM 659 660 if (line.charAt(0) == '#') continue; // comments 661 662 if (line.equals("@TITLECASE@")) { 663 titleSetting = TITLEWORD; 664 out.println("<tr><td colspan='2' class='title'><b>Names</b></td></tr>"); 665 continue; 666 } else if (line.equals("@UPPERFILTER@")) { 667 //upperfilter = true; 668 continue; 669 } else if (line.startsWith("@SET")) { 670 UnicodeSet s = new UnicodeSet(line.substring(4).trim()); 671 out.println("<tr><td colspan='2' class='title'><b>Characters</b></td></tr>"); 672 UnicodeSetIterator it = new UnicodeSetIterator(s); 673 while (it.next()) { 674 addSentenceToTable(out, it.codepoint != UnicodeSetIterator.IS_STRING 675 ? UTF16.valueOf(it.codepoint) 676 : it.string, 677 NONE, true, testRoundTrip, first, tl, lt); 678 } 679 continue; 680 } 681 682 sentenceBreak.setText(line); 683 int start = 0; 684 while (true) { 685 int end = sentenceBreak.next(); 686 if (end == BreakIterator.DONE) break; 687 String coreSentence = line.substring(start, end); 688 //System.out.println("Core: " + hex.transliterate(coreSentence)); 689 end = start; 690 691 int oldPos = 0; 692 while (oldPos < coreSentence.length()) { 693 // hack, because sentence doesn't seem to be working right 694 int pos = coreSentence.indexOf(". ", oldPos); 695 if (pos < 0) pos = coreSentence.length(); else pos = pos+2; 696 int pos2 = coreSentence.indexOf('\u3002', oldPos); 697 if (pos2 < 0) pos2 = coreSentence.length(); else pos2 = pos2 + 1; 698 if (pos > pos2) pos = pos2; 699 String sentence = coreSentence.substring(oldPos, pos).trim(); 700 //System.out.println("Sentence: " + hex.transliterate(coreSentence)); 701 oldPos = pos; 702 703 addSentenceToTable(out, sentence, 704 titleSetting, false, testRoundTrip, first, tl, lt); 705 706 first = false; 707 } 708 } 709 } 710 out.println("</table></body>"); 711 out.close(); 712 713 // Now write the source/target sets 714 if (generateSets) { 715 outFile = new File(targetFile + "_Sets.html"); 716 System.out.println("Writing: " + outFile.getCanonicalPath()); 717 718 out = new PrintWriter( 719 new BufferedWriter( 720 new OutputStreamWriter( 721 new FileOutputStream(outFile), "UTF-8"))); 722 out.println("<head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"); 723 out.println("<style><!--"); 724 out.println("body { font-family: 'Arial Unicode MS', 'Lucida Sans Unicode', Arial, sans-serif; margin: 5 }"); 725 out.println("--></style>"); 726 out.println("<title>" + id + " Transliteration Sets</title></head>"); 727 out.println("<body bgcolor='#FFFFFF'>"); 728 729 int dashPos = id.indexOf('-'); 730 int slashPos = id.indexOf('/'); 731 if (slashPos < 0) slashPos = id.length(); 732 UnicodeSet sourceSuper = null; 733 try { 734 String temp = id.substring(0,dashPos); 735 if (temp.equals("ja")) sourceSuper = new UnicodeSet("[[:Han:][:hiragana:][:katakana:]]"); 736 else sourceSuper = new UnicodeSet("[[:" + temp + ":][:Mn:][:Me:]]"); 737 } catch (Exception e) {} 738 739 UnicodeSet targetSuper = null; 740 try { 741 targetSuper = new UnicodeSet("[[:" + id.substring(dashPos+1, slashPos) + ":][:Mn:][:Me:]]"); 742 } catch (Exception e) {} 743 744 int nfdStyle = CLOSE_CASE | CLOSE_FLATTEN | CLOSE_CANONICAL; 745 int nfkdStyle = nfdStyle | CLOSE_COMPATIBILITY; 746 out.println("<ul>"); 747 out.println("<p><b>None</b></p>"); 748 showSets(out, translit, lt, null, null, 0); 749 out.println("<p><b>NFD</b></p>"); 750 showSets(out, translit, lt, sourceSuper, targetSuper, nfdStyle); 751 out.println("<p><b>NFKD</b></p>"); 752 showSets(out, translit, lt, sourceSuper, targetSuper, nfkdStyle); 753 out.println("</ul></body>"); 754 out.close(); 755 } 756 System.out.println("Done Writing"); 757 } catch (Exception e) { 758 e.printStackTrace(); 759 } finally { 760 if (in != null) { 761 try { 762 in.close(); 763 } catch (Exception e) { 764 // ignore 765 } 766 } 767 } 768 } 769 770 static void addSentenceToTable(PrintWriter out, String sentence, 771 byte titleSetting, boolean addName, boolean testRoundTrip, boolean first, 772 Transliterator tl, Transliterator lt) { 773 if (sentence.length() == 0) return; // skip empty lines 774 775 String originalShow = sentence; 776 String latin; 777 latin = tl.transliterate(saveAscii.transliterate(sentence)); 778 779 String latinShow = latin; 780 if (titleSetting == TITLEWORD) { 781 latinShow = title.transliterate(latin); 782 } else if (titleSetting == TITLELINE) { 783 latinShow = titlecaseFirstWord(latinShow); 784 } 785 latinShow = restoreAscii.transliterate(latinShow); 786 787 String reverse; 788 reverse = restoreAscii.transliterate(lt.transliterate(latin)); 789 790 String NFKDSentence = Normalizer.normalize(sentence, Normalizer.NFKD); 791 String NFKDLatin = Normalizer.normalize(latin, Normalizer.NFKD); 792 String NFKDReverse = Normalizer.normalize(reverse, Normalizer.NFKD); 793 794 if (latinShow.length() == 0) { 795 latinShow = "<i>empty</i>"; 796 } else if (NFKDSentence.equals(NFKDLatin)) { 797 latinShow = "<span class='r'>" + latinShow + "</span>"; 798 } 799 String reverseShow = reverse; 800 801 if (testRoundTrip && !NFKDReverse.equals(NFKDSentence)) { 802 int minLen = reverse.length(); 803 if (minLen > sentence.length()) minLen = sentence.length(); 804 int i; 805 for (i = 0; i < minLen; ++i) { 806 if (reverse.charAt(i) != sentence.charAt(i)) break; 807 } 808 //originalShow = sentence.substring(0,i) + "<span class='d'>" + sentence.substring(i) + "</span>"; 809 reverseShow = reverseShow.length() == 0 810 ? "<i>empty</i>" 811 //: reverse.substring(0,i) + "<span class='d'>" + reverse.substring(i) + "</span>"; 812 : showDifference(sentence, reverse); 813 out.println("<tr><td class='s'" + (first ? " width='50%'>" : ">") + originalShow 814 + "</td><td rowSpan='2'>" + latinShow 815 + "</td></tr><tr><td class='r'>" + reverseShow 816 + "</td></tr>"); 817 } else { 818 out.println("<tr><td class='s'" + (first ? " width='50%'>" : ">") + originalShow 819 + "</td><td>" + latinShow 820 + "</td></tr>"); 821 } 822 if (addName) { 823 latinShow = hexAndName.transliterate(latin); 824 if (latinShow.length() == 0) latinShow = "<i>empty</i>"; 825 originalShow = hexAndName.transliterate(sentence); 826 if (originalShow.length() == 0) originalShow = "<i>empty</i>"; 827 828 out.println("<tr><td class='n'>" + originalShow 829 + "</td><td class='n'>" + latinShow 830 + "</td></tr>"); 831 } 832 out.println("<tr><td></td></tr>"); 833 834 } 835 836 static String showDifference(String as, String bs) { 837 IntDiffer differ = new IntDiffer(300, 3); 838 StringBuilder out = new StringBuilder(); 839 int ia = 0; 840 int ib = 0; 841 boolean done; 842 do { 843 done = true; 844 if (ia < as.length()) { 845 int ca = as.codePointAt(ia); 846 ia += Character.charCount(ca); 847 differ.addA(ca); 848 done = false; 849 } 850 if (ib < bs.length()) { 851 int cb = bs.codePointAt(ib); 852 ib += Character.charCount(cb); 853 differ.addB(cb); 854 done = false; 855 } 856 differ.checkMatch(done); 857 858 if (differ.getACount() != 0 || differ.getBCount() != 0) { 859 out.append("..."); 860 if (differ.getACount() != 0) { 861 out.append("<span class='r'>"); 862 for (int i = 0; i < differ.getACount(); ++i) { 863 out.appendCodePoint(differ.getA(i)); 864 } 865 out.append("</span>"); 866 } 867 if (differ.getBCount() != 0) { 868 out.append("<span class='d'>"); 869 for (int i = 0; i < differ.getBCount(); ++i) { 870 out.appendCodePoint(differ.getB(i)); 871 } 872 out.append("</span>"); 873 } 874 out.append("..."); 875 } 876 } while (!done); 877 return out.toString(); 878 } 879 880 static void showSets(PrintWriter out, Transliterator translit, Transliterator inverse, 881 UnicodeSet sourceSuper, UnicodeSet targetSuper, int options) { 882 out.println("<li>Source Set:<ul><li>" + toPattern(closeUnicodeSet(translit.getSourceSet(), options), sourceSuper) + "</li></ul></li>"); 883 out.println("<li>Reverse Target Set:<ul><li>" + toPattern(closeUnicodeSet(inverse.getTargetSet(), options), sourceSuper) + "</li></ul></li>"); 884 out.println("<li>Target Set:<ul><li>" + toPattern(closeUnicodeSet(translit.getTargetSet(), options), targetSuper) + "</li></ul></li>"); 885 out.println("<li>Reverse Source Set:<ul><li>" + toPattern(closeUnicodeSet(inverse.getSourceSet(), options), targetSuper) + "</li></ul></li>"); 886 } 887 888 static final int CLOSE_CASE = 1, CLOSE_FLATTEN = 2, CLOSE_CANONICAL = 4, CLOSE_COMPATIBILITY = 8; 889 890 static UnicodeSet closeUnicodeSet(UnicodeSet source, int options) { 891 if (options == 0) return source; 892 893 UnicodeSetIterator it = new UnicodeSetIterator(source); 894 UnicodeSet additions = new UnicodeSet(); // to avoid messing up iterator 895 UnicodeSet removals = new UnicodeSet(); // to avoid messing up iterator 896 String base; 897 int cp; 898 899 // Add all case equivalents 900 if ((options & CLOSE_CASE) != 0) { 901 while (it.next()) { 902 cp = it.codepoint; 903 if (cp == UnicodeSetIterator.IS_STRING) continue; 904 int type = UCharacter.getType(cp); 905 if (type == Character.UPPERCASE_LETTER || type == Character.LOWERCASE_LETTER || type == Character.TITLECASE_LETTER) { 906 additions.add(UCharacter.toLowerCase(UTF16.valueOf(cp))); 907 additions.add(UCharacter.toUpperCase(UTF16.valueOf(cp))); 908 } 909 } 910 source.addAll(additions); 911 } 912 913 // Add the canonical closure of all strings and characters in source 914 if ((options & CLOSE_CANONICAL) != 0) { 915 it.reset(); 916 additions.clear(); 917 CanonicalIterator ci = new CanonicalIterator("."); 918 while (it.next()) { 919 if (it.codepoint == UnicodeSetIterator.IS_STRING) base = it.string; 920 else base = UTF16.valueOf(it.codepoint); 921 ci.setSource(base); 922 while (true) { 923 String trial = ci.next(); 924 if (trial == null) break; 925 if (trial.equals(base)) continue; 926 additions.add(trial); 927 } 928 } 929 source.addAll(additions); 930 } 931 932 // flatten strings 933 if ((options & CLOSE_FLATTEN) != 0) { 934 it.reset(); 935 additions.clear(); 936 while (it.next()) { 937 if (it.codepoint != UnicodeSetIterator.IS_STRING) continue; 938 additions.addAll(it.string); 939 removals.add(it.string); 940 //System.out.println("flattening '" + hex.transliterate(it.string) + "'"); 941 } 942 source.addAll(additions); 943 source.removeAll(removals); 944 } 945 946 // Now add decompositions of characters in source 947 if ((options & CLOSE_COMPATIBILITY) != 0) { 948 it.reset(source); 949 additions.clear(); 950 while (it.next()) { 951 if (it.codepoint == UnicodeSetIterator.IS_STRING) base = it.string; 952 else base = UTF16.valueOf(it.codepoint); 953 if (Normalizer.isNormalized(base, Normalizer.NFKD,0)) continue; 954 String decomp = Normalizer.normalize(base, Normalizer.NFKD); 955 additions.add(decomp); 956 } 957 source.addAll(additions); 958 959 // Now add any other character that decomposes to a character in source 960 for (cp = 0; cp < 0x10FFFF; ++cp) { 961 if (!UCharacter.isDefined(cp)) continue; 962 if (Normalizer.isNormalized(cp, Normalizer.NFKD,0)) continue; 963 if (source.contains(cp)) continue; 964 965 String decomp = Normalizer.normalize(cp, Normalizer.NFKD); 966 if (source.containsAll(decomp)) { 967 // System.out.println("Adding: " + Integer.toString(cp,16) + " " + UCharacter.getName(cp)); 968 source.add(cp); 969 } 970 } 971 } 972 973 return source; 974 } 975 976 static String toPattern(UnicodeSet source, UnicodeSet superset) { 977 if (superset != null) { 978 source.removeAll(superset); 979 return "[" + superset.toPattern(true) + " " + source.toPattern(true) + "]"; 980 } 981 return source.toPattern(true); 982 } 983 984 static BreakIterator bi = BreakIterator.getWordInstance(); 985 986 static String titlecaseFirstWord(String line) { 987 // search for first word with letters. If the first letter is lower, then titlecase it. 988 bi.setText(line); 989 int start = 0; 990 while (true) { 991 int end = bi.next(); 992 if (end == BreakIterator.DONE) break; 993 int firstLetterType = getFirstLetterType(line, start, end); 994 if (firstLetterType != Character.UNASSIGNED) { 995 if (firstLetterType != Character.LOWERCASE_LETTER) break; 996 line = line.substring(0, start) 997 + UCharacter.toTitleCase(line.substring(start, end), bi) 998 + line.substring(end); 999 break; 1000 } 1001 end = start; 1002 } 1003 return line; 1004 } 1005 1006 static final int LETTER_MASK = 1007 (1<<Character.UPPERCASE_LETTER) 1008 | (1<<Character.LOWERCASE_LETTER) 1009 | (1<<Character.TITLECASE_LETTER) 1010 | (1<<Character.MODIFIER_LETTER) 1011 | (1<<Character.OTHER_LETTER) 1012 ; 1013 1014 static int getFirstLetterType(String line, int start, int end) { 1015 int cp; 1016 for (int i = start; i < end; i += UTF16.getCharCount(cp)) { 1017 cp = UTF16.charAt(line, i); 1018 int type = UCharacter.getType(cp); 1019 if (((1<<type) & LETTER_MASK) != 0) return type; 1020 } 1021 return Character.UNASSIGNED; 1022 } 1023 1024 static void printNames(UnicodeSet s, String targetFile) { 1025 try { 1026 File outFile = new File(targetFile); 1027 System.out.println("Writing: " + outFile.getCanonicalPath()); 1028 1029 PrintWriter out = new PrintWriter( 1030 new BufferedWriter( 1031 new OutputStreamWriter( 1032 new FileOutputStream(outFile), "UTF-8"))); 1033 UnicodeSet main = new UnicodeSet(); 1034 1035 UnicodeSet others = new UnicodeSet(); 1036 UnicodeSetIterator it = new UnicodeSetIterator(s); 1037 while (it.next()) { 1038 if (!UCharacter.isDefined(it.codepoint)) continue; 1039 if (!Normalizer.isNormalized(it.codepoint, Normalizer.NFD,0)) { 1040 String decomp = Normalizer.normalize(it.codepoint, Normalizer.NFD); 1041 others.addAll(decomp); 1042 continue; 1043 } 1044 out.println(" " + UTF16.valueOf(it.codepoint) + " <> XXX # " + UCharacter.getName(it.codepoint)); 1045 main.add(it.codepoint); 1046 } 1047 1048 if (others.size() != 0) { 1049 out.println("Decomposed characters found above: "); 1050 others.removeAll(main); 1051 it.reset(others); 1052 while (it.next()) { 1053 out.println(" " + UTF16.valueOf(it.codepoint) + " <> XXX # " + UCharacter.getName(it.codepoint)); 1054 } 1055 } 1056 1057 out.close(); 1058 System.out.println("Done Writing"); 1059 } catch (Exception e) { 1060 e.printStackTrace(); 1061 } 1062 } 1063 1064 static Transliterator hex = Transliterator.getInstance("[^\\u0020-\\u007E] hex"); 1065 static final String saveRules = 1066 "A <> \uEA41; B <> \uEA42; C <> \uEA43; D <> \uEA44; E <> \uEA45; F <> \uEA46; G <> \uEA47; H <> \uEA48; I <> \uEA49; " 1067 + "J <> \uEA4A; K <> \uEA4B; L <> \uEA4C; M <> \uEA4D; N <> \uEA4E; O <> \uEA4F; P <> \uEA50; Q <> \uEA51; R <> \uEA52; " 1068 + "S <> \uEA53; T <> \uEA54; U <> \uEA55; V <> \uEA56; W <> \uEA57; X <> \uEA58; Y <> \uEA59; Z <> \uEA5A; " 1069 + "a <> \uEA61; b <> \uEA62; c <> \uEA63; d <> \uEA64; e <> \uEA65; f <> \uEA66; g <> \uEA67; h <> \uEA68; i <> \uEA69; " 1070 + "j <> \uEA6A; k <> \uEA6B; l <> \uEA6C; m <> \uEA6D; n <> \uEA6E; o <> \uEA6F; p <> \uEA70; q <> \uEA71; r <> \uEA72; " 1071 + "s <> \uEA73; t <> \uEA74; u <> \uEA75; v <> \uEA76; w <> \uEA77; x <> \uEA78; y <> \uEA79; z <> \uEA7A;"; 1072 1073 static Transliterator saveAscii = Transliterator.createFromRules("ascii-saved", saveRules, Transliterator.FORWARD); 1074 static Transliterator restoreAscii = Transliterator.createFromRules("ascii-saved", saveRules, Transliterator.REVERSE); 1075 1076 static { 1077 1078 if (false) { 1079 1080 for (char i = 'A'; i <= 'z'; ++i) { 1081 System.out.print(i + " <> " + hex.transliterate(String.valueOf((char)(0xEA00 + i))) + "; "); 1082 } 1083 1084 UnicodeSet x = new UnicodeSet("[[:^ccc=0:]&[:^ccc=230:]]"); 1085 x = x.complement(); 1086 x = x.complement(); 1087 System.out.println("Test: " + x.toPattern(true)); 1088 1089 Transliterator y = Transliterator.createFromRules("xxx", "$notAbove = [[:^ccc=0:]&[:^ccc=230:]]; u ($notAbove*) \u0308 > XXX | $1; ", Transliterator.FORWARD); 1090 1091 String[] testList = {"u\u0308", "u\u0316\u0308", "u\u0308\u0316", "u\u0301\u0308", "u\u0308\u0301"}; 1092 for (int i = 0; i < testList.length; ++i) { 1093 String yy = y.transliterate(testList[i]); 1094 System.out.println(hex.transliterate(testList[i]) + " => " + hex.transliterate(yy)); 1095 } 1096 1097 //printNames(new UnicodeSet("[\u0600-\u06FF]"), "Arabic-Latin.txt"); 1098 1099 1100 /* 1101 BreakTransliterator.register(); 1102 1103 BreakTransliterator testTrans = new BreakTransliterator("Any-XXX", null, null, "$"); 1104 String testSource = "The Quick: Brown fox--jumped."; 1105 BreakIterator bi = testTrans.getBreakIterator(); 1106 bi.setText(new StringCharacterIterator(testSource)); 1107 printBreaks(0, testSource, bi); 1108 //bi.setText(UCharacterIterator.getInstance(testSource)); 1109 //printBreaks(1, testSource, bi); 1110 1111 printIteration(2, testSource, new StringCharacterIterator(testSource)); 1112 //printIteration(3, testSource, UCharacterIterator.getInstance(testSource)); 1113 1114 1115 1116 String test = testTrans.transliterate(testSource); 1117 System.out.println("Test3: " + test); 1118 DummyFactory.add(testTrans.getID(), testTrans); 1119 */ 1120 1121 // AnyTransliterator.ScriptRunIterator.registerAnyToScript(); 1122 1123 AnyTransliterator at = new AnyTransliterator("Greek", null); 1124 at.transliterate("(cat,\u03b1,\u0915)"); 1125 DummyFactory.add(at.getID(), at); 1126 1127 at = new AnyTransliterator("Devanagari", null); 1128 at.transliterate("(cat,\u03b1,\u0915)"); 1129 DummyFactory.add(at.getID(), at); 1130 1131 at = new AnyTransliterator("Latin", null); 1132 at.transliterate("(cat,\u03b1,\u0915)"); 1133 DummyFactory.add(at.getID(), at); 1134 1135 DummyFactory.add("Any-gif", Transliterator.createFromRules("gif", "'\\'u(..)(..) > '<img src=\"http://www.unicode.org/gifs/24/' $1 '/U' $1$2 '.gif\">';", Transliterator.FORWARD)); 1136 DummyFactory.add("gif-Any", Transliterator.getInstance("Any-Null")); 1137 1138 DummyFactory.add("Any-RemoveCurly", Transliterator.createFromRules("RemoveCurly", "[\\{\\}] > ;", Transliterator.FORWARD)); 1139 DummyFactory.add("RemoveCurly-Any", Transliterator.getInstance("Any-Null")); 1140 1141 System.out.println("Trying &hex"); 1142 Transliterator t = Transliterator.createFromRules("hex2", "(.) > &hex($1);", Transliterator.FORWARD); 1143 System.out.println("Registering"); 1144 DummyFactory.add("Any-hex2", t); 1145 1146 System.out.println("Trying &gif"); 1147 t = Transliterator.createFromRules("gif2", "(.) > &any-gif($1);", Transliterator.FORWARD); 1148 System.out.println("Registering"); 1149 DummyFactory.add("Any-gif2", t); 1150 } 1151 } 1152 1153 1154 void setTransliterator(String name, String id) { 1155 if (DEBUG) System.out.println("Got: " + name); 1156 if (id == null) { 1157 translit = Transliterator.getInstance(name); 1158 } else { 1159 String reverseId = ""; 1160 int pos = id.indexOf('-'); 1161 if (pos < 0) { 1162 reverseId = id + "-Any"; 1163 id = "Any-" + id; 1164 } else { 1165 int pos2 = id.indexOf("/", pos); 1166 if (pos2 < 0) { 1167 reverseId = id.substring(pos+1) + "-" + id.substring(0,pos); 1168 } else { 1169 reverseId = id.substring(pos+1, pos2) + "-" + id.substring(0,pos) + id.substring(pos2); 1170 } 1171 } 1172 1173 1174 translit = Transliterator.createFromRules(id, name, Transliterator.FORWARD); 1175 if (DEBUG) { 1176 System.out.println("***Forward Rules"); 1177 System.out.println(translit.toRules(true)); 1178 System.out.println("***Source Set"); 1179 System.out.println(translit.getSourceSet().toPattern(true)); 1180 } 1181 System.out.println("***Target Set"); 1182 UnicodeSet target = translit.getTargetSet(); 1183 System.out.println(target.toPattern(true)); 1184 UnicodeSet rest = new UnicodeSet("[a-z]").removeAll(target); 1185 System.out.println("***ASCII - Target Set"); 1186 System.out.println(rest.toPattern(true)); 1187 1188 DummyFactory.add(id, translit); 1189 1190 Transliterator translit2 = Transliterator.createFromRules(reverseId, name, Transliterator.REVERSE); 1191 if (DEBUG) { 1192 System.out.println("***Backward Rules"); 1193 System.out.println(translit2.toRules(true)); 1194 } 1195 DummyFactory.add(reverseId, translit2); 1196 1197 Transliterator rev = translit.getInverse(); 1198 if (DEBUG) System.out.println("***Inverse Rules"); 1199 if (DEBUG) System.out.println(rev.toRules(true)); 1200 1201 } 1202 text.flush(); 1203 text.setTransliterator(translit); 1204 convertSelectionItem.setLabel(Transliterator.getDisplayName(translit.getID())); 1205 1206 addHistory(translit); 1207 1208 Transliterator inv; 1209 try { 1210 inv = translit.getInverse(); 1211 } catch (Exception ex) { 1212 inv = null; 1213 } 1214 if (inv != null) { 1215 addHistory(inv); 1216 swapSelectionItem.setEnabled(true); 1217 } else { 1218 swapSelectionItem.setEnabled(false); 1219 } 1220 System.out.println("Set transliterator: " + translit.getID() 1221 + (inv != null ? " and " + inv.getID() : "")); 1222 } 1223 1224 void addHistory(Transliterator trans) { 1225 String name = trans.getID(); 1226 MenuItem cmi = (MenuItem) historyMap.get(name); 1227 if (cmi == null) { 1228 cmi = new MenuItem(Transliterator.getDisplayName(name)); 1229 cmi.addActionListener(new TransliterationListener(name)); 1230 historyMap.put(name, cmi); 1231 historySet.add(cmi); 1232 historyMenu.removeAll(); 1233 Iterator it = historySet.iterator(); 1234 while (it.hasNext()) { 1235 historyMenu.add((MenuItem)it.next()); 1236 } 1237 } 1238 } 1239 1240 class TransliterationListener implements ActionListener, ItemListener { 1241 String name; 1242 public TransliterationListener(String name) { 1243 this.name = name; 1244 } 1245 public void actionPerformed(ActionEvent e) { 1246 setTransliterator(name, null); 1247 } 1248 public void itemStateChanged(ItemEvent e) { 1249 if (e.getStateChange() == ItemEvent.SELECTED) { 1250 setTransliterator(name, null); 1251 } else { 1252 setTransliterator("Any-Null", null); 1253 } 1254 } 1255 } 1256 1257 class FontActionListener implements ActionListener { 1258 String name; 1259 public FontActionListener(String name) { 1260 this.name = name; 1261 } 1262 public void actionPerformed(ActionEvent e) { 1263 if (DEBUG) System.out.println("Font: " + name); 1264 fontName = name; 1265 text.setFont(new Font(fontName, Font.PLAIN, fontSize)); 1266 } 1267 } 1268 1269 class SizeActionListener implements ActionListener { 1270 int size; 1271 public SizeActionListener(int size) { 1272 this.size = size; 1273 } 1274 public void actionPerformed(ActionEvent e) { 1275 if (DEBUG) System.out.println("Size: " + size); 1276 fontSize = size; 1277 text.setFont(new Font(fontName, Font.PLAIN, fontSize)); 1278 } 1279 } 1280 1281 Set add(Set s, Enumeration enumeration) { 1282 while(enumeration.hasMoreElements()) { 1283 s.add(enumeration.nextElement()); 1284 } 1285 return s; 1286 } 1287 1288 /** 1289 * Get a sorted list of the system transliterators. 1290 */ 1291 /* 1292 private static Vector getSystemTransliteratorNames() { 1293 Vector v = new Vector(); 1294 for (Enumeration e=Transliterator.getAvailableIDs(); 1295 e.hasMoreElements(); ) { 1296 v.addElement(e.nextElement()); 1297 } 1298 // Insertion sort, O(n^2) acceptable for small n 1299 for (int i=0; i<(v.size()-1); ++i) { 1300 String a = (String) v.elementAt(i); 1301 for (int j=i+1; j<v.size(); ++j) { 1302 String b = (String) v.elementAt(j); 1303 if (a.compareTo(b) > 0) { 1304 v.setElementAt(b, i); 1305 v.setElementAt(a, j); 1306 a = b; 1307 } 1308 } 1309 } 1310 return v; 1311 } 1312 */ 1313 1314 /* 1315 private void setNoTransliterator() { 1316 translitItem = noTranslitItem; 1317 noTranslitItem.setState(true); 1318 handleSetTransliterator(noTranslitItem.getLabel()); 1319 compound = false; 1320 for (int i=0; i<translitMenu.getItemCount(); ++i) { 1321 MenuItem it = translitMenu.getItem(i); 1322 if (it != noTranslitItem && it instanceof CheckboxMenuItem) { 1323 ((CheckboxMenuItem) it).setState(false); 1324 } 1325 } 1326 } 1327 */ 1328 /* 1329 private void handleAddToCompound(String name) { 1330 if (compoundCount < MAX_COMPOUND) { 1331 compoundTranslit[compoundCount] = decodeTranslitItem(name); 1332 ++compoundCount; 1333 Transliterator t[] = new Transliterator[compoundCount]; 1334 System.arraycopy(compoundTranslit, 0, t, 0, compoundCount); 1335 translit = new CompoundTransliterator(t); 1336 text.setTransliterator(translit); 1337 } 1338 } 1339 */ 1340 /* 1341 private void handleSetTransliterator(String name) { 1342 translit = decodeTranslitItem(name); 1343 text.setTransliterator(translit); 1344 } 1345 */ 1346 1347 /** 1348 * Decode a menu item that looks like <translit name>. 1349 */ 1350 /* 1351 private static Transliterator decodeTranslitItem(String name) { 1352 return (name.equals(NO_TRANSLITERATOR)) 1353 ? null : Transliterator.getInstance(name); 1354 } 1355 */ 1356 1357 private void handleBatchTransliterate(Transliterator trans) { 1358 if (trans == null) { 1359 return; 1360 } 1361 1362 int start = text.getSelectionStart(); 1363 int end = text.getSelectionEnd(); 1364 ReplaceableString s = 1365 new ReplaceableString(text.getText().substring(start, end)); 1366 1367 StringBuffer log = null; 1368 if (DEBUG) { 1369 log = new StringBuffer(); 1370 log.append('"' + s.toString() + "\" (start " + start + 1371 ", end " + end + ") -> \""); 1372 } 1373 1374 trans.transliterate(s); 1375 String str = s.toString(); 1376 1377 if (DEBUG) { 1378 log.append(str + "\""); 1379 System.out.println("Batch " + trans.getID() + ": " + log.toString()); 1380 } 1381 1382 text.replaceRange(str, start, end); 1383 text.select(start, start + str.length()); 1384 } 1385 1386 private void handleClose() { 1387 helpDialog.dispose(); 1388 dispose(); 1389 } 1390 1391 /* 1392 class InfoDialog extends Dialog { 1393 protected Button button; 1394 protected TextArea area; 1395 protected Dialog me; 1396 protected Panel bottom; 1397 1398 public TextArea getArea() { 1399 return area; 1400 } 1401 1402 public Panel getBottom() { 1403 return bottom; 1404 } 1405 1406 InfoDialog(Frame parent, String title, String label, String message) { 1407 super(parent, title, false); 1408 me = this; 1409 this.setLayout(new BorderLayout()); 1410 if (label.length() != 0) { 1411 this.add("North", new Label(label)); 1412 } 1413 1414 area = new TextArea(message, 8, 80, TextArea.SCROLLBARS_VERTICAL_ONLY); 1415 this.add("Center", area); 1416 1417 button = new Button("Hide"); 1418 button.addActionListener(new ActionListener() { 1419 public void actionPerformed(ActionEvent e) { 1420 me.hide(); 1421 } 1422 }); 1423 bottom = new Panel(); 1424 bottom.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); 1425 bottom.add(button); 1426 this.add("South", bottom); 1427 this.pack(); 1428 addWindowListener(new WindowAdapter() { 1429 public void windowClosing(WindowEvent e) { 1430 me.hide(); 1431 } 1432 }); 1433 } 1434 } 1435 */ 1436 } 1437