/**
*############################################################################
* 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);
}
}
}
}
}
}