/** *############################################################################ * 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) 2004 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.metadata; import java.awt.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; 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.CollectionTreeNode; import org.greenstone.gatherer.gui.WarningDialog; public class MetadataValueTableModel extends AbstractTableModel { /** It is not expected that this class will ever be serialized */ private static final long serialVersionUID = 0L; /** The CollectionTreeNodes this model is built for */ private CollectionTreeNode[] file_nodes = null; /** The list of MetadataValueTableEntries in the table */ private ArrayList metadata_value_table_entries = new ArrayList(); static final private String[] COLUMN_NAMES = { "", Dictionary.get("Metadata.Element"), Dictionary.get("Metadata.Value") }; public int addBlankRowForMetadataElement(MetadataElement metadata_element) { MetadataValueTableModelBuilder metadata_value_table_model_builder = new MetadataValueTableModelBuilder(); MetadataValue blank_metadata_value = new MetadataValue(metadata_element, new MetadataValueTreeNode("")); return metadata_value_table_model_builder.insertMetadataValue(blank_metadata_value); } public int findMetadataValueTableEntryToSelect(MetadataValueTableEntry metadata_value_table_entry) { MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); // Find the correct entry to select for (int i = 0; i < metadata_value_table_entries.size(); i++) { MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i); int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element); // We've found the right element, so check if the value already exists if (element_comparison == 0) { int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry); if (value_comparison == 0) { // Entry found! return i; } } // We've just gone past the correct entry to select if (element_comparison > 0) { return i - 1; } } // Have to select the last entry return metadata_value_table_entries.size() - 1; } public Class getColumnClass(int col) { return getValueAt(0, col).getClass(); } /** Returns the number of columns in this table. */ public int getColumnCount() { return COLUMN_NAMES.length; } /** Retrieves the name of the specified column. */ public String getColumnName(int col) { return COLUMN_NAMES[col]; } /* Called to retrieve the MetadataValueTableEntry at a certain row. Usually caused by the user selecting a row in the table. It is synchronized so that the model doesn't up and change while we're trying to retrieve the indicated element. */ public synchronized MetadataValueTableEntry getMetadataValueTableEntry(int row) { if (row >= 0 && row < metadata_value_table_entries.size()) { return (MetadataValueTableEntry) metadata_value_table_entries.get(row); } return null; } /** Returns the number of rows in this table. */ public int getRowCount() { return metadata_value_table_entries.size(); } /** Returns the cell value at a given row and column as an Object. */ public Object getValueAt(int row, int col) { // Check values are reasonable if (row < 0 || row >= metadata_value_table_entries.size() || col < 0 || col >= COLUMN_NAMES.length) { return null; } MetadataValueTableEntry metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(row); if(metadata_value_table_entry == null) { System.err.println("\n@@@@@ MetadataValueTableModel.getValueAt(): metadata_value_table_entry is unexpectedly null!\n"); return null; } if (col == 0 && metadata_value_table_entry.isInheritedMetadata()) { return metadata_value_table_entry.getFolderMetadataInheritedFrom(); } if (col == 1) { return metadata_value_table_entry.getMetadataElement(); } if (col == 2) { return decodeHTMLEntities(metadata_value_table_entry.getFullValue()); } return null; } public String decodeHTMLEntities(String text) { text = text.replace("&#40;", "("); text = text.replace("&#41;", ")"); text = text.replace("&#44;", ","); text = text.replace("&#60;", "<"); text = text.replace("&#62;", ">"); text = text.replace("&#91;", "["); text = text.replace("&#93;", "]"); text = text.replace("&#123;", "{"); text = text.replace("&#125;", "}"); return text; } public boolean isCellEditable(int row, int col) { // The inherited and element columns are never editable if (col < 2) { return false; } // Extracted and inherited metadata is not editable MetadataValueTableEntry metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(row); if (metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement() || metadata_value_table_entry.isInheritedMetadata()) { return false; } return true; } /** Determine if the given metadata is common to all selected file nodes. */ public boolean isCommon(MetadataValueTableEntry metadata_value_table_entry) { return (file_nodes != null && metadata_value_table_entry.getOccurrences() == file_nodes.length); } /** Determine if the given metadata is common to all selected file nodes. */ public boolean isCommon(int row) { if (row >= 0 && row < metadata_value_table_entries.size()) { return isCommon((MetadataValueTableEntry) metadata_value_table_entries.get(row)); } return false; } public void rebuild(CollectionTreeNode[] file_nodes) { this.file_nodes = file_nodes; metadata_value_table_entries.clear(); // Collection is in a state of flux if (!Gatherer.c_man.ready()) { return; } if (file_nodes == null || file_nodes.length == 0) { return; } // Create model builder MetadataValueTableModelBuilder builder = new MetadataValueTableModelBuilder(); builder.run(); } public void setValueAt(Object new_metadata_value, int row, int col) { MetadataValueTableEntry metadata_value_table_entry = getMetadataValueTableEntry(row); if(metadata_value_table_entry == null) { System.err.println("\n@@@@@ MetadataValueTableModel.setValueAt(): metadata_value_table_entry is unexpectedly null!\n"); return; } // If nothing has changed no action is necessary String old_metadata_value = metadata_value_table_entry.getFullValue(); if (new_metadata_value.equals(old_metadata_value)) { return; } // Lock the interface so nothing can be changed while the metadata edit is being processed Gatherer.g_man.wait(true); // Check for a restricted metadata element MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); if (!new_metadata_value.equals("") && metadata_element.isRestricted()) { if (metadata_element.getMetadataValueTreeNode((String)new_metadata_value)==null) { WarningDialog dialog = new WarningDialog("warning.InvalidMetadata", Dictionary.get("InvalidMetadata.Title"), Dictionary.get("InvalidMetadata.Message"), null, false); int dialog_result = dialog.display(); dialog.dispose(); Gatherer.g_man.wait(false); return; } } // Metadata value added if (old_metadata_value.equals("") && !new_metadata_value.equals("")) { // If we're adding metadata to folders display the warning if (!file_nodes[0].isLeaf()) { WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", Dictionary.get("DirectoryLevelMetadata.Title"), Dictionary.get("DirectoryLevelMetadata.Message"), null, true); int dialog_result = dialog.display(); dialog.dispose(); if (dialog_result != JOptionPane.OK_OPTION) { Gatherer.g_man.wait(false); return; } } MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value); MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); metadata_value.setIsAccumulatingMetadata(true); (new AppendMetadataTask(metadata_value)).run(); } // Metadata value removed else if (!old_metadata_value.equals("") && new_metadata_value.equals("")) { (new RemoveMetadataTask(metadata_value_table_entry)).run(); } // Metadata value replaced else { MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value); MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node); metadata_value.setIsAccumulatingMetadata(!metadata_value_table_entry.isInheritedMetadata()); (new ReplaceMetadataTask(metadata_value_table_entry, metadata_value)).run(); } } private class AppendMetadataTask // extends Thread { private MetadataValue metadata_value = null; private AppendMetadataTask(MetadataValue metadata_value) { this.metadata_value = metadata_value; } public void run() { try { // Edit metadata.xml files to add the metadata MetadataXMLFileManager.addMetadata(file_nodes, metadata_value); } catch (Exception exception) { // We need to catch any exceptions here so the interface is unlocked below DebugStream.printStackTrace(exception); } // Operation finished, so turn busy cursor off and unlock interface Gatherer.g_man.wait(false); } } private class ReplaceMetadataTask // extends Thread { private MetadataValueTableEntry selected_metadata_value_table_entry = null; private MetadataValue metadata_value = null; private ReplaceMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry, MetadataValue metadata_value) { this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; this.metadata_value = metadata_value; } public void run() { try { // Edit metadata.xml files to replace the metadata MetadataXMLFileManager.replaceMetadata(file_nodes, selected_metadata_value_table_entry, metadata_value); } catch (Exception exception) { // We need to catch any exceptions here so the interface is unlocked below DebugStream.printStackTrace(exception); } // Operation finished, so turn busy cursor off and unlock interface Gatherer.g_man.wait(false); } } private class RemoveMetadataTask // extends Thread { private MetadataValueTableEntry selected_metadata_value_table_entry = null; private RemoveMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry) { this.selected_metadata_value_table_entry = selected_metadata_value_table_entry; } public void run() { try { // Edit metadata.xml files to remove the metadata MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry); } catch (Exception exception) { // We need to catch any exceptions here so the interface is unlocked below DebugStream.printStackTrace(exception); } // Operation finished, so turn busy cursor off and unlock interface Gatherer.g_man.wait(false); } } private class MetadataValueTableModelBuilder { public void run() { // System.err.println("Building MetadataValueTableModel..."); // Build a list of MetadataValueTableEntries that represent the metadata asssigned to the selected files boolean hid_extracted_metadata = false; ArrayList metadata_elements_seen = new ArrayList(); // Process each of the selected files in turn for (int i = 0; i < file_nodes.length; i++) { File current_file = file_nodes[i].getFile(); // Get the metadata assigned to this file ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedToFile(current_file); for (int j = 0; j < assigned_metadata.size(); j++) { MetadataValue metadata_value = (MetadataValue) assigned_metadata.get(j); MetadataElement metadata_element = metadata_value.getMetadataElement(); // Insert this metadata value into the table, unless it already exists (in which case increment its count) insertMetadataValue(metadata_value); // Remember we have seen this metadata element if (metadata_elements_seen.contains(metadata_element) == false) { metadata_elements_seen.add(metadata_element); } } // Get the extracted metadata for this file, if desired if (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC) == true) { ArrayList extracted_metadata = DocXMLFileManager.getMetadataExtractedFromFile(current_file); for (int k = 0; k < extracted_metadata.size(); k++) { MetadataValue metadata_value = (MetadataValue) extracted_metadata.get(k); // Insert this metadata value into the table, unless it already exists (in which case increment its count) insertMetadataValue(metadata_value); } } } // Make sure each non-extracted metadata element appears in the table (even if blank) ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement(); for (int i = 0; i < every_metadata_set_element.size(); i++) { MetadataElement metadata_element = (MetadataElement) every_metadata_set_element.get(i); // If we haven't seen this metadata element and it isn't extracted, add it now if (!metadata_elements_seen.contains(metadata_element) && !metadata_element.isExtractedMetadataElement()) { MetadataValueTableEntry metadata_value_table_entry = new MetadataValueTableEntry(metadata_element, new MetadataValueTreeNode("")); // Blank metadata is common to all selected files (otherwise it wouldn't be blank!) metadata_value_table_entry.setOccurrences(file_nodes.length); // Add it to the table insertMetadataValueTableEntry(metadata_value_table_entry); } } // If extracted metadata was hidden, display the warning if (hid_extracted_metadata) { showExtractedMetadataWarning(); } } /** Inserts the new metadata value into the table */ private int insertMetadataValue(MetadataValue metadata_value) { return insertMetadataValueTableEntry(new MetadataValueTableEntry(metadata_value)); } /** Inserts the new metadata value table entry into the table */ private int insertMetadataValueTableEntry(MetadataValueTableEntry metadata_value_table_entry) { MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement(); // Find the correct place to insert the table entry for (int i = 0; i < metadata_value_table_entries.size(); i++) { MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i); int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element); // We've found the right element, so check if the value already exists if (element_comparison == 0) { int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry); if (value_comparison == 0) { // Entry already exists, so increment count (except for blank entries) if (!metadata_value_table_entry.getFullValue().equals("")) { current_metadata_value_table_entry.anotherOccurrence(); } return i; } } // Found insertion point if (element_comparison > 0) { metadata_value_table_entries.add(i, metadata_value_table_entry); fireTableRowsInserted(i, i); return i; } } // Must go at the end of the table metadata_value_table_entries.add(metadata_value_table_entry); fireTableRowsInserted(metadata_value_table_entries.size() - 1, metadata_value_table_entries.size() - 1); return metadata_value_table_entries.size() - 1; } private void showExtractedMetadataWarning() { Runnable task = new Runnable() { public void run() { WarningDialog dialog = new WarningDialog("warning.ExtractedMetadata", Dictionary.get("ExtractedMetadata.Title"), Dictionary.get("ExtractedMetadata.Message"), null, false); dialog.display(); dialog.dispose(); dialog = null; } }; SwingUtilities.invokeLater(task); } } }