Index: src/org/apache/lucene/luke/core/HighFreqTerms.java
===================================================================
--- src/org/apache/lucene/luke/core/HighFreqTerms.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/HighFreqTerms.java	(working copy)
@@ -100,10 +100,10 @@
   }
   
   /**
-   * 
-   * @param reader
-   * @param numTerms
-   * @param field
+   * // TODO move this method to org.apache.lucene.misc.HighFreqTerms
+   * @param reader IndexReader
+   * @param numTerms the max number of terms
+   * @param fieldNames tye array of field names
    * @return TermStats[] ordered by terms with highest docFreq first.
    * @throws Exception
    */
Index: src/org/apache/lucene/luke/core/IndexInfo.java
===================================================================
--- src/org/apache/lucene/luke/core/IndexInfo.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/IndexInfo.java	(working copy)
@@ -177,6 +177,7 @@
       }
     }
   }
+
   
   /**
    * @return the reader
Index: src/org/apache/lucene/luke/core/TableComparator.java
===================================================================
--- src/org/apache/lucene/luke/core/TableComparator.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/TableComparator.java	(working copy)
@@ -1,63 +0,0 @@
-package org.apache.lucene.luke.core;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you 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.
- */
-
-import java.util.Comparator;
-
-import org.apache.pivot.collections.Dictionary;
-import org.apache.pivot.collections.Map;
-import org.apache.pivot.wtk.SortDirection;
-import org.apache.pivot.wtk.TableView;
-
-public class TableComparator implements Comparator<Map<String,String>> {
-  private TableView tableView;
-  
-  public TableComparator(TableView fieldsTable) {
-    if (fieldsTable == null) {
-      throw new IllegalArgumentException();
-    }
-    
-    this.tableView = fieldsTable;
-  }
-  
-  @Override
-  public int compare(Map<String,String> o1, Map<String,String> o2) {
-    Dictionary.Pair<String, SortDirection> sort = tableView.getSort().get(0);
-
-    int result;
-    if (sort.key.equals("name")) {
-      // sort by name
-      result = o1.get(sort.key).compareTo(o2.get(sort.key));
-    } else if (sort.key.equals("termCount")) {
-      // sort by termCount
-      Integer c1 = Integer.parseInt(o1.get(sort.key));
-      Integer c2 = Integer.parseInt(o2.get(sort.key));
-      result = c1.compareTo(c2);
-    } else {
-      // other (ignored)
-      result = 0;
-    }
-    //int result = o1.get("name").compareTo(o2.get("name"));
-    //SortDirection sortDirection = tableView.getSort().get("name");
-    SortDirection sortDirection = sort.value;
-    result *= (sortDirection == SortDirection.DESCENDING ? 1 : -1);
-
-    return result * -1;
-  }
-  
-}
\ No newline at end of file
Index: src/org/apache/lucene/luke/core/TermStats.java
===================================================================
--- src/org/apache/lucene/luke/core/TermStats.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/TermStats.java	(working copy)
@@ -26,13 +26,15 @@
   public long totalTermFreq;
   
   TermStats(String field, BytesRef termtext, int df) {
-    this.termtext = (BytesRef)termtext.clone();
+    //this.termtext = (BytesRef)termtext.clone();
+    this.termtext = BytesRef.deepCopyOf(termtext);
     this.field = field;
     this.docFreq = df;
   }
   
   TermStats(String field, BytesRef termtext, int df, long tf) {
-    this.termtext = (BytesRef)termtext.clone();
+    //this.termtext = (BytesRef)termtext.clone();
+    this.termtext = BytesRef.deepCopyOf(termtext);
     this.field = field;
     this.docFreq = df;
     this.totalTermFreq = tf;
Index: src/org/apache/lucene/luke/core/Util.java
===================================================================
--- src/org/apache/lucene/luke/core/Util.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/Util.java	(working copy)
@@ -19,11 +19,19 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 
 import org.apache.lucene.document.DateTools.Resolution;
+import org.apache.lucene.index.FieldInfo;
 import org.apache.lucene.index.FieldInfo.IndexOptions;
 import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.luke.core.decoders.*;
+import org.apache.lucene.search.similarities.TFIDFSimilarity;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.FSDirectory;
 import org.apache.lucene.store.MMapDirectory;
@@ -161,18 +169,20 @@
     return sb.toString();
   }
   
-  public static String fieldFlags(IndexableField f) {
-    if (f == null) {
-      return "-----------";
-    }
+  public static String fieldFlags(IndexableField f, FieldInfo info) {
+    //if (f == null) {
+    //  return "-----------";
+    //}
     StringBuffer flags = new StringBuffer();
-    if (f != null && f.fieldType().indexed()) flags.append("I");
+    //if (f != null && f.fieldType().indexed()) flags.append("I");
+    if (info != null && info.isIndexed()) flags.append("I");
     else flags.append("-");
     if (f != null && f.fieldType().tokenized()) flags.append("T");
     else flags.append("-");
     if (f != null && f.fieldType().stored()) flags.append("S");
     else flags.append("-");
-    if (f != null && f.fieldType().storeTermVectors()) flags.append("V");
+    //if (f != null && f.fieldType().storeTermVectors()) flags.append("V");
+    if (info != null && info.hasVectors()) flags.append("V");
     else flags.append("-");
     if (f != null && f.fieldType().storeTermVectorOffsets()) flags.append("o");
     else flags.append("-");
@@ -180,9 +190,13 @@
     else flags.append("-");
     if (f != null && f.fieldType().storeTermVectorPayloads()) flags.append("a");
     else flags.append("-");
-    IndexOptions opts = f.fieldType().indexOptions();
+    if (info != null && info.hasPayloads()) flags.append("P");
+    else flags.append("-");
+    //IndexOptions opts = f.fieldType().indexOptions();
+    IndexOptions opts = info.getIndexOptions();
     // TODO: how to handle these codes
-    if (f.fieldType().indexed() && opts != null) {
+    //if (f.fieldType().indexed() && opts != null) {
+    if (info.isIndexed() && opts != null) {
       switch (opts) {
       case DOCS_ONLY:
         flags.append("1");
@@ -199,13 +213,32 @@
     } else {
       flags.append("-");
     }
-    if (f != null && f.fieldType().omitNorms()) flags.append("O");
+    //if (f != null && f.fieldType().omitNorms()) flags.append("O");
+    if (info != null && !info.hasNorms()) flags.append("O");
     else flags.append("-");
+    // TODO lazy
+    flags.append("-");
+    if (f != null && f.binaryValue() != null) flags.append("B");
+    else flags.append("-");
 
 
     return flags.toString();
   }
-  
+
+  public static String docValuesType(FieldInfo info) {
+    if (info == null || !info.hasDocValues() || info.getDocValuesType() == null) {
+      return "---";
+    }
+    return info.getDocValuesType().name();
+  }
+
+  public static String normType(FieldInfo info) {
+    if (info == null || !info.hasNorms() || info.getNormType() == null) {
+      return "---";
+    }
+    return info.getNormType().name();
+  }
+
   public static Resolution getResolution(String key) {
     if (key == null || key.trim().length() == 0) {
       return Resolution.MILLISECOND;
@@ -270,4 +303,56 @@
       return String.valueOf(len / 1048576);
     }
   }
+
+  public static float decodeNormValue(long v, String fieldName, TFIDFSimilarity sim) throws Exception {
+    try {
+      return sim.decodeNormValue(v);
+    } catch (Exception e) {
+      throw new Exception("ERROR decoding norm for field "  + fieldName + ":" + e.toString());
+    }
+  }
+
+  public static long encodeNormValue(float v, String fieldName, TFIDFSimilarity sim) throws Exception {
+    try {
+      return sim.encodeNormValue(v);
+    } catch (Exception e) {
+      throw new Exception("ERROR encoding norm for field "  + fieldName + ":" + e.toString());
+    }
+  }
+
+
+  public static List<Decoder> loadDecoders() {
+    List decoders = new ArrayList();
+    // default decoders
+    decoders.add(new BinaryDecoder());
+    decoders.add(new DateDecoder());
+    decoders.add(new NumDoubleDecoder());
+    decoders.add(new NumFloatDecoder());
+    decoders.add(new NumIntDecoder());
+    decoders.add(new NumLongDecoder());
+    decoders.add(new StringDecoder());
+
+    // load external decoders
+    try {
+      String extLoaders = System.getProperty("luke.ext.decoder.loader");
+      if (extLoaders != null) {
+        String[] classes = extLoaders.split(",");
+        for (String className : classes) {
+          Class clazz = Class.forName(className);
+          Class[] interfaces = clazz.getInterfaces();
+          if (Arrays.asList(interfaces).indexOf(DecoderLoader.class) < 0) {
+            throw new Exception(className + " is not a DecoderLoader.");
+          }
+          DecoderLoader loader = (DecoderLoader)clazz.newInstance();
+          List<Decoder> extDecoders = loader.loadDecoders();
+          for (Decoder dec : extDecoders) {
+            decoders.add(dec);
+          }
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return decoders;
+  }
 }
Index: src/org/apache/lucene/luke/core/decoders/BinaryDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/BinaryDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/BinaryDecoder.java	(working copy)
@@ -19,23 +19,18 @@
 
 import org.apache.lucene.document.Field;
 import org.apache.lucene.luke.core.Util;
+import org.apache.lucene.util.BytesRef;
 
 public class BinaryDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) throws Exception {
-    byte[] data;
-    if (value instanceof byte[]) {
-      data = (byte[])value;
-    } else {
-      data = value.toString().getBytes();
-    }
-    return Util.bytesToHex(data, 0, data.length, false);
+  public String decodeTerm(String fieldName, BytesRef value) throws Exception {
+    return Util.bytesToHex(value.bytes, 0, value.length, false);
   }
 
   @Override
   public String decodeStored(String fieldName, Field value) throws Exception {
-    return decodeTerm(fieldName, value);
+    return decodeTerm(fieldName, new BytesRef(value.stringValue()));
   }
   
   public String toString() {
Index: src/org/apache/lucene/luke/core/decoders/DateDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/DateDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/DateDecoder.java	(working copy)
@@ -19,17 +19,18 @@
 
 import org.apache.lucene.document.DateTools;
 import org.apache.lucene.document.Field;
+import org.apache.lucene.util.BytesRef;
 
 public class DateDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) throws Exception {
+  public String decodeTerm(String fieldName, BytesRef value) throws Exception {
     return DateTools.stringToDate(value.toString()).toString();
   }
   
   @Override
   public String decodeStored(String fieldName, Field value) throws Exception {
-    return decodeTerm(fieldName, value.stringValue());
+    return decodeTerm(fieldName, new BytesRef(value.stringValue()));
   }
   
   public String toString() {
Index: src/org/apache/lucene/luke/core/decoders/Decoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/Decoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/Decoder.java	(working copy)
@@ -18,9 +18,10 @@
  */
 
 import org.apache.lucene.document.Field;
+import org.apache.lucene.util.BytesRef;
 
 public interface Decoder {
   
-  public String decodeTerm(String fieldName, Object value) throws Exception;
+  public String decodeTerm(String fieldName, BytesRef value) throws Exception;
   public String decodeStored(String fieldName, Field value) throws Exception;
 }
Index: src/org/apache/lucene/luke/core/decoders/DecoderLoader.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/DecoderLoader.java	(revision 0)
+++ src/org/apache/lucene/luke/core/decoders/DecoderLoader.java	(working copy)
@@ -0,0 +1,24 @@
+package org.apache.lucene.luke.core.decoders;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import java.util.List;
+
+public interface DecoderLoader {
+  public List<Decoder> loadDecoders();
+}
Index: src/org/apache/lucene/luke/core/decoders/NumDoubleDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/NumDoubleDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/NumDoubleDecoder.java	(working copy)
@@ -1,5 +1,22 @@
 package org.apache.lucene.luke.core.decoders;
 
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
 import org.apache.lucene.document.Field;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.NumericUtils;
@@ -7,9 +24,8 @@
 public class NumDoubleDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) {
-    BytesRef ref = new BytesRef(value.toString());
-    return Double.toString(NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(ref)));
+  public String decodeTerm(String fieldName, BytesRef value) {
+    return Double.toString(NumericUtils.sortableLongToDouble(NumericUtils.prefixCodedToLong(value)));
   }
 
   @Override
@@ -18,7 +34,7 @@
   }
 
   public String toString() {
-    return "numeric-double";
+    return "numeric double";
   }
 
 }
Index: src/org/apache/lucene/luke/core/decoders/NumFloatDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/NumFloatDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/NumFloatDecoder.java	(working copy)
@@ -6,9 +6,9 @@
 
 public class NumFloatDecoder implements Decoder {
   @Override
-  public String decodeTerm(String fieldName, Object value) {
-    BytesRef ref = new BytesRef(value.toString());
-    return Float.toString(NumericUtils.sortableIntToFloat(NumericUtils.prefixCodedToInt(ref)));
+  public String decodeTerm(String fieldName, BytesRef value) {
+    //BytesRef ref = new BytesRef(value.toString());
+    return Float.toString(NumericUtils.sortableIntToFloat(NumericUtils.prefixCodedToInt(value)));
   }
 
   @Override
@@ -17,7 +17,7 @@
   }
 
   public String toString() {
-    return "numeric-float";
+    return "numeric float";
   }
 
 }
Index: src/org/apache/lucene/luke/core/decoders/NumIntDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/NumIntDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/NumIntDecoder.java	(working copy)
@@ -24,9 +24,8 @@
 public class NumIntDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) {
-    BytesRef ref = new BytesRef(value.toString());
-    return Integer.toString(NumericUtils.prefixCodedToInt(ref));
+  public String decodeTerm(String fieldName, BytesRef value) {
+    return Integer.toString(NumericUtils.prefixCodedToInt(value));
   }
   
   @Override
@@ -35,7 +34,7 @@
   }
   
   public String toString() {
-    return "numeric-int";
+    return "numeric int";
   }
 
 }
Index: src/org/apache/lucene/luke/core/decoders/NumLongDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/NumLongDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/NumLongDecoder.java	(working copy)
@@ -24,9 +24,8 @@
 public class NumLongDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) {
-    BytesRef ref = new BytesRef(value.toString());
-    return Long.toString(NumericUtils.prefixCodedToLong(ref));
+  public String decodeTerm(String fieldName, BytesRef value) {
+    return Long.toString(NumericUtils.prefixCodedToLong(value));
   }
   
   @Override
@@ -35,7 +34,7 @@
   }
   
   public String toString() {
-    return "numeric-long";
+    return "numeric long";
   }
 
 }
