/** *######################################################################### * * 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; /************************************************************************************** * Written: 16/07/03 * Revised: **************************************************************************************/ import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; import org.greenstone.gatherer.Configuration; import org.greenstone.gatherer.Dictionary; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.cdm.CollectionConfiguration; import org.greenstone.gatherer.cdm.CollectionDesignManager; import org.greenstone.gatherer.cdm.Control; import org.greenstone.gatherer.cdm.SearchType; import org.greenstone.gatherer.cdm.DOMProxyListModel; import org.greenstone.gatherer.gui.GComboBox; import org.greenstone.gatherer.gui.GLIButton; import org.greenstone.gatherer.util.Utility; import org.w3c.dom.*; /** This class maintains an ordered list of the search types available in the collection (MGPP command available in G2.39 or later). Currently only 'form' and 'plain' are valid. * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.4 */ public class SearchTypeManager extends DOMProxyListModel { static final public String[] SEARCH_TYPES = { "form", "plain" }; /** The controls used to edit the search types. */ private Control controls = null; /** A reference to ourselves so our inner classes have access. */ private DOMProxyListModel model; public SearchTypeManager(Element searchtypes_element) { super(searchtypes_element, CollectionConfiguration.CONTENT_ELEMENT, new SearchType()); this.model = this; Gatherer.println("SearchTypeManager: parsed " + getSize() + " search types."); } private void addSearchType(SearchType searchtype) { if(!contains(searchtype)) { add(getSize(), searchtype); Gatherer.c_man.configurationChanged(); } } public Control getControls() { if(controls == null) { controls = new SearchTypeControl(); } return controls; } /** Return a list of the currently assigned search types as a comma separated string. * @return a String */ public String getSearchTypes() { StringBuffer search_types = new StringBuffer(); ArrayList types = children(); for (int i = 0; i < types.size(); i++) { if (i>0) { search_types.append(","); } search_types.append(((SearchType)types.get(i)).getName()); } return search_types.toString(); } /** Be examining the SearchType 'root' we were created with, determine if mgpp is enabled. * @return true if MGPP is enabled, false otherwise */ public boolean isMGPPEnabled() { return root.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR); } private void moveSearchType(SearchType search_type, boolean direction) { // Try to move the classifier one step in the desired direction. int index = indexOf(search_type); if(direction) { index--; } else { index++; } // Check we aren't at an edge if((direction && index < 0) || (!direction && index >= getSize())) { String args[] = new String[2]; args[0] = Dictionary.get("CDM.SearchTypeManager.SearchType"); args[1] = search_type.toString(); String message = null; if (direction) { message = Dictionary.get("CDM.Move.At_Top", args); } else { message = Dictionary.get("CDM.Move.At_Bottom", args); } JOptionPane.showMessageDialog(Gatherer.g_man, message, Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE); return; } remove(search_type); add(index, search_type); Gatherer.c_man.configurationChanged(); } private void removeSearchType(SearchType searchtype) { if(contains(searchtype)) { remove(searchtype); Gatherer.c_man.configurationChanged(); } } private class SearchTypeControl extends JPanel implements Control { private GComboBox search_type_combobox; private JButton add_button; private JButton move_down_button; private JButton move_up_button; private JButton remove_button; private JCheckBox enable_advanced_searches_checkbox; private JLabel current_search_types_label; private JLabel search_type_label; private JLabel title_label; private JList current_search_types_list; private JTextArea instructions_textarea; public SearchTypeControl() { // Creation title_label = new JLabel(); title_label.setHorizontalAlignment(JLabel.CENTER); Dictionary.registerText(title_label, "CDM.SearchTypeManager.Title"); JPanel instructions_panel = new JPanel(); instructions_textarea = new JTextArea(); instructions_textarea.setCaretPosition(0); instructions_textarea.setEditable(false); instructions_textarea.setLineWrap(true); instructions_textarea.setRows(6); instructions_textarea.setWrapStyleWord(true); Dictionary.registerText(instructions_textarea, "CDM.SearchTypeManager.Instructions"); JPanel spacer_panel = new JPanel(); JPanel empty_panel = new JPanel(); JPanel inner_panel = new JPanel(); enable_advanced_searches_checkbox = new JCheckBox(); Dictionary.registerText(enable_advanced_searches_checkbox, "CDM.SearchTypeManager.Enable"); JPanel current_search_types_panel = new JPanel(); current_search_types_label = new JLabel(); Dictionary.registerText(current_search_types_label, "CDM.SearchTypeManager.Assigned"); current_search_types_list = new JList(model); current_search_types_list.setVisibleRowCount(3); JPanel movement_panel = new JPanel(); move_up_button = new JButton("", Utility.getImage("arrow-up.gif")); move_up_button.setEnabled(false); move_up_button.setMnemonic(KeyEvent.VK_U); //move_up_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE); Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip"); move_down_button = new JButton("", Utility.getImage("arrow-down.gif")); move_down_button.setEnabled(false); move_down_button.setMnemonic(KeyEvent.VK_D); //move_down_button.setPreferredSize(Utility.DOUBLE_IMAGE_BUTTON_SIZE); Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip"); JPanel search_type_panel = new JPanel(); search_type_label = new JLabel(); Dictionary.registerText(search_type_label, "CDM.SearchTypeManager.SearchType_Selection"); search_type_combobox = new GComboBox(SEARCH_TYPES); search_type_combobox.setPreferredSize(Utility.LABEL_SIZE); search_type_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false)); search_type_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false)); search_type_combobox.setEditable(true); search_type_combobox.setSelectedIndex(0); search_type_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false)); search_type_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false)); Dictionary.registerTooltip(search_type_combobox, "CDM.SearchTypeManager.SearchType_Selection_Tooltip"); JPanel button_panel = new JPanel(); add_button = new GLIButton(); add_button.setEnabled(false); add_button.setMnemonic(KeyEvent.VK_A); Dictionary.registerBoth(add_button, "CDM.SearchTypeManager.Add", "CDM.SearchTypeManager.Add_Tooltip"); remove_button = new GLIButton(); remove_button.setEnabled(false); remove_button.setMnemonic(KeyEvent.VK_R); Dictionary.registerBoth(remove_button, "CDM.SearchTypeManager.Remove", "CDM.SearchTypeManager.Remove_Tooltip"); // Connection add_button.addActionListener(new AddActionListener()); current_search_types_list.addListSelectionListener(new CurrentSearchTypesListSelectionListener()); enable_advanced_searches_checkbox.addActionListener(new EnableAdvancedSearchesActionListener()); move_up_button.addActionListener(new MoveListener(true)); move_down_button.addActionListener(new MoveListener(false)); remove_button.addActionListener(new RemoveActionListener()); SearchTypesActionDocumentListener stadl = new SearchTypesActionDocumentListener(); search_type_combobox.addActionListener(stadl); ((JTextField)search_type_combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(stadl); // Layout instructions_panel.setBorder(BorderFactory.createEmptyBorder(0,0,2,0)); instructions_panel.setLayout(new BorderLayout()); instructions_panel.add(title_label, BorderLayout.NORTH); instructions_panel.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER); movement_panel.setBorder(BorderFactory.createEmptyBorder(0,2,0,0)); movement_panel.setLayout(new GridLayout(2,1,5,0)); movement_panel.add(move_up_button); movement_panel.add(move_down_button); current_search_types_panel.setBorder(BorderFactory.createEmptyBorder(2,0,2,0)); current_search_types_panel.setLayout(new BorderLayout()); current_search_types_panel.add(current_search_types_label, BorderLayout.NORTH); current_search_types_panel.add(new JScrollPane(current_search_types_list), BorderLayout.CENTER); current_search_types_panel.add(movement_panel, BorderLayout.EAST); button_panel.setBorder(BorderFactory.createEmptyBorder(2,0,0,0)); button_panel.setLayout(new GridLayout(1,2,0,5)); button_panel.add(add_button); button_panel.add(remove_button); search_type_panel.setLayout(new BorderLayout(5,3)); search_type_panel.add(search_type_label, BorderLayout.WEST); search_type_panel.add(search_type_combobox, BorderLayout.CENTER); search_type_panel.add(button_panel, BorderLayout.SOUTH); inner_panel.setLayout(new BorderLayout()); inner_panel.add(enable_advanced_searches_checkbox, BorderLayout.NORTH); inner_panel.add(current_search_types_panel, BorderLayout.CENTER); inner_panel.add(search_type_panel, BorderLayout.SOUTH); spacer_panel.setLayout(new BorderLayout()); spacer_panel.add(inner_panel, BorderLayout.NORTH); spacer_panel.add(empty_panel, BorderLayout.CENTER); setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); setLayout(new BorderLayout()); add(instructions_panel, BorderLayout.NORTH); add(spacer_panel, BorderLayout.CENTER); } public void destroy() { } public void gainFocus() { instructions_textarea.setCaretPosition(0); validateControls(isMGPPEnabled()); } public void loseFocus() { } private void validateControls(boolean advanced_search_enabled) { // Enable or disable controls based on whether MGPP is enabled // validate add button, which depends on the current combobox selection and the contents of the assigned search types list Object selected_item = search_type_combobox.getSelectedItem(); add_button.setEnabled(advanced_search_enabled && selected_item != null && !model.contains(selected_item)); // validate other controls. current_search_types_list.setEnabled(advanced_search_enabled); enable_advanced_searches_checkbox.setSelected(advanced_search_enabled); search_type_combobox.setEnabled(advanced_search_enabled); remove_button.setEnabled(current_search_types_list.getModel().getSize() > 1 && !current_search_types_list.isSelectionEmpty() && advanced_search_enabled); } /** Listenes for actions on the Add button, and if detected adds a new search type. */ private class AddActionListener implements ActionListener { /** Called when someone actions the Add button. * @param event an ActionEvent containing information about the add button click */ public void actionPerformed(ActionEvent event) { Object selected_item = search_type_combobox.getSelectedItem(); if(selected_item != null) { if(search_type_combobox.getSelectedIndex() == -1) { search_type_combobox.insertItemAt(selected_item, search_type_combobox.getItemCount()); } // Add the search type SearchType new_searchtype = new SearchType((String)selected_item); addSearchType(new_searchtype); } add_button.setEnabled(false); } } /** Listens for selections within the search types list and updates the remove button appropriately. */ private class CurrentSearchTypesListSelectionListener implements ListSelectionListener { /** Called when the selection in the list changes. * @param event a ListSelectionEvent containing information about the selection change */ public void valueChanged(ListSelectionEvent event) { if(!event.getValueIsAdjusting()) { SearchType search_type = null; if ((search_type = (SearchType) current_search_types_list.getSelectedValue()) != null) { int index = model.indexOf(search_type); // Move up is only enabled if the current selection isn't at index 0 move_up_button.setEnabled(index != 0); // Move down is only enabled if the current selection isn't at index getSize() - 1 move_down_button.setEnabled(index != model.getSize() - 1); // Remove is only enabled if this isn't the last search type remove_button.setEnabled(current_search_types_list.getModel().getSize() > 1); } else { move_up_button.setEnabled(false); move_down_button.setEnabled(false); remove_button.setEnabled(false); } } } } /** The most complex listener in this class, this listens for changes to the enable advanced searches checkbox, and when they occur it not only updates the controls on this page, but asks the IndexManager to action the appropriate changes to the underlying DOM so as to support either MG or MGPP styles of indexes. */ private class EnableAdvancedSearchesActionListener implements ActionListener { /** Called whenever the checkbox is checked or unchecked. * @param event an ActionEvent containing information about the checking action */ public void actionPerformed(ActionEvent event) { Gatherer.g_man.wait(true); boolean advanced_search_enabled = enable_advanced_searches_checkbox.isSelected(); model.root.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (advanced_search_enabled ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR)); CollectionDesignManager.index_manager.setMGPPEnabled(advanced_search_enabled); validateControls(advanced_search_enabled); Gatherer.g_man.wait(false); } } /** Listenes for actions on the Remove button, and if detected removes the currently selected search types. */ private class RemoveActionListener implements ActionListener { /** Called when someone actions the Remove button. * @param event an ActionEvent containing information about the remove button click */ public void actionPerformed(ActionEvent event) { if(!current_search_types_list.isSelectionEmpty()) { Object[] selected_items = current_search_types_list.getSelectedValues(); for(int i = 0; model.getSize() > 1 && i < selected_items.length; i++) { removeSearchType((SearchType)selected_items[i]); } } Object selected_object = search_type_combobox.getSelectedItem(); if(selected_object != null) { add_button.setEnabled(!model.contains(selected_object)); } else { add_button.setEnabled(false); } remove_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 first selected search type (if any) SearchType search_type = null; if((search_type = (SearchType) current_search_types_list.getSelectedValue()) != null) { // Move search type moveSearchType(search_type, move_up); // Reselect the moved search type current_search_types_list.setSelectedValue(search_type, true); } // No selection - no movement else { move_up_button.setEnabled(false); move_down_button.setEnabled(false); } } } /** Listens for changes in the search types combobox, and enabled add button appropriately. */ private class SearchTypesActionDocumentListener implements ActionListener, DocumentListener { /** Called whenever a selection action occurs on the combobox. * @param event an ActionEvent containing information about the selection event */ public void actionPerformed(ActionEvent event) { validateAddButton(); } /** Gives notification that an attribute or set of attributes changed. * @param event a DocumentEvent containing information about the text changed */ public void changedUpdate(DocumentEvent event) { validateAddButton(); } /** Gives notification that there was an insert into the document. * @param event a DocumentEvent containing information about the text added */ public void insertUpdate(DocumentEvent event) { validateAddButton(); } /** Gives notification that a portion of the document has been removed. * @param event a DocumentEvent containing information about the text removed */ public void removeUpdate(DocumentEvent event) { validateAddButton(); } /** Change the enable state of the add button depending on the current value in the search type combobox. */ private void validateAddButton() { Object selected_object = search_type_combobox.getSelectedItem(); if(selected_object != null) { add_button.setEnabled(!model.contains(selected_object)); } else { add_button.setEnabled(false); } } } } }