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