| // 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(); |
| } |
| } |
| } |
| } |