source: trunk/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java@ 4580

Last change on this file since 4580 was 4494, checked in by jmt12, 21 years ago

2030098: Fixed translation manager and separated the Languages from the possible text fragment Translations.

  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
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
38
39
40
41
42
43package org.greenstone.gatherer.cdm;
44/**************************************************************************************
45 * Title: Gatherer
46 * Description: The Gatherer: a tool for gathering and enriching a digital collection.
47 * Copyright: Copyright (c) 2001
48 * Company: The University of Waikato
49 * Written: 08/05/02
50 * Revised: 17/11/02 - Commented
51 **************************************************************************************/
52import java.awt.BorderLayout;
53import java.awt.Color;
54import java.awt.Component;
55import java.awt.Dimension;
56import java.awt.GridLayout;
57import java.awt.event.ActionEvent;
58import java.awt.event.ActionListener;
59import java.awt.event.KeyEvent;
60import java.io.BufferedReader;
61import java.io.File;
62import java.io.FileReader;
63import java.util.ArrayList;
64import java.util.Collections;
65import java.util.Enumeration;
66import java.util.Iterator;
67import java.util.LinkedHashMap;
68import java.util.StringTokenizer;
69import java.util.Vector;
70import javax.swing.BorderFactory;
71import javax.swing.DefaultListCellRenderer;
72import javax.swing.DefaultListModel;
73import javax.swing.ListModel;
74import javax.swing.JButton;
75import javax.swing.JComboBox;
76import javax.swing.JLabel;
77import javax.swing.JList;
78import javax.swing.JPanel;
79import javax.swing.JScrollPane;
80import javax.swing.JTextArea;
81import javax.swing.JTextField;
82import javax.swing.event.ListSelectionEvent;
83import javax.swing.event.ListSelectionListener;
84import org.greenstone.gatherer.Gatherer;
85import org.greenstone.gatherer.cdm.Language;
86/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
87 * @author John Thompson, Greenstone Digital Library, University of Waikato
88 * @version 2.3
89 */
90public class LanguageManager
91 extends DefaultListModel {
92 /** A reference to the collection design manager. */
93 private CollectionDesignManager manager = null;
94 /** The visual controls for this manager. */
95 private Control controls = null;
96 /** A reference to the Gatherer. */
97 private Gatherer gatherer = null;
98 /** A reference to this class as a model, for the inner controls class. */
99 private ListModel model = null;
100 /** A hashtable of code->name mappings of known languages. */
101 private LinkedHashMap known_languages = null;
102 /** The default language object. */
103 private Language default_language = null;
104
105 static final private Dimension LABEL_SIZE = new Dimension(125,25);
106 /** Constructor.
107 * @param gatherer A reference to the <strong>Gatherer</strong>.
108 * @param manager A reference to the <strong>CollectionDesignManager</strong>.
109 */
110 public LanguageManager(Gatherer gatherer, CollectionDesignManager manager) {
111 super();
112 this.gatherer = gatherer;
113 this.known_languages = new LinkedHashMap();
114 this.manager = manager;
115 this.model = this;
116 loadLanguages();
117 }
118 /** Method to add a new language.
119 * @param language The <strong>Language</strong> to add.
120 * @see org.greenstone.gatherer.Gatherer
121 * @see org.greenstone.gatherer.collection.CollectionManager
122 */
123 public void addLanguage(Language language) {
124 if(!contains(language)) {
125 // Add alphabetically.
126 for(int index = 0; index < size(); index++) {
127 Language sibling = (Language) get(index);
128 int position = language.compareTo(sibling);
129 // Sibling is before language.
130 if(position > 0) {
131 // Carry on.
132 }
133 // Language is equal to, or before sibling. Insert it.
134 else if(position == 0 || position < 0) {
135 add(index, language);
136 gatherer.c_man.configurationChanged();
137 return;
138 }
139 }
140 // If we got this far, we haven't inserted language, and we are out of model so.
141 addElement(language);
142 gatherer.c_man.configurationChanged();
143 }
144 }
145 /** Method to retrieve the control for this manager.
146 * @return A <strong>JPanel</strong> containing the controls.
147 */
148 public JPanel getControls() {
149 if(controls == null) {
150 controls = new Control();
151 }
152 return controls;
153 }
154 /** Method to retrieve the default language code.
155 * @return A <strong>Language</strong> containing a two letter code.
156 */
157 public Language getDefaultLanguage() {
158 // If no default is set...
159 if(default_language == null) {
160 // And we have other assigned languages, use the first one of them.
161 if(size() >= 1) {
162 default_language = (Language) get(0);
163 }
164 // And we have nothing else, use English.
165 else {
166 default_language = getLanguage("en", false);
167 // Remember to add it.
168 addLanguage(default_language);
169 }
170 }
171 return default_language;
172 }
173 /** Method to retrieve a certain language object by its code.
174 * @param code The two letter code of a language, as a <strong>String</strong>.
175 * @param assigned_only If <i>true</i> only those languages currently having indexes built for them are checked, otherwise the known languages buffer is checked.
176 * @return The <strong>Language</strong> that matches the given code, or <i>null</i> if no such language exists.
177 */
178 public Language getLanguage(String code, boolean assigned_only) {
179 if(assigned_only) {
180 for(int i = 0; i < size(); i++) {
181 Language pos = (Language)get(i);
182 ///ystem.err.println("Comparing " + pos.getCode() + " and " + code);
183 if(pos.getCode().equals(code)) {
184 return pos;
185 }
186 }
187 }
188 else {
189 if(known_languages.containsKey(code)) {
190 return new Language((Language)known_languages.get(code));
191 }
192 }
193 return null;
194 }
195 /** Method to return a list of the known language codes.
196 * @return An <strong>ArrayList</strong> containing a series of alphabetically sorted two letter codes.
197 */
198 public ArrayList getLanguageCodes() {
199 ArrayList result = new ArrayList();
200 Iterator key_iter = known_languages.keySet().iterator();
201 while(key_iter.hasNext()) {
202 result.add(known_languages.get(key_iter.next()));
203 }
204 //for(Enumeration keys = known_languages.keys(); keys.hasMoreElements(); ) {
205 // result.add(known_languages.get(keys.nextElement()));
206 //}
207 //Collections.sort(result);
208 return result;
209 }
210 /** Mark the current set of controls, if any, as obsolete and deallocate them. If further need of the controls will cause new controls to be created.
211 * @see org.greenstone.gatherer.cdm.IndexManager.Control
212 */
213 public void invalidateControls() {
214 if(controls != null) {
215 controls.destroy();
216 }
217 controls = null;
218 }
219
220 /** Determine if the given language is the current default language.
221 * @param language The <strong>Language</strong> to test.
222 * @return <i>true</i> if the language is the default one, <i>false</i> otherwise.
223 */
224 public boolean isDefaultLanguage(Language language) {
225 return (language.equals(default_language));
226 }
227 /** This method attempts to parse a language command from the given string. If such a command is parsed, it is immediately added to the list of languages.
228 * @param command The <strong>String</strong> containing a possible language command.
229 * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
230 * @see org.greenstone.gatherer.cdm.Language
231 */
232 public boolean parse(String command) {
233 String command_lc = command.toLowerCase();
234 if(command_lc.startsWith("languages")) {
235 StringTokenizer tokenizer = new StringTokenizer(command);
236 tokenizer.nextToken();
237 while(tokenizer.hasMoreTokens()) {
238 String code = tokenizer.nextToken();
239 if(known_languages.containsKey(code)) {
240 Language language = (Language)known_languages.get(code);
241 addElement(new Language(language));
242 }
243 else {
244 addElement(new Language(code, code, false));
245 }
246 }
247 return true;
248 }
249 if(command_lc.startsWith("defaultlanguage")) {
250 StringTokenizer tokenizer = new StringTokenizer(command);
251 tokenizer.nextToken();
252 if(tokenizer.hasMoreTokens()) {
253 String code = tokenizer.nextToken();
254 Language language = getLanguage(code, true);
255 if(language == null) {
256 language = new Language(code, (String)known_languages.get(code), true);
257 addElement(language);
258 }
259 else {
260 language.setDefault(true);
261 }
262 setDefault(language);
263 }
264 return true;
265 }
266 return false;
267 }
268 /** Method to cause the list appearance to update if the selection changes. */
269 public void refreshAppearance() {
270 fireContentsChanged(this, 0, size());
271 }
272 /** Method to remove a certain language.
273 * @param language The <strong>Language</strong> to remove.
274 * @see org.greenstone.gatherer.Gatherer
275 * @see org.greenstone.gatherer.collection.CollectionManager
276 */
277 public void removeLanguage(Language language) {
278 removeElement(language);
279 if(default_language != null && default_language.equals(language)) {
280 default_language = null;
281 }
282 gatherer.c_man.configurationChanged();
283 }
284 /** Method to set the default language.
285 * @param language The <strong>Language</strong> to use as a default, or <i>null</i> for no default.
286 * @see org.greenstone.gatherer.Gatherer
287 * @see org.greenstone.gatherer.collection.CollectionManager
288 */
289 public void setDefault(Language language) {
290 // Unset existing.
291 Language old = null;
292 if(default_language != null) {
293 old = default_language;
294 default_language.setDefault(false);
295 default_language = null;
296 }
297 // Now set the new if its not null.
298 if(language != null) {
299 default_language = language;
300 default_language.setDefault(true);
301 }
302 // Now cause the model to refresh any lists that are listening.
303 int start = 0;
304 int end = size() - 1;
305 if(default_language != null && old != null) {
306 int index_default = indexOf(default_language);
307 int index_old = indexOf(old);
308 if(index_default < index_old) {
309 start = index_default;
310 end = index_old;
311 }
312 else {
313 start = index_old;
314 end = index_default;
315 }
316 }
317 else if(default_language != null) {
318 start = end = indexOf(default_language);
319 }
320 else {
321 start = end = indexOf(old);
322 }
323 fireContentsChanged(this, 0, size());
324 gatherer.c_man.configurationChanged();
325 }
326 /** Method to translate this object into a block of commands as you you expect to find in the collection configuration file.
327 * @return A <strong>String</string> containing a series of commands.
328 */
329 public String toString() {
330 StringBuffer text = new StringBuffer();
331 if(size() > 1) {
332 text.append("languages ");
333 for(int i = 0; i < size(); i++) {
334 Language language = (Language) get(i);
335 text.append(language.getCode());
336 if(i < size() - 1) {
337 text.append(" ");
338 }
339 else {
340 text.append("\n");
341 }
342 }
343 // Only bother with default language if there is more than one language.
344 if(default_language != null) {
345 text.append("defaultlanguage ");
346 text.append(default_language.getCode());
347 text.append("\n");
348 }
349 text.append("\n");
350 }
351 return text.toString();
352 }
353 /** Overloaded to call get with both a key and an empty argument array.
354 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
355 * @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.
356 */
357 private String get(String key) {
358 return get(key, null);
359 }
360 /** 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>
361 * 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>.
362 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
363 * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
364 * @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.
365 * @see org.greenstone.gatherer.Gatherer
366 * @see org.greenstone.gatherer.Dictionary
367 */
368 private String get(String key, String args[]) {
369 if(key.indexOf('.') == -1) {
370 key = "CDM.LanguageManager." + key;
371 }
372 return gatherer.dictionary.get(key, args);
373 }
374 /** This method loads a series of code->language mappings into known_languages, by reading from the 'languages.dat' file, which is essentially a verbatim copy of the ISO 639 Standard.
375 * @see org.greenstone.gatherer.cdm.Language
376 */
377 private void loadLanguages() {
378 try {
379 File in_file = new File("languages.dat");
380 FileReader in_reader = new FileReader(in_file);
381 BufferedReader in = new BufferedReader(in_reader);
382 String entry = null;
383 while((entry = in.readLine()) != null) {
384 if(!entry.startsWith("#")) {
385 StringTokenizer tokenizer = new StringTokenizer(entry);
386 String name = tokenizer.nextToken();
387 String code = tokenizer.nextToken().toLowerCase();
388 Language language = new Language(code, name, false);
389 known_languages.put(code, language);
390 }
391 }
392 in.close();
393 }
394 catch (Exception error) {
395 error.printStackTrace();
396 }
397 }
398
399 /** This class represents the visual component of the Language Manager. */
400 private class Control
401 extends JPanel {
402 /** The button to add a new language support. */
403 private JButton add = null;
404 /** The button to clear the current default language. */
405 private JButton clear_default = null;
406 /** The button to remove a supported language. */
407 private JButton remove = null;
408 /** The button to set the current language as the default one. */
409 private JButton set_default = null;
410 /** A combobox listing the available supported languages. */
411 private JComboBox selector = null;
412 /** A list of currently supported languages. */
413 private JList list = null;
414 /** A description of the language currently selected. */
415 private JTextArea description = null;
416 /** The text field showing the currently name of the default language. Non-editable. */
417 private JTextField default_language_value = null;
418 /** Constructor.
419 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.AddListener
420 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ClearDefaultListener
421 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.ListListener
422 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.RemoveListener
423 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SelectorListener
424 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.SetDefaultListener
425 * @see org.greenstone.gatherer.cdm.LanguageManager.Control.TranslateListener
426 */
427 public Control() {
428 super();
429 // Creation.
430 JPanel center_panel = new JPanel();
431
432 JLabel title_label = new JLabel(get("Title"));
433 title_label.setHorizontalAlignment(JLabel.CENTER);
434 title_label.setOpaque(true);
435
436 list = new JList(model);
437 list.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
438 list.setCellRenderer(new ListRenderer());
439
440 JPanel details_panel = new JPanel();
441
442 JPanel default_panel = new JPanel();
443
444 JLabel default_label = new JLabel(get("Default_Language"));
445 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
446 default_label.setPreferredSize(LABEL_SIZE);
447
448 if(default_language == null) {
449 default_language_value = new JTextField();
450 }
451 else {
452 default_language_value = new JTextField(default_language.toString());
453 }
454 default_language_value.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
455 default_language_value.setEditable(false);
456
457 JPanel control_panel = new JPanel();
458
459 JLabel selector_label = new JLabel(get("Selector"));
460 selector_label.setPreferredSize(LABEL_SIZE);
461
462 selector = new JComboBox(getLanguageCodes().toArray());
463 selector.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
464
465 JPanel button_panel = new JPanel();
466
467 add = new JButton(get("Add"));
468 add.setMnemonic(KeyEvent.VK_A);
469 if(selector.getSelectedItem() != null) {
470 add.setEnabled(true);
471 }
472 else {
473 add.setEnabled(false);
474 }
475
476 remove = new JButton(get("Remove"));
477 remove.setMnemonic(KeyEvent.VK_R);
478 remove.setEnabled(false);
479
480 clear_default = new JButton(get("Clear_Default"));
481 clear_default.setMnemonic(KeyEvent.VK_C);
482 clear_default.setEnabled(false);
483
484 set_default = new JButton(get("Set_Default"));
485 set_default.setMnemonic(KeyEvent.VK_S);
486 set_default.setEnabled(false);
487
488 // Set up and connect listeners.
489 add.addActionListener(new AddListener());
490 clear_default.addActionListener(new ClearDefaultListener());
491 remove.addActionListener(new RemoveListener());
492 selector.addActionListener(new SelectorListener());
493 set_default.addActionListener(new SetDefaultListener());
494 list.addListSelectionListener(new ListListener());
495 // Layout components.
496 default_panel.setBorder(BorderFactory.createRaisedBevelBorder());
497 default_panel.setLayout(new BorderLayout());
498 default_panel.add(default_label, BorderLayout.WEST);
499 default_panel.add(default_language_value, BorderLayout.CENTER);
500
501 control_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
502 control_panel.setLayout(new BorderLayout());
503 control_panel.add(selector_label, BorderLayout.WEST);
504 control_panel.add(selector, BorderLayout.CENTER);
505
506 details_panel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
507 details_panel.setLayout(new BorderLayout());
508 details_panel.add(default_panel, BorderLayout.CENTER);
509 details_panel.add(control_panel, BorderLayout.SOUTH);
510
511 center_panel.setLayout(new BorderLayout());
512 center_panel.add(title_label, BorderLayout.NORTH);
513 center_panel.add(new JScrollPane(list), BorderLayout.CENTER);
514 center_panel.add(details_panel, BorderLayout.SOUTH);
515
516 button_panel.setLayout(new GridLayout(2,2,5,5));
517 button_panel.add(add);
518 button_panel.add(remove);
519 button_panel.add(clear_default);
520 button_panel.add(set_default);
521
522 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
523 setLayout(new BorderLayout());
524 add(center_panel, BorderLayout.CENTER);
525 add(button_panel, BorderLayout.SOUTH);
526 }
527 /** Destructor.
528 */
529 public void destroy() {
530 }
531 /** Listens for actions apon the 'add' button in the LanguageManager controls, and if detected calls the add method of the manager with a newly created language. */
532 private class AddListener
533 implements ActionListener {
534 /** Add a new language support.
535 * @param event an ActionEvent
536 * @see org.greenstone.gatherer.cdm.Language
537 */
538 public void actionPerformed(ActionEvent event) {
539 Language language = (Language)selector.getSelectedItem();
540 if(language != null) {
541 addLanguage(new Language(language));
542 }
543 }
544 }
545 /** Listens for actions apon the 'clear default' button in the LanguageManager controls, and if detected calls the setDefault method of the manager with <i>null</i>. */
546 private class ClearDefaultListener
547 implements ActionListener {
548 /** Clear the default index.
549 * @param event An <strong>ActionEvent</strong>.
550 */
551 public void actionPerformed(ActionEvent event) {
552 setDefault(null);
553 clear_default.setEnabled(false);
554 default_language_value.setText("");
555 }
556 }
557 /** Listens for actions apon the 'remove' button in the LanguageManager controls, and if detected calls the remove method of the manager with the language selected for removal. */
558 private class RemoveListener
559 implements ActionListener {
560 /** Remove the currently selected language, if any.
561 * @param event An <strong>ActionEvent</strong>.
562 * @see org.greenstone.gatherer.cdm.Language
563 */
564 public void actionPerformed(ActionEvent event) {
565 if(!list.isSelectionEmpty()) {
566 removeLanguage((Language)list.getSelectedValue());
567 if(default_language == null) {
568 clear_default.setEnabled(false);
569 default_language_value.setText("");
570 }
571 }
572 }
573 }
574 /** Listens for selections wihtin the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
575 private class SelectorListener
576 implements ActionListener {
577 /** Enable or disable controls depeding on selection.
578 * @param event An <strong>ActionEvent</strong>.
579 */
580 public void actionPerformed(ActionEvent event) {
581 if(selector.getSelectedItem() != null) {
582 add.setEnabled(true);
583 //description.setText((String)known_languages.get(code));
584 }
585 else {
586 add.setEnabled(false);
587 //description.setText("");
588 }
589 }
590 }
591 /** Listens for actions apon the 'set default' button in the LanguageManager controls, and if detected calls the <i>setDefault()</i> method of the manager with the language selected for default. */
592 private class SetDefaultListener
593 implements ActionListener {
594 /** Set the default index to the one currently selected, if any.
595 * @param event An <strong>ActionEvent</strong>.
596 * @see org.greenstone.gatherer.cdm.Language
597 */
598 public void actionPerformed(ActionEvent event) {
599 if(!list.isSelectionEmpty()) {
600 setDefault((Language)list.getSelectedValue());
601 clear_default.setEnabled(true);
602 default_language_value.setText(default_language.toString());
603 }
604 }
605 }
606 /** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
607 private class ListListener
608 implements ListSelectionListener {
609 /** Enable or disable controls depending on the current list selection.
610 * @param event A <strong>ListSelectionEvent</strong>.
611 */
612 public void valueChanged(ListSelectionEvent event) {
613 if(list.isSelectionEmpty()) {
614 remove.setEnabled(false);
615 set_default.setEnabled(false);
616 }
617 else {
618 remove.setEnabled(true);
619 set_default.setEnabled(true);
620 }
621 refreshAppearance();
622 }
623 }
624 /** Our list cel renderer which renders the default cell just a little different. */
625 private class ListRenderer
626 extends DefaultListCellRenderer {
627 /** Method to produce the component used to display an entry in the list.
628 * @param list The <strong>JList</strong> the component will be placed in.
629 * @param value A value to be displayed for this component, as a <strong>Object</strong>.
630 * @param index The position in the list it will occupy as an <i>int</i>.
631 * @param isSelected Whether the user has currently selected this component, as a <i>boolean</i>.
632 * @param cellHasFocus Whether the component currently has focus, again as a <i>boolean</i>.
633 * @return A <strong>Component</strong> to be used as the entry in the list.
634 * @see org.greenstone.gatherer.cdm.Language
635 */
636 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
637 Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
638 Language language = (Language) value;
639 if(language.isDefault() && !isSelected) {
640 component.setBackground(Gatherer.config.getColor("coloring.workspace_selection_background", false));
641 }
642 if(component instanceof JLabel) {
643 ((JLabel)component).setOpaque(true);
644 }
645 return component;
646 }
647 }
648 }
649}
650
651
652
653
654
655
656
Note: See TracBrowser for help on using the repository browser.