/** *############################################################################ * 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 * Based on code by John Thompson * * 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 java.util.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.tree.*; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.DebugStream; import org.greenstone.gatherer.Dictionary; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.collection.CollectionTree; import org.greenstone.gatherer.collection.CollectionTreeNode; import org.greenstone.gatherer.gui.tree.DragTree; import org.greenstone.gatherer.metadata.MetadataElement; import org.greenstone.gatherer.metadata.MetadataValue; import org.greenstone.gatherer.metadata.MetadataValueTableEntry; import org.greenstone.gatherer.metadata.MetadataValueTreeNode; import org.greenstone.gatherer.metadata.MetadataXMLFileManager; /** Provides a view of controls for the editing of metadata. */ public class EnrichPane extends JPanel implements TreeSelectionListener { static private Dimension MINIMUM_SIZE = new Dimension(100, 100); static private Dimension COLLECTION_TREE_SIZE = new Dimension(250, 500); private boolean has_focus = false; /** The collection tree. */ private CollectionTree collection_tree = null; /** The currently reported selection. */ private CollectionTreeNode[] file_nodes = null; /** Used to dynamically filter the collection tree. */ private Filter collection_filter = null; /** The label at the top of the collection tree, which shows the collection name. */ private JLabel collection_label; /** The panel that contains the collection tree. */ private JPanel collection_pane = null; /** The scrollable area into which the collection tree is placed. */ private JScrollPane collection_scroll = null; /** The splitpane dividing the collection tree and the metadata editing controls. */ private JSplitPane external_split; /** The metadata value table shows the metadata values that are currently assigned to a file. */ private MetadataValueTablePane metadata_value_table_pane = null; /** The metadata value tree shows the metadata values that are currently assigned to a metadata element. */ private MetadataValueTreePane metadata_value_tree_pane = null; public EnrichPane() { // Create the metadata value tree pane metadata_value_tree_pane = new MetadataValueTreePane(); metadata_value_tree_pane.addMetadataValueTreeSelectionListener(new MetadataValueTreeSelectionListener()); // Create metadata value table pane metadata_value_table_pane = new MetadataValueTablePane(); metadata_value_table_pane.addMetadataValueTableListSelectionListener(new MetadataValueTableListSelectionListener()); metadata_value_table_pane.addMetadataValueTableMouseListener(new MetadataValueTableMouseListener()); metadata_value_table_pane.addMetadataValueTextFieldDocumentListener(new MetadataValueTextFieldDocumentListener()); metadata_value_table_pane.addMetadataValueTextFieldKeyListener(new MetadataValueTextFieldKeyListener()); } /** Some actions can only occur after this panel has been displayed on-screen, so this method is provided to do exactly that. Such actions include the proportioning of the split panes and the setting of table column widths. */ public void afterDisplay() { external_split.setDividerLocation(0.3); } /** Used to create, connect and layout the components to be shown on this control panel. * @see org.greenstone.gatherer.Gatherer * @see org.greenstone.gatherer.file.FileOpenActionListener * @see org.greenstone.gatherer.gui.Filter */ public void display() { JPanel left_hand_pane = new JPanel(new BorderLayout()); GLIButton metadata_set_button = new GLIButton(Dictionary.get("EnrichPane.ManageMetadataSets"), Dictionary.get("EnrichPane.ManageMetadataSets_Tooltip")); metadata_set_button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { MetadataSetDialog msd = new MetadataSetDialog(); if (msd.setsChanged()) { valueChanged(null); } } }); // Collection Tree collection_pane = new JPanel(new BorderLayout()); collection_pane.setMinimumSize(MINIMUM_SIZE); collection_pane.setPreferredSize(COLLECTION_TREE_SIZE); collection_label = new JLabel(Dictionary.get("Collection.No_Collection")); collection_label.setOpaque(true); collection_tree = Gatherer.c_man.getCollectionTree(); collection_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); collection_tree.addTreeSelectionListener(this); collection_filter = collection_tree.getFilter(); external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); // Layout collection_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3,3,3,3), BorderFactory.createLoweredBevelBorder())); collection_pane.setMinimumSize(MINIMUM_SIZE); collection_pane.setPreferredSize(new Dimension(Gatherer.g_man.getSize().width / 3, Gatherer.g_man.getSize().height)); // Collection Pane collection_pane.add(collection_label, BorderLayout.NORTH); JSplitPane metadata_editing_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); metadata_editing_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5)); metadata_editing_pane.setDividerSize(8); metadata_editing_pane.add(metadata_value_table_pane, JSplitPane.TOP); metadata_editing_pane.add(metadata_value_tree_pane, JSplitPane.BOTTOM); metadata_editing_pane.setDividerLocation(250); left_hand_pane.add(collection_pane, BorderLayout.CENTER); left_hand_pane.add(metadata_set_button, BorderLayout.SOUTH); external_split.add(left_hand_pane, JSplitPane.LEFT); external_split.add(metadata_editing_pane, JSplitPane.RIGHT); this.setLayout(new BorderLayout()); this.add(external_split, BorderLayout.CENTER); } /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab */ public void gainFocus() { // Remember that we currently have focus has_focus = true; // Add the collection tree and filter back into this pane collection_scroll = new JScrollPane(collection_tree); collection_pane.add(collection_scroll, BorderLayout.CENTER); collection_pane.add(collection_filter, BorderLayout.SOUTH); // Select the first node in the tree if nothing is already selected if (collection_tree.getSelectionPaths() == null && collection_tree.getRowCount() > 0) { collection_tree.setImmediate(true); collection_tree.setSelectionRow(0); collection_tree.setImmediate(false); return; } // Force all of the controls to be updated valueChanged(null); } /** Called to inform this pane that it has just lost focus as an effect of the user clicking on another tab */ public void loseFocus() { // Very important: make sure metadata value is saved before leaving the pane metadata_value_table_pane.stopEditingAndRebuild(file_nodes); // Make sure all the metadata has been saved to file MetadataXMLFileManager.saveMetadataXMLFiles(); // Remove the collection tree and filter from this pane so it can be added to the Gather pane collection_pane.remove(collection_scroll); collection_pane.remove(collection_filter); // Remember that we no longer have focus has_focus = false; } /** Called whenever the detail mode changes to ensure the filters are at an appropriate level (ie only editable by those that understand regular expression matching) * @param mode the mode level as an int */ public void modeChanged(int mode) { collection_filter.setEditable(mode > Configuration.LIBRARIAN_MODE); } /** Refresh this pane, depending on what has just happened (refresh_reason). */ public void refresh(int refresh_reason, boolean collection_loaded) { if (collection_loaded) { // Update collection label collection_label.setText(Dictionary.get("Collection.Collection")); collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false)); collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false)); // Update collection tree if (refresh_reason == Gatherer.COLLECTION_OPENED) { collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel()); } // Update collection filter collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false)); } else { // Update collection label collection_label.setText(Dictionary.get("Collection.No_Collection")); collection_label.setBackground(Color.lightGray); collection_label.setForeground(Color.black); // Update collection tree collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error"))); // Update collection filter collection_filter.setBackground(Color.lightGray); } // Enable or disable the controls collection_tree.setEnabled(collection_loaded); collection_filter.setEnabled(collection_loaded); // Force the metadata table to be rebuilt (for switching extracted metadata on or off) if (refresh_reason == Gatherer.PREFERENCES_CHANGED) { metadata_value_table_pane.stopEditingAndRebuild(file_nodes); } } /** Called whenever the collection tree selection changes. This causes the metadata value table to be rebuilt. */ public void valueChanged(TreeSelectionEvent event) { // If we haven't got focus then it must have been a selection in the Gather pane, so don't bother rebuilding if (has_focus == false) { return; } // Nothing selected in the collection tree if (collection_tree.getSelectionCount() == 0) { file_nodes = null; } // Some files selected in the collection tree else { TreePath paths[] = collection_tree.getSelectionPaths(); file_nodes = new CollectionTreeNode[paths.length]; for (int i = 0; i < paths.length; i++) { file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent(); } } // Update the metadata value table (and consequently, the metadata value tree) metadata_value_table_pane.stopEditingAndRebuild(file_nodes); } private class MetadataValueTableListSelectionListener implements ListSelectionListener { public void valueChanged(ListSelectionEvent list_selection_event) { // We only want to handle one event per selection, so wait for the value to stabilise if (list_selection_event.getValueIsAdjusting()) { return; } // Update the metadata value tree for the current table selection metadata_value_tree_pane.rebuild(metadata_value_table_pane.getSelectedMetadataValueTableEntry()); } } private class MetadataValueTableMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent mouse_event) { // We're only interested in clicks on the inherited column if (metadata_value_table_pane.isMouseEventForInheritedMetadataValueTableColumn(mouse_event) == false) { return; } // If the selected metadata is inherited, switch to the folder it came from MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table_pane.getSelectedMetadataValueTableEntry(); if (selected_metadata_value_table_entry.isInheritedMetadata()) { collection_tree.setSelection(selected_metadata_value_table_entry.getFolderMetadataInheritedFrom()); } } } private class MetadataValueTextFieldDocumentListener implements DocumentListener { /** Gives notification that an attribute or set of attributes changed */ public void changedUpdate(DocumentEvent document_event) { validate(document_event); } /** Gives notification that there was an insert into the document */ public void insertUpdate(DocumentEvent document_event) { validate(document_event); } /** Gives notification that a portion of the document has been removed */ public void removeUpdate(DocumentEvent document_event) { validate(document_event); } /** Ensures that the value tree is updated in response to changes in the value text field */ private void validate(DocumentEvent document_event) { try { Document document = document_event.getDocument(); String metadata_value_string = document.getText(0, document.getLength()); metadata_value_tree_pane.selectBestPathForMetadataValue(metadata_value_string); } catch (Exception exception) { DebugStream.printStackTrace(exception); } } } private class MetadataValueTextFieldKeyListener extends KeyAdapter { /** Gives notification of key events on the text field */ public void keyPressed(KeyEvent key_event) { // Tab: Auto-complete what is selected in the metadata value tree if (key_event.getKeyCode() == KeyEvent.VK_TAB) { MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode(); if (selected_metadata_value_tree_node != null) { metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue()); } // We do not want this event to be processed by the table also key_event.consume(); } // Enter: save the current value then add a blank row for the selected metadata element if (key_event.getKeyCode() == KeyEvent.VK_ENTER) { metadata_value_table_pane.stopEditingAndAddBlankRowForSelectedMetadataElement(); } } } private class MetadataValueTreeSelectionListener implements TreeSelectionListener { public void valueChanged(TreeSelectionEvent tree_selection_event) { // When a node is selected in the tree, fill the metadata value text field with the selected node's value MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode(); if (selected_metadata_value_tree_node != null) { metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue()); } } } }