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 main(String[] args)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 Demo(int width, int height)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 initMenus()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 FileListener(Demo frame, int choice)425 FileListener(Demo frame, int choice) { 426 this.frame = frame; 427 this.choice = choice; 428 } 429 actionPerformed(ActionEvent e)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 add(String ID, Transliterator t)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 } getInstance(String ID)530 public Transliterator getInstance(String ID) { 531 return (Transliterator) m.get(ID); 532 } 533 } 534 printBreaks(int num, String testSource, BreakIterator brkItr)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 printIteration(int num, String testSource, CharacterIterator ci)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 printSources()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 genTestFile(File sourceFile, Transliterator translit, String variant)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 addSentenceToTable(PrintWriter out, String sentence, byte titleSetting, boolean addName, boolean testRoundTrip, boolean first, Transliterator tl, Transliterator lt)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 showDifference(String as, String bs)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 showSets(PrintWriter out, Transliterator translit, Transliterator inverse, UnicodeSet sourceSuper, UnicodeSet targetSuper, int options)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 closeUnicodeSet(UnicodeSet source, int options)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 toPattern(UnicodeSet source, UnicodeSet superset)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 titlecaseFirstWord(String line)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 getFirstLetterType(String line, int start, int end)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 printNames(UnicodeSet s, String targetFile)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)"); at.getID()1125 DummyFactory.add(at.getID(), at); 1126 1127 at = new AnyTransliterator("Devanagari", null); 1128 at.transliterate("(cat,\u03b1,\u0915)"); at.getID()1129 DummyFactory.add(at.getID(), at); 1130 1131 at = new AnyTransliterator("Latin", null); 1132 at.transliterate("(cat,\u03b1,\u0915)"); at.getID()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 setTransliterator(String name, String id)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 addHistory(Transliterator trans)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; TransliterationListener(String name)1242 public TransliterationListener(String name) { 1243 this.name = name; 1244 } actionPerformed(ActionEvent e)1245 public void actionPerformed(ActionEvent e) { 1246 setTransliterator(name, null); 1247 } itemStateChanged(ItemEvent e)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; FontActionListener(String name)1259 public FontActionListener(String name) { 1260 this.name = name; 1261 } actionPerformed(ActionEvent e)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; SizeActionListener(int size)1271 public SizeActionListener(int size) { 1272 this.size = size; 1273 } actionPerformed(ActionEvent e)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 add(Set s, Enumeration enumeration)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 handleBatchTransliterate(Transliterator trans)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 handleClose()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