diff options
Diffstat (limited to 'src/server/gwt')
10 files changed, 670 insertions, 0 deletions
diff --git a/src/server/gwt/Translate-compile b/src/server/gwt/Translate-compile new file mode 100644 index 000000000..608f17e99 --- /dev/null +++ b/src/server/gwt/Translate-compile @@ -0,0 +1,13 @@ +#!/bin/sh + +APPDIR=`dirname $0`; + +if [ -z "$GWT_CLASSPATH" ]; then + echo 'ERROR: $GWT_CLASSPATH is not set' + echo 'Set $GWT_CLASSPATH to point to the GWT JAR files. For example:' + echo 'export GWT_DIR="/Users/bringert/src/gwt-mac-1.5.2"' + echo 'export GWT_CLASSPATH="$GWT_DIR/gwt-user.jar:$GWT_DIR/gwt-dev-mac.jar"' + exit 1 +fi + +java -XstartOnFirstThread -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:$GWT_CLASSPATH" com.google.gwt.dev.GWTCompiler -out "$APPDIR/www" "$@" se.chalmers.cs.gf.gwt.TranslateApp; diff --git a/src/server/gwt/Translate-shell-external b/src/server/gwt/Translate-shell-external new file mode 100644 index 000000000..78a258ec5 --- /dev/null +++ b/src/server/gwt/Translate-shell-external @@ -0,0 +1,13 @@ +#!/bin/sh + +APPDIR=`dirname $0`; + +if [ -z "$GWT_CLASSPATH" ]; then + echo 'ERROR: $GWT_CLASSPATH is not set' + echo 'Set $GWT_CLASSPATH to point to the GWT JAR files. For example:' + echo 'export GWT_DIR="/Users/bringert/src/gwt-mac-1.5.2"' + echo 'export GWT_CLASSPATH="$GWT_DIR/gwt-user.jar:$GWT_DIR/gwt-dev-mac.jar"' + exit 1 +fi + +java -XstartOnFirstThread -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:$GWT_CLASSPATH" com.google.gwt.dev.GWTShell -out "$APPDIR/www" -noserver "$@" http://localhost:41296/gwt/www/se.chalmers.cs.gf.gwt.TranslateApp/Translate.html; diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/PGF.gwt.xml b/src/server/gwt/src/se/chalmers/cs/gf/gwt/PGF.gwt.xml new file mode 100644 index 000000000..959f16040 --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/PGF.gwt.xml @@ -0,0 +1,8 @@ +<module> + + <!-- Inherit the core Web Toolkit stuff. --> + <inherits name="com.google.gwt.user.User" /> + <inherits name="com.google.gwt.http.HTTP" /> + <inherits name="com.google.gwt.json.JSON" /> + +</module> diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/TranslateApp.gwt.xml b/src/server/gwt/src/se/chalmers/cs/gf/gwt/TranslateApp.gwt.xml new file mode 100644 index 000000000..3f35d1bef --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/TranslateApp.gwt.xml @@ -0,0 +1,24 @@ +<module> + + <!-- Inherit the core Web Toolkit stuff. --> + <inherits name="com.google.gwt.user.User" /> + + <inherits name="se.chalmers.cs.gf.gwt.PGF" /> + + <!-- Inherit the default GWT style sheet. You can change --> + <!-- the theme of your GWT application by uncommenting --> + <!-- any one of the following lines. --> + <inherits name="com.google.gwt.user.theme.standard.Standard"/> + <!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> --> + <!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> --> + + <!-- Other module inherits --> + + + <!-- Specify the app entry point class. --> + <entry-point class="se.chalmers.cs.gf.gwt.client.TranslateApp" /> + + <!-- Specify the application specific style sheet. --> + <stylesheet src="Translate.css" /> + +</module> diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/CompletionOracle.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/CompletionOracle.java new file mode 100644 index 000000000..1073eed67 --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/CompletionOracle.java @@ -0,0 +1,84 @@ +package se.chalmers.cs.gf.gwt.client; + +import com.google.gwt.user.client.ui.SuggestOracle; + +import com.google.gwt.core.client.GWT; + +import java.util.*; + +public class CompletionOracle extends SuggestOracle { + + private PGF pgf; + + private ErrorHandler errorHandler; + + private List<String> inputLangs = null; + + private PGFRequest pgfRequest = null; + + + public CompletionOracle (PGF pgf) { + this(pgf, null); + } + + public CompletionOracle (PGF pgf, ErrorHandler errorHandler) { + this.pgf = pgf; + this.errorHandler = errorHandler; + } + + public void setInputLangs(List<String> inputLangs) { + this.inputLangs = inputLangs; + } + + public List<String> getInputLangs() { + return inputLangs; + } + + public void setErrorHandler(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + public static interface ErrorHandler { + public void onError(Throwable e); + } + + 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) { + + // only allow a single completion request at a time + if (pgfRequest != null) + pgfRequest.cancel(); + + pgfRequest = pgf.complete(request.getQuery(), getInputLangs(), null, request.getLimit(), + new PGF.CompleteCallback() { + public void onResult(PGF.Completions completions) { + Collection<CompletionSuggestion> suggestions = new ArrayList<CompletionSuggestion>(); + for (int i = 0; i < completions.length(); i++) { + String text = completions.get(i).getText(); + suggestions.add(new CompletionSuggestion(text)); + } + callback.onSuggestionsReady(request, new SuggestOracle.Response(suggestions)); + } + + public void onError(Throwable e) { + errorHandler.onError(e); + } + + }); + } + +} diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGF.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGF.java new file mode 100644 index 000000000..daf97c7ae --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGF.java @@ -0,0 +1,221 @@ +package se.chalmers.cs.gf.gwt.client; + +import com.google.gwt.http.client.*; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JsArray; +import com.google.gwt.core.client.JavaScriptObject; + +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.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.ArrayList; + +public class PGF { + + private String baseURL; + private String pgfName; + + public PGF (String baseURL, String pgfName) { + this.baseURL = baseURL; + this.pgfName = pgfName; + } + + public static interface GFCallback<T extends JavaScriptObject> { + public void onResult (T result) ; + public void onError (Throwable e) ; + } + + public static class IterableJsArray<T extends JavaScriptObject> extends JsArray<T> { + protected IterableJsArray() {} + + public final Iterable<T> iterable() { + return new Iterable<T>() { + public Iterator<T> iterator() { + return new Iterator<T>() { + private int i = 0; + public boolean hasNext() { + return i < length(); + } + public T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return get(i++); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + } + + /* Grammar */ + + public PGFRequest grammar (final GrammarCallback callback) { + return sendRequest("grammar", null, callback); + } + + public interface GrammarCallback extends GFCallback<Grammar> { } + + public static class Grammar extends JavaScriptObject { + protected Grammar() { } + + public final native String getName() /*-{ return this.name; }-*/; + + public final native String getUserLanguage() /*-{ return this.userLanguage; }-*/; + + public final native IterableJsArray<Language> getLanguages() /*-{ return this.languages; }-*/; + + public final Language getLanguage(String name) { + int c = getLanguages().length(); + for (int i = 0; i < c; i++) { + Language l = getLanguages().get(i); + if (l.getName().equals(name)) + return l; + } + return null; + } + } + + public static class Language extends JavaScriptObject { + protected Language() { } + + public final native String getName() /*-{ return this.name; }-*/; + public final native String getLanguageCode() /*-{ return this.languageCode; }-*/; + public final native boolean canParse() /*-{ return this.canParse; }-*/; + } + + /* Translation */ + + public PGFRequest translate (String input, List<String> fromLangs, String cat, List<String> toLangs, + final TranslateCallback callback) { + List<Arg> args = new ArrayList<Arg>(); + args.add(new Arg("input", input)); + if (fromLangs != null) { + for (String from : fromLangs) { + args.add(new Arg("from", from)); + } + } + args.add(new Arg("cat", cat)); + if (toLangs != null) { + for (String to : toLangs) { + args.add(new Arg("to", to)); + } + } + return sendRequest("translate", args, callback); + } + + public interface TranslateCallback extends GFCallback<Translations> { } + + public static class Translations extends IterableJsArray<Translation> { + protected Translations() { } + } + + public static class Translation extends JavaScriptObject { + protected Translation() { } + + public final native String getFrom() /*-{ return this.from; }-*/; + public final native String getTo() /*-{ return this.to; }-*/; + public final native String getText() /*-{ return this.text; }-*/; + } + + /* Completion */ + + public PGFRequest complete (String input, List<String> fromLangs, String cat, int limit, final CompleteCallback callback) { + List<Arg> args = new ArrayList<Arg>(); + args.add(new Arg("input", input)); + if (fromLangs != null) { + for (String from : fromLangs) { + args.add(new Arg("from", from)); + } + } + args.add(new Arg("cat", cat)); + args.add(new Arg("limit", limit)); + return sendRequest("complete", args, callback); + } + + public interface CompleteCallback extends GFCallback<Completions> { } + + public static class Completions extends IterableJsArray<Translation> { + protected Completions() { } + } + + public static class Completion extends JavaScriptObject { + protected Completion() { } + + public final native String getFrom() /*-{ return this.from; }-*/; + public final native String getText() /*-{ return this.text; }-*/; + } + + /* Utilities */ + + private <T extends JavaScriptObject> PGFRequest sendRequest (String resource, List<Arg> vars, final GFCallback<T> callback) { + String url = baseURL + "/" + pgfName + "/" + resource + "?" + buildQueryString(vars); + RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); + builder.setTimeoutMillis(30000); + builder.setHeader("Accept","text/plain, text/html;q=0.5, */*;q=0.1"); + Request request = null; + + try { + request = builder.sendRequest(null, new RequestCallback() { + public void onError(Request request, Throwable e) { + callback.onError(e); + } + + public void onResponseReceived(Request request, Response response) { + if (200 == response.getStatusCode()) { + callback.onResult((T)eval(response.getText()).cast()); + } else { + RequestException e = new RequestException("Response not OK: " + response.getStatusCode() + ". " + response.getText()); + callback.onError(e); + } + } + }); + } catch (RequestException e) { + callback.onError(e); + } + + return new PGFRequest(request); + } + + private static native JavaScriptObject eval(String json) /*-{ + return eval('(' + json + ')'); + }-*/; + + private static class Arg { + public final String name; + public final String value; + public Arg (String name, String value) { + this.name = name; + this.value = value; + } + public Arg (String name, int value) { + this(name, Integer.toString(value)); + } + } + + private static String buildQueryString(List<Arg> args) { + StringBuffer sb = new StringBuffer(); + if (args != null) { + for (Arg arg : args) { + if (arg.value != null) { + if (sb.length() > 0) { + sb.append("&"); + } + sb.append(URL.encodeComponent(arg.name)); + sb.append("="); + sb.append(URL.encodeComponent(arg.value)); + } + } + } + return sb.toString(); + } + +}
\ No newline at end of file diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGFRequest.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGFRequest.java new file mode 100644 index 000000000..b46ad9382 --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/PGFRequest.java @@ -0,0 +1,19 @@ +package se.chalmers.cs.gf.gwt.client; + +import com.google.gwt.http.client.*; + +public class PGFRequest { + + private Request httpRequest; + + PGFRequest (Request httpRequest) { + this.httpRequest = httpRequest; + } + + public void cancel() { + if (httpRequest != null) { + httpRequest.cancel(); + } + } + +}
\ No newline at end of file diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/TranslateApp.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/TranslateApp.java new file mode 100644 index 000000000..fd92713c3 --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/TranslateApp.java @@ -0,0 +1,214 @@ +package se.chalmers.cs.gf.gwt.client; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ChangeListener; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.DockPanel; +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.HorizontalPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.PopupPanel; +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.core.client.GWT; + +import com.google.gwt.user.client.Window; + +import com.google.gwt.i18n.client.LocaleInfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class TranslateApp implements EntryPoint { + + private static final String pgfBaseURL = "/pgf"; + private static final String pgfName = "grammar.pgf"; + + private PGF pgf; + + private CompletionOracle oracle; + private SuggestBox suggest; + private PGF.Grammar grammar; + private ListBox fromLangBox; + private ListBox toLangBox; + private Button translateButton; + private VerticalPanel outputPanel; + private PopupPanel statusPopup; + private Label statusLabel; + + private void addTranslation(String text, String toLang) { + Label l = new Label(text); + l.addStyleName("my-translation"); + PGF.Language lang = grammar.getLanguage(toLang); + if (lang != null) { + l.getElement().setLang(lang.getLanguageCode()); + } + outputPanel.add(l); + } + + private void translate() { + outputPanel.clear(); + setStatus("Translating..."); + pgf.translate(suggest.getText(), listBoxSelection(fromLangBox), null, + listBoxSelection(toLangBox), new PGF.TranslateCallback() { + public void onResult (PGF.Translations translations) { + for (PGF.Translation t : translations.iterable()) { + addTranslation(t.getText(), t.getTo()); + } + clearStatus(); + } + public void onError (Throwable e) { + showError("Translation failed", e); + } + }); + } + + private void updateLangs() { + oracle.setInputLangs(listBoxSelection(fromLangBox)); + } + + private List<String> listBoxSelection(ListBox box) { + int c = box.getItemCount(); + List<String> l = new ArrayList<String>(); + for (int i = 0; i < c; i++) { + if (box.isItemSelected(i)) { + l.add(box.getValue(i)); + } + } + return l; + } + + private void setStatus(String msg) { + statusLabel.setText(msg); + statusPopup.center(); + } + + private void showError(String msg, Throwable e) { + GWT.log(msg, e); + setStatus(msg); + } + + private void clearStatus() { + statusPopup.hide(); + } + + private void setGrammar(PGF.Grammar grammar) { + this.grammar = grammar; + + for (PGF.Language l : grammar.getLanguages().iterable()) { + String name = l.getName(); + if (l.canParse()) { + fromLangBox.addItem(name); + if (name.equals(grammar.getUserLanguage())) { + fromLangBox.setSelectedIndex(fromLangBox.getItemCount()-1); + } + } + toLangBox.addItem(name); + } + + updateLangs(); + clearStatus(); + fromLangBox.setEnabled(true); + toLangBox.setEnabled(true); + translateButton.setEnabled(true); + } + + private void createTranslationUI() { + + oracle = new CompletionOracle(pgf, new CompletionOracle.ErrorHandler() { + public void onError(Throwable e) { + showError("Completion failed", e); + } + }); + + suggest = new SuggestBox(oracle); + suggest.addKeyboardListener(new KeyboardListenerAdapter() { + public void onKeyUp (Widget sender, char keyCode, int modifiers) { + if (keyCode == KEY_ENTER) { + translate(); + } + } + }); + + fromLangBox = new ListBox(); + fromLangBox.setEnabled(false); + fromLangBox.addItem("Any language", ""); + fromLangBox.addChangeListener(new ChangeListener() { + public void onChange(Widget sender) { + updateLangs(); + translate(); + } + }); + + toLangBox = new ListBox(); + toLangBox.setEnabled(false); + toLangBox.addItem("All languages", ""); + toLangBox.addChangeListener(new ChangeListener() { + public void onChange(Widget sender) { + updateLangs(); + translate(); + } + }); + + translateButton = new Button("Translate"); + translateButton.setEnabled(false); + translateButton.addClickListener(new ClickListener() { + public void onClick(Widget sender) { + translate(); + } + }); + + HorizontalPanel settingsPanel = new HorizontalPanel(); + settingsPanel.addStyleName("my-settingsPanel"); + settingsPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE); + settingsPanel.add(new Label("From:")); + settingsPanel.add(fromLangBox); + settingsPanel.add(new Label("To:")); + settingsPanel.add(toLangBox); + settingsPanel.add(translateButton); + + outputPanel = new VerticalPanel(); + outputPanel.addStyleName("my-translations"); + + VerticalPanel vPanel = new VerticalPanel(); + vPanel.setWidth("100%"); + vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER); + vPanel.add(suggest); + vPanel.add(settingsPanel); + vPanel.add(outputPanel); + + RootPanel.get().add(vPanel); + + } + + public void onModuleLoad() { + statusLabel = new Label("Loading..."); + statusPopup = new PopupPanel(true, true); + statusPopup.add(statusLabel); + statusPopup.center(); + + pgf = new PGF(pgfBaseURL, pgfName); + + createTranslationUI(); + + pgf.grammar(new PGF.GrammarCallback() { + public void onResult(PGF.Grammar grammar) { + setGrammar(grammar); + } + + public void onError (Throwable e) { + showError("Error getting language information", e); + } + }); + } + +} diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.css b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.css new file mode 100644 index 000000000..5b5d22023 --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.css @@ -0,0 +1,38 @@ +/** Add css rules here for your application. */ + +.gwt-SuggestBox { + width: 70%; + font-size: 150%; + margin: 1em 0 0.5em 0; +} + +.my-settingsPanel * { + margin: 0 0.4em; +} + +.my-translations { + margin-top: 1em; +} + +.my-translation { + margin: 0.2em; + padding-left: 25px; + font-size: 150%; + background-repeat: no-repeat; + background-position: 0% 50%; +} + +/* +* [LANG=bg] { background-image: url("flags/bg.png"); } +* [LANG=ca] { background-image: url("flags/catalonia.png"); } +* [LANG=da] { background-image: url("flags/dk.png"); } +* [LANG=de] { background-image: url("flags/de.png"); } +* [LANG=en] { background-image: url("flags/gb.png"); } +* [LANG=fi] { background-image: url("flags/fi.png"); } +* [LANG=fr] { background-image: url("flags/fr.png"); } +* [LANG=it] { background-image: url("flags/it.png"); } +* [LANG=no] { background-image: url("flags/no.png"); } +* [LANG=ru] { background-image: url("flags/ru.png"); } +* [LANG=es] { background-image: url("flags/es.png"); } +* [LANG=sv] { background-image: url("flags/se.png"); } +*/
\ No newline at end of file diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.html b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.html new file mode 100644 index 000000000..f3fc1da8c --- /dev/null +++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Translate.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- The HTML 4.01 Transitional DOCTYPE declaration--> +<!-- above set at the top of the file will set --> +<!-- the browser's rendering engine into --> +<!-- "Quirks Mode". Replacing this declaration --> +<!-- with a "Standards Mode" doctype is supported, --> +<!-- but may lead to some differences in layout. --> + +<html> + <head> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <!-- --> + <!-- Any title is fine --> + <!-- --> + <title>Translate</title> + + <!-- --> + <!-- This script loads your compiled module. --> + <!-- If you add any GWT meta tags, they must --> + <!-- be added before this line. --> + <!-- --> + <script type="text/javascript" language="javascript" src="se.chalmers.cs.gf.gwt.TranslateApp.nocache.js"></script> + </head> + + <!-- --> + <!-- The body can have arbitrary html, or --> + <!-- you can leave the body empty if you want --> + <!-- to create a completely dynamic UI. --> + <!-- --> + <body> + + <!-- OPTIONAL: include this if you want history support --> + <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe> + + </body> +</html> |
