source: trunk/gli/src/org/greenstone/gatherer/cdm/TranslationView.java@ 4932

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

Major CDM rewrite so it uses DOM.

  • Property svn:keywords set to Author Date Id Revision
File size: 21.7 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.CollectionConfiguration;
38import org.greenstone.gatherer.cdm.CollectionDesignManager;
39import org.greenstone.gatherer.cdm.CollectionMeta;
40import org.greenstone.gatherer.cdm.CollectionMetaManager;
41import org.greenstone.gatherer.cdm.Control;
42import org.greenstone.gatherer.cdm.Index;
43import org.greenstone.gatherer.cdm.LanguageListCellRenderer;
44import org.greenstone.gatherer.cdm.LanguageManager;
45import org.greenstone.gatherer.cdm.SubcollectionIndex;
46
47/** 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.
48 * @author John Thompson, Greenstone Digital Library, University of Waikato
49 * @version 2.3
50 */
51public class TranslationView {
52
53 private Control controls;
54
55 static final private Dimension LABEL_SIZE = new Dimension(225,25);
56 static final private int LANGUAGE_WIDTH = 75;
57 static final private String GENERAL_STR = "General:";
58 static final private String INDEX_STR = "Index:";
59 static final private String PARTITION_STR = "Partitions:";
60
61 public TranslationView() {
62 Gatherer.println("TranslationView: Initialized.");
63 }
64
65 public void destroy() {
66 if(controls != null) {
67 controls.destroy();
68 controls = null;
69 }
70 }
71
72 public Control getControls() {
73 if(controls == null) {
74 controls = new TranslationControl();
75 }
76 return controls;
77 }
78
79 private String get(String key) {
80 if(key.indexOf(".") == -1) {
81 key = "CDM.TranslationManager." + key;
82 }
83 return Gatherer.dictionary.get(key);
84 }
85
86 private Object[] getFeaturesList() {
87 ArrayList features_model = new ArrayList();
88
89 // Add the indexes
90 ArrayList indexes = CollectionDesignManager.index_manager.getIndexes();
91 int indexes_size = indexes.size();
92 for(int j = 0; j < indexes_size; j++) {
93 Object bob = new BobTheMagicalComparableWrapper(indexes.get(j));
94 if(!features_model.contains(bob)) {
95 features_model.add(bob);
96 }
97 }
98
99 // We also add subindexes.
100 ArrayList subindexes = CollectionDesignManager.subcollectionindex_manager.getSubcollectionIndexes();
101 int subindexes_size = subindexes.size();
102 for(int j = 0; j < subindexes_size; j++) {
103 Object bob = new BobTheMagicalComparableWrapper(subindexes.get(j));
104 if(!features_model.contains(bob)) {
105 features_model.add(bob);
106 }
107 }
108
109 // Finally we add any remaining metadata as general
110 ArrayList general_metadata = CollectionDesignManager.collectionmeta_manager.getMetadata();
111 for(int i = 0; i < general_metadata.size(); i++) {
112 CollectionMeta metadata = (CollectionMeta) general_metadata.get(i);
113 if(!metadata.isSpecial()) {
114 Object bob = new BobTheMagicalComparableWrapper(metadata.getName());
115 if(!features_model.contains(bob)) {
116 features_model.add(bob);
117 }
118 }
119 }
120
121 Collections.sort(features_model);
122
123 return features_model.toArray();
124 }
125
126 private class BobTheMagicalComparableWrapper
127 implements Comparable {
128 private Object content;
129 private String text;
130 BobTheMagicalComparableWrapper(Object content) {
131 this.content = content;
132 }
133 public int compareTo(Object object) {
134 if(object == null) {
135 object = "";
136 }
137 if(text == null) {
138 toString();
139 }
140 return text.compareTo(object.toString());
141 }
142
143 /** Equals is used by contains and since we want to prevent double up of metadata we compare differently than in compareTo. */
144 public boolean equals(Object object) {
145 return (object != null && content.toString().equals(((BobTheMagicalComparableWrapper)object).getContent().toString()));
146 }
147
148 public Object getContent() {
149 return content;
150 }
151
152 public String getName() {
153 if(content instanceof Index) {
154 return CollectionConfiguration.STOP_CHARACTER + ((Index)content).getID();
155 }
156 else if (content instanceof SubcollectionIndex) {
157 return CollectionConfiguration.STOP_CHARACTER + ((SubcollectionIndex)content).getID();
158 }
159 else {
160 return content.toString();
161 }
162 }
163
164 public String toString() {
165 if(text == null) {
166 String temp = content.toString();
167 if(temp.indexOf(CollectionConfiguration.SPACE_CHARACTER) != -1) {
168 temp = temp.substring(0, temp.indexOf(CollectionConfiguration.SPACE_CHARACTER));
169 }
170 if(content instanceof Index) {
171 text = INDEX_STR + temp;
172 }
173 else if(content instanceof SubcollectionIndex) {
174 text = PARTITION_STR + temp;
175 }
176 else {
177 text = GENERAL_STR + temp;
178 }
179 }
180 return text;
181 }
182 }
183
184 private class TranslationControl
185 extends JPanel
186 implements Control {
187
188 private boolean ignore_event = false;
189 private FragmentTableModel fragment_table_model;
190 private JComboBox language_combobox;
191 private JList features_list;
192 private JTable fragment_table;
193 private JTextArea default_area;
194 private JTextArea translation_area;
195
196 TranslationControl() {
197 fragment_table_model = new FragmentTableModel(new ArrayList());
198 // Creation
199 JPanel header_panel = new JPanel();
200 JLabel title_label = new JLabel(get("Title"));
201 title_label.setHorizontalAlignment(JLabel.CENTER);
202 JTextArea instruction_area = new JTextArea(get("Instructions"));
203 instruction_area.setEditable(false);
204 instruction_area.setLineWrap(true);
205 instruction_area.setRows(3);
206 instruction_area.setWrapStyleWord(true);
207
208 JPanel center_panel = new JPanel();
209
210 JPanel selection_panel = new JPanel();
211
212 JPanel component_selection_panel = new JPanel();
213 JLabel component_label = new JLabel(get("Affected_Features"));
214 features_list = new JList(getFeaturesList());
215 features_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
216
217 JPanel fragment_selection_panel = new JPanel();
218 JLabel fragment_label = new JLabel(get("Assigned_Fragments"));
219
220 fragment_table = new JTable(fragment_table_model);
221 fragment_table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
222 fragment_table.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
223 fragment_table.setColumnSelectionAllowed(false);
224 fragment_table.setDefaultRenderer(Object.class, new FragmentTableRenderer());
225 fragment_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
226
227 JScrollPane table_scroll = new JScrollPane(fragment_table);
228 table_scroll.getViewport().setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
229 table_scroll.setOpaque(true);
230
231 JPanel south_panel = new JPanel();
232
233 JPanel text_panel = new JPanel();
234
235 JPanel language_panel = new JPanel();
236 JLabel language_label = new JLabel(get("Language"));
237 language_label.setPreferredSize(LABEL_SIZE);
238 language_combobox = new JComboBox(CollectionDesignManager.language_manager.getLanguageCodes().toArray());
239 language_combobox.setRenderer(new LanguageListCellRenderer());
240
241 JPanel default_text_panel = new JPanel();
242 JLabel default_label = new JLabel(get("Default_Text"));
243 default_area = new JTextArea();
244 default_area.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
245 default_area.setEditable(false);
246 default_area.setLineWrap(true);
247 default_area.setWrapStyleWord(true);
248
249 JPanel translated_text_panel = new JPanel();
250 JLabel translation_label = new JLabel(get("Translation"));
251 translation_area = new JTextArea();
252 translation_area.setBackground(Gatherer.config.getColor("coloring.disabled", false));
253 translation_area.setEnabled(false);
254 translation_area.setLineWrap(true);
255 translation_area.setWrapStyleWord(true);
256
257 // Connection
258 language_combobox.addActionListener(new LanguageActionListener());
259 translation_area.getDocument().addDocumentListener(new TranslationDocumentListener());
260 features_list.addListSelectionListener(new FeaturesListSelectionListener());
261 fragment_table.getSelectionModel().addListSelectionListener(new FragmentListSelectionListener());
262 // Layout
263 header_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
264 header_panel.setLayout(new BorderLayout());
265 header_panel.add(title_label, BorderLayout.NORTH);
266 header_panel.add(new JScrollPane(instruction_area), BorderLayout.CENTER);
267
268 component_selection_panel.setLayout(new BorderLayout());
269 component_selection_panel.add(component_label, BorderLayout.NORTH);
270 component_selection_panel.add(new JScrollPane(features_list), BorderLayout.CENTER);
271
272 fragment_selection_panel.setLayout(new BorderLayout());
273 fragment_selection_panel.add(fragment_label, BorderLayout.NORTH);
274 fragment_selection_panel.add(table_scroll, BorderLayout.CENTER);
275
276 selection_panel.setLayout(new GridLayout(2,1,0,5));
277 selection_panel.add(component_selection_panel);
278 selection_panel.add(fragment_selection_panel);
279
280 default_text_panel.setLayout(new BorderLayout());
281 default_text_panel.add(default_label, BorderLayout.NORTH);
282 default_text_panel.add(new JScrollPane(default_area), BorderLayout.CENTER);
283
284 translated_text_panel.setLayout(new BorderLayout());
285 translated_text_panel.add(translation_label, BorderLayout.NORTH);
286 translated_text_panel.add(new JScrollPane(translation_area), BorderLayout.CENTER);
287
288 text_panel.setLayout(new GridLayout(1,2,5,0));
289 text_panel.add(default_text_panel);
290 text_panel.add(translated_text_panel);
291
292 language_panel.setLayout(new BorderLayout());
293 language_panel.add(language_label, BorderLayout.WEST);
294 language_panel.add(language_combobox, BorderLayout.CENTER);
295
296 south_panel.setLayout(new BorderLayout());
297 south_panel.add(language_panel, BorderLayout.NORTH);
298 south_panel.add(text_panel, BorderLayout.CENTER);
299
300 center_panel.setLayout(new GridLayout(2,1,0,5));
301 center_panel.add(selection_panel);
302 center_panel.add(south_panel);
303
304 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
305 setLayout(new BorderLayout());
306 add(header_panel, BorderLayout.NORTH);
307 add(center_panel, BorderLayout.CENTER);
308 }
309
310 public void destroy() {
311 }
312
313 public void gainFocus() {
314 // Rebuild the features model, just incase features have been added or removed.
315 if(features_list != null) {
316 Object selected_feature = features_list.getSelectedValue();
317 features_list.setListData(getFeaturesList());
318 if(selected_feature != null) {
319 features_list.setSelectedValue(selected_feature, true);
320 }
321 }
322 }
323
324 public void loseFocus() {
325 }
326
327 private class FeaturesListSelectionListener
328 implements ListSelectionListener {
329 public void valueChanged(ListSelectionEvent event) {
330 if(!event.getValueIsAdjusting()) {
331 if(!ignore_event) { // And it shouldn't ever be.
332 ignore_event = true;
333 ///ystem.err.println("FeaturesListSelectionListener");
334 if(!features_list.isSelectionEmpty()) {
335 // Determine the features name. Remember to remove our helpful source prefix (delimited by ':').
336 BobTheMagicalComparableWrapper selected_feature = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
337 // Retrieve the default language translation, or otherwise the first match, to be default text.
338 CollectionMeta default_metadata = CollectionDesignManager.collectionmeta_manager.getMetadatum(selected_feature.getName());
339 if(default_metadata != null) {
340 default_area.setText(default_metadata.getValue());
341 }
342 // Update the text fragment table.
343 fragment_table.clearSelection();
344 fragment_table_model.setData(CollectionDesignManager.collectionmeta_manager.getMetadata(selected_feature.getName()));
345 selected_feature = null;
346 // Now we check whatever value is currently selected in the combobox to see if it is valid to add.
347 String language_name = (String) language_combobox.getSelectedItem();
348 int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
349 if(index != -1) {
350 CollectionMeta metadata = fragment_table_model.getMetadata(index);
351 fragment_table.setRowSelectionInterval(index, index);
352 translation_area.setText(metadata.getValue());
353 metadata = null;
354 }
355 else {
356 translation_area.setText("");
357 }
358 // Update and enable the text area
359 translation_area.setEnabled(true);
360 translation_area.setBackground(Gatherer.config.getColor("coloring.editable", false));
361 }
362 else {
363 default_area.setText("");
364 fragment_table.clearSelection();
365 fragment_table_model.setData(new ArrayList());
366 translation_area.setText("");
367 // Update and disable the text area
368 translation_area.setText("");
369 translation_area.setEnabled(false);
370 translation_area.setBackground(Gatherer.config.getColor("coloring.disabled", false));
371 }
372 ignore_event = false;
373 }
374 }
375 }
376 }
377
378 private class FragmentListSelectionListener
379 implements ListSelectionListener {
380 public void valueChanged(ListSelectionEvent event) {
381 if(!event.getValueIsAdjusting() && !ignore_event) {
382 ignore_event = true;
383 ///ystem.err.println("FragmentListSelectionListener");
384 int index = -1;
385 if((index = fragment_table.getSelectedRow()) != -1) {
386 // A row has been selected. Retrieve the collection metadata.
387 CollectionMeta metadata = fragment_table_model.getMetadata(index);
388 if(metadata != null) {
389 // Update the combobox to show the current language.
390 String language = metadata.getLanguage();
391 ///ystem.err.println("Searching for the language: " + language_name);
392 for(int i = 0; i < language_combobox.getItemCount(); i++) {
393 if(language_combobox.getItemAt(i).toString().equals(language)) {
394 language_combobox.setSelectedIndex(i);
395 }
396 }
397 }
398 translation_area.setText(metadata.getValue());
399 }
400 else {
401 translation_area.setText("");
402 }
403 ignore_event = false;
404 }
405 }
406 }
407
408 private class FragmentTableModel
409 extends AbstractTableModel {
410
411 private ArrayList metadata;
412
413 FragmentTableModel(ArrayList metadata) {
414 this.metadata = metadata;
415 }
416 public int getRowCount() {
417 return metadata.size();
418 }
419 public int getColumnCount() {
420 return 2;
421 }
422 public String getColumnName(int column) {
423 return get("Column_Name_" + column);
424 }
425
426 public CollectionMeta getMetadata(int row) {
427 if(0 <= row && row < metadata.size()) {
428 return (CollectionMeta) metadata.get(row);
429 }
430 return null;
431 }
432
433 public int getMetadataIndexByLanguage(String language) {
434 for(int i = 0; i < metadata.size(); i++) {
435 CollectionMeta metadatum = (CollectionMeta) metadata.get(i);
436 if(language.equals(metadatum.getLanguage())) {
437 return i;
438 }
439 }
440 return -1;
441 }
442
443 public Object getValueAt(int row, int column) {
444 if(0 <= row && row < metadata.size()) {
445 CollectionMeta metadatum = (CollectionMeta) metadata.get(row);
446 switch(column) {
447 case 0:
448 return metadatum.getLanguage();
449 default:
450 return metadatum.getValue();
451 }
452 }
453 return "#Error";
454 }
455
456 public void remove(int index) {
457 metadata.remove(index);
458 fireTableRowsDeleted(index, index);
459 }
460
461 public void setData(ArrayList metadata) {
462 this.metadata = metadata;
463 fireTableDataChanged();
464 }
465
466 public int size() {
467 return metadata.size();
468 }
469 }
470
471 private class FragmentTableRenderer
472 extends DefaultTableCellRenderer {
473 /** Retrieve the component used to rubberstamp the table based on the given parameters.
474 * @param table The <strong>JTable</strong> to rendered.
475 * @param value The <strong>Object</strong> whose representation will be shown in the table row.
476 * @param isSelected <i>true</i> iff the column/row is selected.
477 * @param hasFocus <i>true</i> iff the column/row is in focus.
478 * @param row An <i>int</i> specifying the target row.
479 * @param column An <i>int</i> specifying the target column.
480 * @see org.greenstone.gatherer.cdm.Language
481 */
482 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
483 JComponent component = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
484 if(isSelected) {
485 component.setBackground(Gatherer.config.getColor("coloring.workspace_heading_background", false));
486 }
487 else {
488 component.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
489 }
490 return component;
491 }
492 }
493
494 private class LanguageActionListener
495 implements ActionListener {
496 public void actionPerformed(ActionEvent event) {
497 if(!ignore_event) {
498 ignore_event = true;
499 ///ystem.err.println("LanguageActionListener");
500 // 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.
501 String language_name = language_combobox.getSelectedItem().toString();
502 int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
503 if(index != -1) {
504 CollectionMeta metadata = fragment_table_model.getMetadata(index);
505 fragment_table.setRowSelectionInterval(index, index);
506 translation_area.setText(metadata.getValue());
507 }
508 else {
509 fragment_table.clearSelection();
510 translation_area.setText("");
511 }
512 // Ready the text area
513 translation_area.setEnabled(true);
514 translation_area.setBackground(Gatherer.config.getColor("coloring.editable", false));
515 ignore_event = false;
516 }
517 }
518 }
519
520 private class TranslationDocumentListener
521 implements DocumentListener {
522 /** Gives notification that an attribute or set of attributes changed. */
523 public void changedUpdate(DocumentEvent e) {
524 update();
525 }
526 /** Gives notification that there was an insert into the document. */
527 public void insertUpdate(DocumentEvent e) {
528 update();
529 }
530 /** Gives notification that a portion of the document has been removed. */
531 public void removeUpdate(DocumentEvent e) {
532 update();
533 }
534 /** 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. */
535 private void update() {
536 if(!ignore_event) {
537 ignore_event = true;
538 String translation_text = translation_area.getText();
539 // 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.
540 int index = -1;
541 if((index = fragment_table.getSelectedRow()) == -1 && translation_text.length() > 0) {
542 BobTheMagicalComparableWrapper selected_feature = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
543 String language = (String) language_combobox.getSelectedItem();
544 CollectionMeta metadatum = new CollectionMeta(selected_feature.getName(), language);
545 metadatum.setValue(translation_text);
546 CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
547 fragment_table.clearSelection();
548 ArrayList metadata = CollectionDesignManager.collectionmeta_manager.getMetadata(selected_feature.getName());
549 fragment_table_model.setData(metadata);
550 index = fragment_table_model.getMetadataIndexByLanguage(language);
551 fragment_table.setRowSelectionInterval(index, index);
552 metadatum = null;
553 language = null;
554 selected_feature = null;
555 }
556 else {
557 CollectionMeta metadata = fragment_table_model.getMetadata(index);
558 // If the text is now empty, and there was previously a metadata fragment selected, then remove the fragments metadata and update the table
559 if(translation_text.length() == 0) {
560 ///ystem.err.println("Removing collectionmeta! fireTableRowsDeleted(" + index + "," + index + ")");
561 CollectionDesignManager.collectionmeta_manager.removeMetadata(metadata);
562 fragment_table_model.remove(index);
563 }
564 // Otherwise update the fragment metadata and ask the table to repaint the appropriate row
565 else {
566 ///ystem.err.println("Updating collectionmeta!");
567 metadata.setValue(translation_text);
568 fragment_table_model.fireTableRowsUpdated(index, index);
569 }
570 metadata = null;
571 }
572 translation_text = null;
573 ignore_event = false;
574 }
575 }
576 }
577 }
578
579}
580
581
Note: See TracBrowser for help on using the repository browser.