Index: src/org/apache/lucene/luke/core/decoders/SolrDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/SolrDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/SolrDecoder.java	(working copy)
@@ -24,8 +24,14 @@
 
 import org.apache.lucene.document.Field;
 import org.apache.lucene.luke.core.ClassFinder;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.CharsRef;
 import org.apache.solr.schema.FieldType;
 
+/**
+ * NOT Used.
+ * The logic here has moved to org.apache.lucene.ext.SolrDecoderLoader.
+ */
 public class SolrDecoder implements Decoder {
   private static final String solr_prefix = "org.apache.solr.schema.";
   
@@ -86,8 +92,9 @@
     name = type;
   }
   
-  public String decodeTerm(String fieldName, Object value) throws Exception {
-    return fieldType.indexedToReadable(value.toString());
+  public String decodeTerm(String fieldName, BytesRef value) throws Exception {
+    CharsRef chars = fieldType.indexedToReadable(value, new CharsRef());
+    return chars.toString();
   }
   
   public String decodeStored(String fieldName, Field value)
@@ -100,3 +107,4 @@
   }
   
 }
+
Index: src/org/apache/lucene/luke/core/decoders/StringDecoder.java
===================================================================
--- src/org/apache/lucene/luke/core/decoders/StringDecoder.java	(revision 1655665)
+++ src/org/apache/lucene/luke/core/decoders/StringDecoder.java	(working copy)
@@ -18,17 +18,18 @@
  */
 
 import org.apache.lucene.document.Field;
