source: trunk/gli/src/org/greenstone/gatherer/gui/MetadataValueTablePane.java@ 9888

Last change on this file since 9888 was 9856, checked in by mdewsnip, 19 years ago

Major changes to the metadata value table and tree in the Enrich pane. The metadata value table now allows direct editing in the table -- hopefully much more obvious to the user. Classes involved have been untangled and are much more re-usable. Special code for replacing metadata has been added, which uses a more direct and efficient method rather than removing then adding metadata as before. And many many minor tidy-ups.

  • Property svn:keywords set to Author Date Id Revision
File size: 15.1 KB
Line 
1/**
2 *############################################################################
3 * A component of the Greenstone Librarian Interface, part of the Greenstone
4 * digital library suite from the New Zealand Digital Library Project at the
5 * University of Waikato, New Zealand.
6 *
7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
8 *
9 * Copyright (C) 2005 New Zealand Digital Library Project
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *############################################################################
25 */
26
27package org.greenstone.gatherer.gui;
28
29
30import java.awt.*;
31import java.awt.event.*;
32import java.io.*;
33import javax.swing.*;
34import javax.swing.event.*;
35import javax.swing.table.*;
36import org.greenstone.gatherer.Configuration;
37import org.greenstone.gatherer.Dictionary;
38import org.greenstone.gatherer.collection.CollectionTreeNode;
39import org.greenstone.gatherer.metadata.MetadataChangedListener;
40import org.greenstone.gatherer.metadata.MetadataElement;
41import org.greenstone.gatherer.metadata.MetadataTools;
42import org.greenstone.gatherer.metadata.MetadataValue;
43import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
44import org.greenstone.gatherer.metadata.MetadataValueTableModel;
45import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
46import org.greenstone.gatherer.util.Utility;
47
48
49public class MetadataValueTablePane
50 extends JPanel
51{
52 private MetadataValueTable metadata_value_table = null;
53 /** Used to display either the MetadataValueTable (when files are selected) or a placeholder panel */
54 private CardLayout card_layout = null;
55 /** The name of the panel containing the metadata value table */
56 private String METADATA_VALUE_TABLE_CARD = "";
57 /** The name of the panel containing the "no metadata available" placeholder */
58 private String NO_METADATA_AVAILABLE_CARD = "No metadata available";
59 /** The name of the panel containing the "no files selected" placeholder */
60 private String NO_FILES_SELECTED_CARD = "No files selected";
61
62
63 public MetadataValueTablePane()
64 {
65 super();
66
67 metadata_value_table = new MetadataValueTable();
68
69 JScrollPane metadata_value_table_scroll = new JScrollPane(metadata_value_table);
70 metadata_value_table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false));
71 metadata_value_table_scroll.setOpaque(true);
72
73 JPanel metadata_value_table_pane = new JPanel();
74 metadata_value_table_pane.setLayout(new BorderLayout());
75 metadata_value_table_pane.add(metadata_value_table_scroll, BorderLayout.CENTER);
76
77 JLabel no_metadata_available_label = new JLabel();
78 no_metadata_available_label.setHorizontalAlignment(JLabel.CENTER);
79 no_metadata_available_label.setOpaque(false);
80 no_metadata_available_label.setVerticalAlignment(JLabel.CENTER);
81 Dictionary.registerText(no_metadata_available_label, "EnrichPane.No_Metadata");
82
83 JPanel no_metadata_available_pane = new JPanel();
84 no_metadata_available_pane.setLayout(new BorderLayout());
85 no_metadata_available_pane.add(no_metadata_available_label, BorderLayout.CENTER);
86
87 JLabel no_files_selected_label = new JLabel();
88 no_files_selected_label.setHorizontalAlignment(JLabel.CENTER);
89 no_files_selected_label.setOpaque(false);
90 no_files_selected_label.setVerticalAlignment(JLabel.CENTER);
91 Dictionary.registerText(no_files_selected_label, "EnrichPane.No_File");
92
93 JPanel no_files_selected_pane = new JPanel();
94 no_files_selected_pane.setLayout(new BorderLayout());
95 no_files_selected_pane.add(no_files_selected_label, BorderLayout.CENTER);
96
97 card_layout = new CardLayout();
98
99 this.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
100 this.setFont(Configuration.getFont("general.font", false));
101 this.setLayout(card_layout);
102 this.add(metadata_value_table_pane, METADATA_VALUE_TABLE_CARD);
103 this.add(no_metadata_available_pane, NO_METADATA_AVAILABLE_CARD);
104 this.add(no_files_selected_pane, NO_FILES_SELECTED_CARD);
105 }
106
107
108 public void addMetadataValueTableListSelectionListener(ListSelectionListener list_selection_listener)
109 {
110 metadata_value_table.getSelectionModel().addListSelectionListener(list_selection_listener);
111 }
112
113
114 public void addMetadataValueTableMouseListener(MouseListener mouse_listener)
115 {
116 metadata_value_table.addMouseListener(mouse_listener);
117 }
118
119
120 public void addMetadataValueTextFieldDocumentListener(DocumentListener document_listener)
121 {
122 metadata_value_table.getMetadataValueTextField().getDocument().addDocumentListener(document_listener);
123 }
124
125
126 public void addMetadataValueTextFieldKeyListener(KeyListener key_listener)
127 {
128 metadata_value_table.getMetadataValueTextField().addKeyListener(key_listener);
129 }
130
131
132 public MetadataValueTableEntry getSelectedMetadataValueTableEntry()
133 {
134 return metadata_value_table.getSelectedMetadataValueTableEntry();
135 }
136
137
138 public boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event)
139 {
140 return metadata_value_table.isMouseEventForInheritedMetadataValueTableColumn(mouse_event);
141 }
142
143
144 public void setMetadataValueTextFieldValue(String metadata_value_string)
145 {
146 metadata_value_table.setMetadataValueTextFieldValue(metadata_value_string);
147 }
148
149
150 public void stopEditingAndAddBlankRowForSelectedMetadataElement()
151 {
152 metadata_value_table.stopEditing();
153 metadata_value_table.addBlankRowForSelectedMetadataElement();
154 }
155
156
157 public void stopEditingAndRebuild(CollectionTreeNode[] file_nodes)
158 {
159 metadata_value_table.stopEditing();
160 metadata_value_table.rebuild(file_nodes);
161
162 // If no files are selected display the "no file selected" card
163 if (file_nodes == null) {
164 card_layout.show(this, NO_FILES_SELECTED_CARD);
165 }
166 // If the metadata value table is empty display the "no metadata available" card
167 else if (metadata_value_table.getRowCount() == 0) {
168 card_layout.show(this, NO_METADATA_AVAILABLE_CARD);
169 }
170 // Otherwise display the card with the metadata value table
171 else {
172 card_layout.show(this, METADATA_VALUE_TABLE_CARD);
173 }
174 }
175
176
177 private class MetadataValueTable
178 extends JTable
179 implements MetadataChangedListener
180 {
181 private int MINIMUM_TABLE_HEADER_SIZE = 15;
182
183 private MetadataValueTableModel metadata_value_table_model = null;
184 private JTextField metadata_value_text_field = new JTextField();
185
186
187 public MetadataValueTable()
188 {
189 // Create the model for the table
190 metadata_value_table_model = new MetadataValueTableModel();
191 setModel(metadata_value_table_model);
192
193 // We allow only one row in the table to be selected at a time
194 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
195
196 // We use our own editor for the value column so we have easy access to the underlying text field
197 setDefaultEditor(String.class, new DefaultCellEditor(metadata_value_text_field));
198
199 // We need to listen for double clicks on the text field to open the editor dialog
200 metadata_value_text_field.addMouseListener(new MetadataValueTextFieldMouseListener());
201
202 // We need to listen for key presses so we can catch Enter presses
203 addKeyListener(new MetadataValueTableKeyListener());
204
205 // We need to listen for metadata changes so we can rebuild the table
206 MetadataXMLFileManager.addMetadataChangedListener(this);
207
208 // We also have to ensure that the table column header hasn't gone on a severe Jenny Craig binge and has somehow lost 7/8th of its component size
209 JTableHeader table_header = getTableHeader();
210 Dimension table_header_preferred_size = table_header.getPreferredSize();
211 if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) {
212 table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE);
213 table_header.setPreferredSize(table_header_preferred_size);
214 }
215
216 // Set the size of the table columns: 2/7 for element, 5/7 for value (actual numbers don't matter)
217 TableColumnModel column_model = getColumnModel();
218 TableColumn inherited_column = column_model.getColumn(0);
219 inherited_column.setMinWidth(25);
220 inherited_column.setPreferredWidth(25);
221 inherited_column.setMaxWidth(25);
222 TableColumn element_column = column_model.getColumn(1);
223 element_column.setPreferredWidth(200);
224 TableColumn value_column = column_model.getColumn(2);
225 value_column.setPreferredWidth(500);
226
227 // Use our own renderer for the table cells
228 MetadataValueTableCellRenderer metadata_value_table_cell_renderer = new MetadataValueTableCellRenderer();
229 inherited_column.setCellRenderer(metadata_value_table_cell_renderer);
230 element_column.setCellRenderer(metadata_value_table_cell_renderer);
231 value_column.setCellRenderer(metadata_value_table_cell_renderer);
232 }
233
234
235 private void addBlankRowForSelectedMetadataElement()
236 {
237 // Add a blank entry for the selected metadata element, then switch to it
238 MetadataElement selected_metadata_element = getSelectedMetadataValueTableEntry().getMetadataElement();
239 int blank_row = metadata_value_table_model.addBlankRowForMetadataElement(selected_metadata_element);
240 changeSelection(blank_row, 2, false, false);
241 }
242
243
244 private JTextField getMetadataValueTextField()
245 {
246 return metadata_value_text_field;
247 }
248
249
250 private MetadataValueTableEntry getSelectedMetadataValueTableEntry()
251 {
252 return metadata_value_table_model.getMetadataValueTableEntry(getSelectedRow());
253 }
254
255
256 private boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event)
257 {
258 return (columnAtPoint(mouse_event.getPoint()) == 0);
259 }
260
261
262 public void metadataChanged(CollectionTreeNode[] file_nodes)
263 {
264 rebuild(file_nodes);
265 }
266
267
268 private void rebuild(CollectionTreeNode[] file_nodes)
269 {
270 // Note the metadata value table entry currently selected
271 MetadataValueTableEntry selected_metadata_value_table_entry = getSelectedMetadataValueTableEntry();
272
273 // We don't want a lot of ListSelectionEvents while the table is rebuilding
274 clearSelection();
275
276 // Rebuild the metadata value table model
277 metadata_value_table_model.rebuild(file_nodes);
278
279 // Restore the metadata value table entry selection
280 if (selected_metadata_value_table_entry != null) {
281 int row_to_select = metadata_value_table_model.findMetadataValueTableEntryToSelect(selected_metadata_value_table_entry);
282 changeSelection(row_to_select, 2, false, false);
283 }
284 }
285
286
287 private void setMetadataValueTextFieldValue(String metadata_value_string)
288 {
289 metadata_value_text_field.setText(metadata_value_string);
290 metadata_value_text_field.requestFocus();
291 }
292
293
294 private void stopEditing()
295 {
296 // Save the current value in the text field, then remove the editor so it doesn't get saved again
297 TableCellEditor table_cell_editor = getCellEditor();
298 if (table_cell_editor != null) {
299 Object new_metadata_value = table_cell_editor.getCellEditorValue();
300 setValueAt(new_metadata_value, editingRow, editingColumn);
301 removeEditor();
302 }
303 }
304
305
306 private class MetadataValueTableCellRenderer
307 extends DefaultTableCellRenderer
308 {
309 /** Returns the default table cell renderer.
310 * @param table The <strong>JTable</strong>.
311 * @param value The value to assign to the cell at [row, column] as an <strong>Object</strong>.
312 * @param isSelected <i>true</i> if cell is selected.
313 * @param hasFocus <i>true</i> if cell has focus.
314 * @param row The row of the cell to render as an <i>int</i>.
315 * @param column The column of the cell to render as an <i>int</i>.
316 * @return The default table cell renderer <strong>Component</strong>.
317 */
318 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
319 {
320 JComponent component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
321
322 // First column: inherited metadata icon
323 if (column == 0 && value != null) {
324 component = new JLabel(Utility.getImage("upfolder.gif"));
325 }
326
327 // Make sure the focus always stay in the value cell of the selected row
328 if (column == 2 && isSelected) {
329 table.editCellAt(row, column);
330 if (table.isEditing()) {
331 table.getEditorComponent().requestFocus();
332 }
333 }
334
335 // Set up the component
336 component.setOpaque(true);
337
338 // Foreground
339 if (metadata_value_table_model.isCommon(row)) {
340 component.setForeground(Color.black);
341 }
342 else {
343 component.setForeground(Color.gray);
344 }
345
346 // Background
347 if (isSelected) {
348 component.setBackground(Configuration.getColor("coloring.workspace_heading_background", true));
349 }
350 else {
351 if (column < 2) {
352 component.setBackground(Configuration.getColor("coloring.collection_heading_background", true));
353 }
354 else {
355 component.setBackground(Configuration.getColor("coloring.collection_tree_background", true));
356 }
357 }
358
359 // The value column of cells never paints focus
360 if (column == 2) {
361 component.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
362 }
363
364 // We set a tooltip over the element column containing the definition of the element
365 if (value instanceof MetadataElement) {
366 String interface_language_code = Configuration.getLanguage();
367 String metadata_element_definition = MetadataTools.getMetadataElementAttribute((MetadataElement) value, "definition", interface_language_code, "en");
368 if (metadata_element_definition != null) {
369 component.setToolTipText(Utility.formatHTMLWidth(metadata_element_definition, 60));
370 }
371 }
372
373 return component;
374 }
375 }
376
377
378 private class MetadataValueTableKeyListener
379 extends KeyAdapter
380 {
381 /** Gives notification of key events on the text field */
382 public void keyPressed(KeyEvent key_event)
383 {
384 // Enter: save the current value then add a blank row for the selected metadata element
385 if (key_event.getKeyCode() == KeyEvent.VK_ENTER) {
386 // ...but not for extracted metadata elements of course
387 MetadataValueTableEntry metadata_value_table_entry = getSelectedMetadataValueTableEntry();
388 if (!metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement()) {
389 addBlankRowForSelectedMetadataElement();
390 }
391
392 // We do not want this event to be processed by the table also
393 key_event.consume();
394 }
395 }
396 }
397
398
399 private class MetadataValueTextFieldMouseListener
400 extends MouseAdapter
401 {
402 public void mouseClicked(MouseEvent mouse_event)
403 {
404 // Double-click: pop up an editor dialog for large metadata values
405 if (mouse_event.getClickCount() == 2) {
406 EditorDialog editor_dialog = new EditorDialog();
407 String new_metadata_value_string = editor_dialog.display(metadata_value_text_field.getText());
408 if (new_metadata_value_string != null) {
409 setMetadataValueTextFieldValue(new_metadata_value_string);
410 }
411 }
412 }
413 }
414 }
415}
Note: See TracBrowser for help on using the repository browser.