* improved auto-completion
This commit is contained in:
parent
4346a6e05b
commit
ab14e07924
|
@ -8,7 +8,6 @@ import java.awt.Window;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -34,6 +33,7 @@ import net.sourceforge.tuned.ui.LabelProvider;
|
||||||
import net.sourceforge.tuned.ui.SelectButtonTextField;
|
import net.sourceforge.tuned.ui.SelectButtonTextField;
|
||||||
import net.sourceforge.tuned.ui.TunedUtilities;
|
import net.sourceforge.tuned.ui.TunedUtilities;
|
||||||
import ca.odell.glazedlists.EventList;
|
import ca.odell.glazedlists.EventList;
|
||||||
|
import ca.odell.glazedlists.matchers.TextMatcherEditor;
|
||||||
import ca.odell.glazedlists.swing.AutoCompleteSupport;
|
import ca.odell.glazedlists.swing.AutoCompleteSupport;
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public abstract class AbstractSearchPanel<S, E> extends FileBotPanel {
|
||||||
searchTextField.getSelectButton().setModel(createSearchEngines());
|
searchTextField.getSelectButton().setModel(createSearchEngines());
|
||||||
searchTextField.getSelectButton().setLabelProvider(createSearchEngineLabelProvider());
|
searchTextField.getSelectButton().setLabelProvider(createSearchEngineLabelProvider());
|
||||||
|
|
||||||
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory);
|
AutoCompleteSupport.install(searchTextField.getEditor(), searchHistory).setFilterMode(TextMatcherEditor.CONTAINS);
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ENTER"), searchAction);
|
||||||
}
|
}
|
||||||
|
@ -150,14 +150,30 @@ public abstract class AbstractSearchPanel<S, E> extends FileBotPanel {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// choose search result
|
Collection<? extends SearchResult> results = get();
|
||||||
requestProcessor.setSearchResult(requestProcessor.selectSearchResult(get(), SwingUtilities.getWindowAncestor(AbstractSearchPanel.this)));
|
|
||||||
|
|
||||||
if (requestProcessor.getSearchResult() == null) {
|
SearchResult selectedSearchResult = null;
|
||||||
|
|
||||||
|
switch (results.size()) {
|
||||||
|
case 0:
|
||||||
|
Logger.getLogger("ui").log(Level.WARNING, String.format("'%s' has not been found.", requestProcessor.request.getSearchText()));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
selectedSearchResult = results.iterator().next();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
selectedSearchResult = requestProcessor.selectSearchResult(results, SwingUtilities.getWindowAncestor(AbstractSearchPanel.this));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSearchResult == null) {
|
||||||
tab.close();
|
tab.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set search result
|
||||||
|
requestProcessor.setSearchResult(selectedSearchResult);
|
||||||
|
|
||||||
String historyEntry = requestProcessor.getHistoryEntry();
|
String historyEntry = requestProcessor.getHistoryEntry();
|
||||||
|
|
||||||
if (historyEntry != null && !searchHistory.contains(historyEntry)) {
|
if (historyEntry != null && !searchHistory.contains(historyEntry)) {
|
||||||
|
@ -324,28 +340,6 @@ public abstract class AbstractSearchPanel<S, E> extends FileBotPanel {
|
||||||
|
|
||||||
|
|
||||||
protected SearchResult selectSearchResult(Collection<? extends SearchResult> searchResults, Window window) throws Exception {
|
protected SearchResult selectSearchResult(Collection<? extends SearchResult> searchResults, Window window) throws Exception {
|
||||||
|
|
||||||
switch (searchResults.size()) {
|
|
||||||
case 0:
|
|
||||||
Logger.getLogger("ui").warning(String.format("'%s' has not been found.", request.getSearchText()));
|
|
||||||
return null;
|
|
||||||
case 1:
|
|
||||||
return searchResults.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SearchResult> exactMatches = new LinkedList<SearchResult>();
|
|
||||||
|
|
||||||
// find exact matches
|
|
||||||
for (SearchResult result : searchResults) {
|
|
||||||
if (result.getName().toLowerCase().startsWith(request.getSearchText().toLowerCase())) {
|
|
||||||
exactMatches.add(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exactMatches.size() == 1) {
|
|
||||||
return exactMatches.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiple results have been found, user must select one
|
// multiple results have been found, user must select one
|
||||||
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, searchResults);
|
SelectDialog<SearchResult> selectDialog = new SelectDialog<SearchResult>(window, searchResults);
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,21 @@ import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.DefaultListCellRenderer;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JList;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
import javax.swing.border.LineBorder;
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.event.DocumentEvent;
|
||||||
|
import javax.swing.event.DocumentListener;
|
||||||
import javax.swing.plaf.basic.BasicComboBoxUI;
|
import javax.swing.plaf.basic.BasicComboBoxUI;
|
||||||
import javax.swing.plaf.basic.BasicComboPopup;
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
import javax.swing.plaf.basic.ComboPopup;
|
import javax.swing.plaf.basic.ComboPopup;
|
||||||
|
@ -41,6 +48,7 @@ public class SelectButtonTextField<T> extends JComponent {
|
||||||
add(selectButton, "h pref!, w pref!, sizegroupy this");
|
add(selectButton, "h pref!, w pref!, sizegroupy this");
|
||||||
add(editor, "gap 0, w 195px!, sizegroupy this");
|
add(editor, "gap 0, w 195px!, sizegroupy this");
|
||||||
|
|
||||||
|
editor.setRenderer(new CompletionCellRenderer());
|
||||||
editor.setUI(new TextFieldComboBoxUI());
|
editor.setUI(new TextFieldComboBoxUI());
|
||||||
|
|
||||||
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
|
TunedUtilities.putActionForKeystroke(this, KeyStroke.getKeyStroke("ctrl UP"), new SpinClientAction(-1));
|
||||||
|
@ -87,6 +95,37 @@ public class SelectButtonTextField<T> extends JComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class CompletionCellRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
|
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||||
|
|
||||||
|
setBorder(new EmptyBorder(1, 4, 1, 4));
|
||||||
|
|
||||||
|
String highlightText = SelectButtonTextField.this.getText().substring(0, ((TextFieldComboBoxUI) editor.getUI()).getEditor().getSelectionStart());
|
||||||
|
|
||||||
|
// highlight the matching sequence
|
||||||
|
Matcher matcher = Pattern.compile(highlightText, Pattern.LITERAL | Pattern.CASE_INSENSITIVE).matcher(value.toString());
|
||||||
|
|
||||||
|
// use no-break, because we really don't want line-wrapping in our table cells
|
||||||
|
StringBuffer htmlText = new StringBuffer("<html><nobr>");
|
||||||
|
|
||||||
|
if (matcher.find()) {
|
||||||
|
matcher.appendReplacement(htmlText, "<span style='font-weight: bold; text-decoration: underline;'>$0</span>");
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher.appendTail(htmlText);
|
||||||
|
|
||||||
|
htmlText.append("</nobr></html>");
|
||||||
|
|
||||||
|
setText(htmlText.toString());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private class TextFieldComboBoxUI extends BasicComboBoxUI {
|
private class TextFieldComboBoxUI extends BasicComboBoxUI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,6 +153,27 @@ public class SelectButtonTextField<T> extends JComponent {
|
||||||
editor.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
|
editor.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
|
||||||
|
|
||||||
editor.addFocusListener(createFocusListener());
|
editor.addFocusListener(createFocusListener());
|
||||||
|
|
||||||
|
editor.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changedUpdate(DocumentEvent e) {
|
||||||
|
popup.getList().repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertUpdate(DocumentEvent e) {
|
||||||
|
popup.getList().repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUpdate(DocumentEvent e) {
|
||||||
|
popup.getList().repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,9 +212,10 @@ public class SelectButtonTextField<T> extends JComponent {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void focusLost(FocusEvent e) {
|
public void focusLost(FocusEvent e) {
|
||||||
if (isPopupVisible(comboBox))
|
if (isPopupVisible(comboBox)) {
|
||||||
setPopupVisible(comboBox, false);
|
setPopupVisible(comboBox, false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue