blob: d66d6a60b2f564e9e85ba7346953bcf6f0f07f21 [file] [log] [blame]
// Copyright (C) 2010 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.ui;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.SuggestOracle;
/**
* Delegates to a slow SuggestOracle, such as a remote server API.
*
* <p>A response is only supplied to the UI if no requests were made after the oracle begin that
* request.
*
* <p>When a request is made while the delegate is still processing a prior request all intermediate
* requests are discarded and the most recent request is queued. The pending request's response is
* discarded and the most recent request is started.
*/
public class RemoteSuggestOracle extends SuggestOracle {
private final SuggestOracle oracle;
private Query query;
private String last;
private Timer requestRetentionTimer;
private boolean cancelOutstandingRequest;
private boolean serveSuggestions;
public RemoteSuggestOracle(SuggestOracle src) {
oracle = src;
}
public String getLast() {
return last;
}
@Override
public void requestSuggestions(Request req, Callback cb) {
if (!serveSuggestions) {
return;
}
// Use a timer for key stroke retention, such that we don't query the
// backend for each and every keystroke we receive.
if (requestRetentionTimer != null) {
requestRetentionTimer.cancel();
}
requestRetentionTimer =
new Timer() {
@Override
public void run() {
Query q = new Query(req, cb);
if (query == null) {
query = q;
q.start();
} else {
query = q;
}
}
};
requestRetentionTimer.schedule(200);
}
@Override
public void requestDefaultSuggestions(Request req, Callback cb) {
requestSuggestions(req, cb);
}
@Override
public boolean isDisplayStringHTML() {
return oracle.isDisplayStringHTML();
}
public void cancelOutstandingRequest() {
if (requestRetentionTimer != null) {
requestRetentionTimer.cancel();
}
if (query != null) {
cancelOutstandingRequest = true;
}
}
public void setServeSuggestions(boolean serveSuggestions) {
this.serveSuggestions = serveSuggestions;
}
private class Query implements Callback {
final Request request;
final Callback callback;
Query(Request req, Callback cb) {
request = req;
callback = cb;
}
void start() {
oracle.requestSuggestions(request, this);
}
@Override
public void onSuggestionsReady(Request req, Response res) {
if (cancelOutstandingRequest || !serveSuggestions) {
// If cancelOutstandingRequest() was called, we ignore this response
cancelOutstandingRequest = false;
query = null;
} else if (query == this) {
// No new request was started while this query was running.
// Propose this request's response as the suggestions.
query = null;
last = request.getQuery();
callback.onSuggestionsReady(req, res);
} else {
// Another query came in while this one was running. Skip
// this response and start the most recent query.
query.start();
}
}
}
}