source: trunk/gli/src/org/greenstone/gatherer/cdm/TranslationManager.java@ 4364

Last change on this file since 4364 was 4293, checked in by jmt12, 21 years ago

Initial revision

  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 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: 22/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.Font;
57import java.awt.GridLayout;
58import java.awt.Toolkit;
59import java.awt.event.ActionEvent;
60import java.awt.event.ActionListener;
61import java.awt.event.KeyAdapter;
62import java.awt.event.KeyEvent;
63import java.util.ArrayList;
64import java.util.Collections;
65import javax.swing.BorderFactory;
66import javax.swing.DefaultListModel;
67import javax.swing.ListSelectionModel;
68import javax.swing.JButton;
69import javax.swing.JCheckBox;
70import javax.swing.JDialog;
71import javax.swing.JLabel;
72import javax.swing.JList;
73import javax.swing.JPanel;
74import javax.swing.JScrollPane;
75import javax.swing.JTable;
76import javax.swing.JTextArea;
77import javax.swing.event.ListSelectionEvent;
78import javax.swing.event.ListSelectionListener;
79import javax.swing.table.AbstractTableModel;
80import javax.swing.table.DefaultTableCellRenderer;
81import javax.swing.table.TableColumn;
82import org.greenstone.gatherer.Gatherer;
83import org.greenstone.gatherer.cdm.CollectionDesignManager;
84import org.greenstone.gatherer.cdm.CollectionMeta;
85import org.greenstone.gatherer.cdm.CollectionMetaManager;
86import org.greenstone.gatherer.cdm.Language;
87import org.greenstone.gatherer.cdm.LanguageManager;
88/** This class provides a graphical interface to allow a user to quickly and conviently (ie all in one place) translate the text fragments associated with general metadata and indexes into each of the assigned languages in the collection. It should provide clear controls for the editing of these text fragments, plus clear indicate what languages still need further translation, which it will do through a combination of coloring and other visual indicators.
89* @author John Thompson, Greenstone Digital Library, University of Waikato
90* @version 2.3
91*/
92public class TranslationManager
93 extends JDialog {
94 /** A reference to our creator, the CollectionDesignManager. */
95 private CollectionDesignManager manager = null;
96 /** The currently selected collection metadata. */
97 private CollectionMeta current = null;
98 /** A listener for selection changes in the feature list. */
99 private FeatureListener features_listener = null;
100 /** A reference to the Gatherer, for access to the Dictionary and messaging purposes. */
101 private Gatherer gatherer = null;
102 /** The button used to close the translation dialog. */
103 private JButton close_button = null;
104 /** A reference to the dialog so that our inner classes can interact with it. */
105 private JDialog dialog = null;
106 /** The label denoting the features list. */
107 private JLabel features_label = null;
108 /** The label denoting the language table. */
109 private JLabel languages_label = null;
110 /** The label denoting the original text area. */
111 private JLabel original_label = null;
112 /** The label denoting the original language field */
113 private JLabel original_language_label = null;
114 /** The label denoting the translated text area. */
115 private JLabel translation_label = null;
116 /** The label denoting the translated language field. */
117 private JLabel translation_language_label = null;
118 /** A list of the various features that have collection metadata associated with them. */
119 private JList features_list = null;
120 /** The base panel. */
121 private JPanel content_pane = null;
122 /** The right panel. */
123 private JPanel control_pane = null;
124 /** The panel the features list is shown in. */
125 private JPanel features_pane = null;
126 /** The panel the languages table is shown in. */
127 private JPanel languages_pane = null;
128 /** The panel the original text is shown in. */
129 private JPanel original_pane = null;
130 /** The panel the original language field is shown in. */
131 private JPanel original_header_pane = null;
132 /** The panel the translation text is shown in. */
133 private JPanel translation_pane = null;
134 /** The panel the translation language field is shown in. */
135 private JPanel translation_header_pane = null;
136 /** The table used to show the languages supported by the collection. */
137 private JTable languages_table = null;
138 /** The text area displaying the original text (in the default language). */
139 private JTextArea original = null;
140 /** The text area displaying the translated text (in the selected language). */
141 private JTextArea translation = null;
142 /** The language currently selected. */
143 private Language current_language = null;
144 /** The proxy model to the language manager which serves as the basis for the table. */
145 private TableProxy languages_model = null;
146 /** The default size of the features list. */
147 static final private Dimension FEATURE_SIZE = new Dimension(200, 400);
148 /** The default size of the translation dialog. */
149 static final private Dimension SIZE = new Dimension(800, 450);
150 /** Constructor.
151 * @param gatherer A reference to the <strong>Gatherer</strong>.
152 * @param manager A reference to the <strong>CollectionDesignManager</strong>.
153 * @see org.greenstone.gatherer.Configuration
154 * @see org.greenstone.gatherer.cdm.CollectionMeta
155 * @see org.greenstone.gatherer.cdm.TranslationManager.TableProxy
156 */
157 public TranslationManager(Gatherer gatherer, CollectionDesignManager manager) {
158 super();
159 this.dialog = this;
160 this.gatherer = gatherer;
161 this.manager = manager;
162 this.languages_model = new TableProxy();
163 // Create the features model. Basically we want one string entry for each unique name in the metadata.
164 ArrayList features_model = new ArrayList();
165 for(int i = 0; i < manager.collectionmetadatum.size(); i++) {
166 CollectionMeta metadata = (CollectionMeta) manager.collectionmetadatum.get(i);
167 Object object = metadata.getName();
168 String name = null;
169 if(object instanceof Index) {
170 name = ((Index)object).toString(false);
171 }
172 else {
173 name = object.toString();
174 }
175 if(!features_model.contains(name)) {
176 features_model.add(name);
177 }
178 }
179 Collections.sort(features_model);
180 // Create components...
181 setModal(true);
182 setSize(SIZE);
183 close_button = new JButton(get("General.Close"));
184 content_pane = (JPanel) getContentPane();
185 control_pane = new JPanel();
186 features_label = new JLabel(get("Affected_Features"));
187 features_label.setHorizontalAlignment(JLabel.CENTER);
188 features_list = new JList(features_model.toArray());
189 features_listener = new FeatureListener();
190 features_pane = new JPanel();
191 features_pane.setPreferredSize(FEATURE_SIZE);
192 languages_table = new JTable(languages_model);
193 languages_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
194 languages_label = new JLabel(get("Assigned_Languages"));
195 languages_label.setHorizontalAlignment(JLabel.CENTER);
196 languages_pane = new JPanel();
197 original = new JTextArea();
198 original.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
199 original.setEditable(false);
200 original.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
201 original_header_pane = new JPanel();
202 original_label = new JLabel(get("Default_Text"));
203 original_label.setHorizontalAlignment(JLabel.CENTER);
204 original_language_label = new JLabel("");
205 original_pane = new JPanel();
206 translation = new JTextArea();
207 translation.setEnabled(false);
208 translation.setFont(new Font("Arial Unicode MS", Font.PLAIN, 10));
209 translation_header_pane = new JPanel();
210 translation_label = new JLabel(get("Translation"));
211 translation_label.setHorizontalAlignment(JLabel.CENTER);
212 translation_language_label = new JLabel("");
213 translation_pane = new JPanel();
214 // Add listeners...
215 close_button.addActionListener(new CloseListener());
216 translation.addKeyListener(new TranslationListener());
217 features_list.addListSelectionListener(features_listener);
218 features_list.addListSelectionListener(languages_model);
219 ListSelectionModel languages_selection_model = languages_table.getSelectionModel();
220 languages_selection_model.addListSelectionListener(new TableListener());
221 // Layout...
222 features_pane.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
223 features_pane.setLayout(new BorderLayout());
224 features_pane.add(features_label, BorderLayout.NORTH);
225 features_pane.add(new JScrollPane(features_list), BorderLayout.CENTER);
226 languages_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
227 languages_pane.setLayout(new BorderLayout());
228 languages_pane.add(languages_label, BorderLayout.NORTH);
229 languages_pane.add(new JScrollPane(languages_table), BorderLayout.CENTER);
230 original_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
231 original_header_pane.setLayout(new BorderLayout());
232 original_header_pane.add(original_label, BorderLayout.WEST);
233 original_header_pane.add(original_language_label, BorderLayout.EAST);
234 original_pane.setLayout(new BorderLayout());
235 original_pane.add(original_header_pane, BorderLayout.NORTH);
236 original_pane.add(new JScrollPane(original), BorderLayout.CENTER);
237 translation_header_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
238 translation_header_pane.setLayout(new BorderLayout());
239 translation_header_pane.add(translation_label, BorderLayout.WEST);
240 translation_header_pane.add(translation_language_label, BorderLayout.EAST);
241 translation_pane.setLayout(new BorderLayout());
242 translation_pane.add(translation_header_pane, BorderLayout.NORTH);
243 translation_pane.add(new JScrollPane(translation), BorderLayout.CENTER);
244 control_pane.setLayout(new GridLayout(3,1));
245 control_pane.add(languages_pane);
246 control_pane.add(original_pane);
247 control_pane.add(translation_pane);
248 content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
249 content_pane.setLayout(new BorderLayout());
250 content_pane.add(features_pane, BorderLayout.WEST);
251 content_pane.add(control_pane, BorderLayout.CENTER);
252 content_pane.add(close_button, BorderLayout.SOUTH);
253 // Display...
254 Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
255 for (int i = 0; i < languages_model.getColumnCount() - 1; i++) {
256 TableColumn column = languages_table.getColumnModel().getColumn(i);
257 column.setMinWidth(0);
258 column.setMaxWidth(screen_size.width);
259 column.setPreferredWidth((SIZE.width - FEATURE_SIZE.width) / 6);
260 }
261 setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
262 show();
263 }
264 /** Destructor
265 */
266 public void destroy() {
267 dialog = null;
268 }
269 /** Retrieve a phrase from the dictionary based on a certain key.
270 * @param key The search <strong>String</strong>.
271 * @return The matching phrase from the Dictionary as a <strong>String</strong>.
272 */
273 private String get(String key) {
274 return get(key, null);
275 }
276 /** Retrieve a phrase from the dictionary based on a certain key and certain arguments.
277 * @param key The search <strong>String</strong>.
278 * @param args A <strong>String[]</strong> used to complete and format the returned phrase.
279 * @return The matching phrase from the Dictionary as a <strong>String</strong>.
280 * @see org.greenstone.gatherer.Dictionary
281 * @see org.greenstone.gatherer.Gatherer
282 */
283 private String get(String key, String args[]) {
284 if(key.indexOf(".") == -1) {
285 key = "CDM.TranslationManager." + key;
286 }
287 return gatherer.dictionary.get(key, args);
288 }
289 /** Listens for actions apon the close button. */
290 private class CloseListener
291 implements ActionListener {
292 /** Closes the dialog. Any implementation of an ActionListener must include this method so we can be informed when an action has occured.
293 * @param event An <Strong>ActionEvent</strong> containing details about the action.
294 */
295 public void actionPerformed(ActionEvent event) {
296 dialog.dispose();
297 }
298 }
299 /** Listens to selections within the feature list. */
300 private class FeatureListener
301 implements ListSelectionListener {
302 /** Called whenever the selection changes in the registered list, which requires us to create a new TableProxy.
303 * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
304 * @see org.greenstone.gatherer.cdm.CollectionMeta
305 * @see org.greenstone.gatherer.cdm.Language
306 */
307 public void valueChanged(ListSelectionEvent event) {
308 // Try to find the default language value for this feature.
309 String name = (String) features_list.getSelectedValue();
310 Language language = manager.languages.getDefaultLanguage();
311 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(name, language, true);
312 if(metadata != null && metadata.getValue() != null && metadata.getValue().length() != 0) {
313 if(!metadata.getLanguage().equals(language)) {
314 original_label.setText(get("Existing_Text"));
315 }
316 else {
317 original_label.setText(get("Default_Text"));
318 }
319 original.setText(metadata.getValue());
320 original_language_label.setText(metadata.getLanguage().toString());
321 }
322 else {
323 original_label.setText(get("No_Text"));
324 original.setText("");
325 }
326 }
327 }
328 /** Listens for selections within the languages table. */
329 private class TableListener
330 implements ListSelectionListener {
331 /** Called whenever the selection changes in the registered list, which requires us to update several parts of the dialog.
332 * @param event A <strong>ListSelectionEvent</strong> containing more information about the list selection change.
333 * @see org.greenstone.gatherer.cdm.CollectionMeta
334 * @see org.greenstone.gatherer.cdm.Language
335 */
336 public void valueChanged(ListSelectionEvent event) {
337 if (event.getValueIsAdjusting()) return;
338 ListSelectionModel lsm = (ListSelectionModel)event.getSource();
339 if (!lsm.isSelectionEmpty()) {
340 int row = lsm.getMinSelectionIndex();
341 current = languages_model.getMetadata(row);
342 if(current != null) {
343 if (current.getValue() != null) {
344 translation.setText(current.getValue());
345 }
346 else {
347 translation.setText("");
348 }
349 current_language = current.getLanguage();
350 }
351 else {
352 current_language = (Language) languages_model.getValueAt(row, 1);
353 translation.setText("");
354 }
355 features_listener.valueChanged(null);
356 translation_language_label.setText(current_language.toString());
357 translation.setEnabled(true);
358 }
359 }
360 }
361 /** A AbstractTableModel extension based upon a vector of CollectionMeta, which can also listen to a list for selection changes. */
362 private class TableProxy
363 extends AbstractTableModel
364 implements ListSelectionListener {
365 /** Called when the contents of a cell changes.
366 */
367 public void cellChanged() {
368 fireTableDataChanged();
369 }
370 /** Returns the most specific superclass for all the cell values in the column.
371 * @param column An <i>int</i> specifying which columns class to be determined.
372 * @return The columns <strong>Class</strong>.
373 */
374 public Class getColumnClass(int column) {
375 return String.class;
376 }
377 /** Returns the number of columns in the model.
378 * @return An <i>int</i> specifying the number of columns.
379 */
380 public int getColumnCount() {
381 if(!features_list.isSelectionEmpty()) {
382 return 2;
383 }
384 return 0;
385 }
386 /** Returns the name of the column at columnIndex.
387 * @param column An <i>int</i> specifying the column whose name you are interesting in.
388 * @return The name of the column as a <strong>String</strong>.
389 */
390 public String getColumnName(int column) {
391 String name = null;
392 switch(column) {
393 case 0:
394 name = get("Language");
395 break;
396 case 1:
397 name = get("Text");
398 break;
399 }
400 return name;
401 }
402 /** Retrieve the collection metadata from the specified row.
403 * @param row An <i>int</i> indicating the row in question.
404 * @see org.greenstone.gatherer.cdm.Language
405 * @see org.greenstone.gatherer.cdm.LanguageManager
406 */
407 public CollectionMeta getMetadata(int row) {
408 String name = (String) features_list.getSelectedValue();
409 Language language = (Language) getValueAt(row, 0);
410 return manager.collectionmetadatum.getMetadata(name, language, false);
411 }
412 /** Returns the number of rows in the model.
413 * @return An <i>int</i> specifying the number of rows in the table, which is exactly the number of languages assigned to this collection.
414 * @see org.greenstone.gatherer.cdm.LanguageManager
415 */
416 public int getRowCount() {
417 return manager.languages.size();
418 }
419 /** Returns the value for the cell at column and row.
420 * @param row The desired row as an <i>int</i>.
421 * @param column The desired column as an <i>int</i>.
422 * @return The value at the row, column reference.
423 * @see org.greenstone.gatherer.cdm.CollectionMeta
424 * @see org.greenstone.gatherer.cdm.Language
425 * @see org.greenstone.gatherer.cdm.LanguageManager
426 */
427 public Object getValueAt(int row, int column) {
428 if(!features_list.isSelectionEmpty()) {
429 // First of all find the Language that matches the row and the current feature name, because in any case you'll need them.
430 Language language = (Language)manager.languages.get(row);
431 String feature_name = (String)features_list.getSelectedValue();
432 // Also try to locate the collection level metadata that matches.
433 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(feature_name, language, false);
434 // Now we do subtly different things depending on the column.
435 switch(column) {
436 case 0: // The Language. Easiest case.
437 return language;
438 case 1: // The value of the metadata. Needs us to retrieve the value for a certain feature and language.
439 if(metadata != null) {
440 return metadata.getValue();
441 }
442 }
443 // If all else fails, return an empty string and hope the class caster doesn't explode.
444 }
445 return "";
446 }
447 /** Returns true if the cell at row and column is editable.
448 * @param row The row of the cell as an <i>int</i>.
449 * @param column The column of the cell also as an <i>int</i>.
450 */
451 public boolean isCellEditable(int rowIndex, int columnIndex) {
452 return false;
453 }
454 /** Sets the value in the cell at columnIndex and rowIndex to aValue.
455 */
456 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
457 }
458 /** Any implementation of <i>ListSelectionListener</i> must include this method so we can be informed when the list selection has changed.
459 * @param event A <strong>ListSelectionEvent</strong> containing information about the selection change.
460 */
461 public void valueChanged(ListSelectionEvent event) {
462 fireTableStructureChanged();
463 }
464 }
465 /** This provides a custom renderer that colours the background of the default language cell green, and the foreground of currently unready metadata rows red. */
466 private class TableRenderer
467 extends DefaultTableCellRenderer {
468 /** Retrieve the component used to rubberstamp the table based on the given parameters.
469 * @param table The <strong>JTable</strong> to rendered.
470 * @param value The <strong>Object</strong> whose representation will be shown in the table row.
471 * @param isSelected <i>true</i> iff the column/row is selected.
472 * @param hasFocus <i>true</i> iff the column/row is in focus.
473 * @param row An <i>int</i> specifying the target row.
474 * @param column An <i>int</i> specifying the target column.
475 * @see org.greenstone.gatherer.cdm.Language
476 */
477 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
478 Component component = null;
479 // Create the component.
480 if(value instanceof String || value instanceof Language) {
481 JLabel label = new JLabel(value.toString());
482 label.setOpaque(true);
483 component = label;
484 }
485 else {
486 JCheckBox check = new JCheckBox("", ((Boolean)value).booleanValue());
487 JPanel pane = new JPanel(new BorderLayout());
488 pane.add(check, BorderLayout.CENTER);
489 component = pane;
490 }
491 // Check for default property
492 Language language = (Language)languages_model.getValueAt(row, 1);
493 if(language.isDefault()) {
494 if(isSelected) {
495 component.setBackground(Gatherer.config.getColor("coloring.collection_selection_background", false));
496 }
497 else {
498 component.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
499 }
500 }
501 else {
502 if(isSelected) {
503 component.setBackground(table.getSelectionBackground());
504 }
505 else {
506 component.setForeground(Color.white);
507 }
508 }
509 // Check for readiness
510 Boolean ready = (Boolean)languages_model.getValueAt(row, 0);
511 if(!ready.booleanValue()) {
512 component.setForeground(Color.red);
513 }
514 else {
515 component.setForeground(Color.black);
516 }
517 return component;
518 }
519 }
520 /** Listens for actions within the translation text field and immediately updates the collection metadata as necessary. */
521 private class TranslationListener
522 extends KeyAdapter {
523 /** This method is called when a key has been released, and is perfect for us to synchronize the contents of the translation field with the collection metadata associated with the selected feature and language.
524 * @param event A <strong>KeyEvent</strong> containing more detail about the key released.
525 * @see org.greenstone.gatherer.cdm.CollectionMeta
526 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
527 * @see org.greenstone.gatherer.cdm.Index
528 */
529 public void keyReleased(KeyEvent event) {
530 if(current == null) {
531 String name = (String)features_list.getSelectedValue();
532 Index index = manager.indexes.getIndex(name);
533 if(index == null) {
534 current = new CollectionMeta(manager, name, current_language, translation.getText());
535 }
536 else {
537 current = new CollectionMeta(manager, index, current_language, translation.getText());
538 }
539 manager.collectionmetadatum.addMetadata(current);
540 }
541 else {
542 current.update(current.getName(), current.getLanguage(), translation.getText());
543 }
544 languages_model.cellChanged();
545 }
546 }
547}
Note: See TracBrowser for help on using the repository browser.