home *** CD-ROM | disk | FTP | other *** search
/ BUG 15 / BUGCD1998_06.ISO / aplic / jbuilder / jsamples.z / LocaleChooser.java < prev    next >
Encoding:
Java Source  |  1997-07-30  |  19.8 KB  |  609 lines

  1. package borland.samples.intl.beans;
  2.  
  3. import java.awt.*;
  4. import java.awt.event.*;
  5. import java.awt.image.*;
  6. import java.beans.*;
  7. import java.text.*;
  8. import java.util.*;
  9. import borland.jbcl.model.*;
  10. import borland.jbcl.control.*;
  11. import borland.jbcl.view.*;
  12. import borland.jbcl.util.*;
  13. import COM.objectspace.jgl.*;
  14.  
  15. import borland.samples.intl.beans.event.*;
  16.  
  17. /**
  18.  * The LocaleChooser sample Java Bean allows a user to select a locale from among a list of locales.
  19.  * A user selects a locale by double-clicking on one of the leaves of the locale tree.
  20.  *<p>
  21.  * When the LocaleChooser first appears, the current locale (if present in the tree) is denoted by a blue
  22.  * ball adjacent to the locale name.
  23.  *
  24.  * LocaleChooser takes advantage of the JBCL Model-View architecture to perform animation within the tree.
  25.  * A local AnimationTimer class sends a periodic timer event to the LocaleChooser, which updates the
  26.  * currently displayed frame of the image.
  27.  *<p>
  28.  * LocaleChooser also uses a specialized version of the BasicTreeContainer to sort node labels as they are
  29.  * added to the locale tree.
  30.  *<p>
  31.  * Customizable Properties
  32.  *<ul>
  33.  *<li>localeChoices
  34.  *<li>displayStyle
  35.  *<li>selectedLocales
  36.  *<li>allowMultiSelect
  37.  *<li>acceptLeafNodesOnly
  38.  *<li>collationLocale
  39.  *<li>locale
  40.  *<li>title
  41.  *<li>animationEnabled
  42.  *</ul>
  43.  *<p>
  44.  * Events
  45.  * The LocaleChooser bean fires a LocaleChangeEvent when a user selects (double-clicks) a new locale.
  46.  *<p>
  47.  * <I>Special thanks</i> to Mr. Marghescu for allowing me to use his wonderful globe.gif
  48.  * in this sample Java Bean.  He wishes it be known that:
  49.  *<p>
  50.  * The globe.gif image was designed and is owned by Silviu Marghescu
  51.  * (silviu@emaginet.com).  Permission to use and redistribute is
  52.  * granted to Borland International.  Third parties should contact the
  53.  * author before using the image in commercial products.
  54.  *<p>
  55.  * Silviu Marghescu
  56.  *
  57.  * Thank you Mr. Marghescu! -dcy
  58.  */
  59. public class LocaleChooser extends BevelPanel implements ActionListener, BinaryComparator, Runnable {
  60.  
  61.   protected TreeControl treeControl = new TreeControl();
  62.   protected GraphLocation rootNode = null;
  63.   protected GraphLocation currentLocaleNode = null;
  64.   protected WritableGraphSelection selection = new SingleGraphSelection();
  65.   protected Vector localeChangeListeners = new Vector();
  66.   protected Collator collator = null;
  67.   protected Image currentSelectionImage = null;
  68.   protected Image rootImage = null;
  69.  
  70.   // display styles, public constants
  71.   public static final int ISO = 0;               // ISO two-letter codes
  72.   public static final int TARGET_LOCALE = 1;     // according to the target locale (default)
  73.   public static final int CURRENT_LOCALE = 2;    // according to the current locale
  74.  
  75.   public static final Locale TITLE_LOCALE = new Locale("", "", "LocaleChooser.TITLE");  
  76.   public static final Locale EVERY_LOCALE = new Locale("", "", "LocaleChooser.ALL");
  77.   public static final Locale [] ALL_LOCALES = { EVERY_LOCALE };
  78.   public static final Locale NULL_LOCALE = new Locale("", "", "LocaleChooser.NULL");
  79.   public static final Locale [] NO_LOCALES = { NULL_LOCALE };
  80.   public static final Locale DEFAULT_RUNTIME_LOCALE = new Locale("", "", "LocaleChooser.DEFAULT");
  81.   public static final String DEFAULT_TITLE = null;
  82.  
  83.   // user-definable properties
  84.   protected Locale [] localeChoices = ALL_LOCALES;
  85.   protected boolean allowMultiSelect = false;
  86.   protected boolean acceptLeafNodesOnly = true;
  87.   protected Locale [] selectedLocales = NO_LOCALES;
  88.   protected int displayStyle = TARGET_LOCALE;
  89.   protected Locale collationLocale = NULL_LOCALE;
  90.   protected String title = DEFAULT_TITLE;
  91.  
  92.   // resourceable strings
  93.   ResourceBundle resourceBundle = ResourceBundle.getBundle("borland.samples.intl.beans.resources.LocaleChooserRes");
  94.  
  95.   private Thread animationThread;
  96.   private boolean animationEnabled = false;
  97.   private int animationRate = 100;
  98.   private int imageIndex = 0;
  99.   private Image [] images;
  100.  
  101.   public LocaleChooser() {
  102.     this(ALL_LOCALES);
  103.   }
  104.  
  105.   public LocaleChooser(Locale [] localeChoices) {
  106.     currentSelectionImage = Toolkit.getDefaultToolkit().getImage(LocaleChooser.class.getResource("resources/blueball.gif"));
  107.     rootImage = Toolkit.getDefaultToolkit().getImage(LocaleChooser.class.getResource("resources/globe.gif"));
  108.  
  109.     MediaTracker mt = new MediaTracker(this);
  110.     images = new Image[36];
  111.     int [] pixels;
  112.     for (int i = 0; i < 36; i++) {
  113.       pixels = new int[2500];
  114.       PixelGrabber pg = new PixelGrabber(rootImage, 0, i * 50, 50, 50, pixels, 0, 50);
  115.       try {
  116.     pg.grabPixels();
  117.       } catch (InterruptedException e) {
  118.     e.printStackTrace();
  119.       }
  120.       MemoryImageSource mis = new MemoryImageSource(50, 50, pixels, 0, 50);
  121.       images[i] = createImage(mis);
  122.       mt.addImage(images[i], i);
  123.     }
  124.     mt.checkAll(true);
  125.  
  126.     setAnimationEnabled(true);
  127.  
  128. //  Call setLocaleChoices to build the locale tree
  129.     setLocaleChoices(localeChoices);
  130.     super.setLayout(new BorderLayout());
  131.     super.add(treeControl, BorderLayout.CENTER);
  132.     treeControl.setExpandByDefault(true);
  133.     treeControl.addActionListener(this);
  134.     treeControl.setSelection(selection);
  135.     treeControl.setViewManager(new BasicViewManager(new CompositeItemPainter(new SelectableTextItemPainter(),
  136.                                          new ImageItemPainter(treeControl, Alignment.CENTER))));
  137.   }
  138.  
  139.   // By convention, a null argument is interpreted to mean all available locales at runtime
  140.   public void setLocaleChoices(Locale [] localeChoices) {
  141.     try {
  142.       if ((localeChoices == null) ||
  143.       (localeChoices == NO_LOCALES)) {
  144.     this.localeChoices = NO_LOCALES;
  145.       } else if (localeChoices == ALL_LOCALES) {
  146.     this.localeChoices = ALL_LOCALES;
  147.       } else {
  148.     this.localeChoices = (Locale []) localeChoices.clone();
  149.     for (int i = 0; i < localeChoices.length; i++) {
  150.     }
  151.       }
  152.     } catch (Exception e) {
  153.       e.printStackTrace();    // should never occur!
  154.     }
  155.     buildTree();
  156.   }
  157.  
  158.   public Locale [] getLocaleChoices() {
  159.     Locale [] localeListCopy = null;
  160.     try {
  161.       if ((localeChoices == ALL_LOCALES) || (localeChoices == NO_LOCALES)) {
  162.     return localeChoices;
  163.       }
  164.       localeListCopy = (Locale []) localeChoices.clone();
  165.     } catch (Exception e) {
  166.       e.printStackTrace();    // should never occur!
  167.     }
  168.     return localeListCopy;
  169.   }
  170.  
  171.   // By convention, a null argument is interpreted to mean that no locales are selected
  172.   public void setSelectedLocales(Locale [] selectedLocales) {
  173.     LinkedTreeNode treeNode;
  174.     Locale locale;
  175.  
  176.     if (allowMultiSelect) {
  177.       selection = new BasicGraphSelection();
  178.     } else {
  179.       selection = new SingleGraphSelection();
  180.     }
  181.  
  182.     if (selectedLocales == NO_LOCALES) {
  183.       this.selectedLocales = NO_LOCALES;
  184.       treeControl.setSelection(selection);
  185.       return;
  186.     }
  187.  
  188.     if (selectedLocales == ALL_LOCALES) {
  189.       this.selectedLocales = ALL_LOCALES;
  190.     }
  191.  
  192.     InputIterator iterator = ((LinkedTreeContainer) treeControl.getModel()).elements();
  193.     while (!iterator.atEnd()) {
  194.       treeNode = (LinkedTreeNode) iterator.get();
  195.       locale = ((LocaleDataPair) ((Pair) treeControl.get(treeNode)).first).getLocale();
  196.       if (selectedLocales == ALL_LOCALES) {
  197.     selection.add(treeNode);
  198.       } else {
  199.     for (int i = 0; i < selectedLocales.length; i++) {
  200.       if (locale.equals(selectedLocales[i])) {
  201.         selection.add(treeNode);
  202.         break;
  203.       }
  204.     }
  205.       }
  206.       iterator.advance();
  207.     }
  208.     treeControl.setSelection(selection);
  209.   }
  210.  
  211.   public Locale [] getSelectedLocales() {
  212.     GraphLocation [] selectedNodes = selection.getAll();
  213.     Locale [] selectedLocales = new Locale[selectedNodes.length];
  214.  
  215.     for (int i = 0; i < selectedLocales.length; i++) {
  216.       selectedLocales[i] = ((LocaleDataPair) ((Pair) treeControl.get(selectedNodes[i])).first).getLocale();
  217.     }
  218.  
  219.     if ((selectedLocales.length == 0) || 
  220.     ((selectedLocales.length == 1) && selectedLocales[0].equals(NO_LOCALES))) {
  221.       return NO_LOCALES;
  222.     } else if ((selectedLocales.length == 1) && selectedLocales[0].equals(ALL_LOCALES)) {
  223.       return ALL_LOCALES;
  224.     }
  225.     return selectedLocales;
  226.   }
  227.  
  228.   // ISO, TARGET_LOCALE, CURRENT_LOCALE
  229.   public void setDisplayStyle(int displayStyle) {
  230.     this.displayStyle = displayStyle;
  231.     buildTree();
  232.   }
  233.  
  234.   public int getDisplayStyle() {
  235.     return displayStyle;
  236.   }
  237.  
  238.   public void setAcceptLeafNodesOnly(boolean acceptLeafNodesOnly) {
  239.     this.acceptLeafNodesOnly = acceptLeafNodesOnly;
  240.   }
  241.  
  242.   public boolean isAcceptLeafNodesOnly() {
  243.     return acceptLeafNodesOnly;
  244.   }
  245.  
  246.   public void setAllowMultiSelect(boolean allowMultiSelect) {
  247.  
  248.     if (this.allowMultiSelect == allowMultiSelect) {
  249.       return;
  250.     }
  251.  
  252.     if (allowMultiSelect) {
  253.       selection = new BasicGraphSelection();
  254.     } else {
  255.       selection = new SingleGraphSelection();
  256.     }
  257.  
  258.     treeControl.setSelection(selection);
  259.     this.allowMultiSelect = allowMultiSelect;
  260.   }
  261.  
  262.   public boolean isAllowMultiSelect() {
  263.     return allowMultiSelect;
  264.   }
  265.  
  266.   public void setLocale(Locale locale) {
  267.     super.setLocale(locale);
  268.  
  269.     Locale.setDefault(locale);
  270.  
  271.     // update the resourced locale title
  272.     if (title == DEFAULT_TITLE) {
  273.       resourceBundle = ResourceBundle.getBundle("borland.samples.intl.beans.resources.LocaleChooserRes");
  274.       setTitle(DEFAULT_TITLE);
  275.     }
  276.  
  277.     // update the current locale denoted in the tree
  278.     InputIterator i = ((LinkedTreeContainer) treeControl.getModel()).elements();
  279.     LinkedTreeNode treeNode;
  280.  
  281.     while (!i.atEnd()) {
  282.       treeNode = (LinkedTreeNode) i.get();
  283.       if (((LocaleDataPair) ((Pair) treeControl.get(treeNode)).first).getLocale().equals(locale)) {
  284.     setCurrentLocaleNode(treeNode);
  285.     break;
  286.       }
  287.       i.advance();
  288.     }
  289.     notifyLocaleChangeListeners(locale);
  290.   }
  291.  
  292.   public Locale getLocale() {
  293.     try {
  294.       return super.getLocale();
  295.     } catch (IllegalComponentStateException e) {
  296.       return Locale.getDefault();
  297.     }
  298.   }
  299.  
  300.   public void actionPerformed(ActionEvent e) {
  301.  
  302.     LinkedTreeNode target = (LinkedTreeNode) treeControl.getSubfocus();
  303.  
  304.     if (acceptLeafNodesOnly && (target.hasChildren() == TriState.YES)) {
  305.       return;
  306.     }
  307.  
  308.     Locale newLocale = ((LocaleDataPair) ((Pair) treeControl.get(target)).first).getLocale();
  309.     setCurrentLocaleNode(target);
  310.     setLocale(newLocale);
  311.  
  312.   }
  313.  
  314.   protected void buildTree() {
  315.     Locale [] selectedLocales = getSelectedLocales();
  316.  
  317.     LocaleDataPair localeDataPair = new LocaleDataPair(title == DEFAULT_TITLE ? resourceBundle.getString("Select_a_locale") :
  318.                                         title,
  319.                                TITLE_LOCALE);
  320.  
  321.     BasicOrderedTreeContainer basicOrderedTreeContainer = 
  322.       new BasicOrderedTreeContainer(new Pair(localeDataPair, images[imageIndex]));
  323.     imageIndex = (imageIndex + 1) % images.length;
  324.  
  325.     treeControl.setModel(basicOrderedTreeContainer);
  326.  
  327.     rootNode = treeControl.getRoot();
  328.  
  329.     GraphLocation languageTreeNode = null;
  330.     GraphLocation countryTreeNode = null;
  331.     GraphLocation variantTreeNode = null;
  332.  
  333.     currentLocaleNode = null;
  334.  
  335.     Locale [] treeChoices;
  336.  
  337.     if (localeChoices == NO_LOCALES) {
  338.       treeChoices = new Locale [] { };
  339.     } else if (localeChoices == ALL_LOCALES) {
  340.       treeChoices = getAllRuntimeLocales();
  341.     } else {
  342.       treeChoices = localeChoices;
  343.     }
  344.  
  345.     for (int i = 0; i < treeChoices.length; i++) {
  346.       if (treeChoices[i].getLanguage().length() != 0) {
  347.     localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayLanguage(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), ""));
  348.     if (displayStyle == ISO) {
  349.       localeDataPair.setText(treeChoices[i].getLanguage());
  350.     } else if (displayStyle == CURRENT_LOCALE) {
  351.       localeDataPair.setText(treeChoices[i].getDisplayLanguage(getLocale()));
  352.     }
  353.         languageTreeNode =
  354.       basicOrderedTreeContainer.addOrderedChild(rootNode,
  355.                                             new Pair(localeDataPair, null),
  356.                                         this);
  357.         if (getLocale().getLanguage().equals(treeChoices[i].getLanguage())) {
  358.       setCurrentLocaleNode(languageTreeNode);
  359.         }
  360.       } else {
  361.         continue;
  362.       }
  363.       if (treeChoices[i].getCountry().length() != 0) {
  364.     localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayCountry(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), treeChoices[i].getCountry()));
  365.     if (displayStyle == ISO) {
  366.       localeDataPair.setText(treeChoices[i].getCountry());
  367.     } else if (displayStyle == CURRENT_LOCALE) {
  368.       localeDataPair.setText(treeChoices[i].getDisplayCountry(getLocale()));
  369.     }
  370.     countryTreeNode =
  371.       basicOrderedTreeContainer.addOrderedChild(languageTreeNode,
  372.                                         new Pair(localeDataPair, null),
  373.                                         this);
  374.     if (getLocale().getLanguage().equals(treeChoices[i].getLanguage()) &&
  375.             getLocale().getCountry().equals(treeChoices[i].getCountry())) {
  376.       setCurrentLocaleNode(countryTreeNode);
  377.     }
  378.       } else {
  379.         continue;
  380.       }
  381.       if (treeChoices[i].getVariant().length() != 0) {
  382.     localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayVariant(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), treeChoices[i].getCountry(), treeChoices[i].getVariant()));
  383.     if (displayStyle == ISO) {
  384.       localeDataPair.setText(treeChoices[i].getVariant());
  385.     } else if (displayStyle == CURRENT_LOCALE) {
  386.       localeDataPair.setText(treeChoices[i].getDisplayVariant(getLocale()));
  387.     }
  388.     variantTreeNode =
  389.           basicOrderedTreeContainer.addOrderedChild(countryTreeNode,
  390.                                         new Pair(localeDataPair, null),
  391.                                         this);
  392.     if (getLocale().equals(treeChoices[i])) {
  393.       setCurrentLocaleNode(variantTreeNode);
  394.     }
  395.       }
  396.     }
  397.  
  398.     setSelectedLocales(selectedLocales);
  399.   }
  400.  
  401.   public void setTitle(String title) {
  402.     this.title = title;
  403.     LocaleDataPair oldLocaleDataPair = (LocaleDataPair) ((Pair) treeControl.get(rootNode)).first;
  404.     LocaleDataPair newLocaleDataPair = new LocaleDataPair(title == DEFAULT_TITLE ? resourceBundle.getString("Select_a_locale") :
  405.                                                        title,
  406.                               oldLocaleDataPair.getLocale());
  407.     treeControl.set(rootNode, new Pair(newLocaleDataPair, images[imageIndex]));
  408.     imageIndex = (imageIndex + 1) % images.length;
  409.   }
  410.  
  411.   public String getTitle() {
  412.     return title;
  413.   }
  414.  
  415.   // a null value for the collationLocale means no specified Locale, i.e., Unicode collation order
  416.   public void setCollationLocale(Locale collationLocale) {
  417.     this.collationLocale = collationLocale;
  418.     if (collationLocale.equals(NULL_LOCALE)) {
  419.       collator = null;
  420.     } else if (collationLocale.equals(DEFAULT_RUNTIME_LOCALE)) {
  421.       collator = Collator.getInstance();
  422.     } else {
  423.       collator = Collator.getInstance(collationLocale);
  424.     }
  425.   }
  426.  
  427.   public Locale getCollationLocale() {
  428.     return collationLocale;
  429.   }
  430.  
  431.   public Dimension getMinimumSize() {
  432.     return treeControl.getMinimumSize();
  433.   }
  434.  
  435.   public Dimension getPreferredSize() {
  436.     Dimension dimension = treeControl.getPreferredSize();
  437.     return new Dimension(dimension.width + 5, dimension.height + 5);
  438.   }
  439.  
  440.   private void setCurrentLocaleNode(GraphLocation node) {
  441.     // don't do anything if the same node is selected again
  442.     if (currentLocaleNode == node) {
  443.       return;
  444.     }
  445.     // unmark the old node
  446.     if (currentLocaleNode != null) {
  447.       Pair oldPair = (Pair) treeControl.get(currentLocaleNode);
  448.       treeControl.set(currentLocaleNode, new Pair(oldPair.first, null));
  449.     }
  450.     // mark the new node
  451.     if (node != null) {
  452.       currentLocaleNode = node;
  453.       Pair oldPair = (Pair) treeControl.get(currentLocaleNode);
  454.       treeControl.set(currentLocaleNode, new Pair(oldPair.first, currentSelectionImage));
  455.     }    
  456.   }
  457.  
  458.   private Locale [] getAllRuntimeLocales() {
  459.     return java.text.NumberFormat.getAvailableLocales();
  460.   }
  461.  
  462.   // event-handling 
  463.   public synchronized void addLocaleChangeListener(LocaleChangeListener listener) {
  464.     localeChangeListeners.addElement(listener);
  465.   }
  466.  
  467.   public synchronized void removeLocaleChangeListener(LocaleChangeListener listener) {
  468.     localeChangeListeners.removeElement(listener);
  469.   }
  470.                             
  471.   protected void notifyLocaleChangeListeners(Locale locale) {
  472.     LocaleChangeEvent localeChangeEvent = new LocaleChangeEvent(this, locale);
  473.     Vector listeners;
  474.  
  475.     Component component = this;
  476.     Frame frame = null;
  477.  
  478.     while ((component = component.getParent()) != null) {
  479.       if (component instanceof Frame) {
  480.     frame = (Frame) component;
  481.     break;
  482.       }
  483.     }
  484.  
  485.     if (frame == null) {
  486.       frame = new Frame();
  487.     }
  488.     this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  489.     frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
  490.  
  491.     synchronized (this) {
  492.       listeners = (Vector) localeChangeListeners.clone();
  493.     }
  494.     for (int i = 0; i < listeners.size(); i++) {
  495.       ((LocaleChangeListener) listeners.elementAt(i)).localeChanged(localeChangeEvent);
  496.     }
  497.     frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  498.     this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  499.   }
  500.  
  501.  
  502.   public void addSelectionListener(GraphSelectionListener listener) {
  503.     treeControl.addSelectionListener(listener);
  504.   }
  505.  
  506.   public void removeSelectionListener(GraphSelectionListener listener) {
  507.     treeControl.removeSelectionListener(listener);
  508.   }
  509.  
  510.   // implementation of BinaryComparator interface
  511.   public int compare(Object item1, Object item2) {
  512.     if (collator == null) {
  513.       return ((Pair) item1).first.toString().compareTo(((Pair) item2).first.toString());
  514.     } else {
  515.       return collator.compare(((Pair) item1).first.toString(),
  516.                   ((Pair) item2).first.toString());
  517.     }
  518.   }
  519.  
  520.   public synchronized void setAnimationEnabled(boolean animationEnabled) {
  521.     this.animationEnabled = animationEnabled;
  522.     if (animationEnabled && animationThread == null) {
  523.       animationThread = new Thread(this);
  524.       animationThread.start();
  525.     }
  526.     if (animationEnabled) {
  527.       notify();
  528.     } else {
  529.       imageIndex = 0;
  530.       Pair oldPair = (Pair) treeControl.get(rootNode);
  531.       oldPair.second = images[imageIndex];
  532.       treeControl.touched(rootNode);
  533.     }
  534.   }
  535.  
  536.   public boolean getAnimationEnabled() {
  537.     return animationEnabled;
  538.   }
  539.  
  540.   // implementation of Runnable interface
  541.   public void run() {
  542.     try {
  543.       while (true) {
  544.     synchronized (this) {
  545.       while (!animationEnabled) {
  546.         wait();
  547.       }
  548.     }
  549.     if (rootNode != null) {
  550.       Pair oldPair = (Pair) treeControl.get(rootNode);
  551.       oldPair.second = images[imageIndex];
  552.       treeControl.touched(rootNode);
  553.       imageIndex = (imageIndex + 1) % images.length;
  554.     }
  555.     Thread.sleep(animationRate);
  556.       }
  557.     } catch (InterruptedException e) {
  558.     }
  559.   }
  560.  
  561.   public Component add(Component comp) {
  562.     return null;
  563.   }
  564.   public Component add(String name, Component comp) {
  565.     return null;
  566.   }
  567.   public Component add(Component comp, int index) {
  568.     return null;
  569.   }
  570.   public void add(Component comp, Object constraints) {}
  571.   public void add(Component comp, Object constraints, int index) {}
  572.   public void remove(int index) {}
  573.   public void remove(Component comp) {}
  574.   public void removeAll() {}
  575.   public void setLayout(LayoutManager mgr) {}
  576.   public LayoutManager getLayout() {
  577.     return super.getLayout();
  578.   }
  579.  
  580. }
  581.  
  582. // need to override the Pair.toString() method to return the correct string for TextItemPainter()
  583. class LocaleDataPair extends Pair {
  584.   String textItem;
  585.   Locale locale;
  586.  
  587.   public LocaleDataPair(String textItem, Locale locale) {
  588.     this.textItem = textItem;
  589.     this.locale = locale;
  590.   }
  591.  
  592.   public String toString() {
  593.     return textItem;
  594.   }
  595.  
  596.   public Locale getLocale() {
  597.     return locale;
  598.   }
  599.  
  600.   public void setLocale(Locale locale) {
  601.     this.locale = locale;
  602.   }
  603.  
  604.   public void setText(String textItem) {
  605.     this.textItem = textItem;
  606.   }
  607.  
  608. }
  609.