Add SuggestOracle to SearchPanel
Remembering all of the possible search operators is tricky. Now we suggest them as the user types. Change-Id: I17c9dd7fb69bf6a0292fbcf496a8b539308229b9 Signed-off-by: Brad Larson <bklarson@gmail.com>
This commit is contained in:
committed by
Edwin Kempin
parent
e6ec46892f
commit
a54e150669
@@ -27,6 +27,8 @@ import com.google.gwt.event.shared.HandlerRegistration;
|
|||||||
import com.google.gwt.user.client.ui.Button;
|
import com.google.gwt.user.client.ui.Button;
|
||||||
import com.google.gwt.user.client.ui.Composite;
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
import com.google.gwt.user.client.ui.FlowPanel;
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
import com.google.gwt.user.client.ui.SuggestBox;
|
||||||
|
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
|
||||||
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
||||||
import com.google.gwtexpui.globalkey.client.KeyCommand;
|
import com.google.gwtexpui.globalkey.client.KeyCommand;
|
||||||
|
|
||||||
@@ -42,15 +44,22 @@ class SearchPanel extends Composite {
|
|||||||
searchBox = new HintTextBox();
|
searchBox = new HintTextBox();
|
||||||
searchBox.setVisibleLength(70);
|
searchBox.setVisibleLength(70);
|
||||||
searchBox.setHintText(Gerrit.C.searchHint());
|
searchBox.setHintText(Gerrit.C.searchHint());
|
||||||
|
final MySuggestionDisplay suggestionDisplay = new MySuggestionDisplay();
|
||||||
searchBox.addKeyPressHandler(new KeyPressHandler() {
|
searchBox.addKeyPressHandler(new KeyPressHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onKeyPress(final KeyPressEvent event) {
|
public void onKeyPress(final KeyPressEvent event) {
|
||||||
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
|
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
|
||||||
doSearch();
|
if (!suggestionDisplay.isSuggestionSelected) {
|
||||||
|
doSearch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final SuggestBox suggestBox =
|
||||||
|
new SuggestBox(new SearchSuggestOracle(), searchBox, suggestionDisplay);
|
||||||
|
searchBox.setStyleName("gwt-TextBox");
|
||||||
|
|
||||||
final Button searchButton = new Button(Gerrit.C.searchButton());
|
final Button searchButton = new Button(Gerrit.C.searchButton());
|
||||||
searchButton.addClickHandler(new ClickHandler() {
|
searchButton.addClickHandler(new ClickHandler() {
|
||||||
@Override
|
@Override
|
||||||
@@ -59,7 +68,7 @@ class SearchPanel extends Composite {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
body.add(searchBox);
|
body.add(suggestBox);
|
||||||
body.add(searchButton);
|
body.add(searchButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,4 +115,15 @@ class SearchPanel extends Composite {
|
|||||||
Gerrit.display(PageLinks.toChangeQuery(query), QueryScreen.forQuery(query));
|
Gerrit.display(PageLinks.toChangeQuery(query), QueryScreen.forQuery(query));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class MySuggestionDisplay extends SuggestBox.DefaultSuggestionDisplay {
|
||||||
|
private boolean isSuggestionSelected;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Suggestion getCurrentSelection() {
|
||||||
|
Suggestion currentSelection = super.getCurrentSelection();
|
||||||
|
isSuggestionSelected = currentSelection != null;
|
||||||
|
return currentSelection;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright (C) 2012 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package com.google.gerrit.client;
|
||||||
|
|
||||||
|
import com.google.gwt.user.client.ui.SuggestOracle;
|
||||||
|
import com.google.gwtexpui.safehtml.client.HighlightSuggestOracle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
public class SearchSuggestOracle extends HighlightSuggestOracle {
|
||||||
|
private static final TreeSet<String> suggestions = new TreeSet<String>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
suggestions.add("age:");
|
||||||
|
suggestions.add("age:1week"); // Give an example age
|
||||||
|
|
||||||
|
suggestions.add("change:");
|
||||||
|
|
||||||
|
suggestions.add("owner:");
|
||||||
|
suggestions.add("owner:self");
|
||||||
|
suggestions.add("ownerin:");
|
||||||
|
|
||||||
|
suggestions.add("reviewer:");
|
||||||
|
suggestions.add("reviewer:self");
|
||||||
|
suggestions.add("reviewerin:");
|
||||||
|
|
||||||
|
suggestions.add("commit:");
|
||||||
|
suggestions.add("project:");
|
||||||
|
suggestions.add("branch:");
|
||||||
|
suggestions.add("topic:");
|
||||||
|
suggestions.add("ref:");
|
||||||
|
suggestions.add("tr:");
|
||||||
|
suggestions.add("bug:");
|
||||||
|
suggestions.add("label:");
|
||||||
|
suggestions.add("message:");
|
||||||
|
suggestions.add("file:");
|
||||||
|
|
||||||
|
suggestions.add("has:");
|
||||||
|
suggestions.add("has:draft");
|
||||||
|
suggestions.add("has:star");
|
||||||
|
|
||||||
|
suggestions.add("is:");
|
||||||
|
suggestions.add("is:starred");
|
||||||
|
suggestions.add("is:watched");
|
||||||
|
suggestions.add("is:reviewed");
|
||||||
|
suggestions.add("is:owner");
|
||||||
|
suggestions.add("is:reviewer");
|
||||||
|
suggestions.add("is:open");
|
||||||
|
suggestions.add("is:draft");
|
||||||
|
suggestions.add("is:closed");
|
||||||
|
suggestions.add("is:submitted");
|
||||||
|
suggestions.add("is:merged");
|
||||||
|
suggestions.add("is:abandoned");
|
||||||
|
|
||||||
|
suggestions.add("status:");
|
||||||
|
suggestions.add("status:open");
|
||||||
|
suggestions.add("status:reviewed");
|
||||||
|
suggestions.add("status:submitted");
|
||||||
|
suggestions.add("status:closed");
|
||||||
|
suggestions.add("status:merged");
|
||||||
|
suggestions.add("status:abandoned");
|
||||||
|
|
||||||
|
suggestions.add("AND");
|
||||||
|
suggestions.add("OR");
|
||||||
|
suggestions.add("NOT");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestDefaultSuggestions(Request request, Callback done) {
|
||||||
|
final ArrayList<SearchSuggestion> r = new ArrayList<SearchSuggestOracle.SearchSuggestion>();
|
||||||
|
// No text - show some default suggestions.
|
||||||
|
r.add(new SearchSuggestion("status:open", "status:open"));
|
||||||
|
r.add(new SearchSuggestion("age:1week", "age:1week"));
|
||||||
|
if (Gerrit.isSignedIn()) {
|
||||||
|
r.add(new SearchSuggestion("owner:self", "owner:self"));
|
||||||
|
}
|
||||||
|
done.onSuggestionsReady(request, new Response(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRequestSuggestions(Request request, Callback done) {
|
||||||
|
final String query = request.getQuery();
|
||||||
|
int lastSpace = query.lastIndexOf(' ');
|
||||||
|
final String lastWord;
|
||||||
|
// NOTE: this method is not called if the query is empty.
|
||||||
|
if (lastSpace == query.length() - 1) {
|
||||||
|
// Starting a new word - don't show suggestions yet.
|
||||||
|
done.onSuggestionsReady(request, null);
|
||||||
|
return;
|
||||||
|
} else if (lastSpace == -1) {
|
||||||
|
lastWord = query;
|
||||||
|
} else {
|
||||||
|
lastWord = query.substring(lastSpace + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArrayList<SearchSuggestion> r = new ArrayList<SearchSuggestOracle.SearchSuggestion>();
|
||||||
|
for (String suggestion : suggestions.tailSet(lastWord)) {
|
||||||
|
if ((lastWord.length() < suggestion.length()) && suggestion.startsWith(lastWord)) {
|
||||||
|
if (suggestion.contains("self") && !Gerrit.isSignedIn()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r.add(new SearchSuggestion(suggestion, query + suggestion.substring(lastWord.length())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done.onSuggestionsReady(request, new Response(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SearchSuggestion implements SuggestOracle.Suggestion {
|
||||||
|
private final String suggestion;
|
||||||
|
private final String fullQuery;
|
||||||
|
public SearchSuggestion(String suggestion, String fullQuery) {
|
||||||
|
this.suggestion = suggestion;
|
||||||
|
// Add a space to the query if it is a complete operation (e.g.
|
||||||
|
// "status:open") so the user can keep on typing.
|
||||||
|
this.fullQuery = fullQuery.endsWith(":") ? fullQuery : fullQuery + " ";
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getDisplayString() {
|
||||||
|
return suggestion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReplacementString() {
|
||||||
|
return fullQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,9 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
|
|||||||
private static final Pattern PAT_LABEL =
|
private static final Pattern PAT_LABEL =
|
||||||
Pattern.compile("^[a-zA-Z][a-zA-Z0-9]*((=|>=|<=)[+-]?|[+-])\\d+$");
|
Pattern.compile("^[a-zA-Z][a-zA-Z0-9]*((=|>=|<=)[+-]?|[+-])\\d+$");
|
||||||
|
|
||||||
|
// NOTE: As new search operations are added, please keep the
|
||||||
|
// SearchSuggestOracle up to date.
|
||||||
|
|
||||||
public static final String FIELD_AGE = "age";
|
public static final String FIELD_AGE = "age";
|
||||||
public static final String FIELD_BRANCH = "branch";
|
public static final String FIELD_BRANCH = "branch";
|
||||||
public static final String FIELD_CHANGE = "change";
|
public static final String FIELD_CHANGE = "change";
|
||||||
|
|||||||
Reference in New Issue
Block a user