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