+import org.apache.lucene.util.BytesRef;
 
 public class StringDecoder implements Decoder {
 
   @Override
-  public String decodeTerm(String fieldName, Object value) {
-    return value != null ? value.toString() : "(null)";
+  public String decodeTerm(String fieldName, BytesRef value) {
+    return value != null ? value.utf8ToString() : "(null)";
   }
   
   @Override
   public String decodeStored(String fieldName, Field value) {
-    return decodeTerm(fieldName, value.stringValue());
+    return value.stringValue();
   }
 
   public String toString() {
Index: src/org/apache/lucene/luke/ext/SolrDecoderLoader.java
===================================================================
--- src/org/apache/lucene/luke/ext/SolrDecoderLoader.java	(revision 0)
+++ src/org/apache/lucene/luke/ext/SolrDecoderLoader.java	(working copy)
@@ -0,0 +1,81 @@
+package org.apache.lucene.luke.ext;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import org.apache.lucene.document.Field;
+import org.apache.lucene.luke.core.ClassFinder;
+import org.apache.lucene.luke.core.decoders.Decoder;
+import org.apache.lucene.luke.core.decoders.DecoderLoader;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.CharsRef;
+import org.apache.solr.schema.FieldType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SolrDecoderLoader implements DecoderLoader {
+  private static final String solr_prefix = "org.apache.solr.schema.";
+
+  @Override
+  public List<Decoder> loadDecoders() {
+    List<Decoder> decoders = new ArrayList<Decoder>();
+    try {
+      Class[] classes = ClassFinder.getInstantiableSubclasses(FieldType.class);
+      if (classes == null || classes.length == 0) {
+        throw new ClassNotFoundException("Missing Solr types???");
+      }
+      for (Class cls : classes) {
+        FieldType ft = (FieldType) cls.newInstance();
+        if (cls.getName().startsWith(solr_prefix)) {
+          String name = "solr." + cls.getName().substring(solr_prefix.length());
+          decoders.add(new SolrDecoder(name, ft));
+        }
+      }
+    } catch (Exception e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return decoders;
+  }
+}
+
+class SolrDecoder implements Decoder {
+  private String name;
+  private FieldType fieldType;
+
+  public SolrDecoder(String name, FieldType fieldType) {
+    this.name = name;
+    this.fieldType = fieldType;
+  }
+
+  public String decodeTerm(String fieldName, BytesRef value) throws Exception {
+    CharsRef chars = fieldType.indexedToReadable(value, new CharsRef());
+    return chars.toString();
+  }
+
+  public String decodeStored(String fieldName, Field value)
+    throws Exception {
+    return fieldType.storedToReadable(value);
+  }
+
+  public String toString() {
+    return name;
+  }
+
+}
+
Index: src/org/apache/lucene/luke/ui/DocumentsTab.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/DocumentsTab.bxml	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/DocumentsTab.bxml	(working copy)
@@ -1,169 +1,259 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <luke:DocumentsTab bxml:id="DocumentsTab"
-	styles="{verticalSpacing:2,horizontalSpacing:2,padding:4,backgroundColor:11}"
 	xmlns:bxml="http://pivot.apache.org/bxml" xmlns:content="org.apache.pivot.wtk.content"
-	xmlns="org.apache.pivot.wtk" xmlns:luke="org.apache.lucene.luke.ui">
+	xmlns="org.apache.pivot.wtk" xmlns:luke="org.apache.lucene.luke.ui"
+	orientation="vertical" splitRatio="0.30">
 
+	<bxml:define>
+		<bxml:include bxml:id="posAndOffsetsWindow" src="PosAndOffsetsWindow.bxml" />
+	</bxml:define>
+	<bxml:define>
+		<bxml:include bxml:id="tvWindow" src="TermVectorWindow.bxml" />
+	</bxml:define>
+	<bxml:define>
+		<bxml:include bxml:id="fieldDataWindow" src="FieldDataWindow.bxml" />
+	</bxml:define>
+	<bxml:define>
+		<bxml:include bxml:id="fieldNormWindow" src="FieldNormWindow.bxml" />
+	</bxml:define>
 
-	<columns>
-		<TablePane.Column width="1*" />
-	</columns>
-	<rows>
-		<TablePane.Row>
-			<FlowPane styles="{padding:10}">
-				<BoxPane orientation="vertical">
-					<Label text="%documentsTab_browseByDocNum" />
-					<BoxPane>
-						<Label text="Doc. #:" />
-						<Label text="0" />
-						<PushButton preferredHeight="20" action="prevDoc">
-							<buttonData>
-								<content:ButtonData icon="/img/prev.png" />
-							</buttonData>
-						</PushButton>
-						<TextInput preferredWidth="48" bxml:id="docNum" />
-						<PushButton preferredHeight="20" action="nextDoc">
-							<buttonData>
-								<content:ButtonData icon="/img/next.png" />
-							</buttonData>
-						</PushButton>
-						<Label bxml:id="maxDocs" text="?" />
+	<top>
+		<SplitPane orientation="horizontal" splitRatio="0.20" styles="{useShadow:true}">
+			<left>
+				<Border styles="{padding:1}">
+				<content>
+				<TablePane styles="{verticalSpacing:1,horizontalSpacing:1,padding:5,backgroundColor:11}">
+					<columns>
+						<TablePane.Column width="1*" />
+					</columns>
+					<rows>
+						<TablePane.Row>
+							<BoxPane orientation="vertical">
+								<Label text="%documentsTab_browseByDocNum" styles="{padding:2,font:{bold:true}}"/>
+								<Label text="Doc. #" styles="{padding:2}"/>
+								<BoxPane orientation="horizontal">
+									<Label text="0" styles="{padding:2}"/>
+									<PushButton preferredHeight="20" action="prevDoc">
+										<buttonData>
+											<content:ButtonData icon="/img/prev.png" />
+										</buttonData>
+									</PushButton>
+									<TextInput preferredWidth="48" bxml:id="docNum" />
+									<PushButton preferredHeight="20" action="nextDoc">
+										<buttonData>
+											<content:ButtonData icon="/img/next.png" />
+										</buttonData>
+									</PushButton>
+									<Label bxml:id="maxDocs" text="?" styles="{padding:2}"/>
+								</BoxPane>
+							</BoxPane>
+						</TablePane.Row>
+					</rows>
+				</TablePane>
+				</content>
+				</Border>
+			</left>
+			<right>
+				<SplitPane orientation="horizontal" splitRatio="0.50" styles="{useShadow:true}">
+					<left>
+						<Border styles="{padding:1}">
+						<content>
+						<TablePane styles="{verticalSpacing:2,horizontalSpacing:1,padding:5,backgroundColor:11}">
+							<columns>
+								<TablePane.Column width="1*" />
+							</columns>
+							<rows>
+								<TablePane.Row>
+									<BoxPane orientation="vertical">
+										<Label text="%documentsTab_browseByTerm" styles="{padding:1,font:{bold:true}}"/>
+										<Label text="%documentsTab_selectField" styles="{wrapText:true}"/>
+										<Label text="%documentsTab_enterTermHint" styles="{wrapText:true}"/>
+										<ListButton bxml:id="fieldsList" listSize="20" />
+										<Label text="%documentsTab_term" />
+										<BoxPane>
+											<PushButton buttonData="%documentsTab_firstTerm"
+																	action="showFirstTerm" />
+											<TextInput bxml:id="termText" />
+											<PushButton action="showNextTerm">
+												<buttonData>
+													<content:ButtonData icon="/img/next.png" />
+												</buttonData>
+											</PushButton>
+										</BoxPane>
+									</BoxPane>
+								</TablePane.Row>
 
-					</BoxPane>
-				</BoxPane>
+								<TablePane.Row>
+									<BoxPane>
+										<Label text="%documentsTab_decodedValue" />
+										<TextArea bxml:id="decText" />
+									</BoxPane>
+								</TablePane.Row>
+							</rows>
+						</TablePane>
+						</content>
+						</Border>
+					</left>
+					<right>
+						<Border styles="{padding:1}">
+						<content>
+						<TablePane styles="{verticalSpacing:2,horizontalSpacing:1,padding:5,backgroundColor:11}">
+							<columns>
+								<TablePane.Column width="1*" />
+							</columns>
+							<rows>
+								<TablePane.Row>
+									<BoxPane orientation="vertical">
+										<Label text="%documentsTab_browseDocsWithTerm" styles="{padding:1,font:{bold:true}}"/>
+										<Label text="%documentsTab_selectTerm" styles="{wrapText:true}"/>
+										<BoxPane>
+											<!--Label text="%documentsTab_document" /-->
+											<PushButton buttonData="%documentsTab_firstDoc" action="showFirstTermDoc" />
+											<PushButton action="showNextTermDoc">
+												<buttonData>
+													<content:ButtonData icon="/img/next.png" />
+												</buttonData>
+											</PushButton>
 
-				<BoxPane orientation="vertical">
-					<Label text="%documentsTab_browseByTerm" />
-					<Label text="%documentsTab_enterTermHint" />
-					<BoxPane>
-						<PushButton buttonData="%documentsTab_firstTerm"
-							action="showFirstTerm" />
-						<Label text="%documentsTab_term" />
-						<ListButton bxml:id="fieldsList" listSize="20" />
-						<TextInput bxml:id="termText" />
-						<PushButton action="showNextTerm">
-							<buttonData>
-								<content:ButtonData icon="/img/next.png" />
-							</buttonData>
-						</PushButton>
-					</BoxPane>
-				</BoxPane>
+											<Label text=" ("/>
+											<Label bxml:id="tdNum" text="?" />
+											<Label text=" of " />
+											<Label bxml:id="tdMax" text="?" />
+											<Label text=" documents )" />
+										</BoxPane>
+									</BoxPane>
+								</TablePane.Row>
 
+								<TablePane.Row>
+									<BoxPane orientation="vertical">
+										<BoxPane>
+											<Label text="%documentsTab_termFreqInDoc" />
+											<Label bxml:id="tFreq" text="?" />
+										</BoxPane>
+										<PushButton bxml:id="bPos" buttonData="%documentsTab_showPositions"
+																action="showPositions" />
+									</BoxPane>
+								</TablePane.Row>
 
-				<!-- second row -->
-				<Label text="%documentsTab_decodedValue" />
-				<TextArea bxml:id="decText" />
+								<TablePane.Row>
+									<Separator/>
+								</TablePane.Row>
 
-				<Separator />
-				<BoxPane orientation="vertical">
-					<BoxPane>
-						<Label text="%documentsTab_browseDocsWithTerm" />
-						<Label text="( " />
-						<Label bxml:id="dFreq" text="0" />
-						<Label text=" documents)" />
-					</BoxPane>
+								<TablePane.Row>
+									<BoxPane>
+										<PushButton buttonData="%documentsTab_showAllDocs"
+																action="showAllTermDoc"/>
+										<BoxPane>
+											<PushButton action="deleteTermDoc">
+												<buttonData>
+													<content:ButtonData icon="/img/delete.gif" />
+												</buttonData>
+											</PushButton>
+											<Label text="%documentsTab_deleteAllDocs" styles="{padding:1}"/>
+										</BoxPane>
+									</BoxPane>
+								</TablePane.Row>
 
-					<BoxPane>
-						<Label text="%documentsTab_document" />
-						<Label bxml:id="tdNum" text="?" />
-						<Label text=" of " />
-						<Label bxml:id="tdMax" text="?" />
-						<PushButton buttonData="%documentsTab_firstDoc" action="showFirstTermDoc" />
-						<PushButton action="showNextTermDoc">
-							<buttonData>
-								<content:ButtonData icon="/img/next.png" />
-							</buttonData>
-						</PushButton>
-					</BoxPane>
+							</rows>
+						</TablePane>
+						</content>
+						</Border>
+					</right>
+				</SplitPane>
+			</right>
+		</SplitPane>
+	</top>
 
-				</BoxPane>
-				<BoxPane orientation="vertical">
-					<PushButton buttonData="%documentsTab_showAllDocs"
-						action="showAllTermDoc" />
-					<PushButton buttonData="%documentsTab_deleteAllDocs"
-						action="deleteTermDoc">
-						<buttonData>
-							<content:ButtonData icon="/img/delete.gif" />
-						</buttonData>
-					</PushButton>
-				</BoxPane>
-				<Label text=" " />
-				<Label text="%documentsTab_termFreqInDoc" />
-
-				<Label bxml:id="tFreq" text="?" />
-				<PushButton bxml:id="bPos" buttonData="%documentsTab_showPositions"
-					action="showPositions" />
-			</FlowPane>
-		</TablePane.Row>
-		<TablePane.Row>
-			<TablePane styles="{verticalSpacing:1, horizontalSpacing:1}">
-				<columns>
-					<TablePane.Column width="1*" />
-					<TablePane.Column />
-				</columns>
-				<rows>
-					<TablePane.Row>
-						<FlowPane>
-							<Label text="Doc #:" />
-							<Label bxml:id="docNum2" text="?" />
-							<Label text=" " />
-						</FlowPane>
-						<FlowPane>
-							<TablePane styles="{verticalSpacing:1, horizontalSpacing:1}">
-								<columns>
-									<TablePane.Column />
-									<TablePane.Column />
-									<TablePane.Column />
-									<TablePane.Column />
-									<TablePane.Column />
-									<TablePane.Column />
-								</columns>
-								<rows>
-									<TablePane.Row>
-										<Label text="Flags: " />
-										<Label text=" I - Indexed " />
-										<Label text="  T - Tokenized " />
-										<Label text="  S - Stored " />
-										<Label text="  V - Term Vector " />
-										<Label text=" (o - offsets; p - positions) " />
-									</TablePane.Row>
-									<TablePane.Row>
-										<TablePane.Filler />
-
-										<Label text=" O - Omit Norms " />
-										<Label text="  f - Omit TF " />
-										<Label text="  L - Lazy " />
-										<Label text="  B - Binary " />
-									</TablePane.Row>
-								</rows>
-							</TablePane>
-						</FlowPane>
-					</TablePane.Row>
-				</rows>
-			</TablePane>
-		</TablePane.Row>
-		<TablePane.Row height="1*">
-			<ScrollPane horizontalScrollBarPolicy="fill_to_capacity" styles="{backgroundColor:11}">
-				<view>
-					<TableView bxml:id="docTable">
+	<bottom>
+		<TablePane styles="{verticalSpacing:5,horizontalSpacing:1,padding:5,backgroundColor:11}">
+			<columns>
+				<TablePane.Column width="1*" />
+			</columns>
+			<rows>
+				<TablePane.Row>
+					<TablePane>
 						<columns>
-							<TableView.Column name="field"
-								headerData="%documentsTab_docTable_col1" />
-							<TableView.Column name="itsvopfolb"
-								headerData="%documentsTab_docTable_col2" />
-							<TableView.Column name="norm"
-								headerData="%documentsTab_docTable_col3" />
-							<TableView.Column name="value"
-								headerData="%documentsTab_docTable_col4" width="1*" />
+							<TablePane.Column width="1*" />
+							<TablePane.Column />
 						</columns>
+						<rows>
+							<TablePane.Row>
+								<FlowPane>
+									<Label text="Doc #:" />
+									<Label bxml:id="docNum2" text="?" />
+									<Label text=" " />
+								</FlowPane>
+								<FlowPane>
+									<TablePane styles="{verticalSpacing:1, horizontalSpacing:1}">
+										<columns>
+											<TablePane.Column />
+											<TablePane.Column />
+											<TablePane.Column />
+											<TablePane.Column />
+											<TablePane.Column />
+											<TablePane.Column />
+										</columns>
+										<rows>
+											<TablePane.Row>
+												<Label text="Flags: " />
+												<Label text=" I - Indexed " />
+												<Label text=" T - Tokenized " />
+												<Label text=" S - Stored " />
+												<Label text=" V - Term Vector " />
+												<Label text=" (o - offsets; p - positions; a - payloads) " />
+											</TablePane.Row>
+											<TablePane.Row>
+												<TablePane.Filler />
+												<Label text=" P - Payloads" />
+												<Label text=" t - Index options" />
+												<Label text=" O - Omit Norms " />
+												<!--Label text="  f - Omit TF " /-->
+												<Label text=" L - Lazy " />
+												<Label text=" B - Binary " />
+											</TablePane.Row>
+										</rows>
+									</TablePane>
+								</FlowPane>
+							</TablePane.Row>
+						</rows>
+					</TablePane>
+				</TablePane.Row>
+				<TablePane.Row height="1*">
+					<Border styles="{padding:1}">
+						<content>
+							<ScrollPane horizontalScrollBarPolicy="fill_to_capacity" styles="{backgroundColor:11}">
+								<view>
+									<TableView bxml:id="docTable">
+										<columns>
+											<TableView.Column name="name"
+																				headerData="%documentsTab_docTable_col1" />
+											<TableView.Column name="itsvopatolb"
+																				headerData="%documentsTab_docTable_col2" />
+											<TableView.Column name="docvaluestype"
+																				headerData="%documentsTab_docTable_col3" />
+											<TableView.Column name="norm"
+																				headerData="%documentsTab_docTable_col4" />
+											<TableView.Column name="value"
+																				headerData="%documentsTab_docTable_col5" width="1*" />
+										</columns>
 
-					</TableView>
-				</view>
-				<columnHeader>
-					<TableViewHeader tableView="$docTable" />
-				</columnHeader>
-			</ScrollPane>
-		</TablePane.Row>
-	</rows>
+									</TableView>
+								</view>
+								<columnHeader>
+									<TableViewHeader tableView="$docTable" />
+								</columnHeader>
+							</ScrollPane>
+						</content>
+					</Border>
+				</TablePane.Row>
+				<TablePane.Row>
+					<BoxPane orientation="vertical">
+						<Label text="%documentsTab_indexOptionsNote1" styles="{wrapText:true}"/>
+						<Label text="%documentsTab_indexOptionsNote2" styles="{wrapText:true}"/>
+					</BoxPane>
+				</TablePane.Row>
+			</rows>
+		</TablePane>
+	</bottom>
 </luke:DocumentsTab>
Index: src/org/apache/lucene/luke/ui/DocumentsTab.java
===================================================================
--- src/org/apache/lucene/luke/ui/DocumentsTab.java	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/DocumentsTab.java	(working copy)
@@ -17,8 +17,9 @@
  * limitations under the License.
  */
 
-import java.io.IOException;
+import java.io.*;
 import java.net.URL;
+import java.util.Arrays;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.Field;
@@ -41,31 +42,25 @@
 import org.apache.lucene.luke.core.Util;
 import org.apache.lucene.luke.core.decoders.Decoder;
 import org.apache.lucene.luke.ui.LukeWindow.LukeMediator;
+import org.apache.lucene.search.DocIdSetIterator;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.similarities.DefaultSimilarity;
+import org.apache.lucene.search.similarities.Similarity;
+import org.apache.lucene.search.similarities.TFIDFSimilarity;
+import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.pivot.beans.BXML;
 import org.apache.pivot.beans.Bindable;
-import org.apache.pivot.collections.ArrayList;
-import org.apache.pivot.collections.HashMap;
-import org.apache.pivot.collections.List;
-import org.apache.pivot.collections.Map;
+import org.apache.pivot.collections.*;
 import org.apache.pivot.util.Resources;
 import org.apache.pivot.util.concurrent.Task;
 import org.apache.pivot.util.concurrent.TaskExecutionException;
 import org.apache.pivot.util.concurrent.TaskListener;
-import org.apache.pivot.wtk.Action;
-import org.apache.pivot.wtk.Component;
-import org.apache.pivot.wtk.Label;
-import org.apache.pivot.wtk.ListButton;
-import org.apache.pivot.wtk.TablePane;
-import org.apache.pivot.wtk.TableView;
-import org.apache.pivot.wtk.TaskAdapter;
-import org.apache.pivot.wtk.TextArea;
-import org.apache.pivot.wtk.TextInput;
+import org.apache.pivot.wtk.*;
 
-public class DocumentsTab extends TablePane implements Bindable {
+public class DocumentsTab extends SplitPane implements Bindable {
 
   private int iNum;
   @BXML
@@ -91,6 +86,20 @@
   @BXML
   private TextArea decText;
 
+  @BXML
+  private PushButton bPos;
+  @BXML
+  private PosAndOffsetsWindow posAndOffsetsWindow;
+
+  @BXML
+  private TermVectorWindow tvWindow;
+
+  @BXML
+  private FieldDataWindow fieldDataWindow;
+
+  @BXML
+  private FieldNormWindow fieldNormWindow;
+
   private java.util.List<String> fieldNames = null;
 
   // this gets injected by LukeWindow at init
@@ -99,7 +108,8 @@
   private Resources resources;
 
   private TermsEnum te;
-  private DocsAndPositionsEnum td;
+  //private DocsAndPositionsEnum td;
+  private DocsEnum td;
 
   private String fld;
   private Term lastTerm;
@@ -218,6 +228,15 @@
       fieldsList.setSelectedIndex(0);
     }
     maxDocs.setText(String.valueOf(ir.maxDoc() - 1));
+
+    bPos.setAction(new Action() {
+      @Override
+      public void perform(Component component) {
+        showPositionsWindow();
+      }
+    });
+
+    addlListenerToDocTable();
   }
 
   private void showDoc(int incr) {
@@ -242,6 +261,11 @@
       }
       docNum.setText(String.valueOf(iNum));
 
+      td = null;
+      tdNum.setText("?");
+      tFreq.setText("?");
+      tdMax.setText("?");
+
       org.apache.lucene.util.Bits live = ar.getLiveDocs();
       if (live == null || live.get(iNum)) {
         Task<Object> populateTableTask = new Task<Object>() {
@@ -314,7 +338,7 @@
 
   public void popTableWithDoc(int docid, Document doc) {
     docNum.setText(String.valueOf(docid));
-    List<Map<String,String>> tableData = new ArrayList<Map<String,String>>();
+    List<Map<String,Object>> tableData = new ArrayList<Map<String,Object>>();
     docTable.setTableData(tableData);
 
     // putProperty(table, "doc", doc);
@@ -326,10 +350,9 @@
 
     docNum2.setText(String.valueOf(docid));
     for (int i = 0; i < indexFields.size(); i++) {
-      Map<String,String> row = new HashMap<String,String>();
-
       IndexableField[] fields = doc.getFields(indexFields.get(i));
-      if (fields == null) {
+      if (fields == null || fields.length == 0) {
+        Map<String,Object> row = new HashMap<String,Object>();
         tableData.add(row);
         addFieldRow(row, indexFields.get(i), null, docid);
         continue;
@@ -339,6 +362,7 @@
         // System.out.println("f.len=" + fields[j].getBinaryLength() +
         // ", doc.len=" + doc.getBinaryValue(indexFields[i]).length);
         // }
+        Map<String,Object> row = new HashMap<String,Object>();
         tableData.add(row);
         addFieldRow(row, indexFields.get(i), fields[j], docid);
       }
@@ -345,7 +369,14 @@
     }
   }
 
-  private void addFieldRow(Map<String,String> row, String fName, IndexableField field, int docid) {
+  private static final String FIELDROW_KEY_NAME = "name";
+  private static final String FIELDROW_KEY_FLAGS = "itsvopatolb";
+  private static final String FIELDROW_KEY_DVTYPE = "docvaluestype";
+  private static final String FIELDROW_KEY_NORM = "norm";
+  private static final String FIELDROW_KEY_VALUE = "value";
+  private static final String FIELDROW_KEY_FIELD = "field";
+
+  private void addFieldRow(Map<String,Object> row, String fName, IndexableField field, int docid) {
     java.util.Map<String,Decoder> decoders = lukeMediator.getDecoders();
     Decoder defDecoder = lukeMediator.getDefDecoder();
 
@@ -353,29 +384,32 @@
     // putProperty(row, "field", f);
     // putProperty(row, "fName", fName);
 
-    row.put("field", fName);
-    row.put("itsvopfolb", Util.fieldFlags(f));
+    row.put(FIELDROW_KEY_FIELD, field);
 
+    row.put(FIELDROW_KEY_NAME, fName);
+    row.put(FIELDROW_KEY_FLAGS, Util.fieldFlags(f, infos.fieldInfo(fName)));
+    row.put(FIELDROW_KEY_DVTYPE, Util.docValuesType(infos.fieldInfo(fName)));
+
     // if (f == null) {
     // setBoolean(cell, "enabled", false);
     // }
 
-    if (f != null) {
+    if (fName != null) {
       try {
         FieldInfo info = infos.fieldInfo(fName);
         if (info.hasNorms()) {
           NumericDocValues norms = ar.getNormValues(fName);
-          String val = Long.toString(norms.get(docid));
-          row.put("norm", String.valueOf(norms.get(docid)));
+          String norm = String.valueOf(norms.get(docid)) + " (" + Util.normType(info) + ")";
+          row.put(FIELDROW_KEY_NORM, norm);
         } else {
-          row.put("norm", "---");
+          row.put(FIELDROW_KEY_NORM, "---");
         }
       } catch (IOException ioe) {
         ioe.printStackTrace();
-        row.put("norm", "!?!");
+        row.put(FIELDROW_KEY_NORM, "!?!");
       }
     } else {
-      row.put("norm", "---");
+      row.put(FIELDROW_KEY_NORM, "---");
       // setBoolean(cell, "enabled", false);
     }
 
@@ -395,15 +429,16 @@
         if (f.fieldType().stored()) {
           text = dec.decodeStored(f.name(), f);
         } else {
-          text = dec.decodeTerm(f.name(), text);
+          //text = dec.decodeTerm(f.name(), text);
+          text = dec.decodeTerm(f.name(), f.binaryValue());
         }
       } catch (Throwable e) {
         // TODO:
         // setColor(cell, "foreground", Color.RED);
       }
-      row.put("value", Util.escape(text));
+      row.put(FIELDROW_KEY_VALUE, Util.escape(text));
     } else {
-      row.put("value", "<not present or not stored>");
+      row.put(FIELDROW_KEY_VALUE, "<not present or not stored>");
       // setBoolean(cell, "enabled", false);
     }
   }
@@ -428,7 +463,7 @@
         try {
 
           fld = (String) fieldsList.getSelectedItem();
-          System.out.println("fld:" + fld);
+          //System.out.println("fld:" + fld);
           Terms terms = MultiFields.getTerms(ir, fld);
           te = terms.iterator(null);
           BytesRef term = te.next();
@@ -472,7 +507,7 @@
       @Override
       public void taskExecuted(Task<Object> task) {
         try {
-          DocsAndPositionsEnum td = MultiFields.getTermPositionsEnum(ir, null, lastTerm.field(), lastTerm.bytes());
+          DocsEnum td = MultiFields.getTermDocsEnum(ir, null, lastTerm.field(), lastTerm.bytes());
           td.nextDoc();
           tdNum.setText("1");
           DocumentsTab.this.td = td;
@@ -549,7 +584,7 @@
 
   }
 
-  private void showTerm(final Term t) {
+  protected void showTerm(final Term t) {
     if (t == null) {
       // TODO:
       // showStatus("No terms?!");
@@ -571,7 +606,8 @@
     String s = null;
     boolean decodeErr = false;
     try {
-      s = dec.decodeTerm(t.field(), t.text());
+      //s = dec.decodeTerm(t.field(), t.text());
+      s = dec.decodeTerm(t.field(), t.bytes());
     } catch (Throwable e) {
       s = e.getMessage();
       decodeErr = true;
@@ -580,7 +616,8 @@
     termText.setText(t.text());
 
     if (!s.equals(t.text())) {
-      decText.setText(s);
+      String decoded = s + " (by " + dec.toString() + ")";
+      decText.setText(decoded);
 
       if (decodeErr) {
         // setColor(rawText, "foreground", Color.RED);
@@ -613,14 +650,11 @@
 
         try {
           int freq = ir.docFreq(t);
-          dFreq.setText(String.valueOf(freq));
-
           tdMax.setText(String.valueOf(freq));
         } catch (Exception e) {
           e.printStackTrace();
           // TODO:
           // showStatus(e.getMessage());
-          dFreq.setText("?");
         }
         // ai.setActive(false);
       }
@@ -670,17 +704,20 @@
           String rawString = rawTerm != null ? rawTerm.utf8ToString() : null;
 
           if (te == null || !DocumentsTab.this.fld.equals(fld) || !text.equals(rawString)) {
+            // seek for requested term
             Terms terms = MultiFields.getTerms(ir, fld);
             te = terms.iterator(null);
 
             DocumentsTab.this.fld = fld;
             status = te.seekCeil(new BytesRef(text));
-            if (status.equals(SeekStatus.FOUND)) {
+            if (status.equals(SeekStatus.FOUND) || status.equals(SeekStatus.NOT_FOUND)) {
+              // precise term or different term after the requested term was found.
               rawTerm = te.term();
             } else {
               rawTerm = null;
             }
           } else {
+            // move to next term
             rawTerm = te.next();
           }
           if (rawTerm == null) { // proceed to next field
@@ -696,7 +733,7 @@
               te = terms.iterator(null);
               rawTerm = te.next();
               DocumentsTab.this.fld = fld;
-              break;
+              //break;
             }
           }
           if (rawTerm == null) {
@@ -744,6 +781,7 @@
         try {
           Document doc = ir.document(td.docID());
           docNum.setText(String.valueOf(td.docID()));
+          iNum = td.docID();
 
           tFreq.setText(String.valueOf(td.freq()));
 
@@ -767,6 +805,38 @@
 
   }
 
+  private void showPositionsWindow() {
+    try {
+      if (td == null) {
+        Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_docNotSelected"), getWindow());
+      } else {
+        // create new Enum to show positions info
+        DocsAndPositionsEnum pe = MultiFields.getTermPositionsEnum(ir, null, lastTerm.field(), lastTerm.bytes());
+        if (pe == null) {
+          Alert.alert(MessageType.INFO, (String)resources.get("documentsTab_msg_positionNotIndexed"), getWindow());
+        } else {
+          // enumerate docId to the current doc
+          while(pe.docID() != td.docID()) {
+            if (pe.nextDoc() == DocIdSetIterator.NO_MORE_DOCS) {
+              // this must not happen!
+              Alert.alert(MessageType.ERROR, (String)resources.get("documentsTab_msg_noPositionInfo"), getWindow());
+            }
+          }
+          try {
+            posAndOffsetsWindow.initPositionInfo(pe, lastTerm);
+            posAndOffsetsWindow.open(getDisplay(), getWindow());
+          } catch (Exception e) {
+            // TODO:
+            e.printStackTrace();
+          }
+        }
+      }
+    } catch (Exception e) {
+      // TODO
+      e.printStackTrace();
+    }
+  }
+
   public void showAllTermDoc() {
     final IndexReader ir = lukeMediator.getIndexInfo().getReader();
     if (ir == null) {
@@ -825,4 +895,178 @@
 
   }
 
+  private void addlListenerToDocTable() {
+    docTable.getComponentMouseButtonListeners().add(new ComponentMouseButtonListener.Adapter() {
+      @Override
+      public boolean mouseClick(Component component, Mouse.Button button, int i, int i1, int i2) {
+        final Map<String, Object> row = (Map<String, Object>) docTable.getSelectedRow();
+        if (row == null) {
+          System.out.println("No field selected.");
+          return false;
+        }
+        if (button.name().equals(Mouse.Button.RIGHT.name())) {
+          MenuPopup popup = new MenuPopup();
+          Menu menu = new Menu();
+          Menu.Section section = new Menu.Section();
+          Menu.Item item1 = new Menu.Item(resources.get("documentsTab_docTable_popup_menu1"));
+          item1.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              String name = (String)row.get(FIELDROW_KEY_NAME);
+              try {
+                Terms terms = ir.getTermVector(iNum, name);
+                if (terms == null) {
+                  String msg = "DocId: " + iNum + ", field: " + name;
+                  Alert.alert(MessageType.WARNING, "Term vector not avalable for " + msg, getWindow());
+                } else {
+                  showTermVectorWindow(name, terms);
+                }
+              } catch (IOException e) {
+                // TODO:
+                e.printStackTrace();
+              }
+
+            }
+          });
+          Menu.Item item2 = new Menu.Item(resources.get("documentsTab_docTable_popup_menu2"));
+          item2.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              String name = (String)row.get(FIELDROW_KEY_NAME);
+              IndexableField field = (IndexableField)row.get(FIELDROW_KEY_FIELD);
+              if (field == null) {
+                Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_noDataAvailable"), getWindow());
+              } else {
+                showFieldDataWindow(name, field);
+              }
+            }
+          });
+          Menu.Item item3 = new Menu.Item(resources.get("documentsTab_docTable_popup_menu3"));
+          item3.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              String name = (String)row.get(FIELDROW_KEY_NAME);
+              IndexableField field = (IndexableField)row.get(FIELDROW_KEY_FIELD);
+              FieldInfo info = infos.fieldInfo(name);
+              if (field == null) {
+                Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_noDataAvailable"), getWindow());
+              } else if (!info.isIndexed() || !info.hasNorms()) {
+                Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_noNorm"), getWindow());
+              } else {
+                showFieldNormWindow(name);
+              }
+            }
+          });
+          Menu.Item item4 = new Menu.Item(resources.get("documentsTab_docTable_popup_menu4"));
+          item4.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              String name = (String)row.get(FIELDROW_KEY_NAME);
+              IndexableField field = (IndexableField)row.get(FIELDROW_KEY_FIELD);
+              if (ir == null) {
+                Alert.alert(MessageType.ERROR, (String)resources.get("documentsTab_noOrClosedIndex"), getWindow());
+              } else if (field == null) {
+                Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_noDataAvailable"), getWindow());
+              } else {
+                saveFieldData(field);
+              }
+            }
+          });
+          section.add(item1);
+          section.add(item2);
+          section.add(item3);
+          section.add(item4);
+          menu.getSections().add(section);
+          popup.setMenu(menu);
+          popup.open(getWindow(), getMouseLocation().x + 20, getMouseLocation().y + 50);
+          return true;
+        }
+        return false;
+      }
+    });
+
+  }
+
+  private void showTermVectorWindow(String fieldName, Terms tv) {
+    try {
+      tvWindow.initTermVector(fieldName, tv);
+    } catch (IOException e) {
+      // TODO
+      e.printStackTrace();
+    }
+    tvWindow.open(getDisplay(), getWindow());
+  }
+
+  private void showFieldDataWindow(String fieldName, IndexableField field) {
+    fieldDataWindow.initFieldData(fieldName, field);
+    fieldDataWindow.open(getDisplay(), getWindow());
+  }
+
+  private static TFIDFSimilarity defaultSimilarity = new DefaultSimilarity();
+  private void showFieldNormWindow(String fieldName) {
+    if (ar != null) {
+      try {
+        NumericDocValues norms = ar.getNormValues(fieldName);
+        fieldNormWindow.initFieldNorm(iNum, fieldName, norms);
+        fieldNormWindow.open(getDisplay(), getWindow());
+      } catch (Exception e) {
+        Alert.alert(MessageType.ERROR, (String)resources.get("documentsTab_msg_errorNorm"), getWindow());
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private void saveFieldData(IndexableField field) {
+    byte[] data = null;
+    if (field.binaryValue() != null) {
+      BytesRef bytes = field.binaryValue();
+      data = new byte[bytes.length];
+      System.arraycopy(bytes.bytes, bytes.offset, data, 0,
+        bytes.length);
+    }
+    else {
+      try {
+        data = field.stringValue().getBytes("UTF-8");
+      } catch (UnsupportedEncodingException uee) {
+        uee.printStackTrace();
+        data = field.stringValue().getBytes();
+      }
+    }
+    if (data == null || data.length == 0) {
+      Alert.alert(MessageType.WARNING, (String)resources.get("documentsTab_msg_noDataAvailable"), getWindow());
+    }
+
+    final byte[] fieldData = Arrays.copyOf(data, data.length);
+    final FileBrowserSheet fileBrowserSheet = new FileBrowserSheet(FileBrowserSheet.Mode.SAVE_AS);
+    fileBrowserSheet.open(getWindow(), new SheetCloseListener() {
+      @Override
+      public void sheetClosed(Sheet sheet) {
+        if (sheet.getResult()) {
+          Sequence<File> selectedFiles = fileBrowserSheet.getSelectedFiles();
+          File file = selectedFiles.get(0);
+          try {
+            OutputStream os = new FileOutputStream(file);
+            int delta = fieldData.length / 100;
+            if (delta == 0) delta = 1;
+            for (int i = 0; i < fieldData.length; i++) {
+              os.write(fieldData[i]);
+              // TODO: show progress
+              //if (i % delta == 0) {
+              // setInteger(bar, "value", i / delta);
+              //}
+            }
+            os.flush();
+            os.close();
+            Alert.alert(MessageType.INFO, "Saved to " + file.getAbsolutePath(), getWindow());
+          } catch (IOException e) {
+            e.printStackTrace();
+            Alert.alert(MessageType.ERROR, "Can't save to : " + file.getAbsoluteFile(), getWindow());
+          }
+        } else {
+          Alert.alert(MessageType.INFO, "You didn't select anything.", getWindow());
+        }
+
+      }
+    });
+  }
 }
Index: src/org/apache/lucene/luke/ui/FieldDataWindow.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/FieldDataWindow.bxml	(revision 0)
+++ src/org/apache/lucene/luke/ui/FieldDataWindow.bxml	(working copy)
@@ -0,0 +1,57 @@
+<luke:FieldDataWindow bxml:id="fieldData" icon="/img/luke.gif"
+													title="%fieldDataWindow_title" xmlns:bxml="http://pivot.apache.org/bxml"
+													xmlns:luke="org.apache.lucene.luke.ui" xmlns:content="org.apache.pivot.wtk.content"
+													xmlns="org.apache.pivot.wtk">
+	<content>
+		<TablePane styles="{verticalSpacing:10}">
+			<columns>
+				<TablePane.Column width="1*"/>
+			</columns>
+			<rows>
+				<TablePane.Row>
+					<TablePane styles="{verticalSpacing:1,horizontalSpacing:1}">
+						<columns>
+							<TablePane.Column />
+							<TablePane.Column width="1*"/>
+						</columns>
+						<rows>
+							<TablePane.Row>
+								<Label text="Field name:" styles="{font:{bold:true},backgroundColor:'#dce0e7',padding:2}"/>
+								<Label bxml:id="name" text="?" styles="{backgroundColor:'#fcfdfd',padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Field length: " styles="{font:{bold:true},backgroundColor:'#f1f1f1',padding:2}"/>
+								<Label bxml:id="length" text="?" styles="{backgroundColor:11,padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Show content as: " styles="{font:{bold:true},backgroundColor:'#dce0e7',padding:2}"/>
+								<Spinner bxml:id="cDecoder" />
+							</TablePane.Row>
+						</rows>
+					</TablePane>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<Label bxml:id="error" text="%fieldDataWindow_decodeError" visible="false"
+								 styles="{color:'red',padding:2,wrapText:true}" preferredWidth="500"/>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<Border styles="{padding:1}">
+						<ScrollPane>
+							<TextArea bxml:id="data" preferredWidth="500" preferredHeight="250" editable="false"/>
+						</ScrollPane>
+					</Border>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<BoxPane orientation="horizontal" styles="{horizontalAlignment:'right'}">
+						<PushButton buttonData="%label_ok"
+												ButtonPressListener.buttonPressed="fieldData.close()">
+						</PushButton>
+					</BoxPane>
+				</TablePane.Row>
+			</rows>
+		</TablePane>
+	</content>
+</luke:FieldDataWindow>
\ No newline at end of file

Property changes on: src/org/apache/lucene/luke/ui/FieldDataWindow.bxml
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/xml
\ No newline at end of property
Index: src/org/apache/lucene/luke/ui/FieldDataWindow.java
===================================================================
--- src/org/apache/lucene/luke/ui/FieldDataWindow.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/FieldDataWindow.java	(working copy)
@@ -0,0 +1,222 @@
+package org.apache.lucene.luke.ui;
+
+import org.apache.lucene.analysis.payloads.PayloadHelper;
+import org.apache.lucene.document.DateTools;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.luke.core.Util;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.NumericUtils;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.Bindable;
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.List;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.serialization.SerializationException;
+import org.apache.pivot.util.Resources;
+import org.apache.pivot.wtk.*;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.Date;
+
+public class FieldDataWindow extends Dialog implements Bindable {
+
+  @BXML
+  private Label name;
+  @BXML
+  private Label length;
+  @BXML
+  private Spinner cDecoder;
+  @BXML
+  private Label error;
+  @BXML
+  private TextArea data;
+
+  private Resources resources;
+
+  private IndexableField field;
+
+  @Override
+  public void initialize(Map<String, Object> map, URL url, Resources resources) {
+    this.resources = resources;
+  }
+
+  public void initFieldData(String fieldName, IndexableField field) {
+    this.field = field;
+
+    setContentDecoders();
+
+    name.setText(fieldName);
+    ContentDecoder dec = ContentDecoder.defDecoder();
+    dec.decode(field);
+    data.setText(String.valueOf(dec.value));
+    length.setText(Integer.toString(dec.len));
+  }
+
+  private void setContentDecoders() {
+    ArrayList<Object> decoders = new ArrayList<Object>();
+    ContentDecoder[] contentDecoders = ContentDecoder.values();
+    for (int i = contentDecoders.length - 1; i >= 0; i--) {
+      decoders.add(contentDecoders[i]);
+    }
+    cDecoder.setSpinnerData(decoders);
+    cDecoder.setSelectedItem(ContentDecoder.STRING_UTF8);
+
+    cDecoder.getSpinnerSelectionListeners().add(new SpinnerSelectionListener.Adapter() {
+      @Override
+      public void selectedItemChanged(Spinner spinner, Object o) {
+        ContentDecoder dec = (ContentDecoder) spinner.getSelectedItem();
+        if (dec == null) {
+          dec = ContentDecoder.defDecoder();
+        }
+        dec.decode(field);
+        data.setText(dec.value);
+        length.setText(Integer.toString(dec.len));
+        if (dec.warn) {
+          error.setVisible(true);
+          try {
+            data.setStyles("{color:'#bdbdbd'}");
+          } catch (SerializationException e) {
+            e.printStackTrace();
+          }
+          data.setEnabled(false);
+        } else {
+          error.setVisible(false);
+          try {
+            data.setStyles("{color:'#000000'}");
+          } catch (SerializationException e) {
+            e.printStackTrace();
+          }
+          data.setEnabled(true);
+        }
+      }
+    });
+  }
+
+
+  enum ContentDecoder {
+    STRING_UTF8("String UTF-8"),
+    STRING("String default enc."),
+    HEXDUMP("Hexdump"),
+    DATETIME("Date / Time"),
+    NUMERIC("Numeric"),
+    LONG("Long (prefix-coded)"),
+    ARRAY_OF_INT("Array of int"),
+    ARRAY_OF_FLOAT("Array of float");
+
+    private String strExpr;
+    ContentDecoder(String strExpr) {
+      this.strExpr = strExpr;
+    }
+
+    @Override
+    public String toString() {
+      return strExpr;
+    }
+
+    public static ContentDecoder defDecoder() {
+      return STRING_UTF8;
+    }
+
+    String value = "";  // decoded value
+    int len;       // length of decoded value
+    boolean warn;  // set to true if decode failed
+
+    public void decode(IndexableField field) {
+      if (field == null) {
+        return ;
+      }
+      warn = false;
+      byte[] data = null;
+      if (field.binaryValue() != null) {
+        BytesRef bytes = field.binaryValue();
+        data = new byte[bytes.length];
+        System.arraycopy(bytes.bytes, bytes.offset, data, 0,
+          bytes.length);
+      }
+      else if (field.stringValue() != null) {
+        try {
+          data = field.stringValue().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException uee) {
+          warn = true;
+          uee.printStackTrace();
+          data = field.stringValue().getBytes();
+        }
+      }
+      if (data == null) data = new byte[0];
+
+      switch(this) {
+        case STRING_UTF8:
+          value = field.stringValue();
+          if (value != null) len = value.length();
+          break;
+        case STRING:
+          value = new String(data);
+          len = value.length();
+          break;
+        case HEXDUMP:
+          value = Util.bytesToHex(data, 0, data.length, true);
+          len = data.length;
+          break;
+        case DATETIME:
+          try {
+            Date d = DateTools.stringToDate(field.stringValue());
+            value = d.toString();
+            len = 1;
+          } catch (Exception e) {
+            warn = true;
+            value = Util.bytesToHex(data, 0, data.length, true);
+          }
+          break;
+        case NUMERIC:
+          if (field.numericValue() != null) {
+            value = field.numericValue().toString() + " (" + field.numericValue().getClass().getSimpleName() + ")";
+          } else {
+            warn = true;
+            value = Util.bytesToHex(data, 0, data.length, true);
+          }
+          break;
+        case LONG:
+          try {
+            long num = NumericUtils.prefixCodedToLong(new BytesRef(field.stringValue()));
+            value = String.valueOf(num);
+            len = 1;
+          } catch (Exception e) {
+            warn = true;
+            value = Util.bytesToHex(data, 0, data.length, true);
+          }
+          break;
+        case ARRAY_OF_INT:
+          if (data.length % 4 == 0) {
+            len = data.length / 4;
+            StringBuilder sb = new StringBuilder();
+            for (int k = 0; k < data.length; k += 4) {
+              if (k > 0) sb.append(',');
+              sb.append(String.valueOf(PayloadHelper.decodeInt(data, k)));
+            }
+            value = sb.toString();
+          } else {
+            warn = true;
+            value = Util.bytesToHex(data, 0, data.length, true);
+          }
+          break;
+        case ARRAY_OF_FLOAT:
+          if (data.length % 4 == 0) {
+            len = data.length / 4;
+            StringBuilder sb = new StringBuilder();
+            for (int k = 0; k < data.length; k += 4) {
+              if (k > 0) sb.append(',');
+              sb.append(String.valueOf(PayloadHelper.decodeFloat(data, k)));
+            }
+            value = sb.toString();
+          } else {
+            warn = true;
+            value = Util.bytesToHex(data, 0, data.length, true);
+          }
+          break;
+      }
+    }
+
+  }
+}
Index: src/org/apache/lucene/luke/ui/FieldNormWindow.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/FieldNormWindow.bxml	(revision 0)
+++ src/org/apache/lucene/luke/ui/FieldNormWindow.bxml	(working copy)
@@ -0,0 +1,75 @@
+<luke:FieldNormWindow bxml:id="fieldNorm" icon="/img/luke.gif"
+											 title="%fieldNormWindow_title" xmlns:bxml="http://pivot.apache.org/bxml"
+											 xmlns:luke="org.apache.lucene.luke.ui" xmlns:content="org.apache.pivot.wtk.content"
+											 xmlns="org.apache.pivot.wtk">
+	<content>
+		<TablePane styles="{verticalSpacing:10}">
+			<columns>
+				<TablePane.Column width="1*"/>
+			</columns>
+			<rows>
+				<TablePane.Row>
+					<TablePane styles="{verticalSpacing:5,horizontalSpacing:5}">
+						<columns>
+							<TablePane.Column />
+							<TablePane.Column width="1*"/>
+						</columns>
+						<rows>
+							<TablePane.Row>
+								<Label text="Field name: " />
+								<Label bxml:id="field" text="?" styles="{font:{bold:true}}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Field norm: " />
+								<Label bxml:id="normVal" text="?" styles="{font:{bold:true}}"/>
+							</TablePane.Row>
+						</rows>
+					</TablePane>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<Separator/>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<BoxPane orientation="vertical" styles="{fill:true}">
+						<Label text="%fieldNormWindow_simClass"/>
+						<BoxPane styles="{fill:true}">
+							<TextInput bxml:id="simclass" preferredWidth="400"/>
+							<PushButton bxml:id="refreshButton">
+								<buttonData>
+									<content:ButtonData icon="/img/refresh.png" />
+								</buttonData>
+							</PushButton>
+						</BoxPane>
+						<Label bxml:id="simErr" text="" styles="{color:'red'}" visible="false"/>
+					  <TablePane styles="{verticalSpacing:5,horizontalSpacing:5}">
+							<columns>
+								<TablePane.Column />
+								<TablePane.Column width="1*"/>
+							</columns>
+							<rows>
+								<TablePane.Row>
+									<Label text="%fieldNormWindow_otherNorm"/>
+									<TextInput bxml:id="otherNorm" />
+								</TablePane.Row>
+								<TablePane.Row>
+									<Label text="%fieldNormWindow_encNorm"/>
+									<Label bxml:id="encNorm" text="?"/>
+								</TablePane.Row>
+							</rows>
+						</TablePane>
+					</BoxPane>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<BoxPane orientation="horizontal" styles="{horizontalAlignment:'right'}">
+						<PushButton buttonData="%label_ok"
+												ButtonPressListener.buttonPressed="fieldNorm.close()">
+						</PushButton>
+					</BoxPane>
+				</TablePane.Row>
+			</rows>
+		</TablePane>
+	</content>
+</luke:FieldNormWindow>
\ No newline at end of file

Property changes on: src/org/apache/lucene/luke/ui/FieldNormWindow.bxml
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/xml
\ No newline at end of property
Index: src/org/apache/lucene/luke/ui/FieldNormWindow.java
===================================================================
--- src/org/apache/lucene/luke/ui/FieldNormWindow.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/FieldNormWindow.java	(working copy)
@@ -0,0 +1,122 @@
+package org.apache.lucene.luke.ui;
+
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.luke.core.Util;
+import org.apache.lucene.search.similarities.DefaultSimilarity;
+import org.apache.lucene.search.similarities.Similarity;
+import org.apache.lucene.search.similarities.TFIDFSimilarity;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.Bindable;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.util.Resources;
+import org.apache.pivot.wtk.*;
+
+import java.net.URL;
+
+public class FieldNormWindow extends Dialog implements Bindable {
+
+  @BXML
+  private Label field;
+  @BXML
+  private Label normVal;
+  @BXML
+  private TextInput simclass;
+  @BXML
+  private Label simErr;
+  @BXML
+  private PushButton refreshButton;
+  @BXML
+  private TextInput otherNorm;
+  @BXML
+  private Label encNorm;
+
+  private Resources resources;
+
+  private String fieldName;
+
+  private static TFIDFSimilarity defaultSimilarity = new DefaultSimilarity();
+
+  @Override
+  public void initialize(Map<String, Object> map, URL url, Resources resources) {
+    this.resources = resources;
+  }
+
+  public void initFieldNorm(int docId, String fieldName, NumericDocValues norms) throws Exception {
+    this.fieldName = fieldName;
+    TFIDFSimilarity sim = defaultSimilarity;
+    byte curBVal = (byte) norms.get(docId);
+    float curFVal = Util.decodeNormValue(curBVal, fieldName, sim);
+    field.setText(fieldName);
+    normVal.setText(Float.toString(curFVal));
+    simclass.setText(sim.getClass().getName());
+    otherNorm.setText(Float.toString(curFVal));
+    encNorm.setText(Float.toString(curFVal) + " (0x" + Util.byteToHex(curBVal) + ")");
+
+    refreshButton.setAction(new Action() {
+      @Override
+      public void perform(Component component) {
+        changeNorms();
+      }
+    });
+    otherNorm.getTextInputContentListeners().add(new TextInputContentListener.Adapter(){
+      @Override
+      public void textChanged(TextInput textInput) {
+        changeNorms();
+      }
+    });
+  }
+
+  private void changeNorms() {
+    String simClassString = simclass.getText();
+
+    Similarity sim = createSimilarity(simClassString);
+    TFIDFSimilarity s = null;
+    if (sim != null && (sim instanceof TFIDFSimilarity)) {
+      s = (TFIDFSimilarity)sim;
+    } else {
+      s = defaultSimilarity;
+    }
+    if (s == null) {
+      s = defaultSimilarity;
+    }
+    //setString(sim, "text", s.getClass().getName());
+    simclass.setText(s.getClass().getName());
+    try {
+      float newFVal = Float.parseFloat(otherNorm.getText());
+      long newBVal = Util.encodeNormValue(newFVal, fieldName, s);
+      float encFVal = Util.decodeNormValue(newBVal, fieldName, s);
+      encNorm.setText(String.valueOf(encFVal) + " (0x" + Util.byteToHex((byte) (newBVal & 0xFF)) + ")");
+    } catch (Exception e) {
+      // TODO:
+      e.printStackTrace();
+    }
+  }
+
+  public Similarity createSimilarity(String simClass) {
+    //Object ckSimDef = find(srchOpts, "ckSimDef");
+    //Object ckSimSweet = find(srchOpts, "ckSimSweet");
+    //Object ckSimOther = find(srchOpts, "ckSimOther");
+    //Object simClass = find(srchOpts, "simClass");
+    //Object ckSimCust = find(srchOpts, "ckSimCust");
+    //if (getBoolean(ckSimDef, "selected")) {
+    //      return new DefaultSimilarity();
+    //} else if (getBoolean(ckSimSweet, "selected")) {
+    //  return new SweetSpotSimilarity();
+    //} else if (getBoolean(ckSimOther, "selected")) {
+    try {
+      Class clazz = Class.forName(simClass);
+      if (Similarity.class.isAssignableFrom(clazz)) {
+        Similarity sim = (Similarity) clazz.newInstance();
+        simErr.setVisible(false);
+        return sim;
+      } else {
+        simErr.setText("Not a subclass of Similarity: " + clazz.getName());
+        simErr.setVisible(true);
+      }
+    } catch (Exception e) {
+      simErr.setText("Invalid similarity class " + simClass + ", using DefaultSimilarity.");
+      simErr.setVisible(true);
+    }
+    return new DefaultSimilarity();
+  }
+}
Index: src/org/apache/lucene/luke/ui/LukeApplication_en.json
===================================================================
--- src/org/apache/lucene/luke/ui/LukeApplication_en.json	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/LukeApplication_en.json	(working copy)
@@ -26,6 +26,9 @@
  sandstoneTheme: "Sandstone Theme",
  skyTheme: "Sky Theme",
  navyTheme: "Navy Theme",
+
+ label_ok: "OK",
+ label_clipboard: "Copy to Clipboard",
  
  lukeInitWindow_title: "Path to index directory:",
  lukeInitWindow_path: "Path:",
@@ -58,9 +61,10 @@
  overviewTab_userData: "Current commit user data:",
  
  overviewTab_fieldsAndTermCounts: "Available fields and term counts per field:",
- overviewTab_topRankingTerms: "Top Ranking Terms (Right click for more options)",
+ overviewTab_topRankingTerms: "Top Ranking Terms (Select a row and right click for more options)",
  overviewTab_decoderWarn: "Tokens marked in red indicate decoding errors, likely due to a mismatched decoder.",
  overviewTab_fieldSelect: "Select fields from the list below, and press button to view top terms in these fields. No selection means all fields.",
+ overviewTab_fieldsHintDecoder: "Hint: Double click 'Decoder' column, select decoder class, and press Enter to set the suitable decoder.",
  overviewTab_topTermsHint: "Hint: use Shift-Click to select ranges, or Ctrl-Click to select multiple fields (or unselect all).",
  overviewTab_showTopTerms: "Show top terms >>",
  
@@ -68,28 +72,63 @@
  overviewTab_topTermsTable_col2: "DF",
  overviewTab_topTermsTable_col3: "Field",
  overviewTab_topTermsTable_col4: "Text",
+
+ overviewTab_topTermTable_popup_menu1: "Browse term docs",
+ overviewTab_topTermTable_popup_menu2: "Show all term docs",
+ overviewTab_topTermTable_popup_menu3: "Copy to clipboard",
  
  documentsTab_noOrClosedIndex: "FAILED: No index, or index is closed. Reopen it.",
  documentsTab_docNumOutsideRange: "Document number outside valid range.",
  documentsTab_browseByDocNum: "Browse by document number:",
  documentsTab_browseByTerm: "Browse by term:",
+ documentsTab_selectField: "Select a field from the spinner below, press Next to browse terms.",
  documentsTab_enterTermHint: "(Hint: enter a substring and press Next to start at the nearest term).",
  documentsTab_firstTerm: "First Term",
  documentsTab_term: "Term:",
  documentsTab_decodedValue: "Decoded value:",
- documentsTab_browseDocsWithTerm: "Browse documents with this term",
+ documentsTab_browseDocsWithTerm: "Browse documents with this term:",
+ documentsTab_selectTerm: "After select term, press Next to browse docs with the term.",
  documentsTab_showAllDocs: "Show All Docs",
  documentsTab_deleteAllDocs: "Delete All Docs",
  documentsTab_document: "Document:",
  documentsTab_firstDoc: "First Doc",
  documentsTab_termFreqInDoc: "Term freq in this doc:",
- documentsTab_showPositions: "Show Positions",
- 
+ documentsTab_showPositions: "Show Positions and Offsets",
+ documentsTab_indexOptionsNote1: "Note: flag 't - Index options' means, 1: DOCS_ONLY; 2:DOCS_AND_FREQS; 3: DOCS_AND_FREQS_AND_POSITIONS; 4: DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS.",
+ documentsTab_indexOptionsNote2: "(See Javadocs about FieldInfo.IndexOptions for more info.)",
+
  documentsTab_docTable_col1: "Field",
- documentsTab_docTable_col2: "ITSVopfOLB",
- documentsTab_docTable_col3: "Norm",
- documentsTab_docTable_col4: "Value",
- 
+ documentsTab_docTable_col2: "ITSVopaPtOLB",
+ documentsTab_docTable_col3: "DocValues Type",
+ documentsTab_docTable_col4: "Norm (Norm Type)",
+ documentsTab_docTable_col5: "Value",
+
+ documentsTab_docTable_popup_menu1: "Field's Term Vector",
+ documentsTab_docTable_popup_menu2: "Show Full Text",
+ documentsTab_docTable_popup_menu3: "Set Norm",
+ documentsTab_docTable_popup_menu4: "Save Field",
+
+ documentsTab_msg_docNotSelected: "Please select a term and a document for showing term positions.",
+ documentsTab_msg_positionNotIndexed: "Positions are not indexed for this term.",
+ documentsTab_msg_noPositionInfo: "No positions info ???",
+ documentsTab_msg_noDataAvailable: "No data available for this field.",
+ documentsTab_msg_noNorm: "Cannot examine norm value - this field is not indexed.",
+ documentsTab_msg_errorNorm: "Error reading norm: ",
+ documentsTab_msg_cantOverwriteDir: "Can't overwrite a directory.",
+
+ posAndOffsetsWindow_title: "Term Positions and Offsets",
+
+ termVectorWindow_title: "Term Vector",
+ termVectorWindow_field: "Term vector for the field: ",
+
+ fieldDataWindow_title: "Field Data",
+ fieldDataWindow_decodeError: "Some values could not be properly represented in this format. They are marked in grey and presented as a hex dump.",
+
+ fieldNormWindow_title: "Field Norm",
+ fieldNormWindow_simClass: "Encode other field norm using this TFIDFSimilarity (full class name): ",
+ fieldNormWindow_otherNorm: "Enter norm value: ",
+ fieldNormWindow_encNorm: "Encoded value rounded to: ",
+
  searchTab_searchPrompt: "Enter search expression here:",
  searchTab_update: "Update",
  searchTab_explainStructure: "Explain Structure",
Index: src/org/apache/lucene/luke/ui/LukeWindow.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/LukeWindow.bxml	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/LukeWindow.bxml	(working copy)
@@ -103,7 +103,7 @@
 								</content>
 							</Border>
 
-							<Border>
+							<Border styles="{backgroundColor:11,thickness:0}">
 								<TabPane.tabData>
 									<content:ButtonData icon="/img/docs.gif"
 										text="%lukeWindow_documentsTabText" />
@@ -160,7 +160,10 @@
 					</TabPane>
 				</TablePane.Row>
 				<TablePane.Row>
-					<Label bxml:id="statusLabel" text="" styles="{padding:2}" />
+					<BoxPane>
+						<Label bxml:id="indexName" text="" styles="{padding:2}"/>
+						<Label bxml:id="statusLabel" text="" styles="{padding:2}" />
+					</BoxPane>
 				</TablePane.Row>
 			</rows>
 		</TablePane>
Index: src/org/apache/lucene/luke/ui/LukeWindow.java
===================================================================
--- src/org/apache/lucene/luke/ui/LukeWindow.java	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/LukeWindow.java	(working copy)
@@ -23,7 +23,6 @@
 import java.lang.reflect.Constructor;
 import java.net.URL;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 
 import org.apache.lucene.analysis.Analyzer;
@@ -99,6 +98,8 @@
   @BXML
   private LukeInitWindow lukeInitWindow;
   @BXML
+  private TabPane tabPane;
+  @BXML
   private FilesTab filesTab;
   @BXML
   private DocumentsTab documentsTab;
@@ -108,6 +109,8 @@
   private OverviewTab overviewTab;
   @BXML
   private AnalyzersTab analyzersTab;
+  @BXML
+  private Label indexName;
 
   private LukeMediator lukeMediator = new LukeMediator();
 
@@ -439,6 +442,7 @@
 
       // initPlugins();
       showStatus("Index successfully open.");
+      indexName.setText("Index path: " + indexPath);
     } catch (Exception e) {
       e.printStackTrace();
       errorMsg(e.getMessage());
@@ -622,8 +626,13 @@
       setComponentColor(component, "scrollButtonBackgroundColor", theme[2]);
       setComponentColor(component, "borderColor", theme[3]);
     } else if (component instanceof PushButton || component instanceof ListButton) {
-      component.getComponentMouseButtonListeners().add(mouseButtonPressedListener);
-      component.getComponentMouseListeners().add(mouseMoveListener);
+      // Listeners are added at start-up time only.
+      if (component.getComponentMouseButtonListeners().isEmpty()) {
+        component.getComponentMouseButtonListeners().add(mouseButtonPressedListener);
+      }
+      if (component.getComponentMouseListeners().isEmpty()) {
+        component.getComponentMouseListeners().add(mouseMoveListener);
+      }
       setComponentColor(component, "color", theme[1]);
       setComponentColor(component, "backgroundColor", theme[0]);
       setComponentColor(component, "borderColor", theme[3]);
@@ -679,7 +688,7 @@
 
   private Directory directory;
 
-  class LukeMediator {
+  public class LukeMediator {
 
     // populated by LukeWindow#openIndex
     private IndexInfo indexInfo;
@@ -700,6 +709,14 @@
       return overviewTab;
     }
 
+    public DocumentsTab getDocumentsTab() {
+      return documentsTab;
+    }
+
+    public TabPane getTabPane() {
+      return tabPane;
+    }
+
     public LukeWindow getLukeWindow() {
       return LukeWindow.this;
     }
Index: src/org/apache/lucene/luke/ui/OverviewTab.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/OverviewTab.bxml	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/OverviewTab.bxml	(working copy)
@@ -148,9 +148,12 @@
 											</columns>
 											<rows>
 												<TablePane.Row height="-1">
-													<Label styles="{backgroundColor:11,padding:2}" text="%overviewTab_fieldSelect" />
+													<Label styles="{backgroundColor:11,padding:2,wrapText:true}" text="%overviewTab_fieldSelect" />
 												</TablePane.Row>
 												<TablePane.Row height="-1">
+													<Label styles="{backgroundColor:11,padding:2,wrapText:true}" text="%overviewTab_fieldsHintDecoder" />
+												</TablePane.Row>
+												<TablePane.Row height="-1">
 													<Label styles="{backgroundColor:11,font:{bold:true}}"
 														text="%overviewTab_fieldsAndTermCounts" />
 												</TablePane.Row>
Index: src/org/apache/lucene/luke/ui/OverviewTab.java
===================================================================
--- src/org/apache/lucene/luke/ui/OverviewTab.java	(revision 1655665)
+++ src/org/apache/lucene/luke/ui/OverviewTab.java	(working copy)
@@ -21,19 +21,16 @@
 import java.text.NumberFormat;
 import java.util.Collections;
 
-import org.apache.lucene.index.AtomicReaderContext;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.IndexCommit;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.SegmentReader;
-import org.apache.lucene.luke.core.FieldTermCount;
+import org.apache.lucene.index.*;
+import org.apache.lucene.luke.core.*;
 import org.apache.lucene.luke.core.HighFreqTerms;
-import org.apache.lucene.luke.core.IndexInfo;
-import org.apache.lucene.luke.core.TableComparator;
 import org.apache.lucene.luke.core.TermStats;
-import org.apache.lucene.luke.core.decoders.Decoder;
+import org.apache.lucene.luke.core.decoders.*;
 import org.apache.lucene.luke.ui.LukeWindow.LukeMediator;
+import org.apache.lucene.luke.ui.util.FieldsTableRow;
+import org.apache.lucene.luke.ui.util.TableComparator;
 import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.BytesRef;
 import org.apache.pivot.beans.BXML;
 import org.apache.pivot.beans.Bindable;
 import org.apache.pivot.collections.*;
@@ -43,6 +40,7 @@
 import org.apache.pivot.util.concurrent.TaskExecutionException;
 import org.apache.pivot.util.concurrent.TaskListener;
 import org.apache.pivot.wtk.*;
+import org.apache.pivot.wtk.content.TableViewRowEditor;
 
 
 public class OverviewTab extends SplitPane implements Bindable {
@@ -230,7 +228,6 @@
 
             iTerms.setText(String.valueOf(numTerms));
             initFieldList(null, null);
-
           } catch (Exception e) {
             // showStatus("ERROR: can't count terms per field");
             numTerms = -1;
@@ -261,6 +258,7 @@
       };
 
       fListTask.execute(new TaskAdapter<String>(taskListener));
+      clearFieldsTableStatus();
 
       String sDel = ir.hasDeletions() ? "Yes (" + ir.numDeletedDocs() + ")" : "No";
       IndexCommit ic = ir instanceof DirectoryReader ? ((DirectoryReader) ir).getIndexCommit() : null;
@@ -347,16 +345,24 @@
 
     Sequence<?> fields = fieldsTable.getSelectedRows();
 
-    String[] flds = null;
+    final java.util.Map<String, Decoder> fldDecMap = new java.util.HashMap<String, Decoder>();
     if (fields == null || fields.getLength() == 0) {
-      flds = indexInfo.getFieldNames().toArray(new String[0]);
+      // no fields selected
+      for (String fld : indexInfo.getFieldNames()) {
+        Decoder dec = lukeMediator.getDecoders().get(fld);
+        if (dec == null) {
+          dec = lukeMediator.getDefDecoder();
+        }
+        fldDecMap.put(fld, dec);
+      }
     } else {
-      flds = new String[fields.getLength()];
+      // some fields selected
       for (int i = 0; i < fields.getLength(); i++) {
-        flds[i] = ((Map<String,String>) fields.get(i)).get("name");
+        String fld = ((FieldsTableRow)fields.get(i)).getName();
+        Decoder dec = ((FieldsTableRow)fields.get(i)).getDecoder();
+        fldDecMap.put(fld, dec);
       }
     }
-    final String[] fflds = flds;
 
     tTable.setTableData(new ArrayList(0));
 
@@ -387,6 +393,7 @@
       public void taskExecuted(Task<Object> task) {
         // this must happen here rather than in the task because it must happen in the UI dispatch thread
         try {
+          final String[] fflds = fldDecMap.keySet().toArray(new String[0]);
           TermStats[] topTerms = HighFreqTerms.getHighFreqTerms(ir, ndoc, fflds);
 
           List<Map<String,String>> tableData = new ArrayList<Map<String,String>>();
@@ -409,12 +416,11 @@
 
             row.put("field", topTerms[i].field);
 
-            Decoder dec = lukeMediator.getDecoders().get(topTerms[i].field);
-            if (dec == null)
-              dec = lukeMediator.getDefDecoder();
+            Decoder dec = fldDecMap.get(topTerms[i].field);
+
             String s;
             try {
-              s = dec.decodeTerm(topTerms[i].field, topTerms[i].termtext.utf8ToString());
+              s = dec.decodeTerm(topTerms[i].field, topTerms[i].termtext);
             } catch (Throwable e) {
               // e.printStackTrace();
               s = topTerms[i].termtext.utf8ToString();
@@ -422,6 +428,8 @@
               // setColor(cell, "foreground", Color.RED);
             }
             row.put("text", s);
+            // hidden field. would be used when the user select 'Browse term docs' menu at top terms table.
+            row.put("rawterm", topTerms[i].termtext.utf8ToString());
             tableData.add(row);
           }
           tTable.setTableData(tableData);
@@ -443,8 +451,74 @@
     };
 
     topTermsTask.execute(new TaskAdapter<Object>(taskListener));
+
+    addListenerToTopTermsTable();
   }
 
+  private void addListenerToTopTermsTable() {
+    // register mouse button listener for more options.
+    tTable.getComponentMouseButtonListeners().add(new ComponentMouseButtonListener.Adapter(){
+      @Override
+      public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+        final Map<String, String> row = (Map<String, String>) tTable.getSelectedRow();
+        if (row == null) {
+          System.out.println("No term selected.");
+          return false;
+        }
+        if (button.name().equals(Mouse.Button.RIGHT.name())) {
+          MenuPopup popup = new MenuPopup();
+          Menu menu = new Menu();
+          Menu.Section section1 = new Menu.Section();
+          Menu.Section section2 = new Menu.Section();
+          Menu.Item item1 = new Menu.Item(resources.get("overviewTab_topTermTable_popup_menu1"));
+          item1.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              // 'Browse term docs' menu selected. switch to Documents tab.
+              Term term = new Term(row.get("field"), new BytesRef(row.get("rawterm")));
+              lukeMediator.getDocumentsTab().showTerm(term);
+              // TODO: index access isn't good...
+              lukeMediator.getTabPane().setSelectedIndex(1);
+            }
+          });
+          Menu.Item item2 = new Menu.Item(resources.get("overviewTab_topTermTable_popup_menu2"));
+          item2.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              // 'Show all term docs' menu selected. switch to Search tab.
+              // TODO
+            }
+          });
+          Menu.Item item3 = new Menu.Item(resources.get("overviewTab_topTermTable_popup_menu3"));
+          item3.setAction(new Action() {
+            @Override
+            public void perform(Component component) {
+              // 'Copy to clipboard' menu selected.
+              StringBuilder sb = new StringBuilder();
+              sb.append(row.get("num") + "\t");
+              sb.append(row.get("df") + "\t");
+              sb.append(row.get("field") + "\t");
+              sb.append(row.get("text") + "\t");
+              LocalManifest content = new LocalManifest();
+              content.putText(sb.toString());
+              Clipboard.setContent(content);
+            }
+          });
+          section1.add(item1);
+          section1.add(item2);
+          section2.add(item3);
+          menu.getSections().add(section1);
+          menu.getSections().add(section2);
+          popup.setMenu(menu);
+
+          popup.open(getWindow(), getMouseLocation().x + 20, getMouseLocation().y);
+          return true;
+        }
+        return false;
+      }
+    });
+  }
+
   private void initFieldList(Object fCombo, Object defFld) {
     // removeAll(fieldsTable);
     // removeAll(defFld);
@@ -454,11 +528,12 @@
     NumberFormat percentFormat = NumberFormat.getNumberInstance();
     intCountFormat.setGroupingUsed(true);
     percentFormat.setMaximumFractionDigits(2);
+    // sort listener
     fieldsTable.getTableViewSortListeners().add(new TableViewSortListener.Adapter() {
       @Override
       public void sortChanged(TableView tableView) {
         @SuppressWarnings("unchecked")
-        List<Map<String, String>> tableData = (List<Map<String, String>>) tableView.getTableData();
+        List<FieldsTableRow> tableData = (List<FieldsTableRow>) tableView.getTableData();
         tableData.setComparator(new TableComparator(tableView));
       }
     });
@@ -465,34 +540,39 @@
     // default sort : sorted by name in ascending order
     fieldsTable.setSort("name", SortDirection.ASCENDING);
 
-    for (String s : indexInfo.getFieldNames()) {
-      Map<String,String> row = new HashMap<String,String>();
+    // row editor for decoders
+    List decoders = new ArrayList();
+    for (Decoder dec : Util.loadDecoders()) {
+      decoders.add(dec);
+    }
+    ListButton decodersButton = new ListButton(decoders);
+    decodersButton.setSelectedItemKey("decoder");
+    TableViewRowEditor rowEditor = new TableViewRowEditor();
+    rowEditor.getCellEditors().put("decoder", decodersButton);
+    fieldsTable.setRowEditor(rowEditor);
 
-      row.put("name", s);
 
-      FieldTermCount ftc = termCounts.get(s);
+    for (String fname : indexInfo.getFieldNames()) {
+      FieldsTableRow row = new FieldsTableRow(lukeMediator);
+      row.setName(fname);
+      FieldTermCount ftc = termCounts.get(fname);
       if (ftc != null) {
         long cnt = ftc.termCount;
-
-        row.put("termCount", intCountFormat.format(cnt));
-
+        row.setTermCount(intCountFormat.format(cnt));
         float pcent = (float) (cnt * 100) / (float) numTerms;
-
-        row.put("percent", percentFormat.format(pcent) + " %");
-
+        row.setPercent(percentFormat.format(pcent) + " %");
       } else {
-        row.put("termCount", "0");
-        row.put("percent", "0.00%");
+        row.setTermCount("0");
+        row.setPercent("0.00%");
       }
 
-      //tableData.add(row);
-      List<Map<String, String>> tableData = (List<Map<String, String>>)fieldsTable.getTableData();
+      List<FieldsTableRow> tableData = (List<FieldsTableRow>)fieldsTable.getTableData();
       tableData.add(row);
 
-      Decoder dec = lukeMediator.getDecoders().get(s);
+      Decoder dec = lukeMediator.getDecoders().get(fname);
       if (dec == null)
         dec = lukeMediator.getDefDecoder();
-      row.put("decoder", dec.toString());
+      row.setDecoder(dec);
 
       // populate combos
       // Object choice = create("choice");
@@ -504,9 +584,14 @@
       // setString(choice, "text", s);
       // putProperty(choice, "fName", s);
     }
-    //fieldsTable.setTableData(tableData);
+
   }
 
+  private void clearFieldsTableStatus() {
+    // clear the fields table view status
+    fieldsTable.clearSelection();
+  }
+
   private int getNTerms() {
     final int nTermsInt = nTerms.getSelectedIndex();
     return nTermsInt;
Index: src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.bxml	(revision 0)
+++ src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.bxml	(working copy)
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<luke:PosAndOffsetsWindow bxml:id="posAndOffsets" icon="/img/luke.gif"
+										 title="%posAndOffsetsWindow_title" xmlns:bxml="http://pivot.apache.org/bxml"
+										 xmlns:luke="org.apache.lucene.luke.ui" xmlns:content="org.apache.pivot.wtk.content"
+										 xmlns="org.apache.pivot.wtk">
+	<content>
+		<TablePane styles="{verticalSpacing:10}">
+			<columns>
+				<TablePane.Column width="1*"/>
+			</columns>
+			<rows>
+				<TablePane.Row>
+					<TablePane styles="{verticalSpacing:1,horizontalSpacing:1}">
+						<columns>
+							<TablePane.Column />
+							<TablePane.Column width="1*"/>
+						</columns>
+						<rows>
+							<TablePane.Row>
+								<Label text="Document #" styles="{font:{bold:true},backgroundColor:'#dce0e7',padding:2}"/>
+								<Label bxml:id="docNum" text="?" styles="{backgroundColor:'#fcfdfd',padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Term positions for term: " styles="{font:{bold:true},backgroundColor:'#f1f1f1',padding:2}"/>
+								<Label bxml:id="term" text="?" styles="{backgroundColor:11,padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Term Frequency: " styles="{font:{bold:true},backgroundColor:'#dce0e7',padding:2}"/>
+								<Label bxml:id="tf" text="?" styles="{backgroundColor:'#fcfdfd',padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Offsets: " styles="{font:{bold:true},backgroundColor:'#f1f1f1',padding:2}"/>
+								<Label bxml:id="offsets" text="?" styles="{backgroundColor:11,padding:2}"/>
+							</TablePane.Row>
+							<TablePane.Row>
+								<Label text="Show payload as: " styles="{font:{bold:true},backgroundColor:'#dce0e7',padding:2}"/>
+								<Spinner bxml:id="pDecoder" />
+							</TablePane.Row>
+						</rows>
+					</TablePane>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<Border styles="{padding:1}">
+						<ScrollPane horizontalScrollBarPolicy="fill_to_capacity" styles="{backgroundColor:11}">
+							<view>
+								<TableView bxml:id="posTable" selectMode="multi">
+									<columns>
+										<TableView.Column name="pos"
+																			headerData="Position" width="50"/>
+										<TableView.Column name="offsets"
+																			headerData="Offsets" width="100"/>
+										<TableView.Column name="payloadStr"
+																			headerData="Payload" width="300"/>
+									</columns>
+								</TableView>
+							</view>
+							<columnHeader>
+								<TableViewHeader tableView="$posTable" />
+							</columnHeader>
+						</ScrollPane>
+					</Border>
+				</TablePane.Row>
+
+				<TablePane.Row>
+					<BoxPane orientation="horizontal" styles="{horizontalAlignment:'right'}">
+						<PushButton buttonData="%label_ok"
+												ButtonPressListener.buttonPressed="posAndOffsets.close()">
+						</PushButton>
+						<PushButton bxml:id="posCopyButton" buttonData="%label_clipboard"/>
+					</BoxPane>
+				</TablePane.Row>
+			</rows>
+		</TablePane>
+	</content>
+</luke:PosAndOffsetsWindow>
\ No newline at end of file

Property changes on: src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.bxml
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/xml
\ No newline at end of property
Index: src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.java
===================================================================
--- src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/PosAndOffsetsWindow.java	(working copy)
@@ -0,0 +1,208 @@
+package org.apache.lucene.luke.ui;
+
+import org.apache.lucene.analysis.payloads.PayloadHelper;
+import org.apache.lucene.index.DocsAndPositionsEnum;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.luke.core.Util;
+import org.apache.lucene.util.BytesRef;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.Bindable;
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.List;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.util.Resources;
+import org.apache.pivot.wtk.*;
+
+import java.net.URL;
+
+public class PosAndOffsetsWindow extends Dialog implements Bindable {
+
+  @BXML
+  private TableView posTable;
+  @BXML
+  private Label docNum;
+  @BXML
+  private Label term;
+  @BXML
+  private Label tf;
+  @BXML
+  private Label offsets;
+  @BXML
+  private Spinner pDecoder;
+  @BXML
+  private PushButton posCopyButton;
+
+  private Resources resources;
+
+  private List<PositionAndOffset> tableData;
+
+  @Override
+  public void initialize(Map<String, Object> map, URL url, Resources resources) {
+    this.resources = resources;
+  }
+
+  public void initPositionInfo(DocsAndPositionsEnum pe, Term lastTerm) throws Exception {
+    setPayloadDecoders();
+    tableData = new ArrayList<PositionAndOffset>(getTermPositionAndOffsets(pe));
+    docNum.setText(String.valueOf(pe.docID()));
+    term.setText(lastTerm.field() + ":" + lastTerm.text());
+    tf.setText(String.valueOf(pe.freq()));
+    if (!tableData.isEmpty()) {
+      offsets.setText(String.valueOf(tableData.get(0).hasOffsets));
+    }
+    posTable.setTableData(tableData);
+    addPushButtonListener();
+  }
+
+  private void setPayloadDecoders() {
+    ArrayList<Object> decoders = new ArrayList<Object>();
+    decoders.add(PayloadDecoder.ARRAY_OF_FLOAT);
+    decoders.add(PayloadDecoder.ARRAY_OF_INT);
+    decoders.add(PayloadDecoder.HEXDUMP);
+    decoders.add(PayloadDecoder.STRING);
+    decoders.add(PayloadDecoder.STRING_UTF8);
+    pDecoder.setSpinnerData(decoders);
+    pDecoder.setSelectedItem(PayloadDecoder.STRING_UTF8);
+
+    pDecoder.getSpinnerSelectionListeners().add(new SpinnerSelectionListener.Adapter() {
+      @Override
+      public void selectedItemChanged(Spinner spinner, Object o) {
+        try {
+          for (PositionAndOffset row : tableData) {
+            PayloadDecoder dec = (PayloadDecoder) spinner.getSelectedItem();
+            if (dec == null) {
+              dec = PayloadDecoder.defDecoder();
+            }
+            row.payloadStr = dec.decode(row.payload);
+          }
+          posTable.repaint();  // update table data
+        } catch (Exception e) {
+          // TODO:
+          e.printStackTrace();
+        }
+      }
+    });
+  }
+
+  public class PositionAndOffset {
+    public int pos = -1;
+    public boolean hasOffsets = false;
+    public String offsets = "----";
+    public BytesRef payload = null;
+    public String payloadStr = "----";
+  }
+
+  private PositionAndOffset[] getTermPositionAndOffsets(DocsAndPositionsEnum pe) throws Exception {
+    int freq = pe.freq();
+
+    PositionAndOffset[] res = new PositionAndOffset[freq];
+    for (int i = 0; i < freq; i++) {
+      PositionAndOffset po = new PositionAndOffset();
+      po.pos = pe.nextPosition();
+      if (pe.startOffset() >= 0 && pe.endOffset() >= 0) {
+        // retrieve start and end offsets
+        po.hasOffsets = true;
+        po.offsets = String.valueOf(pe.startOffset()) + " - " + String.valueOf(pe.endOffset());
+      }
+      if (pe.getPayload() != null) {
+        po.payload = pe.getPayload();
+        po.payloadStr = ((PayloadDecoder) pDecoder.getSelectedItem()).decode(pe.getPayload());
+      }
+      res[i] = po;
+    }
+    return res;
+  }
+
+  enum PayloadDecoder {
+    STRING_UTF8("String UTF-8"),
+    STRING("String default enc."),
+    HEXDUMP("Hexdump"),
+    ARRAY_OF_INT("Array of int"),
+    ARRAY_OF_FLOAT("Array of float");
+
+    private String strExpr = null;
+    PayloadDecoder(String expr) {
+      this.strExpr = expr;
+    }
+
+    @Override
+    public String toString() {
+      return strExpr;
+    }
+
+    public static PayloadDecoder defDecoder() {
+      return STRING_UTF8;
+    }
+
+    public String decode(BytesRef payload) {
+      String val = "----";
+      StringBuilder sb = null;
+      if (payload == null) {
+        return val;
+      }
+      switch(this) {
+        case STRING_UTF8:
+          try {
+            val = new String(payload.bytes, payload.offset, payload.length, "UTF-8");
+          } catch (Exception e) {
+            e.printStackTrace();
+            val = new String(payload.bytes, payload.offset, payload.length);
+          }
+          break;
+        case STRING:
+          val = new String(payload.bytes, payload.offset, payload.length);
+          break;
+        case HEXDUMP:
+          val = Util.bytesToHex(payload.bytes, payload.offset, payload.length, false);
+          break;
+        case ARRAY_OF_INT:
+          sb = new StringBuilder();
+          for (int k = payload.offset; k < payload.offset + payload.length; k += 4) {
+            if (k > 0) sb.append(',');
+            sb.append(String.valueOf(PayloadHelper.decodeInt(payload.bytes, k)));
+          }
+          val = sb.toString();
+          break;
+        case ARRAY_OF_FLOAT:
+          sb = new StringBuilder();
+          for (int k = payload.offset; k < payload.offset + payload.length; k += 4) {
+            if (k > 0) sb.append(',');
+            sb.append(String.valueOf(PayloadHelper.decodeFloat(payload.bytes, k)));
+          }
+          val = sb.toString();
+          break;
+      }
+      return val;
+    }
+  }
+
+  private void addPushButtonListener() {
+
+    posCopyButton.getButtonPressListeners().add(new ButtonPressListener() {
+      @Override
+      public void buttonPressed(Button button) {
+        // fired when 'Copy to Clipboard' button pressed
+        Sequence<PositionAndOffset> selectedRows = (Sequence<PositionAndOffset>) posTable.getSelectedRows();
+        if (selectedRows == null || selectedRows.getLength() == 0) {
+          Alert.alert(MessageType.INFO, "No rows selected.", getWindow());
+        } else {
+          StringBuilder sb = new StringBuilder();
+          for (int i = 0; i < selectedRows.getLength(); i++) {
+            PositionAndOffset row = selectedRows.get(i);
+            sb.append(row.pos + "\t");
+            sb.append(row.offsets + "\t");
+            sb.append(row.payloadStr);
+            if (i < selectedRows.getLength() - 1) {
+              sb.append("\n");
+            }
+          }
+          LocalManifest content = new LocalManifest();
+          content.putText(sb.toString());
+          Clipboard.setContent(content);
+        }
+      }
+    });
+  }
+
+}
Index: src/org/apache/lucene/luke/ui/TermVectorWindow.bxml
===================================================================
--- src/org/apache/lucene/luke/ui/TermVectorWindow.bxml	(revision 0)
+++ src/org/apache/lucene/luke/ui/TermVectorWindow.bxml	(working copy)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<luke:TermVectorWindow bxml:id="termVector" icon="/img/luke.gif"
+													title="%termVectorWindow_title" xmlns:bxml="http://pivot.apache.org/bxml"
+													xmlns:luke="org.apache.lucene.luke.ui" xmlns:content="org.apache.pivot.wtk.content"
+													xmlns="org.apache.pivot.wtk">
+	<content>
+		<TablePane styles="{verticalSpacing:10}">
+			<columns>
+				<TablePane.Column width="1*"/>
+			</columns>
+			<rows>
+				<TablePane.Row>
+					<BoxPane styles="{fill:true}">
+						<ImageView image="/img/info.gif"/>
+						<Label text="%termVectorWindow_field" />
+						<Label bxml:id="field" text="?" styles="{font:{bold:true}}"/>
+					</BoxPane>
+				</TablePane.Row>
+				<TablePane.Row>
+					<Border styles="{padding:1}">
+						<ScrollPane horizontalScrollBarPolicy="fill_to_capacity" styles="{backgroundColor:11}">
+							<view>
+								<TableView bxml:id="tvTable" selectMode="multi">
+									<columns>
+										<TableView.Column name="term"
+																			headerData="Term" width="100"/>
+										<TableView.Column name="freq"
+																			headerData="Freq." width="50"/>
+										<TableView.Column name="pos"
+																			headerData="Positions" width="100"/>
+										<TableView.Column name="offsets"
+																			headerData="Offsets" width="100" />
+									</columns>
+								</TableView>
+							</view>
+							<columnHeader>
+								<TableViewHeader tableView="$tvTable" sortMode="single_column" />
+							</columnHeader>
+						</ScrollPane>
+					</Border>
+				</TablePane.Row>
+				<TablePane.Row>
+					<BoxPane orientation="horizontal" styles="{horizontalAlignment:'right'}">
+						<PushButton buttonData="%label_ok"
+												ButtonPressListener.buttonPressed="termVector.close()">
+						</PushButton>
+						<PushButton bxml:id="tvCopyButton" buttonData="%label_clipboard"/>
+					</BoxPane>
+				</TablePane.Row>
+			</rows>
+		</TablePane>
+	</content>
+</luke:TermVectorWindow>
\ No newline at end of file

Property changes on: src/org/apache/lucene/luke/ui/TermVectorWindow.bxml
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/xml
\ No newline at end of property
Index: src/org/apache/lucene/luke/ui/TermVectorWindow.java
===================================================================
--- src/org/apache/lucene/luke/ui/TermVectorWindow.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/TermVectorWindow.java	(working copy)
@@ -0,0 +1,143 @@
+package org.apache.lucene.luke.ui;
+
+import org.apache.lucene.index.DocsAndPositionsEnum;
+import org.apache.lucene.index.DocsEnum;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.index.TermsEnum;
+import org.apache.lucene.luke.ui.util.TermVectorTableComparator;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.util.Bits;
+import org.apache.lucene.util.BytesRef;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.Bindable;
+import org.apache.pivot.collections.*;
+import org.apache.pivot.util.Resources;
+import org.apache.pivot.wtk.*;
+
+import java.io.IOException;
+import java.net.URL;
+
+public class TermVectorWindow extends Dialog implements Bindable{
+
+  @BXML
+  private Label field;
+  @BXML
+  private TableView tvTable;
+  @BXML
+  private PushButton tvCopyButton;
+
+  private Resources resources;
+
+  private List<Map<String, String>> tableData;
+
+  public static String TVROW_KEY_TERM = "term";
+  public static String TVROW_KEY_FREQ = "freq";
+  public static String TVROW_KEY_POSITION = "pos";
+  public static String TVROW_KEY_OFFSETS = "offsets";
+
+  @Override
+  public void initialize(Map<String, Object> map, URL url, Resources resources) {
+    this.resources = resources;
+  }
+
+  public void initTermVector(String fieldName, Terms tv) throws IOException {
+    field.setText(fieldName);
+    tableData = new ArrayList<Map<String, String>>();
+    TermsEnum te = tv.iterator(null);
+    BytesRef term = null;
+
+    // populate table data with term vector info
+    while((term = te.next()) != null) {
+      Map<String, String> row = new HashMap<String, String>();
+      tableData.add(row);
+      row.put(TVROW_KEY_TERM, term.utf8ToString());
+      // try to get DocsAndPositionsEnum
+      DocsEnum de = te.docsAndPositions(null, null);
+      if (de == null) {
+        // if positions are not indexed, get DocsEnum
+        de = te.docs(null, null);
+      }
+      // must have one doc
+      if (de.nextDoc() == DocIdSetIterator.NO_MORE_DOCS) {
+        continue;
+      }
+      row.put(TVROW_KEY_FREQ, String.valueOf(de.freq()));
+      if (de instanceof DocsAndPositionsEnum) {
+        // positions are available
+        DocsAndPositionsEnum dpe = (DocsAndPositionsEnum) de;
+        StringBuilder bufPos = new StringBuilder();
+        StringBuilder bufOff = new StringBuilder();
+        // enumerate all positions info
+        for (int i = 0; i < de.freq(); i++) {
+          int pos = dpe.nextPosition();
+          bufPos.append(String.valueOf(pos));
+          if (i < de.freq() - 1) {
+            bufPos.append((","));
+          }
+          // offsets are indexed?
+          int sOffset = dpe.startOffset();
+          int eOffset = dpe.endOffset();
+          if (sOffset >= 0 && eOffset >= 0) {
+            String offsets = String.valueOf(sOffset) + "-" + String.valueOf(eOffset);
+            bufOff.append(offsets);
+            if (i < de.freq() - 1) {
+              bufOff.append(",");
+            }
+          }
+        }
+        row.put(TVROW_KEY_POSITION, bufPos.toString());
+        row.put(TVROW_KEY_OFFSETS, (bufOff.length() == 0) ? "----" : bufOff.toString());
+      } else {
+        // positions are not available
+        row.put(TVROW_KEY_POSITION, "----");
+        row.put(TVROW_KEY_OFFSETS, "----");
+      }
+    }
+    // register sort listener
+    tvTable.getTableViewSortListeners().add(new TableViewSortListener.Adapter() {
+      @Override
+      public void sortChanged(TableView tableView) {
+        List<Map<String, String>> tableData = (List<Map<String, String>>) tableView.getTableData();
+        tableData.setComparator(new TermVectorTableComparator(tableView));
+      }
+    });
+    // default sort : by ascending order of term
+    Sequence<Dictionary.Pair<String, SortDirection>> sort = new ArrayList<Dictionary.Pair<String, SortDirection>>();
+    sort.add(new Dictionary.Pair<String, SortDirection>(TVROW_KEY_TERM, SortDirection.ASCENDING));
+    sort.add(new Dictionary.Pair<String, SortDirection>(TVROW_KEY_FREQ, SortDirection.DESCENDING));
+    tvTable.setSort(sort);
+
+    tvTable.setTableData(tableData);
+    addPushButtonListener();
+  }
+
+  private void addPushButtonListener() {
+
+    tvCopyButton.getButtonPressListeners().add(new ButtonPressListener() {
+      @Override
+      public void buttonPressed(Button button) {
+        // fired when 'Copy to Clipboard' button pressed
+        Sequence<Map<String, String>> selectedRows = (Sequence<Map<String, String>>) tvTable.getSelectedRows();
+        if (selectedRows == null || selectedRows.getLength() == 0) {
+          Alert.alert(MessageType.INFO, "No rows selected.", getWindow());
+        } else {
+          StringBuilder sb = new StringBuilder();
+          for (int i = 0; i < selectedRows.getLength(); i++) {
+            Map<String, String> row = selectedRows.get(i);
+            sb.append(row.get(TVROW_KEY_TERM) + "\t");
+            sb.append(row.get(TVROW_KEY_FREQ) + "\t");
+            sb.append(row.get(TVROW_KEY_POSITION) + "\t");
+            sb.append(row.get(TVROW_KEY_OFFSETS));
+            if (i < selectedRows.getLength() - 1) {
+              sb.append("\n");
+            }
+          }
+          LocalManifest content = new LocalManifest();
+          content.putText(sb.toString());
+          Clipboard.setContent(content);
+        }
+      }
+    });
+  }
+
+}
Index: src/org/apache/lucene/luke/ui/util/FieldsTableRow.java
===================================================================
--- src/org/apache/lucene/luke/ui/util/FieldsTableRow.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/util/FieldsTableRow.java	(working copy)
@@ -0,0 +1,61 @@
+package org.apache.lucene.luke.ui.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+import org.apache.lucene.luke.core.decoders.Decoder;
+import org.apache.lucene.luke.ui.LukeWindow;
+
+public class FieldsTableRow {
+  private String name;
+  private String termCount;
+  private String percent;
+  private Decoder decoder;
+
+  private LukeWindow.LukeMediator lukeMediator;
+
+  public FieldsTableRow(LukeWindow.LukeMediator lukeMediator) {
+    this.lukeMediator = lukeMediator;
+  }
+
+  public String getName() {
+    return name;
+  }
+  public void setName(String name) {
+    this.name = name;
+  }
+  public String getTermCount() {
+    return termCount;
+  }
+  public void setTermCount(String termCount) {
+    this.termCount = termCount;
+  }
+  public String getPercent() {
+    return percent;
+  }
+  public void setPercent(String percent) {
+    this.percent = percent;
+  }
+  public Decoder getDecoder() {
+    return decoder;
+  }
+  public void setDecoder(Decoder decoder) {
+    this.decoder = decoder;
+    this.lukeMediator.getDecoders().put(name, decoder);
+  }
+
+}
Index: src/org/apache/lucene/luke/ui/util/TableComparator.java
===================================================================
--- src/org/apache/lucene/luke/ui/util/TableComparator.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/util/TableComparator.java	(working copy)
@@ -0,0 +1,102 @@
+package org.apache.lucene.luke.ui.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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.
+ */
+
+
+import java.util.Comparator;
+
+import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.wtk.SortDirection;
+import org.apache.pivot.wtk.TableView;
+
+public class TableComparator implements Comparator<FieldsTableRow> {
+  private TableView tableView;
+
+  public TableComparator(TableView fieldsTable) {
+    if (fieldsTable == null) {
+      throw new IllegalArgumentException();
+    }
+
+    this.tableView = fieldsTable;
+  }
+
+  @Override
+  public int compare(FieldsTableRow row1, FieldsTableRow row2) {
+    Dictionary.Pair<String, SortDirection> sort = tableView.getSort().get(0);
+
+    int result;
+    if (sort.key.equals("name")) {
+      // sort by name
+      result = row1.getName().compareTo(row2.getName());
+    } else if (sort.key.equals("termCount")) {
+      // sort by termCount
+      Integer c1 = Integer.parseInt(row1.getTermCount());
+      Integer c2 = Integer.parseInt(row2.getTermCount());
+      result = c1.compareTo(c2);
+    } else {
+      // other (ignored)
+      result = 0;
+    }
+    //int result = o1.get("name").compareTo(o2.get("name"));
+    //SortDirection sortDirection = tableView.getSort().get("name");
+    SortDirection sortDirection = sort.value;
+    result *= (sortDirection == SortDirection.DESCENDING ? 1 : -1);
+
+    return result * -1;
+  }
+}
+
+/*
+public class TableComparator implements Comparator<Map<String,String>> {
+  private TableView tableView;
+  
+  public TableComparator(TableView fieldsTable) {
+    if (fieldsTable == null) {
+      throw new IllegalArgumentException();
+    }
+    
+    this.tableView = fieldsTable;
+  }
+  
+  @Override
+  public int compare(Map<String,String> o1, Map<String,String> o2) {
+    Dictionary.Pair<String, SortDirection> sort = tableView.getSort().get(0);
+
+    int result;
+    if (sort.key.equals("name")) {
+      // sort by name
+      result = o1.get(sort.key).compareTo(o2.get(sort.key));
+    } else if (sort.key.equals("termCount")) {
+      // sort by termCount
+      Integer c1 = Integer.parseInt(o1.get(sort.key));
+      Integer c2 = Integer.parseInt(o2.get(sort.key));
+      result = c1.compareTo(c2);
+    } else {
+      // other (ignored)
+      result = 0;
+    }
+    //int result = o1.get("name").compareTo(o2.get("name"));
+    //SortDirection sortDirection = tableView.getSort().get("name");
+    SortDirection sortDirection = sort.value;
+    result *= (sortDirection == SortDirection.DESCENDING ? 1 : -1);
+
+    return result * -1;
+  }
+  
+}
+*/
Index: src/org/apache/lucene/luke/ui/util/TermVectorTableComparator.java
===================================================================
--- src/org/apache/lucene/luke/ui/util/TermVectorTableComparator.java	(revision 0)
+++ src/org/apache/lucene/luke/ui/util/TermVectorTableComparator.java	(working copy)
@@ -0,0 +1,46 @@
+package org.apache.lucene.luke.ui.util;
+
+import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.wtk.SortDirection;
+import org.apache.pivot.wtk.TableView;
+
+import java.util.Comparator;
+
+import static org.apache.lucene.luke.ui.TermVectorWindow.TVROW_KEY_FREQ;
+import static org.apache.lucene.luke.ui.TermVectorWindow.TVROW_KEY_TERM;
+
+
+public class TermVectorTableComparator implements Comparator<Map<String, String>> {
+  private TableView tableView;
+
+  public TermVectorTableComparator(TableView tableView) {
+    if (tableView == null) {
+      throw new IllegalArgumentException();
+    }
+    this.tableView = tableView;
+  }
+
+  @Override
+  public int compare(Map<String, String> row1, Map<String, String> row2) {
+    Dictionary.Pair<String, SortDirection> sort = tableView.getSort().get(0);
+
+    int result;
+    if (sort.key.equals(TVROW_KEY_TERM)) {
+      // sort by name
+      result = row1.get(TVROW_KEY_TERM).compareTo(row2.get(TVROW_KEY_TERM));
+    } else if (sort.key.equals(TVROW_KEY_FREQ)) {
+      // sort by termCount
+      Integer f1 = Integer.parseInt(row1.get(TVROW_KEY_FREQ));
+      Integer f2 = Integer.parseInt(row2.get(TVROW_KEY_FREQ));
+      result = f1.compareTo(f2);
+    } else {
+      // other (ignored)
+      result = 0;
+    }
+    SortDirection sortDirection = sort.value;
+    result *= (sortDirection == SortDirection.DESCENDING ? 1 : -1);
+
+    return result * -1;
+  }
+}
