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-2010, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.dev.demo.rbnf; 10 11 import java.awt.BorderLayout; 12 import java.awt.Button; 13 import java.awt.CardLayout; 14 import java.awt.Checkbox; 15 import java.awt.Choice; 16 import java.awt.Component; 17 import java.awt.Dimension; 18 import java.awt.Font; 19 import java.awt.FontMetrics; 20 import java.awt.Frame; 21 import java.awt.Graphics; 22 import java.awt.GridLayout; 23 import java.awt.Panel; 24 import java.awt.ScrollPane; 25 import java.awt.TextArea; 26 import java.awt.TextComponent; 27 import java.awt.TextField; 28 import java.awt.event.ActionEvent; 29 import java.awt.event.ActionListener; 30 import java.awt.event.FocusAdapter; 31 import java.awt.event.FocusEvent; 32 import java.awt.event.FocusListener; 33 import java.awt.event.ItemEvent; 34 import java.awt.event.ItemListener; 35 import java.awt.event.KeyAdapter; 36 import java.awt.event.KeyEvent; 37 import java.awt.event.KeyListener; 38 import java.awt.event.TextEvent; 39 import java.awt.event.TextListener; 40 import java.awt.event.WindowAdapter; 41 import java.awt.event.WindowEvent; 42 import java.text.BreakIterator; 43 import java.text.DecimalFormat; 44 import java.text.ParsePosition; 45 import java.util.Locale; 46 47 import com.ibm.icu.dev.demo.impl.DemoApplet; 48 import com.ibm.icu.text.RuleBasedNumberFormat; 49 50 public class RbnfDemo extends DemoApplet { 51 /** 52 * For serialization 53 */ 54 private static final long serialVersionUID = -9119861296873763536L; 55 56 /** 57 * Puts a copyright in the .class file 58 */ 59 // private static final String copyrightNotice 60 // = "Copyright \u00a91997-1998 IBM Corp. All rights reserved."; 61 62 /* 63 * code to run the demo as an application 64 */ 65 public static void main(String[] argv) { 66 new RbnfDemo().showDemo(); 67 } 68 69 protected Dimension getDefaultFrameSize(DemoApplet applet, Frame f) { 70 return new Dimension(430,270); 71 } 72 73 protected Frame createDemoFrame(DemoApplet applet) { 74 final Frame window = new Frame("Number Spellout Demo"); 75 window.setSize(800, 600); 76 window.setLayout(new BorderLayout()); 77 78 Panel mainPanel = new Panel(); 79 mainPanel.setLayout(new GridLayout(1,2)); 80 81 commentaryField = new TextArea("", 0, 0, TextArea.SCROLLBARS_VERTICAL_ONLY); 82 commentaryField.setSize(800, 50); 83 commentaryField.setText(RbnfSampleRuleSets.sampleRuleSetCommentary[0]); 84 commentaryField.setEditable(false); 85 commentaryField.setFont(new Font("Helvetica", Font.PLAIN, 14)); 86 87 spelloutFormatter = new RuleBasedNumberFormat(RbnfSampleRuleSets.usEnglish, Locale.US); 88 spelloutFormatter.setLenientParseMode(lenientParse); 89 populateRuleSetMenu(); 90 numberFormatter = new DecimalFormat("#,##0.##########"); 91 parsePosition = new ParsePosition(0); 92 theNumber = 0; 93 94 numberField = new TextField(); 95 numberField.setFont(new Font("Serif", Font.PLAIN, 24)); 96 textField = new DemoTextFieldHolder(); 97 textField.setFont(new Font("Serif", Font.PLAIN, 24)); 98 rulesField = new DemoTextFieldHolder(); 99 rulesField.setFont(new Font("Serif", Font.PLAIN, 14)); 100 lenientParseButton = new Checkbox("Lenient parse", lenientParse); 101 102 numberField.addTextListener(new TextListener() { 103 public void textValueChanged(TextEvent e) { 104 if (!numberFieldHasFocus) 105 return; 106 107 String fieldText = ((TextComponent)(e.getSource())).getText(); 108 parsePosition.setIndex(0); 109 Number temp = numberFormatter.parse(fieldText, parsePosition); 110 if (temp == null || parsePosition.getIndex() == 0) { 111 theNumber = 0; 112 textField.setText("PARSE ERROR"); 113 } 114 else { 115 theNumber = temp.doubleValue(); 116 textField.setText(spelloutFormatter.format(theNumber, ruleSetName)); 117 } 118 } 119 } ); 120 121 numberField.addFocusListener(new FocusAdapter() { 122 public void focusLost(FocusEvent e) { 123 numberFieldHasFocus = false; 124 numberField.setText(numberFormatter.format(theNumber)); 125 } 126 127 public void focusGained(FocusEvent e) { 128 numberFieldHasFocus = true; 129 numberField.selectAll(); 130 } 131 } ); 132 133 textField.addKeyListener(new KeyAdapter() { 134 public void keyTyped(KeyEvent e) { 135 if (e.getKeyChar() == '\t') { 136 String fieldText = ((TextComponent)(e.getSource())).getText(); 137 parsePosition.setIndex(0); 138 theNumber = spelloutFormatter.parse(fieldText, parsePosition) 139 .doubleValue(); 140 if (parsePosition.getIndex() == 0) { 141 theNumber = 0; 142 numberField.setText("PARSE ERROR"); 143 textField.selectAll(); 144 } 145 else if (parsePosition.getIndex() < fieldText.length()) { 146 textField.select(parsePosition.getIndex(), fieldText.length()); 147 numberField.setText(numberFormatter.format(theNumber)); 148 } 149 else { 150 textField.selectAll(); 151 numberField.setText(numberFormatter.format(theNumber)); 152 } 153 e.consume(); 154 } 155 } 156 } ); 157 158 textField.addFocusListener(new FocusAdapter() { 159 public void focusLost(FocusEvent e) { 160 String fieldText = ((TextComponent)(e.getSource())).getText(); 161 parsePosition.setIndex(0); 162 theNumber = spelloutFormatter.parse(fieldText, parsePosition) 163 .doubleValue(); 164 if (parsePosition.getIndex() == 0) 165 numberField.setText("PARSE ERROR"); 166 else 167 numberField.setText(numberFormatter.format(theNumber)); 168 textField.setText(textField.getText()); // textField.repaint() didn't work right 169 } 170 171 public void focusGained(FocusEvent e) { 172 textField.selectAll(); 173 } 174 } ); 175 176 rulesField.addKeyListener(new KeyAdapter() { 177 public void keyTyped(KeyEvent e) { 178 if (e.getKeyChar() == '\t') { 179 String fieldText = ((TextComponent)(e.getSource())).getText(); 180 if (formatterMenu.getSelectedItem().equals("Custom") || !fieldText.equals( 181 RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()])) { 182 try { 183 RuleBasedNumberFormat temp = new RuleBasedNumberFormat(fieldText); 184 temp.setLenientParseMode(lenientParse); 185 populateRuleSetMenu(); 186 spelloutFormatter = temp; 187 customRuleSet = fieldText; 188 formatterMenu.select("Custom"); 189 commentaryField.setText(RbnfSampleRuleSets. 190 sampleRuleSetCommentary[RbnfSampleRuleSets. 191 sampleRuleSetCommentary.length - 1]); 192 redisplay(); 193 } 194 catch (Exception x) { 195 textField.setText(x.toString()); 196 } 197 } 198 e.consume(); 199 } 200 } 201 } ); 202 203 rulesField.addFocusListener(new FocusAdapter() { 204 public void focusLost(FocusEvent e) { 205 String fieldText = ((TextComponent)(e.getSource())).getText(); 206 if (formatterMenu.getSelectedItem().equals("Custom") || !fieldText.equals( 207 RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()])) { 208 try { 209 RuleBasedNumberFormat temp = new RuleBasedNumberFormat(fieldText); 210 temp.setLenientParseMode(lenientParse); 211 populateRuleSetMenu(); 212 spelloutFormatter = temp; 213 customRuleSet = fieldText; 214 formatterMenu.select("Custom"); 215 redisplay(); 216 } 217 catch (Exception x) { 218 textField.setText(x.toString()); 219 } 220 } 221 rulesField.setText(rulesField.getText()); // rulesField.repaint() didn't work right 222 } 223 } ); 224 225 lenientParseButton.addItemListener(new ItemListener() { 226 public void itemStateChanged(ItemEvent e) { 227 lenientParse = lenientParseButton.getState(); 228 spelloutFormatter.setLenientParseMode(lenientParse); 229 } 230 } ); 231 232 numberField.setText(numberFormatter.format(theNumber)); 233 numberField.selectAll(); 234 textField.setText(spelloutFormatter.format(theNumber, ruleSetName)); 235 236 Panel leftPanel = new Panel(); 237 leftPanel.setLayout(new BorderLayout()); 238 Panel panel = new Panel(); 239 panel.setLayout(new BorderLayout()); 240 Panel panel1 = new Panel(); 241 panel1.setLayout(new GridLayout(3, 1)); 242 panel1.add(new Panel()); 243 panel1.add(numberField, "Center"); 244 panel1.add(lenientParseButton); 245 panel.add(panel1, "Center"); 246 Panel panel2 = new Panel(); 247 panel2.setLayout(new GridLayout(3, 3)); 248 Button button = new Button("+100"); 249 button.addActionListener( new ActionListener() { 250 public void actionPerformed(ActionEvent e) { 251 roll(100); 252 } 253 } ); 254 panel2.add(button); 255 button = new Button("+10"); 256 button.addActionListener( new ActionListener() { 257 public void actionPerformed(ActionEvent e) { 258 roll(10); 259 } 260 } ); 261 panel2.add(button); 262 button = new Button("+1"); 263 button.addActionListener( new ActionListener() { 264 public void actionPerformed(ActionEvent e) { 265 roll(1); 266 } 267 } ); 268 panel2.add(button); 269 button = new Button("<"); 270 button.addActionListener( new ActionListener() { 271 public void actionPerformed(ActionEvent e) { 272 theNumber *= 10; 273 redisplay(); 274 } 275 } ); 276 panel2.add(button); 277 panel2.add(new Panel()); 278 button = new Button(">"); 279 button.addActionListener( new ActionListener() { 280 public void actionPerformed(ActionEvent e) { 281 theNumber /= 10; 282 redisplay(); 283 } 284 } ); 285 panel2.add(button); 286 button = new Button("-100"); 287 button.addActionListener( new ActionListener() { 288 public void actionPerformed(ActionEvent e) { 289 roll(-100); 290 } 291 } ); 292 panel2.add(button); 293 button = new Button("-10"); 294 button.addActionListener( new ActionListener() { 295 public void actionPerformed(ActionEvent e) { 296 roll(-10); 297 } 298 } ); 299 panel2.add(button); 300 button = new Button("-1"); 301 button.addActionListener( new ActionListener() { 302 public void actionPerformed(ActionEvent e) { 303 roll(-1); 304 } 305 } ); 306 panel2.add(button); 307 panel.add(panel2, "East"); 308 leftPanel.add(panel, "North"); 309 leftPanel.add(textField, "Center"); 310 311 Panel rightPanel = new Panel(); 312 rightPanel.setLayout(new BorderLayout()); 313 formatterMenu = new Choice(); 314 for (int i = 0; i < RbnfSampleRuleSets.sampleRuleSetNames.length; i++) 315 formatterMenu.addItem(RbnfSampleRuleSets.sampleRuleSetNames[i]); 316 formatterMenu.addItem("Custom"); 317 formatterMenu.addItemListener(new ItemListener() { 318 public void itemStateChanged(ItemEvent e) { 319 Choice source = (Choice)(e.getSource()); 320 int item = source.getSelectedIndex(); 321 Locale locale = RbnfSampleRuleSets.sampleRuleSetLocales[item]; 322 323 commentaryField.setText(RbnfSampleRuleSets. 324 sampleRuleSetCommentary[item]); 325 326 if (locale != null && (locale.getLanguage().equals("iw") 327 || locale.getLanguage().equals("ru") || locale.getLanguage().equals("ja") 328 || locale.getLanguage().equals("el") 329 || locale.getLanguage().equals("zh"))) { 330 textField.togglePanes(false); 331 rulesField.togglePanes(false); 332 } 333 else { 334 textField.togglePanes(true); 335 rulesField.togglePanes(true); 336 } 337 338 makeNewSpelloutFormatter(); 339 redisplay(); 340 } 341 } ); 342 343 ruleSetMenu = new Choice(); 344 populateRuleSetMenu(); 345 346 ruleSetMenu.addItemListener(new ItemListener() { 347 public void itemStateChanged(ItemEvent e) { 348 ruleSetName = ruleSetMenu.getSelectedItem(); 349 redisplay(); 350 } 351 } ); 352 353 Panel menuPanel = new Panel(); 354 menuPanel.setLayout(new GridLayout(1, 2)); 355 menuPanel.add(formatterMenu); 356 menuPanel.add(ruleSetMenu); 357 rightPanel.add(menuPanel, "North"); 358 359 rulesField.setText(RbnfSampleRuleSets.sampleRuleSets[formatterMenu.getSelectedIndex()]); 360 rightPanel.add(rulesField, "Center"); 361 362 mainPanel.add(leftPanel); 363 mainPanel.add(rightPanel); 364 365 window.add(mainPanel, "Center"); 366 window.add(commentaryField, "South"); 367 368 window.doLayout(); 369 window.show(); 370 final DemoApplet theApplet = applet; 371 window.addWindowListener( 372 new WindowAdapter() { 373 public void windowClosing(WindowEvent e) { 374 setVisible(false); 375 window.dispose(); 376 377 if (theApplet != null) { 378 theApplet.demoClosed(); 379 } else System.exit(0); 380 } 381 } ); 382 return window; 383 } 384 385 void roll(int delta) { 386 theNumber += delta; 387 redisplay(); 388 } 389 390 void redisplay() { 391 numberField.setText(numberFormatter.format(theNumber)); 392 textField.setText(spelloutFormatter.format(theNumber, ruleSetName)); 393 } 394 395 void makeNewSpelloutFormatter() { 396 int item = formatterMenu.getSelectedIndex(); 397 String formatterMenuItem = formatterMenu.getSelectedItem(); 398 399 if (formatterMenuItem.equals("Custom")) { 400 rulesField.setText(customRuleSet); 401 spelloutFormatter = new RuleBasedNumberFormat(customRuleSet); 402 } 403 else { 404 rulesField.setText(RbnfSampleRuleSets.sampleRuleSets[item]); 405 406 Locale locale = RbnfSampleRuleSets.sampleRuleSetLocales[item]; 407 if (locale == null) 408 locale = Locale.getDefault(); 409 410 spelloutFormatter = new RuleBasedNumberFormat(RbnfSampleRuleSets. 411 sampleRuleSets[item], locale); 412 } 413 spelloutFormatter.setLenientParseMode(lenientParse); 414 populateRuleSetMenu(); 415 } 416 417 void populateRuleSetMenu() { 418 String[] ruleSetNames = spelloutFormatter.getRuleSetNames(); 419 420 if (ruleSetMenu != null) { 421 ruleSetMenu.removeAll(); 422 for (int i = 0; i < ruleSetNames.length; i++) 423 ruleSetMenu.addItem(ruleSetNames[i]); 424 425 ruleSetName = ruleSetMenu.getSelectedItem(); 426 } 427 else 428 ruleSetName = ruleSetNames[0]; 429 } 430 431 // private Frame demoWindow = null; 432 433 private TextComponent numberField; 434 private DemoTextFieldHolder textField; 435 private DemoTextFieldHolder rulesField; 436 private TextComponent commentaryField; 437 private Checkbox lenientParseButton; 438 439 private boolean numberFieldHasFocus = true; 440 441 private RuleBasedNumberFormat spelloutFormatter; 442 private DecimalFormat numberFormatter; 443 private ParsePosition parsePosition; 444 445 private boolean lenientParse = true; 446 447 private double theNumber = 0; 448 // private boolean canEdit = true; 449 450 private Choice formatterMenu; 451 private Choice ruleSetMenu; 452 private String ruleSetName; 453 454 private String customRuleSet = "NO RULES!"; 455 } 456 457 class DemoTextField extends Component { 458 /** 459 * For serialization 460 */ 461 private static final long serialVersionUID = -7947090021239472658L; 462 public DemoTextField() { 463 } 464 465 public void setText(String text) { 466 this.text = text; 467 this.repaint(); 468 } 469 470 public String getText() { 471 return text; 472 } 473 474 public void paint(Graphics g) { 475 Font font = getFont(); 476 FontMetrics fm = g.getFontMetrics(); 477 g.setFont(font); 478 String txt = getText(); 479 BreakIterator bi = BreakIterator.getLineInstance(); 480 bi.setText(txt); 481 int lineHeight = fm.getHeight(); 482 int width = getSize().width; 483 int penY = fm.getAscent(); 484 int lineStart = 0; 485 int tempLineEnd = bi.first(); 486 int lineEnd = 0; 487 int maxLineEnd = 0; 488 totalHeight = 0; 489 490 while (lineStart < txt.length()) { 491 maxLineEnd = txt.indexOf('\n', lineStart); 492 if (maxLineEnd == -1) 493 maxLineEnd = Integer.MAX_VALUE; 494 while (tempLineEnd != BreakIterator.DONE && fm.stringWidth(txt.substring( 495 lineStart, tempLineEnd)) < width) { 496 lineEnd = tempLineEnd; 497 tempLineEnd = bi.next(); 498 } 499 if (lineStart >= lineEnd) { 500 if (tempLineEnd == BreakIterator.DONE) 501 lineEnd = txt.length(); 502 else 503 lineEnd = tempLineEnd; 504 } 505 if (lineEnd > maxLineEnd) 506 lineEnd = maxLineEnd; 507 g.drawString(txt.substring(lineStart, lineEnd), 0, penY); 508 penY += lineHeight; 509 totalHeight += lineHeight; 510 lineStart = lineEnd; 511 if (lineStart < txt.length() && txt.charAt(lineStart) == '\n') 512 ++lineStart; 513 } 514 } 515 516 /* 517 public Dimension getPreferredSize() { 518 Dimension size = getParent().getSize(); 519 return new Dimension(size.width, totalHeight); 520 } 521 */ 522 523 private String text; 524 private int totalHeight; 525 } 526 527 class DemoTextFieldHolder extends Panel { 528 /** 529 * For serialization 530 */ 531 private static final long serialVersionUID = 7514498764062569858L; 532 public DemoTextFieldHolder() { 533 tf1 = new TextArea("", 0, 0, TextArea.SCROLLBARS_VERTICAL_ONLY); 534 tf2 = new DemoTextField(); 535 sp = new ScrollPane(); 536 537 setLayout(new CardLayout()); 538 539 sp.add(tf2, "TextField1"); 540 sp.setVisible(false); 541 add(tf1, "TestField2"); 542 add(sp, "ScrollPane"); 543 } 544 545 public void addFocusListener(FocusListener l) { 546 tf1.addFocusListener(l); 547 } 548 549 public void addKeyListener(KeyListener l) { 550 tf1.addKeyListener(l); 551 } 552 553 public void setText(String text) { 554 tf1.setText(text); 555 tf2.setText(text); 556 } 557 558 public String getText() { 559 return tf1.getText(); 560 } 561 562 public void select(int start, int end) { 563 tf1.select(start, end); 564 } 565 566 public void selectAll() { 567 tf1.selectAll(); 568 } 569 570 public void togglePanes(boolean canShowRealTextField) { 571 if (canShowRealTextField != showingRealTextField) { 572 CardLayout layout = (CardLayout)(getLayout()); 573 layout.next(this); 574 showingRealTextField = canShowRealTextField; 575 } 576 } 577 578 private TextArea tf1 = null; 579 private DemoTextField tf2 = null; 580 private ScrollPane sp = null; 581 private boolean showingRealTextField = true; 582 } 583