source: trunk/gli/src/org/greenstone/gatherer/cdm/TranslationManager.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: 20.4 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 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.util.*;
32import javax.swing.*;
33import javax.swing.event.*;
34import javax.swing.table.*;
35import org.greenstone.gatherer.Dictionary;
36import org.greenstone.gatherer.Gatherer;
37import org.greenstone.gatherer.cdm.CollectionDesignManager;
38import org.greenstone.gatherer.cdm.CollectionMeta;
39import org.greenstone.gatherer.cdm.CollectionMetaManager;
40import org.greenstone.gatherer.cdm.Language;
41import org.greenstone.gatherer.cdm.LanguageManager;
42
43/** 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.
44 * @author John Thompson, Greenstone Digital Library, University of Waikato
45 * @version 2.3
46 */
47public class TranslationManager {
48
49 private CollectionDesignManager manager;
50 private Control controls;
51
52 static final private Dimension LABEL_SIZE = new Dimension(225,25);
53 static final private int LANGUAGE_WIDTH = 75;
54 static final private String GENERAL_STR = "General:";
55 static final private String INDEX_STR = "Index:";
56 static final private String PARTITION_STR = "Partitions:";
57
58 TranslationManager(CollectionDesignManager manager) {
59 this.manager = manager;
60 }
61
62 public JPanel getControls() {
63 if(controls == null) {
64 controls = new Control();
65 }
66 return controls;
67 }
68
69 private String get(String key) {
70 if(key.indexOf(".") == -1) {
71 key = "CDM.TranslationManager." + key;
72 }
73 return Gatherer.dictionary.get(key);
74 }
75
76 private Object[] getFeaturesList() {
77 ArrayList features_model = new ArrayList();
78 for(int i = 0; i < manager.collectionmetadatum.size(); i++) {
79 CollectionMeta metadata = (CollectionMeta) manager.collectionmetadatum.get(i);
80 Object bob = new BobTheMagicalComparableWrapper(metadata.getName());
81 if(!features_model.contains(bob)) {
82 features_model.add(bob);
83 }
84 }
85 // We also add subindexes.
86 SubIndexes subindexes = manager.subcollections.getSubIndexes();
87 for(int j = 0; j < subindexes.size(); j++) {
88 Object bob = new BobTheMagicalComparableWrapper(subindexes.get(j));
89 if(!features_model.contains(bob)) {
90 features_model.add(bob);
91 }
92 }
93 Collections.sort(features_model);
94 return features_model.toArray();
95 }
96
97
98 private class BobTheMagicalComparableWrapper
99 implements Comparable {
100 private Object content;
101 private String text;
102 BobTheMagicalComparableWrapper(Object content) {
103 this.content = content;
104 }
105 public int compareTo(Object object) {
106 if(object == null) {
107 object = "";
108 }
109 if(text == null) {
110 toString();
111 }
112 return text.compareTo(object.toString());
113 }
114 public boolean equals(Object object) {
115 if(object == null) {
116 return false;
117 }
118 if(text == null) {
119 toString();
120 }
121 return text.equals(object.toString());
122 }
123 public Object getContent() {
124 return content;
125 }
126 public String toString() {
127 if(text == null) {
128 if(content instanceof Index) {
129 text = INDEX_STR + content.toString();
130 }
131 else if(content instanceof SubIndex) {
132 text = PARTITION_STR + content.toString();
133 }
134 else {
135 text = GENERAL_STR + content.toString();
136 }
137 }
138 return text;
139 }
140 }
141
142 private class Control
143 extends JPanel {
144
145 private boolean ignore_event = false;
146 private FragmentTableModel fragment_table_model;
147 private JComboBox language_combobox;
148 private JList features_list;
149 private JTable fragment_table;
150 private JTextArea default_area;
151 private JTextArea translation_area;
152
153 Control() {
154 fragment_table_model = new FragmentTableModel(new ArrayList());
155 // Creation
156 JPanel header_panel = new JPanel();
157 JLabel title_label = new JLabel(get("Title"));
158 title_label.setHorizontalAlignment(JLabel.CENTER);
159 JTextArea instruction_area = new JTextArea(get("Instructions"));
160 instruction_area.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
161 instruction_area.setEditable(false);
162 instruction_area.setLineWrap(true);
163 instruction_area.setRows(3);
164 instruction_area.setWrapStyleWord(true);
165
166 JPanel center_panel = new JPanel();
167
168 JPanel selection_panel = new JPanel();
169
170 JPanel component_selection_panel = new JPanel();
171 JLabel component_label = new JLabel(get("Affected_Features"));
172 features_list = new JList(getFeaturesList());
173 features_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
174
175 JPanel fragment_selection_panel = new JPanel();
176 JLabel fragment_label = new JLabel(get("Assigned_Fragments"));
177 fragment_table = new JTable(fragment_table_model);
178 fragment_table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
179 fragment_table.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
180 fragment_table.setColumnSelectionAllowed(false);
181 fragment_table.setDefaultRenderer(Object.class, new FragmentTableRenderer());
182 fragment_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
183 //TableColumnModel column_model = fragment_table.getColumnModel();
184 //TableColumn language_column = column_model.getColumn(0);
185 //language_column.setPreferredWidth(LANGUAGE_WIDTH);
186 //language_column = null;
187 //column_model = null;
188 //fragment_table.sizeColumnsToFit(0);
189
190 JPanel south_panel = new JPanel();
191
192 JPanel text_panel = new JPanel();
193
194 JPanel language_panel = new JPanel();
195 JLabel language_label = new JLabel(get("Language"));
196 language_label.setPreferredSize(LABEL_SIZE);
197 language_combobox = new JComboBox(manager.languages.getLanguageCodes().toArray());
198
199 JPanel default_text_panel = new JPanel();
200 JLabel default_label = new JLabel(get("Default_Text"));
201 default_area = new JTextArea();
202 default_area.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
203 default_area.setEditable(false);
204 default_area.setLineWrap(true);
205 default_area.setWrapStyleWord(true);
206
207 JPanel translated_text_panel = new JPanel();
208 JLabel translation_label = new JLabel(get("Translation"));
209 translation_area = new JTextArea();
210 translation_area.setBackground(Gatherer.config.getColor("coloring.disabled", false));
211 translation_area.setEnabled(false);
212 translation_area.setLineWrap(true);
213 translation_area.setWrapStyleWord(true);
214
215 // Connection
216 language_combobox.addActionListener(new LanguageActionListener());
217 translation_area.getDocument().addDocumentListener(new TranslationDocumentListener());
218 features_list.addListSelectionListener(new FeaturesListSelectionListener());
219 fragment_table.getSelectionModel().addListSelectionListener(new FragmentListSelectionListener());
220 // Layout
221 header_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
222 header_panel.setLayout(new BorderLayout());
223 header_panel.add(title_label, BorderLayout.NORTH);
224 header_panel.add(new JScrollPane(instruction_area), BorderLayout.CENTER);
225
226 component_selection_panel.setLayout(new BorderLayout());
227 component_selection_panel.add(component_label, BorderLayout.NORTH);
228 component_selection_panel.add(new JScrollPane(features_list), BorderLayout.CENTER);
229
230 fragment_selection_panel.setLayout(new BorderLayout());
231 fragment_selection_panel.add(fragment_label, BorderLayout.NORTH);
232 fragment_selection_panel.add(new JScrollPane(fragment_table), BorderLayout.CENTER);
233
234 selection_panel.setLayout(new GridLayout(2,1,0,5));
235 selection_panel.add(component_selection_panel);
236 selection_panel.add(fragment_selection_panel);
237
238 default_text_panel.setLayout(new BorderLayout());
239 default_text_panel.add(default_label, BorderLayout.NORTH);
240 default_text_panel.add(new JScrollPane(default_area), BorderLayout.CENTER);
241
242 translated_text_panel.setLayout(new BorderLayout());
243 translated_text_panel.add(translation_label, BorderLayout.NORTH);
244 translated_text_panel.add(new JScrollPane(translation_area), BorderLayout.CENTER);
245
246 text_panel.setLayout(new GridLayout(1,2,5,0));
247 text_panel.add(default_text_panel);
248 text_panel.add(translated_text_panel);
249
250 language_panel.setLayout(new BorderLayout());
251 language_panel.add(language_label, BorderLayout.WEST);
252 language_panel.add(language_combobox, BorderLayout.CENTER);
253
254 south_panel.setLayout(new BorderLayout());
255 south_panel.add(language_panel, BorderLayout.NORTH);
256 south_panel.add(text_panel, BorderLayout.CENTER);
257
258 center_panel.setLayout(new GridLayout(2,1,0,5));
259 center_panel.add(selection_panel);
260 center_panel.add(south_panel);
261
262 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
263 setLayout(new BorderLayout());
264 add(header_panel, BorderLayout.NORTH);
265 add(center_panel, BorderLayout.CENTER);
266 }
267
268 public void updateUI() {
269 // Rebuild the features model, just incase features have been added or removed.
270 if(features_list != null) {
271 Object selected_feature = features_list.getSelectedValue();
272 features_list.setListData(getFeaturesList());
273 if(selected_feature != null) {
274 features_list.setSelectedValue(selected_feature, true);
275 }
276 }
277 // Carry on.
278 super.updateUI();
279 }
280
281 private class FeaturesListSelectionListener
282 implements ListSelectionListener {
283 public void valueChanged(ListSelectionEvent event) {
284 if(!event.getValueIsAdjusting()) {
285 if(!ignore_event) { // And it shouldn't ever be.
286 ignore_event = true;
287 ///ystem.err.println("FeaturesListSelectionListener");
288 if(!features_list.isSelectionEmpty()) {
289 // Determine the features name. Remember to remove our helpful source prefix (delimited by ':').
290 BobTheMagicalComparableWrapper bob = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
291 Object selected_feature = bob.getContent();
292 bob = null;
293 // Retrieve the default language translation, or otherwise the first match, to be default text.
294 CollectionMeta default_metadata = manager.collectionmetadatum.getMetadata(selected_feature, manager.languages.getDefaultLanguage(), true);
295 if(default_metadata != null) {
296 default_area.setText(default_metadata.getValue());
297 }
298 // Update the text fragment table.
299 fragment_table.clearSelection();
300 fragment_table_model.setData(manager.collectionmetadatum.getMetadata(selected_feature));
301 selected_feature = null;
302 // Now we check whatever value is currently selected in the combobox to see if it is valid to add.
303 String language_name = language_combobox.getSelectedItem().toString();
304 int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
305 if(index != -1) {
306 CollectionMeta metadata = fragment_table_model.getMetadata(index);
307 fragment_table.setRowSelectionInterval(index, index);
308 translation_area.setText(metadata.getValue());
309 metadata = null;
310 }
311 else {
312 translation_area.setText("");
313 }
314 // Update and enable the text area
315 translation_area.setEnabled(true);
316 translation_area.setBackground(Gatherer.config.getColor("coloring.editable", false));
317 }
318 else {
319 default_area.setText("");
320 fragment_table.clearSelection();
321 fragment_table_model.setData(new ArrayList());
322 translation_area.setText("");
323 // Update and disable the text area
324 translation_area.setText("");
325 translation_area.setEnabled(false);
326 translation_area.setBackground(Gatherer.config.getColor("coloring.disabled", false));
327 }
328 ignore_event = false;
329 }
330 }
331 }
332 }
333
334 private class FragmentListSelectionListener
335 implements ListSelectionListener {
336 public void valueChanged(ListSelectionEvent event) {
337 if(!event.getValueIsAdjusting() && !ignore_event) {
338 ignore_event = true;
339 ///ystem.err.println("FragmentListSelectionListener");
340 int index = -1;
341 if((index = fragment_table.getSelectedRow()) != -1) {
342 // A row has been selected. Retrieve the collection metadata.
343 CollectionMeta metadata = fragment_table_model.getMetadata(index);
344 if(metadata != null) {
345 // Update the combobox to show the current language.
346 Language language = metadata.getLanguage();
347 String language_name = language.toString();
348 ///ystem.err.println("Searching for the language: " + language_name);
349 for(int i = 0; i < language_combobox.getItemCount(); i++) {
350 if(language_combobox.getItemAt(i).toString().equals(language_name)) {
351 language_combobox.setSelectedIndex(i);
352 }
353 }
354 }
355 translation_area.setText(metadata.getValue());
356 }
357 else {
358 translation_area.setText("");
359 }
360 ignore_event = false;
361 }
362 }
363 }
364
365 private class FragmentTableModel
366 extends AbstractTableModel {
367
368 private ArrayList metadatum;
369
370 FragmentTableModel(ArrayList metadatum) {
371 this.metadatum = metadatum;
372 }
373 public int getRowCount() {
374 return metadatum.size();
375 }
376 public int getColumnCount() {
377 return 2;
378 }
379 public String getColumnName(int column) {
380 return get("Column_Name_" + column);
381 }
382
383 public CollectionMeta getMetadata(int row) {
384 if(0 <= row && row < metadatum.size()) {
385 return (CollectionMeta) metadatum.get(row);
386 }
387 return null;
388 }
389
390 public int getMetadataIndexByLanguage(String language) {
391 for(int i = 0; i < metadatum.size(); i++) {
392 CollectionMeta metadata = (CollectionMeta) metadatum.get(i);
393 if(language.equals(metadata.getLanguage().toString())) {
394 return i;
395 }
396 }
397 return -1;
398 }
399
400 public Object getValueAt(int row, int column) {
401 if(0 <= row && row < metadatum.size()) {
402 CollectionMeta metadata = (CollectionMeta) metadatum.get(row);
403 switch(column) {
404 case 0:
405 return metadata.getLanguage();
406 default:
407 return metadata.getValue();
408 }
409 }
410 return "#Error";
411 }
412
413 public void remove(int index) {
414 metadatum.remove(index);
415 fireTableRowsDeleted(index, index);
416 }
417
418 public void setData(ArrayList metadatum) {
419 this.metadatum = metadatum;
420 fireTableDataChanged();
421 }
422 }
423
424 private class FragmentTableRenderer
425 extends DefaultTableCellRenderer {
426 /** Retrieve the component used to rubberstamp the table based on the given parameters.
427 * @param table The <strong>JTable</strong> to rendered.
428 * @param value The <strong>Object</strong> whose representation will be shown in the table row.
429 * @param isSelected <i>true</i> iff the column/row is selected.
430 * @param hasFocus <i>true</i> iff the column/row is in focus.
431 * @param row An <i>int</i> specifying the target row.
432 * @param column An <i>int</i> specifying the target column.
433 * @see org.greenstone.gatherer.cdm.Language
434 */
435 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
436 JComponent component = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
437 if(isSelected) {
438 component.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", false));
439 }
440 else {
441 component.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
442 }
443 return component;
444 }
445 }
446
447 private class LanguageActionListener
448 implements ActionListener {
449 public void actionPerformed(ActionEvent event) {
450 if(!ignore_event) {
451 ignore_event = true;
452 ///ystem.err.println("LanguageActionListener");
453 // If the newly selected language value already exists in the fragment table, and that row isn't the one selected, then select that row the text area.
454 String language_name = language_combobox.getSelectedItem().toString();
455 int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
456 if(index != -1) {
457 CollectionMeta metadata = fragment_table_model.getMetadata(index);
458 fragment_table.setRowSelectionInterval(index, index);
459 translation_area.setText(metadata.getValue());
460 }
461 else {
462 fragment_table.clearSelection();
463 translation_area.setText("");
464 }
465 // Ready the text area
466 translation_area.setEnabled(true);
467 translation_area.setBackground(Gatherer.config.getColor("coloring.editable", false));
468 ignore_event = false;
469 }
470 }
471 }
472
473 private class TranslationDocumentListener
474 implements DocumentListener {
475 /** Gives notification that an attribute or set of attributes changed. */
476 public void changedUpdate(DocumentEvent e) {
477 update();
478 }
479 /** Gives notification that there was an insert into the document. */
480 public void insertUpdate(DocumentEvent e) {
481 update();
482 }
483 /** Gives notification that a portion of the document has been removed. */
484 public void removeUpdate(DocumentEvent e) {
485 update();
486 }
487 /** The text area has changed in some way. Given that this can only happed when we are editing or adding a text fragment we better respond appropriately. */
488 private void update() {
489 if(!ignore_event) {
490 ignore_event = true;
491 String translation_text = translation_area.getText();
492 // If there is no current fragment table selection, but translation text is not an empty string, then this is a new fragment. Create new collection metadata, refresh the fragment table, then ensure that the new metadata is selected. Remember that it is the selected metadata to which changes will be applied.
493 int index = -1;
494 if((index = fragment_table.getSelectedRow()) == -1 && translation_text.length() > 0) {
495 ///ystem.err.println("Adding new collectionmeta!");
496 BobTheMagicalComparableWrapper bob = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
497 Object selected_feature = bob.getContent();
498 Language language = (Language) language_combobox.getSelectedItem();
499 CollectionMeta metadata = new CollectionMeta(manager, selected_feature, language, translation_text);
500 manager.collectionmetadatum.addMetadata(metadata);
501 fragment_table.clearSelection();
502 fragment_table_model.setData(manager.collectionmetadatum.getMetadata(selected_feature));
503 index = fragment_table_model.getMetadataIndexByLanguage(language.toString());
504 fragment_table.setRowSelectionInterval(index, index);
505 metadata = null;
506 language = null;
507 selected_feature = null;
508 }
509 else {
510 CollectionMeta metadata = fragment_table_model.getMetadata(index);
511 // If the text is now empty, and there was previously a metadata fragment selected, then remove the fragments metadata and update the table
512 if(translation_text.length() == 0) {
513 ///ystem.err.println("Removing collectionmeta! fireTableRowsDeleted(" + index + "," + index + ")");
514 manager.collectionmetadatum.removeMetadata(metadata);
515 fragment_table_model.remove(index);
516 }
517 // Otherwise update the fragment metadata and ask the table to repaint the appropriate row
518 else {
519 ///ystem.err.println("Updating collectionmeta!");
520 metadata.setValue(translation_text);
521 fragment_table_model.fireTableRowsUpdated(index, index);
522 }
523 metadata = null;
524 }
525 translation_text = null;
526 ignore_event = false;
527 }
528 }
529 }
530 }
531
532}
533
534
Note: See TracBrowser for help on using the repository browser.