diff --git a/src/server/gwt-client/Translate-compile b/src/server/gwt-client/Translate-compile
new file mode 100644
index 000000000..d98e10016
--- /dev/null
+++ b/src/server/gwt-client/Translate-compile
@@ -0,0 +1,3 @@
+#!/bin/sh
+APPDIR=`dirname $0`;
+java -XstartOnFirstThread -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:/Users/bringert/src/gwt-mac-1.5.2/gwt-user.jar:/Users/bringert/src/gwt-mac-1.5.2/gwt-dev-mac.jar" com.google.gwt.dev.GWTCompiler -out "$APPDIR/www" "$@" se.chalmers.cs.gf.gwt_translate.Translate;
diff --git a/src/server/gwt-client/Translate-shell b/src/server/gwt-client/Translate-shell
new file mode 100644
index 000000000..668700d52
--- /dev/null
+++ b/src/server/gwt-client/Translate-shell
@@ -0,0 +1,3 @@
+#!/bin/sh
+APPDIR=`dirname $0`;
+java -XstartOnFirstThread -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:/Users/bringert/src/gwt-mac-1.5.2/gwt-user.jar:/Users/bringert/src/gwt-mac-1.5.2/gwt-dev-mac.jar" com.google.gwt.dev.GWTShell -out "$APPDIR/www" "$@" se.chalmers.cs.gf.gwt_translate.Translate/Translate.html;
diff --git a/src/server/gwt-client/Translate-shell-external b/src/server/gwt-client/Translate-shell-external
new file mode 100644
index 000000000..aaa6bb45a
--- /dev/null
+++ b/src/server/gwt-client/Translate-shell-external
@@ -0,0 +1,3 @@
+#!/bin/sh
+APPDIR=`dirname $0`;
+java -XstartOnFirstThread -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:/Users/bringert/src/gwt-mac-1.5.2/gwt-user.jar:/Users/bringert/src/gwt-mac-1.5.2/gwt-dev-mac.jar" com.google.gwt.dev.GWTShell -out "$APPDIR/www" -noserver "$@" http://localhost/~bringert/gwt-client/se.chalmers.cs.gf.gwt_translate.Translate/Translate.html;
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/Translate.gwt.xml b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/Translate.gwt.xml
new file mode 100644
index 000000000..49b229a66
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/Translate.gwt.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/CompletionOracle.java b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/CompletionOracle.java
new file mode 100644
index 000000000..2e496eb7b
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/CompletionOracle.java
@@ -0,0 +1,46 @@
+package se.chalmers.cs.gf.gwt_translate.client;
+
+import com.google.gwt.user.client.ui.SuggestOracle;
+
+import java.util.*;
+
+public class CompletionOracle extends SuggestOracle {
+
+ private GF gf;
+
+ public CompletionOracle (String gfBaseURL) {
+ gf = new GF(gfBaseURL);
+ }
+
+ public static class CompletionSuggestion implements SuggestOracle.Suggestion {
+ private String string;
+ public CompletionSuggestion(String string) {
+ this.string = string;
+ }
+
+ public String getDisplayString() {
+ return string;
+ }
+
+ public String getReplacementString() {
+ return string + " ";
+ }
+ }
+
+ public void requestSuggestions(final SuggestOracle.Request request, final SuggestOracle.Callback callback) {
+ gf.complete(request.getQuery(), request.getLimit(), new GF.CompleteCallback() {
+ public void onCompleteDone(GF.Completions completions) {
+ Collection suggestions = new ArrayList();
+ for (String lang : completions.getCompletionLanguages()) {
+ int c = completions.countCompletions(lang);
+ for (int i = 0; i < c; i++) {
+ String text = request.getQuery() + " " + completions.getCompletion(lang,i);
+ suggestions.add(new CompletionSuggestion(text));
+ }
+ }
+ callback.onSuggestionsReady(request, new SuggestOracle.Response(suggestions));
+ }
+ });
+ }
+
+}
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/GF.java b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/GF.java
new file mode 100644
index 000000000..99fb2e275
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/GF.java
@@ -0,0 +1,103 @@
+package se.chalmers.cs.gf.gwt_translate.client;
+
+import com.google.gwt.http.client.*;
+import com.google.gwt.core.client.GWT;
+
+import com.google.gwt.json.client.JSONValue;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONParser;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+
+public class GF {
+
+ private String baseURL;
+
+ public GF (String baseURL) {
+ this.baseURL = baseURL;
+ }
+
+ /* Translation */
+
+
+ /* Completion */
+
+ public void complete (String text, int count, final CompleteCallback callback) {
+ Map args = new HashMap();
+ args.put("input",text);
+ // args.put("from",);
+ // args.put("cat",);
+ // args.put("count",);
+ sendRequest("complete", args, new JSONRequestCallback() {
+ public void onJSONReceived(JSONValue json) {
+ callback.onCompleteDone(new Completions(json));
+ }
+ });
+ }
+
+ public static final class Completions {
+ private final JSONObject completions;
+ public Completions (JSONValue json) {
+ this.completions = json.isObject();
+ }
+ public final Set getCompletionLanguages() { return completions.keySet(); }
+ public final int countCompletions(String lang) {
+ JSONValue cs = completions.get(lang);
+ return cs == null ? 0 : cs.isArray().size();
+ }
+ public final String getCompletion(String lang, int i) {
+ JSONValue cs = completions.get(lang);
+ return cs == null ? null : cs.isArray().get(i).isString().stringValue();
+ }
+ }
+
+ public interface CompleteCallback {
+ public void onCompleteDone (Completions completions);
+ }
+
+
+ /* Utilities */
+
+ public interface JSONRequestCallback {
+ public void onJSONReceived(JSONValue json);
+ }
+
+ private void sendRequest (String resource, Map vars, final JSONRequestCallback callback) {
+ String url = baseURL + "/" + resource + "?" + buildQueryString(vars);
+ RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
+
+ try {
+ Request request = builder.sendRequest(null, new RequestCallback() {
+ public void onError(Request request, Throwable e) {
+ GWT.log("onError called", e);
+ }
+
+ public void onResponseReceived(Request request, Response response) {
+ if (200 == response.getStatusCode()) {
+ callback.onJSONReceived(JSONParser.parse(response.getText()));
+ } else {
+ GWT.log("Response not OK: " + response.getStatusCode(), null);
+ }
+ }
+ });
+ } catch (RequestException e) {
+ GWT.log("Failed to send request", e);
+ }
+ }
+
+ private static String buildQueryString(Map vars) {
+ StringBuffer sb = new StringBuffer();
+ for (Map.Entry e : vars.entrySet()) {
+ if (sb.length() > 0) {
+ sb.append("&");
+ }
+ sb.append(URL.encodeComponent(e.getKey()));
+ sb.append("=");
+ sb.append(URL.encodeComponent(e.getValue()));
+ }
+ return sb.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/Translate.java b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/Translate.java
new file mode 100644
index 000000000..71eaf422d
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/client/Translate.java
@@ -0,0 +1,60 @@
+package se.chalmers.cs.gf.gwt_translate.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
+
+import com.google.gwt.user.client.Window;
+
+public class Translate implements EntryPoint {
+
+ private SuggestBox suggest;
+ private Grid outputTable;
+
+ private void translate() {
+ outputTable.resizeRows(3);
+ outputTable.setText(0, 1, suggest.getText());
+ outputTable.setText(1, 1, suggest.getText());
+ outputTable.setText(2, 1, suggest.getText());
+ }
+
+ public void onModuleLoad() {
+
+ suggest = new SuggestBox(new CompletionOracle("http://localhost/~bringert/gf-server/gf.fcgi"));
+ suggest.setWidth("50em");
+ suggest.addKeyboardListener(new KeyboardListenerAdapter() {
+ public void onKeyUp (Widget sender, char keyCode, int modifiers) {
+ if (keyCode == KEY_ENTER) {
+ translate();
+ }
+ }
+ });
+
+ Button translateButton = new Button("Translate");
+ translateButton.addClickListener(new ClickListener() {
+ public void onClick(Widget sender) {
+ translate();
+ }
+ });
+
+ outputTable = new Grid(0, 2);
+
+ VerticalPanel vPanel = new VerticalPanel();
+ vPanel.setWidth("100%");
+ vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
+ vPanel.add(suggest);
+ vPanel.add(translateButton);
+ vPanel.add(outputTable);
+
+ RootPanel.get().add(vPanel);
+
+ }
+}
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.css b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.css
new file mode 100644
index 000000000..3cf302fd6
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.css
@@ -0,0 +1,12 @@
+/** Add css rules here for your application. */
+
+
+/** Example rules used by the template application (remove for your app) */
+.pc-template-btn {
+ display: block;
+ font-size: 16pt
+}
+
+#pc-template-img {
+ margin-top: 20px;
+}
diff --git a/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.html b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.html
new file mode 100644
index 000000000..d9bd6cef9
--- /dev/null
+++ b/src/server/gwt-client/src/se/chalmers/cs/gf/gwt_translate/public/Translate.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Translate
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+