package org.limewire.ui.swing.search.advanced;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import javax.swing.Action;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.Resource;
import org.limewire.core.api.FilePropertyKey;
import org.limewire.core.api.library.FriendAutoCompleterFactory;
import org.limewire.core.api.search.SearchCategory;
import org.limewire.ui.swing.action.AbstractAction;
import org.limewire.ui.swing.components.BasicAutoCompleter;
import org.limewire.ui.swing.components.CollectionBackedComboBoxModel;
import org.limewire.ui.swing.components.DropDownListAutoCompleteControl;
import org.limewire.ui.swing.components.FilteredDocument;
import org.limewire.ui.swing.components.TextFieldClipboardControl;
import org.limewire.ui.swing.util.FilePropertyKeyUtils;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
/** An abstract panel for creating advanced searches. */
abstract class AdvancedPanel extends JPanel {
private final Map<FilePropertyKey, JComponent> componentMap =
new EnumMap<FilePropertyKey, JComponent>(FilePropertyKey.class);
private final SearchCategory category;
private final FriendAutoCompleterFactory friendAutoCompleterFactory;
private final Action enterKeyAction;
private Component firstComponent;
/**
* Resource package since this class is abstract.
*/
private static class Resources {
@Resource(key="AdvancedPanel.font") public Font font;
public Resources() {
GuiUtils.assignResources(this);
}
}
private final Resources resources = new Resources();
/**
* Constructs an AdvancedPanel that will search the given category.
*/
public AdvancedPanel(SearchCategory category, FriendAutoCompleterFactory friendAutoCompleterFactory, Action enterKeyAction) {
super(new MigLayout("fillx", "[]related[grow]", ""));
this.category = category;
this.friendAutoCompleterFactory = friendAutoCompleterFactory;
this.enterKeyAction = enterKeyAction;
GuiUtils.assignResources(this);
}
/**
* Adds a new JTextField that will search using the given FilePropertyKey using
* the default for the description text.
*/
protected void addField(FilePropertyKey key) {
addField(I18n.tr(FilePropertyKeyUtils.getUntraslatedDisplayName(key, category)), key);
}
/**
* Adds a new JTextField that will search using the given FilePropertyKey.
*/
private void addField(String description, FilePropertyKey key) {
JLabel label = new JLabel(description);
label.setFont(resources.font);
add(label);
JTextField textField = new JTextField();
TextFieldClipboardControl.install(textField);
FilteredDocument.configure(textField, key);
addEnterAction(textField);
textField.setFont(resources.font);
final DropDownListAutoCompleteControl autoCompleteControl = DropDownListAutoCompleteControl.install(textField, new BasicAutoCompleter(friendAutoCompleterFactory.getDictionary(category, key)));
autoCompleteControl.setAutoComplete(true);
add(textField, "growx, wrap");
componentMap.put(key, textField);
setFirstComponent(textField);
}
private void addEnterAction(JComponent component) {
component.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "pressed");
component.getActionMap().put("pressed", new AbstractAction("pressed") {
public void actionPerformed(ActionEvent e) {
if(enterKeyAction != null) {
enterKeyAction.actionPerformed(e);
}
}
});
}
/**
* Adds a new JTextField that will search using the given FilePropertyKey using
* the default for the description text.
* The contents of the combo are all the possible values.
*/
protected void addField(FilePropertyKey key, List<String> possibleValues) {
addField(I18n.tr(FilePropertyKeyUtils.getUntraslatedDisplayName(key, category)), key, possibleValues);
}
/**
* Adds a new JComboBox that will search using the given FilePropertyKey.
* The contents of the combo are all the possible values.
*/
private void addField(String name, FilePropertyKey key, List<String> possibleValues) {
JLabel label = new JLabel(name);
label.setFont(resources.font);
add(label);
JComboBox comboBox = new JComboBox(new CollectionBackedComboBoxModel(possibleValues));
addEnterAction(comboBox);
comboBox.setFont(resources.font);
add(comboBox, "growx, wrap");
componentMap.put(key, comboBox);
setFirstComponent(comboBox);
}
/**
* Gets a map between the key for each field with user data and that data.
*
* <p> Describes the requested advanced search request.
*/
public Map<FilePropertyKey, String> getSearchData() {
Map<FilePropertyKey, String> searchData = new EnumMap<FilePropertyKey, String>(FilePropertyKey.class);
for(Map.Entry<FilePropertyKey, JComponent> entry : componentMap.entrySet()) {
String value = getData(entry.getValue());
if(value != null && !value.trim().equals("")) {
searchData.put(entry.getKey(), value);
}
}
if(searchData.size() > 0) {
return searchData;
} else {
return null;
}
}
/**
* @return the {@link SearchCategory} that this panel represents.
*/
public SearchCategory getSearchCategory() {
return category;
}
private String getData(JComponent component) {
if(component instanceof JTextField) {
return ((JTextField)component).getText();
} else if(component instanceof JComboBox) {
return ((JComboBox)component).getSelectedItem().toString();
} else {
throw new IllegalStateException("invalid component: " + component);
}
}
/**
* Sets the first focusable component only if it is not already set.
*/
private void setFirstComponent(Component component) {
if (firstComponent == null && component.isFocusable()) {
firstComponent = component;
}
}
/**
* Requests focus on the first component in the panel.
*/
public boolean requestFocusFirstComponent() {
if (firstComponent != null) {
return firstComponent.requestFocusInWindow();
} else {
return false;
}
}
}