/** *############################################################################ * A component of the Greenstone Librarian Interface, part of the Greenstone * digital library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ * * Copyright (C) 2005 New Zealand Digital Library Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *############################################################################ */ package org.greenstone.gatherer.gui; import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.table.*; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.Dictionary; import org.greenstone.gatherer.collection.CollectionTreeNode; import org.greenstone.gatherer.metadata.MetadataChangedListener; import org.greenstone.gatherer.metadata.MetadataElement; import org.greenstone.gatherer.metadata.MetadataTools; import org.greenstone.gatherer.metadata.MetadataValue; import org.greenstone.gatherer.metadata.MetadataValueTableEntry; import org.greenstone.gatherer.metadata.MetadataValueTableModel; import org.greenstone.gatherer.metadata.MetadataXMLFileManager; import org.greenstone.gatherer.util.JarTools; import org.greenstone.gatherer.util.Utility; public class MetadataValueTablePane extends JPanel { private MetadataValueTable metadata_value_table = null; /** Used to display either the MetadataValueTable (when files are selected) or a placeholder panel */ private CardLayout card_layout = null; /** The name of the panel containing the metadata value table */ private String METADATA_VALUE_TABLE_CARD = ""; /** The name of the panel containing the "no metadata available" placeholder */ private String NO_METADATA_AVAILABLE_CARD = "No metadata available"; /** The name of the panel containing the "no files selected" placeholder */ private String NO_FILES_SELECTED_CARD = "No files selected"; public MetadataValueTablePane() { super(); metadata_value_table = new MetadataValueTable(); JScrollPane metadata_value_table_scroll = new JScrollPane(metadata_value_table); metadata_value_table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false)); metadata_value_table_scroll.setOpaque(true); JPanel metadata_value_table_pane = new JPanel(); metadata_value_table_pane.setLayout(new BorderLayout()); metadata_value_table_pane.add(metadata_value_table_scroll, BorderLayout.CENTER); JLabel no_metadata_available_label = new JLabel(Dictionary.get("EnrichPane.No_Metadata")); no_metadata_available_label.setHorizontalAlignment(JLabel.CENTER); no_metadata_available_label.setOpaque(false); no_metadata_available_label.setVerticalAlignment(JLabel.CENTER); JPanel no_metadata_available_pane = new JPanel(); no_metadata_available_pane.setLayout(new BorderLayout()); no_metadata_available_pane.add(no_metadata_available_label, BorderLayout.CENTER); JLabel no_files_selected_label = new JLabel(Dictionary.get("EnrichPane.No_File")); no_files_selected_label.setHorizontalAlignment(JLabel.CENTER); no_files_selected_label.setOpaque(false); no_files_selected_label.setVerticalAlignment(JLabel.CENTER); JPanel no_files_selected_pane = new JPanel(); no_files_selected_pane.setLayout(new BorderLayout()); no_files_selected_pane.add(no_files_selected_label, BorderLayout.CENTER); card_layout = new CardLayout(); this.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); this.setFont(Configuration.getFont("general.font", false)); this.setLayout(card_layout); this.add(metadata_value_table_pane, METADATA_VALUE_TABLE_CARD); this.add(no_metadata_available_pane, NO_METADATA_AVAILABLE_CARD); this.add(no_files_selected_pane, NO_FILES_SELECTED_CARD); } public void addMetadataValueTableListSelectionListener(ListSelectionListener list_selection_listener) { metadata_value_table.getSelectionModel().addListSelectionListener(list_selection_listener); } public void addMetadataValueTableMouseListener(MouseListener mouse_listener) { metadata_value_table.addMouseListener(mouse_listener); } public void addMetadataValueTextFieldDocumentListener(DocumentListener document_listener) { metadata_value_table.getMetadataValueTextField().getDocument().addDocumentListener(document_listener); } public void addMetadataValueTextFieldKeyListener(KeyListener key_listener) { metadata_value_table.getMetadataValueTextField().addKeyListener(key_listener); } public MetadataValueTableEntry getSelectedMetadataValueTableEntry() { return metadata_value_table.getSelectedMetadataValueTableEntry(); } public boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event) { return metadata_value_table.isMouseEventForInheritedMetadataValueTableColumn(mouse_event); } public void setMetadataValueTextFieldValue(String metadata_value_string) { metadata_value_table.setMetadataValueTextFieldValue(metadata_value_string); } public void stopEditingAndAddBlankRowForSelectedMetadataElement() { metadata_value_table.stopEditing(); metadata_value_table.addBlankRowForSelectedMetadataElement(); } public void stopEditingAndRebuild(CollectionTreeNode[] file_nodes) { metadata_value_table.stopEditing(); metadata_value_table.rebuild(file_nodes); // If no files are selected display the "no file selected" card if (file_nodes == null) { card_layout.show(this, NO_FILES_SELECTED_CARD); } // If the metadata value table is empty display the "no metadata available" card else if (metadata_value_table.getRowCount() == 0) { card_layout.show(this, NO_METADATA_AVAILABLE_CARD); } // Otherwise display the card with the metadata value table else { card_layout.show(this, METADATA_VALUE_TABLE_CARD); } } private class MetadataValueTable extends JTable implements MetadataChangedListener { private int MINIMUM_TABLE_HEADER_SIZE = 15; private MetadataValueTableModel metadata_value_table_model = null; private JTextField metadata_value_text_field = new JTextField(); public MetadataValueTable() { // Create the model for the table metadata_value_table_model = new MetadataValueTableModel(); setModel(metadata_value_table_model); // We allow only one row in the table to be selected at a time setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // We use our own editor for the value column so we have easy access to the underlying text field setDefaultEditor(String.class, new DefaultCellEditor(metadata_value_text_field)); // We need to listen for double clicks on the text field to open the editor dialog metadata_value_text_field.addMouseListener(new MetadataValueTextFieldMouseListener()); metadata_value_text_field.setBorder(null); // We need to listen for key presses so we can catch Enter presses addKeyListener(new MetadataValueTableKeyListener()); // We need to listen for metadata changes so we can rebuild the table MetadataXMLFileManager.addMetadataChangedListener(this); // 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 JTableHeader table_header = getTableHeader(); Dimension table_header_preferred_size = table_header.getPreferredSize(); if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) { table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE); table_header.setPreferredSize(table_header_preferred_size); } // Set the size of the table columns: 2/7 for element, 5/7 for value (actual numbers don't matter) TableColumnModel column_model = getColumnModel(); TableColumn inherited_column = column_model.getColumn(0); inherited_column.setMinWidth(25); inherited_column.setPreferredWidth(25); inherited_column.setMaxWidth(25); TableColumn element_column = column_model.getColumn(1); element_column.setPreferredWidth(200); TableColumn value_column = column_model.getColumn(2); value_column.setPreferredWidth(500); // Use our own renderer for the table cells MetadataValueTableCellRenderer metadata_value_table_cell_renderer = new MetadataValueTableCellRenderer(); inherited_column.setCellRenderer(metadata_value_table_cell_renderer); element_column.setCellRenderer(metadata_value_table_cell_renderer); value_column.setCellRenderer(metadata_value_table_cell_renderer); } private void addBlankRowForSelectedMetadataElement() { // Add a blank entry for the selected metadata element, then switch to it MetadataElement selected_metadata_element = getSelectedMetadataValueTableEntry().getMetadataElement(); int blank_row = metadata_value_table_model.addBlankRowForMetadataElement(selected_metadata_element); changeSelection(blank_row, 2, false, false); } private JTextField getMetadataValueTextField() { return metadata_value_text_field; } private MetadataValueTableEntry getSelectedMetadataValueTableEntry() { return metadata_value_table_model.getMetadataValueTableEntry(getSelectedRow()); } private boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event) { return (columnAtPoint(mouse_event.getPoint()) == 0); } public void metadataChanged(CollectionTreeNode[] file_nodes) { rebuild(file_nodes); } private void rebuild(CollectionTreeNode[] file_nodes) { // Note the metadata value table entry currently selected MetadataValueTableEntry selected_metadata_value_table_entry = getSelectedMetadataValueTableEntry(); // We don't want a lot of ListSelectionEvents while the table is rebuilding clearSelection(); // Rebuild the metadata value table model metadata_value_table_model.rebuild(file_nodes); // Restore the metadata value table entry selection if (selected_metadata_value_table_entry != null) { int row_to_select = metadata_value_table_model.findMetadataValueTableEntryToSelect(selected_metadata_value_table_entry); changeSelection(row_to_select, 2, false, false); } } private void setMetadataValueTextFieldValue(String metadata_value_string) { metadata_value_text_field.setText(metadata_value_string); metadata_value_text_field.requestFocus(); } private void stopEditing() { // Save the current value in the text field, then remove the editor so it doesn't get saved again TableCellEditor table_cell_editor = getCellEditor(); if (table_cell_editor != null) { Object new_metadata_value = table_cell_editor.getCellEditorValue(); setValueAt(new_metadata_value, editingRow, editingColumn); removeEditor(); } } private class MetadataValueTableCellRenderer extends DefaultTableCellRenderer { /** Returns the default table cell renderer. * @param table The JTable. * @param value The value to assign to the cell at [row, column] as an Object. * @param isSelected true if cell is selected. * @param hasFocus true if cell has focus. * @param row The row of the cell to render as an int. * @param column The column of the cell to render as an int. * @return The default table cell renderer Component. */ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JComponent component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); int real_column = table.convertColumnIndexToModel(column); // First column: inherited metadata icon if (real_column == 0 && value != null) { component = new JLabel(JarTools.getImage("upfolder.gif")); component.setToolTipText(Dictionary.get("EnrichPane.InheritedMetadata_Tooltip")); } // Make sure the focus always stay in the value cell of the selected row if (real_column == 2 && isSelected) { table.editCellAt(row, column); if (table.isEditing()) { table.getEditorComponent().requestFocus(); } } // Set up the component component.setOpaque(true); // Foreground if (metadata_value_table_model.isCommon(row)) { component.setForeground(Color.black); } else { component.setForeground(Color.gray); } // Background if (isSelected) { component.setBackground(Configuration.getColor("coloring.workspace_heading_background", true)); } else { if (real_column < 2) { component.setBackground(Configuration.getColor("coloring.collection_heading_background", true)); } else { component.setBackground(Configuration.getColor("coloring.collection_tree_background", true)); } } // The value column of cells never paints focus if (real_column == 2) { component.setBorder(BorderFactory.createEmptyBorder(0,2,0,0)); } // We set a tooltip over the element column containing the definition of the element if (value instanceof MetadataElement) { String interface_language_code = Configuration.getLanguage(); String metadata_element_definition = MetadataTools.getMetadataElementAttribute((MetadataElement) value, "definition", interface_language_code, "en"); if (metadata_element_definition != null) { component.setToolTipText(Utility.formatHTMLWidth(metadata_element_definition, 60)); } } return component; } } private class MetadataValueTableKeyListener extends KeyAdapter { /** Gives notification of key events on the text field */ public void keyPressed(KeyEvent key_event) { // Enter: save the current value then add a blank row for the selected metadata element if (key_event.getKeyCode() == KeyEvent.VK_ENTER) { // ...but not for extracted metadata elements of course MetadataValueTableEntry metadata_value_table_entry = getSelectedMetadataValueTableEntry(); if (!metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement()) { addBlankRowForSelectedMetadataElement(); } // We do not want this event to be processed by the table also key_event.consume(); } } } private class MetadataValueTextFieldMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent mouse_event) { // Double-click: pop up an editor dialog for large metadata values if (mouse_event.getClickCount() == 2) { EditorDialog editor_dialog = new EditorDialog(); String new_metadata_value_string = editor_dialog.display(metadata_value_text_field.getText()); if (new_metadata_value_string != null) { setMetadataValueTextFieldValue(new_metadata_value_string); } } } } } }