mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-09 04:59:31 -06:00
initial import of the new GF editor. Note: the FridgeApp is temporary broken. It will be fixed with the next patch
This commit is contained in:
@@ -13,8 +13,10 @@
|
||||
<!-- <inherits name="com.google.gwt.user.theme.chrome.Chrome"/> -->
|
||||
<!-- <inherits name="com.google.gwt.user.theme.dark.Dark"/> -->
|
||||
|
||||
<!-- Other module inherits -->
|
||||
|
||||
<replace-with class="org.grammaticalframework.ui.gwt.client.selection.support.InternetExplorerSelectionSupport">
|
||||
<when-type-is class="org.grammaticalframework.ui.gwt.client.selection.support.SelectionSupport"/>
|
||||
<when-property-is name="user.agent" value="ie6"/>
|
||||
</replace-with>
|
||||
|
||||
<!-- Specify the app entry point class. -->
|
||||
<entry-point class="org.grammaticalframework.ui.gwt.client.EditorApp" />
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
import com.google.gwt.user.client.History;
|
||||
import com.google.gwt.user.client.HistoryListener;
|
||||
import com.google.gwt.user.client.Command;
|
||||
import com.google.gwt.user.client.DeferredCommand;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import com.google.gwt.http.client.*;
|
||||
import com.google.gwt.xml.client.*;
|
||||
import com.google.gwt.event.logical.shared.*;
|
||||
|
||||
public class BrowsePanel extends Composite {
|
||||
|
||||
private PGFWrapper pgf;
|
||||
private HTML sourceView;
|
||||
private SuggestBox searchBox;
|
||||
private CompletionOracle oracle;
|
||||
private List<String> identifiers = null;
|
||||
|
||||
public BrowsePanel(PGFWrapper pgf) {
|
||||
this.pgf = pgf;
|
||||
|
||||
oracle = new CompletionOracle();
|
||||
|
||||
HorizontalPanel browsePanel = new HorizontalPanel();
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.add(createSearchPanel(oracle));
|
||||
vPanel.add(createTreeView());
|
||||
browsePanel.add(vPanel);
|
||||
browsePanel.add(createSourcePanel());
|
||||
browsePanel.setCellWidth(sourceView,"100%");
|
||||
|
||||
initWidget(browsePanel);
|
||||
setStylePrimaryName("my-BrowsePanel");
|
||||
|
||||
pgf.addSettingsListener(new MySettingsListener(pgf));
|
||||
}
|
||||
|
||||
public native void onActivate() /*-{
|
||||
$doc.browsePanel = this;
|
||||
$doc.callBrowse = @org.grammaticalframework.ui.gwt.client.BrowsePanel::callBrowse(Lorg/grammaticalframework/ui/gwt/client/BrowsePanel;Ljava/lang/String;);
|
||||
}-*/;
|
||||
|
||||
protected Widget createSearchPanel(CompletionOracle oracle) {
|
||||
searchBox = new SuggestBox(oracle);
|
||||
searchBox.setLimit(10);
|
||||
searchBox.addKeyboardListener(new KeyboardListenerAdapter() {
|
||||
public void onKeyUp (Widget sender, char keyCode, int modifiers) {
|
||||
if (keyCode == KEY_ENTER) {
|
||||
callBrowse(BrowsePanel.this,searchBox.getText());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
DecoratorPanel decorator = new DecoratorPanel();
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.add(new Label("Search"));
|
||||
vPanel.add(searchBox);
|
||||
decorator.add(vPanel);
|
||||
return decorator;
|
||||
}
|
||||
|
||||
private static void callBrowse(BrowsePanel panel, String id) {
|
||||
panel.browse(id);
|
||||
History.newItem("browse:"+id);
|
||||
}
|
||||
|
||||
public void browse(final String id) {
|
||||
if (id == null || id.equals("")) {
|
||||
sourceView.setHTML("");
|
||||
return;
|
||||
}
|
||||
|
||||
pgf.browse(id, "javascript:document.callBrowse(document.browsePanel,'$ID')",
|
||||
"my-identifierLink",
|
||||
new RequestCallback() {
|
||||
public void onResponseReceived(Request request, Response response) {
|
||||
sourceView.setHTML(response.getText());
|
||||
}
|
||||
|
||||
public void onError(Request request, java.lang.Throwable exception) {
|
||||
// errorHandler.onError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected Widget createTreeView() {
|
||||
hierarchyTree = new Tree();
|
||||
hierarchyTree.addSelectionHandler(new SelectionHandler<TreeItem>() {
|
||||
public void onSelection(SelectionEvent<TreeItem> event) {
|
||||
TreeItem item = event.getSelectedItem();
|
||||
callBrowse(BrowsePanel.this,item.getText());
|
||||
}
|
||||
});
|
||||
return hierarchyTree;
|
||||
}
|
||||
|
||||
protected Widget createSourcePanel() {
|
||||
sourceView = new HTML();
|
||||
sourceView.setStylePrimaryName("source");
|
||||
return sourceView;
|
||||
}
|
||||
|
||||
protected class CompletionOracle extends SuggestOracle {
|
||||
|
||||
public CompletionOracle() {
|
||||
}
|
||||
|
||||
public void requestSuggestions(SuggestOracle.Request request, SuggestOracle.Callback callback) {
|
||||
List<CompletionSuggestion> list = new ArrayList();
|
||||
|
||||
int index = Collections.binarySearch(identifiers, request.getQuery());
|
||||
index = (index >= 0) ? index : -(index+1);
|
||||
|
||||
for (; index < identifiers.size(); index++) {
|
||||
String id = identifiers.get(index);
|
||||
|
||||
if (id.startsWith(request.getQuery())) {
|
||||
list.add(new CompletionSuggestion(id));
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
if (list.size() > request.getLimit())
|
||||
break;
|
||||
}
|
||||
|
||||
callback.onSuggestionsReady(request, new SuggestOracle.Response(list));
|
||||
}
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
}
|
||||
|
||||
Tree hierarchyTree = null;
|
||||
|
||||
protected void reloadHierarchyTree() {
|
||||
hierarchyTree.clear();
|
||||
|
||||
final String url = pgf.getGrammarURL()+".xml";
|
||||
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
|
||||
try
|
||||
{
|
||||
builder.sendRequest(null, new RequestCallback() {
|
||||
public void onResponseReceived(Request request, Response response)
|
||||
{
|
||||
if (200 == response.getStatusCode())
|
||||
{
|
||||
try
|
||||
{
|
||||
Document browseDoc = XMLParser.parse(response.getText());
|
||||
|
||||
TreeLoader loader = new TreeLoader();
|
||||
|
||||
Element element = browseDoc.getDocumentElement();
|
||||
NodeList children = element.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node instanceof Element) {
|
||||
Element childElement = (Element) node;
|
||||
TreeItem childItem = hierarchyTree.addItem(childElement.getAttribute("name"));
|
||||
loader.push(childElement, childItem);
|
||||
}
|
||||
}
|
||||
|
||||
loader.execute();
|
||||
}
|
||||
catch (DOMException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(Request request, Throwable e)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (RequestException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TreeLoader implements Command {
|
||||
private int count = 0;
|
||||
private ArrayList<Element> elements = new ArrayList<Element>();
|
||||
private ArrayList<TreeItem> items = new ArrayList<TreeItem>();
|
||||
|
||||
public void execute() {
|
||||
for (int n = 0; n < 100; n++) {
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
int index = --count;
|
||||
Element element = (Element) elements.remove(index);
|
||||
TreeItem item = (TreeItem) items.remove(index);
|
||||
|
||||
NodeList children = element.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node instanceof Element) {
|
||||
Element childElement = (Element) node;
|
||||
TreeItem childItem = item.addItem(childElement.getAttribute("name"));
|
||||
push(childElement, childItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
DeferredCommand.addCommand(this);
|
||||
}
|
||||
|
||||
public final void push(Element element, TreeItem item) {
|
||||
elements.add(element);
|
||||
items.add(item);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
protected class MySettingsListener implements PGFWrapper.SettingsListener {
|
||||
|
||||
private PGFWrapper pgf;
|
||||
|
||||
public MySettingsListener(PGFWrapper pgf) {
|
||||
this.pgf = pgf;
|
||||
}
|
||||
|
||||
public void onAvailableGrammarsChanged() { }
|
||||
public void onSelectedGrammarChanged()
|
||||
{
|
||||
List<String> ids = new ArrayList();
|
||||
|
||||
for (int i = 0; i < pgf.getCategories().length(); i++) {
|
||||
ids.add(pgf.getCategories().get(i));
|
||||
}
|
||||
for (int i = 0; i < pgf.getFunctions().length(); i++) {
|
||||
ids.add(pgf.getFunctions().get(i));
|
||||
}
|
||||
|
||||
Collections.sort(ids);
|
||||
|
||||
identifiers = ids;
|
||||
sourceView.setText("");
|
||||
searchBox.setText("");
|
||||
reloadHierarchyTree();
|
||||
}
|
||||
public void onInputLanguageChanged() { }
|
||||
public void onOutputLanguageChanged() { }
|
||||
public void onStartCategoryChanged() { }
|
||||
public void onSettingsError(String msg, Throwable e) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.core.client.*;
|
||||
import com.google.gwt.user.client.*;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import com.google.gwt.event.dom.client.*;
|
||||
import com.google.gwt.event.logical.shared.*;
|
||||
import com.google.gwt.event.shared.*;
|
||||
|
||||
public class EditorApp implements EntryPoint {
|
||||
|
||||
protected static final String pgfBaseURL = "/grammars";
|
||||
|
||||
protected PGFWrapper pgf;
|
||||
|
||||
protected VerticalPanel outputPanel;
|
||||
protected Widget translatePanel;
|
||||
protected BrowsePanel browsePanel;
|
||||
protected QueryPanel queryPanel;
|
||||
protected StatusPopup statusPopup;
|
||||
protected TextInputPanel textPanel;
|
||||
protected FridgeBagPanel bagPanel;
|
||||
protected MagnetFactory magnetFactory;
|
||||
|
||||
private JSONRequest completeRequest = null;
|
||||
private JSONRequest translateRequest = null;
|
||||
|
||||
private int maxMagnets = 100;
|
||||
private static final int LIMIT_SCALE_FACTOR = 4;
|
||||
|
||||
private String cachedPrefix = null;
|
||||
private List<Magnet> cachedMagnets = Collections.emptyList();
|
||||
|
||||
//
|
||||
// Update
|
||||
//
|
||||
protected void update() {
|
||||
clearMagnetCache();
|
||||
updateBag("");
|
||||
updateTranslation();
|
||||
}
|
||||
|
||||
protected void clearMagnetCache() {
|
||||
cachedPrefix = null;
|
||||
cachedMagnets = Collections.emptyList();
|
||||
}
|
||||
|
||||
protected void updateTranslation() {
|
||||
if (translateRequest != null) {
|
||||
translateRequest.cancel();
|
||||
}
|
||||
|
||||
outputPanel.clear();
|
||||
outputPanel.addStyleDependentName("working");
|
||||
translateRequest = pgf.translate(textPanel.getText(),
|
||||
new PGF.TranslateCallback() {
|
||||
public void onResult (PGF.Translations translations) {
|
||||
translateRequest = null;
|
||||
|
||||
outputPanel.clear();
|
||||
outputPanel.removeStyleDependentName("working");
|
||||
for (PGF.TranslationResult tr : translations.iterable()) {
|
||||
textPanel.renderBracketedString(tr.getBracketedString());
|
||||
|
||||
if (tr.getTranslations() != null)
|
||||
for (PGF.Translation t : tr.getTranslations().iterable()) {
|
||||
LinearizationsPanel lin = new LinearizationsPanel(pgf, t.getTree(), t.getLinearizations());
|
||||
lin.setWidth("100%");
|
||||
outputPanel.add(lin);
|
||||
}
|
||||
|
||||
if (tr.getTypeErrors() != null && tr.getTypeErrors().length > 0) {
|
||||
for (PGF.TcError error : tr.getTypeErrors()) {
|
||||
VerticalPanel panel = new VerticalPanel();
|
||||
panel.addStyleName("my-typeError");
|
||||
Label errLabel = new Label("Type Error");
|
||||
errLabel.addStyleName("title");
|
||||
panel.add(errLabel);
|
||||
panel.add(createErrorMsg(error));
|
||||
outputPanel.add(panel);
|
||||
}
|
||||
textPanel.showError(tr.getTypeErrors()[0].getFId());
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onError (Throwable e) {
|
||||
translateRequest = null;
|
||||
|
||||
showError("Translation failed", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class Callback {
|
||||
private String prefix;
|
||||
|
||||
public Callback(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public void onResult(List<Magnet> magnets) {
|
||||
bagPanel.fill(magnets);
|
||||
|
||||
if (magnets.size() == 0) {
|
||||
if (prefix.isEmpty()) {
|
||||
textPanel.hideSearchBox();
|
||||
textPanel.setFocus(true);
|
||||
}
|
||||
else
|
||||
textPanel.showSearchError();
|
||||
} else {
|
||||
textPanel.clearSearchError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBag(String prefix) {
|
||||
Callback callback = new Callback(prefix);
|
||||
List<Magnet> magnets = filterCachedMagnets(prefix);
|
||||
if (magnets != null)
|
||||
callback.onResult(magnets);
|
||||
else
|
||||
retrieveMagnets(prefix, callback);
|
||||
}
|
||||
|
||||
public List<Magnet> filterCachedMagnets(final String prefix) {
|
||||
if (prefix.length() > 0 && cachedPrefix != null && prefix.startsWith(cachedPrefix)) {
|
||||
// If the prefix had no completions, there is no way that the current input will.
|
||||
if (cachedMagnets.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Magnet> magnets = new ArrayList<Magnet>();
|
||||
for (Magnet magnet : cachedMagnets) {
|
||||
if (magnet.getWord().startsWith(prefix)) {
|
||||
magnets.add(magnet);
|
||||
if (magnets.size() >= maxMagnets)
|
||||
return magnets;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void retrieveMagnets(final String prefix, final Callback callback) {
|
||||
final String query = textPanel.getText() + " " + prefix;
|
||||
|
||||
if (completeRequest != null) {
|
||||
completeRequest.cancel();
|
||||
}
|
||||
|
||||
bagPanel.clear();
|
||||
completeRequest = pgf.complete(query, LIMIT_SCALE_FACTOR * maxMagnets,
|
||||
new PGF.CompleteCallback() {
|
||||
public void onResult(PGF.Completions completions) {
|
||||
completeRequest = null;
|
||||
|
||||
cachedPrefix = query;
|
||||
cachedMagnets = new ArrayList<Magnet>();
|
||||
|
||||
for (PGF.Completion completion : completions.iterable()) {
|
||||
textPanel.renderBracketedString(completion.getBracketedString());
|
||||
if (completion.getCompletions() != null) {
|
||||
if (completion.getText() != prefix)
|
||||
textPanel.setSearchTerm(completion.getText());
|
||||
|
||||
for (String word : completion.getCompletions()) {
|
||||
Magnet magnet = magnetFactory.createMagnet(word, completion.getFrom());
|
||||
cachedMagnets.add(magnet);
|
||||
}
|
||||
} else {
|
||||
textPanel.setSearchTerm(completion.getText());
|
||||
}
|
||||
}
|
||||
|
||||
List<Magnet> magnets = new ArrayList<Magnet>();
|
||||
for (Magnet magnet : cachedMagnets) {
|
||||
magnets.add(magnet);
|
||||
if (magnets.size() >= maxMagnets)
|
||||
break;
|
||||
}
|
||||
callback.onResult(magnets);
|
||||
}
|
||||
|
||||
public void onError(Throwable e) {
|
||||
completeRequest = null;
|
||||
|
||||
showError("Getting completions failed", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Status stuff
|
||||
//
|
||||
|
||||
protected void setStatus(String msg) {
|
||||
statusPopup.setStatus(msg);
|
||||
}
|
||||
|
||||
protected void showError(String msg, Throwable e) {
|
||||
statusPopup.showError(msg, e);
|
||||
}
|
||||
|
||||
protected void clearStatus() {
|
||||
statusPopup.clearStatus();
|
||||
}
|
||||
|
||||
//
|
||||
// GUI
|
||||
//
|
||||
|
||||
protected Widget createUI() {
|
||||
translatePanel = createTranslatePanel();
|
||||
browsePanel = createBrowsePanel();
|
||||
queryPanel = createQueryPanel();
|
||||
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.setWidth("100%");
|
||||
vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
|
||||
|
||||
HorizontalPanel hPanel = new HorizontalPanel();
|
||||
hPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE);
|
||||
hPanel.setStylePrimaryName("my-HeaderPanel");
|
||||
|
||||
Widget linksPanel = createLinksPanel(vPanel);
|
||||
hPanel.add(linksPanel);
|
||||
hPanel.setCellHorizontalAlignment(linksPanel,HorizontalPanel.ALIGN_LEFT);
|
||||
|
||||
Widget settingsPanel = createSettingsPanel();
|
||||
hPanel.add(settingsPanel);
|
||||
hPanel.setCellHorizontalAlignment(settingsPanel,HorizontalPanel.ALIGN_RIGHT);
|
||||
|
||||
vPanel.add(hPanel);
|
||||
vPanel.add(translatePanel);
|
||||
|
||||
History.newItem("translate");
|
||||
History.addHistoryListener(new MyHistoryListener(vPanel));
|
||||
|
||||
return vPanel;
|
||||
}
|
||||
|
||||
protected Widget createSettingsPanel () {
|
||||
return new SettingsPanel(pgf);
|
||||
}
|
||||
|
||||
protected Widget createTranslatePanel() {
|
||||
textPanel = new TextInputPanel();
|
||||
textPanel.addValueChangeHandler(new ValueChangeHandler<String>() {
|
||||
public void onValueChange(ValueChangeEvent<String> event) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
textPanel.addSelectionHandler(new SelectionHandler<String>() {
|
||||
public void onSelection(SelectionEvent<String> event) {
|
||||
String prefix = event.getSelectedItem();
|
||||
char lastChar = prefix.charAt(prefix.length()-1);
|
||||
|
||||
Iterator<Magnet> iter = bagPanel.iterator();
|
||||
if ((Character.isSpace(lastChar) || lastChar == 160) && iter.hasNext()) {
|
||||
Magnet magnet = iter.next();
|
||||
textPanel.setSearchTerm("");
|
||||
textPanel.addMagnet(magnet);
|
||||
}
|
||||
else
|
||||
updateBag(prefix);
|
||||
}
|
||||
});
|
||||
|
||||
final ClickListener magnetClickListener = new ClickListener () {
|
||||
public void onClick(Widget widget) {
|
||||
Magnet magnet = (Magnet)widget;
|
||||
textPanel.hideSearchBox();
|
||||
textPanel.addMagnet(magnet);
|
||||
textPanel.setFocus(true);
|
||||
}
|
||||
};
|
||||
magnetFactory = new MagnetFactory(magnetClickListener);
|
||||
|
||||
bagPanel = new FridgeBagPanel();
|
||||
|
||||
outputPanel = new VerticalPanel();
|
||||
outputPanel.addStyleName("my-translations");
|
||||
|
||||
final DockPanel translatePanel = new DockPanel();
|
||||
translatePanel.setStyleName("my-TranslatePanel");
|
||||
translatePanel.add(textPanel, DockPanel.NORTH);
|
||||
translatePanel.add(bagPanel, DockPanel.CENTER);
|
||||
translatePanel.add(outputPanel, DockPanel.EAST);
|
||||
|
||||
translatePanel.setCellHeight(bagPanel, "100%");
|
||||
translatePanel.setCellWidth(bagPanel, "70%");
|
||||
translatePanel.setCellHeight(outputPanel, "100%");
|
||||
translatePanel.setCellWidth(outputPanel, "30%");
|
||||
translatePanel.setCellVerticalAlignment(bagPanel, HasVerticalAlignment.ALIGN_TOP);
|
||||
translatePanel.setCellHorizontalAlignment(outputPanel, HasHorizontalAlignment.ALIGN_RIGHT);
|
||||
|
||||
Window.addWindowResizeListener(new WindowResizeListener() {
|
||||
public void onWindowResized(int w, int h) {
|
||||
translatePanel.setPixelSize(w-20, h-50);
|
||||
}
|
||||
});
|
||||
int w = Window.getClientWidth();
|
||||
int h = Window.getClientHeight();
|
||||
translatePanel.setPixelSize(w-20, h-50);
|
||||
|
||||
return translatePanel;
|
||||
}
|
||||
|
||||
protected BrowsePanel createBrowsePanel() {
|
||||
return new BrowsePanel(pgf);
|
||||
}
|
||||
|
||||
protected QueryPanel createQueryPanel() {
|
||||
return new QueryPanel(pgf);
|
||||
}
|
||||
|
||||
protected Widget createLinksPanel(final Panel parent) {
|
||||
HorizontalPanel linksPanel = new HorizontalPanel();
|
||||
linksPanel.setStylePrimaryName("my-LinksPanel");
|
||||
|
||||
Hyperlink translateLink = new Hyperlink("Translate", "translate");
|
||||
translateLink.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
parent.remove(browsePanel);
|
||||
parent.remove(queryPanel);
|
||||
parent.add(translatePanel);
|
||||
}
|
||||
});
|
||||
linksPanel.add(translateLink);
|
||||
|
||||
Hyperlink queryLink = new Hyperlink("Query", "query");
|
||||
queryLink.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
parent.remove(translatePanel);
|
||||
parent.remove(browsePanel);
|
||||
parent.add(queryPanel);
|
||||
}
|
||||
});
|
||||
linksPanel.add(queryLink);
|
||||
|
||||
Hyperlink browseLink = new Hyperlink("Browse", "browse");
|
||||
browseLink.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
parent.remove(translatePanel);
|
||||
parent.remove(queryPanel);
|
||||
parent.add(browsePanel);
|
||||
browsePanel.onActivate();
|
||||
}
|
||||
});
|
||||
linksPanel.add(browseLink);
|
||||
|
||||
return linksPanel;
|
||||
}
|
||||
|
||||
protected Widget createErrorMsg(final PGF.TcError error) {
|
||||
HTML msgHTML = new HTML("<pre>"+error.getMsg()+"</pre>");
|
||||
msgHTML.addStyleName("content");
|
||||
msgHTML.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
textPanel.showError(error.getFId());
|
||||
}
|
||||
});
|
||||
return msgHTML;
|
||||
}
|
||||
|
||||
//
|
||||
// History stuff
|
||||
//
|
||||
|
||||
protected class MyHistoryListener implements HistoryListener {
|
||||
private final Panel parent;
|
||||
|
||||
public MyHistoryListener(Panel parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void onHistoryChanged(String token) {
|
||||
if (token.equals("translate")) {
|
||||
parent.remove(queryPanel);
|
||||
parent.remove(browsePanel);
|
||||
parent.add(translatePanel);
|
||||
} else if (token.equals("query")) {
|
||||
parent.remove(translatePanel);
|
||||
parent.remove(browsePanel);
|
||||
parent.add(queryPanel);
|
||||
} else if (token.equals("browse")) {
|
||||
parent.remove(translatePanel);
|
||||
parent.remove(queryPanel);
|
||||
parent.add(browsePanel);
|
||||
browsePanel.onActivate();
|
||||
browsePanel.browse(null);
|
||||
} else if (token.startsWith("browse:")) {
|
||||
browsePanel.browse(token.substring(7));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
protected void setPGFName (String pgfName) {
|
||||
if (pgfName != null && !pgfName.equals(pgf.getPGFName())) {
|
||||
pgf.setPGFName(pgfName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setInputLanguage (String inputLanguage) {
|
||||
if (inputLanguage != null && !inputLanguage.equals(pgf.getInputLanguage())) {
|
||||
pgf.setInputLanguage(inputLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
|
||||
protected class MySettingsListener implements PGFWrapper.SettingsListener {
|
||||
// Will only happen on load
|
||||
public void onAvailableGrammarsChanged() {
|
||||
if (pgf.getPGFName() == null) {
|
||||
List<String> grammars = pgf.getGrammars();
|
||||
if (!grammars.isEmpty()) {
|
||||
pgf.setPGFName(grammars.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onSelectedGrammarChanged() {
|
||||
textPanel.clear();
|
||||
if (pgf.getInputLanguage() == null) {
|
||||
GWT.log("Setting input language to user language: " + pgf.getUserLanguage(), null);
|
||||
pgf.setInputLanguage(pgf.getUserLanguage());
|
||||
}
|
||||
update();
|
||||
}
|
||||
public void onInputLanguageChanged() {
|
||||
update();
|
||||
}
|
||||
public void onOutputLanguageChanged() {
|
||||
update();
|
||||
}
|
||||
public void onStartCategoryChanged() {
|
||||
update();
|
||||
}
|
||||
public void onSettingsError(String msg, Throwable e) {
|
||||
showError(msg,e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onModuleLoad() {
|
||||
statusPopup = new StatusPopup();
|
||||
|
||||
pgf = new PGFWrapper(pgfBaseURL);
|
||||
RootPanel.get().add(createUI());
|
||||
pgf.addSettingsListener(new MySettingsListener());
|
||||
pgf.updateAvailableGrammars();
|
||||
|
||||
textPanel.setFocus(true);
|
||||
}
|
||||
}
|
||||
@@ -1,108 +1,38 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
|
||||
public class FridgeBagPanel extends Composite {
|
||||
public class FridgeBagPanel extends Composite implements Iterable<Magnet> {
|
||||
|
||||
private PGFWrapper pgf;
|
||||
private FlowPanel mainPanel;
|
||||
|
||||
private MagnetFactory magnetFactory;
|
||||
|
||||
private JSONRequest completeRequest = null;
|
||||
|
||||
private FlowPanel prefixPanel;
|
||||
|
||||
private FlowPanel mainPanel;
|
||||
|
||||
private int maxMagnets = 100;
|
||||
|
||||
private LinkedHashSet<String> prefixes = new LinkedHashSet<String>();
|
||||
|
||||
|
||||
public FridgeBagPanel (PGFWrapper pgf, MagnetFactory magnetFactory) {
|
||||
this.pgf = pgf;
|
||||
this.magnetFactory = magnetFactory;
|
||||
prefixPanel = new FlowPanel();
|
||||
prefixPanel.setStylePrimaryName("my-PrefixPanel");
|
||||
public FridgeBagPanel () {
|
||||
mainPanel = new FlowPanel();
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
|
||||
vPanel.add(prefixPanel);
|
||||
vPanel.add(mainPanel);
|
||||
initWidget(new ScrollPanel(vPanel));
|
||||
|
||||
initWidget(new ScrollPanel(mainPanel));
|
||||
setStylePrimaryName("my-FridgeBagPanel");
|
||||
addStyleDependentName("empty");
|
||||
}
|
||||
|
||||
public void updateBag (String text) {
|
||||
updateBag(text, "");
|
||||
}
|
||||
|
||||
public void updateBag (final String text, String prefix) {
|
||||
if (completeRequest != null) {
|
||||
completeRequest.cancel();
|
||||
}
|
||||
final boolean updatePrefixes = prefix.equals("");
|
||||
public void clear() {
|
||||
mainPanel.clear();
|
||||
addStyleDependentName("empty");
|
||||
if (updatePrefixes) { clearPrefixes(); }
|
||||
int limit = updatePrefixes ? 0 : maxMagnets;
|
||||
completeRequest = pgf.complete(text + " " + prefix,
|
||||
limit, new PGF.CompleteCallback() {
|
||||
public void onResult(PGF.Completions completions) {
|
||||
for (PGF.Completion completion : completions.iterable()) {
|
||||
for (String word : completion.getCompletions()) {
|
||||
if (updatePrefixes) {
|
||||
addPrefix(text, word.substring(0,1));
|
||||
}
|
||||
if (mainPanel.getWidgetCount() < maxMagnets) {
|
||||
Magnet magnet = magnetFactory.createMagnet(word, completion.getFrom());
|
||||
mainPanel.add(magnet);
|
||||
removeStyleDependentName("empty");
|
||||
} else {
|
||||
prefixPanel.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onError(Throwable e) {
|
||||
// FIXME: show message to user?
|
||||
GWT.log("Error getting completions.", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void clearPrefixes () {
|
||||
prefixes.clear();
|
||||
prefixPanel.clear();
|
||||
prefixPanel.setVisible(false);
|
||||
}
|
||||
|
||||
protected void addPrefix(final String text, final String prefix) {
|
||||
if (prefixes.add(prefix)) {
|
||||
Button prefixButton = new Button(prefix, new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
updateBag(text, prefix);
|
||||
}
|
||||
});
|
||||
prefixButton.setTitle("Show only magnets stating with '" + prefix + "'");
|
||||
prefixPanel.add(prefixButton);
|
||||
public void fill(List<Magnet> magnets) {
|
||||
for (Magnet magnet : magnets) {
|
||||
mainPanel.add(magnet);
|
||||
}
|
||||
|
||||
if (mainPanel.getWidgetCount() == 0)
|
||||
addStyleDependentName("empty");
|
||||
else
|
||||
removeStyleDependentName("empty");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public void cloneMagnet (Magnet magnet) {
|
||||
int i = getWidgetIndex(magnet);
|
||||
GWT.log("cloneMagnet: " + magnet.getParent(), null);
|
||||
if (i != -1) {
|
||||
GWT.log("cloning", null);
|
||||
insert(magnetFactory.createMagnet(magnet), i);
|
||||
}
|
||||
public Iterator<Magnet> iterator() {
|
||||
return (Iterator<Magnet>) (Iterator) mainPanel.iterator();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.core.client.*;
|
||||
import com.google.gwt.user.client.*;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import com.google.gwt.event.dom.client.*;
|
||||
import com.google.gwt.event.logical.shared.*;
|
||||
import com.google.gwt.event.shared.*;
|
||||
|
||||
public class LinearizationsPanel extends Composite {
|
||||
|
||||
protected PGFWrapper pgf;
|
||||
|
||||
public LinearizationsPanel(PGFWrapper pgf, String tree, PGF.Linearizations lins) {
|
||||
this.pgf = pgf;
|
||||
|
||||
HorizontalPanel hPanel = new HorizontalPanel();
|
||||
VerticalPanel linsPanel = new VerticalPanel();
|
||||
linsPanel.addStyleName("my-translation-bar");
|
||||
hPanel.add(linsPanel);
|
||||
HorizontalPanel btnPanel = new HorizontalPanel();
|
||||
btnPanel.addStyleName("my-translation-btns");
|
||||
btnPanel.setSpacing(4);
|
||||
btnPanel.add(createAbsTreeButton(tree));
|
||||
btnPanel.add(createAlignButton(tree));
|
||||
hPanel.add(btnPanel);
|
||||
hPanel.setCellHorizontalAlignment(btnPanel,HasHorizontalAlignment.ALIGN_RIGHT);
|
||||
|
||||
for (PGF.Linearization l : lins.iterable()) {
|
||||
linsPanel.add(createTranslation(l.getTo(), tree, l.getText()));
|
||||
}
|
||||
|
||||
initWidget(hPanel);
|
||||
setStylePrimaryName("my-translation-frame");
|
||||
}
|
||||
|
||||
protected Widget createAbsTreeButton(final String abstractTree) {
|
||||
Image treeBtn = new Image("org.grammaticalframework.ui.gwt.EditorApp/tree-btn.png");
|
||||
treeBtn.setTitle("Displays the abstract syntax tree.");
|
||||
treeBtn.addClickListener(
|
||||
new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
// Create a dialog box and set the caption text
|
||||
final DialogBox dialogBox = new DialogBox();
|
||||
dialogBox.setText("Abstract Syntax Tree");
|
||||
|
||||
// Create a table to layout the content
|
||||
HorizontalPanel dialogContents = new HorizontalPanel();
|
||||
dialogContents.setSpacing(4);
|
||||
dialogBox.setWidget(dialogContents);
|
||||
|
||||
// Add an image to the dialog
|
||||
|
||||
Frame image = new Frame(pgf.graphvizAbstractTree(abstractTree));
|
||||
image.addStyleName("my-treeimage");
|
||||
dialogContents.add(image);
|
||||
|
||||
// Add a close button at the bottom of the dialog
|
||||
Button closeButton = new Button("Close",
|
||||
new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
dialogBox.hide();
|
||||
}
|
||||
});
|
||||
dialogContents.add(closeButton);
|
||||
|
||||
dialogBox.center();
|
||||
dialogBox.show();
|
||||
}
|
||||
});
|
||||
return treeBtn;
|
||||
}
|
||||
|
||||
protected Widget createAlignButton(final String abstractTree) {
|
||||
Image alignBtn = new Image("org.grammaticalframework.ui.gwt.EditorApp/align-btn.png");
|
||||
alignBtn.setTitle("Displays word-alignment diagram.");
|
||||
alignBtn.addClickListener(
|
||||
new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
// Create a dialog box and set the caption text
|
||||
final DialogBox dialogBox = new DialogBox();
|
||||
dialogBox.setText("Word Alignment");
|
||||
|
||||
// Create a table to layout the content
|
||||
HorizontalPanel dialogContents = new HorizontalPanel();
|
||||
dialogContents.setSpacing(4);
|
||||
dialogBox.setWidget(dialogContents);
|
||||
|
||||
// Add an image to the dialog
|
||||
Frame image = new Frame(pgf.graphvizAlignment(abstractTree));
|
||||
image.addStyleName("my-alignmentimage");
|
||||
dialogContents.add(image);
|
||||
|
||||
// Add a close button at the bottom of the dialog
|
||||
Button closeButton = new Button("Close",
|
||||
new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
dialogBox.hide();
|
||||
}
|
||||
});
|
||||
dialogContents.add(closeButton);
|
||||
|
||||
dialogBox.center();
|
||||
dialogBox.show();
|
||||
}
|
||||
});
|
||||
return alignBtn;
|
||||
}
|
||||
|
||||
protected Widget createTranslation(final String language, final String abstractTree, String text) {
|
||||
Label l = new Label(text);
|
||||
l.addStyleName("my-translation");
|
||||
String lang = pgf.getLanguageCode(language);
|
||||
if (lang != null) {
|
||||
l.getElement().setLang(lang);
|
||||
}
|
||||
l.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
// Create a dialog box and set the caption text
|
||||
final DialogBox dialogBox = new DialogBox();
|
||||
dialogBox.setText("Parse Tree");
|
||||
|
||||
// Create a table to layout the content
|
||||
HorizontalPanel dialogContents = new HorizontalPanel();
|
||||
dialogContents.setSpacing(4);
|
||||
dialogBox.setWidget(dialogContents);
|
||||
|
||||
// Add an image to the dialog
|
||||
Frame image = new Frame(pgf.graphvizParseTree(abstractTree, language));
|
||||
image.addStyleName("my-treeimage");
|
||||
dialogContents.add(image);
|
||||
|
||||
// Add a close button at the bottom of the dialog
|
||||
Button closeButton = new Button("Close",
|
||||
new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
dialogBox.hide();
|
||||
}
|
||||
});
|
||||
dialogContents.add(closeButton);
|
||||
|
||||
dialogBox.center();
|
||||
dialogBox.show();
|
||||
}
|
||||
});
|
||||
return l;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.core.client.*;
|
||||
import com.google.gwt.user.client.*;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import com.google.gwt.event.dom.client.*;
|
||||
import com.google.gwt.event.logical.shared.*;
|
||||
import com.google.gwt.event.shared.*;
|
||||
import com.google.gwt.dom.client.Node;
|
||||
import com.google.gwt.dom.client.Text;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import org.grammaticalframework.ui.gwt.client.selection.*;
|
||||
|
||||
public class MagnetSearchBox extends FocusWidget {
|
||||
public MagnetSearchBox() {
|
||||
this(Document.get().createDivElement());
|
||||
}
|
||||
|
||||
public MagnetSearchBox(Element elem) {
|
||||
super(elem);
|
||||
elem.setAttribute("contentEditable", "true");
|
||||
setStyleName("searchbox");
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return getElement().getInnerText();
|
||||
}
|
||||
|
||||
public void setText(String s) {
|
||||
getElement().setInnerText(s);
|
||||
}
|
||||
|
||||
public int getCursorPos() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setCursorPos(int pos) {
|
||||
Node child = getElement().getFirstChild();
|
||||
if (child instanceof Text) {
|
||||
SelectionEndPoint selPoint = new SelectionEndPoint((Text) child,pos);
|
||||
Selection sel = Selection.getSelection();
|
||||
sel.select(selPoint,selPoint);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -74,17 +74,6 @@ public class PGF {
|
||||
public final native Linearizations getLinearizations() /*-{ return this.linearizations; }-*/;
|
||||
}
|
||||
|
||||
public static class Linearizations extends IterableJsArray<Linearization> {
|
||||
protected Linearizations() { }
|
||||
}
|
||||
|
||||
public static class Linearization extends JavaScriptObject {
|
||||
protected Linearization() { }
|
||||
|
||||
public final native String getTo() /*-{ return this.to; }-*/;
|
||||
public final native String getText() /*-{ return this.text; }-*/;
|
||||
}
|
||||
|
||||
/* Completion */
|
||||
|
||||
/**
|
||||
@@ -152,20 +141,6 @@ public class PGF {
|
||||
public final native int getFId() /*-{ return this.fid; }-*/;
|
||||
public final native int getIndex() /*-{ return this.index; }-*/;
|
||||
public final native BracketedString[] getChildren() /*-{ return this.children; }-*/;
|
||||
|
||||
public final String render() {
|
||||
if (getToken() != null)
|
||||
return getToken();
|
||||
else {
|
||||
StringBuilder sbuilder = new StringBuilder();
|
||||
for (BracketedString bs : getChildren()) {
|
||||
if (sbuilder.length() > 0)
|
||||
sbuilder.append(' ');
|
||||
sbuilder.append(bs.render());
|
||||
}
|
||||
return sbuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TcError extends JavaScriptObject {
|
||||
@@ -174,6 +149,29 @@ public class PGF {
|
||||
public final native int getFId() /*-{ return this.fid; }-*/;
|
||||
public final native String getMsg() /*-{ return this.msg; }-*/;
|
||||
}
|
||||
|
||||
|
||||
/* Linearization */
|
||||
|
||||
public JSONRequest linearize (String pgfURL, String tree, String toLang, final LinearizeCallback callback) {
|
||||
List<Arg> args = new ArrayList<Arg>();
|
||||
args.add(new Arg("tree", tree));
|
||||
args.add(new Arg("to", toLang));
|
||||
return sendGrammarRequest(pgfURL, "linearize", args, callback);
|
||||
}
|
||||
|
||||
public interface LinearizeCallback extends JSONCallback<Linearizations> { }
|
||||
|
||||
public static class Linearizations extends IterableJsArray<Linearization> {
|
||||
protected Linearizations() { }
|
||||
}
|
||||
|
||||
public static class Linearization extends JavaScriptObject {
|
||||
protected Linearization() { }
|
||||
|
||||
public final native String getTo() /*-{ return this.to; }-*/;
|
||||
public final native String getText() /*-{ return this.text; }-*/;
|
||||
}
|
||||
|
||||
public String graphvizAbstractTree(String pgfURL, String abstractTree) {
|
||||
List<Arg> args = new ArrayList<Arg>();
|
||||
@@ -216,8 +214,20 @@ public class PGF {
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public JSONRequest query(String pgfURL, String query, QueryCallback callback) {
|
||||
List<Arg> args = new ArrayList<Arg>();
|
||||
args.add(new Arg("cat", query));
|
||||
return sendGrammarRequest(pgfURL, "query", args, callback);
|
||||
}
|
||||
|
||||
public interface QueryCallback extends JSONCallback<QueryResult> {}
|
||||
|
||||
/* Common */
|
||||
public static class QueryResult extends JavaScriptObject {
|
||||
protected QueryResult() { }
|
||||
|
||||
public final native String[] getRows() /*-{ return this.rows; }-*/;
|
||||
}
|
||||
|
||||
public <T extends JavaScriptObject> JSONRequest sendGrammarRequest(String pgfURL, String resource, List<Arg> args, final JSONCallback<T> callback) {
|
||||
args.add(new Arg("command", resource));
|
||||
|
||||
@@ -138,6 +138,10 @@ public class PGFWrapper {
|
||||
return pgf.parse(grammarURL, input, inputLanguage, cat, callback);
|
||||
}
|
||||
|
||||
public JSONRequest linearize (String tree, final PGF.LinearizeCallback callback) {
|
||||
return pgf.linearize(grammarURL, tree, outputLanguage, callback);
|
||||
}
|
||||
|
||||
public String graphvizAbstractTree(String abstractTree) {
|
||||
return pgf.graphvizAbstractTree(grammarURL,abstractTree);
|
||||
}
|
||||
@@ -154,6 +158,10 @@ public class PGFWrapper {
|
||||
return pgf.browse(grammarURL, id, href, cssClass, callback);
|
||||
}
|
||||
|
||||
public JSONRequest query(String query, PGF.QueryCallback callback) {
|
||||
return pgf.query(grammarURL, query, callback);
|
||||
}
|
||||
|
||||
//
|
||||
// Settings
|
||||
//
|
||||
@@ -242,7 +250,7 @@ public class PGFWrapper {
|
||||
PGF.Language l = languages.get(language);
|
||||
return l == null ? null : l.getLanguageCode();
|
||||
}
|
||||
|
||||
|
||||
public Collection<String> getAllLanguages() {
|
||||
return languages.keySet();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.http.client.*;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
|
||||
public class QueryPanel extends Composite {
|
||||
|
||||
private PGFWrapper pgf;
|
||||
|
||||
public QueryPanel(PGFWrapper pgf) {
|
||||
this.pgf = pgf;
|
||||
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.add(createQueryPanel());
|
||||
|
||||
initWidget(vPanel);
|
||||
setStylePrimaryName("my-QueryPanel");
|
||||
|
||||
pgf.addSettingsListener(new MySettingsListener(pgf));
|
||||
}
|
||||
|
||||
protected Widget createQueryPanel() {
|
||||
final TextArea queryBox = new TextArea();
|
||||
queryBox.setStylePrimaryName("my-QueryBox");
|
||||
|
||||
final Grid resultGrid = new Grid(0, 1);
|
||||
resultGrid.setStylePrimaryName("my-ResultGrid");
|
||||
resultGrid.setBorderWidth(3);
|
||||
|
||||
Button execButton = new Button("Execute");
|
||||
execButton.addClickListener(new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
pgf.query(queryBox.getText(), new PGF.QueryCallback() {
|
||||
public void onResult(PGF.QueryResult result) {
|
||||
while (resultGrid.getRowCount() > 0) {
|
||||
resultGrid.removeRow(resultGrid.getRowCount() - 1);
|
||||
}
|
||||
|
||||
ClickListener labelClickListener = new ClickListener() {
|
||||
public void onClick(Widget sender) {
|
||||
final Label label = (Label) sender;
|
||||
pgf.linearize(label.getText(), new PGF.LinearizeCallback() {
|
||||
public void onResult(PGF.Linearizations result) {
|
||||
final PopupPanel popup = new PopupPanel(true);
|
||||
popup.setWidget(new LinearizationsPanel(pgf, label.getText(), result));
|
||||
popup.setPopupPosition(label.getAbsoluteLeft(),
|
||||
label.getAbsoluteTop()+label.getOffsetHeight());
|
||||
popup.show();
|
||||
}
|
||||
|
||||
public void onError(Throwable e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
int row = 0;
|
||||
for (String tree : result.getRows()) {
|
||||
Label label = new Label(tree);
|
||||
label.addClickListener(labelClickListener);
|
||||
resultGrid.insertRow(row);
|
||||
resultGrid.setWidget(row, 0, label);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(Throwable e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
DecoratorPanel queryDecorator = new DecoratorPanel();
|
||||
VerticalPanel vPanel = new VerticalPanel();
|
||||
vPanel.add(new Label("Query"));
|
||||
HorizontalPanel hPanel = new HorizontalPanel();
|
||||
hPanel.add(queryBox);
|
||||
hPanel.add(execButton);
|
||||
vPanel.add(hPanel);
|
||||
queryDecorator.add(vPanel);
|
||||
|
||||
VerticalPanel queryPanel = new VerticalPanel();
|
||||
queryPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
|
||||
queryPanel.add(queryDecorator);
|
||||
queryPanel.add(resultGrid);
|
||||
|
||||
return queryPanel;
|
||||
}
|
||||
|
||||
protected class MySettingsListener implements PGFWrapper.SettingsListener {
|
||||
|
||||
private PGFWrapper pgf;
|
||||
|
||||
public MySettingsListener(PGFWrapper pgf) {
|
||||
this.pgf = pgf;
|
||||
}
|
||||
|
||||
public void onAvailableGrammarsChanged() { }
|
||||
public void onSelectedGrammarChanged() { }
|
||||
public void onInputLanguageChanged() { }
|
||||
public void onOutputLanguageChanged() { }
|
||||
public void onStartCategoryChanged() { }
|
||||
public void onSettingsError(String msg, Throwable e) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,547 @@
|
||||
package org.grammaticalframework.ui.gwt.client;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gwt.core.client.*;
|
||||
import com.google.gwt.user.client.*;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import com.google.gwt.event.dom.client.*;
|
||||
import com.google.gwt.event.logical.shared.*;
|
||||
import com.google.gwt.event.shared.*;
|
||||
|
||||
public class TextInputPanel extends Composite implements Focusable, HasValueChangeHandlers<String>, HasSelectionHandlers<String> {
|
||||
|
||||
protected FlowPanel textPanel = null;
|
||||
protected FlowPanel mainPanel = null;
|
||||
protected FocusPanel focusPanel = null;
|
||||
protected Panel focusedPanel = null;
|
||||
protected List<Panel> selectedPanels = null;
|
||||
protected List<Panel> errorPanels = null;
|
||||
protected Panel tempPanel = null;
|
||||
protected Label status = null;
|
||||
protected NavigationController navigationController;
|
||||
protected MagnetSearchBox searchBox = null;
|
||||
|
||||
private List<Label> words = new ArrayList<Label>();
|
||||
|
||||
private Map<Panel, Phrase> mapPanel2Phrase = new HashMap<Panel, Phrase>();
|
||||
private Map<Integer, Phrase> mapFId2Phrase = new HashMap<Integer, Phrase>();
|
||||
|
||||
private ChangeListenerCollection changeListeners = null;
|
||||
|
||||
public TextInputPanel() {
|
||||
mainPanel = new FlowPanel();
|
||||
mainPanel.setStylePrimaryName("wordspanel");
|
||||
|
||||
textPanel = new FlowPanel();
|
||||
textPanel.add(mainPanel);
|
||||
textPanel.setStylePrimaryName("wordspanel");
|
||||
|
||||
Label space = new Label(" ");
|
||||
space.setStylePrimaryName("wordspace");
|
||||
textPanel.add(space);
|
||||
|
||||
Panel contentPanel = new FlowPanel();
|
||||
contentPanel.add(textPanel);
|
||||
contentPanel.setStylePrimaryName("text");
|
||||
|
||||
focusPanel = new FocusPanel();
|
||||
focusPanel.setWidget(contentPanel);
|
||||
focusPanel.setStylePrimaryName("frame");
|
||||
|
||||
Widget buttons = createToolbarPanel();
|
||||
|
||||
VerticalPanel wrapper = new VerticalPanel();
|
||||
wrapper.add(buttons);
|
||||
wrapper.add(focusPanel);
|
||||
initWidget(wrapper);
|
||||
setStylePrimaryName("my-TextInputPanel");
|
||||
|
||||
navigationController = new NavigationController();
|
||||
focusPanel.addKeyDownHandler(navigationController);
|
||||
}
|
||||
|
||||
protected Widget createToolbarPanel() {
|
||||
HorizontalPanel toolbar = new HorizontalPanel();
|
||||
toolbar.setStylePrimaryName("toolbar");
|
||||
|
||||
Panel buttons = new HorizontalPanel();
|
||||
toolbar.add(buttons);
|
||||
toolbar.setCellHorizontalAlignment(buttons,HorizontalPanel.ALIGN_LEFT);
|
||||
toolbar.setCellVerticalAlignment(buttons,HorizontalPanel.ALIGN_MIDDLE);
|
||||
|
||||
Image clearButton = new Image("org.grammaticalframework.ui.gwt.EditorApp/textinput-buttons.png",0,0,20,20);
|
||||
clearButton.setTitle("Clears the whole text.");
|
||||
clearButton.setStylePrimaryName("button");
|
||||
clearButton.addClickListener(new ClickListener () {
|
||||
public void onClick(Widget sender) {
|
||||
clear();
|
||||
}
|
||||
});
|
||||
buttons.add(clearButton);
|
||||
|
||||
Image deleteLastButton = new Image("org.grammaticalframework.ui.gwt.EditorApp/textinput-buttons.png",20,0,20,20);
|
||||
deleteLastButton.setTitle("Removes the last word.");
|
||||
deleteLastButton.setStylePrimaryName("button");
|
||||
deleteLastButton.addClickListener(new ClickListener () {
|
||||
public void onClick(Widget sender) {
|
||||
deleteLast();
|
||||
}
|
||||
});
|
||||
buttons.add(deleteLastButton);
|
||||
|
||||
status = new Label();
|
||||
status.setTitle("The currently selected category.");
|
||||
status.setStylePrimaryName("status");
|
||||
toolbar.add(status);
|
||||
toolbar.setCellHorizontalAlignment(status,HorizontalPanel.ALIGN_RIGHT);
|
||||
toolbar.setCellVerticalAlignment(status,HorizontalPanel.ALIGN_MIDDLE);
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void renderBracketedString(final PGF.BracketedString bs) {
|
||||
words.clear();
|
||||
mapPanel2Phrase.clear();
|
||||
mapFId2Phrase.clear();
|
||||
mainPanel.clear();
|
||||
selectedPanels = null;
|
||||
focusedPanel = null;
|
||||
errorPanels = null;
|
||||
tempPanel = null;
|
||||
|
||||
Widget widget = createWordPanels(bs);
|
||||
mainPanel.add(widget);
|
||||
}
|
||||
|
||||
private Widget createWordPanels(final PGF.BracketedString bs) {
|
||||
if (bs.getToken() != null) {
|
||||
Label wordLabel = new Label(bs.getToken());
|
||||
wordLabel.setStylePrimaryName("wordlabel");
|
||||
wordLabel.addClickListener(navigationController);
|
||||
words.add(wordLabel);
|
||||
return wordLabel;
|
||||
} else {
|
||||
FlowPanel panel = new FlowPanel();
|
||||
panel.setStylePrimaryName("wordspanel");
|
||||
|
||||
Integer fid = new Integer(bs.getFId());
|
||||
Phrase phrase = mapFId2Phrase.get(fid);
|
||||
if (phrase == null) {
|
||||
phrase = new Phrase();
|
||||
phrase.cat = bs.getCat();
|
||||
phrase.panels = new ArrayList<Panel>();
|
||||
mapFId2Phrase.put(fid,phrase);
|
||||
}
|
||||
phrase.panels.add(panel);
|
||||
mapPanel2Phrase.put(panel, phrase);
|
||||
|
||||
for (PGF.BracketedString child : bs.getChildren()) {
|
||||
if (panel.getWidgetCount() > 0) {
|
||||
Label space = new Label(" ");
|
||||
space.setStylePrimaryName("wordspace");
|
||||
panel.add(space);
|
||||
}
|
||||
panel.add(createWordPanels(child));
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
setSearchTerm("");
|
||||
words.clear();
|
||||
mapPanel2Phrase.clear();
|
||||
mapFId2Phrase.clear();
|
||||
mainPanel.clear();
|
||||
selectedPanels = null;
|
||||
focusedPanel = null;
|
||||
errorPanels = null;
|
||||
tempPanel = null;
|
||||
fireValueChange();
|
||||
}
|
||||
|
||||
public void addMagnet(Magnet magnet) {
|
||||
Label wordLabel = new Label(magnet.getText());
|
||||
wordLabel.setStylePrimaryName("wordlabel");
|
||||
getTempPanel().add(wordLabel);
|
||||
words.add(wordLabel);
|
||||
|
||||
fireValueChange();
|
||||
}
|
||||
|
||||
public String deleteLast() {
|
||||
int wordsCount = words.size();
|
||||
if (wordsCount <= 0)
|
||||
return null;
|
||||
Label lastWord = words.remove(wordsCount-1);
|
||||
|
||||
setSearchTerm("");
|
||||
mapPanel2Phrase.clear();
|
||||
mapFId2Phrase.clear();
|
||||
mainPanel.clear();
|
||||
selectedPanels = null;
|
||||
focusedPanel = null;
|
||||
errorPanels = null;
|
||||
tempPanel = null;
|
||||
for (Label word : words) {
|
||||
if (((FlowPanel) getTempPanel()).getWidgetCount() > 0) {
|
||||
Label space = new Label(" ");
|
||||
space.setStylePrimaryName("wordspace");
|
||||
getTempPanel().add(space);
|
||||
}
|
||||
getTempPanel().add(word);
|
||||
}
|
||||
fireValueChange();
|
||||
|
||||
return lastWord.getText();
|
||||
}
|
||||
|
||||
public void showSearchBox() {
|
||||
if (searchBox == null) {
|
||||
searchBox = new MagnetSearchBox();
|
||||
SearchBoxKeyboardHandler handler = new SearchBoxKeyboardHandler();
|
||||
searchBox.addKeyUpHandler(handler);
|
||||
searchBox.addKeyDownHandler(handler);
|
||||
|
||||
textPanel.add(searchBox);
|
||||
searchBox.setFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void hideSearchBox() {
|
||||
if (searchBox != null) {
|
||||
searchBox.removeFromParent();
|
||||
searchBox = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSearchTerm(String term) {
|
||||
if (searchBox != null) {
|
||||
searchBox.setText(term);
|
||||
if ("".equals(term))
|
||||
searchBox.setCursorPos(0);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSearchTerm() {
|
||||
if (searchBox != null)
|
||||
return searchBox.getText();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void showSearchError() {
|
||||
if (searchBox != null) {
|
||||
searchBox.addStyleDependentName("error");
|
||||
}
|
||||
}
|
||||
|
||||
public void clearSearchError() {
|
||||
if (searchBox != null) {
|
||||
searchBox.removeStyleDependentName("error");
|
||||
}
|
||||
}
|
||||
|
||||
public void showError(int fid) {
|
||||
if (errorPanels != null) {
|
||||
for (Panel panel : errorPanels) {
|
||||
panel.removeStyleDependentName("error");
|
||||
}
|
||||
errorPanels = null;
|
||||
}
|
||||
|
||||
Phrase phrase = mapFId2Phrase.get(fid);
|
||||
if (phrase != null) {
|
||||
errorPanels = phrase.panels;
|
||||
if (errorPanels != null) {
|
||||
for (Panel selPanel : errorPanels) {
|
||||
selPanel.addStyleDependentName("error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Panel getTempPanel() {
|
||||
if (tempPanel == null) {
|
||||
if (mainPanel.getWidgetCount() > 0) {
|
||||
Label space = new Label(" ");
|
||||
space.setStylePrimaryName("wordspace");
|
||||
mainPanel.add(space);
|
||||
}
|
||||
|
||||
tempPanel = new FlowPanel();
|
||||
tempPanel.setStylePrimaryName("wordspanel");
|
||||
mainPanel.add(tempPanel);
|
||||
}
|
||||
return tempPanel;
|
||||
}
|
||||
|
||||
protected void fireValueChange() {
|
||||
DeferredCommand.addCommand(new Command() {
|
||||
public void execute() {
|
||||
ValueChangeEvent.fire(TextInputPanel.this, getText());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void fireSelection() {
|
||||
SelectionEvent.fire(this, (searchBox == null) ? "" : searchBox.getText());
|
||||
}
|
||||
|
||||
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
|
||||
return addHandler(handler, ValueChangeEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addSelectionHandler(SelectionHandler<String> handler) {
|
||||
return addHandler(handler, SelectionEvent.getType());
|
||||
}
|
||||
|
||||
public String getText () {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Label word : words) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(word.getText());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getTabIndex() {
|
||||
return focusPanel.getTabIndex();
|
||||
}
|
||||
|
||||
public void setTabIndex(int index) {
|
||||
focusPanel.setTabIndex(index);
|
||||
}
|
||||
|
||||
public void setAccessKey(char key) {
|
||||
focusPanel.setAccessKey(key);
|
||||
}
|
||||
|
||||
public void setFocus(boolean focused) {
|
||||
focusPanel.setFocus(focused);
|
||||
}
|
||||
|
||||
private class Phrase {
|
||||
public String cat;
|
||||
public ArrayList<Panel> panels;
|
||||
}
|
||||
|
||||
private final class NavigationController implements KeyDownHandler, ClickListener {
|
||||
|
||||
public void onKeyDown(KeyDownEvent event) {
|
||||
switch (event.getNativeKeyCode()) {
|
||||
case KeyCodes.KEY_UP:
|
||||
if (focusedPanel != null) {
|
||||
Panel firstUp = null;
|
||||
FlowPanel parent = (FlowPanel) focusedPanel.getParent();
|
||||
while (parent != mainPanel) {
|
||||
if (parent.getWidgetCount() > 1) {
|
||||
firstUp = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
parent = (FlowPanel) parent.getParent();
|
||||
}
|
||||
|
||||
if (firstUp != null)
|
||||
setFocusedPanel(firstUp);
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KeyCodes.KEY_DOWN:
|
||||
if (focusedPanel != null) {
|
||||
Panel firstDown = null;
|
||||
for (Widget child : focusedPanel) {
|
||||
if (child instanceof Panel) {
|
||||
firstDown = (Panel) child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstDown != null)
|
||||
setFocusedPanel(firstDown);
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KeyCodes.KEY_LEFT:
|
||||
if (focusedPanel != null) {
|
||||
Panel firstLeft = null;
|
||||
Panel parent = (Panel) focusedPanel.getParent();
|
||||
for (Widget child : parent) {
|
||||
if (child instanceof Panel) {
|
||||
if (child == focusedPanel)
|
||||
break;
|
||||
firstLeft = (Panel) child;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstLeft == null) {
|
||||
if (parent != mainPanel)
|
||||
firstLeft = parent;
|
||||
} else {
|
||||
for (;;) {
|
||||
Panel lastChild = null;
|
||||
for (Widget child : firstLeft) {
|
||||
if (child instanceof Panel) {
|
||||
lastChild = (Panel) child;
|
||||
}
|
||||
}
|
||||
if (lastChild == null)
|
||||
break;
|
||||
firstLeft = lastChild;
|
||||
}
|
||||
}
|
||||
if (firstLeft != null)
|
||||
setFocusedPanel(firstLeft);
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KeyCodes.KEY_RIGHT:
|
||||
if (focusedPanel != null) {
|
||||
Panel firstRight = null;
|
||||
Panel parent = (Panel) focusedPanel.getParent();
|
||||
Widget prev = null;
|
||||
for (Widget child : parent) {
|
||||
if (child instanceof Panel) {
|
||||
if (prev == focusedPanel) {
|
||||
firstRight = (Panel) child;
|
||||
break;
|
||||
}
|
||||
prev = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstRight == null) {
|
||||
if (parent != mainPanel)
|
||||
firstRight = parent;
|
||||
} else {
|
||||
for (;;) {
|
||||
Panel firstChild = null;
|
||||
for (Widget child : firstRight) {
|
||||
if (child instanceof Panel) {
|
||||
firstChild = (Panel) child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstChild == null)
|
||||
break;
|
||||
firstRight = firstChild;
|
||||
}
|
||||
}
|
||||
if (firstRight != null)
|
||||
setFocusedPanel(firstRight);
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KeyCodes.KEY_ENTER:
|
||||
case KeyCodes.KEY_ESCAPE:
|
||||
break;
|
||||
default:
|
||||
if (searchBox == null) {
|
||||
showSearchBox();
|
||||
searchBox.fireEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(Widget sender) {
|
||||
FlowPanel panel = (FlowPanel) sender.getParent();
|
||||
FlowPanel tmpPanel = panel;
|
||||
while (tmpPanel != mainPanel) {
|
||||
FlowPanel parent = (FlowPanel) tmpPanel.getParent();
|
||||
|
||||
if (tmpPanel == focusedPanel && parent != mainPanel) {
|
||||
panel = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
tmpPanel = parent;
|
||||
}
|
||||
|
||||
tmpPanel = (FlowPanel) panel.getParent();
|
||||
while (tmpPanel != mainPanel) {
|
||||
if (tmpPanel.getWidgetCount() > 1)
|
||||
break;
|
||||
|
||||
panel = tmpPanel;
|
||||
tmpPanel = (FlowPanel) panel.getParent();
|
||||
}
|
||||
|
||||
setFocusedPanel(panel);
|
||||
}
|
||||
|
||||
private void setFocusedPanel(Panel panel) {
|
||||
if (selectedPanels != null) {
|
||||
for (Panel tmpPanel : selectedPanels) {
|
||||
tmpPanel.removeStyleDependentName("selected");
|
||||
}
|
||||
selectedPanels = null;
|
||||
}
|
||||
|
||||
if (focusedPanel != null) {
|
||||
focusedPanel.removeStyleDependentName("focused");
|
||||
focusedPanel = null;
|
||||
}
|
||||
|
||||
Phrase phrase = mapPanel2Phrase.get(panel);
|
||||
if (phrase != null) {
|
||||
status.setText(phrase.cat);
|
||||
selectedPanels = phrase.panels;
|
||||
if (selectedPanels != null) {
|
||||
for (Panel selPanel : selectedPanels) {
|
||||
selPanel.addStyleDependentName("selected");
|
||||
}
|
||||
}
|
||||
|
||||
focusedPanel = panel;
|
||||
focusedPanel.addStyleDependentName("focused");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class SearchBoxKeyboardHandler implements KeyUpHandler, KeyDownHandler {
|
||||
|
||||
public void onKeyDown(KeyDownEvent event) {
|
||||
switch (event.getNativeKeyCode()) {
|
||||
case KeyCodes.KEY_ESCAPE:
|
||||
hideSearchBox();
|
||||
fireSelection();
|
||||
setFocus(true);
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case KeyCodes.KEY_ENTER:
|
||||
searchBox.setText(searchBox.getText()+" ");
|
||||
fireSelection();
|
||||
hideSearchBox();
|
||||
setFocus(true);
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case KeyCodes.KEY_BACKSPACE:
|
||||
if ("".equals(searchBox.getText())) {
|
||||
String word = deleteLast();
|
||||
searchBox.setText(word);
|
||||
searchBox.setCursorPos(word.length());
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
switch (event.getNativeKeyCode()) {
|
||||
case KeyCodes.KEY_ESCAPE:
|
||||
case KeyCodes.KEY_ENTER:
|
||||
case KeyCodes.KEY_UP:
|
||||
case KeyCodes.KEY_DOWN:
|
||||
case KeyCodes.KEY_LEFT:
|
||||
case KeyCodes.KEY_RIGHT:
|
||||
break;
|
||||
default:
|
||||
fireSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright Miroslav Pokorny
|
||||
*
|
||||
* 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 org.grammaticalframework.ui.gwt.client.selection;
|
||||
|
||||
import org.grammaticalframework.ui.gwt.client.selection.support.SelectionSupport;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
|
||||
/**
|
||||
* The Selection class is a singleton that represents any selection made by the
|
||||
* user typically done with the mouse.
|
||||
*
|
||||
* @author Miroslav Pokorny (mP)
|
||||
*/
|
||||
public class Selection extends JavaScriptObject {
|
||||
|
||||
/**
|
||||
* The browser aware support that takes care of browser difference nasties.
|
||||
*/
|
||||
static private SelectionSupport support = (SelectionSupport) GWT.create(SelectionSupport.class);
|
||||
|
||||
static SelectionSupport getSupport() {
|
||||
return Selection.support;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document Selection singleton
|
||||
*
|
||||
* @return The singleton instance
|
||||
*/
|
||||
static public Selection getSelection() {
|
||||
return Selection.support.getSelection();
|
||||
}
|
||||
|
||||
protected Selection() {
|
||||
super();
|
||||
}
|
||||
|
||||
final public SelectionEndPoint getStart() {
|
||||
return Selection.getSupport().getStart(this);
|
||||
}
|
||||
|
||||
final public SelectionEndPoint getEnd() {
|
||||
return Selection.getSupport().getEnd(this);
|
||||
}
|
||||
|
||||
final public void select(final SelectionEndPoint start, final SelectionEndPoint end) {
|
||||
Selection.getSupport().select(this, start, end);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright Miroslav Pokorny
|
||||
*
|
||||
* 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 org.grammaticalframework.ui.gwt.client.selection;
|
||||
|
||||
import com.google.gwt.dom.client.Text;
|
||||
|
||||
/**
|
||||
* An end point uses a combination of a textNode and offset to mark the
|
||||
* start/end of a selection
|
||||
*
|
||||
* @author Miroslav Pokorny (mP)
|
||||
*/
|
||||
public class SelectionEndPoint {
|
||||
|
||||
public SelectionEndPoint() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SelectionEndPoint(Text text, final int offset) {
|
||||
super();
|
||||
|
||||
this.setTextNode(text);
|
||||
this.setOffset(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* The textNode containing the start/end of the selection.
|
||||
*/
|
||||
private Text textNode;
|
||||
|
||||
public Text getTextNode() {
|
||||
return textNode;
|
||||
}
|
||||
|
||||
public void setTextNode(final Text textNode) {
|
||||
this.textNode = textNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of characters starting from the beginning of the textNode
|
||||
* where the selection begins/ends.
|
||||
*/
|
||||
public int offset;
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void setOffset(final int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return super.toString() + ", offset: " + offset + ", textNode\"" + this.textNode + "\"";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright Miroslav Pokorny
|
||||
*
|
||||
* 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 org.grammaticalframework.ui.gwt.client.selection.support;
|
||||
|
||||
import org.grammaticalframework.ui.gwt.client.selection.Selection;
|
||||
import org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.dom.client.Text;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
|
||||
/**
|
||||
* A specialised SelectionSupport class that is adapted to handle
|
||||
* InternetExplorer differences from the standard implementation.
|
||||
*
|
||||
* @author Miroslav Pokorny (mP)
|
||||
*/
|
||||
public class InternetExplorerSelectionSupport extends SelectionSupport {
|
||||
|
||||
final static String PARENT_NODE = "parentNode";
|
||||
|
||||
@Override
|
||||
native public Selection getSelection()/*-{
|
||||
return $wnd.document.selection;
|
||||
}-*/;
|
||||
|
||||
@Override
|
||||
public SelectionEndPoint getStart(final Selection selection) {
|
||||
return this.getStart0(selection);
|
||||
}
|
||||
|
||||
native protected SelectionEndPoint getStart0(final Selection selection) /*-{
|
||||
var selectionRange = selection.createRange();
|
||||
var element = selectionRange.parentElement();
|
||||
|
||||
return this.@org.grammaticalframework.ui.gwt.client.selection.support.InternetExplorerSelectionSupport::getStart1(Lorg/grammaticalframework/ui/gwt/client/selection/Selection;Lcom/google/gwt/user/client/Element;)(selection,element);
|
||||
}-*/;
|
||||
|
||||
native protected SelectionEndPoint getStart1(final Selection selection, final Element element)/*-{
|
||||
var endPoint = null;
|
||||
|
||||
if(! selection.createRange ){
|
||||
alert( "selection.createRange" + selection.createRange );
|
||||
}
|
||||
|
||||
var selectionRange = selection.createRange();
|
||||
|
||||
var range = selectionRange.duplicate();
|
||||
range.moveToElementText( element );
|
||||
range.collapse();
|
||||
|
||||
// loop thru all the childNodes belonging to element.
|
||||
var childNodes = element.childNodes;
|
||||
for( var i = 0; i < childNodes.length; i++ ){
|
||||
var node = childNodes[ i ];
|
||||
var nodeType = node.nodeType;
|
||||
|
||||
// found an element check its child nodes...
|
||||
if( 1 == nodeType ){
|
||||
endPoint = this.@org.grammaticalframework.ui.gwt.client.selection.support.InternetExplorerSelectionSupport::getStart1(Lorg/grammaticalframework/ui/gwt/client/selection/Selection;Lcom/google/gwt/user/client/Element;)(selection,node);
|
||||
|
||||
if( null == endPoint ){
|
||||
range.move( "character", node.innerText.toString().length );
|
||||
continue;
|
||||
}
|
||||
// endPoint found stop searching....
|
||||
break;
|
||||
}
|
||||
|
||||
// found a textNode...
|
||||
if( 3 == nodeType ){
|
||||
var text = node.data;
|
||||
for( var j = 0; j < text.length; j++ ){
|
||||
// found selection start stop searching!
|
||||
if( selectionRange.compareEndPoints( "StartToStart", range ) == 0 ){
|
||||
endPoint = @org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint::new(Lcom/google/gwt/dom/client/Text;I)(node,j);
|
||||
break;
|
||||
}
|
||||
range.move("character", 1 );
|
||||
}
|
||||
// did the above for loop find the start ? if so stop escape!
|
||||
if( null != endPoint ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return endPoint;
|
||||
}-*/;
|
||||
|
||||
@Override
|
||||
public void select(final Selection selection, final SelectionEndPoint start, final SelectionEndPoint end) {
|
||||
this.setStart0(selection, start.getTextNode(), start.getOffset());
|
||||
this.setEnd0(selection, end.getTextNode(), end.getOffset());
|
||||
}
|
||||
|
||||
native private void setStart0(final Selection selection, final Text textNode, final int offset)/*-{
|
||||
var rangeOffset = offset;
|
||||
var moveToElement = null;
|
||||
|
||||
// try an element before $textNode counting the number of characters one has moved backwards...
|
||||
var node = textNode.previousSibling;
|
||||
|
||||
while( node ){
|
||||
// if a textNode is try its previous sibling...
|
||||
if( node.nodeType == 3 ){
|
||||
rangeOffset = rangeOffset + node.data.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
// found an element stop searching...
|
||||
if( node.nodeType == 1 ){
|
||||
moveToElement = node;
|
||||
rangeOffset = rangeOffset + node.innerText.toString().length;
|
||||
break;
|
||||
}
|
||||
|
||||
// ignore other types...
|
||||
node = node.previousSibling;
|
||||
}
|
||||
|
||||
// if moveToElement is null use textNode's parent.
|
||||
if( ! moveToElement ){
|
||||
moveToElement = textNode.parentNode;
|
||||
}
|
||||
|
||||
// update the start of selection range...
|
||||
var range = selection.createRange();
|
||||
range.moveToElementText( moveToElement );
|
||||
range.moveStart( "character", rangeOffset );
|
||||
range.select();
|
||||
}-*/;
|
||||
|
||||
native private void setEnd0(final Selection selection, final Text textNode, final int offset)/*-{
|
||||
var rangeOffset = offset;
|
||||
var moveToElement = null;
|
||||
|
||||
// try an element before $textNode counting the number of characters one has moved backwards...
|
||||
var node = textNode.previousSibling;
|
||||
|
||||
while( node ){
|
||||
// if textNode is try its previous sibling...
|
||||
if( node.nodeType == 3 ){
|
||||
rangeOffset = rangeOffset + node.data.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
// found an element stop searching...
|
||||
if( node.nodeType == 1 ){
|
||||
moveToElement = node;
|
||||
rangeOffset = rangeOffset + node.innerText.toString().length;
|
||||
break;
|
||||
}
|
||||
|
||||
// ignore other types...
|
||||
node = node.previousSibling;
|
||||
}
|
||||
|
||||
// if moveToElement is null use textNode's parent.
|
||||
if( ! moveToElement ){
|
||||
moveToElement = textNode.parentNode;
|
||||
}
|
||||
|
||||
// update the end of selection range...
|
||||
var range = selection.createRange();
|
||||
range.moveToElementText( moveToElement );
|
||||
range.moveStart( "character", rangeOffset );
|
||||
range.collapse();
|
||||
|
||||
var selectionRange = selection.createRange();
|
||||
selectionRange.setEndPoint( "EndToStart", range );
|
||||
selectionRange.select();
|
||||
}-*/;
|
||||
|
||||
@Override
|
||||
public SelectionEndPoint getEnd(final Selection selection) {
|
||||
return this.getEnd0(selection);
|
||||
}
|
||||
|
||||
protected native SelectionEndPoint getEnd0(final Selection selection) /*-{
|
||||
var selectionRange = selection.createRange();
|
||||
var element = selectionRange.parentElement();
|
||||
|
||||
return this.@org.grammaticalframework.ui.gwt.client.selection.support.InternetExplorerSelectionSupport::getEnd1(Lorg/grammaticalframework/ui/gwt/client/selection/Selection;Lcom/google/gwt/user/client/Element;)(selection,element);
|
||||
}-*/;
|
||||
|
||||
protected native SelectionEndPoint getEnd1(final Selection selection, final Element element)/*-{
|
||||
var endPoint = null;
|
||||
|
||||
var selectionRange = selection.createRange();
|
||||
|
||||
var range = selectionRange.duplicate();
|
||||
range.moveToElementText( element );
|
||||
range.collapse( true );
|
||||
|
||||
// loop thru all the childNodes belonging to element.
|
||||
var childNodes = element.childNodes;
|
||||
for( var i = 0; i < childNodes.length; i++ ){
|
||||
var node = childNodes[ i ];
|
||||
var nodeType = node.nodeType;
|
||||
|
||||
// found an element check its child nodes...
|
||||
if( 1 == nodeType ){
|
||||
endPoint = this.@org.grammaticalframework.ui.gwt.client.selection.support.InternetExplorerSelectionSupport::getEnd1(Lorg/grammaticalframework/ui/gwt/client/selection/Selection;Lcom/google/gwt/user/client/Element;)(selection,node);
|
||||
|
||||
if( null == endPoint ){
|
||||
range.move( "character", node.innerText.toString().length );
|
||||
continue;
|
||||
}
|
||||
// endPoint found stop searching....
|
||||
break;
|
||||
}
|
||||
|
||||
// found a textNode...
|
||||
if( 3 == nodeType ){
|
||||
var text = node.data;
|
||||
for( var j = 0; j < text.length; j++ ){
|
||||
// found selection end stop searching!
|
||||
if( selectionRange.compareEndPoints( "EndToStart", range ) == 0 ){
|
||||
endPoint = @org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint::new(Lcom/google/gwt/dom/client/Text;I)(node,j);
|
||||
break;
|
||||
}
|
||||
range.move( "character", 1 );
|
||||
}
|
||||
// did the above for loop find the end ? if so stop escape!
|
||||
if( null != endPoint ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return endPoint;
|
||||
}-*/;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright Miroslav Pokorny
|
||||
*
|
||||
* 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 org.grammaticalframework.ui.gwt.client.selection.support;
|
||||
|
||||
import org.grammaticalframework.ui.gwt.client.selection.Selection;
|
||||
import org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.dom.client.Text;
|
||||
import com.google.gwt.user.client.Element;
|
||||
|
||||
/**
|
||||
* This class provides the standard implementation of
|
||||
*
|
||||
* @author Miroslav Pokorny (mP)
|
||||
*/
|
||||
public class SelectionSupport {
|
||||
|
||||
public SelectionEndPoint getStart(final Selection selection) {
|
||||
return getStart0(selection);
|
||||
}
|
||||
|
||||
native private SelectionEndPoint getStart0(final Selection selection) /*-{
|
||||
var node = selection.anchorNode || null;
|
||||
var offset = selection.anchorOffset;
|
||||
return @org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint::new(Lcom/google/gwt/dom/client/Text;I)(value,j);
|
||||
}-*/;
|
||||
|
||||
public SelectionEndPoint getEnd(final Selection selection) {
|
||||
return getEnd0(selection);
|
||||
}
|
||||
|
||||
native private SelectionEndPoint getEnd0(final Selection selection) /*-{
|
||||
var node = selection.focusNode || null;
|
||||
var offset = selection.focusOffset;
|
||||
return @org.grammaticalframework.ui.gwt.client.selection.SelectionEndPoint::new(Lcom/google/gwt/dom/client/Text;I)(value,j);
|
||||
}-*/;
|
||||
|
||||
public void select(final Selection selection, final SelectionEndPoint start, final SelectionEndPoint end) {
|
||||
select0(selection, start.getTextNode(), start.getOffset(), end.getTextNode(), end.getOffset());
|
||||
}
|
||||
|
||||
native private void select0(final Selection selection, final Text startNode, final int startOffset, final Text endNode, final int endOffset)/*-{
|
||||
var range = startNode.ownerDocument.createRange();
|
||||
range.setStart(startNode, startOffset);
|
||||
range.setEnd(endNode, endOffset);
|
||||
|
||||
// delete all ranges then recreate...
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}-*/;
|
||||
|
||||
native public Selection getSelection()/*-{
|
||||
return $wnd.getSelection();
|
||||
}-*/;
|
||||
}
|
||||
253
src/ui/gwt/src/org/grammaticalframework/ui/gwt/public/Editor.css
Normal file
253
src/ui/gwt/src/org/grammaticalframework/ui/gwt/public/Editor.css
Normal file
@@ -0,0 +1,253 @@
|
||||
/** Add css rules here for your application. */
|
||||
|
||||
.my-TranslatePanel {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em
|
||||
}
|
||||
|
||||
.my-TextInputPanel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .frame {
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
background-color: #F3F3F3;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .text {
|
||||
padding: 1em;
|
||||
background-color: white;
|
||||
border-top: 1px solid #CCCCCC;
|
||||
border-left: 1px solid #CCCCCC;
|
||||
border-bottom: 2px solid #BBBBBB;
|
||||
border-right: 2px solid #BBBBBB;
|
||||
min-width: 100px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .toolbar {
|
||||
width: 100%;
|
||||
padding: 3px;
|
||||
background-attachement: scroll;
|
||||
background-color: #E5E5E5;
|
||||
background-image: url("background.png");
|
||||
background-position: 0px -192px;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .toolbar .button {
|
||||
float: left;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .toolbar .button:hover {
|
||||
margin: 1px;
|
||||
border: 1px solid rgb(147,194,241);
|
||||
}
|
||||
|
||||
.my-TextInputPanel .toolbar .status {
|
||||
padding: 1px;
|
||||
background-color: #E5E5E5;
|
||||
border: 1px solid #BBBBBB;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .searchbox {
|
||||
font-size: 150%;
|
||||
padding: 2px;
|
||||
display: inline;
|
||||
border-bottom: 1px dashed green;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .searchbox-error {
|
||||
border-bottom: 1px dashed red;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordspanel {
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordspanel-selected {
|
||||
background-color: rgb(147,194,241);
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordspanel-focused {
|
||||
background-color: rgb(147,194,241);
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordspanel-error {
|
||||
border-bottom: 1px dashed red;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordlabel {
|
||||
display: inline;
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
.my-TextInputPanel .wordspace {
|
||||
display: inline;
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
.my-SettingsPanel * {
|
||||
margin: 0 0.4em;
|
||||
}
|
||||
|
||||
.my-LinksPanel * {
|
||||
margin: 0 0.1em;
|
||||
}
|
||||
|
||||
.my-HeaderPanel {
|
||||
width: 100%;
|
||||
margin: 0 0.1em;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-color: rgb(122,165,214);
|
||||
}
|
||||
|
||||
.my-BrowsePanel {
|
||||
width: 100%;
|
||||
margin: 1em;
|
||||
border-width: 5px;
|
||||
border-color: rgb(122,165,214);
|
||||
}
|
||||
|
||||
.my-BrowsePanel .source {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.my-BrowseFrame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 1em;
|
||||
border-style:none;
|
||||
}
|
||||
|
||||
.my-QueryPanel {
|
||||
margin: 1em;
|
||||
border-width: 5px;
|
||||
border-color: rgb(122,165,214);
|
||||
}
|
||||
|
||||
.my-QueryBox {
|
||||
min-width: 630px;
|
||||
min-height: 94px;
|
||||
}
|
||||
|
||||
.my-ResultGrid {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.my-translations {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.my-translation-frame {
|
||||
margin: 0.5em;
|
||||
background: #D0E4F6;
|
||||
}
|
||||
|
||||
.my-translation-bar {
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.my-translation {
|
||||
margin: 0.2em;
|
||||
font-size: 150%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0% 50%;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.my-translation-btns {
|
||||
background: #DDDDDD;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.my-treeimage {
|
||||
width: 650px;
|
||||
height: 520px;
|
||||
}
|
||||
|
||||
.my-alignmentimage {
|
||||
width: 450px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.my-typeError {
|
||||
margin: 2px;
|
||||
padding: 12px;
|
||||
font-size: 150%;
|
||||
font-weight: bold;
|
||||
background: #CDFFDA;
|
||||
}
|
||||
|
||||
.my-typeError .title {
|
||||
background: #DDDDDD;
|
||||
}
|
||||
|
||||
.my-typeError .content {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.my-identifierLink:link {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.my-identifierLink:hover {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
background-color: rgb(147, 194, 241);
|
||||
}
|
||||
|
||||
.my-FridgeBagPanel {
|
||||
padding: 0.2em;
|
||||
margin-top: 1.5em;
|
||||
border: 3px solid #dddddd;
|
||||
}
|
||||
|
||||
.my-FridgeBagPanel-empty {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.my-Magnet {
|
||||
float: left;
|
||||
margin: 0.3em;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
padding: 0.3em;
|
||||
color: black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.my-SyntaxTable {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.my-SyntaxRow {
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.my-SyntaxLang {
|
||||
background: rgb(147,194,241);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.my-SyntaxLin {
|
||||
border: 1px solid rgb(147,194,241);
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 760 B |
BIN
src/ui/gwt/src/org/grammaticalframework/ui/gwt/public/new.png
Normal file
BIN
src/ui/gwt/src/org/grammaticalframework/ui/gwt/public/new.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 230 B |
Binary file not shown.
|
After Width: | Height: | Size: 518 B |
Reference in New Issue
Block a user