home *** CD-ROM | disk | FTP | other *** search
Wrap
Java Source | 1997-07-30 | 19.8 KB | 609 lines
package borland.samples.intl.beans; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.beans.*; import java.text.*; import java.util.*; import borland.jbcl.model.*; import borland.jbcl.control.*; import borland.jbcl.view.*; import borland.jbcl.util.*; import COM.objectspace.jgl.*; import borland.samples.intl.beans.event.*; /** * The LocaleChooser sample Java Bean allows a user to select a locale from among a list of locales. * A user selects a locale by double-clicking on one of the leaves of the locale tree. *<p> * When the LocaleChooser first appears, the current locale (if present in the tree) is denoted by a blue * ball adjacent to the locale name. * * LocaleChooser takes advantage of the JBCL Model-View architecture to perform animation within the tree. * A local AnimationTimer class sends a periodic timer event to the LocaleChooser, which updates the * currently displayed frame of the image. *<p> * LocaleChooser also uses a specialized version of the BasicTreeContainer to sort node labels as they are * added to the locale tree. *<p> * Customizable Properties *<ul> *<li>localeChoices *<li>displayStyle *<li>selectedLocales *<li>allowMultiSelect *<li>acceptLeafNodesOnly *<li>collationLocale *<li>locale *<li>title *<li>animationEnabled *</ul> *<p> * Events * The LocaleChooser bean fires a LocaleChangeEvent when a user selects (double-clicks) a new locale. *<p> * <I>Special thanks</i> to Mr. Marghescu for allowing me to use his wonderful globe.gif * in this sample Java Bean. He wishes it be known that: *<p> * The globe.gif image was designed and is owned by Silviu Marghescu * (silviu@emaginet.com). Permission to use and redistribute is * granted to Borland International. Third parties should contact the * author before using the image in commercial products. *<p> * Silviu Marghescu * * Thank you Mr. Marghescu! -dcy */ public class LocaleChooser extends BevelPanel implements ActionListener, BinaryComparator, Runnable { protected TreeControl treeControl = new TreeControl(); protected GraphLocation rootNode = null; protected GraphLocation currentLocaleNode = null; protected WritableGraphSelection selection = new SingleGraphSelection(); protected Vector localeChangeListeners = new Vector(); protected Collator collator = null; protected Image currentSelectionImage = null; protected Image rootImage = null; // display styles, public constants public static final int ISO = 0; // ISO two-letter codes public static final int TARGET_LOCALE = 1; // according to the target locale (default) public static final int CURRENT_LOCALE = 2; // according to the current locale public static final Locale TITLE_LOCALE = new Locale("", "", "LocaleChooser.TITLE"); public static final Locale EVERY_LOCALE = new Locale("", "", "LocaleChooser.ALL"); public static final Locale [] ALL_LOCALES = { EVERY_LOCALE }; public static final Locale NULL_LOCALE = new Locale("", "", "LocaleChooser.NULL"); public static final Locale [] NO_LOCALES = { NULL_LOCALE }; public static final Locale DEFAULT_RUNTIME_LOCALE = new Locale("", "", "LocaleChooser.DEFAULT"); public static final String DEFAULT_TITLE = null; // user-definable properties protected Locale [] localeChoices = ALL_LOCALES; protected boolean allowMultiSelect = false; protected boolean acceptLeafNodesOnly = true; protected Locale [] selectedLocales = NO_LOCALES; protected int displayStyle = TARGET_LOCALE; protected Locale collationLocale = NULL_LOCALE; protected String title = DEFAULT_TITLE; // resourceable strings ResourceBundle resourceBundle = ResourceBundle.getBundle("borland.samples.intl.beans.resources.LocaleChooserRes"); private Thread animationThread; private boolean animationEnabled = false; private int animationRate = 100; private int imageIndex = 0; private Image [] images; public LocaleChooser() { this(ALL_LOCALES); } public LocaleChooser(Locale [] localeChoices) { currentSelectionImage = Toolkit.getDefaultToolkit().getImage(LocaleChooser.class.getResource("resources/blueball.gif")); rootImage = Toolkit.getDefaultToolkit().getImage(LocaleChooser.class.getResource("resources/globe.gif")); MediaTracker mt = new MediaTracker(this); images = new Image[36]; int [] pixels; for (int i = 0; i < 36; i++) { pixels = new int[2500]; PixelGrabber pg = new PixelGrabber(rootImage, 0, i * 50, 50, 50, pixels, 0, 50); try { pg.grabPixels(); } catch (InterruptedException e) { e.printStackTrace(); } MemoryImageSource mis = new MemoryImageSource(50, 50, pixels, 0, 50); images[i] = createImage(mis); mt.addImage(images[i], i); } mt.checkAll(true); setAnimationEnabled(true); // Call setLocaleChoices to build the locale tree setLocaleChoices(localeChoices); super.setLayout(new BorderLayout()); super.add(treeControl, BorderLayout.CENTER); treeControl.setExpandByDefault(true); treeControl.addActionListener(this); treeControl.setSelection(selection); treeControl.setViewManager(new BasicViewManager(new CompositeItemPainter(new SelectableTextItemPainter(), new ImageItemPainter(treeControl, Alignment.CENTER)))); } // By convention, a null argument is interpreted to mean all available locales at runtime public void setLocaleChoices(Locale [] localeChoices) { try { if ((localeChoices == null) || (localeChoices == NO_LOCALES)) { this.localeChoices = NO_LOCALES; } else if (localeChoices == ALL_LOCALES) { this.localeChoices = ALL_LOCALES; } else { this.localeChoices = (Locale []) localeChoices.clone(); for (int i = 0; i < localeChoices.length; i++) { } } } catch (Exception e) { e.printStackTrace(); // should never occur! } buildTree(); } public Locale [] getLocaleChoices() { Locale [] localeListCopy = null; try { if ((localeChoices == ALL_LOCALES) || (localeChoices == NO_LOCALES)) { return localeChoices; } localeListCopy = (Locale []) localeChoices.clone(); } catch (Exception e) { e.printStackTrace(); // should never occur! } return localeListCopy; } // By convention, a null argument is interpreted to mean that no locales are selected public void setSelectedLocales(Locale [] selectedLocales) { LinkedTreeNode treeNode; Locale locale; if (allowMultiSelect) { selection = new BasicGraphSelection(); } else { selection = new SingleGraphSelection(); } if (selectedLocales == NO_LOCALES) { this.selectedLocales = NO_LOCALES; treeControl.setSelection(selection); return; } if (selectedLocales == ALL_LOCALES) { this.selectedLocales = ALL_LOCALES; } InputIterator iterator = ((LinkedTreeContainer) treeControl.getModel()).elements(); while (!iterator.atEnd()) { treeNode = (LinkedTreeNode) iterator.get(); locale = ((LocaleDataPair) ((Pair) treeControl.get(treeNode)).first).getLocale(); if (selectedLocales == ALL_LOCALES) { selection.add(treeNode); } else { for (int i = 0; i < selectedLocales.length; i++) { if (locale.equals(selectedLocales[i])) { selection.add(treeNode); break; } } } iterator.advance(); } treeControl.setSelection(selection); } public Locale [] getSelectedLocales() { GraphLocation [] selectedNodes = selection.getAll(); Locale [] selectedLocales = new Locale[selectedNodes.length]; for (int i = 0; i < selectedLocales.length; i++) { selectedLocales[i] = ((LocaleDataPair) ((Pair) treeControl.get(selectedNodes[i])).first).getLocale(); } if ((selectedLocales.length == 0) || ((selectedLocales.length == 1) && selectedLocales[0].equals(NO_LOCALES))) { return NO_LOCALES; } else if ((selectedLocales.length == 1) && selectedLocales[0].equals(ALL_LOCALES)) { return ALL_LOCALES; } return selectedLocales; } // ISO, TARGET_LOCALE, CURRENT_LOCALE public void setDisplayStyle(int displayStyle) { this.displayStyle = displayStyle; buildTree(); } public int getDisplayStyle() { return displayStyle; } public void setAcceptLeafNodesOnly(boolean acceptLeafNodesOnly) { this.acceptLeafNodesOnly = acceptLeafNodesOnly; } public boolean isAcceptLeafNodesOnly() { return acceptLeafNodesOnly; } public void setAllowMultiSelect(boolean allowMultiSelect) { if (this.allowMultiSelect == allowMultiSelect) { return; } if (allowMultiSelect) { selection = new BasicGraphSelection(); } else { selection = new SingleGraphSelection(); } treeControl.setSelection(selection); this.allowMultiSelect = allowMultiSelect; } public boolean isAllowMultiSelect() { return allowMultiSelect; } public void setLocale(Locale locale) { super.setLocale(locale); Locale.setDefault(locale); // update the resourced locale title if (title == DEFAULT_TITLE) { resourceBundle = ResourceBundle.getBundle("borland.samples.intl.beans.resources.LocaleChooserRes"); setTitle(DEFAULT_TITLE); } // update the current locale denoted in the tree InputIterator i = ((LinkedTreeContainer) treeControl.getModel()).elements(); LinkedTreeNode treeNode; while (!i.atEnd()) { treeNode = (LinkedTreeNode) i.get(); if (((LocaleDataPair) ((Pair) treeControl.get(treeNode)).first).getLocale().equals(locale)) { setCurrentLocaleNode(treeNode); break; } i.advance(); } notifyLocaleChangeListeners(locale); } public Locale getLocale() { try { return super.getLocale(); } catch (IllegalComponentStateException e) { return Locale.getDefault(); } } public void actionPerformed(ActionEvent e) { LinkedTreeNode target = (LinkedTreeNode) treeControl.getSubfocus(); if (acceptLeafNodesOnly && (target.hasChildren() == TriState.YES)) { return; } Locale newLocale = ((LocaleDataPair) ((Pair) treeControl.get(target)).first).getLocale(); setCurrentLocaleNode(target); setLocale(newLocale); } protected void buildTree() { Locale [] selectedLocales = getSelectedLocales(); LocaleDataPair localeDataPair = new LocaleDataPair(title == DEFAULT_TITLE ? resourceBundle.getString("Select_a_locale") : title, TITLE_LOCALE); BasicOrderedTreeContainer basicOrderedTreeContainer = new BasicOrderedTreeContainer(new Pair(localeDataPair, images[imageIndex])); imageIndex = (imageIndex + 1) % images.length; treeControl.setModel(basicOrderedTreeContainer); rootNode = treeControl.getRoot(); GraphLocation languageTreeNode = null; GraphLocation countryTreeNode = null; GraphLocation variantTreeNode = null; currentLocaleNode = null; Locale [] treeChoices; if (localeChoices == NO_LOCALES) { treeChoices = new Locale [] { }; } else if (localeChoices == ALL_LOCALES) { treeChoices = getAllRuntimeLocales(); } else { treeChoices = localeChoices; } for (int i = 0; i < treeChoices.length; i++) { if (treeChoices[i].getLanguage().length() != 0) { localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayLanguage(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), "")); if (displayStyle == ISO) { localeDataPair.setText(treeChoices[i].getLanguage()); } else if (displayStyle == CURRENT_LOCALE) { localeDataPair.setText(treeChoices[i].getDisplayLanguage(getLocale())); } languageTreeNode = basicOrderedTreeContainer.addOrderedChild(rootNode, new Pair(localeDataPair, null), this); if (getLocale().getLanguage().equals(treeChoices[i].getLanguage())) { setCurrentLocaleNode(languageTreeNode); } } else { continue; } if (treeChoices[i].getCountry().length() != 0) { localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayCountry(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), treeChoices[i].getCountry())); if (displayStyle == ISO) { localeDataPair.setText(treeChoices[i].getCountry()); } else if (displayStyle == CURRENT_LOCALE) { localeDataPair.setText(treeChoices[i].getDisplayCountry(getLocale())); } countryTreeNode = basicOrderedTreeContainer.addOrderedChild(languageTreeNode, new Pair(localeDataPair, null), this); if (getLocale().getLanguage().equals(treeChoices[i].getLanguage()) && getLocale().getCountry().equals(treeChoices[i].getCountry())) { setCurrentLocaleNode(countryTreeNode); } } else { continue; } if (treeChoices[i].getVariant().length() != 0) { localeDataPair = new LocaleDataPair(treeChoices[i].getDisplayVariant(treeChoices[i]), new Locale(treeChoices[i].getLanguage(), treeChoices[i].getCountry(), treeChoices[i].getVariant())); if (displayStyle == ISO) { localeDataPair.setText(treeChoices[i].getVariant()); } else if (displayStyle == CURRENT_LOCALE) { localeDataPair.setText(treeChoices[i].getDisplayVariant(getLocale())); } variantTreeNode = basicOrderedTreeContainer.addOrderedChild(countryTreeNode, new Pair(localeDataPair, null), this); if (getLocale().equals(treeChoices[i])) { setCurrentLocaleNode(variantTreeNode); } } } setSelectedLocales(selectedLocales); } public void setTitle(String title) { this.title = title; LocaleDataPair oldLocaleDataPair = (LocaleDataPair) ((Pair) treeControl.get(rootNode)).first; LocaleDataPair newLocaleDataPair = new LocaleDataPair(title == DEFAULT_TITLE ? resourceBundle.getString("Select_a_locale") : title, oldLocaleDataPair.getLocale()); treeControl.set(rootNode, new Pair(newLocaleDataPair, images[imageIndex])); imageIndex = (imageIndex + 1) % images.length; } public String getTitle() { return title; } // a null value for the collationLocale means no specified Locale, i.e., Unicode collation order public void setCollationLocale(Locale collationLocale) { this.collationLocale = collationLocale; if (collationLocale.equals(NULL_LOCALE)) { collator = null; } else if (collationLocale.equals(DEFAULT_RUNTIME_LOCALE)) { collator = Collator.getInstance(); } else { collator = Collator.getInstance(collationLocale); } } public Locale getCollationLocale() { return collationLocale; } public Dimension getMinimumSize() { return treeControl.getMinimumSize(); } public Dimension getPreferredSize() { Dimension dimension = treeControl.getPreferredSize(); return new Dimension(dimension.width + 5, dimension.height + 5); } private void setCurrentLocaleNode(GraphLocation node) { // don't do anything if the same node is selected again if (currentLocaleNode == node) { return; } // unmark the old node if (currentLocaleNode != null) { Pair oldPair = (Pair) treeControl.get(currentLocaleNode); treeControl.set(currentLocaleNode, new Pair(oldPair.first, null)); } // mark the new node if (node != null) { currentLocaleNode = node; Pair oldPair = (Pair) treeControl.get(currentLocaleNode); treeControl.set(currentLocaleNode, new Pair(oldPair.first, currentSelectionImage)); } } private Locale [] getAllRuntimeLocales() { return java.text.NumberFormat.getAvailableLocales(); } // event-handling public synchronized void addLocaleChangeListener(LocaleChangeListener listener) { localeChangeListeners.addElement(listener); } public synchronized void removeLocaleChangeListener(LocaleChangeListener listener) { localeChangeListeners.removeElement(listener); } protected void notifyLocaleChangeListeners(Locale locale) { LocaleChangeEvent localeChangeEvent = new LocaleChangeEvent(this, locale); Vector listeners; Component component = this; Frame frame = null; while ((component = component.getParent()) != null) { if (component instanceof Frame) { frame = (Frame) component; break; } } if (frame == null) { frame = new Frame(); } this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); synchronized (this) { listeners = (Vector) localeChangeListeners.clone(); } for (int i = 0; i < listeners.size(); i++) { ((LocaleChangeListener) listeners.elementAt(i)).localeChanged(localeChangeEvent); } frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } public void addSelectionListener(GraphSelectionListener listener) { treeControl.addSelectionListener(listener); } public void removeSelectionListener(GraphSelectionListener listener) { treeControl.removeSelectionListener(listener); } // implementation of BinaryComparator interface public int compare(Object item1, Object item2) { if (collator == null) { return ((Pair) item1).first.toString().compareTo(((Pair) item2).first.toString()); } else { return collator.compare(((Pair) item1).first.toString(), ((Pair) item2).first.toString()); } } public synchronized void setAnimationEnabled(boolean animationEnabled) { this.animationEnabled = animationEnabled; if (animationEnabled && animationThread == null) { animationThread = new Thread(this); animationThread.start(); } if (animationEnabled) { notify(); } else { imageIndex = 0; Pair oldPair = (Pair) treeControl.get(rootNode); oldPair.second = images[imageIndex]; treeControl.touched(rootNode); } } public boolean getAnimationEnabled() { return animationEnabled; } // implementation of Runnable interface public void run() { try { while (true) { synchronized (this) { while (!animationEnabled) { wait(); } } if (rootNode != null) { Pair oldPair = (Pair) treeControl.get(rootNode); oldPair.second = images[imageIndex]; treeControl.touched(rootNode); imageIndex = (imageIndex + 1) % images.length; } Thread.sleep(animationRate); } } catch (InterruptedException e) { } } public Component add(Component comp) { return null; } public Component add(String name, Component comp) { return null; } public Component add(Component comp, int index) { return null; } public void add(Component comp, Object constraints) {} public void add(Component comp, Object constraints, int index) {} public void remove(int index) {} public void remove(Component comp) {} public void removeAll() {} public void setLayout(LayoutManager mgr) {} public LayoutManager getLayout() { return super.getLayout(); } } // need to override the Pair.toString() method to return the correct string for TextItemPainter() class LocaleDataPair extends Pair { String textItem; Locale locale; public LocaleDataPair(String textItem, Locale locale) { this.textItem = textItem; this.locale = locale; } public String toString() { return textItem; } public Locale getLocale() { return locale; } public void setLocale(Locale locale) { this.locale = locale; } public void setText(String textItem) { this.textItem = textItem; } }