/** *######################################################################### * * 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.gui; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.text.*; import jp.gr.java_conf.tame.swing.combobox.*; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.gui.SmarterTextArea; import org.greenstone.gatherer.util.Utility; /** Combines the idea of a combobox with a text area so that multiline entries can be displayed properly. Basically takes a JCombobox, (or in this case a SteppedComboBox that allows us to control the popup window that appears), butchers out the JTextField editor while retaining the button and the data model, then uses a JTextArea for the editor instead. * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.3 */ public class ComboArea extends JPanel { /** Should the listener ignore any change events fired (most likely as a result of the listener in the first place). */ private boolean ignore = false; /** The combobox we are going to utilize. */ private SteppedComboBox combobox = null; /** The text area involved. Not quite a JTextArea, the smarter part is that is allows coloring contrary to the UIManager settings. */ private SmarterTextArea text_area = null; /** Create a new ComboArea demarked by a particular label. The label is given here so that it fits nicely with the text area and button. * @param text The label text to be shown above text area as a String. * @param label_size The Dimension to use for the label. * @see jp.gr.java_conf.tame.swing.combobox.SteppedComboBox * @see org.greenstone.gatherer.gui.ComboArea.ComboAreaListener * @see org.greenstone.gatherer.gui.ComboArea.Renderer */ public ComboArea(String text, Dimension label_size) { // Creation JPanel title_pane = new JPanel(); title_pane.setOpaque(false); JLabel label = new JLabel(text); label.setOpaque(false); label.setPreferredSize(label_size); JPanel text_pane = new JPanel(); text_area = new SmarterTextArea(); text_area.setRows(3); JPanel button_pane = new JPanel(); Dimension button_size = new Dimension(label_size.height, label_size.height); button_pane.setMaximumSize(button_size); button_pane.setMinimumSize(button_size); button_pane.setPreferredSize(button_size); button_pane.setSize(button_size); combobox = new SteppedComboBox(Gatherer.self, button_size); combobox.setDependant(text_area); combobox.setPreferredSize(label_size); combobox.setRenderer(new Renderer()); // Connection combobox.addActionListener(new ComboAreaListener()); // Layout title_pane.setLayout(new BorderLayout()); title_pane.add(label, BorderLayout.WEST); button_pane.setLayout(new BorderLayout()); button_pane.add(combobox.getButton(), BorderLayout.CENTER); text_pane.setLayout(new BorderLayout()); text_pane.add(new JScrollPane(text_area), BorderLayout.CENTER); text_pane.add(button_pane, BorderLayout.EAST); setLayout(new BorderLayout()); add(title_pane, BorderLayout.NORTH); add(text_pane, BorderLayout.CENTER); } /** Add an element to our combobox model. Remember to tell the listeners to ignore this action unless you want an infinite loop. * @param item The Object to add. */ public void add(Object item) { ignore = true; combobox.add(item.toString()); ignore = false; } /** Clear the combobox model. */ public void clear() { combobox.clear(); } /** Retrieve the text currently displayed in the text area. * @return A String containing the required text. */ public String getText() { return text_area.getText(); } /** Retrieve a reference to the text area. * @return A JTextComponent reference. */ public JTextComponent getTextComponent() { return text_area; } /** Change the selected item in the combobox to the one given. If such an object doesn't exist in the model, ignore it. Notice that this time we don't ignore, as we want a selection to update the text field. * @param item The Object that we want to select from the combobox. */ public void setSelectedItem(Object item) { combobox.setSelectedItem(item); } /** Set the text shown in the text area to the value provided. Note that this has no effect on the combobox, nor will this value be stored in the model. * @param text The String to display. */ public void setText(String text) { text_area.setText(text); } /** This clas listens for changes in the selected item in the combobox and if applicable updates the text area to match. */ private class ComboAreaListener implements ActionListener { /** Whenever a new object is selected from the combobox list, determine if this is an appropriate time to update the text area and if so do so. * @param event An ActionEvent encompassing all the relevant data about an action having been performed. */ public void actionPerformed(ActionEvent event) { Object object = combobox.getSelectedItem(); if(object != null && !ignore) { text_area.setText(object.toString()); } } } /** This renderer is used to ensure that the labels shown in the combobox drop-down list are both correct in colouring and legible. The later is important as the entry itself may actually span several lines. */ private class Renderer extends DefaultListCellRenderer { /** Retrieve the component used to 'rubberstamp' the desired entry in the combobox. * @param list The JList this component will be renderer in. * @param value The Object whose value should be represented by the component returned. * @param index An int giving the objects index in the list of objects. * @param isSelected true if this object is currently selected, false otherwise. * @param cellHasFocus true if this object is currently in focus, false otherwise. * @see org.greenstone.gatherer.util.Utility */ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel temp = null; if(value != null) { // Only show a single line by removing new lines. StringBuffer text = new StringBuffer(Utility.stripNL((String)value)); // Generate prototype label temp = (JLabel) super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus); // Trim down the value string so it fits nicely. Start by shortening it to the number of characters determined from the smarter text area. int preferred_characters = text_area.calculateColumnCount(); if(preferred_characters > 3 && text.length() > preferred_characters) { text.delete(preferred_characters - 3, text.length()); text.append("..."); } temp.setText(text.toString()); // If we are still too long, shorten by one character at a time until it fits while(temp.getPreferredSize().width > text_area.getSize().width && text.length() > 4) { // Remove the last four characters and mark as being chopped text.delete(text.length() - 4, text.length()); text.append("..."); // Assign new string, rinse and repeat. temp.setText(text.toString()); } } else { temp = (JLabel) super.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus); } // Colouring should be the same as the dependant we are based on. if(isSelected) { temp.setBackground(text_area.getSelectionColor()); temp.setForeground(text_area.getSelectedTextColor()); } else { temp.setBackground(text_area.getBackground()); temp.setForeground(text_area.getForeground()); } return temp; } } }