/* Copyright (C) 2003-2011 JabRef contributors.
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package net.sf.jabref;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.*;
import com.jgoodies.forms.layout.Sizes;
import com.jgoodies.looks.Options;
/**
* A combo-box and a manage button that will add selected strings to an
* associated entry editor.
*
* Used to manage keywords and authors for instance.
*
* @author $Author$
* @version $Revision$ ($Date$)
*
*/
public class FieldContentSelector extends JComponent {
JComboBox comboBox;
FieldEditor editor;
MetaData metaData;
JabRefFrame frame;
Window owner;
BasePanel panel;
private AbstractAction action;
String delimiter;
/**
*
* Create a new FieldContentSelector.
*
* @param frame
* The one JabRef-Frame.
* @param panel
* The basepanel the entry-editor is on.
* @param owner
* The window/frame/dialog which should be the owner of the
* content selector dialog.
* @param editor
* The entry editor which will be appended by the text selected
* by the user from the combobox.
* @param metaData
* The metadata that contains the list of items to display in the
* combobox under the key Globals.SELECTOR_META_PREFIX +
* editor.getFieldName().
* @param action
* The action that will be performed to after an item from the
* combobox has been appended to the text in the entryeditor.
* @param horizontalLayout
* Whether to put a 2 pixel horizontal strut between combobox and
* button.
*/
public FieldContentSelector(JabRefFrame frame, final BasePanel panel,
Window owner, final FieldEditor editor, final MetaData metaData,
final AbstractAction action, boolean horizontalLayout, String delimiter) {
this.frame = frame;
this.editor = editor;
this.metaData = metaData;
this.panel = panel;
this.owner = owner;
this.action = action;
this.delimiter = delimiter;
comboBox = new JComboBox() {
public Dimension getPreferredSize() {
Dimension parents = super.getPreferredSize();
if (parents.width > GUIGlobals.MAX_CONTENT_SELECTOR_WIDTH)
parents.width = GUIGlobals.MAX_CONTENT_SELECTOR_WIDTH;
return parents;
}
};
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints con = new GridBagConstraints();
setLayout(gbl);
// comboBox.setEditable(true);
comboBox.setMaximumRowCount(35);
// Set the width of the popup independent of the size of th box itself:
comboBox.putClientProperty(Options.COMBO_POPUP_PROTOTYPE_DISPLAY_VALUE_KEY,
"The longest text in the combo popup menu. And even longer.");
rebuildComboBox();
con.gridwidth = horizontalLayout ? 3 : GridBagConstraints.REMAINDER;
con.fill = GridBagConstraints.HORIZONTAL;
con.weightx = 1;
gbl.setConstraints(comboBox, con);
comboBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/*
* These conditions signify arrow key navigation in the dropdown
* list, so we should not react to it. I'm not sure if this is
* well defined enough to be guaranteed to work everywhere.
*/
if (e.getActionCommand().equals("comboBoxChanged") && (e.getModifiers() == 0))
return;
selectionMade();
}
});
// Add an action for the Enter key that signals a selection:
comboBox.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "enter");
comboBox.getActionMap().put("enter", new AbstractAction() {
public void actionPerformed(ActionEvent actionEvent) {
selectionMade();
comboBox.setPopupVisible(false);
}
});
add(comboBox);
if (horizontalLayout)
add(Box.createHorizontalStrut(Sizes.dialogUnitXAsPixel(2, this)));
JButton manage = new JButton(Globals.lang("Manage"));
gbl.setConstraints(manage, con);
add(manage);
manage.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ContentSelectorDialog2 csd = new ContentSelectorDialog2(FieldContentSelector.this.owner, FieldContentSelector.this.frame, panel, true, metaData, editor.getFieldName());
Util.placeDialog(csd, FieldContentSelector.this.frame);
// Calling setVisible(true) will open the modal dialog and block
// for the dialog to close.
csd.setVisible(true);
// So we need to rebuild the ComboBox afterwards
rebuildComboBox();
}
});
}
private void selectionMade() {
// The first element is only for show.
// CO: Why?
if (comboBox.getSelectedIndex() == 0)
return;
String chosen = (String) comboBox.getSelectedItem();
if (chosen == null || chosen.equals(""))
return;
// The following is not possible at the moment since the
// combobox cannot be edited!
// User edited in a new word. Add it.
// if (comboBox.getSelectedIndex() == -1)
// addWord(chosen);
// TODO: could improve checking as not do add the same item twice
if (!editor.getText().equals(""))
editor.append(FieldContentSelector.this.delimiter);
editor.append(chosen);
comboBox.setSelectedIndex(0);
// Fire event that we changed the editor
if (action != null)
action.actionPerformed(new ActionEvent(editor, 0, ""));
// Transfer focus to the editor.
editor.requestFocus();
}
void rebuildComboBox() {
comboBox.removeAllItems();
// TODO: CO - What for?
comboBox.addItem("");
Vector<String> items = metaData.getData(Globals.SELECTOR_META_PREFIX + editor.getFieldName());
if (items != null) {
Iterator<String> i = items.iterator();
while (i.hasNext())
comboBox.addItem(i.next());
}
}
// Not used since the comboBox is not editable
// /**
// * Adds a word to the selector (to the JList and to the MetaData), unless it
// * is already there
// *
// * @param newWord
// * String Word to add
// */
// public void addWord(String newWord) {
//
// Vector items = metaData.getData(Globals.SELECTOR_META_PREFIX + editor.getFieldName());
// boolean exists = false;
// int pos = -1;
// for (int i = 0; i < items.size(); i++) {
// String s = (String) items.elementAt(i);
// if (s.equals(newWord)) {
// exists = true;
// break;
// }
// if (s.toLowerCase().compareTo(newWord.toLowerCase()) < 0)
// pos = i + 1;
// }
// if (!exists) {
// items.add(Math.max(0, pos), newWord);
// // TODO CO: Why is this non-undoable?
// panel.markNonUndoableBaseChanged();
// panel.updateAllContentSelectors();
// }
// }
}