Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/greenstone/gatherer/Dictionary.java


1   /**
2    *#########################################################################
3    *
4    * A component of the Gatherer application, part of the Greenstone digital
5    * library suite from the New Zealand Digital Library Project at the
6    * University of Waikato, New Zealand.
7    *
8    * <BR><BR>
9    *
10   * Author: John Thompson, Greenstone Digital Library, University of Waikato
11   *
12   * <BR><BR>
13   *
14   * Copyright (C) 1999 New Zealand Digital Library Project
15   *
16   * <BR><BR>
17   *
18   * This program is free software; you can redistribute it and/or modify
19   * it under the terms of the GNU General Public License as published by
20   * the Free Software Foundation; either version 2 of the License, or
21   * (at your option) any later version.
22   *
23   * <BR><BR>
24   *
25   * This program is distributed in the hope that it will be useful,
26   * but WITHOUT ANY WARRANTY; without even the implied warranty of
27   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28   * GNU General Public License for more details.
29   *
30   * <BR><BR>
31   *
32   * You should have received a copy of the GNU General Public License
33   * along with this program; if not, write to the Free Software
34   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35   *########################################################################
36   */
37  package org.greenstone.gatherer;
38  
39  import java.awt.*;
40  import java.io.*;
41  import java.util.*;
42  import javax.swing.*;
43  import javax.swing.plaf.*;
44  import javax.swing.text.*;
45  import javax.swing.tree.*;
46  import org.greenstone.gatherer.util.Utility;
47  
48  /** Extends the ResourceBundle class to allow for the automatic insertion of  arguments. Note that the key names beginning Farg are reserved for formatting. <BR>
49   * <BR>
50   * Property files usable by this class have the Backus-Naur form: <BR>
51   * <BR>
52   * FileLine ::= Comment | Mapping <BR>
53   * Comment  ::= '#' SString <BR>
54   * Mapping  ::= NZString ':' SString ( Argument SString )* <BR>
55   * NZString ::= ( Char | Int ) SString <BR>
56   * Argument ::= '{' Int '}' <BR>
57   * SString  ::= String . ['"','#',...] -> ['\"','\#',...] <BR>
58   * <BR>
59   * In order to add a new dictionary Locale, simply copy the existing dictionary.properties files, replace the values (Strings after the ':') with the new language specific ones being careful to maintain formatting and Gatherer placed arguments, then save the new dictionary as: <br>
60   * <BR>
61   * dictionary_<I>locale</I>.properties<BR>
62   * <BR>
63   * where locale is made of two two-letter codes seperated by an underscore. The first code is in lower-case and defines the language. The second is in upper-case and defines the country. For example the default dictionary could also correctly be called:
64   * <BR>
65   * dictionary_en_NZ.properties<BR>
66   * @author John Thompson, Greenstone Digital Library, University of Waikato
67   * @version 2.3
68   */
69  public class Dictionary
70      extends HashMap {
71  
72      static final private boolean KEY_LIST_DEBUG = false;
73      static final private String KEY_LIST_FILENAME = "keylist.txt";
74  
75      /** A String which more explicitly states the Locale of this dictionary. */
76      public String language = null;
77      /** A static reference to ourself. */
78      static public Dictionary self;
79      /** The font used when displaying various html text. */
80      private FontUIResource font = null;
81      /** A reference to remind us of the current locale. */
82      private Locale locale = null;
83      /** The ResourceBundle which contains the raw key-value mappings. Loaded from a file named "dictionary<I>locale</I>.properties*/
84      private ResourceBundle dictionary = null;
85  
86      private TreeSet key_list = null;;
87  
88      /**  Constructs the Dictionary class by first checking if a Locale has been set. If not the default locale is used, and a ResourceBundle is created. Finally a single important String, Language, is made available outside the class so a more read-able version of the Locale of this Dictionary is present.
89       * @param locale The <strong>Locale</strong> used to load the desired dictionary resource bundle.
90       */
91      public Dictionary(Locale locale, FontUIResource font) {
92    super();
93    this.self = this;
94  
95    if (KEY_LIST_DEBUG) {
96        // Reload the keylist
97        File file = new File(KEY_LIST_FILENAME);
98        key_list = new TreeSet();
99        try {
100     BufferedReader br = new BufferedReader(new FileReader(file));
101     String line;
102     while((line = br.readLine()) != null) {
103         key_list.add(line);
104     }
105     br.close();
106     br = null;
107       }
108       catch(Exception error) {
109     error.printStackTrace();
110       }
111   }
112 
113   // Initialize.
114   this.font = font;
115   if (locale == null) {
116       this.locale = Locale.getDefault();
117   }
118   else {
119       this.locale = locale;
120       Locale.setDefault(locale);
121   }
122   dictionary = ResourceBundle.getBundle(Utility.DICTIONARY, this.locale);
123   // Now quickly read in language name.
124   language = dictionary.getString("Language");
125     }
126 
127 
128     /** Change the currently loaded dictionary and update registered components */
129     public void changeDictionary(Locale locale)
130     {
131   this.locale = locale;
132 
133   // Load new dictionary
134   dictionary = ResourceBundle.getBundle(Utility.DICTIONARY, locale);
135   language = dictionary.getString("Language");
136   Gatherer.println("Loaded new dictionary: " + language);
137 
138   // Refresh all registered component
139   // !! TO FINISH !!
140   Gatherer.println("Updating components...");
141 //    ArrayList temp_list = new ArrayList();
142 //    Iterator components = keySet().iterator();
143 //    while (components.hasNext()) {
144 //        Component component = (Component) components.next();
145 //        temp_list.add(component);
146 //    }
147 
148 //    for (int i = 0; i < temp_list.size(); i++) {
149 //        Component component = (Component) temp_list.get(i);
150 //        ComponentDetails details = (ComponentDetails) get(component);
151 //        oldSetBoth(component, details.text_key, details.text_args, details.tooltip_key);
152 //    }
153 
154 //    for (Iterator keys = keySet().iterator(); keys.hasNext(); ) {
155 //        Component component = (Component) keys.next();
156 //        ComponentDetails details = (ComponentDetails) get(component);
157 //        oldSetBoth(component, details.text_key, details.text_args, details.tooltip_key);
158 //    }
159     }
160 
161 
162     /** Change the currently loaded dictionary and update registered (ie dynamic) components as possible. */
163 //      public void oldChangeDictionary(Locale locale) {
164 //    this.locale = locale;
165 //    // Load new dictionary
166 //    dictionary = ResourceBundle.getBundle(Utility.DICTIONARY, locale);
167 //    language = dictionary.getString("Language");
168 //    Gatherer.println("Having loaded new dictionary: " + language);
169 //    // Refresh all registered component
170 //    Gatherer.println("Updating components");
171 //    for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
172 //        Object component = keys.next();
173 //        String[] args = (String[]) get(component);
174 //        if(component instanceof AbstractButton) {
175 //      register((AbstractButton)component, args, true);
176 //        }
177 //        else if(component instanceof JComboBox) {
178 //      register((JComboBox)component, args, true);
179 //        }
180 //        else if(component instanceof JDialog) {
181 //      register((JDialog)component, args, true);
182 //        }
183 //        else if(component instanceof JFrame) {
184 //      register((JFrame)component, args, true);
185 //        }
186 //        else if(component instanceof JLabel) {
187 //      register((JLabel)component, args, true);
188 //        }
189 //        else if(component instanceof JTabbedPane) {
190 //      register((JTabbedPane)component, args, true);
191 //        }
192 //        else if(component instanceof JTextComponent) {
193 //      register((JTextComponent)component, args, true);
194 //        }
195 //        else if(component instanceof JTree) {
196 //      register((JTree)component, args, true);
197 //        }
198 //        else if(component instanceof TitledBorder) {
199 //      register((TitledBorder)component, args, true);
200 //        }
201 //        args = null;
202 //        component = null;
203 //    }
204 //      }
205 
206     /** Remove the component from our registered components list. */
207     /* private void deregister(Object component) {
208   remove(component);
209   } */
210 
211     public void destroy() {
212   if(key_list != null) {
213       try {
214     FileOutputStream fos = new FileOutputStream(KEY_LIST_FILENAME);
215     for(Iterator iter = key_list.iterator(); iter.hasNext(); ) {
216         String value = (String) iter.next();
217         fos.write(value.getBytes());
218         fos.write('\n');
219         value = null;
220     }
221     fos.close();
222     fos = null;
223       }
224       catch(Exception error) {
225     error.printStackTrace();
226       }
227   }
228     }
229 
230 
231     static public String get(String key)
232     {
233   return self.oldget(key);
234     }
235 
236 
237     static public String get(String key, String arg)
238     {
239   String[] args = new String[1];
240   args[0] = arg;
241   return self.oldget(key, args);
242     }
243 
244 
245     static public String get(String key, String[] args)
246     {
247   return self.oldget(key, args);
248     }
249 
250 
251     /**
252      * @deprecated
253      * Overloaded to call get with both a key and an empty argument array.
254      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
255      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
256      */
257     public String oldget(String key) {
258   return oldget(key, (String[])null);
259     }
260 
261     /**
262      * @deprecated
263      * Convienence method with transforms the second string argument into a string array. */
264     public String oldget(String key, String arg) {
265   String[] args = new String[1];
266   args[0] = arg;
267   return oldget(key, args);
268     }
269 
270     /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
271      * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
272      * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
273      * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
274      * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
275      */
276     public String oldget(String key, String args[]) {
277   if(key_list != null) {
278       synchronized(this) {
279     key_list.add(key);
280       }
281   }
282   try {
283       String initial = dictionary.getString(key);
284       // If the string contains arguments we have to insert them.
285       String complete = "";
286       // While we still have initial string left.
287       while(initial.length() > 0 && initial.indexOf('{') != -1 && initial.indexOf('}') != -1) {
288     // Remove preamble
289     int opening = initial.indexOf('{');
290     int closing = initial.indexOf('}');
291     int comment_mark = initial.indexOf('-', opening); // May not exist
292     if(comment_mark > closing) { // May also be detecting a later comment
293         comment_mark = -1;
294     }
295     complete = complete + initial.substring(0, opening);
296     // Parse arg_num
297     String arg_str = null;
298     if(comment_mark != -1) {
299         arg_str = initial.substring(opening + 1, comment_mark);
300     }
301     else {
302         arg_str = initial.substring(opening + 1, closing);
303     }
304     int arg_num = Integer.parseInt(arg_str);
305     if(closing + 1 < initial.length()) {
306         initial = initial.substring(closing + 1);
307     }
308     else {
309         initial = "";
310     }
311     // Insert argument
312     if(args != null && 0 <= arg_num && arg_num < args.length) {
313         complete = complete + args[arg_num];
314     }
315     else if(arg_num >= 32) {
316         String f_subargs[] = new String[1];
317         if(font != null) {
318       f_subargs[0] = font.getFontName();
319         }
320         else {
321       f_subargs[0] = "Arial";
322         }
323         complete = complete + oldget("Farg" + arg_num, f_subargs);
324     }
325       }
326       return complete + initial;
327   }
328   catch (Exception e) {
329       System.err.println("Missing value for key: " + key);
330       Gatherer.printStackTrace(e);
331       return key;
332   }
333     }
334 
335     /** Retrieve the two letter code of the current language we are using, according to the stored locale.
336      * @return A <strong>String</strong> containing the two letter ISO639 language code.
337      */
338     public String getLanguage() {
339   return locale.getLanguage();
340     }
341 
342 
343     static public void setBoth(Component component, String text_key, String tooltip_key)
344     {
345   setText(component, text_key);
346   setTooltip(component, tooltip_key);
347     }
348 
349 
350     static public void setText(Component component, String text_key)
351     {
352   setText(component, text_key, null);
353     }
354 
355 
356     static public void setText(Component component, String text_key, String[] args)
357     {
358   if (component != null) {
359       // Update the component using the AWTEvent queue
360       ComponentDetails details = new ComponentDetails(true, text_key, args, false, null);
361       ComponentUpdateTask task = new ComponentUpdateTask(component, details, true);
362       SwingUtilities.invokeLater(task);
363   }
364     }
365 
366 
367     static public void setTooltip(Component component, String tooltip_key)
368     {
369   if (component != null) {
370       // Update the component using the AWTEvent queue
371       ComponentDetails details = new ComponentDetails(false, null, null, true, tooltip_key);
372       ComponentUpdateTask task = new ComponentUpdateTask(component, details, true);
373       SwingUtilities.invokeLater(task);
374   }
375     }
376 
377 
378     static public void registerBoth(Component component, String text_key, String tooltip_key)
379     {
380   registerText(component, text_key, null);
381   registerTooltip(component, tooltip_key);
382     }
383 
384 
385     static public void registerText(Component component, String text_key)
386     {
387   registerText(component, text_key, null);
388     }
389 
390 
391     static public void registerText(Component component, String text_key, String[] args)
392     {
393   if (component != null) {
394       // Update the component's details
395       ComponentDetails details = (ComponentDetails) self.remove(component);
396       if (details == null) {
397     details = new ComponentDetails(true, text_key, args, false, null);
398       }
399       else {
400     details.has_text = true;
401     details.text_key = text_key;
402     details.text_args = args;
403       }
404       self.put(component, details);
405 
406       // Update the component using the AWTEvent queue
407       ComponentUpdateTask task = new ComponentUpdateTask(component, details, true);
408       SwingUtilities.invokeLater(task);
409   }
410     }
411 
412     static public void registerTooltip(Component component, String tooltip_key) {
413         self.registerTooltip(component, tooltip_key, true);
414     }
415 
416     static public void registerTooltip(Component component, String tooltip_key, boolean is_key)
417     {
418   if (component != null) {
419       // Update the component's details
420       ComponentDetails details = (ComponentDetails) self.remove(component);
421       if (details == null) {
422     details = new ComponentDetails(false, null, null, true, tooltip_key);
423       }
424       else {
425     details.has_tooltip = true;
426     details.tooltip_key = tooltip_key;
427       }
428       self.put(component, details);
429 
430       // Update the component using the AWTEvent queue
431       ComponentUpdateTask task = new ComponentUpdateTask(component, details, is_key);
432       SwingUtilities.invokeLater(task);
433   }
434     }
435 
436 
437     static private class ComponentDetails
438     {
439   public boolean has_text;
440   public String text_key;
441   public String[] text_args;
442   public boolean has_tooltip;
443   public String tooltip_key;
444 
445   public ComponentDetails(boolean has_text, String text_key, String[] text_args,
446         boolean has_tooltip, String tooltip_key)
447   {
448       this.has_text = has_text;
449       this.text_key = text_key;
450       this.text_args = text_args;
451       this.has_tooltip = has_tooltip;
452       this.tooltip_key = tooltip_key;
453   }
454     }
455 
456 
457     static private class ComponentUpdateTask
458   implements Runnable {
459 
460   private Component component;
461   private String text = null;
462   private String tooltip = null;
463 
464   public ComponentUpdateTask(Component component, ComponentDetails details, boolean is_key)
465   {
466       this.component = component;
467 
468       if (details.has_text) {
469     text = self.oldget(details.text_key, details.text_args);
470       }
471       if (details.has_tooltip) {
472             if(is_key) {
473         tooltip = self.oldget(details.tooltip_key, (String[]) null);
474             }
475             else {
476                 tooltip = details.tooltip_key;
477             }
478       }
479   }
480 
481 
482   public void run()
483   {
484       // If the component has text
485       if (text != null) {
486     if (component instanceof AbstractButton) {
487         ((AbstractButton) component).setText(text);
488     }
489     else if (component instanceof Frame) {
490         ((Frame) component).setTitle(text);
491     }
492     else if (component instanceof JDialog) {
493         ((JDialog) component).setTitle(text);
494     }
495     else if (component instanceof JLabel) {
496         ((JLabel) component).setText(text);
497     }
498     else if (component instanceof JProgressBar) {
499         ((JProgressBar) component).setString(text);
500     }
501     else if (component instanceof JTextComponent) {
502         ((JTextComponent) component).setText(text);
503         ((JTextComponent) component).setCaretPosition(0);
504     }
505     else {
506         System.err.println("Unhandled component: " + component.getClass());
507     }
508       }
509 
510       // If the component has a tooltip
511       if (tooltip != null) {
512     if (component instanceof JComponent) {
513         ((JComponent) component).setToolTipText(tooltip);
514     }
515       }
516   }
517     }
518 
519 
520     /**
521      * Register a tab pane component. This will be deprecated eventually. */
522     static public void register(JTabbedPane component)
523     {
524   if (component != null) {
525       String[] args = new String[component.getTabCount()];
526 
527       // Iterate through the tabbed panes tabs, updating values and recording the original key of each item in args.
528       for (int i = 0; i < args.length; i++) {
529     if (args[i] == null) {
530         args[i] = component.getTitleAt(i);
531     }
532     String value = self.oldget(args[i], (String[]) null);
533     String tooltip = self.oldget(args[i] + "_Tooltip", (String[]) null);
534     JTabbedPaneChangeTask task = new JTabbedPaneChangeTask(component, i, value, tooltip);
535     SwingUtilities.invokeLater(task);
536       }
537   }
538     }
539 
540 
541     /** Updates a tabbed panes tab title and tooltip. */
542     static private class JTabbedPaneChangeTask
543     implements Runnable {
544 
545     private JTabbedPane component;
546     private int index;
547     private String value;
548     private String tooltip;
549 
550     public JTabbedPaneChangeTask(JTabbedPane component, int index, String value, String tooltip) {
551         this.component = component;
552         this.index = index;
553       this.value = value;
554         this.tooltip = tooltip;
555     }
556 
557     public void run() {
558         component.setTitleAt(index, value);
559       component.setToolTipTextAt(index, tooltip);
560     }
561     }
562 }