diff --git a/src/ui/android/res/layout/alternative_item.xml b/src/ui/android/res/layout/alternative_item.xml
index 49f090a26..40106c989 100644
--- a/src/ui/android/res/layout/alternative_item.xml
+++ b/src/ui/android/res/layout/alternative_item.xml
@@ -12,16 +12,18 @@
android:paddingRight="5dp" />
-
+
\ No newline at end of file
diff --git a/src/ui/android/res/layout/lexical_item.xml b/src/ui/android/res/layout/lexical_item.xml
new file mode 100644
index 000000000..e7f551491
--- /dev/null
+++ b/src/ui/android/res/layout/lexical_item.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java b/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java
index d394417ce..964daf92f 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java
@@ -103,8 +103,8 @@ public class AlternativesActivity extends ListActivity {
ImageView arrow = (ImageView) expandedView.findViewById(R.id.arrow);
arrow.setImageResource(R.drawable.open_arrow);
- WebView inflectionView = (WebView) expandedView.findViewById(R.id.lexical_inflection);
- ((RelativeLayout) expandedView).removeView(inflectionView);
+ View view = (View) expandedView.findViewById(R.id.desc_details);
+ ((RelativeLayout) expandedView).removeView(view);
expandedView = null;
}
@@ -117,10 +117,10 @@ public class AlternativesActivity extends ListActivity {
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
arrow.setImageResource(R.drawable.close_arrow);
- WebView inflectionView = (WebView) view.findViewById(R.id.lexical_inflection);
+ WebView inflectionView = (WebView) view.findViewById(R.id.desc_details);
if (inflectionView == null) {
inflectionView = new WebView(this);
- inflectionView.setId(R.id.lexical_inflection);
+ inflectionView.setId(R.id.desc_details);
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, R.id.lexical_desc);
@@ -136,18 +136,18 @@ public class AlternativesActivity extends ListActivity {
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
arrow.setImageResource(R.drawable.close_arrow);
- WebView inflectionView = (WebView) view.findViewById(R.id.lexical_inflection);
- if (inflectionView == null) {
- inflectionView = new WebView(this);
- inflectionView.setId(R.id.lexical_inflection);
+ ParseTreeView parseView = (ParseTreeView) view.findViewById(R.id.desc_details);
+ if (parseView == null) {
+ parseView = new ParseTreeView(this);
+ parseView.setId(R.id.desc_details);
RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.BELOW, R.id.lexical_desc);
- ((RelativeLayout) view).addView(inflectionView, params);
+ params.addRule(RelativeLayout.BELOW, R.id.alternative_desc);
+ ((RelativeLayout) view).addView(parseView, params);
}
- String content = String.format("[%.4f] %s", ep.getProb(), ep.getExpr());
- inflectionView.loadData(content, "text/plain; charset=UTF-8", null);
+ Object[] brackets = mTranslator.bracketedLinearize(ep.getExpr());
+ parseView.setBrackets(brackets);
expandedView = view;
}
@@ -160,16 +160,16 @@ public class AlternativesActivity extends ListActivity {
public View getView(int position, View convertView, ViewGroup parent) {
Object item = getItem(position);
- if (convertView == null) {
- LayoutInflater inflater = (LayoutInflater)
- getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.alternative_item, null);
- }
-
- TextView descView = (TextView)
- convertView.findViewById(R.id.lexical_desc);
-
if (item instanceof MorphoAnalysis) {
+ if (convertView == null) {
+ LayoutInflater inflater = (LayoutInflater)
+ getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.lexical_item, null);
+ }
+
+ TextView descView = (TextView)
+ convertView.findViewById(R.id.lexical_desc);
+
final String lemma = ((MorphoAnalysis) item).getLemma();
String phrase = mTranslator.generateLexiconEntry(lemma);
@@ -188,55 +188,62 @@ public class AlternativesActivity extends ListActivity {
}
}
});
- } else {
- if (item instanceof ExprProb) {
- final ExprProb ep = (ExprProb) item;
-
- String phrase = mTranslator.linearize(ep.getExpr());
+ } else if (item instanceof ExprProb) {
+ final ExprProb ep = (ExprProb) item;
+
+ if (convertView == null) {
+ LayoutInflater inflater = (LayoutInflater)
+ getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.alternative_item, null);
+ }
- // parse by words, marked by %, darkest red color
- if (phrase.charAt(0) == '%') {
- descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
- phrase = phrase.substring(2);
- }
+ TextView descView = (TextView)
+ convertView.findViewById(R.id.alternative_desc);
- // parse by chunks, marked by *, red color
- else if (phrase.charAt(0) == '*') {
- descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_chunk_utterance_bg));
- phrase = phrase.substring(2);
- }
+ String phrase = mTranslator.linearize(ep.getExpr());
- // parse error or unknown translations (in []) present, darkest red color
- else if (phrase.contains("parse error:") || phrase.contains("[")) {
- descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
- }
+ // parse by words, marked by %, darkest red color
+ if (phrase.charAt(0) == '%') {
+ descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
+ phrase = phrase.substring(2);
+ }
- // parse by domain grammar, marked by +, green color
- else if (phrase.charAt(0) == '+') {
- descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_best_utterance_bg));
- phrase = phrase.substring(2);
- }
-
- else {
- descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_utterance_bg));
- }
+ // parse by chunks, marked by *, red color
+ else if (phrase.charAt(0) == '*') {
+ descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_chunk_utterance_bg));
+ phrase = phrase.substring(2);
+ }
- descView.setText(phrase);
+ // parse error or unknown translations (in []) present, darkest red color
+ else if (phrase.contains("parse error:") || phrase.contains("[")) {
+ descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_worst_utterance_bg));
+ }
- convertView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- if (expandedView == view)
- collapse();
- else if (expandedView == null)
- expandExpr(view, ep);
- else {
- collapse();
- expandExpr(view, ep);
- }
+ // parse by domain grammar, marked by +, green color
+ else if (phrase.charAt(0) == '+') {
+ descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_best_utterance_bg));
+ phrase = phrase.substring(2);
+ }
+
+ else {
+ descView.setBackgroundDrawable(getResources().getDrawable(R.drawable.second_person_utterance_bg));
+ }
+
+ descView.setText(phrase);
+
+ convertView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (expandedView == view)
+ collapse();
+ else if (expandedView == null)
+ expandExpr(view, ep);
+ else {
+ collapse();
+ expandExpr(view, ep);
}
- });
- }
+ }
+ });
}
return convertView;
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/ParseTreeView.java b/src/ui/android/src/org/grammaticalframework/ui/android/ParseTreeView.java
new file mode 100644
index 000000000..f443ab2eb
--- /dev/null
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/ParseTreeView.java
@@ -0,0 +1,221 @@
+package org.grammaticalframework.ui.android;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.View;
+import org.grammaticalframework.pgf.Bracket;
+
+
+public class ParseTreeView extends View {
+ private static final float SISTER_SKIP = 25;
+ private static final float PARENT_SKIP = 0.5f;
+ private static final float ABOVE_LINE_SKIP = 0.1f;
+ private static final float BELOW_LINE_SKIP = 0.1f;
+
+ private Paint paint;
+ private Object[] brackets;
+
+ public ParseTreeView(Context context) {
+ super(context);
+ initialize();
+ }
+
+ public ParseTreeView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
+ }
+
+ private void initialize() {
+ paint = new Paint();
+ paint.setTextSize(60);
+ brackets = null;
+ }
+
+ public Object[] getBrackets() {
+ return brackets;
+ }
+
+ public void setBrackets(Object[] brackets) {
+ this.brackets = brackets;
+ }
+
+ static class MeasureResult {
+ float width = 0.0f;
+ float height = 0.0f;
+ float nodeTab = 0.0f;
+ float nodeCenter = 0.0f;
+ float childTab = 0.0f;
+ float localWidth = 0.0f;
+ float localHeight = 0.0f;
+ }
+
+ private MeasureResult mr = new MeasureResult();
+ private SparseArray coords = new SparseArray();
+
+ private void measureTree(Object o, PointF zeroPoint) {
+ if (o instanceof Bracket) {
+ Bracket bracket = (Bracket) o;
+
+ Rect bounds = new Rect();
+ paint.getTextBounds(bracket.cat,0,bracket.cat.length(),bounds);
+ float localWidth = bounds.width();
+ float localHeight = bounds.height();
+ float layerHeight = localHeight * (1.0f + BELOW_LINE_SKIP + ABOVE_LINE_SKIP + PARENT_SKIP);
+
+ PointF local = coords.get(bracket.fid);
+ if (local == null) {
+ if (zeroPoint != null)
+ coords.put(bracket.fid, zeroPoint);
+ } else {
+ localWidth = 0;
+ }
+
+ float subWidth = 0.0f;
+ float subHeight = 0.0f;
+ float nodeCenter = 0.0f;
+ for (int i = 0; i < bracket.children.length; i++) {
+ measureTree(bracket.children[i], zeroPoint);
+
+ if (i == 0) {
+ nodeCenter += (subWidth + mr.nodeCenter) / 2.0;
+ }
+ if (i == bracket.children.length - 1) {
+ nodeCenter += (subWidth + mr.nodeCenter) / 2.0;
+ }
+
+ subWidth += mr.width;
+ if (i < bracket.children.length - 1) {
+ subWidth += SISTER_SKIP;
+ }
+
+ if (subHeight < mr.height)
+ subHeight = mr.height;
+ }
+ float localLeft = localWidth / 2.0f;
+ float subLeft = nodeCenter;
+ float totalLeft = Math.max(localLeft, subLeft);
+ float localRight = localWidth / 2.0f;
+ float subRight = subWidth - nodeCenter;
+ float totalRight = Math.max(localRight, subRight);
+ mr.width = totalLeft + totalRight;
+ mr.height = layerHeight + subHeight;
+ mr.childTab = totalLeft - subLeft;
+ mr.nodeTab = totalLeft - localLeft;
+ mr.nodeCenter = nodeCenter + mr.childTab;
+ mr.localWidth = localWidth;
+ mr.localHeight = localHeight;
+ } else {
+ String word = o.toString();
+
+ Rect bounds = new Rect();
+ paint.getTextBounds(word,0,word.length(),bounds);
+ mr.width = bounds.width();
+ mr.height = bounds.height();
+ mr.nodeTab = 0.0f;
+ mr.nodeCenter = bounds.width() / 2.0f;
+ mr.childTab = 0.0f;
+ mr.localWidth = bounds.width();
+ mr.localHeight = bounds.height();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (brackets == null) {
+ setMeasuredDimension(0, 0);
+ return;
+ }
+
+ float width = 0.0f;
+ float height = 0.0f;
+ PointF zeroPoint = new PointF();
+ for (int i = 0; i < brackets.length; i++) {
+ measureTree(brackets[i], zeroPoint);
+
+ width += mr.width;
+ if (i < brackets.length - 1) {
+ width += SISTER_SKIP;
+ }
+
+ if (height < mr.height)
+ height = mr.height;
+ }
+
+ width += 10;
+ height += 10;
+
+ int w = getPaddingLeft() + (int) width + getPaddingRight();
+ int h = getPaddingTop() + (int) height + getPaddingBottom();
+
+ setMeasuredDimension(w, h);
+ }
+
+ private void drawTree(Canvas canvas,
+ float x, float y, float bottom, PointF parentPoint,
+ Object o) {
+ if (o instanceof Bracket) {
+ Bracket bracket = (Bracket) o;
+
+ PointF lineStart = coords.get(bracket.fid);
+ if (lineStart == null) {
+ lineStart = new PointF(x + mr.nodeCenter, y + mr.localHeight * (1.0f + BELOW_LINE_SKIP));
+ coords.put(bracket.fid, lineStart);
+
+ if (parentPoint != null) {
+ float lineEndX = x + mr.nodeCenter;
+ float lineEndY = y;
+ canvas.drawLine(parentPoint.x, parentPoint.y, lineEndX, lineEndY, paint);
+ }
+
+ canvas.drawText(bracket.cat, x+mr.nodeTab, y+mr.localHeight, paint);
+ }
+
+ float layerMultiplier = (1.0f + BELOW_LINE_SKIP + ABOVE_LINE_SKIP + PARENT_SKIP);
+ float layerHeight = mr.localHeight * layerMultiplier;
+ float childStartX = x + mr.childTab;
+ float childStartY = y + layerHeight;
+ for (int i = 0; i < bracket.children.length; i++) {
+ Object child = bracket.children[i];
+ measureTree(child, null);
+ float w = mr.width;
+ drawTree(canvas, childStartX, childStartY, bottom, lineStart, child);
+ childStartX += w + SISTER_SKIP;
+ }
+ } else {
+ float lineEndX = x + mr.nodeCenter;
+ float lineEndY = bottom - mr.height;
+ canvas.drawLine(parentPoint.x, parentPoint.y, lineEndX, lineEndY, paint);
+ canvas.drawText(o.toString(), x, bottom, paint);
+ }
+ }
+
+ @Override
+ protected void onDraw (Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (brackets == null) {
+ return;
+ }
+
+ coords.clear();
+
+ float startX = getPaddingLeft();
+ for (int i = 0; i < brackets.length; i++) {
+ Object child = brackets[i];
+
+ measureTree(child, null);
+ float w = mr.width;
+ drawTree(canvas, startX, getPaddingTop(), getPaddingTop()+mr.height, null, child);
+ startX += w + SISTER_SKIP;
+ }
+ }
+}
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java b/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java
index 4643eaf4e..e9a5ecee5 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java
@@ -340,6 +340,11 @@ public class Translator {
return targetLang.linearize(expr);
}
+ public Object[] bracketedLinearize(Expr expr) {
+ Concr targetLang = getTargetConcr();
+ return targetLang.bracketedLinearize(expr);
+ }
+
public String generateLexiconEntry(String lemma) {
Concr sourceLang = getSourceConcr();
Concr targetLang = getTargetConcr();