/** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * * Author: John Thompson, Greenstone Digital Library, University of Waikato * * Copyright (C) 1999 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.cdm; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.Dictionary; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.collection.CollectionManager; import org.greenstone.gatherer.gui.DesignPaneHeader; import org.greenstone.gatherer.gui.GComboBox; import org.greenstone.gatherer.metadata.MetadataElement; import org.greenstone.gatherer.metadata.MetadataSet; import org.greenstone.gatherer.metadata.MetadataSetManager; import org.greenstone.gatherer.util.Utility; /** * This manager implements the "Depositor Metadata" section in GLI Format Panel, where * users can customize which metadata elements will be used to describe an item when deposited in the Depositor. * * @author Anna Huang, Greenstone Digital Library, University of Waikato * @version 1.0 */ public class DepositorMetadataManager { /** Display controls of the element */ static private Dimension LABEL_SIZE = new Dimension(150, 15); static private Dimension ROW_SIZE = new Dimension(400, 20); /** Available types, corresponds to the HTML input types */ static private String[] TYPEOPTIONS = new String[]{"text", "textarea"}; /** Default elements to be used in Depositor */ static private String DEFAULT_METADATA_ELEMENTS = "dc.Title, dc.Creator, dc.Description"; /** Definition attribute of a metadata element */ static private String DEFINITION = "definition"; /** Display controls */ private Control controls; /** List of MetadataElementEntry objects, each represents a metadata element */ private ArrayList metadata_checklist_model = null; /** Collection configuration file manager */ private CollectionMetaManager collmeta_manager = CollectionDesignManager.collectionmeta_manager; public DepositorMetadataManager() { } /** Destructor. */ public void destroy() { if (controls != null) { controls.destroy(); controls = null; } if(metadata_checklist_model != null) { metadata_checklist_model.clear(); metadata_checklist_model = null; } } public Control getControls() { if (controls == null) { controls = new DepositorControl(); } return controls; } /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden * @param mode the new mode as an int */ public void modeChanged(int mode) { } /** * The implementation of this display control is similar to the ArgumentConfiguration, * where each component in the central panel is another JPanel component consists of a checkbox and a drop down list. */ private class DepositorControl extends JPanel implements Control { private JPanel central_pane = null; public DepositorControl() { super(); JPanel header_panel = new DesignPaneHeader("CDM.GUI.DepositorMetadata", "depositormetadatasettings"); // load all possible metadata sets, and existing configuration buildModel(); central_pane = new JPanel(); central_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); central_pane.setLayout(new BoxLayout(central_pane, BoxLayout.Y_AXIS)); // build the central pane, ie. create gui component for each metadata element buildPane(); JPanel collection_checklist_pane = new JPanel(); collection_checklist_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0)); collection_checklist_pane.setLayout(new BorderLayout()); collection_checklist_pane.add(new JScrollPane(central_pane), BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(0,5,0,0)); setLayout(new BorderLayout()); add(header_panel, BorderLayout.NORTH); add(collection_checklist_pane, BorderLayout.CENTER); } public void destroy() { } public void gainFocus() { } public void loseFocus() { StringBuffer converted_javascript = new StringBuffer(); // get currently selected metadata elements and create the javascript associative array variable if (metadata_checklist_model != null) { int size = metadata_checklist_model.size(); for(int i = 0; i < size; i++) { MetadataElementEntry entry = (MetadataElementEntry) metadata_checklist_model.get(i); if (entry.isSelected()) { StringBuffer element = new StringBuffer(); element.append("{\"name\":\"").append(entry.name).append("\","); element.append("\"label\":\"").append(entry.label).append("\","); element.append("\"tooltip\":\"").append(entry.name).append(": ").append(entry.tooltip).append("\","); element.append("\"type\":\"").append(entry.getType()).append("\"}"); if(converted_javascript.length() != 0) { converted_javascript.append(", "); } converted_javascript.append(element); element = null; } } // if none of the elements were selected, use the default setting if (converted_javascript.length() == 0) { System.err.println("Error: DepositorMetadataMananger should have at least one selected metadata element."); } // save to the configuration file CollectionMeta depositor_metadata_meta = collmeta_manager.getMetadatum("depositormetadata", true); depositor_metadata_meta.setValue(converted_javascript.toString()); } } private void buildModel() { metadata_checklist_model = new ArrayList(); String current_coll_name = CollectionManager.getLoadedCollectionName(); // get the elements that have already been used in depositor // add the "depositormetadata" meta if not found in the configuration file CollectionMeta depositor_metadata_meta = collmeta_manager.getMetadatum("depositormetadata", true); String selected_metadata_javascript = depositor_metadata_meta.getValue(true); // load all MDSets in the collection, ie. .mds files in the collection's metadata directory String file_name = Gatherer.getCollectDirectoryPath() + File.separator + current_coll_name + File.separator + "metadata"; ArrayList metadata_sets = MetadataSetManager.listMetadataSets(new File(file_name)); // if the collection doesn't have a metadata directory, load all the MDSets in the global GLI/metadata directory if (metadata_sets == null) { file_name = org.greenstone.gatherer.gems.MetadataSetManager.getGLIMetadataDirectoryPath(); metadata_sets = MetadataSetManager.listMetadataSets(new File(file_name)); } // always load the dc mds boolean found = false; for (int i = 0, j = metadata_sets.size(); i < j; i++) { if (((MetadataSet) metadata_sets.get(i)).getNamespace().equals("dc")) { found = true; break; } } if (found == false) { file_name = org.greenstone.gatherer.gems.MetadataSetManager.getGLIMetadataDirectoryPath(); file_name += "dublin.mds"; File dublin_mds_file = new File(file_name); if (dublin_mds_file.exists()) { MetadataSetManager.loadMetadataSet(dublin_mds_file); metadata_sets = MetadataSetManager.getMetadataSets(); } } // unload the ex mds for (int i = 0, j = metadata_sets.size(); i < j; i++) { if (((MetadataSet) metadata_sets.get(i)).getNamespace().equals("ex")) { metadata_sets.remove(i); break; } } if (metadata_sets == null) { System.err.println("Error: DepositorMetadataMananger can't find any valid metadata set files."); return; } // load all the metadata elements for (int i = 0, j = metadata_sets.size(); i < j; i++) { MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i); ArrayList elements = metadata_set.getMetadataSetElements(); for (int k = 0; elements != null && k < elements.size(); k++) { MetadataElement element = (MetadataElement) elements.get(k); // all names are language independent at the moment. MetadataElementEntry entry = new MetadataElementEntry (element.getFullName(), element.getName(), false); entry.setToolTip(element.getAttribute(DEFINITION, "en")); metadata_checklist_model.add(entry); } } if (!selected_metadata_javascript.equals("")) { for (int i = 0, j = metadata_checklist_model.size(); i < j; i++) { MetadataElementEntry entry = (MetadataElementEntry) metadata_checklist_model.get(i); String temp = "\"name\":\"" + entry.name + "\""; if (selected_metadata_javascript.indexOf(temp) != -1) { entry.setSelected(true); entry.type = getValueFromJSAssociatedArray(selected_metadata_javascript, entry.name, "type"); } temp = null; } } else { // use default elements for (int i = 0, j = metadata_checklist_model.size(); i < j; i++) { MetadataElementEntry entry = (MetadataElementEntry) metadata_checklist_model.get(i); if (DEFAULT_METADATA_ELEMENTS.indexOf(entry.name) != -1) { entry.setSelected(true); entry.type = TYPEOPTIONS[0]; } } } } private void buildPane() { // use different background color for two adjacent metadata sets String current_namespace = null; String current_bgcolor_name = null; for (int i = 0, j = metadata_checklist_model.size(); i < j; i++) { MetadataElementEntry entry = (MetadataElementEntry) metadata_checklist_model.get(i); if (current_namespace == null) { current_namespace = entry.namespace; current_bgcolor_name = "coloring.collection_tree_background"; } else { if (!entry.namespace.equals(current_namespace)) { current_namespace = entry.namespace; current_bgcolor_name = (current_bgcolor_name == "coloring.collection_tree_background") ? "coloring.collection_heading_background" : "coloring.collection_tree_background"; } } if (entry.getGUIControl() == null) { MetadataElementControl element_control = entry.initGUIControl(current_bgcolor_name); central_pane.add(element_control, BorderLayout.NORTH); } } } /** * Retrieve the value for the specified element in the given javascript associative array expression * * @param text * @param identifier * @param elem_name * @return */ private String getValueFromJSAssociatedArray(String text, String identifier, String elem_name) { int p = text.indexOf(elem_name, text.indexOf(identifier)); if (p == -1) { return null; } p = text.indexOf("\":\"", p); if (p == -1) { return null; } p += 3; return text.substring(p, text.indexOf("\"", p)); } } private class MetadataElementControl extends JPanel { private JCheckBox enabled = null; private JComponent value_control = null; public MetadataElementControl (MetadataElementEntry entry, String background_color_name) { String tip = "" + entry.tooltip + ""; tip = Utility.formatHTMLWidth(tip, 80); setBackground(Configuration.getColor(background_color_name, false)); setBorder(BorderFactory.createEmptyBorder(0,0,0,0)); setLayout(new BorderLayout()); setPreferredSize(ROW_SIZE); // the checkbox component enabled = new JCheckBox(entry.name); enabled.setSelected(entry.selected); enabled.setOpaque(false); enabled.setPreferredSize(LABEL_SIZE); enabled.setToolTipText(entry.tooltip); add(enabled, BorderLayout.WEST); // the drop down list component ArrayList option_list = new ArrayList(); for (int i = 0; i < TYPEOPTIONS.length; i++) { option_list.add(TYPEOPTIONS[i]); } value_control = new GComboBox(option_list.toArray(), false, false); selectValue((JComboBox)value_control, entry.type); value_control.setOpaque(true); if (entry.selected) { value_control.setBackground(Color.white); value_control.setEnabled(true); } else { value_control.setBackground(Color.lightGray); value_control.setEnabled(false); value_control.setVisible(false); } add(value_control, BorderLayout.CENTER); enabled.addActionListener(new EnabledListener(value_control)); } private boolean selectValue(JComboBox combobox, String target) { if (target == null) { combobox.setSelectedIndex(0); return false; } for (int i = 0; i < combobox.getItemCount(); i++) { if (combobox.getItemAt(i).toString().equals(target)) { combobox.setSelectedIndex(i); return true; } } return false; } private class EnabledListener implements ActionListener { private JComponent target = null; public EnabledListener(JComponent target) { this.target = target; } public void actionPerformed(ActionEvent event) { JCheckBox source = (JCheckBox)event.getSource(); // check at least one of the elements should be ticked checkTickedElements(source); // update the status of the drop-down list component associated with the current checkbox if (this.target == null) { return; } if(source.isSelected()) { target.setBackground(Color.white); target.setEnabled(true); target.setVisible(true); } else { target.setBackground(Color.lightGray); target.setEnabled(false); target.setVisible(false); } } private void checkTickedElements(JCheckBox source) { if (source.isSelected()) { return; } boolean b = false; for (int i = 0, j = metadata_checklist_model.size(); i < j; i++) { if (((MetadataElementEntry) metadata_checklist_model.get(i)).gui_object.enabled.isSelected()) { b = true; break; } } // there must be at least one element selected in the list if (b == false) { Object[] options = {Dictionary.get("General.OK")}; JOptionPane.showOptionDialog(Gatherer.g_man, Dictionary.get("CDM.DepositorMetadataManager.Warning"), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); source.setSelected(true); } } } } private class MetadataElementEntry implements Comparable { /** namespace, used to distinguish different metadata sets and use different colors when displaying */ String namespace = null; /** identifier, with namespace */ String name = null; /** language independent label, without namespace, used for display in the depositor web page, eg. Title */ String label = null; /** type of the element: text or textarea */ String type = null; /** description of the element, used in web page */ String tooltip = null; /** whether current element is selected or not */ boolean selected ; /** GUI component object associated with this element */ MetadataElementControl gui_object = null; /** * Constructor * @param name Language independent identifier of the element with namespace, eg. dc.Title * @param label Language independent label of the element, without namespace, eg. Title * @param selected Whether the current element has been selected as depositor metadata element */ public MetadataElementEntry(String name, String label, boolean selected) { this.name = name; this.label = label; this.selected = selected; if (name.indexOf(".") != -1) { namespace = name.substring(0, name.indexOf(".")); } } /** * Initiate the MetadataElementControl GUI component object associated with this element, with the specified background color * @param background_color_name System configured color name for the background, eg. "coloring.collection_heading_background", or "coloring.collection_tree_background" * @return the initialized component object */ public MetadataElementControl initGUIControl (String background_color_name) { gui_object = new MetadataElementControl(this, background_color_name); return gui_object; } /** * Get the associated GUI component * @return */ public MetadataElementControl getGUIControl() { return gui_object; } /** * Set selected * @param b */ public void setSelected(boolean b) { this.selected = b; } public boolean isSelected() { return gui_object.enabled.isSelected(); } /** * Get the selected type for the element * @return type */ public String getType() { return ((JComboBox) gui_object.value_control).getSelectedItem().toString(); } public void setToolTip (String tip) { if (tip == null) { tooltip = ""; return; } this.tooltip = tip; } public int compareTo(Object obj) { return compareTo((MetadataElementEntry) obj); } public int compareTo(MetadataElementEntry obj) { return this.name.compareTo(obj.name); } } }