/**
*#########################################################################
*
* 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.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.DebugStream;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.gui.GLIButton;
import org.greenstone.gatherer.metadata.MetadataElement;
import org.greenstone.gatherer.metadata.MetadataSetManager;
import org.greenstone.gatherer.util.CheckList;
import org.greenstone.gatherer.util.CheckListEntry;
import org.greenstone.gatherer.util.JarTools;
import org.greenstone.gatherer.util.StaticStrings;
import org.greenstone.gatherer.util.XMLTools;
import org.w3c.dom.*;
/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
* @author John Thompson, Greenstone Digital Library, University of Waikato
* @version 2.3
*/
public class LanguageManager
extends DOMProxyListModel {
static public Document LANGUAGES_DOCUMENT = XMLTools.parseXMLFile("xml/languages.xml", true);
static final private Dimension COMPONENT_SIZE = new Dimension(125,25);
/** The visual controls for this manager. */
private Control controls = null;
/** A reference to this class as a model, for the inner controls class. */
private DOMProxyListModel model = null;
/** A hashtable of code->name mappings of known languages. */
private LinkedHashMap known_languages = null;
/** The default language object. */
private Language default_language = null;
/** The language metadata element - specifies which metadata the
language should be read from to determine the partitons */
private Element language_metadata = null;
/** Constructor. */
public LanguageManager(Element languages_element) {
super(languages_element, StaticStrings.LANGUAGE_ELEMENT, new Language());
DebugStream.println("LanguageManager: " + getSize() + " languages parsed.");
this.model = this;
// Retrieve the default language
NodeList default_language_elements = CollectionConfiguration.getElementsByTagName(StaticStrings.LANGUAGE_DEFAULT_ELEMENT);
if(default_language_elements.getLength() > 0) {
default_language = new Language((Element)default_language_elements.item(0));
}
// Retrieve the language metadata
language_metadata = CollectionDesignManager.collect_config.getLanguageMetadata();
// Load a series of code->language mappings into known_languages, by reading from the 'languages.xml' file, which is essentially a subset of the ISO 639 Standard.
known_languages = new LinkedHashMap();
NodeList language_elements = LANGUAGES_DOCUMENT.getDocumentElement().getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
for(int i = 0; i < language_elements.getLength(); i++) {
Element language_element = (Element) language_elements.item(i);
String code = language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE);
String name = language_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
known_languages.put(code.toLowerCase(), name);
name = null;
code = null;
language_element = null;
}
}
/** Method to add a new language.
* @param language The Language to add.
* @see org.greenstone.gatherer.Gatherer
* @see org.greenstone.gatherer.collection.CollectionManager
*/
private void addLanguage(Language language) {
if(!contains(language)) {
// need to add a pseudo metadata
CollectionMeta metadatum = new CollectionMeta(StaticStrings.STOP_CHARACTER + language.getCode());
metadatum.setValue(language.getName());
CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
add(getSize(), language);
}
}
public void destroy() {
if(controls != null) {
controls.destroy();
controls = null;
}
known_languages.clear();
known_languages = null;
default_language = null;
}
/** Method to retrieve the control for this manager.
* @return the Control for editing the language partitions
*/
public Control getControls() {
if(controls == null) {
// Build controls
controls = new LanguageControl();
}
return controls;
}
/** Method to retrieve a certain language object by its code.
* @param code The two letter code of a language, as a String.
* @return The Language that matches the given code, or null if no such language exists.
*/
public Language getLanguage(String code) {
int size = getSize();
for(int i = 0; i < size; i++) {
Language language = (Language) getElementAt(i);
if(language.getCode().equals(code)) {
return language;
}
}
return null;
}
public ArrayList getLanguages() {
return children();
}
/** Method to return a list of the known language codes.
* @return an ArrayList containing the series of known language codes as per the languages.dat file
*/
public ArrayList getLanguageCodes() {
return new ArrayList(known_languages.keySet());
}
public String getLanguageName(String code) {
return (String) known_languages.get(code);
}
/** 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) {
}
private int moveLanguage(Language lang, boolean move_up)
{
// Determine the current position of the language
int position = indexOf(lang);
int new_position;
// Attempt to move the language up
if (move_up) {
// Check it's not already at the top
if (position == 0) {
return position;
}
// This automatically removes the language first, as an Element can only exist once in a particular document
new_position = position - 1;
addBefore(lang, (Language) getElementAt(new_position));
}
// Attempt to move the language down
else {
// Check it's not already at the bottom
if (position == (getSize()) - 1) {
return position;
}
// This automatically removes the language first, as an Element can only exist once in a particular document
new_position = position + 1;
addAfter(lang, (Language) getElementAt(new_position));
}
return new_position;
}
/** Method to remove a certain language.
* @param language The Language to remove.
* @see org.greenstone.gatherer.Gatherer
* @see org.greenstone.gatherer.collection.CollectionManager
*/
private void removeLanguage(Language language) {
remove(language);
// Remove any collection metadata for this language
CollectionDesignManager.collectionmeta_manager.removeMetadata(StaticStrings.STOP_CHARACTER + language.getCode());
if(default_language != null && default_language.equals(language)) {
setDefault(null);
}
}
private void replaceLanguage(Language old_language, Language new_language) {
// Remove old lang collection meta
CollectionDesignManager.collectionmeta_manager.removeMetadata(StaticStrings.STOP_CHARACTER + old_language.getCode());
// Add new one
CollectionMeta metadatum = new CollectionMeta(StaticStrings.STOP_CHARACTER + new_language.getCode());
metadatum.setValue(new_language.getName());
CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
if(default_language != null && default_language.equals(old_language)) {
setDefault(new_language);
}
// get the position of the old one
int position = indexOf(old_language);
remove(old_language);
add(position, new_language);
}
/** Method to set the default language.
* @param language The Language to use as a default, or null for no default.
* @see org.greenstone.gatherer.Gatherer
* @see org.greenstone.gatherer.collection.CollectionManager
*/
public void setDefault(Language language) {
if(language != null) {
if(default_language == null) {
// Create the default index element, and place immediately after indexes element.
Element default_language_element = root.getOwnerDocument().createElement(StaticStrings.LANGUAGE_DEFAULT_ELEMENT);
default_language = new Language(default_language_element);
Node target_node = CollectionConfiguration.findInsertionPoint(default_language_element);
if(target_node != null) {
root.getOwnerDocument().getDocumentElement().insertBefore(default_language_element, target_node);
}
else {
root.getOwnerDocument().getDocumentElement().appendChild(default_language_element);
}
}
default_language.setAssigned(true);
default_language.setCode(language.getCode());
}
else {
if(default_language != null) {
default_language.setAssigned(false);
}
}
}
/** This class represents the visual component of the Language Manager. */
private class LanguageControl
extends JPanel
implements Control {
/** The list of available languages */
private CheckList language_list = null;
/** The button to add a new language support. */
private JButton add_button = null;
/** The button to replace a language support. */
private JButton replace_button = null;
/** The button to remove a supported language. */
private JButton remove_button = null;
/** button to move a language up in the list */
private JButton move_down_button;
/** button to move a language down in the list */
private JButton move_up_button;
/** The button to set the current language as the default one. */
private JButton set_default_button = null;
/** A list of currently supported languages. */
private JList selected_languages_list = null;
/** A list of metadata elements that may hold the language metadata */
private JComboBox language_metadata_combo = null;
/** Constructor.
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.AddListener
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.ClearDefaultListener
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.ListListener
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.RemoveListener
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.SelectorListener
* @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.SetDefaultListener
*/
public LanguageControl() {
super();
// Creation.
JPanel center_panel = new JPanel();
JLabel selected_languages_list_label = new JLabel(Dictionary.get("CDM.LanguageManager.Assigned_Languages"));
selected_languages_list = new JList(model);
selected_languages_list.setCellRenderer(new MyLanguageListCellRenderer());
selected_languages_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
selected_languages_list.setVisibleRowCount(5);
JPanel control_panel = new JPanel();
JLabel selector_label = new JLabel(Dictionary.get("CDM.LanguageManager.Selector"));
language_metadata_combo = new JComboBox(MetadataSetManager.getEveryMetadataSetElement().toArray());
language_metadata_combo.setOpaque(false);
language_metadata_combo.setToolTipText(Dictionary.get("CDM.LanguageManager.LanguageMetadata_Tooltip"));
JLabel language_metadata_label = new JLabel(Dictionary.get("CDM.LanguageManager.LanguageMetadata"));
String current_value = "ex.Language";
if (language_metadata.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR) && !language_metadata.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals("")) {
current_value = language_metadata.getAttribute(StaticStrings.NAME_ATTRIBUTE);
}
ArgumentControl.selectValue(language_metadata_combo, current_value);
language_list = new CheckList(false);
language_list.setListData(getLanguageCodes());
language_list.setToolTipText(Dictionary.get("CDM.LanguageManager.Selector_Tooltip"));
language_list.setCellRenderer(new LanguageCheckListCellRenderer());
JPanel movement_pane = new JPanel();
move_up_button = new GLIButton(Dictionary.get("CDM.Move.Move_Up"), JarTools.getImage("arrow-up.gif"), Dictionary.get("CDM.Move.Move_Up_Tooltip"));
move_up_button.setEnabled(false);
move_down_button = new GLIButton(Dictionary.get("CDM.Move.Move_Down"), JarTools.getImage("arrow-down.gif"), Dictionary.get("CDM.Move.Move_Down_Tooltip"));
move_down_button.setEnabled(false);
set_default_button = new GLIButton(Dictionary.get("CDM.LanguageManager.Set_Default"), Dictionary.get("CDM.LanguageManager.Set_Default_Tooltip"));
set_default_button.setEnabled(false);
JPanel button_panel = new JPanel();
add_button = new GLIButton(Dictionary.get("CDM.SubcollectionIndexManager.Add_Subindex"), Dictionary.get("CDM.LanguageManager.Add_Tooltip"));
add_button.setEnabled(false);
replace_button = new GLIButton(Dictionary.get("CDM.SubcollectionIndexManager.Replace_Subindex"), Dictionary.get("CDM.LanguageManager.Replace_Tooltip"));
replace_button.setEnabled(false);
remove_button = new GLIButton(Dictionary.get("CDM.SubcollectionIndexManager.Remove_Subindex"), Dictionary.get("CDM.LanguageManager.Remove_Tooltip"));
remove_button.setEnabled(false);
// Set up and connect listeners.
add_button.addActionListener(new AddListener());
add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
move_down_button.addActionListener(new MoveListener(false));
move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
move_up_button.addActionListener(new MoveListener(true));
move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
remove_button.addActionListener(new RemoveListener());
remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
replace_button.addActionListener(new ReplaceListener());
replace_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
language_list.addListSelectionListener(new LanguageListListener());
language_metadata_combo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String value = ((MetadataElement)language_metadata_combo.getSelectedItem()).getFullName();
language_metadata.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
language_metadata.setAttribute(StaticStrings.NAME_ATTRIBUTE, value);
}
});
set_default_button.addActionListener(new SetDefaultListener());
set_default_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
selected_languages_list.addListSelectionListener(new AssignedListListener());
// Layout components
button_panel.setLayout(new GridLayout(1,3));
button_panel.add(add_button);
button_panel.add(replace_button);
button_panel.add(remove_button);
JPanel metadata_panel = new JPanel();
metadata_panel.setLayout(new BorderLayout());
JPanel inner_panel = new JPanel();
inner_panel.setLayout(new BorderLayout(10,10));
inner_panel.add(language_metadata_label, BorderLayout.WEST);
inner_panel.add(language_metadata_combo, BorderLayout.CENTER);
metadata_panel.add(new JPanel(), BorderLayout.CENTER);
metadata_panel.add(inner_panel, BorderLayout.EAST);
movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
movement_pane.setLayout(new GridLayout(3,1));
movement_pane.add(move_up_button);
movement_pane.add(move_down_button);
movement_pane.add(set_default_button);
control_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
control_panel.setLayout(new BorderLayout());
control_panel.add(selector_label, BorderLayout.WEST);
control_panel.add(new JScrollPane(language_list), BorderLayout.CENTER);
control_panel.add(button_panel, BorderLayout.SOUTH);
center_panel.setLayout(new BorderLayout());
center_panel.add(selected_languages_list_label, BorderLayout.NORTH);
center_panel.add(new JScrollPane(selected_languages_list), BorderLayout.CENTER);
center_panel.add(movement_pane, BorderLayout.EAST);
JPanel top_panel = new JPanel();
top_panel.setLayout(new BorderLayout());
top_panel.add(metadata_panel, BorderLayout.NORTH);
top_panel.add(center_panel, BorderLayout.SOUTH);
setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
setLayout(new BorderLayout());
add(top_panel, BorderLayout.NORTH);
add(control_panel, BorderLayout.CENTER);
}
/** Destructor. */
public void destroy() {
}
public void gainFocus() {
}
public void loseFocus() {
}
private void clearControls() {
selected_languages_list.clearSelection();
language_list.clearTicked();
add_button.setEnabled(false);
remove_button.setEnabled(false);
replace_button.setEnabled(false);
set_default_button.setEnabled(false);
move_down_button.setEnabled(false);
move_up_button.setEnabled(false);
}
private void updateControlsWithSelectedLanguage()
{
Language selected_lang = (Language) selected_languages_list.getSelectedValue();
if (selected_lang == null) {
clearControls();
return;
}
// Display the selected subcollection index's sources
language_list.clearTicked();
language_list.setTickedObjects(selected_lang.getCode().split(","));
}
private void validateButtons() {
boolean add_enabled = false;
boolean replace_enabled = false;
if (!language_list.isNothingTicked()) {
// Create a dummy Langauge and see if its in the collection
ArrayList langs = language_list.getTicked();
StringBuffer code_str = new StringBuffer();
boolean first = true;
for (int i=0; iActionEvent.
* @see org.greenstone.gatherer.cdm.Language
*/
public void actionPerformed(ActionEvent event) {
Language delete_me = (Language)selected_languages_list.getSelectedValue();
if(delete_me != null) {
removeLanguage(delete_me);
}
}
}
private class ReplaceListener
implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (selected_languages_list.isSelectionEmpty() || language_list.isNothingTicked()) {
// This should never happen, but just in case...
replace_button.setEnabled(false);
return;
}
Language old_language = (Language) selected_languages_list.getSelectedValue();
Language new_language = new Language(language_list.getTicked());
replaceLanguage(old_language, new_language);
}
}
private class LanguageListListener
implements ListSelectionListener {
public void valueChanged(ListSelectionEvent event) {
if (event.getValueIsAdjusting()) {
return;
}
validateButtons();
}
}
/** Listens for actions apon the 'set default' button in the LanguageManager controls, and if detected calls the setDefault() method of the manager with the language selected for default. */
private class SetDefaultListener
implements ActionListener {
/** Set the default index to the one currently selected, if any.
* @param event An ActionEvent.
* @see org.greenstone.gatherer.cdm.Language
*/
public void actionPerformed(ActionEvent event) {
Language selected_language = (Language) selected_languages_list.getSelectedValue();
if(selected_language != null) {
setDefault(selected_language);
// This should cause a repaint of just the desired row
selected_languages_list.setSelectedValue(selected_language, true);
}
set_default_button.setEnabled(false);
}
}
private class MoveListener
implements ActionListener
{
private boolean move_up;
public MoveListener(boolean move_up)
{
this.move_up = move_up;
}
public void actionPerformed(ActionEvent event)
{
// Retrieve the selected language
Language language = (Language) selected_languages_list.getSelectedValue();
if (language != null) {
int new_position = moveLanguage(language, move_up);
// Ensure the language that moved is still selected
selected_languages_list.setSelectedIndex(new_position);
}
}
}
/** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
private class AssignedListListener
implements ListSelectionListener {
/** Enable or disable controls depending on the current list selection.
* @param event A ListSelectionEvent.
*/
public void valueChanged(ListSelectionEvent event) {
if (event.getValueIsAdjusting()) {
return;
}
if(selected_languages_list.isSelectionEmpty()) {
clearControls();
return;
}
int i = selected_languages_list.getSelectedIndex();
int size = selected_languages_list.getModel().getSize();
Language selected_lang = (Language)selected_languages_list.getSelectedValue();
remove_button.setEnabled(true);
replace_button.setEnabled(false);
add_button.setEnabled(false);
set_default_button.setEnabled(default_language == null || !default_language.equals(selected_lang));
if (i > 0) {
move_up_button.setEnabled(true);
}
else {
move_up_button.setEnabled(false);
}
if (i < size-1){
move_down_button.setEnabled(true);
}
else {
move_down_button.setEnabled(false);
}
updateControlsWithSelectedLanguage();
}
}
private class MyLanguageListCellRenderer
extends DefaultListCellRenderer
{
/** Return a component that has been configured to display the specified value. */
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (default_language != null && default_language.equals(value)) {
component.setText(component.getText() + " [" + Dictionary.get("CDM.LanguageManager.Default_Language")+"]");
}
return component;
}
}
}
/** A custom list cell renderer for producing rows which contain clickable check boxes. */
private class LanguageCheckListCellRenderer
implements ListCellRenderer
{
/** Return a component that has been configured to display the specified value. That component's paint method is then called to "render" the cell. If it is necessary to compute the dimensions of a list because the list cells do not have a fixed size, this method is called to generate a component on which getPreferredSize can be invoked.
* @param list The JList we're painting.
* @param value The value returned by list.getModel().getElementAt(index), as an Object.
* @param index The cells index as an int.
* @param is_selected true if the specified cell was selected, false otherwise.
* @param cell_has_focus true if and only if the specified cell has the focus.
* @return A Component whose paint() method will render the specified value.
*/
public Component getListCellRendererComponent(JList list, Object value, int index, boolean is_selected, boolean cell_has_focus) {
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(list.getBackground());
checkbox.setForeground(list.getForeground());
checkbox.setBorderPainted(false);
checkbox.setEnabled(list.isEnabled());
checkbox.setFont(list.getFont());
checkbox.setFocusPainted(false);
checkbox.setBorder((is_selected) ? UIManager.getBorder("List.focusCellHighlightBorder") : new EmptyBorder(1, 1, 1, 1));
String code = (String)((CheckListEntry)list.getModel().getElementAt(index)).getObject();
checkbox.setText((String)known_languages.get(code));
return checkbox;
}
}
}