diff --git a/src/server/gwt/Fridge-compile b/src/server/gwt/Fridge-compile
new file mode 100644
index 000000000..1a421c5d5
--- /dev/null
+++ b/src/server/gwt/Fridge-compile
@@ -0,0 +1,17 @@
+#!/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
+
+if [ `uname` = "Darwin" ]; then
+ GWT_JAVA_OPTS=-XstartOnFirstThread
+fi
+
+java $GWT_JAVA_OPTS -Xmx256M -cp "$APPDIR/src:$APPDIR/bin:$GWT_CLASSPATH" com.google.gwt.dev.GWTCompiler -out "$APPDIR/www" "$@" se.chalmers.cs.gf.gwt.FridgeApp;
diff --git a/src/server/gwt/Fridge-shell-external b/src/server/gwt/Fridge-shell-external
new file mode 100644
index 000000000..b6261e63a
--- /dev/null
+++ b/src/server/gwt/Fridge-shell-external
@@ -0,0 +1,17 @@
+#!/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
+
+if [ `uname` = "Darwin" ]; then
+ GWT_JAVA_OPTS=-XstartOnFirstThread
+fi
+
+java $GWT_JAVA_OPTS -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.FridgeApp/Fridge.html;
diff --git a/src/server/gwt/FridgeApp.launch b/src/server/gwt/FridgeApp.launch
new file mode 100644
index 000000000..69acf02d0
--- /dev/null
+++ b/src/server/gwt/FridgeApp.launch
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/server/gwt/TranslateApp.launch b/src/server/gwt/TranslateApp.launch
index 400ecca5c..8eff471c2 100644
--- a/src/server/gwt/TranslateApp.launch
+++ b/src/server/gwt/TranslateApp.launch
@@ -1,16 +1,21 @@
-
-
+
+
+
+
+
+
+
-
-
+
+
-
+
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/FridgeApp.gwt.xml b/src/server/gwt/src/se/chalmers/cs/gf/gwt/FridgeApp.gwt.xml
new file mode 100644
index 000000000..c1a7fbf0e
--- /dev/null
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/FridgeApp.gwt.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/FridgeApp.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/FridgeApp.java
new file mode 100644
index 000000000..b2dc0a6c7
--- /dev/null
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/FridgeApp.java
@@ -0,0 +1,235 @@
+package se.chalmers.cs.gf.gwt.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+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.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.PushButton;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+
+public class FridgeApp implements EntryPoint {
+
+ private static final String pgfBaseURL = "/pgf";
+
+ private PGF pgf;
+
+ private FlowPanel textPanel;
+ private Panel bagPanel;
+ private SettingsPanel settingsPanel;
+ private VerticalPanel outputPanel;
+ private StatusPopup statusPopup;
+
+ //
+ // Translation
+ //
+
+ private void translate() {
+ outputPanel.clear();
+ setStatus("Translating...");
+ pgf.translate(settingsPanel.getGrammarName(),
+ getText(),
+ settingsPanel.getInputLanguages(), null,
+ settingsPanel.getOutputLanguages(),
+ new PGF.TranslateCallback() {
+ public void onResult (PGF.Translations translations) {
+ for (final PGF.Translation t : translations.iterable()) {
+ PushButton l = new PushButton(t.getText());
+ l.addStyleName("my-translation");
+ l.addClickListener(new ClickListener() {
+ public void onClick(Widget sender) {
+ setText(t.getTo(), t.getText());
+ }
+ });
+ PGF.Language lang = settingsPanel.getGrammar().getLanguage(t.getTo());
+ if (lang != null) {
+ l.getElement().setLang(lang.getLanguageCode());
+ }
+ outputPanel.add(l);
+ }
+ clearStatus();
+ }
+ public void onError (Throwable e) {
+ showError("Translation failed", e);
+ }
+ });
+ }
+
+ //
+ // Magnets
+ //
+
+ private List getWords() {
+ List l = new ArrayList();
+ for (Widget w : textPanel) {
+ l.add(((Magnet)w).getText());
+ }
+ return l;
+ }
+
+ private String getText () {
+ StringBuilder sb = new StringBuilder();
+ for (String word : getWords()) {
+ if (sb.length() > 0) {
+ sb.append(' ');
+ }
+ sb.append(word);
+ }
+ return sb.toString();
+ }
+
+ private void setText (String language, String text) {
+ settingsPanel.setInputLanguages(Collections.singletonList(language));
+ textPanel.clear();
+ for (String word : text.split("\\s+")) {
+ textPanel.add(new Magnet(language, word));
+ }
+ updateBag();
+ }
+
+ private ClickListener magnetClickListener = new ClickListener () {
+ public void onClick(Widget sender) {
+ Magnet magnet = (Magnet)sender;
+ textPanel.add(new Magnet(magnet));
+ update();
+ }
+ };
+
+ private void updateBag () {
+ bagPanel.clear();
+ int limit = 100;
+ pgf.complete(settingsPanel.getGrammarName(),
+ getText() + " ",
+ settingsPanel.getInputLanguages(), null,
+ limit, new PGF.CompleteCallback() {
+ public void onResult(PGF.Completions completions) {
+ boolean empty = true;
+ List oldWords = getWords();
+ for (PGF.Completion completion : completions.iterable()) {
+ String[] newWords = completion.getText().split("\\s+");
+ if (newWords.length == oldWords.size()+1) {
+ String word = newWords[newWords.length-1];
+ bagPanel.add(new Magnet(completion.getFrom(), word, magnetClickListener));
+ empty = false;
+ }
+ }
+ if (empty) {
+ bagPanel.add(new Label(""));
+ }
+ }
+ public void onError(Throwable e) {
+ showError("Error getting completions.", e);
+ }
+ });
+ }
+
+ public void update() {
+ updateBag();
+ translate();
+ }
+
+ public void clear() {
+ textPanel.clear();
+ update();
+ }
+
+ public void deleteLastMagnet() {
+ int c = textPanel.getWidgetCount();
+ if (c > 0) {
+ textPanel.remove(c-1);
+ update();
+ }
+ }
+
+ //
+ // Status stuff
+ //
+
+ private void setStatus(String msg) {
+ statusPopup.setStatus(msg);
+ }
+
+ private void showError(String msg, Throwable e) {
+ statusPopup.showError(msg, e);
+ }
+
+ private void clearStatus() {
+ statusPopup.clearStatus();
+ }
+
+ //
+ // GUI
+ //
+
+ private void createTranslationUI() {
+
+ statusPopup = new StatusPopup();
+ setStatus("Loading...");
+
+ settingsPanel = new SettingsPanel(pgf);
+ settingsPanel.addSettingsListener(new SettingsPanel.SettingsListener() {
+ public void grammarChanged(String pgfName) {
+ }
+ public void languagesChanged(List inputLangs, List outputLangs) {
+ update();
+ }
+ public void settingsError(String msg, Throwable e) {
+ showError(msg,e);
+ }
+ });
+
+ Panel buttons = new HorizontalPanel();
+ buttons.add(new Button("Clear", new ClickListener () {
+ public void onClick(Widget sender) {
+ clear();
+ }
+ }));
+ buttons.add(new Button("Delete last", new ClickListener () {
+ public void onClick(Widget sender) {
+ deleteLastMagnet();
+ }
+ }));
+
+
+ outputPanel = new VerticalPanel();
+ outputPanel.addStyleName("my-translations");
+
+ textPanel = new FlowPanel();
+ textPanel.setStylePrimaryName("my-TextPanel");
+
+ bagPanel = new FlowPanel();
+ bagPanel.setStylePrimaryName("my-BagPanel");
+
+ VerticalPanel mainPanel = new VerticalPanel();
+ mainPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
+ mainPanel.setWidth("100%");
+ mainPanel.add(textPanel);
+ mainPanel.add(buttons);
+ mainPanel.add(bagPanel);
+ mainPanel.add(outputPanel);
+ mainPanel.add(settingsPanel);
+
+ RootPanel.get().add(mainPanel);
+
+ }
+
+ //
+ // Initialization
+ //
+
+ public void onModuleLoad() {
+ pgf = new PGF(pgfBaseURL);
+ createTranslationUI();
+ settingsPanel.updateAvailableGrammars();
+ }
+
+}
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/Magnet.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/Magnet.java
new file mode 100644
index 000000000..9f86a6747
--- /dev/null
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/Magnet.java
@@ -0,0 +1,66 @@
+package se.chalmers.cs.gf.gwt.client;
+
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.ClickListenerCollection;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.PushButton;
+import com.google.gwt.user.client.ui.SourcesClickEvents;
+import com.google.gwt.user.client.ui.Widget;
+
+public class Magnet extends Composite implements SourcesClickEvents {
+
+ private String language;
+
+ private String text;
+
+ private ClickListenerCollection clickListeners = null;
+
+ public Magnet(Magnet magnet) {
+ this(magnet.language, magnet.text);
+ }
+
+ public Magnet(String language, String text) {
+ this(language, text, null);
+ }
+
+ public Magnet(String language, String text, ClickListener listener) {
+ this.language = language;
+ this.text = text;
+ final PushButton button = new PushButton(text);
+ button.addClickListener(new ClickListener() {
+ public void onClick(Widget sender) {
+ button.setFocus(false);
+ fireClick();
+ }
+ });
+ initWidget(button);
+ addStyleName("my-Magnet");
+ if (listener != null) {
+ addClickListener(listener);
+ }
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void addClickListener(ClickListener listener) {
+ if (clickListeners == null) {
+ clickListeners = new ClickListenerCollection();
+ }
+ clickListeners.add(listener);
+ }
+
+ public void removeClickListener(ClickListener listener) {
+ if (clickListeners != null) {
+ clickListeners.remove(listener);
+ }
+ }
+
+ public void fireClick () {
+ if (clickListeners != null) {
+ clickListeners.fireClick(this);
+ }
+ }
+
+}
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/MultiListBox.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/MultiListBox.java
index ac09c751f..fafdf2646 100644
--- a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/MultiListBox.java
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/MultiListBox.java
@@ -1,24 +1,34 @@
package se.chalmers.cs.gf.gwt.client;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
import com.google.gwt.user.client.ui.ListBox;
-import java.util.ArrayList;
-import java.util.List;
-
public class MultiListBox extends ListBox {
- public MultiListBox() {
- }
-
- public List getSelectedValues() {
- int c = getItemCount();
- List l = new ArrayList();
- for (int i = 0; i < c; i++) {
- if (isItemSelected(i)) {
- l.add(getValue(i));
- }
+ public MultiListBox() {
+ }
+
+ public List getSelectedValues() {
+ int c = getItemCount();
+ List l = new ArrayList();
+ for (int i = 0; i < c; i++) {
+ if (isItemSelected(i)) {
+ l.add(getValue(i));
+ }
+ }
+ return l;
+ }
+
+ public void setSelectedValues(List values) {
+ Set vs = new HashSet(values);
+ int c = getItemCount();
+ for (int i = 0; i < c; i++) {
+ setItemSelected(i, vs.contains(getValue(i)));
+ }
}
- return l;
- }
}
\ No newline at end of file
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
index d97b64c1d..a9d38c6a8 100644
--- 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
@@ -105,6 +105,11 @@ public class PGF {
/* Completion */
+ /**
+ * Get suggestions for completing the input.
+ * @param limit The number of suggestions to get.
+ * If -1 is passed, all available suggestions are retrieved.
+ */
public JSONRequest complete (String pgfName, String input, List fromLangs, String cat, int limit, final CompleteCallback callback) {
List args = new ArrayList();
args.add(new Arg("input", input));
@@ -114,7 +119,9 @@ public class PGF {
}
}
args.add(new Arg("cat", cat));
- args.add(new Arg("limit", limit));
+ if (limit != -1) {
+ args.add(new Arg("limit", limit));
+ }
return sendGrammarRequest(pgfName, "complete", args, callback);
}
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/SettingsPanel.java b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/SettingsPanel.java
index 3f52b1fab..893bff8ff 100644
--- a/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/SettingsPanel.java
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/client/SettingsPanel.java
@@ -121,12 +121,16 @@ public class SettingsPanel extends Composite {
public List getInputLanguages() {
return fromLangBox.getSelectedValues();
- }
-
+ }
+
public List getOutputLanguages() {
return toLangBox.getSelectedValues();
}
+ public void setInputLanguages(List langs) {
+ fromLangBox.setSelectedValues(langs);
+ }
+
private void updateAvailableLanguages() {
pgf.grammar(getGrammarName(), new PGF.GrammarCallback() {
public void onResult(PGF.Grammar grammar) {
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.css b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.css
new file mode 100644
index 000000000..6d692d606
--- /dev/null
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.css
@@ -0,0 +1,32 @@
+.my-TextPanel, .my-BagPanel, .my-translations, .my-SettingsPanel {
+ margin: 1em;
+}
+
+.my-TextPanel {
+ font-size: 150%;
+ min-height: 2em;
+ border: 3px dashed silver;
+ overflow: auto;
+}
+
+.my-BagPanel {
+ border: 1px solid silver;
+ overflow: auto;
+}
+
+.my-Magnet {
+ float: left;
+ margin: 0.3em;
+ padding: 0.3em;
+}
+
+.my-translations {
+ border: 1px solid silver;
+}
+
+.my-translation {
+ margin: 0.2em;
+}
+
+.my-SettingsPanel {
+}
\ No newline at end of file
diff --git a/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.html b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.html
new file mode 100644
index 000000000..2686838f6
--- /dev/null
+++ b/src/server/gwt/src/se/chalmers/cs/gf/gwt/public/Fridge.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fridge
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+