home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / documentation / tutorial / intl / collation / demos-1.1 / CollateDemo.java < prev    next >
Encoding:
Java Source  |  1997-07-13  |  50.7 KB  |  1,515 lines

  1. /*
  2.  * Copyright (c) 1995-1997 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software
  5.  * and its documentation for NON-COMMERCIAL purposes and without
  6.  * fee is hereby granted provided that this copyright notice
  7.  * appears in all copies. Please refer to the file "copyright.html"
  8.  * for further important copyright and licensing information.
  9.  *
  10.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  11.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  12.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  13.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  14.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  15.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  16.  */
  17. /*
  18.  * @(#)CollateDemo.java    1.1 97/5/23
  19.  *
  20.  * (C) Copyright Taligent, Inc. 1996,1997 - All Rights Reserved
  21.  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  22.  *
  23.  * Portions copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
  24.  *
  25.  *   The original version of this source code and documentation is copyrighted
  26.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  27.  * materials are provided under terms of a License Agreement between Taligent
  28.  * and Sun. This technology is protected by multiple US and International
  29.  * patents. This notice and attribution to Taligent may not be removed.
  30.  *   Taligent is a registered trademark of Taligent, Inc.
  31.  *
  32.  * Permission to use, copy, modify, and distribute this software
  33.  * and its documentation for NON-COMMERCIAL purposes and without
  34.  * fee is hereby granted provided that this copyright notice
  35.  * appears in all copies. Please refer to the file "copyright.html"
  36.  * for further important copyright and licensing information.
  37.  *
  38.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  39.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  40.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  41.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  42.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  43.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  44.  *
  45.  */
  46.  
  47. import java.applet.Applet;
  48. import java.awt.*;
  49. import java.util.Vector;
  50. import java.util.Locale;
  51. import java.text.NumberFormat;
  52. import java.text.Collator;
  53. import java.text.RuleBasedCollator;
  54. import java.text.ParseException;
  55. import java.text.CollationElementIterator;
  56. import java.text.BreakIterator;
  57.  
  58. /**
  59.  * Concrete class for demonstrating language sensitive collation.
  60.  * The following is the instruction on how to run the collation demo.
  61.  * <p>
  62.  * ===================
  63.  * <H3>Customization</H3>
  64.  * You can produce a new collation by adding to or changing an existing
  65.  * one.
  66.  * <H4>To show...</H4>
  67.  * <BLOCKQUOTE>You can modify an existing collation to show how this works.
  68.  * By adding items at the end of a collation you override earlier
  69.  * information.
  70.  * Watch how you can make the letter P sort at the end of the
  71.  * alphabet.</BLOCKQUOTE>
  72.  * <H4>Do...</H4>
  73.  * <BLOCKQUOTE>1. Scroll to the end of the Sequence field. After the Z,
  74.  * type
  75.  * "< p , P". This will put the letter P (with both of its
  76.  * case
  77.  * variants) at the end of the alphabet. Hit the Set Rule button. This creates
  78.  * a new collation with the name "Custom-1" (you could give it a
  79.  * different name by typing in the Collator Name field). When you now look
  80.  * at the Text field, you will see that you have changed the sequence to put
  81.  * <I>Pat</I>
  82.  * at the end. (If you did not have Sort Ascending on, click it
  83.  * now.)</BLOCKQUOTE>
  84.  * <BR>
  85.  * Making P sort at the end may not seem terribly useful, but it is used to
  86.  * make modifications in the sorting sequence for different languages.
  87.  * <H4>To show...</H4>
  88.  * <BLOCKQUOTE>For example, you can add CH as a single letter after C, as
  89.  * in
  90.  * traditional Spanish sorting.</BLOCKQUOTE>
  91.  * <H4>Do...</H4>
  92.  * <BLOCKQUOTE>Enter in the following after Z; "& C < ch , cH, Ch,
  93.  * CH".
  94.  * Hit the Set Rule button, type in test words in the Text field (such as
  95.  * "czar",
  96.  * "churo" and "darn"), and select Sort Ascending to
  97.  * see
  98.  * the resulting sort order.</BLOCKQUOTE>
  99.  * <H4>To show...</H4>
  100.  * <BLOCKQUOTE>You can also add other sequences to the collation rules,
  101.  * such as sorting symbols with their alphabetic equivalents.</BLOCKQUOTE>
  102.  * <H4>Do...</H4>
  103.  * <BLOCKQUOTE>1. Scroll to the end of the Sequence field. After the end,
  104.  * type the following list (you can just select this text in your browser and
  105.  * paste it in, to avoid typing). Now type lines in the Text field with these
  106.  * symbols on them, and select Sort Ascending to see the resulting sort
  107.  * order.</BLOCKQUOTE>
  108.  * <UL>
  109.  *   <UL>
  110.  *     <LI>& Asterisk ; *
  111.  *     <LI>& Question-mark ; ?
  112.  *     <LI>& Hash-mark ; #
  113.  *     <LI>& Exclamation-mark ; !
  114.  *     <LI>& Dollar-sign ; $
  115.  *     <LI>& Ampersand ; '&';
  116.  *   </UL>
  117.  * </UL>
  118.  * <H4>Details</H4>
  119.  * If you are an advanced user and interested in trying out more rules,
  120.  * here is a brief explanation of how they work. The sequence is a list of
  121.  * rules. Each rule is of two forms:
  122.  * <UL>
  123.  *   <LI><modifier>
  124.  *   <LI><relation> <text-argument>
  125.  *   <LI><reset> <text-argument>
  126.  * </UL>
  127.  * <H5>Modifier</H5>
  128.  * <BLOCKQUOTE>@ Indicates that accents are sorted backwards, as in
  129.  * French</BLOCKQUOTE>
  130.  * <H5>Text-argument</H5>
  131.  * The text can be any number of characters (if you want to include special
  132.  * characters, such as space, use single-quotes around them).
  133.  * <H5>Relation</H5>
  134.  * The relations are the following:
  135.  * <DL>
  136.  *   <DD><    Greater, as a letter difference (primary)
  137.  *   <DD>;    Greater, as an accent difference (secondary)
  138.  *   <DD>,    Greater, as a case difference (tertiary)
  139.  *   <DD>=    Equal
  140.  *   <DD>&    Reset previous comparison.
  141.  * </DL>
  142.  * <H5>Reset</H5>
  143.  * The "&" is special in that does not put the text-argument
  144.  * into the sorting sequence; instead, it indicates that the <I>next</I>
  145.  * rule is with respect to where the text-argument <I>would be</I> sorted.
  146.  * This sounds more complicated than it is in practice. For example, the
  147.  * following are equivalent ways of expressing the same thing:
  148.  * <UL>
  149.  *   <LI>a < b < c
  150.  *   <LI>a < b & b < c
  151.  *   <LI>a < c & a < b
  152.  * </UL>
  153.  * Notice that the order is important, since the subsequent item goes
  154.  * <I>immediately</I>
  155.  * after the text-argument. The following are <I>not</I> equivalent:
  156.  * <UL>
  157.  *   <LI>a < b & a < c
  158.  *   <LI>a < c & a < b
  159.  * </UL>
  160.  * The text-argument must already be present in the sequence, or some
  161.  * initial substring of the text-argument must be present. (e.g. "a <
  162.  * b& ae < e" is valid since "a" is present in the
  163.  * sequence<I>before</I> "ae" is reset). In this latter case,
  164.  * "ae"
  165.  * is <B><I>not</I></B> entered and treated as a single character; instead,
  166.  * "e" is sorted as if it were expanded to two characters:
  167.  * "a"
  168.  * followed by an "e".<BR>
  169.  * This difference appears in natural languages: in traditional Spanish
  170.  * "ch"
  171.  * is treated as though it <I>contracts</I> to a single character
  172.  * (expressed
  173.  * as "c < ch < d"), while in traditional German
  174.  * "ä"
  175.  * (a-umlaut) is treated as though it <I>expands</I> to two characters
  176.  * (expressed
  177.  * as "a & ae ; ä < b").<BR>
  178.  * <H5>Ignorable Characters</H5>
  179.  * The first rule must start with a relation (the examples we have used are
  180.  * fragments; "a < b" really should be "< a <
  181.  * b").
  182.  * If, however, the first relation is not "<", then all the
  183.  * all
  184.  * text-arguments up to the first "<" are ignorable. For
  185.  * example,
  186.  * ", - < a < b" makes "-" an ignorable
  187.  * character,
  188.  * as we saw earlier in the word "black-birds".<BR>
  189.  * <H5>Accents</H5>
  190.  * The Collator automatically normalizes text internally to separate
  191.  * accents
  192.  * from base characters where possible. So, if you type in an
  193.  * "ä"
  194.  * (a-umlaut), after you reset the collation you will see
  195.  * "a\u0308"
  196.  * in the sequence, where \u0308 is the Java syntax for umlaut. The
  197.  * demonstration
  198.  * program uses this syntax instead of just showing the umlaut since many
  199.  * browsers are unable to display the umlaut yet.<BR>
  200.  * <H4>Errors</H4>
  201.  * The following are errors:
  202.  * <UL>
  203.  *   <LI>Two relations in a row (e.g. "a < , b"
  204.  *   <LI>Two text arguments in a row (e.g. "a < b c < d")
  205.  *   <LI>A reset where the text-argument is not already in the sequence
  206.  * (e.g."a < b & e < f")
  207.  * </UL>
  208.  * If you produce one of these errors, then the demonstration will beep at
  209.  * you, and select the offending text (note: on some browsers, the
  210.  * selection will not appear correctly).
  211.  * @version    1.1 11/23/96
  212.  * @author     Kathleen Wilson, Helena Shih
  213.  * @see        java.util.Collator
  214.  * @see        java.util.RuleBasedCollator
  215.  * @see        java.demos.utilities.DemoApplet
  216.  */
  217. public class CollateDemo extends DemoApplet
  218. {
  219.     /**
  220.      * The main function which defines the behavior of the CollateDemo applet
  221.      * when an applet is started.
  222.      */
  223.     public static void main(String argv[]) {
  224.         DemoApplet.showDemo(new CollateFrame(null));
  225.     }
  226.  
  227.     /**
  228.      * This creates a CollateFrame for the demo applet.
  229.      */
  230.     public Frame createDemoFrame(DemoApplet applet) {
  231.         return new CollateFrame(applet);
  232.     }
  233. }
  234.  
  235. /**
  236.  * A Frame is a top-level window with a title. The default layout for a frame
  237.  * is BorderLayout.  The CollateFrame class defines the window layout of
  238.  * CollateDemo.
  239.  */
  240. class CollateFrame extends Frame
  241. {
  242.  
  243.  
  244.     /**
  245.      * Constructs a new CollateFrame that is initially invisible.
  246.      */
  247.     public CollateFrame(DemoApplet applet)
  248.     {
  249.         super("Collator Demo");
  250.         this.applet = applet;
  251.         init();
  252.     }
  253.  
  254.     /**
  255.      * Initializes the applet. You never need to call this directly, it
  256.      * is called automatically by the system once the applet is created.
  257.      */
  258.     public void init()
  259.     {
  260.         theLocale = Locale.US;
  261.         theCollation = Collator.getInstance(theLocale);
  262.         buildGUI();
  263.     }
  264.  
  265.     /**
  266.      * Handles the event. Returns true if the event is handled and should not
  267.      * be passed to the parent of this component. The default event handler
  268.      * calls some helper methods to make life easier on the programmer.
  269.      */
  270.     public boolean handleEvent(Event evt) {
  271.  
  272.         if (evt.target == searchTextEntry &&
  273.            (evt.id == Event.KEY_PRESS || evt.id == Event.KEY_ACTION)) {
  274.            switch (evt.key) {
  275.              case 0x3ef:
  276.                 return handleFindNext();
  277.              case 0x3ee:
  278.                 return handleFindPrevious();
  279.             }
  280.         }
  281.  
  282.         if (evt.id == Event.MOUSE_UP 
  283.             && tabsAndCards.didCardChange() == true) {            
  284.              if (searchPanel.isShowing() == true) {
  285.                isCustomizing = false;
  286.                setSearchMsg("Use arrow keys to find next and previous.");
  287.              }
  288.              else if (sortPanel.isShowing() == true) {
  289.                isCustomizing = false;
  290.              }
  291.              else if (customPanel.isShowing() == true) {
  292.                isCustomizing = true;
  293.                errorText("");
  294.                return handleLocale(); //to display current locale rules
  295.              }
  296.         }
  297.  
  298.         if (evt.id == Event.ACTION_EVENT) {
  299.              errorMsg.setVisible(false);
  300.              if (evt.target == sortAscending)
  301.                     return handleSort(true, false);
  302.              else if (evt.target == sortDescending)
  303.                     return handleSort(false, true);
  304.              else if (evt.target == localeChoice) {
  305.                     handleLocale();
  306.                     return handleSort(sortAscending.getState(),
  307.                                       sortDescending.getState());
  308.              }
  309.              else if (evt.target == decompChoice) {
  310.                 return handleSort(sortAscending.getState(),
  311.                                   sortDescending.getState());
  312.              }
  313.              else if (evt.target == strengthChoice) {
  314.                     return handleSort(sortAscending.getState(),
  315.                                       sortDescending.getState());
  316.              }
  317.              else if (evt.target == collateRulesButton) {
  318.                     collateRulesButton.setLabel("setting");
  319.                     handleSetRules();
  320.                     collateRulesButton.setLabel("Set Rules");
  321.                     return handleSort(sortAscending.getState(),
  322.                                       sortDescending.getState());
  323.              }
  324.         }
  325.         else if (evt.id == Event.KEY_PRESS) {
  326.              if (evt.target == textentry) {
  327.                 checkboxes.setSelectedCheckbox(noSort);
  328.              }
  329.         }
  330.  
  331.         else if (evt.id == Event.WINDOW_DESTROY && evt.target == this) {
  332.                this.setVisible(false);
  333.                this.dispose();
  334.  
  335.                 if (applet != null) {
  336.                    applet.demoClosed();
  337.                 } else System.exit(0);
  338.  
  339.                return true;
  340.         }
  341.  
  342.         return super.handleEvent(evt);
  343.     }
  344.  
  345.     /**
  346.      * This function is called when you press the "SortDescend" button.
  347.      * It does an extremely simple sort, using the Collator.compare function.
  348.      * To improve performance, you could transform the strings into
  349.      * a sort key which is a series of characters that can be
  350.      * compared using bit-wise comparison.  In addition, you can also use
  351.      * collation keys to compare two strings based on the collation rules.
  352.      * @see java.util.Collator#compare
  353.      * @see java.util.Collator#getSortKey
  354.      * @see java.util.Collator#getCollationKey
  355.      */
  356.  
  357.     public boolean handleSort(boolean ascending, boolean descending) {
  358.         if (ascending == descending)
  359.             return true;
  360.         int exchangeResult = ascending ? -1 : 1;
  361.  
  362.         InitializeListVector();
  363.  
  364.         String targetItem;
  365.         String sourceItem;
  366.         byte compareResult;
  367.  
  368.  
  369.         String strengthName = strengthChoice.getSelectedItem();
  370.         if (strengthName.equals(tertiary)) {
  371.              theCollation.setStrength(Collator.TERTIARY);
  372.         }else if (strengthName.equals(secondary)) {
  373.              theCollation.setStrength(Collator.SECONDARY);
  374.         } else theCollation.setStrength(Collator.PRIMARY);
  375.  
  376.         int decompItem = decompChoice.getSelectedIndex();
  377.         if (decompItem == 0) {
  378.              theCollation.setDecomposition(Collator.NO_DECOMPOSITION);
  379.         }else if (decompItem == 1) {
  380.              theCollation.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
  381.         } else theCollation.setDecomposition(Collator.FULL_DECOMPOSITION);
  382.  
  383.         int numItems = textList.size();
  384.         for (int sourceIndex = 1; sourceIndex < numItems; sourceIndex++)
  385.         {
  386.            sourceItem = (String) textList.elementAt(sourceIndex);
  387.            for (int targetIndex = 0; targetIndex < sourceIndex; targetIndex++)
  388.            {
  389.                  targetItem = (String) textList.elementAt(targetIndex);
  390.               compareResult = (byte) theCollation.compare(sourceItem, targetItem);
  391.               if (compareResult == exchangeResult)
  392.               {
  393.                 textList.removeElementAt(sourceIndex);
  394.                 textList.insertElementAt(sourceItem, targetIndex);
  395.                 break;
  396.               }
  397.            }
  398.         }
  399.         resetTextArea();
  400.         return true;
  401.     }
  402.  
  403.     /**
  404.      * This function is called when you press the Locale button.
  405.      * It sets the locale that is to be used to create the collation object.
  406.      * @see java.util.Collator#getInstance
  407.      */
  408.     public boolean handleLocale()
  409.     {
  410.         int index = localeChoice.getSelectedIndex();
  411.         theCollation = collations[index];
  412.  
  413.         if (isCustomizing == true && theCollation != null) {
  414.              String theRules = ruleStrings[index];
  415.  
  416.              if (theRules == null) {
  417.                 theRules = createUnicodeString(
  418.                             ((RuleBasedCollator)theCollation).getRules());
  419.                 ruleStrings[index] = theRules;
  420.              }
  421.             
  422.              ruleEntry.setText(theRules);
  423.          }
  424.  
  425.         return true;
  426.     }
  427.  
  428.     /**
  429.      * This function is called when you press the "Set Rules" button.
  430.      * It sets the rules that are to be used by the current collation object.
  431.      * @see java.util.RuleBasedCollator#getRules
  432.      */
  433.     public void handleSetRules()
  434.     {
  435.         int index = localeChoice.getSelectedIndex();
  436.  
  437.         String rules = ruleEntry.getText();
  438.         if ((rules.equals(ruleStrings[index]) == false)
  439.              && (theCollation instanceof RuleBasedCollator) )
  440.         {
  441.             int idx = 0;
  442.             try
  443.             {
  444.                 String collName = collationName.getText();
  445.                 for (int n = 0; n < localeChoice.getItemCount(); n++)
  446.                 {
  447.                     if (collName.equals(localeChoice.getItem(n)))
  448.                     {
  449.                         theCollation = new
  450.                             RuleBasedCollator(convertStringToRules(rules));
  451.                         collations[n] = theCollation;
  452.                         idx = n;
  453.                         break;
  454.                     }
  455.                 }
  456.                 if (idx == 0)
  457.                 {
  458.                     if (localeChoice.getItemCount() < MAX_COLLATIONS)
  459.                     {
  460.                         idx = localeChoice.getItemCount();
  461.                         theCollation = new
  462.                             RuleBasedCollator(convertStringToRules(rules));
  463.  
  464.                         collations[idx] = theCollation;
  465.                         localeChoice.addItem( collName );
  466.                     }
  467.                     else
  468.                     {
  469.                         throw new ParseException("Max # exceeded!" +
  470.                             "Please replace an existing one.", 0);
  471.                     }
  472.  
  473.                     if (collName.startsWith("custom-"))
  474.                     {
  475.                         untitledIndex++;
  476.                     }
  477.                 }
  478.                 localeChoice.select(idx);
  479.                 ruleStrings[idx] = null; //force recalculation of locale rule string
  480.                 handleLocale();
  481.                 if (localeChoice.getItemCount() < MAX_COLLATIONS)
  482.                     collationName.setText("custom-" + untitledIndex);
  483.             }
  484.             catch (ParseException foo)
  485.             {
  486.                 collateRulesButton.setLabel("Set Rules");
  487.                 errorText("Error: " + foo.getMessage());
  488.             }
  489.         }
  490.     }
  491.  
  492.  
  493.     /**
  494.      * Must be called after the array of locales has been initialized.
  495.      */
  496.  
  497.     public void loadCollationTables()
  498.     {
  499.         MAX_COLLATIONS = locales.length + 10;
  500.         collations = new Collator[MAX_COLLATIONS];
  501.  
  502.         for (int i = 0; i < locales.length; i++)
  503.         {
  504.            collations[i] = Collator.getInstance(locales[i]);
  505.         }
  506.     }
  507.  
  508.     //------------------------------------------------------------
  509.     // package private
  510.     //------------------------------------------------------------
  511.  
  512.     Panel makePanel(Component demo, Component code) {
  513.         Panel temp = new Panel();
  514.  
  515.         GridBagLayout gridbag = new GridBagLayout();
  516.         GridBagConstraints constraints = new GridBagConstraints();
  517.         temp.setLayout(gridbag);
  518.  
  519.         constraints.anchor = GridBagConstraints.NORTHWEST;
  520.            constraints.gridwidth = GridBagConstraints.REMAINDER; //end row
  521.         gridbag.setConstraints(demo, constraints);
  522.  
  523.            constraints.gridheight = GridBagConstraints.REMAINDER; //end column
  524.         gridbag.setConstraints(code, constraints);
  525.  
  526.         temp.add(demo);
  527.         temp.add(code);
  528.         return temp;
  529.     }
  530.  
  531.     void addWithFont(Container container, Component foo, Font font) {
  532.         if (font != null)
  533.             foo.setFont(font);
  534.         container.add(foo);
  535.     }
  536.  
  537.  
  538.     void buildGUI()
  539.     {
  540.         setBackground(Utility.bgColor);
  541.         setLayout(new BorderLayout());
  542.  
  543.     //SORT, SEARCH, CUSTOMIZE
  544.  
  545.         tabsAndCards = new TabPanel();
  546.         tabsAndCards.add("Sort",createSortPanel());
  547.         tabsAndCards.add("Search",createSearchPanel());
  548.         tabsAndCards.add("Customize",createCustomPanel());
  549.  
  550.     // TITLE
  551.  
  552.         Label title=new Label("Collator Demo", Label.CENTER);
  553.         title.setFont(Utility.titleFont);
  554.  
  555.         Panel titlePanel = new Panel();
  556.         titlePanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
  557.         titlePanel.add(title);
  558.         add("North", titlePanel);
  559.  
  560.     // LOCALE
  561.         Locale myLocale = new Locale("","","");
  562.  
  563.         Label localeLabel = new Label("Locale:   ", Label.LEFT);
  564.         localeLabel.setFont(Utility.labelFont);
  565.  
  566.         localeChoice = new Choice();
  567.         localeChoice.setBackground(Utility.choiceColor);
  568.  
  569.         //Get all locales for debugging, but only get G7 locales for demos.
  570.         if (DEBUG == true)
  571.              locales = Collator.getAvailableLocales();
  572.         else locales = Utility.getG7Locales();
  573.  
  574.         int defaultLoc = 0;
  575.         for (int i = 0; i < locales.length; i++) {
  576.             if (locales[i].getCountry().length() > 0) {
  577.                 localeChoice.addItem
  578.                     (locales[i].getDisplayName());
  579.                 if (locales[i].equals(theLocale)) {
  580.                     defaultLoc = i;
  581.                 }
  582.             }
  583.         }
  584.         localeChoice.setFont(Utility.choiceFont);
  585.  
  586.         //must be called after the array of locales has been initialized
  587.         loadCollationTables();
  588.         localeChoice.select(defaultLoc);
  589.  
  590.         Label decompLabel = new Label("Decomposition Mode:", Label.LEFT);
  591.         decompLabel.setFont(Utility.labelFont);
  592.         decompChoice = new Choice();
  593.         decompChoice.setBackground(Utility.choiceColor);
  594.         decompChoice.addItem(no_decomposition);
  595.         decompChoice.addItem(canonical_decomposition);
  596.         decompChoice.addItem(full_decomposition);
  597.         decompChoice.select(canonical_decomposition);
  598.         decompChoice.setFont(Utility.choiceFont);
  599.  
  600.         Label strengthLabel = new Label("Strength:", Label.LEFT);
  601.         strengthLabel.setFont(Utility.labelFont);
  602.  
  603.         strengthChoice = new Choice();
  604.         strengthChoice.setBackground(Utility.choiceColor);
  605.         strengthChoice.addItem(tertiary);
  606.         strengthChoice.addItem(secondary);
  607.         strengthChoice.addItem(primary);
  608.         strengthChoice.setFont(Utility.choiceFont);
  609.  
  610.         Panel infoPanel = new Panel();
  611.         infoPanel.add(localeLabel);
  612.         infoPanel.add(localeChoice);
  613.         infoPanel.add(decompLabel);
  614.         infoPanel.add(decompChoice);
  615.         infoPanel.add(strengthLabel);
  616.         infoPanel.add(strengthChoice);
  617.         Utility.fixGrid(infoPanel,1);
  618.  
  619.         Panel centerPanel = new Panel();
  620.         centerPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 15, 0));
  621.         centerPanel.add(tabsAndCards);
  622.         centerPanel.add(infoPanel);
  623.         add("Center",centerPanel);
  624.  
  625.  
  626.         //COPYRIGHTS
  627.  
  628.         Panel bottomPanel = new Panel();
  629.         bottomPanel.setLayout(new GridLayout(2,1,0,0));
  630.  
  631.         addWithFont (bottomPanel,
  632.                      new Label(Utility.copyright1, Label.LEFT),
  633.                      Utility.creditFont);
  634.         addWithFont (bottomPanel,
  635.                      new Label(Utility.copyright2, Label.LEFT),
  636.                      Utility.creditFont);
  637.         Utility.fixGrid(bottomPanel,1);
  638.  
  639.         add("South", bottomPanel);
  640.     }
  641.  
  642.  
  643.     Panel createSortPanel()
  644.     {
  645.         sortPanel = new Panel();
  646.         sortPanel.setLayout(new BorderLayout());
  647.  
  648.     // CHECKBOXES
  649.  
  650.         checkboxes= new CheckboxGroup();
  651.  
  652.         sortAscending = new Checkbox("Sort Ascending",checkboxes, false);
  653.         sortAscending.setFont(Utility.labelFont);
  654.         sortAscending.setSize(100, 20);
  655.  
  656.         sortDescending = new Checkbox("Sort Descending",checkboxes, false);
  657.         sortDescending.setSize(100, 20);
  658.         sortDescending.setFont(Utility.labelFont);
  659.  
  660.         noSort = new Checkbox("Not Sorted",checkboxes, true);
  661.         noSort.setFont(Utility.labelFont);
  662.         noSort.setSize(100, 20);
  663.  
  664.         Panel bPanel = new Panel();
  665.         bPanel.setLayout(new GridLayout(3,1,0,0));
  666.         bPanel.add(sortAscending);
  667.         bPanel.add(sortDescending);
  668.         bPanel.add(noSort);
  669.  
  670.         Panel buttonPanel = new Panel();
  671.         buttonPanel.setLayout(new BorderLayout());
  672.         buttonPanel.add("North",bPanel);
  673.  
  674.         // TEXT
  675.  
  676.         Panel tePanel = new Panel();
  677.         tePanel.setLayout(new BorderLayout());
  678.  
  679.         textentry.setFont(editFont);
  680.         textentry.setText("black-birds\n" +
  681.                           "Pat\n" +
  682.                           "\u00c4hre\n" +
  683.                           "p\u00E9ch\u00E9\n" +
  684.                           "p\u00EAche\n" +
  685.                           "\u00c5rhus\n" +
  686.                           "p\u00E9cher\n" +
  687.                           "p\u00EAcher\n" +
  688.                           "Tod\n" +
  689.                           "T\u00F6ne\n" +
  690.                           "Tofu\n" +
  691.                           "blackbirds\n" +
  692.                           "Ton\n" +
  693.                           "PAT\n" +
  694.                           "blackbird\n" +
  695.                           "\u00d8re\n" +
  696.                           "black-bird\n" +
  697.                           "pat\n");
  698.  
  699.  
  700.         Label sortLabel = new Label("Text to Sort:", Label.LEFT);
  701.         sortLabel.setFont(Utility.labelFont);
  702.         tePanel.add("North", sortLabel);
  703.         tePanel.add("Center", textentry);
  704.  
  705.         // PUT ALL TOGETHER
  706.  
  707.         Panel middlePanel = new Panel();
  708.         middlePanel.setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
  709.         middlePanel.add(buttonPanel);
  710.         middlePanel.add(tePanel);
  711.         sortPanel.add("Center", middlePanel);
  712.  
  713.         return sortPanel;
  714.     }
  715.  
  716.  
  717.     Panel createCustomPanel()
  718.     {
  719.         customPanel = new Panel();
  720.         customPanel.setLayout(new BorderLayout());
  721.  
  722.         //RULE ENTRY AREA
  723.         Panel ruleEntryPanel = new Panel();
  724.  
  725.         Panel rulePanel = new Panel();
  726.  
  727.         ruleEntry.setFont(ruleFont);
  728.  
  729.         Panel namePanel = new Panel();
  730.         namePanel.setLayout(new FlowLayout(FlowLayout.LEFT,0,2));
  731.         collateRulesButton = new Button("Set Rules");
  732.         collationName = new TextField(10);
  733.         collationName.setText("custom-" + untitledIndex);
  734.         collationName.setFont(Utility.choiceFont);
  735.  
  736.         Label colLabel = new Label("Collator Name: ", Label.LEFT);
  737.         colLabel.setFont(Utility.labelFont);
  738.         namePanel.add(colLabel);
  739.         namePanel.add(collationName);
  740.  
  741.         Label rulesLabel = new Label("Collator Rules:", Label.LEFT);
  742.         rulesLabel.setFont(Utility.labelFont);
  743.         ruleEntryPanel.add(rulesLabel);
  744.         ruleEntryPanel.add(ruleEntry);
  745.         ruleEntryPanel.add(namePanel);
  746.         ruleEntryPanel.add(collateRulesButton);
  747.  
  748.         errorMsg.setFont(Utility.labelFont);
  749.         errorMsg.setText("This is where error messages go.............");
  750.         ruleEntryPanel.add(errorMsg);
  751.  
  752.         Utility.fixGrid(ruleEntryPanel,1);
  753.  
  754.         customPanel.add("Center", ruleEntryPanel);
  755.  
  756.         return customPanel;
  757.     }
  758.  
  759.  
  760.     Panel createSearchPanel() 
  761.     {
  762.         searchPanel = new Panel();
  763.         searchPanel.setLayout(new BorderLayout());
  764.  
  765.         //SEARCH DEMO
  766.  
  767.         Panel searchStringPanel = new Panel();
  768.         searchStringPanel.setLayout(new FlowLayout(FlowLayout.LEFT,20,0));
  769.  
  770.         Label searchLabel = new Label("Search String:", Label.RIGHT);
  771.         searchLabel.setFont(Utility.labelFont);
  772.         searchStringPanel.add(searchLabel);
  773.         searchString.setText("T\u00F6ne");
  774.         searchString.setFont(Utility.choiceFont);
  775.         searchStringPanel.add(searchString);
  776.  
  777.         searchTextEntry.setFont(editFont);
  778.         searchTextEntry.setText("black-birds Pat p\u00E9ch\u00E9 \n" +
  779.             "p\u00EAche p\u00E9cher p\u00EAcher \n" +
  780.             "Tod T\u00F6ne Tofu blackbirds \n" +
  781.             "Ton PAT blackbird \n" +
  782.             "black-bird pat ");
  783.  
  784.         Panel findTextPanel = new Panel();
  785.         findTextPanel.add(searchStringPanel);
  786.         findTextPanel.add(searchTextEntry);
  787.  
  788.         searchByWord.setState(false);
  789.     searchByWord.setFont(Utility.labelFont);
  790.         findTextPanel.add(searchByWord);
  791.  
  792.         searchMsg.setFont(Utility.labelFont);
  793.         setSearchMsg("Use arrow keys to find next and previous.");
  794.         findTextPanel.add(searchMsg);
  795.  
  796.         Utility.fixGrid(findTextPanel,1);
  797.  
  798.         searchPanel.add("Center", findTextPanel);
  799.    
  800.         return searchPanel;
  801.     }
  802.  
  803.  
  804.     //------------------------------------------------------------
  805.     // TextArea and TextField bug work-around
  806.     //------------------------------------------------------------
  807.  
  808.     /**
  809.      * This function fixes a bug in the TextArea and TextField which 
  810.      * messes up the high byte of Unicode characters when you get the
  811.      * text out.
  812.      */
  813.      private String getFixedString(TextComponent theArea)
  814.      {
  815.         String composite = theArea.getText();
  816.  
  817.         char compositeArray[] = composite.toCharArray();
  818.         for (int i = 0; i < compositeArray.length; i++)
  819.         {
  820.            compositeArray[i] = (char) (compositeArray[i] & 0xFF);
  821.         }
  822.  
  823.         return new String(compositeArray);
  824.       }
  825.  
  826.     //------------------------------------------------------------
  827.     // SEARCH DEMO
  828.     //------------------------------------------------------------
  829.  
  830.     private void setSearchMsg(String s)
  831.     {
  832.         if (!s.equals(searchMsg.getText()))
  833.         {
  834.             searchMsg.setText(s);
  835.         }
  836.     }
  837.  
  838.     /**
  839.      * This function is called when you press the "->" key.
  840.      * It searches for the next string meeting the criteria of matching
  841.      * to the search string according the the current locale and strength.
  842.      * @see java.text.CollationElementIterator
  843.      */
  844.     public boolean handleFindNext()
  845.     {
  846.         if (searchByWord.getState() == true) {
  847.             return handleFindNextWord();
  848.         }
  849.  
  850.         String searchStr = getFixedString(searchString);
  851.         String textStr = getFixedString(searchTextEntry);
  852.  
  853.         int searchOffset = searchTextEntry.getSelectionEnd();
  854.         boolean matchFound = false;
  855.  
  856.         int strength = Collator.PRIMARY;
  857.         String strengthName = strengthChoice.getSelectedItem();
  858.         if (strengthName.equals(tertiary)) {
  859.              strength = Collator.TERTIARY;
  860.              theCollation.setStrength(Collator.TERTIARY);
  861.         }else if (strengthName.equals(secondary)) {
  862.              strength = Collator.SECONDARY;
  863.              theCollation.setStrength(Collator.SECONDARY);
  864.         } else theCollation.setStrength(Collator.PRIMARY);
  865.  
  866.         //make sure you only go through the text once
  867.         for (int i = 0; i < textStr.length() + 1; i++) {
  868.  
  869.             if (searchOffset >= textStr.length()) 
  870.                searchOffset = 0;
  871.  
  872.             String sub = textStr.substring(searchOffset, textStr.length());
  873.             
  874.             if (stringsMatch(searchStr, sub, strength) == true) {
  875.               matchFound = true;
  876.               break;
  877.             }
  878.  
  879.             searchOffset++;
  880.         }
  881.  
  882.  
  883.         if (matchFound == true)
  884.         {
  885.            selectMatchingText(searchStr, textStr, searchOffset);
  886.         }else {
  887.            setSearchMsg("No Match Found");
  888.            searchTextEntry.select(0, 0);
  889.         }
  890.  
  891.         return matchFound;
  892.     }
  893.  
  894.  
  895.     /**
  896.      * This function is called when you press the "->" key and
  897.      * you have selected to find whole words only.
  898.      * It searches for the next whole word meeting the criteria of matching
  899.      * to the search string according the the current locale and strength.
  900.      * @see java.text.CollationElementIterator
  901.      */
  902.     public boolean handleFindNextWord()
  903.     {
  904.         int strength = Collator.PRIMARY;
  905.         String strengthName = strengthChoice.getSelectedItem();
  906.         if (strengthName.equals(tertiary)) {
  907.              strength = Collator.TERTIARY;
  908.              theCollation.setStrength(Collator.TERTIARY);
  909.         }else if (strengthName.equals(secondary)) {
  910.              strength = Collator.SECONDARY;
  911.              theCollation.setStrength(Collator.SECONDARY);
  912.         } else theCollation.setStrength(Collator.PRIMARY);
  913.  
  914.         //Strip the leading and trailing spaces off of
  915.         //the search string.
  916.         String searchStr = getFixedString(searchString);
  917.         int ssStart = 0;
  918.         while (Character.isWhitespace(searchStr.charAt(ssStart))) {
  919.             ssStart++;
  920.         }
  921.         int ssEnd = searchStr.length();
  922.         searchStr = searchStr.substring(ssStart,ssEnd);
  923.  
  924.         int searchOffset = searchTextEntry.getSelectionEnd();
  925.         boolean matchFound = false;
  926.  
  927.         String textStr = getFixedString(searchTextEntry);
  928.         wordIterator.setText(textStr);
  929.         int wordEnd = 0;
  930.  
  931.         //make sure you only go through the text once
  932.         for (int i = 0; i < textStr.length() + 1;) {
  933.  
  934.             if (searchOffset >= textStr.length()) 
  935.                searchOffset = 0;
  936.  
  937.             wordEnd = wordIterator.following(searchOffset);
  938.  
  939.             if (theCollation.equals(searchStr,
  940.                       textStr.substring(searchOffset,wordEnd))) {
  941.               matchFound = true;
  942.               break;
  943.             }
  944.  
  945.             i += wordEnd - searchOffset;
  946.             searchOffset = wordEnd;
  947.         }
  948.  
  949.  
  950.         if (matchFound == true)
  951.         {
  952.            searchTextEntry.select(searchOffset, wordEnd);
  953.            setSearchMsg("Found Match: \"" 
  954.                      + textStr.substring(searchOffset,wordEnd)
  955.                      + "\" at index " + String.valueOf(searchOffset));
  956.         }else {
  957.            setSearchMsg("No Match Found");
  958.            searchTextEntry.select(0, 0);
  959.         }
  960.  
  961.         return matchFound;
  962.     }
  963.  
  964.     /**
  965.      * This function is called when you press the "<-" key.
  966.      * It searches for the previous string meeting the criteria of matching
  967.      * to the search string according the the current locale and strength.
  968.      * @see java.text.CollationElementIterator
  969.      */
  970.     public boolean handleFindPrevious()
  971.     {
  972.         if (searchByWord.getState() == true) {
  973.             return handleFindPreviousWord();
  974.         }
  975.  
  976.         String searchStr = getFixedString(searchString);
  977.         String textStr = getFixedString(searchTextEntry);
  978.  
  979.         int searchOffset = searchTextEntry.getSelectionStart() - searchStr.length();
  980.         boolean matchFound = false;
  981.  
  982.         int strength = Collator.PRIMARY;
  983.         String strengthName = strengthChoice.getSelectedItem();
  984.         if (strengthName.equals(tertiary)) {
  985.              strength = Collator.TERTIARY;
  986.              theCollation.setStrength(Collator.TERTIARY);
  987.         }else if (strengthName.equals(secondary)) {
  988.              strength = Collator.SECONDARY;
  989.              theCollation.setStrength(Collator.SECONDARY);
  990.         } else theCollation.setStrength(Collator.PRIMARY);
  991.  
  992.         //make sure you only go through the text once
  993.         for (int i = 0; i < textStr.length() + 1; i++) {
  994.  
  995.             if (searchOffset < 0)
  996.                searchOffset = textStr.length() - 1; 
  997.  
  998.             String sub = textStr.substring(searchOffset, textStr.length());
  999.             
  1000.             if (stringsMatch(searchStr, sub, strength) == true) {
  1001.               matchFound = true;
  1002.               break;
  1003.             }
  1004.  
  1005.             searchOffset--;
  1006.         }
  1007.  
  1008.  
  1009.         if (matchFound == true)
  1010.         {
  1011.            selectMatchingText(searchStr, textStr, searchOffset);
  1012.         }else {
  1013.            setSearchMsg("No Match Found");
  1014.            searchTextEntry.select(0, 0);
  1015.         }
  1016.  
  1017.         return matchFound;
  1018.     }
  1019.  
  1020.  
  1021.     /**
  1022.      * This function is called when you press the "<-" key and
  1023.      * you have selected to find whole words only.
  1024.      * It searches for the previous whole word meeting the criteria of matching
  1025.      * to the search string according the the current locale and strength.
  1026.      * @see java.text.CollationElementIterator
  1027.      */
  1028.     public boolean handleFindPreviousWord()
  1029.     {
  1030.         int strength = Collator.PRIMARY;
  1031.         String strengthName = strengthChoice.getSelectedItem();
  1032.         if (strengthName.equals(tertiary)) {
  1033.              strength = Collator.TERTIARY;
  1034.              theCollation.setStrength(Collator.TERTIARY);
  1035.         }else if (strengthName.equals(secondary)) {
  1036.              strength = Collator.SECONDARY;
  1037.              theCollation.setStrength(Collator.SECONDARY);
  1038.         } else theCollation.setStrength(Collator.PRIMARY);
  1039.  
  1040.         //Strip the leading and trailing spaces off of
  1041.         //the search string.
  1042.         String searchStr = getFixedString(searchString);
  1043.         int ssStart = 0;
  1044.         while (Character.isWhitespace(searchStr.charAt(ssStart))) {
  1045.             ssStart++;
  1046.         }
  1047.         int ssEnd = searchStr.length();
  1048.         searchStr = searchStr.substring(ssStart,ssEnd);
  1049.  
  1050.         String textStr = getFixedString(searchTextEntry);
  1051.         wordIterator.setText(textStr);
  1052.  
  1053.         int searchOffset = searchTextEntry.getSelectionEnd();
  1054.         int wordEnd;
  1055.  
  1056.         if (searchOffset == textStr.length()) {
  1057.            wordIterator.last();
  1058.         } else wordIterator.following(searchOffset);
  1059.  
  1060.         if (searchTextEntry.getSelectionStart() == 
  1061.             searchTextEntry.getSelectionEnd()) {
  1062.            wordEnd = wordIterator.current();
  1063.         } else wordEnd = wordIterator.previous();
  1064.  
  1065.         searchOffset = wordIterator.previous();
  1066.  
  1067.         boolean matchFound = false;
  1068.  
  1069.         //make sure you only go through the text once
  1070.         for (int i = 0; i < textStr.length() + 1;) {
  1071.  
  1072.             if (searchOffset <= 0) {
  1073.                wordEnd = wordIterator.last();
  1074.             } else {
  1075.                wordEnd = searchOffset;
  1076.            }
  1077.  
  1078.             searchOffset = wordIterator.previous();
  1079.  
  1080.             if (theCollation.equals(searchStr,
  1081.                       textStr.substring(searchOffset,wordEnd))) {
  1082.               matchFound = true;
  1083.               break;
  1084.             }
  1085.  
  1086.             i += wordEnd - searchOffset;
  1087.         }
  1088.  
  1089.  
  1090.         if (matchFound == true)
  1091.         {
  1092.            searchTextEntry.select(searchOffset, wordEnd);
  1093.            setSearchMsg("Found Match: \"" 
  1094.                      + textStr.substring(searchOffset,wordEnd)
  1095.                      + "\" at index " + String.valueOf(searchOffset));
  1096.         }else {
  1097.            setSearchMsg("No Match Found");
  1098.            searchTextEntry.select(0, 0);
  1099.         }
  1100.  
  1101.         return matchFound;
  1102.     }
  1103.  
  1104.  
  1105.     /**
  1106.      * This function is used by handleFindNext();
  1107.      * Determine if the textToSearch begins with the text in searchStrIter.
  1108.      */
  1109.     private boolean stringsMatch(String searchStr, String textToSearch, int strength)
  1110.     {
  1111.        CollationElementIterator searchStringIter = 
  1112.              ((RuleBasedCollator)theCollation).getCollationElementIterator(searchStr);
  1113.        CollationElementIterator textToSearchIter = 
  1114.          ((RuleBasedCollator)theCollation).getCollationElementIterator(textToSearch);
  1115.  
  1116.        boolean result = true;
  1117.  
  1118.        int ssOrder = searchStringIter.next();
  1119.        int ttsOrder = textToSearchIter.next();
  1120.  
  1121.        while (ssOrder != CollationElementIterator.NULLORDER
  1122.               && ttsOrder != CollationElementIterator.NULLORDER)
  1123.        {
  1124.  
  1125.           //Ignore the ignorable characters
  1126.           while (mapOrder(ssOrder, strength) == 0) {
  1127.              ssOrder = searchStringIter.next();
  1128.           }
  1129.           if (ssOrder == CollationElementIterator.NULLORDER) {
  1130.                 return result;
  1131.           } 
  1132.           while (mapOrder(ttsOrder, strength) == 0) {
  1133.              ttsOrder = textToSearchIter.next();
  1134.           }
  1135.  
  1136.           if (collationOrdersEqual(ssOrder, ttsOrder, strength) == false) {
  1137.                result = false;
  1138.                break;
  1139.            }
  1140.  
  1141.           ssOrder = searchStringIter.next();
  1142.           ttsOrder = textToSearchIter.next();
  1143.        }
  1144.  
  1145.        return result;
  1146.     }
  1147.  
  1148.  
  1149.     /**
  1150.      * Given a complete order, return the order for the given strength.
  1151.      */
  1152.     private int mapOrder(int order, int strength)
  1153.     {
  1154.        if (strength == Collator.TERTIARY) 
  1155.            return order & 0xFFFFFFFF;
  1156.  
  1157.        if (strength == Collator.PRIMARY) 
  1158.            return order & 0xFFFF0000;
  1159.  
  1160.        return order & 0xFFFFFF00;
  1161.     }
  1162.  
  1163.     /**
  1164.      * This function is used by handleFindNext();
  1165.      * Select the text in the target string that matches the search string.  
  1166.      * Ignore leading and trailing white space.
  1167.      */
  1168.     private void selectMatchingText(String searchStr, String targetStr, 
  1169.                                     int positionInTarget) 
  1170.     {
  1171.        //skip white space at beginning and end of search string.
  1172.        int ssStart = 0;
  1173.        while (Character.isWhitespace(searchStr.charAt(ssStart))) {
  1174.            ssStart++;
  1175.        }
  1176.        int ssEnd = searchStr.length();
  1177.     
  1178.        String searchSubStr = searchStr.substring(ssStart, ssEnd);
  1179.  
  1180.        //skip white space at beginning of target string
  1181.        while (Character.isWhitespace(targetStr.charAt(positionInTarget))) {
  1182.            positionInTarget++;
  1183.        }
  1184.  
  1185.        int endIndex = positionInTarget;
  1186.        for (; endIndex < targetStr.length(); endIndex++) {
  1187.          if (theCollation.equals(searchSubStr, 
  1188.                       targetStr.substring(positionInTarget,endIndex)))
  1189.          {
  1190.            break;
  1191.          }
  1192.        }
  1193.  
  1194.        searchTextEntry.select(positionInTarget, endIndex);
  1195.        setSearchMsg("Found Match: \"" 
  1196.                      + targetStr.substring(positionInTarget,endIndex)
  1197.                      + "\" at index " + String.valueOf(positionInTarget));
  1198.     }
  1199.  
  1200.     /**
  1201.      * This function is used by handleFindNext();
  1202.      * Given a collation strength and two collation orders, resulting from 
  1203.      * calling CollationElementIterator.next(), determine if the two
  1204.      * collation orders are equivalent for the given strength.
  1205.      */
  1206.     private boolean collationOrdersEqual(int order1, int order2, int strength)
  1207.     {
  1208.        if (order1 == order2) return true;
  1209.  
  1210.        if (CollationElementIterator.primaryOrder(order1)
  1211.            != CollationElementIterator.primaryOrder(order2)) return false;
  1212.        if (strength == Collator.PRIMARY) return true;
  1213.  
  1214.        if (CollationElementIterator.secondaryOrder(order1)
  1215.            != CollationElementIterator.secondaryOrder(order2)) return false;
  1216.        if (strength == Collator.SECONDARY) return true;
  1217.  
  1218.        return false;
  1219.     }
  1220.  
  1221.  
  1222.     //------------------------------------------------------------
  1223.     // private
  1224.     //------------------------------------------------------------
  1225.     /**
  1226.      * This function is called by handleSortAscend and handleSortDescend
  1227.      * to seperate each line of the textArea into individual strings,
  1228.      * and add them to the vector to be sorted.
  1229.      */
  1230.     private void InitializeListVector()
  1231.     {
  1232.         textList.removeAllElements();
  1233.  
  1234.         String composite = getFixedString(textentry);
  1235.  
  1236.         String substr;
  1237.  
  1238.         int startOffset = 0;
  1239.         int endOffset = 0;
  1240.         for (; endOffset < composite.length(); endOffset++)
  1241.         {
  1242.             char ch = composite.charAt(endOffset);
  1243.             if (ch == '\n' || ch == '\r')
  1244.             {
  1245.                 if (endOffset > startOffset)
  1246.                 {
  1247.                     substr = composite.substring(startOffset, endOffset);
  1248.                     textList.addElement(substr);
  1249.                 }
  1250.                 startOffset = endOffset + 1;
  1251.             }
  1252.         }
  1253.  
  1254.         if (startOffset < composite.length())
  1255.         {
  1256.             substr = composite.substring(startOffset, composite.length());
  1257.             textList.addElement(substr);
  1258.         }
  1259.  
  1260.     }
  1261.  
  1262.  
  1263.     /**
  1264.      * This function is called by handleSortAscend and handleSortDescend
  1265.      * to reset the text area based on the sort results stored as a vector
  1266.      * of substrings.
  1267.      */
  1268.     private void resetTextArea()
  1269.     {
  1270.         String composite = new String();
  1271.  
  1272.         int i = 0;
  1273.         for (; i < textList.size() - 1; i++)
  1274.         {
  1275.             composite = composite.concat((String) textList.elementAt(i));
  1276.             composite = composite.concat("\n");
  1277.         }
  1278.         //don't add the \n to the end
  1279.            composite = composite.concat((String) textList.elementAt(i));
  1280.  
  1281.         textentry.setText(composite);
  1282.         textList.removeAllElements();
  1283.     }
  1284.  
  1285.  
  1286.  
  1287.     private void errorText(String s) {
  1288.         errorMsg.setText(s);
  1289.         errorMsg.setVisible(true);
  1290.     }
  1291.  
  1292.     private static StringBuffer oneChar = new StringBuffer(7);
  1293.     private String makeDisplayString(char ch) {
  1294.         oneChar.setLength(0);
  1295.         if (ch < 0x0020 ||
  1296.             (ch > 0x007D && ch < 0x00A0) ||
  1297.             ch > 0x00FF) {
  1298.             String temp = Integer.toString((int)ch,16).toUpperCase();
  1299.             oneChar.append(temp);
  1300.             if (temp.length() < 4)
  1301.                 oneChar.append(zeros.substring(0,4-temp.length()));
  1302.         } else {
  1303.             oneChar.append(ch);
  1304.         }
  1305.         return oneChar.toString();
  1306.     }
  1307.  
  1308.      /**
  1309.     Changes a string into a representation that can be pasted into a program.
  1310.     Uses \ t, \ uxxxx, etc. to display characters outside of Latin1.
  1311.     Others are themselves.
  1312.     */
  1313.     private String createUnicodeString(String source) {
  1314.         StringBuffer result = new StringBuffer(source.length());
  1315.         int len = 0;
  1316.         int i = 0;
  1317.         while (i < source.length()) {
  1318.             char ch = source.charAt(i);
  1319.             switch(ch) {
  1320.             case '\'':
  1321.                 int mytemp = i;
  1322.                 int n = 0;
  1323.                 result.append(ch);
  1324.                 ch = source.charAt(++i);
  1325.                 while((ch != '\'') && (i < source.length() -1))
  1326.                 {
  1327.                     String inquote = makeDisplayString(ch);
  1328.                     n++; i++;
  1329.                     if (inquote.length() > 1) {
  1330.                         result.append("\\u");
  1331.                         result.append(inquote);
  1332.                         len += 6;
  1333.                     } else {
  1334.                         result.append(inquote);
  1335.                         len++;
  1336.                     }
  1337.                     ch = source.charAt(i);
  1338.                 }
  1339.                 if (n == 0) {
  1340.                     result.append('\'');
  1341.                     n++; i++;
  1342.                     ch = source.charAt(i);
  1343.                 }
  1344.                 result.append(ch);
  1345.                 len += n;
  1346.                 break;
  1347.             case ';': case '=':
  1348.                 if (len > 15)
  1349.                 {
  1350.                     result.append('\n');
  1351.                     len = 0;
  1352.                 }
  1353.                 result.append(' ');
  1354.                 result.append(ch);
  1355.                 len += 2;
  1356.                 break;
  1357.             case ',':
  1358.                 result.append(' ');
  1359.                 result.append(ch);
  1360.                 result.append(' ');
  1361.                 len += 3;
  1362.                 break;
  1363.             case '<': case '&':
  1364.                 result.append('\n');
  1365.                 result.append(ch);
  1366.                 result.append(' ');
  1367.                 len = 0;
  1368.                 len += 2;
  1369.                 break;
  1370.  
  1371.             case '\n':
  1372.                 break;
  1373.             default:
  1374.                 if( isSpecialChar(ch) ) {
  1375.                     String dspString = makeDisplayString(ch);
  1376.                     if (dspString.length() > 1) {
  1377.                         result.append("'\\u");
  1378.                         result.append(dspString);
  1379.                         result.append("'");
  1380.                         len += 8;
  1381.                     } else if( ch != '\u0020' ){
  1382.                         result.append("'");
  1383.                         result.append(dspString);
  1384.                         result.append("'");
  1385.                         len += 3;
  1386.                     }
  1387.                 }
  1388.                 else {
  1389.                     String dspString = makeDisplayString(ch);
  1390.                     if (dspString.length() > 1) {
  1391.                         result.append("\\u");
  1392.                         result.append(dspString);
  1393.                         len += 6;
  1394.                     } else {
  1395.                         result.append(dspString);
  1396.                         len++;
  1397.                     }
  1398.                 }
  1399.                 break;
  1400.             }
  1401.             i++;
  1402.         }
  1403.         return result.toString();
  1404.     }
  1405.  
  1406.     private boolean isSpecialChar(char ch) {
  1407.         return (((ch <= '\u002F') && (ch >= '\u0020')) ||
  1408.                 (ch == '\u003A') ||
  1409.                 ((ch <= '\u0060') && (ch >= '\u005B')) ||
  1410.                 ((ch <= '\u007E') && (ch >= '\u007B')));
  1411.     }
  1412.  
  1413.     private static final String zeros = "0000";
  1414.  
  1415.     private String convertStringToRules(String source)
  1416.     {
  1417.     StringBuffer result = new StringBuffer(source.length());
  1418.     for (int i = 0; i < source.length(); ++i) {
  1419.         //hack around TextArea bug
  1420.         char ch = (char) (source.charAt(i) & 0xFF);
  1421.         switch(ch) {
  1422.         case '\n':
  1423.             break;
  1424.         case '\'':
  1425.           if ( (i+6 < source.length()) && (source.charAt(i+2) == 'u') )
  1426.           {
  1427.             String temp = source.substring(i+3,i+7);
  1428.             if (temp.equals("005c")) {
  1429.                 //have to handle backslash differently since 
  1430.                 //it is a special character in Java
  1431.                 result.append("'\\u005c'");
  1432.             } else
  1433.                 result.append((char)(Integer.parseInt(temp,16)));
  1434.             i = i + 7;
  1435.            }
  1436.            else result.append(ch);
  1437.  
  1438.             break;
  1439.         case '\\':
  1440.           if ( (i+5 < source.length()) && (source.charAt(i+1) == 'u') )
  1441.           {
  1442.             String temp = source.substring(i+2,i+6);
  1443.             result.append((char)(Integer.parseInt(temp,16)));
  1444.             i = i + 6;
  1445.            }
  1446.            else result.append(ch);
  1447.  
  1448.             break;
  1449.         default:
  1450.             result.append(ch);
  1451.             break;
  1452.         }
  1453.     }
  1454.     return result.toString();
  1455.     }
  1456.  
  1457.     // HSYS : fix
  1458.     private static int MAX_COLLATIONS = 12;
  1459.     private int untitledIndex = 1;
  1460.     private static final int FIELD_COLUMNS = 45;
  1461.     private static final Font editFont = new Font("TimesRoman",Font.PLAIN,18);
  1462.     private static final Font ruleFont = new Font("TimesRoman",Font.BOLD,14);
  1463.  
  1464.     private static final boolean DEBUG = false;
  1465.  
  1466.     private TextArea textentry = new TextArea(13, 15);
  1467.     private TextArea ruleEntry = new TextArea(10, 30);
  1468.     private Vector textList = new Vector(15, 10);
  1469.  
  1470.     private Choice localeChoice;
  1471.  
  1472.     private static final String no_decomposition = "None";
  1473.     private static final String canonical_decomposition = "Canonical";
  1474.     private static final String full_decomposition = "Full";
  1475.     private Choice decompChoice;
  1476.  
  1477.     private static final String tertiary = "Tertiary - a vs. A";
  1478.     private static final String secondary = "Secondary - a vs. \u00E0";
  1479.     private static final String primary = "Primary - a vs. b";
  1480.     private Choice strengthChoice;
  1481.  
  1482.     private Locale theLocale = null;
  1483.     private Collator theCollation = null;
  1484.  
  1485.     private Locale[] locales;
  1486.     private Collator[] collations;
  1487.     private String[] ruleStrings = new String[MAX_COLLATIONS];
  1488.     private Label errorMsg = new Label("", Label.LEFT);
  1489.  
  1490.     CheckboxGroup checkboxes;
  1491.     Checkbox sortAscending;
  1492.     Checkbox sortDescending;
  1493.     Checkbox noSort;
  1494.  
  1495.     Button collateRulesButton;
  1496.     TextField collationName;
  1497.  
  1498.     private DemoApplet applet;
  1499.  
  1500.     private TabPanel tabsAndCards;
  1501.     private Panel sortPanel;
  1502.     private Panel searchPanel;
  1503.     private Panel customPanel;
  1504.  
  1505.     private boolean isCustomizing = false;
  1506.  
  1507.     //SEARCH DEMO
  1508.     private TextField searchString = new TextField(12);
  1509.     private TextArea searchTextEntry = new TextArea(10,30);
  1510.     private Label searchMsg = new Label("", Label.LEFT);
  1511.     private Checkbox searchByWord = new Checkbox("Match Whole Word Only");
  1512.     private BreakIterator wordIterator = BreakIterator.getWordInstance();
  1513. }
  1514.  
  1515.